diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-03 13:42:47 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-05-15 10:27:51 +0000 |
commit | 8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (patch) | |
tree | d29d987c4d7b173cf853279b79a51598f104b403 /chromium/ui | |
parent | 830c9e163d31a9180fadca926b3e1d7dfffb5021 (diff) | |
download | qtwebengine-chromium-8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec.tar.gz |
BASELINE: Update Chromium to 66.0.3359.156
Change-Id: I0c9831ad39911a086b6377b16f995ad75a51e441
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/ui')
875 files changed, 24460 insertions, 11721 deletions
diff --git a/chromium/ui/PRESUBMIT.py b/chromium/ui/PRESUBMIT.py index 7c0c787afbd..810c0919e1f 100644 --- a/chromium/ui/PRESUBMIT.py +++ b/chromium/ui/PRESUBMIT.py @@ -8,39 +8,6 @@ See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for more details about the presubmit API built into depot_tools. """ -INCLUDE_CPP_FILES_ONLY = ( - r'.*\.(cc|h|mm)$', -) - -def CheckUniquePtr(input_api, output_api, - white_list=INCLUDE_CPP_FILES_ONLY, black_list=None): - black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST) - source_file_filter = lambda x: input_api.FilterSourceFile(x, - white_list, - black_list) - errors = [] - for f in input_api.AffectedSourceFiles(source_file_filter): - for line_number, line in f.ChangedContents(): - # Disallow: - # return std::unique_ptr<T>(foo); - # bar = std::unique_ptr<T>(foo); - # But allow: - # return std::unique_ptr<T[]>(foo); - # bar = std::unique_ptr<T[]>(foo); - if input_api.re.search( - r'(=|\breturn)\s*std::unique_ptr<[^\[\]>]+>\([^)]+\)', line): - errors.append(output_api.PresubmitError( - ('%s:%d uses explicit std::unique_ptr constructor. ' + - 'Use std::make_unique<T>() or base::WrapUnique() instead.') % - (f.LocalPath(), line_number))) - # Disallow: - # std::unique_ptr<T>() - if input_api.re.search(r'\bstd::unique_ptr<[^<>]+>\(\)', line): - errors.append(output_api.PresubmitError( - '%s:%d uses std::unique_ptr<T>(). Use nullptr instead.' % - (f.LocalPath(), line_number))) - return errors - def CheckX11HeaderUsage(input_api, output_api): """X11 headers pollute the global namespace with macros for common names so instead code should include "ui/gfx/x/x11.h" which hide the @@ -68,7 +35,6 @@ dangerous macros inside the x11 namespace.""" def CheckChange(input_api, output_api): results = [] - results += CheckUniquePtr(input_api, output_api) results += CheckX11HeaderUsage(input_api, output_api) return results diff --git a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm b/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm index 7ff59beee63..8306398431d 100644 --- a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm +++ b/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.mm @@ -6,6 +6,7 @@ #include <map> +#include "base/debug/dump_without_crashing.h" #include "base/lazy_instance.h" #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" @@ -24,6 +25,10 @@ namespace ui { namespace { +// The maximum number of times to dump before throttling (to avoid sending +// thousands of crash dumps). +const int kMaxCrashDumps = 10; + typedef std::map<gfx::AcceleratedWidget,AcceleratedWidgetMac*> WidgetToHelperMap; base::LazyInstance<WidgetToHelperMap>::DestructorAtExit g_widget_to_helper_map; @@ -148,14 +153,24 @@ void AcceleratedWidgetMac::UpdateCALayerTree( GotCALayerFrame(base::scoped_nsobject<CALayer>(remote_layer_.get(), base::scoped_policy::RETAIN), ca_layer_params.pixel_size, ca_layer_params.scale_factor); - } else { + } else if (ca_layer_params.io_surface_mach_port) { base::ScopedCFTypeRef<IOSurfaceRef> io_surface( IOSurfaceLookupFromMachPort(ca_layer_params.io_surface_mach_port)); if (!io_surface) { LOG(ERROR) << "Unable to open IOSurface for frame."; + static int dump_counter = kMaxCrashDumps; + if (dump_counter) { + dump_counter -= 1; + base::debug::DumpWithoutCrashing(); + } } GotIOSurfaceFrame(io_surface, ca_layer_params.pixel_size, ca_layer_params.scale_factor); + } else { + LOG(ERROR) << "Frame had neither valid CAContext nor valid IOSurface."; + base::ScopedCFTypeRef<IOSurfaceRef> io_surface; + GotIOSurfaceFrame(io_surface, ca_layer_params.pixel_size, + ca_layer_params.scale_factor); } if (view_) view_->AcceleratedWidgetSwapCompleted(); diff --git a/chromium/ui/accessibility/BUILD.gn b/chromium/ui/accessibility/BUILD.gn index b5a6c772be0..d497360d8d8 100644 --- a/chromium/ui/accessibility/BUILD.gn +++ b/chromium/ui/accessibility/BUILD.gn @@ -6,6 +6,7 @@ import("//build/config/linux/gtk/gtk.gni") import("//build/config/linux/pkg_config.gni") import("//build/config/features.gni") import("//build/config/ui.gni") +import("//mojo/public/tools/bindings/mojom.gni") import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/test.gni") import("//tools/json_schema_compiler/json_schema_api.gni") @@ -15,10 +16,18 @@ if (is_android) { import("//build/config/android/rules.gni") } +mojom("ax_enums_mojo") { + sources = [ + "ax_enums.mojom", + ] +} + component("accessibility") { sources = [ "ax_action_data.cc", "ax_action_data.h", + "ax_enum_util.cc", + "ax_enum_util.h", "ax_event_generator.cc", "ax_event_generator.h", "ax_export.h", @@ -81,7 +90,7 @@ component("accessibility") { defines = [ "ACCESSIBILITY_IMPLEMENTATION" ] public_deps = [ - ":ax_gen", + ":ax_enums_mojo", "//base", "//base:i18n", "//ui/base", @@ -134,21 +143,6 @@ component("accessibility") { } } -if (is_android) { - android_library("ui_accessibility_java") { - deps = [ - "//third_party/android_tools:android_support_annotations_java", - ] - srcjar_deps = [ ":ax_enumerations_srcjar" ] - } - - java_cpp_enum("ax_enumerations_srcjar") { - sources = [ - "ax_enums.idl", - ] - } -} - static_library("test_support") { testonly = true sources = [ @@ -186,7 +180,7 @@ test("accessibility_unittests") { deps = [ ":accessibility", - ":ax_gen", + ":ax_enums_mojo", ":test_support", "//base", "//base/test:run_all_unittests", @@ -207,17 +201,6 @@ test("accessibility_unittests") { } } -json_schema_api("ax_gen") { - sources = [ - "ax_enums.idl", - ] - deps = [ - "//base/third_party/dynamic_annotations", - ] - root_namespace = "ui" - schemas = true -} - fuzzer_test("ax_tree_fuzzer") { sources = [ "ax_tree_fuzzer.cc", diff --git a/chromium/ui/accessibility/OWNERS b/chromium/ui/accessibility/OWNERS index 72709ebff2a..bdb5819a93b 100644 --- a/chromium/ui/accessibility/OWNERS +++ b/chromium/ui/accessibility/OWNERS @@ -5,5 +5,8 @@ nektar@chromium.org dougt@chromium.org aleventhal@chromium.org +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS + # TEAM: chromium-accessibility@chromium.org # COMPONENT: Internals>Accessibility diff --git a/chromium/ui/accessibility/PRESUBMIT.py b/chromium/ui/accessibility/PRESUBMIT.py index f953d4f98a6..500b1cc607e 100644 --- a/chromium/ui/accessibility/PRESUBMIT.py +++ b/chromium/ui/accessibility/PRESUBMIT.py @@ -4,9 +4,9 @@ """Presubmit script for ui/accessibility.""" -import os, re +import os, re, json -AX_IDL = 'ui/accessibility/ax_enums.idl' +AX_MOJOM = 'ui/accessibility/ax_enums.mojom' AUTOMATION_IDL = 'chrome/common/extensions/api/automation.idl' AX_JS_FILE = 'content/browser/resources/accessibility/accessibility.js' @@ -16,7 +16,15 @@ def InitialLowerCamelCase(unix_name): words = unix_name.split('_') return words[0] + ''.join(word.capitalize() for word in words[1:]) -# Given a full path to an IDL file containing enum definitions, +def CamelToLowerHacker(str): + out = '' + for i in range(len(str)): + if str[i] >= 'A' and str[i] <= 'Z' and out: + out += '_' + out += str[i] + return out.lower() + +# Given a full path to an IDL or MOJOM file containing enum definitions, # parse the file for enums and return a dict mapping the enum name # to a list of values for that enum. def GetEnumsFromFile(fullpath): @@ -45,7 +53,15 @@ def GetEnumsFromFile(fullpath): m = re.search('([\w]+)', line) if m: enums.setdefault(enum_name, []) - enums[enum_name].append(m.group(1)) + enum_value = m.group(1) + if (enum_value[0] == 'k' and + enum_value[1] == enum_value[1].upper()): + enum_value = CamelToLowerHacker(enum_value[1:]) + if enum_value == 'none' or enum_value == 'last': + continue + if enum_value == 'active_descendant_changed': + enum_value = 'activedescendantchanged' + enums[enum_name].append(enum_value) return enums @@ -57,7 +73,7 @@ def CheckMatchingEnum(ax_enums, output_api): if ax_enum_name not in ax_enums: errs.append(output_api.PresubmitError( - 'Expected %s to have an enum named %s' % (AX_IDL, ax_enum_name))) + 'Expected %s to have an enum named %s' % (AX_MOJOM, ax_enum_name))) return if automation_enum_name not in automation_enums: errs.append(output_api.PresubmitError( @@ -73,7 +89,7 @@ def CheckMatchingEnum(ax_enums, else: errs.append(output_api.PresubmitError( 'Found %s.%s in %s, but did not find %s.%s in %s' % ( - ax_enum_name, value, AX_IDL, + ax_enum_name, value, AX_MOJOM, automation_enum_name, InitialLowerCamelCase(value), AUTOMATION_IDL))) # Should be no remaining items @@ -82,11 +98,11 @@ def CheckMatchingEnum(ax_enums, 'Found %s.%s in %s, but did not find %s.%s in %s' % ( automation_enum_name, value, AUTOMATION_IDL, ax_enum_name, InitialLowerCamelCase(value), - AX_IDL))) + AX_MOJOM))) def CheckEnumsMatch(input_api, output_api): repo_root = input_api.change.RepositoryRoot() - ax_enums = GetEnumsFromFile(os.path.join(repo_root, AX_IDL)) + ax_enums = GetEnumsFromFile(os.path.join(repo_root, AX_MOJOM)) automation_enums = GetEnumsFromFile(os.path.join(repo_root, AUTOMATION_IDL)) # Focused state only exists in automation. @@ -95,15 +111,15 @@ def CheckEnumsMatch(input_api, output_api): automation_enums['StateType'].remove('offscreen') errs = [] - CheckMatchingEnum(ax_enums, 'AXRole', automation_enums, 'RoleType', errs, + CheckMatchingEnum(ax_enums, 'Role', automation_enums, 'RoleType', errs, output_api) - CheckMatchingEnum(ax_enums, 'AXState', automation_enums, 'StateType', errs, + CheckMatchingEnum(ax_enums, 'State', automation_enums, 'StateType', errs, output_api) - CheckMatchingEnum(ax_enums, 'AXEvent', automation_enums, 'EventType', errs, + CheckMatchingEnum(ax_enums, 'Event', automation_enums, 'EventType', errs, output_api) - CheckMatchingEnum(ax_enums, 'AXNameFrom', automation_enums, 'NameFromType', + CheckMatchingEnum(ax_enums, 'NameFrom', automation_enums, 'NameFromType', errs, output_api) - CheckMatchingEnum(ax_enums, 'AXRestriction', automation_enums, + CheckMatchingEnum(ax_enums, 'Restriction', automation_enums, 'Restriction', errs, output_api) return errs @@ -180,7 +196,7 @@ def CheckChangeOnUpload(input_api, output_api): errs = [] for path in input_api.LocalPaths(): path = path.replace('\\', '/') - if AX_IDL == path: + if AX_MOJOM == path: errs.extend(CheckEnumsMatch(input_api, output_api)) if AX_MODE_HEADER == path: @@ -192,10 +208,14 @@ def CheckChangeOnCommit(input_api, output_api): errs = [] for path in input_api.LocalPaths(): path = path.replace('\\', '/') - if AX_IDL == path: + if AX_MOJOM == path: errs.extend(CheckEnumsMatch(input_api, output_api)) if AX_MODE_HEADER == path: errs.extend(CheckModesMatch(input_api, output_api)) return errs + +# Run this script directly to dump its keys, for debugging. +if __name__ == '__main__': + print json.dumps(GetEnumsFromFile(AX_MOJOM), sort_keys=True, indent=4) diff --git a/chromium/ui/accessibility/ax_action_data.cc b/chromium/ui/accessibility/ax_action_data.cc index bca145a9119..3024f145491 100644 --- a/chromium/ui/accessibility/ax_action_data.cc +++ b/chromium/ui/accessibility/ax_action_data.cc @@ -10,6 +10,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_enum_util.h" using base::IntToString; @@ -19,18 +20,27 @@ AXActionData::AXActionData() = default; AXActionData::AXActionData(const AXActionData& other) = default; AXActionData::~AXActionData() = default; +namespace { + +bool IsFlagSet(uint32_t bitfield, ax::mojom::ActionFlags flag) { + return 0 != (bitfield & (1 << static_cast<uint32_t>(flag))); +} + +} // namespace + // Note that this includes an initial space character if nonempty, but -// that works fine because this is normally printed by AXAction::ToString. +// that works fine because this is normally printed by +// ax::mojom::Action::ToString. std::string AXActionData::ToString() const { std::string result = ui::ToString(action); if (target_node_id != -1) result += " target_node_id=" + IntToString(target_node_id); - if (flags & (1 << ui::AX_ACTION_FLAGS_REQUEST_IMAGES)) + if (IsFlagSet(flags, ax::mojom::ActionFlags::kRequestImages)) result += " flag_request_images"; - if (flags & (1 << ui::AX_ACTION_FLAGS_REQUEST_INLINE_TEXT_BOXES)) + if (IsFlagSet(flags, ax::mojom::ActionFlags::kRequestInlineTextBoxes)) result += " flag_request_inline_text_boxes"; if (anchor_node_id != -1) { diff --git a/chromium/ui/accessibility/ax_action_data.h b/chromium/ui/accessibility/ax_action_data.h index 5cd03eed7a3..37efaffb9cc 100644 --- a/chromium/ui/accessibility/ax_action_data.h +++ b/chromium/ui/accessibility/ax_action_data.h @@ -6,7 +6,7 @@ #define UI_ACCESSIBILITY_AX_ACTION_DATA_H_ #include "base/strings/string16.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" #include "ui/gfx/geometry/rect.h" @@ -25,11 +25,11 @@ struct AX_EXPORT AXActionData { // This is a simple serializable struct. All member variables should be // public and copyable. - // See the AXAction enums in ax_enums.idl for explanations of which + // See the ax::mojom::Action enums in ax_enums.idl for explanations of which // parameters apply. // The action to take. - AXAction action = AX_ACTION_NONE; + ax::mojom::Action action = ax::mojom::Action::kNone; // The ID of the tree that this action should be performed on. int target_tree_id = -1; @@ -43,7 +43,7 @@ struct AX_EXPORT AXActionData { // The request id of this action tracked by the client. int request_id = -1; - // Use enums from AXActionFlags + // Use enums from ax::mojom::ActionFlags int flags = 0; // For an action that creates a selection, the selection anchor and focus @@ -67,7 +67,7 @@ struct AX_EXPORT AXActionData { base::string16 value; // The event to fire in response to a HIT_TEST action. - AXEvent hit_test_event_to_fire = AX_EVENT_NONE; + ax::mojom::Event hit_test_event_to_fire = ax::mojom::Event::kNone; }; } // namespace ui diff --git a/chromium/ui/accessibility/ax_enum_util.cc b/chromium/ui/accessibility/ax_enum_util.cc new file mode 100644 index 00000000000..f47b11a714e --- /dev/null +++ b/chromium/ui/accessibility/ax_enum_util.cc @@ -0,0 +1,2233 @@ +// Copyright 2018 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/accessibility/ax_enum_util.h" + +namespace ui { + +const char* ToString(ax::mojom::Event event) { + switch (event) { + case ax::mojom::Event::kNone: + return "none"; + case ax::mojom::Event::kActiveDescendantChanged: + return "activedescendantchanged"; + case ax::mojom::Event::kAlert: + return "alert"; + case ax::mojom::Event::kAriaAttributeChanged: + return "ariaAttributeChanged"; + case ax::mojom::Event::kAutocorrectionOccured: + return "autocorrectionOccured"; + case ax::mojom::Event::kBlur: + return "blur"; + case ax::mojom::Event::kCheckedStateChanged: + return "checkedStateChanged"; + case ax::mojom::Event::kChildrenChanged: + return "childrenChanged"; + case ax::mojom::Event::kClicked: + return "clicked"; + case ax::mojom::Event::kDocumentSelectionChanged: + return "documentSelectionChanged"; + case ax::mojom::Event::kExpandedChanged: + return "expandedChanged"; + case ax::mojom::Event::kFocus: + return "focus"; + case ax::mojom::Event::kHide: + return "hide"; + case ax::mojom::Event::kHitTestResult: + return "hitTestResult"; + case ax::mojom::Event::kHover: + return "hover"; + case ax::mojom::Event::kImageFrameUpdated: + return "imageFrameUpdated"; + case ax::mojom::Event::kInvalidStatusChanged: + return "invalidStatusChanged"; + case ax::mojom::Event::kLayoutComplete: + return "layoutComplete"; + case ax::mojom::Event::kLiveRegionCreated: + return "liveRegionCreated"; + case ax::mojom::Event::kLiveRegionChanged: + return "liveRegionChanged"; + case ax::mojom::Event::kLoadComplete: + return "loadComplete"; + case ax::mojom::Event::kLocationChanged: + return "locationChanged"; + case ax::mojom::Event::kMediaStartedPlaying: + return "mediaStartedPlaying"; + case ax::mojom::Event::kMediaStoppedPlaying: + return "mediaStoppedPlaying"; + case ax::mojom::Event::kMenuEnd: + return "menuEnd"; + case ax::mojom::Event::kMenuListItemSelected: + return "menuListItemSelected"; + case ax::mojom::Event::kMenuListValueChanged: + return "menuListValueChanged"; + case ax::mojom::Event::kMenuPopupEnd: + return "menuPopupEnd"; + case ax::mojom::Event::kMenuPopupStart: + return "menuPopupStart"; + case ax::mojom::Event::kMenuStart: + return "menuStart"; + case ax::mojom::Event::kMouseCanceled: + return "mouseCanceled"; + case ax::mojom::Event::kMouseDragged: + return "mouseDragged"; + case ax::mojom::Event::kMouseMoved: + return "mouseMoved"; + case ax::mojom::Event::kMousePressed: + return "mousePressed"; + case ax::mojom::Event::kMouseReleased: + return "mouseReleased"; + case ax::mojom::Event::kRowCollapsed: + return "rowCollapsed"; + case ax::mojom::Event::kRowCountChanged: + return "rowCountChanged"; + case ax::mojom::Event::kRowExpanded: + return "rowExpanded"; + case ax::mojom::Event::kScrollPositionChanged: + return "scrollPositionChanged"; + case ax::mojom::Event::kScrolledToAnchor: + return "scrolledToAnchor"; + case ax::mojom::Event::kSelectedChildrenChanged: + return "selectedChildrenChanged"; + case ax::mojom::Event::kSelection: + return "selection"; + case ax::mojom::Event::kSelectionAdd: + return "selectionAdd"; + case ax::mojom::Event::kSelectionRemove: + return "selectionRemove"; + case ax::mojom::Event::kShow: + return "show"; + case ax::mojom::Event::kTextChanged: + return "textChanged"; + case ax::mojom::Event::kTextSelectionChanged: + return "textSelectionChanged"; + case ax::mojom::Event::kTreeChanged: + return "treeChanged"; + case ax::mojom::Event::kValueChanged: + return "valueChanged"; + } + + return ""; +} + +ax::mojom::Event ParseEvent(const char* event) { + if (0 == strcmp(event, "none")) + return ax::mojom::Event::kNone; + if (0 == strcmp(event, "activedescendantchanged")) + return ax::mojom::Event::kActiveDescendantChanged; + if (0 == strcmp(event, "alert")) + return ax::mojom::Event::kAlert; + if (0 == strcmp(event, "ariaAttributeChanged")) + return ax::mojom::Event::kAriaAttributeChanged; + if (0 == strcmp(event, "autocorrectionOccured")) + return ax::mojom::Event::kAutocorrectionOccured; + if (0 == strcmp(event, "blur")) + return ax::mojom::Event::kBlur; + if (0 == strcmp(event, "checkedStateChanged")) + return ax::mojom::Event::kCheckedStateChanged; + if (0 == strcmp(event, "childrenChanged")) + return ax::mojom::Event::kChildrenChanged; + if (0 == strcmp(event, "clicked")) + return ax::mojom::Event::kClicked; + if (0 == strcmp(event, "documentSelectionChanged")) + return ax::mojom::Event::kDocumentSelectionChanged; + if (0 == strcmp(event, "expandedChanged")) + return ax::mojom::Event::kExpandedChanged; + if (0 == strcmp(event, "focus")) + return ax::mojom::Event::kFocus; + if (0 == strcmp(event, "hide")) + return ax::mojom::Event::kHide; + if (0 == strcmp(event, "hitTestResult")) + return ax::mojom::Event::kHitTestResult; + if (0 == strcmp(event, "hover")) + return ax::mojom::Event::kHover; + if (0 == strcmp(event, "imageFrameUpdated")) + return ax::mojom::Event::kImageFrameUpdated; + if (0 == strcmp(event, "invalidStatusChanged")) + return ax::mojom::Event::kInvalidStatusChanged; + if (0 == strcmp(event, "layoutComplete")) + return ax::mojom::Event::kLayoutComplete; + if (0 == strcmp(event, "liveRegionCreated")) + return ax::mojom::Event::kLiveRegionCreated; + if (0 == strcmp(event, "liveRegionChanged")) + return ax::mojom::Event::kLiveRegionChanged; + if (0 == strcmp(event, "loadComplete")) + return ax::mojom::Event::kLoadComplete; + if (0 == strcmp(event, "locationChanged")) + return ax::mojom::Event::kLocationChanged; + if (0 == strcmp(event, "mediaStartedPlaying")) + return ax::mojom::Event::kMediaStartedPlaying; + if (0 == strcmp(event, "mediaStoppedPlaying")) + return ax::mojom::Event::kMediaStoppedPlaying; + if (0 == strcmp(event, "menuEnd")) + return ax::mojom::Event::kMenuEnd; + if (0 == strcmp(event, "menuListItemSelected")) + return ax::mojom::Event::kMenuListItemSelected; + if (0 == strcmp(event, "menuListValueChanged")) + return ax::mojom::Event::kMenuListValueChanged; + if (0 == strcmp(event, "menuPopupEnd")) + return ax::mojom::Event::kMenuPopupEnd; + if (0 == strcmp(event, "menuPopupStart")) + return ax::mojom::Event::kMenuPopupStart; + if (0 == strcmp(event, "menuStart")) + return ax::mojom::Event::kMenuStart; + if (0 == strcmp(event, "mouseCanceled")) + return ax::mojom::Event::kMouseCanceled; + if (0 == strcmp(event, "mouseDragged")) + return ax::mojom::Event::kMouseDragged; + if (0 == strcmp(event, "mouseMoved")) + return ax::mojom::Event::kMouseMoved; + if (0 == strcmp(event, "mousePressed")) + return ax::mojom::Event::kMousePressed; + if (0 == strcmp(event, "mouseReleased")) + return ax::mojom::Event::kMouseReleased; + if (0 == strcmp(event, "rowCollapsed")) + return ax::mojom::Event::kRowCollapsed; + if (0 == strcmp(event, "rowCountChanged")) + return ax::mojom::Event::kRowCountChanged; + if (0 == strcmp(event, "rowExpanded")) + return ax::mojom::Event::kRowExpanded; + if (0 == strcmp(event, "scrollPositionChanged")) + return ax::mojom::Event::kScrollPositionChanged; + if (0 == strcmp(event, "scrolledToAnchor")) + return ax::mojom::Event::kScrolledToAnchor; + if (0 == strcmp(event, "selectedChildrenChanged")) + return ax::mojom::Event::kSelectedChildrenChanged; + if (0 == strcmp(event, "selection")) + return ax::mojom::Event::kSelection; + if (0 == strcmp(event, "selectionAdd")) + return ax::mojom::Event::kSelectionAdd; + if (0 == strcmp(event, "selectionRemove")) + return ax::mojom::Event::kSelectionRemove; + if (0 == strcmp(event, "show")) + return ax::mojom::Event::kShow; + if (0 == strcmp(event, "textChanged")) + return ax::mojom::Event::kTextChanged; + if (0 == strcmp(event, "textSelectionChanged")) + return ax::mojom::Event::kTextSelectionChanged; + if (0 == strcmp(event, "treeChanged")) + return ax::mojom::Event::kTreeChanged; + if (0 == strcmp(event, "valueChanged")) + return ax::mojom::Event::kValueChanged; + return ax::mojom::Event::kNone; +} + +const char* ToString(ax::mojom::Role role) { + switch (role) { + case ax::mojom::Role::kNone: + return "none"; + case ax::mojom::Role::kAbbr: + return "abbr"; + case ax::mojom::Role::kAlertDialog: + return "alertDialog"; + case ax::mojom::Role::kAlert: + return "alert"; + case ax::mojom::Role::kAnchor: + return "anchor"; + case ax::mojom::Role::kAnnotation: + return "annotation"; + case ax::mojom::Role::kApplication: + return "application"; + case ax::mojom::Role::kArticle: + return "article"; + case ax::mojom::Role::kAudio: + return "audio"; + case ax::mojom::Role::kBanner: + return "banner"; + case ax::mojom::Role::kBlockquote: + return "blockquote"; + case ax::mojom::Role::kButton: + return "button"; + case ax::mojom::Role::kCanvas: + return "canvas"; + case ax::mojom::Role::kCaption: + return "caption"; + case ax::mojom::Role::kCaret: + return "caret"; + case ax::mojom::Role::kCell: + return "cell"; + case ax::mojom::Role::kCheckBox: + return "checkBox"; + case ax::mojom::Role::kClient: + return "client"; + case ax::mojom::Role::kColorWell: + return "colorWell"; + case ax::mojom::Role::kColumnHeader: + return "columnHeader"; + case ax::mojom::Role::kColumn: + return "column"; + case ax::mojom::Role::kComboBoxGrouping: + return "comboBoxGrouping"; + case ax::mojom::Role::kComboBoxMenuButton: + return "comboBoxMenuButton"; + case ax::mojom::Role::kComplementary: + return "complementary"; + case ax::mojom::Role::kContentInfo: + return "contentInfo"; + case ax::mojom::Role::kDate: + return "date"; + case ax::mojom::Role::kDateTime: + return "dateTime"; + case ax::mojom::Role::kDefinition: + return "definition"; + case ax::mojom::Role::kDescriptionListDetail: + return "descriptionListDetail"; + case ax::mojom::Role::kDescriptionList: + return "descriptionList"; + case ax::mojom::Role::kDescriptionListTerm: + return "descriptionListTerm"; + case ax::mojom::Role::kDesktop: + return "desktop"; + case ax::mojom::Role::kDetails: + return "details"; + case ax::mojom::Role::kDialog: + return "dialog"; + case ax::mojom::Role::kDirectory: + return "directory"; + case ax::mojom::Role::kDisclosureTriangle: + return "disclosureTriangle"; + case ax::mojom::Role::kDocument: + return "document"; + case ax::mojom::Role::kEmbeddedObject: + return "embeddedObject"; + case ax::mojom::Role::kFeed: + return "feed"; + case ax::mojom::Role::kFigcaption: + return "figcaption"; + case ax::mojom::Role::kFigure: + return "figure"; + case ax::mojom::Role::kFooter: + return "footer"; + case ax::mojom::Role::kForm: + return "form"; + case ax::mojom::Role::kGenericContainer: + return "genericContainer"; + case ax::mojom::Role::kGrid: + return "grid"; + case ax::mojom::Role::kGroup: + return "group"; + case ax::mojom::Role::kHeading: + return "heading"; + case ax::mojom::Role::kIframe: + return "iframe"; + case ax::mojom::Role::kIframePresentational: + return "iframePresentational"; + case ax::mojom::Role::kIgnored: + return "ignored"; + case ax::mojom::Role::kImageMap: + return "imageMap"; + case ax::mojom::Role::kImage: + return "image"; + case ax::mojom::Role::kInlineTextBox: + return "inlineTextBox"; + case ax::mojom::Role::kInputTime: + return "inputTime"; + case ax::mojom::Role::kLabelText: + return "labelText"; + case ax::mojom::Role::kLayoutTable: + return "layoutTable"; + case ax::mojom::Role::kLayoutTableCell: + return "layoutTableCell"; + case ax::mojom::Role::kLayoutTableColumn: + return "layoutTableColumn"; + case ax::mojom::Role::kLayoutTableRow: + return "layoutTableRow"; + case ax::mojom::Role::kLegend: + return "legend"; + case ax::mojom::Role::kLineBreak: + return "lineBreak"; + case ax::mojom::Role::kLink: + return "link"; + case ax::mojom::Role::kListBoxOption: + return "listBoxOption"; + case ax::mojom::Role::kListBox: + return "listBox"; + case ax::mojom::Role::kListItem: + return "listItem"; + case ax::mojom::Role::kListMarker: + return "listMarker"; + case ax::mojom::Role::kList: + return "list"; + case ax::mojom::Role::kLocationBar: + return "locationBar"; + case ax::mojom::Role::kLog: + return "log"; + case ax::mojom::Role::kMain: + return "main"; + case ax::mojom::Role::kMark: + return "mark"; + case ax::mojom::Role::kMarquee: + return "marquee"; + case ax::mojom::Role::kMath: + return "math"; + case ax::mojom::Role::kMenu: + return "menu"; + case ax::mojom::Role::kMenuBar: + return "menuBar"; + case ax::mojom::Role::kMenuButton: + return "menuButton"; + case ax::mojom::Role::kMenuItem: + return "menuItem"; + case ax::mojom::Role::kMenuItemCheckBox: + return "menuItemCheckBox"; + case ax::mojom::Role::kMenuItemRadio: + return "menuItemRadio"; + case ax::mojom::Role::kMenuListOption: + return "menuListOption"; + case ax::mojom::Role::kMenuListPopup: + return "menuListPopup"; + case ax::mojom::Role::kMeter: + return "meter"; + case ax::mojom::Role::kNavigation: + return "navigation"; + case ax::mojom::Role::kNote: + return "note"; + case ax::mojom::Role::kPane: + return "pane"; + case ax::mojom::Role::kParagraph: + return "paragraph"; + case ax::mojom::Role::kPopUpButton: + return "popUpButton"; + case ax::mojom::Role::kPre: + return "pre"; + case ax::mojom::Role::kPresentational: + return "presentational"; + case ax::mojom::Role::kProgressIndicator: + return "progressIndicator"; + case ax::mojom::Role::kRadioButton: + return "radioButton"; + case ax::mojom::Role::kRadioGroup: + return "radioGroup"; + case ax::mojom::Role::kRegion: + return "region"; + case ax::mojom::Role::kRootWebArea: + return "rootWebArea"; + case ax::mojom::Role::kRowHeader: + return "rowHeader"; + case ax::mojom::Role::kRow: + return "row"; + case ax::mojom::Role::kRuby: + return "ruby"; + case ax::mojom::Role::kSvgRoot: + return "svgRoot"; + case ax::mojom::Role::kScrollBar: + return "scrollBar"; + case ax::mojom::Role::kSearch: + return "search"; + case ax::mojom::Role::kSearchBox: + return "searchBox"; + case ax::mojom::Role::kSlider: + return "slider"; + case ax::mojom::Role::kSliderThumb: + return "sliderThumb"; + case ax::mojom::Role::kSpinButtonPart: + return "spinButtonPart"; + case ax::mojom::Role::kSpinButton: + return "spinButton"; + case ax::mojom::Role::kSplitter: + return "splitter"; + case ax::mojom::Role::kStaticText: + return "staticText"; + case ax::mojom::Role::kStatus: + return "status"; + case ax::mojom::Role::kSwitch: + return "switch"; + case ax::mojom::Role::kTabList: + return "tabList"; + case ax::mojom::Role::kTabPanel: + return "tabPanel"; + case ax::mojom::Role::kTab: + return "tab"; + case ax::mojom::Role::kTableHeaderContainer: + return "tableHeaderContainer"; + case ax::mojom::Role::kTable: + return "table"; + case ax::mojom::Role::kTerm: + return "term"; + case ax::mojom::Role::kTextField: + return "textField"; + case ax::mojom::Role::kTextFieldWithComboBox: + return "textFieldWithComboBox"; + case ax::mojom::Role::kTime: + return "time"; + case ax::mojom::Role::kTimer: + return "timer"; + case ax::mojom::Role::kTitleBar: + return "titleBar"; + case ax::mojom::Role::kToggleButton: + return "toggleButton"; + case ax::mojom::Role::kToolbar: + return "toolbar"; + case ax::mojom::Role::kTreeGrid: + return "treeGrid"; + case ax::mojom::Role::kTreeItem: + return "treeItem"; + case ax::mojom::Role::kTree: + return "tree"; + case ax::mojom::Role::kUnknown: + return "unknown"; + case ax::mojom::Role::kTooltip: + return "tooltip"; + case ax::mojom::Role::kVideo: + return "video"; + case ax::mojom::Role::kWebArea: + return "webArea"; + case ax::mojom::Role::kWebView: + return "webView"; + case ax::mojom::Role::kWindow: + return "window"; + } + + return ""; +} + +ax::mojom::Role ParseRole(const char* role) { + if (0 == strcmp(role, "none")) + return ax::mojom::Role::kNone; + if (0 == strcmp(role, "abbr")) + return ax::mojom::Role::kAbbr; + if (0 == strcmp(role, "alertDialog")) + return ax::mojom::Role::kAlertDialog; + if (0 == strcmp(role, "alert")) + return ax::mojom::Role::kAlert; + if (0 == strcmp(role, "anchor")) + return ax::mojom::Role::kAnchor; + if (0 == strcmp(role, "annotation")) + return ax::mojom::Role::kAnnotation; + if (0 == strcmp(role, "application")) + return ax::mojom::Role::kApplication; + if (0 == strcmp(role, "article")) + return ax::mojom::Role::kArticle; + if (0 == strcmp(role, "audio")) + return ax::mojom::Role::kAudio; + if (0 == strcmp(role, "banner")) + return ax::mojom::Role::kBanner; + if (0 == strcmp(role, "blockquote")) + return ax::mojom::Role::kBlockquote; + if (0 == strcmp(role, "button")) + return ax::mojom::Role::kButton; + if (0 == strcmp(role, "canvas")) + return ax::mojom::Role::kCanvas; + if (0 == strcmp(role, "caption")) + return ax::mojom::Role::kCaption; + if (0 == strcmp(role, "caret")) + return ax::mojom::Role::kCaret; + if (0 == strcmp(role, "cell")) + return ax::mojom::Role::kCell; + if (0 == strcmp(role, "checkBox")) + return ax::mojom::Role::kCheckBox; + if (0 == strcmp(role, "client")) + return ax::mojom::Role::kClient; + if (0 == strcmp(role, "colorWell")) + return ax::mojom::Role::kColorWell; + if (0 == strcmp(role, "columnHeader")) + return ax::mojom::Role::kColumnHeader; + if (0 == strcmp(role, "column")) + return ax::mojom::Role::kColumn; + if (0 == strcmp(role, "comboBoxGrouping")) + return ax::mojom::Role::kComboBoxGrouping; + if (0 == strcmp(role, "comboBoxMenuButton")) + return ax::mojom::Role::kComboBoxMenuButton; + if (0 == strcmp(role, "complementary")) + return ax::mojom::Role::kComplementary; + if (0 == strcmp(role, "contentInfo")) + return ax::mojom::Role::kContentInfo; + if (0 == strcmp(role, "date")) + return ax::mojom::Role::kDate; + if (0 == strcmp(role, "dateTime")) + return ax::mojom::Role::kDateTime; + if (0 == strcmp(role, "definition")) + return ax::mojom::Role::kDefinition; + if (0 == strcmp(role, "descriptionListDetail")) + return ax::mojom::Role::kDescriptionListDetail; + if (0 == strcmp(role, "descriptionList")) + return ax::mojom::Role::kDescriptionList; + if (0 == strcmp(role, "descriptionListTerm")) + return ax::mojom::Role::kDescriptionListTerm; + if (0 == strcmp(role, "desktop")) + return ax::mojom::Role::kDesktop; + if (0 == strcmp(role, "details")) + return ax::mojom::Role::kDetails; + if (0 == strcmp(role, "dialog")) + return ax::mojom::Role::kDialog; + if (0 == strcmp(role, "directory")) + return ax::mojom::Role::kDirectory; + if (0 == strcmp(role, "disclosureTriangle")) + return ax::mojom::Role::kDisclosureTriangle; + if (0 == strcmp(role, "document")) + return ax::mojom::Role::kDocument; + if (0 == strcmp(role, "embeddedObject")) + return ax::mojom::Role::kEmbeddedObject; + if (0 == strcmp(role, "feed")) + return ax::mojom::Role::kFeed; + if (0 == strcmp(role, "figcaption")) + return ax::mojom::Role::kFigcaption; + if (0 == strcmp(role, "figure")) + return ax::mojom::Role::kFigure; + if (0 == strcmp(role, "footer")) + return ax::mojom::Role::kFooter; + if (0 == strcmp(role, "form")) + return ax::mojom::Role::kForm; + if (0 == strcmp(role, "genericContainer")) + return ax::mojom::Role::kGenericContainer; + if (0 == strcmp(role, "grid")) + return ax::mojom::Role::kGrid; + if (0 == strcmp(role, "group")) + return ax::mojom::Role::kGroup; + if (0 == strcmp(role, "heading")) + return ax::mojom::Role::kHeading; + if (0 == strcmp(role, "iframe")) + return ax::mojom::Role::kIframe; + if (0 == strcmp(role, "iframePresentational")) + return ax::mojom::Role::kIframePresentational; + if (0 == strcmp(role, "ignored")) + return ax::mojom::Role::kIgnored; + if (0 == strcmp(role, "imageMap")) + return ax::mojom::Role::kImageMap; + if (0 == strcmp(role, "image")) + return ax::mojom::Role::kImage; + if (0 == strcmp(role, "inlineTextBox")) + return ax::mojom::Role::kInlineTextBox; + if (0 == strcmp(role, "inputTime")) + return ax::mojom::Role::kInputTime; + if (0 == strcmp(role, "labelText")) + return ax::mojom::Role::kLabelText; + if (0 == strcmp(role, "layoutTable")) + return ax::mojom::Role::kLayoutTable; + if (0 == strcmp(role, "layoutTableCell")) + return ax::mojom::Role::kLayoutTableCell; + if (0 == strcmp(role, "layoutTableColumn")) + return ax::mojom::Role::kLayoutTableColumn; + if (0 == strcmp(role, "layoutTableRow")) + return ax::mojom::Role::kLayoutTableRow; + if (0 == strcmp(role, "legend")) + return ax::mojom::Role::kLegend; + if (0 == strcmp(role, "lineBreak")) + return ax::mojom::Role::kLineBreak; + if (0 == strcmp(role, "link")) + return ax::mojom::Role::kLink; + if (0 == strcmp(role, "listBoxOption")) + return ax::mojom::Role::kListBoxOption; + if (0 == strcmp(role, "listBox")) + return ax::mojom::Role::kListBox; + if (0 == strcmp(role, "listItem")) + return ax::mojom::Role::kListItem; + if (0 == strcmp(role, "listMarker")) + return ax::mojom::Role::kListMarker; + if (0 == strcmp(role, "list")) + return ax::mojom::Role::kList; + if (0 == strcmp(role, "locationBar")) + return ax::mojom::Role::kLocationBar; + if (0 == strcmp(role, "log")) + return ax::mojom::Role::kLog; + if (0 == strcmp(role, "main")) + return ax::mojom::Role::kMain; + if (0 == strcmp(role, "mark")) + return ax::mojom::Role::kMark; + if (0 == strcmp(role, "marquee")) + return ax::mojom::Role::kMarquee; + if (0 == strcmp(role, "math")) + return ax::mojom::Role::kMath; + if (0 == strcmp(role, "menu")) + return ax::mojom::Role::kMenu; + if (0 == strcmp(role, "menuBar")) + return ax::mojom::Role::kMenuBar; + if (0 == strcmp(role, "menuButton")) + return ax::mojom::Role::kMenuButton; + if (0 == strcmp(role, "menuItem")) + return ax::mojom::Role::kMenuItem; + if (0 == strcmp(role, "menuItemCheckBox")) + return ax::mojom::Role::kMenuItemCheckBox; + if (0 == strcmp(role, "menuItemRadio")) + return ax::mojom::Role::kMenuItemRadio; + if (0 == strcmp(role, "menuListOption")) + return ax::mojom::Role::kMenuListOption; + if (0 == strcmp(role, "menuListPopup")) + return ax::mojom::Role::kMenuListPopup; + if (0 == strcmp(role, "meter")) + return ax::mojom::Role::kMeter; + if (0 == strcmp(role, "navigation")) + return ax::mojom::Role::kNavigation; + if (0 == strcmp(role, "note")) + return ax::mojom::Role::kNote; + if (0 == strcmp(role, "pane")) + return ax::mojom::Role::kPane; + if (0 == strcmp(role, "paragraph")) + return ax::mojom::Role::kParagraph; + if (0 == strcmp(role, "popUpButton")) + return ax::mojom::Role::kPopUpButton; + if (0 == strcmp(role, "pre")) + return ax::mojom::Role::kPre; + if (0 == strcmp(role, "presentational")) + return ax::mojom::Role::kPresentational; + if (0 == strcmp(role, "progressIndicator")) + return ax::mojom::Role::kProgressIndicator; + if (0 == strcmp(role, "radioButton")) + return ax::mojom::Role::kRadioButton; + if (0 == strcmp(role, "radioGroup")) + return ax::mojom::Role::kRadioGroup; + if (0 == strcmp(role, "region")) + return ax::mojom::Role::kRegion; + if (0 == strcmp(role, "rootWebArea")) + return ax::mojom::Role::kRootWebArea; + if (0 == strcmp(role, "rowHeader")) + return ax::mojom::Role::kRowHeader; + if (0 == strcmp(role, "row")) + return ax::mojom::Role::kRow; + if (0 == strcmp(role, "ruby")) + return ax::mojom::Role::kRuby; + if (0 == strcmp(role, "svgRoot")) + return ax::mojom::Role::kSvgRoot; + if (0 == strcmp(role, "scrollBar")) + return ax::mojom::Role::kScrollBar; + if (0 == strcmp(role, "search")) + return ax::mojom::Role::kSearch; + if (0 == strcmp(role, "searchBox")) + return ax::mojom::Role::kSearchBox; + if (0 == strcmp(role, "slider")) + return ax::mojom::Role::kSlider; + if (0 == strcmp(role, "sliderThumb")) + return ax::mojom::Role::kSliderThumb; + if (0 == strcmp(role, "spinButtonPart")) + return ax::mojom::Role::kSpinButtonPart; + if (0 == strcmp(role, "spinButton")) + return ax::mojom::Role::kSpinButton; + if (0 == strcmp(role, "splitter")) + return ax::mojom::Role::kSplitter; + if (0 == strcmp(role, "staticText")) + return ax::mojom::Role::kStaticText; + if (0 == strcmp(role, "status")) + return ax::mojom::Role::kStatus; + if (0 == strcmp(role, "switch")) + return ax::mojom::Role::kSwitch; + if (0 == strcmp(role, "tabList")) + return ax::mojom::Role::kTabList; + if (0 == strcmp(role, "tabPanel")) + return ax::mojom::Role::kTabPanel; + if (0 == strcmp(role, "tab")) + return ax::mojom::Role::kTab; + if (0 == strcmp(role, "tableHeaderContainer")) + return ax::mojom::Role::kTableHeaderContainer; + if (0 == strcmp(role, "table")) + return ax::mojom::Role::kTable; + if (0 == strcmp(role, "term")) + return ax::mojom::Role::kTerm; + if (0 == strcmp(role, "textField")) + return ax::mojom::Role::kTextField; + if (0 == strcmp(role, "textFieldWithComboBox")) + return ax::mojom::Role::kTextFieldWithComboBox; + if (0 == strcmp(role, "time")) + return ax::mojom::Role::kTime; + if (0 == strcmp(role, "timer")) + return ax::mojom::Role::kTimer; + if (0 == strcmp(role, "titleBar")) + return ax::mojom::Role::kTitleBar; + if (0 == strcmp(role, "toggleButton")) + return ax::mojom::Role::kToggleButton; + if (0 == strcmp(role, "toolbar")) + return ax::mojom::Role::kToolbar; + if (0 == strcmp(role, "treeGrid")) + return ax::mojom::Role::kTreeGrid; + if (0 == strcmp(role, "treeItem")) + return ax::mojom::Role::kTreeItem; + if (0 == strcmp(role, "tree")) + return ax::mojom::Role::kTree; + if (0 == strcmp(role, "unknown")) + return ax::mojom::Role::kUnknown; + if (0 == strcmp(role, "tooltip")) + return ax::mojom::Role::kTooltip; + if (0 == strcmp(role, "video")) + return ax::mojom::Role::kVideo; + if (0 == strcmp(role, "webArea")) + return ax::mojom::Role::kWebArea; + if (0 == strcmp(role, "webView")) + return ax::mojom::Role::kWebView; + if (0 == strcmp(role, "window")) + return ax::mojom::Role::kWindow; + return ax::mojom::Role::kNone; +} + +const char* ToString(ax::mojom::State state) { + switch (state) { + case ax::mojom::State::kNone: + return "none"; + case ax::mojom::State::kCollapsed: + return "collapsed"; + case ax::mojom::State::kDefault: + return "default"; + case ax::mojom::State::kEditable: + return "editable"; + case ax::mojom::State::kExpanded: + return "expanded"; + case ax::mojom::State::kFocusable: + return "focusable"; + case ax::mojom::State::kHaspopup: + return "haspopup"; + case ax::mojom::State::kHorizontal: + return "horizontal"; + case ax::mojom::State::kHovered: + return "hovered"; + case ax::mojom::State::kIgnored: + return "ignored"; + case ax::mojom::State::kInvisible: + return "invisible"; + case ax::mojom::State::kLinked: + return "linked"; + case ax::mojom::State::kMultiline: + return "multiline"; + case ax::mojom::State::kMultiselectable: + return "multiselectable"; + case ax::mojom::State::kProtected: + return "protected"; + case ax::mojom::State::kRequired: + return "required"; + case ax::mojom::State::kRichlyEditable: + return "richlyEditable"; + case ax::mojom::State::kSelectable: + return "selectable"; + case ax::mojom::State::kSelected: + return "selected"; + case ax::mojom::State::kVertical: + return "vertical"; + case ax::mojom::State::kVisited: + return "visited"; + } + + return ""; +} + +ax::mojom::State ParseState(const char* state) { + if (0 == strcmp(state, "none")) + return ax::mojom::State::kNone; + if (0 == strcmp(state, "collapsed")) + return ax::mojom::State::kCollapsed; + if (0 == strcmp(state, "default")) + return ax::mojom::State::kDefault; + if (0 == strcmp(state, "editable")) + return ax::mojom::State::kEditable; + if (0 == strcmp(state, "expanded")) + return ax::mojom::State::kExpanded; + if (0 == strcmp(state, "focusable")) + return ax::mojom::State::kFocusable; + if (0 == strcmp(state, "haspopup")) + return ax::mojom::State::kHaspopup; + if (0 == strcmp(state, "horizontal")) + return ax::mojom::State::kHorizontal; + if (0 == strcmp(state, "hovered")) + return ax::mojom::State::kHovered; + if (0 == strcmp(state, "ignored")) + return ax::mojom::State::kIgnored; + if (0 == strcmp(state, "invisible")) + return ax::mojom::State::kInvisible; + if (0 == strcmp(state, "linked")) + return ax::mojom::State::kLinked; + if (0 == strcmp(state, "multiline")) + return ax::mojom::State::kMultiline; + if (0 == strcmp(state, "multiselectable")) + return ax::mojom::State::kMultiselectable; + if (0 == strcmp(state, "protected")) + return ax::mojom::State::kProtected; + if (0 == strcmp(state, "required")) + return ax::mojom::State::kRequired; + if (0 == strcmp(state, "richlyEditable")) + return ax::mojom::State::kRichlyEditable; + if (0 == strcmp(state, "selectable")) + return ax::mojom::State::kSelectable; + if (0 == strcmp(state, "selected")) + return ax::mojom::State::kSelected; + if (0 == strcmp(state, "vertical")) + return ax::mojom::State::kVertical; + if (0 == strcmp(state, "visited")) + return ax::mojom::State::kVisited; + return ax::mojom::State::kNone; +} + +const char* ToString(ax::mojom::Action action) { + switch (action) { + case ax::mojom::Action::kNone: + return "none"; + case ax::mojom::Action::kBlur: + return "blur"; + case ax::mojom::Action::kCustomAction: + return "customAction"; + case ax::mojom::Action::kDecrement: + return "decrement"; + case ax::mojom::Action::kDoDefault: + return "doDefault"; + case ax::mojom::Action::kFocus: + return "focus"; + case ax::mojom::Action::kGetImageData: + return "getImageData"; + case ax::mojom::Action::kHitTest: + return "hitTest"; + case ax::mojom::Action::kIncrement: + return "increment"; + case ax::mojom::Action::kLoadInlineTextBoxes: + return "loadInlineTextBoxes"; + case ax::mojom::Action::kReplaceSelectedText: + return "replaceSelectedText"; + case ax::mojom::Action::kScrollBackward: + return "scrollBackward"; + case ax::mojom::Action::kScrollForward: + return "scrollForward"; + case ax::mojom::Action::kScrollUp: + return "scrollUp"; + case ax::mojom::Action::kScrollDown: + return "scrollDown"; + case ax::mojom::Action::kScrollLeft: + return "scrollLeft"; + case ax::mojom::Action::kScrollRight: + return "scrollRight"; + case ax::mojom::Action::kScrollToMakeVisible: + return "scrollToMakeVisible"; + case ax::mojom::Action::kScrollToPoint: + return "scrollToPoint"; + case ax::mojom::Action::kSetScrollOffset: + return "setScrollOffset"; + case ax::mojom::Action::kSetSelection: + return "setSelection"; + case ax::mojom::Action::kSetSequentialFocusNavigationStartingPoint: + return "setSequentialFocusNavigationStartingPoint"; + case ax::mojom::Action::kSetValue: + return "setValue"; + case ax::mojom::Action::kShowContextMenu: + return "showContextMenu"; + } + + return ""; +} + +ax::mojom::Action ParseAction(const char* action) { + if (0 == strcmp(action, "none")) + return ax::mojom::Action::kNone; + if (0 == strcmp(action, "blur")) + return ax::mojom::Action::kBlur; + if (0 == strcmp(action, "customAction")) + return ax::mojom::Action::kCustomAction; + if (0 == strcmp(action, "decrement")) + return ax::mojom::Action::kDecrement; + if (0 == strcmp(action, "doDefault")) + return ax::mojom::Action::kDoDefault; + if (0 == strcmp(action, "focus")) + return ax::mojom::Action::kFocus; + if (0 == strcmp(action, "getImageData")) + return ax::mojom::Action::kGetImageData; + if (0 == strcmp(action, "hitTest")) + return ax::mojom::Action::kHitTest; + if (0 == strcmp(action, "increment")) + return ax::mojom::Action::kIncrement; + if (0 == strcmp(action, "loadInlineTextBoxes")) + return ax::mojom::Action::kLoadInlineTextBoxes; + if (0 == strcmp(action, "replaceSelectedText")) + return ax::mojom::Action::kReplaceSelectedText; + if (0 == strcmp(action, "scrollBackward")) + return ax::mojom::Action::kScrollBackward; + if (0 == strcmp(action, "scrollForward")) + return ax::mojom::Action::kScrollForward; + if (0 == strcmp(action, "scrollUp")) + return ax::mojom::Action::kScrollUp; + if (0 == strcmp(action, "scrollDown")) + return ax::mojom::Action::kScrollDown; + if (0 == strcmp(action, "scrollLeft")) + return ax::mojom::Action::kScrollLeft; + if (0 == strcmp(action, "scrollRight")) + return ax::mojom::Action::kScrollRight; + if (0 == strcmp(action, "scrollToMakeVisible")) + return ax::mojom::Action::kScrollToMakeVisible; + if (0 == strcmp(action, "scrollToPoint")) + return ax::mojom::Action::kScrollToPoint; + if (0 == strcmp(action, "setScrollOffset")) + return ax::mojom::Action::kSetScrollOffset; + if (0 == strcmp(action, "setSelection")) + return ax::mojom::Action::kSetSelection; + if (0 == strcmp(action, "setSequentialFocusNavigationStartingPoint")) + return ax::mojom::Action::kSetSequentialFocusNavigationStartingPoint; + if (0 == strcmp(action, "setValue")) + return ax::mojom::Action::kSetValue; + if (0 == strcmp(action, "showContextMenu")) + return ax::mojom::Action::kShowContextMenu; + return ax::mojom::Action::kNone; +} + +const char* ToString(ax::mojom::ActionFlags action_flags) { + switch (action_flags) { + case ax::mojom::ActionFlags::kNone: + return "none"; + case ax::mojom::ActionFlags::kRequestImages: + return "requestImages"; + case ax::mojom::ActionFlags::kRequestInlineTextBoxes: + return "requestInlineTextBoxes"; + } + + return ""; +} + +ax::mojom::ActionFlags ParseActionFlags(const char* action_flags) { + if (0 == strcmp(action_flags, "none")) + return ax::mojom::ActionFlags::kNone; + if (0 == strcmp(action_flags, "requestImages")) + return ax::mojom::ActionFlags::kRequestImages; + if (0 == strcmp(action_flags, "requestInlineTextBoxes")) + return ax::mojom::ActionFlags::kRequestInlineTextBoxes; + return ax::mojom::ActionFlags::kNone; +} + +const char* ToString(ax::mojom::DefaultActionVerb default_action_verb) { + switch (default_action_verb) { + case ax::mojom::DefaultActionVerb::kNone: + return "none"; + case ax::mojom::DefaultActionVerb::kActivate: + return "activate"; + case ax::mojom::DefaultActionVerb::kCheck: + return "check"; + case ax::mojom::DefaultActionVerb::kClick: + return "click"; + case ax::mojom::DefaultActionVerb::kClickAncestor: + return "clickAncestor"; + case ax::mojom::DefaultActionVerb::kJump: + return "jump"; + case ax::mojom::DefaultActionVerb::kOpen: + return "open"; + case ax::mojom::DefaultActionVerb::kPress: + return "press"; + case ax::mojom::DefaultActionVerb::kSelect: + return "select"; + case ax::mojom::DefaultActionVerb::kUncheck: + return "uncheck"; + } + + return ""; +} + +ax::mojom::DefaultActionVerb ParseDefaultActionVerb( + const char* default_action_verb) { + if (0 == strcmp(default_action_verb, "none")) + return ax::mojom::DefaultActionVerb::kNone; + if (0 == strcmp(default_action_verb, "activate")) + return ax::mojom::DefaultActionVerb::kActivate; + if (0 == strcmp(default_action_verb, "check")) + return ax::mojom::DefaultActionVerb::kCheck; + if (0 == strcmp(default_action_verb, "click")) + return ax::mojom::DefaultActionVerb::kClick; + if (0 == strcmp(default_action_verb, "clickAncestor")) + return ax::mojom::DefaultActionVerb::kClickAncestor; + if (0 == strcmp(default_action_verb, "jump")) + return ax::mojom::DefaultActionVerb::kJump; + if (0 == strcmp(default_action_verb, "open")) + return ax::mojom::DefaultActionVerb::kOpen; + if (0 == strcmp(default_action_verb, "press")) + return ax::mojom::DefaultActionVerb::kPress; + if (0 == strcmp(default_action_verb, "select")) + return ax::mojom::DefaultActionVerb::kSelect; + if (0 == strcmp(default_action_verb, "uncheck")) + return ax::mojom::DefaultActionVerb::kUncheck; + return ax::mojom::DefaultActionVerb::kNone; +} + +const char* ToString(ax::mojom::Mutation mutation) { + switch (mutation) { + case ax::mojom::Mutation::kNone: + return "none"; + case ax::mojom::Mutation::kNodeCreated: + return "nodeCreated"; + case ax::mojom::Mutation::kSubtreeCreated: + return "subtreeCreated"; + case ax::mojom::Mutation::kNodeChanged: + return "nodeChanged"; + case ax::mojom::Mutation::kNodeRemoved: + return "nodeRemoved"; + } + + return ""; +} + +ax::mojom::Mutation ParseMutation(const char* mutation) { + if (0 == strcmp(mutation, "none")) + return ax::mojom::Mutation::kNone; + if (0 == strcmp(mutation, "nodeCreated")) + return ax::mojom::Mutation::kNodeCreated; + if (0 == strcmp(mutation, "subtreeCreated")) + return ax::mojom::Mutation::kSubtreeCreated; + if (0 == strcmp(mutation, "nodeChanged")) + return ax::mojom::Mutation::kNodeChanged; + if (0 == strcmp(mutation, "nodeRemoved")) + return ax::mojom::Mutation::kNodeRemoved; + return ax::mojom::Mutation::kNone; +} + +const char* ToString(ax::mojom::StringAttribute string_attribute) { + switch (string_attribute) { + case ax::mojom::StringAttribute::kNone: + return "none"; + case ax::mojom::StringAttribute::kAccessKey: + return "accessKey"; + case ax::mojom::StringAttribute::kAriaInvalidValue: + return "ariaInvalidValue"; + case ax::mojom::StringAttribute::kAutoComplete: + return "autoComplete"; + case ax::mojom::StringAttribute::kChromeChannel: + return "chromeChannel"; + case ax::mojom::StringAttribute::kClassName: + return "className"; + case ax::mojom::StringAttribute::kContainerLiveRelevant: + return "containerLiveRelevant"; + case ax::mojom::StringAttribute::kContainerLiveStatus: + return "containerLiveStatus"; + case ax::mojom::StringAttribute::kDescription: + return "description"; + case ax::mojom::StringAttribute::kDisplay: + return "display"; + case ax::mojom::StringAttribute::kFontFamily: + return "fontFamily"; + case ax::mojom::StringAttribute::kHtmlTag: + return "htmlTag"; + case ax::mojom::StringAttribute::kImageDataUrl: + return "imageDataUrl"; + case ax::mojom::StringAttribute::kInnerHtml: + return "innerHtml"; + case ax::mojom::StringAttribute::kKeyShortcuts: + return "keyShortcuts"; + case ax::mojom::StringAttribute::kLanguage: + return "language"; + case ax::mojom::StringAttribute::kName: + return "name"; + case ax::mojom::StringAttribute::kLiveRelevant: + return "liveRelevant"; + case ax::mojom::StringAttribute::kLiveStatus: + return "liveStatus"; + case ax::mojom::StringAttribute::kPlaceholder: + return "placeholder"; + case ax::mojom::StringAttribute::kRole: + return "role"; + case ax::mojom::StringAttribute::kRoleDescription: + return "roleDescription"; + case ax::mojom::StringAttribute::kUrl: + return "url"; + case ax::mojom::StringAttribute::kValue: + return "value"; + } + + return ""; +} + +ax::mojom::StringAttribute ParseStringAttribute(const char* string_attribute) { + if (0 == strcmp(string_attribute, "none")) + return ax::mojom::StringAttribute::kNone; + if (0 == strcmp(string_attribute, "accessKey")) + return ax::mojom::StringAttribute::kAccessKey; + if (0 == strcmp(string_attribute, "ariaInvalidValue")) + return ax::mojom::StringAttribute::kAriaInvalidValue; + if (0 == strcmp(string_attribute, "autoComplete")) + return ax::mojom::StringAttribute::kAutoComplete; + if (0 == strcmp(string_attribute, "chromeChannel")) + return ax::mojom::StringAttribute::kChromeChannel; + if (0 == strcmp(string_attribute, "className")) + return ax::mojom::StringAttribute::kClassName; + if (0 == strcmp(string_attribute, "containerLiveRelevant")) + return ax::mojom::StringAttribute::kContainerLiveRelevant; + if (0 == strcmp(string_attribute, "containerLiveStatus")) + return ax::mojom::StringAttribute::kContainerLiveStatus; + if (0 == strcmp(string_attribute, "description")) + return ax::mojom::StringAttribute::kDescription; + if (0 == strcmp(string_attribute, "display")) + return ax::mojom::StringAttribute::kDisplay; + if (0 == strcmp(string_attribute, "fontFamily")) + return ax::mojom::StringAttribute::kFontFamily; + if (0 == strcmp(string_attribute, "htmlTag")) + return ax::mojom::StringAttribute::kHtmlTag; + if (0 == strcmp(string_attribute, "imageDataUrl")) + return ax::mojom::StringAttribute::kImageDataUrl; + if (0 == strcmp(string_attribute, "innerHtml")) + return ax::mojom::StringAttribute::kInnerHtml; + if (0 == strcmp(string_attribute, "keyShortcuts")) + return ax::mojom::StringAttribute::kKeyShortcuts; + if (0 == strcmp(string_attribute, "language")) + return ax::mojom::StringAttribute::kLanguage; + if (0 == strcmp(string_attribute, "name")) + return ax::mojom::StringAttribute::kName; + if (0 == strcmp(string_attribute, "liveRelevant")) + return ax::mojom::StringAttribute::kLiveRelevant; + if (0 == strcmp(string_attribute, "liveStatus")) + return ax::mojom::StringAttribute::kLiveStatus; + if (0 == strcmp(string_attribute, "placeholder")) + return ax::mojom::StringAttribute::kPlaceholder; + if (0 == strcmp(string_attribute, "role")) + return ax::mojom::StringAttribute::kRole; + if (0 == strcmp(string_attribute, "roleDescription")) + return ax::mojom::StringAttribute::kRoleDescription; + if (0 == strcmp(string_attribute, "url")) + return ax::mojom::StringAttribute::kUrl; + if (0 == strcmp(string_attribute, "value")) + return ax::mojom::StringAttribute::kValue; + return ax::mojom::StringAttribute::kNone; +} + +const char* ToString(ax::mojom::IntAttribute int_attribute) { + switch (int_attribute) { + case ax::mojom::IntAttribute::kNone: + return "none"; + case ax::mojom::IntAttribute::kDefaultActionVerb: + return "defaultActionVerb"; + case ax::mojom::IntAttribute::kScrollX: + return "scrollX"; + case ax::mojom::IntAttribute::kScrollXMin: + return "scrollXMin"; + case ax::mojom::IntAttribute::kScrollXMax: + return "scrollXMax"; + case ax::mojom::IntAttribute::kScrollY: + return "scrollY"; + case ax::mojom::IntAttribute::kScrollYMin: + return "scrollYMin"; + case ax::mojom::IntAttribute::kScrollYMax: + return "scrollYMax"; + case ax::mojom::IntAttribute::kTextSelStart: + return "textSelStart"; + case ax::mojom::IntAttribute::kTextSelEnd: + return "textSelEnd"; + case ax::mojom::IntAttribute::kAriaColumnCount: + return "ariaColumnCount"; + case ax::mojom::IntAttribute::kAriaCellColumnIndex: + return "ariaCellColumnIndex"; + case ax::mojom::IntAttribute::kAriaRowCount: + return "ariaRowCount"; + case ax::mojom::IntAttribute::kAriaCellRowIndex: + return "ariaCellRowIndex"; + case ax::mojom::IntAttribute::kTableRowCount: + return "tableRowCount"; + case ax::mojom::IntAttribute::kTableColumnCount: + return "tableColumnCount"; + case ax::mojom::IntAttribute::kTableHeaderId: + return "tableHeaderId"; + case ax::mojom::IntAttribute::kTableRowIndex: + return "tableRowIndex"; + case ax::mojom::IntAttribute::kTableRowHeaderId: + return "tableRowHeaderId"; + case ax::mojom::IntAttribute::kTableColumnIndex: + return "tableColumnIndex"; + case ax::mojom::IntAttribute::kTableColumnHeaderId: + return "tableColumnHeaderId"; + case ax::mojom::IntAttribute::kTableCellColumnIndex: + return "tableCellColumnIndex"; + case ax::mojom::IntAttribute::kTableCellColumnSpan: + return "tableCellColumnSpan"; + case ax::mojom::IntAttribute::kTableCellRowIndex: + return "tableCellRowIndex"; + case ax::mojom::IntAttribute::kTableCellRowSpan: + return "tableCellRowSpan"; + case ax::mojom::IntAttribute::kSortDirection: + return "sortDirection"; + case ax::mojom::IntAttribute::kHierarchicalLevel: + return "hierarchicalLevel"; + case ax::mojom::IntAttribute::kNameFrom: + return "nameFrom"; + case ax::mojom::IntAttribute::kDescriptionFrom: + return "descriptionFrom"; + case ax::mojom::IntAttribute::kActivedescendantId: + return "activedescendantId"; + case ax::mojom::IntAttribute::kDetailsId: + return "detailsId"; + case ax::mojom::IntAttribute::kErrormessageId: + return "errormessageId"; + case ax::mojom::IntAttribute::kInPageLinkTargetId: + return "inPageLinkTargetId"; + case ax::mojom::IntAttribute::kMemberOfId: + return "memberOfId"; + case ax::mojom::IntAttribute::kNextOnLineId: + return "nextOnLineId"; + case ax::mojom::IntAttribute::kPreviousOnLineId: + return "previousOnLineId"; + case ax::mojom::IntAttribute::kChildTreeId: + return "childTreeId"; + case ax::mojom::IntAttribute::kRestriction: + return "restriction"; + case ax::mojom::IntAttribute::kSetSize: + return "setSize"; + case ax::mojom::IntAttribute::kPosInSet: + return "posInSet"; + case ax::mojom::IntAttribute::kColorValue: + return "colorValue"; + case ax::mojom::IntAttribute::kAriaCurrentState: + return "ariaCurrentState"; + case ax::mojom::IntAttribute::kBackgroundColor: + return "backgroundColor"; + case ax::mojom::IntAttribute::kColor: + return "color"; + case ax::mojom::IntAttribute::kInvalidState: + return "invalidState"; + case ax::mojom::IntAttribute::kCheckedState: + return "checkedState"; + case ax::mojom::IntAttribute::kTextDirection: + return "textDirection"; + case ax::mojom::IntAttribute::kTextStyle: + return "textStyle"; + case ax::mojom::IntAttribute::kPreviousFocusId: + return "previousFocusId"; + case ax::mojom::IntAttribute::kNextFocusId: + return "nextFocusId"; + } + + return ""; +} + +ax::mojom::IntAttribute ParseIntAttribute(const char* int_attribute) { + if (0 == strcmp(int_attribute, "none")) + return ax::mojom::IntAttribute::kNone; + if (0 == strcmp(int_attribute, "defaultActionVerb")) + return ax::mojom::IntAttribute::kDefaultActionVerb; + if (0 == strcmp(int_attribute, "scrollX")) + return ax::mojom::IntAttribute::kScrollX; + if (0 == strcmp(int_attribute, "scrollXMin")) + return ax::mojom::IntAttribute::kScrollXMin; + if (0 == strcmp(int_attribute, "scrollXMax")) + return ax::mojom::IntAttribute::kScrollXMax; + if (0 == strcmp(int_attribute, "scrollY")) + return ax::mojom::IntAttribute::kScrollY; + if (0 == strcmp(int_attribute, "scrollYMin")) + return ax::mojom::IntAttribute::kScrollYMin; + if (0 == strcmp(int_attribute, "scrollYMax")) + return ax::mojom::IntAttribute::kScrollYMax; + if (0 == strcmp(int_attribute, "textSelStart")) + return ax::mojom::IntAttribute::kTextSelStart; + if (0 == strcmp(int_attribute, "textSelEnd")) + return ax::mojom::IntAttribute::kTextSelEnd; + if (0 == strcmp(int_attribute, "ariaColumnCount")) + return ax::mojom::IntAttribute::kAriaColumnCount; + if (0 == strcmp(int_attribute, "ariaCellColumnIndex")) + return ax::mojom::IntAttribute::kAriaCellColumnIndex; + if (0 == strcmp(int_attribute, "ariaRowCount")) + return ax::mojom::IntAttribute::kAriaRowCount; + if (0 == strcmp(int_attribute, "ariaCellRowIndex")) + return ax::mojom::IntAttribute::kAriaCellRowIndex; + if (0 == strcmp(int_attribute, "tableRowCount")) + return ax::mojom::IntAttribute::kTableRowCount; + if (0 == strcmp(int_attribute, "tableColumnCount")) + return ax::mojom::IntAttribute::kTableColumnCount; + if (0 == strcmp(int_attribute, "tableHeaderId")) + return ax::mojom::IntAttribute::kTableHeaderId; + if (0 == strcmp(int_attribute, "tableRowIndex")) + return ax::mojom::IntAttribute::kTableRowIndex; + if (0 == strcmp(int_attribute, "tableRowHeaderId")) + return ax::mojom::IntAttribute::kTableRowHeaderId; + if (0 == strcmp(int_attribute, "tableColumnIndex")) + return ax::mojom::IntAttribute::kTableColumnIndex; + if (0 == strcmp(int_attribute, "tableColumnHeaderId")) + return ax::mojom::IntAttribute::kTableColumnHeaderId; + if (0 == strcmp(int_attribute, "tableCellColumnIndex")) + return ax::mojom::IntAttribute::kTableCellColumnIndex; + if (0 == strcmp(int_attribute, "tableCellColumnSpan")) + return ax::mojom::IntAttribute::kTableCellColumnSpan; + if (0 == strcmp(int_attribute, "tableCellRowIndex")) + return ax::mojom::IntAttribute::kTableCellRowIndex; + if (0 == strcmp(int_attribute, "tableCellRowSpan")) + return ax::mojom::IntAttribute::kTableCellRowSpan; + if (0 == strcmp(int_attribute, "sortDirection")) + return ax::mojom::IntAttribute::kSortDirection; + if (0 == strcmp(int_attribute, "hierarchicalLevel")) + return ax::mojom::IntAttribute::kHierarchicalLevel; + if (0 == strcmp(int_attribute, "nameFrom")) + return ax::mojom::IntAttribute::kNameFrom; + if (0 == strcmp(int_attribute, "descriptionFrom")) + return ax::mojom::IntAttribute::kDescriptionFrom; + if (0 == strcmp(int_attribute, "activedescendantId")) + return ax::mojom::IntAttribute::kActivedescendantId; + if (0 == strcmp(int_attribute, "detailsId")) + return ax::mojom::IntAttribute::kDetailsId; + if (0 == strcmp(int_attribute, "errormessageId")) + return ax::mojom::IntAttribute::kErrormessageId; + if (0 == strcmp(int_attribute, "inPageLinkTargetId")) + return ax::mojom::IntAttribute::kInPageLinkTargetId; + if (0 == strcmp(int_attribute, "memberOfId")) + return ax::mojom::IntAttribute::kMemberOfId; + if (0 == strcmp(int_attribute, "nextOnLineId")) + return ax::mojom::IntAttribute::kNextOnLineId; + if (0 == strcmp(int_attribute, "previousOnLineId")) + return ax::mojom::IntAttribute::kPreviousOnLineId; + if (0 == strcmp(int_attribute, "childTreeId")) + return ax::mojom::IntAttribute::kChildTreeId; + if (0 == strcmp(int_attribute, "restriction")) + return ax::mojom::IntAttribute::kRestriction; + if (0 == strcmp(int_attribute, "setSize")) + return ax::mojom::IntAttribute::kSetSize; + if (0 == strcmp(int_attribute, "posInSet")) + return ax::mojom::IntAttribute::kPosInSet; + if (0 == strcmp(int_attribute, "colorValue")) + return ax::mojom::IntAttribute::kColorValue; + if (0 == strcmp(int_attribute, "ariaCurrentState")) + return ax::mojom::IntAttribute::kAriaCurrentState; + if (0 == strcmp(int_attribute, "backgroundColor")) + return ax::mojom::IntAttribute::kBackgroundColor; + if (0 == strcmp(int_attribute, "color")) + return ax::mojom::IntAttribute::kColor; + if (0 == strcmp(int_attribute, "invalidState")) + return ax::mojom::IntAttribute::kInvalidState; + if (0 == strcmp(int_attribute, "checkedState")) + return ax::mojom::IntAttribute::kCheckedState; + if (0 == strcmp(int_attribute, "textDirection")) + return ax::mojom::IntAttribute::kTextDirection; + if (0 == strcmp(int_attribute, "textStyle")) + return ax::mojom::IntAttribute::kTextStyle; + if (0 == strcmp(int_attribute, "previousFocusId")) + return ax::mojom::IntAttribute::kPreviousFocusId; + if (0 == strcmp(int_attribute, "nextFocusId")) + return ax::mojom::IntAttribute::kNextFocusId; + return ax::mojom::IntAttribute::kNone; +} + +const char* ToString(ax::mojom::FloatAttribute float_attribute) { + switch (float_attribute) { + case ax::mojom::FloatAttribute::kNone: + return "none"; + case ax::mojom::FloatAttribute::kValueForRange: + return "valueForRange"; + case ax::mojom::FloatAttribute::kMinValueForRange: + return "minValueForRange"; + case ax::mojom::FloatAttribute::kMaxValueForRange: + return "maxValueForRange"; + case ax::mojom::FloatAttribute::kStepValueForRange: + return "stepValueForRange"; + case ax::mojom::FloatAttribute::kFontSize: + return "fontSize"; + } + + return ""; +} + +ax::mojom::FloatAttribute ParseFloatAttribute(const char* float_attribute) { + if (0 == strcmp(float_attribute, "none")) + return ax::mojom::FloatAttribute::kNone; + if (0 == strcmp(float_attribute, "valueForRange")) + return ax::mojom::FloatAttribute::kValueForRange; + if (0 == strcmp(float_attribute, "minValueForRange")) + return ax::mojom::FloatAttribute::kMinValueForRange; + if (0 == strcmp(float_attribute, "maxValueForRange")) + return ax::mojom::FloatAttribute::kMaxValueForRange; + if (0 == strcmp(float_attribute, "stepValueForRange")) + return ax::mojom::FloatAttribute::kStepValueForRange; + if (0 == strcmp(float_attribute, "fontSize")) + return ax::mojom::FloatAttribute::kFontSize; + return ax::mojom::FloatAttribute::kNone; +} + +const char* ToString(ax::mojom::BoolAttribute bool_attribute) { + switch (bool_attribute) { + case ax::mojom::BoolAttribute::kNone: + return "none"; + case ax::mojom::BoolAttribute::kBusy: + return "busy"; + case ax::mojom::BoolAttribute::kEditableRoot: + return "editableRoot"; + case ax::mojom::BoolAttribute::kContainerLiveAtomic: + return "containerLiveAtomic"; + case ax::mojom::BoolAttribute::kContainerLiveBusy: + return "containerLiveBusy"; + case ax::mojom::BoolAttribute::kLiveAtomic: + return "liveAtomic"; + case ax::mojom::BoolAttribute::kModal: + return "modal"; + case ax::mojom::BoolAttribute::kUpdateLocationOnly: + return "updateLocationOnly"; + case ax::mojom::BoolAttribute::kCanvasHasFallback: + return "canvasHasFallback"; + case ax::mojom::BoolAttribute::kScrollable: + return "scrollable"; + case ax::mojom::BoolAttribute::kClickable: + return "clickable"; + case ax::mojom::BoolAttribute::kClipsChildren: + return "clipsChildren"; + } + + return ""; +} + +ax::mojom::BoolAttribute ParseBoolAttribute(const char* bool_attribute) { + if (0 == strcmp(bool_attribute, "none")) + return ax::mojom::BoolAttribute::kNone; + if (0 == strcmp(bool_attribute, "busy")) + return ax::mojom::BoolAttribute::kBusy; + if (0 == strcmp(bool_attribute, "editableRoot")) + return ax::mojom::BoolAttribute::kEditableRoot; + if (0 == strcmp(bool_attribute, "containerLiveAtomic")) + return ax::mojom::BoolAttribute::kContainerLiveAtomic; + if (0 == strcmp(bool_attribute, "containerLiveBusy")) + return ax::mojom::BoolAttribute::kContainerLiveBusy; + if (0 == strcmp(bool_attribute, "liveAtomic")) + return ax::mojom::BoolAttribute::kLiveAtomic; + if (0 == strcmp(bool_attribute, "modal")) + return ax::mojom::BoolAttribute::kModal; + if (0 == strcmp(bool_attribute, "updateLocationOnly")) + return ax::mojom::BoolAttribute::kUpdateLocationOnly; + if (0 == strcmp(bool_attribute, "canvasHasFallback")) + return ax::mojom::BoolAttribute::kCanvasHasFallback; + if (0 == strcmp(bool_attribute, "scrollable")) + return ax::mojom::BoolAttribute::kScrollable; + if (0 == strcmp(bool_attribute, "clickable")) + return ax::mojom::BoolAttribute::kClickable; + if (0 == strcmp(bool_attribute, "clipsChildren")) + return ax::mojom::BoolAttribute::kClipsChildren; + return ax::mojom::BoolAttribute::kNone; +} + +const char* ToString(ax::mojom::IntListAttribute int_list_attribute) { + switch (int_list_attribute) { + case ax::mojom::IntListAttribute::kNone: + return "none"; + case ax::mojom::IntListAttribute::kIndirectChildIds: + return "indirectChildIds"; + case ax::mojom::IntListAttribute::kControlsIds: + return "controlsIds"; + case ax::mojom::IntListAttribute::kDescribedbyIds: + return "describedbyIds"; + case ax::mojom::IntListAttribute::kFlowtoIds: + return "flowtoIds"; + case ax::mojom::IntListAttribute::kLabelledbyIds: + return "labelledbyIds"; + case ax::mojom::IntListAttribute::kRadioGroupIds: + return "radioGroupIds"; + case ax::mojom::IntListAttribute::kLineBreaks: + return "lineBreaks"; + case ax::mojom::IntListAttribute::kMarkerTypes: + return "markerTypes"; + case ax::mojom::IntListAttribute::kMarkerStarts: + return "markerStarts"; + case ax::mojom::IntListAttribute::kMarkerEnds: + return "markerEnds"; + case ax::mojom::IntListAttribute::kCellIds: + return "cellIds"; + case ax::mojom::IntListAttribute::kUniqueCellIds: + return "uniqueCellIds"; + case ax::mojom::IntListAttribute::kCharacterOffsets: + return "characterOffsets"; + case ax::mojom::IntListAttribute::kCachedLineStarts: + return "cachedLineStarts"; + case ax::mojom::IntListAttribute::kWordStarts: + return "wordStarts"; + case ax::mojom::IntListAttribute::kWordEnds: + return "wordEnds"; + case ax::mojom::IntListAttribute::kCustomActionIds: + return "customActionIds"; + } + + return ""; +} + +ax::mojom::IntListAttribute ParseIntListAttribute( + const char* int_list_attribute) { + if (0 == strcmp(int_list_attribute, "none")) + return ax::mojom::IntListAttribute::kNone; + if (0 == strcmp(int_list_attribute, "indirectChildIds")) + return ax::mojom::IntListAttribute::kIndirectChildIds; + if (0 == strcmp(int_list_attribute, "controlsIds")) + return ax::mojom::IntListAttribute::kControlsIds; + if (0 == strcmp(int_list_attribute, "describedbyIds")) + return ax::mojom::IntListAttribute::kDescribedbyIds; + if (0 == strcmp(int_list_attribute, "flowtoIds")) + return ax::mojom::IntListAttribute::kFlowtoIds; + if (0 == strcmp(int_list_attribute, "labelledbyIds")) + return ax::mojom::IntListAttribute::kLabelledbyIds; + if (0 == strcmp(int_list_attribute, "radioGroupIds")) + return ax::mojom::IntListAttribute::kRadioGroupIds; + if (0 == strcmp(int_list_attribute, "lineBreaks")) + return ax::mojom::IntListAttribute::kLineBreaks; + if (0 == strcmp(int_list_attribute, "markerTypes")) + return ax::mojom::IntListAttribute::kMarkerTypes; + if (0 == strcmp(int_list_attribute, "markerStarts")) + return ax::mojom::IntListAttribute::kMarkerStarts; + if (0 == strcmp(int_list_attribute, "markerEnds")) + return ax::mojom::IntListAttribute::kMarkerEnds; + if (0 == strcmp(int_list_attribute, "cellIds")) + return ax::mojom::IntListAttribute::kCellIds; + if (0 == strcmp(int_list_attribute, "uniqueCellIds")) + return ax::mojom::IntListAttribute::kUniqueCellIds; + if (0 == strcmp(int_list_attribute, "characterOffsets")) + return ax::mojom::IntListAttribute::kCharacterOffsets; + if (0 == strcmp(int_list_attribute, "cachedLineStarts")) + return ax::mojom::IntListAttribute::kCachedLineStarts; + if (0 == strcmp(int_list_attribute, "wordStarts")) + return ax::mojom::IntListAttribute::kWordStarts; + if (0 == strcmp(int_list_attribute, "wordEnds")) + return ax::mojom::IntListAttribute::kWordEnds; + if (0 == strcmp(int_list_attribute, "customActionIds")) + return ax::mojom::IntListAttribute::kCustomActionIds; + return ax::mojom::IntListAttribute::kNone; +} + +const char* ToString(ax::mojom::StringListAttribute string_list_attribute) { + switch (string_list_attribute) { + case ax::mojom::StringListAttribute::kNone: + return "none"; + case ax::mojom::StringListAttribute::kCustomActionDescriptions: + return "customActionDescriptions"; + } + + return ""; +} + +ax::mojom::StringListAttribute ParseStringListAttribute( + const char* string_list_attribute) { + if (0 == strcmp(string_list_attribute, "none")) + return ax::mojom::StringListAttribute::kNone; + if (0 == strcmp(string_list_attribute, "customActionDescriptions")) + return ax::mojom::StringListAttribute::kCustomActionDescriptions; + return ax::mojom::StringListAttribute::kNone; +} + +const char* ToString(ax::mojom::MarkerType marker_type) { + switch (marker_type) { + case ax::mojom::MarkerType::kNone: + return "none"; + case ax::mojom::MarkerType::kSpelling: + return "spelling"; + case ax::mojom::MarkerType::kGrammar: + return "grammar"; + case ax::mojom::MarkerType::kSpellingGrammar: + return "spellingGrammar"; + case ax::mojom::MarkerType::kTextMatch: + return "textMatch"; + case ax::mojom::MarkerType::kSpellingTextMatch: + return "spellingTextMatch"; + case ax::mojom::MarkerType::kGrammarTextMatch: + return "grammarTextMatch"; + case ax::mojom::MarkerType::kSpellingGrammarTextMatch: + return "spellingGrammarTextMatch"; + case ax::mojom::MarkerType::kActiveSuggestion: + return "activeSuggestion"; + case ax::mojom::MarkerType::kSpellingActiveSuggestion: + return "spellingActiveSuggestion"; + case ax::mojom::MarkerType::kGrammarActiveSuggestion: + return "grammarActiveSuggestion"; + case ax::mojom::MarkerType::kSpellingGrammarActiveSuggestion: + return "spellingGrammarActiveSuggestion"; + case ax::mojom::MarkerType::kTextMatchActiveSuggestion: + return "textMatchActiveSuggestion"; + case ax::mojom::MarkerType::kSpellingTextMatchActiveSuggestion: + return "spellingTextMatchActiveSuggestion"; + case ax::mojom::MarkerType::kGrammarTextMatchActiveSuggestion: + return "grammarTextMatchActiveSuggestion"; + case ax::mojom::MarkerType::kSpellingGrammarTextMatchActiveSuggestion: + return "spellingGrammarTextMatchActiveSuggestion"; + case ax::mojom::MarkerType::kSuggestion: + return "suggestion"; + case ax::mojom::MarkerType::kSpellingSuggestion: + return "spellingSuggestion"; + case ax::mojom::MarkerType::kGrammarSuggestion: + return "grammarSuggestion"; + case ax::mojom::MarkerType::kSpellingGrammarSuggestion: + return "spellingGrammarSuggestion"; + case ax::mojom::MarkerType::kTextMatchSuggestion: + return "textMatchSuggestion"; + case ax::mojom::MarkerType::kSpellingTextMatchSuggestion: + return "spellingTextMatchSuggestion"; + case ax::mojom::MarkerType::kGrammarTextMatchSuggestion: + return "grammarTextMatchSuggestion"; + case ax::mojom::MarkerType::kSpellingGrammarTextMatchSuggestion: + return "spellingGrammarTextMatchSuggestion"; + case ax::mojom::MarkerType::kActiveSuggestionSuggestion: + return "activeSuggestionSuggestion"; + case ax::mojom::MarkerType::kSpellingActiveSuggestionSuggestion: + return "spellingActiveSuggestionSuggestion"; + case ax::mojom::MarkerType::kGrammarActiveSuggestionSuggestion: + return "grammarActiveSuggestionSuggestion"; + case ax::mojom::MarkerType::kSpellingGrammarActiveSuggestionSuggestion: + return "spellingGrammarActiveSuggestionSuggestion"; + case ax::mojom::MarkerType::kTextMatchActiveSuggestionSuggestion: + return "textMatchActiveSuggestionSuggestion"; + case ax::mojom::MarkerType::kSpellingTextMatchActiveSuggestionSuggestion: + return "spellingTextMatchActiveSuggestionSuggestion"; + case ax::mojom::MarkerType::kGrammarTextMatchActiveSuggestionSuggestion: + return "grammarTextMatchActiveSuggestionSuggestion"; + case ax::mojom::MarkerType:: + kSpellingGrammarTextMatchActiveSuggestionSuggestion: + return "spellingGrammarTextMatchActiveSuggestionSuggestion"; + } + + return ""; +} + +ax::mojom::MarkerType ParseMarkerType(const char* marker_type) { + if (0 == strcmp(marker_type, "none")) + return ax::mojom::MarkerType::kNone; + if (0 == strcmp(marker_type, "spelling")) + return ax::mojom::MarkerType::kSpelling; + if (0 == strcmp(marker_type, "grammar")) + return ax::mojom::MarkerType::kGrammar; + if (0 == strcmp(marker_type, "spellingGrammar")) + return ax::mojom::MarkerType::kSpellingGrammar; + if (0 == strcmp(marker_type, "textMatch")) + return ax::mojom::MarkerType::kTextMatch; + if (0 == strcmp(marker_type, "spellingTextMatch")) + return ax::mojom::MarkerType::kSpellingTextMatch; + if (0 == strcmp(marker_type, "grammarTextMatch")) + return ax::mojom::MarkerType::kGrammarTextMatch; + if (0 == strcmp(marker_type, "spellingGrammarTextMatch")) + return ax::mojom::MarkerType::kSpellingGrammarTextMatch; + if (0 == strcmp(marker_type, "activeSuggestion")) + return ax::mojom::MarkerType::kActiveSuggestion; + if (0 == strcmp(marker_type, "spellingActiveSuggestion")) + return ax::mojom::MarkerType::kSpellingActiveSuggestion; + if (0 == strcmp(marker_type, "grammarActiveSuggestion")) + return ax::mojom::MarkerType::kGrammarActiveSuggestion; + if (0 == strcmp(marker_type, "spellingGrammarActiveSuggestion")) + return ax::mojom::MarkerType::kSpellingGrammarActiveSuggestion; + if (0 == strcmp(marker_type, "textMatchActiveSuggestion")) + return ax::mojom::MarkerType::kTextMatchActiveSuggestion; + if (0 == strcmp(marker_type, "spellingTextMatchActiveSuggestion")) + return ax::mojom::MarkerType::kSpellingTextMatchActiveSuggestion; + if (0 == strcmp(marker_type, "grammarTextMatchActiveSuggestion")) + return ax::mojom::MarkerType::kGrammarTextMatchActiveSuggestion; + if (0 == strcmp(marker_type, "spellingGrammarTextMatchActiveSuggestion")) + return ax::mojom::MarkerType::kSpellingGrammarTextMatchActiveSuggestion; + if (0 == strcmp(marker_type, "suggestion")) + return ax::mojom::MarkerType::kSuggestion; + if (0 == strcmp(marker_type, "spellingSuggestion")) + return ax::mojom::MarkerType::kSpellingSuggestion; + if (0 == strcmp(marker_type, "grammarSuggestion")) + return ax::mojom::MarkerType::kGrammarSuggestion; + if (0 == strcmp(marker_type, "spellingGrammarSuggestion")) + return ax::mojom::MarkerType::kSpellingGrammarSuggestion; + if (0 == strcmp(marker_type, "textMatchSuggestion")) + return ax::mojom::MarkerType::kTextMatchSuggestion; + if (0 == strcmp(marker_type, "spellingTextMatchSuggestion")) + return ax::mojom::MarkerType::kSpellingTextMatchSuggestion; + if (0 == strcmp(marker_type, "grammarTextMatchSuggestion")) + return ax::mojom::MarkerType::kGrammarTextMatchSuggestion; + if (0 == strcmp(marker_type, "spellingGrammarTextMatchSuggestion")) + return ax::mojom::MarkerType::kSpellingGrammarTextMatchSuggestion; + if (0 == strcmp(marker_type, "activeSuggestionSuggestion")) + return ax::mojom::MarkerType::kActiveSuggestionSuggestion; + if (0 == strcmp(marker_type, "spellingActiveSuggestionSuggestion")) + return ax::mojom::MarkerType::kSpellingActiveSuggestionSuggestion; + if (0 == strcmp(marker_type, "grammarActiveSuggestionSuggestion")) + return ax::mojom::MarkerType::kGrammarActiveSuggestionSuggestion; + if (0 == strcmp(marker_type, "spellingGrammarActiveSuggestionSuggestion")) + return ax::mojom::MarkerType::kSpellingGrammarActiveSuggestionSuggestion; + if (0 == strcmp(marker_type, "textMatchActiveSuggestionSuggestion")) + return ax::mojom::MarkerType::kTextMatchActiveSuggestionSuggestion; + if (0 == strcmp(marker_type, "spellingTextMatchActiveSuggestionSuggestion")) + return ax::mojom::MarkerType::kSpellingTextMatchActiveSuggestionSuggestion; + if (0 == strcmp(marker_type, "grammarTextMatchActiveSuggestionSuggestion")) + return ax::mojom::MarkerType::kGrammarTextMatchActiveSuggestionSuggestion; + if (0 == + strcmp(marker_type, "spellingGrammarTextMatchActiveSuggestionSuggestion")) + return ax::mojom::MarkerType:: + kSpellingGrammarTextMatchActiveSuggestionSuggestion; + return ax::mojom::MarkerType::kNone; +} + +const char* ToString(ax::mojom::TextDirection text_direction) { + switch (text_direction) { + case ax::mojom::TextDirection::kNone: + return "none"; + case ax::mojom::TextDirection::kLtr: + return "ltr"; + case ax::mojom::TextDirection::kRtl: + return "rtl"; + case ax::mojom::TextDirection::kTtb: + return "ttb"; + case ax::mojom::TextDirection::kBtt: + return "btt"; + } + + return ""; +} + +ax::mojom::TextDirection ParseTextDirection(const char* text_direction) { + if (0 == strcmp(text_direction, "none")) + return ax::mojom::TextDirection::kNone; + if (0 == strcmp(text_direction, "ltr")) + return ax::mojom::TextDirection::kLtr; + if (0 == strcmp(text_direction, "rtl")) + return ax::mojom::TextDirection::kRtl; + if (0 == strcmp(text_direction, "ttb")) + return ax::mojom::TextDirection::kTtb; + if (0 == strcmp(text_direction, "btt")) + return ax::mojom::TextDirection::kBtt; + return ax::mojom::TextDirection::kNone; +} + +const char* ToString(ax::mojom::TextStyle text_style) { + switch (text_style) { + case ax::mojom::TextStyle::kNone: + return "none"; + case ax::mojom::TextStyle::kTextStyleBold: + return "textStyleBold"; + case ax::mojom::TextStyle::kTextStyleItalic: + return "textStyleItalic"; + case ax::mojom::TextStyle::kTextStyleBoldItalic: + return "textStyleBoldItalic"; + case ax::mojom::TextStyle::kTextStyleUnderline: + return "textStyleUnderline"; + case ax::mojom::TextStyle::kTextStyleBoldUnderline: + return "textStyleBoldUnderline"; + case ax::mojom::TextStyle::kTextStyleItalicUnderline: + return "textStyleItalicUnderline"; + case ax::mojom::TextStyle::kTextStyleBoldItalicUnderline: + return "textStyleBoldItalicUnderline"; + case ax::mojom::TextStyle::kTextStyleLineThrough: + return "textStyleLineThrough"; + case ax::mojom::TextStyle::kTextStyleBoldLineThrough: + return "textStyleBoldLineThrough"; + case ax::mojom::TextStyle::kTextStyleItalicLineThrough: + return "textStyleItalicLineThrough"; + case ax::mojom::TextStyle::kTextStyleBoldItalicLineThrough: + return "textStyleBoldItalicLineThrough"; + case ax::mojom::TextStyle::kTextStyleUnderlineLineThrough: + return "textStyleUnderlineLineThrough"; + case ax::mojom::TextStyle::kTextStyleBoldUnderlineLineThrough: + return "textStyleBoldUnderlineLineThrough"; + case ax::mojom::TextStyle::kTextStyleItalicUnderlineLineThrough: + return "textStyleItalicUnderlineLineThrough"; + case ax::mojom::TextStyle::kTextStyleBoldItalicUnderlineLineThrough: + return "textStyleBoldItalicUnderlineLineThrough"; + } + + return ""; +} + +ax::mojom::TextStyle ParseTextStyle(const char* text_style) { + if (0 == strcmp(text_style, "none")) + return ax::mojom::TextStyle::kNone; + if (0 == strcmp(text_style, "textStyleBold")) + return ax::mojom::TextStyle::kTextStyleBold; + if (0 == strcmp(text_style, "textStyleItalic")) + return ax::mojom::TextStyle::kTextStyleItalic; + if (0 == strcmp(text_style, "textStyleBoldItalic")) + return ax::mojom::TextStyle::kTextStyleBoldItalic; + if (0 == strcmp(text_style, "textStyleUnderline")) + return ax::mojom::TextStyle::kTextStyleUnderline; + if (0 == strcmp(text_style, "textStyleBoldUnderline")) + return ax::mojom::TextStyle::kTextStyleBoldUnderline; + if (0 == strcmp(text_style, "textStyleItalicUnderline")) + return ax::mojom::TextStyle::kTextStyleItalicUnderline; + if (0 == strcmp(text_style, "textStyleBoldItalicUnderline")) + return ax::mojom::TextStyle::kTextStyleBoldItalicUnderline; + if (0 == strcmp(text_style, "textStyleLineThrough")) + return ax::mojom::TextStyle::kTextStyleLineThrough; + if (0 == strcmp(text_style, "textStyleBoldLineThrough")) + return ax::mojom::TextStyle::kTextStyleBoldLineThrough; + if (0 == strcmp(text_style, "textStyleItalicLineThrough")) + return ax::mojom::TextStyle::kTextStyleItalicLineThrough; + if (0 == strcmp(text_style, "textStyleBoldItalicLineThrough")) + return ax::mojom::TextStyle::kTextStyleBoldItalicLineThrough; + if (0 == strcmp(text_style, "textStyleUnderlineLineThrough")) + return ax::mojom::TextStyle::kTextStyleUnderlineLineThrough; + if (0 == strcmp(text_style, "textStyleBoldUnderlineLineThrough")) + return ax::mojom::TextStyle::kTextStyleBoldUnderlineLineThrough; + if (0 == strcmp(text_style, "textStyleItalicUnderlineLineThrough")) + return ax::mojom::TextStyle::kTextStyleItalicUnderlineLineThrough; + if (0 == strcmp(text_style, "textStyleBoldItalicUnderlineLineThrough")) + return ax::mojom::TextStyle::kTextStyleBoldItalicUnderlineLineThrough; + return ax::mojom::TextStyle::kNone; +} + +const char* ToString(ax::mojom::AriaCurrentState aria_current_state) { + switch (aria_current_state) { + case ax::mojom::AriaCurrentState::kNone: + return "none"; + case ax::mojom::AriaCurrentState::kFalse: + return "false"; + case ax::mojom::AriaCurrentState::kTrue: + return "true"; + case ax::mojom::AriaCurrentState::kPage: + return "page"; + case ax::mojom::AriaCurrentState::kStep: + return "step"; + case ax::mojom::AriaCurrentState::kLocation: + return "location"; + case ax::mojom::AriaCurrentState::kUnclippedLocation: + return "unclippedLocation"; + case ax::mojom::AriaCurrentState::kDate: + return "date"; + case ax::mojom::AriaCurrentState::kTime: + return "time"; + } + + return ""; +} + +ax::mojom::AriaCurrentState ParseAriaCurrentState( + const char* aria_current_state) { + if (0 == strcmp(aria_current_state, "none")) + return ax::mojom::AriaCurrentState::kNone; + if (0 == strcmp(aria_current_state, "false")) + return ax::mojom::AriaCurrentState::kFalse; + if (0 == strcmp(aria_current_state, "true")) + return ax::mojom::AriaCurrentState::kTrue; + if (0 == strcmp(aria_current_state, "page")) + return ax::mojom::AriaCurrentState::kPage; + if (0 == strcmp(aria_current_state, "step")) + return ax::mojom::AriaCurrentState::kStep; + if (0 == strcmp(aria_current_state, "location")) + return ax::mojom::AriaCurrentState::kLocation; + if (0 == strcmp(aria_current_state, "unclippedLocation")) + return ax::mojom::AriaCurrentState::kUnclippedLocation; + if (0 == strcmp(aria_current_state, "date")) + return ax::mojom::AriaCurrentState::kDate; + if (0 == strcmp(aria_current_state, "time")) + return ax::mojom::AriaCurrentState::kTime; + return ax::mojom::AriaCurrentState::kNone; +} + +const char* ToString(ax::mojom::InvalidState invalid_state) { + switch (invalid_state) { + case ax::mojom::InvalidState::kNone: + return "none"; + case ax::mojom::InvalidState::kFalse: + return "false"; + case ax::mojom::InvalidState::kTrue: + return "true"; + case ax::mojom::InvalidState::kSpelling: + return "spelling"; + case ax::mojom::InvalidState::kGrammar: + return "grammar"; + case ax::mojom::InvalidState::kOther: + return "other"; + } + + return ""; +} + +ax::mojom::InvalidState ParseInvalidState(const char* invalid_state) { + if (0 == strcmp(invalid_state, "none")) + return ax::mojom::InvalidState::kNone; + if (0 == strcmp(invalid_state, "false")) + return ax::mojom::InvalidState::kFalse; + if (0 == strcmp(invalid_state, "true")) + return ax::mojom::InvalidState::kTrue; + if (0 == strcmp(invalid_state, "spelling")) + return ax::mojom::InvalidState::kSpelling; + if (0 == strcmp(invalid_state, "grammar")) + return ax::mojom::InvalidState::kGrammar; + if (0 == strcmp(invalid_state, "other")) + return ax::mojom::InvalidState::kOther; + return ax::mojom::InvalidState::kNone; +} + +const char* ToString(ax::mojom::Restriction restriction) { + switch (restriction) { + case ax::mojom::Restriction::kNone: + return "none"; + case ax::mojom::Restriction::kReadOnly: + return "readOnly"; + case ax::mojom::Restriction::kDisabled: + return "disabled"; + } + + return ""; +} + +ax::mojom::Restriction ParseRestriction(const char* restriction) { + if (0 == strcmp(restriction, "none")) + return ax::mojom::Restriction::kNone; + if (0 == strcmp(restriction, "readOnly")) + return ax::mojom::Restriction::kReadOnly; + if (0 == strcmp(restriction, "disabled")) + return ax::mojom::Restriction::kDisabled; + return ax::mojom::Restriction::kNone; +} + +const char* ToString(ax::mojom::CheckedState checked_state) { + switch (checked_state) { + case ax::mojom::CheckedState::kNone: + return "none"; + case ax::mojom::CheckedState::kFalse: + return "false"; + case ax::mojom::CheckedState::kTrue: + return "true"; + case ax::mojom::CheckedState::kMixed: + return "mixed"; + } + + return ""; +} + +ax::mojom::CheckedState ParseCheckedState(const char* checked_state) { + if (0 == strcmp(checked_state, "none")) + return ax::mojom::CheckedState::kNone; + if (0 == strcmp(checked_state, "false")) + return ax::mojom::CheckedState::kFalse; + if (0 == strcmp(checked_state, "true")) + return ax::mojom::CheckedState::kTrue; + if (0 == strcmp(checked_state, "mixed")) + return ax::mojom::CheckedState::kMixed; + return ax::mojom::CheckedState::kNone; +} + +const char* ToString(ax::mojom::SortDirection sort_direction) { + switch (sort_direction) { + case ax::mojom::SortDirection::kNone: + return "none"; + case ax::mojom::SortDirection::kUnsorted: + return "unsorted"; + case ax::mojom::SortDirection::kAscending: + return "ascending"; + case ax::mojom::SortDirection::kDescending: + return "descending"; + case ax::mojom::SortDirection::kOther: + return "other"; + } + + return ""; +} + +ax::mojom::SortDirection ParseSortDirection(const char* sort_direction) { + if (0 == strcmp(sort_direction, "none")) + return ax::mojom::SortDirection::kNone; + if (0 == strcmp(sort_direction, "unsorted")) + return ax::mojom::SortDirection::kUnsorted; + if (0 == strcmp(sort_direction, "ascending")) + return ax::mojom::SortDirection::kAscending; + if (0 == strcmp(sort_direction, "descending")) + return ax::mojom::SortDirection::kDescending; + if (0 == strcmp(sort_direction, "other")) + return ax::mojom::SortDirection::kOther; + return ax::mojom::SortDirection::kNone; +} + +const char* ToString(ax::mojom::NameFrom name_from) { + switch (name_from) { + case ax::mojom::NameFrom::kNone: + return "none"; + case ax::mojom::NameFrom::kUninitialized: + return "uninitialized"; + case ax::mojom::NameFrom::kAttribute: + return "attribute"; + case ax::mojom::NameFrom::kAttributeExplicitlyEmpty: + return "attributeExplicitlyEmpty"; + case ax::mojom::NameFrom::kContents: + return "contents"; + case ax::mojom::NameFrom::kPlaceholder: + return "placeholder"; + case ax::mojom::NameFrom::kRelatedElement: + return "relatedElement"; + case ax::mojom::NameFrom::kValue: + return "value"; + } + + return ""; +} + +ax::mojom::NameFrom ParseNameFrom(const char* name_from) { + if (0 == strcmp(name_from, "none")) + return ax::mojom::NameFrom::kNone; + if (0 == strcmp(name_from, "uninitialized")) + return ax::mojom::NameFrom::kUninitialized; + if (0 == strcmp(name_from, "attribute")) + return ax::mojom::NameFrom::kAttribute; + if (0 == strcmp(name_from, "attributeExplicitlyEmpty")) + return ax::mojom::NameFrom::kAttributeExplicitlyEmpty; + if (0 == strcmp(name_from, "contents")) + return ax::mojom::NameFrom::kContents; + if (0 == strcmp(name_from, "placeholder")) + return ax::mojom::NameFrom::kPlaceholder; + if (0 == strcmp(name_from, "relatedElement")) + return ax::mojom::NameFrom::kRelatedElement; + if (0 == strcmp(name_from, "value")) + return ax::mojom::NameFrom::kValue; + return ax::mojom::NameFrom::kNone; +} + +const char* ToString(ax::mojom::DescriptionFrom description_from) { + switch (description_from) { + case ax::mojom::DescriptionFrom::kNone: + return "none"; + case ax::mojom::DescriptionFrom::kUninitialized: + return "uninitialized"; + case ax::mojom::DescriptionFrom::kAttribute: + return "attribute"; + case ax::mojom::DescriptionFrom::kContents: + return "contents"; + case ax::mojom::DescriptionFrom::kPlaceholder: + return "placeholder"; + case ax::mojom::DescriptionFrom::kRelatedElement: + return "relatedElement"; + } + + return ""; +} + +ax::mojom::DescriptionFrom ParseDescriptionFrom(const char* description_from) { + if (0 == strcmp(description_from, "none")) + return ax::mojom::DescriptionFrom::kNone; + if (0 == strcmp(description_from, "uninitialized")) + return ax::mojom::DescriptionFrom::kUninitialized; + if (0 == strcmp(description_from, "attribute")) + return ax::mojom::DescriptionFrom::kAttribute; + if (0 == strcmp(description_from, "contents")) + return ax::mojom::DescriptionFrom::kContents; + if (0 == strcmp(description_from, "placeholder")) + return ax::mojom::DescriptionFrom::kPlaceholder; + if (0 == strcmp(description_from, "relatedElement")) + return ax::mojom::DescriptionFrom::kRelatedElement; + return ax::mojom::DescriptionFrom::kNone; +} + +const char* ToString(ax::mojom::EventFrom event_from) { + switch (event_from) { + case ax::mojom::EventFrom::kNone: + return "none"; + case ax::mojom::EventFrom::kUser: + return "user"; + case ax::mojom::EventFrom::kPage: + return "page"; + case ax::mojom::EventFrom::kAction: + return "action"; + } + + return ""; +} + +ax::mojom::EventFrom ParseEventFrom(const char* event_from) { + if (0 == strcmp(event_from, "none")) + return ax::mojom::EventFrom::kNone; + if (0 == strcmp(event_from, "user")) + return ax::mojom::EventFrom::kUser; + if (0 == strcmp(event_from, "page")) + return ax::mojom::EventFrom::kPage; + if (0 == strcmp(event_from, "action")) + return ax::mojom::EventFrom::kAction; + return ax::mojom::EventFrom::kNone; +} + +const char* ToString(ax::mojom::Gesture gesture) { + switch (gesture) { + case ax::mojom::Gesture::kNone: + return "none"; + case ax::mojom::Gesture::kClick: + return "click"; + case ax::mojom::Gesture::kSwipeLeft1: + return "swipeLeft1"; + case ax::mojom::Gesture::kSwipeUp1: + return "swipeUp1"; + case ax::mojom::Gesture::kSwipeRight1: + return "swipeRight1"; + case ax::mojom::Gesture::kSwipeDown1: + return "swipeDown1"; + case ax::mojom::Gesture::kSwipeLeft2: + return "swipeLeft2"; + case ax::mojom::Gesture::kSwipeUp2: + return "swipeUp2"; + case ax::mojom::Gesture::kSwipeRight2: + return "swipeRight2"; + case ax::mojom::Gesture::kSwipeDown2: + return "swipeDown2"; + case ax::mojom::Gesture::kSwipeLeft3: + return "swipeLeft3"; + case ax::mojom::Gesture::kSwipeUp3: + return "swipeUp3"; + case ax::mojom::Gesture::kSwipeRight3: + return "swipeRight3"; + case ax::mojom::Gesture::kSwipeDown3: + return "swipeDown3"; + case ax::mojom::Gesture::kSwipeLeft4: + return "swipeLeft4"; + case ax::mojom::Gesture::kSwipeUp4: + return "swipeUp4"; + case ax::mojom::Gesture::kSwipeRight4: + return "swipeRight4"; + case ax::mojom::Gesture::kSwipeDown4: + return "swipeDown4"; + case ax::mojom::Gesture::kTap2: + return "tap2"; + } + + return ""; +} + +ax::mojom::Gesture ParseGesture(const char* gesture) { + if (0 == strcmp(gesture, "none")) + return ax::mojom::Gesture::kNone; + if (0 == strcmp(gesture, "click")) + return ax::mojom::Gesture::kClick; + if (0 == strcmp(gesture, "swipeLeft1")) + return ax::mojom::Gesture::kSwipeLeft1; + if (0 == strcmp(gesture, "swipeUp1")) + return ax::mojom::Gesture::kSwipeUp1; + if (0 == strcmp(gesture, "swipeRight1")) + return ax::mojom::Gesture::kSwipeRight1; + if (0 == strcmp(gesture, "swipeDown1")) + return ax::mojom::Gesture::kSwipeDown1; + if (0 == strcmp(gesture, "swipeLeft2")) + return ax::mojom::Gesture::kSwipeLeft2; + if (0 == strcmp(gesture, "swipeUp2")) + return ax::mojom::Gesture::kSwipeUp2; + if (0 == strcmp(gesture, "swipeRight2")) + return ax::mojom::Gesture::kSwipeRight2; + if (0 == strcmp(gesture, "swipeDown2")) + return ax::mojom::Gesture::kSwipeDown2; + if (0 == strcmp(gesture, "swipeLeft3")) + return ax::mojom::Gesture::kSwipeLeft3; + if (0 == strcmp(gesture, "swipeUp3")) + return ax::mojom::Gesture::kSwipeUp3; + if (0 == strcmp(gesture, "swipeRight3")) + return ax::mojom::Gesture::kSwipeRight3; + if (0 == strcmp(gesture, "swipeDown3")) + return ax::mojom::Gesture::kSwipeDown3; + if (0 == strcmp(gesture, "swipeLeft4")) + return ax::mojom::Gesture::kSwipeLeft4; + if (0 == strcmp(gesture, "swipeUp4")) + return ax::mojom::Gesture::kSwipeUp4; + if (0 == strcmp(gesture, "swipeRight4")) + return ax::mojom::Gesture::kSwipeRight4; + if (0 == strcmp(gesture, "swipeDown4")) + return ax::mojom::Gesture::kSwipeDown4; + if (0 == strcmp(gesture, "tap2")) + return ax::mojom::Gesture::kTap2; + return ax::mojom::Gesture::kNone; +} + +const char* ToString(ax::mojom::TextAffinity text_affinity) { + switch (text_affinity) { + case ax::mojom::TextAffinity::kNone: + return "none"; + case ax::mojom::TextAffinity::kDownstream: + return "downstream"; + case ax::mojom::TextAffinity::kUpstream: + return "upstream"; + } + + return ""; +} + +ax::mojom::TextAffinity ParseTextAffinity(const char* text_affinity) { + if (0 == strcmp(text_affinity, "none")) + return ax::mojom::TextAffinity::kNone; + if (0 == strcmp(text_affinity, "downstream")) + return ax::mojom::TextAffinity::kDownstream; + if (0 == strcmp(text_affinity, "upstream")) + return ax::mojom::TextAffinity::kUpstream; + return ax::mojom::TextAffinity::kNone; +} + +const char* ToString(ax::mojom::TreeOrder tree_order) { + switch (tree_order) { + case ax::mojom::TreeOrder::kNone: + return "none"; + case ax::mojom::TreeOrder::kUndefined: + return "undefined"; + case ax::mojom::TreeOrder::kBefore: + return "before"; + case ax::mojom::TreeOrder::kEqual: + return "equal"; + case ax::mojom::TreeOrder::kAfter: + return "after"; + } + + return ""; +} + +ax::mojom::TreeOrder ParseTreeOrder(const char* tree_order) { + if (0 == strcmp(tree_order, "none")) + return ax::mojom::TreeOrder::kNone; + if (0 == strcmp(tree_order, "undefined")) + return ax::mojom::TreeOrder::kUndefined; + if (0 == strcmp(tree_order, "before")) + return ax::mojom::TreeOrder::kBefore; + if (0 == strcmp(tree_order, "equal")) + return ax::mojom::TreeOrder::kEqual; + if (0 == strcmp(tree_order, "after")) + return ax::mojom::TreeOrder::kAfter; + return ax::mojom::TreeOrder::kNone; +} + +} // namespace ui diff --git a/chromium/ui/accessibility/ax_enum_util.h b/chromium/ui/accessibility/ax_enum_util.h new file mode 100644 index 00000000000..e331b4ea41a --- /dev/null +++ b/chromium/ui/accessibility/ax_enum_util.h @@ -0,0 +1,130 @@ +// Copyright 2018 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/accessibility/ax_enums.mojom.h" +#include "ui/accessibility/ax_export.h" + +namespace ui { + +// ax::mojom::Event +AX_EXPORT const char* ToString(ax::mojom::Event event); +AX_EXPORT ax::mojom::Event ParseEvent(const char* event); + +// ax::mojom::Role +AX_EXPORT const char* ToString(ax::mojom::Role role); +AX_EXPORT ax::mojom::Role ParseRole(const char* role); + +// ax::mojom::State +AX_EXPORT const char* ToString(ax::mojom::State state); +AX_EXPORT ax::mojom::State ParseState(const char* state); + +// ax::mojom::Action +AX_EXPORT const char* ToString(ax::mojom::Action action); +AX_EXPORT ax::mojom::Action ParseAction(const char* action); + +// ax::mojom::ActionFlags +AX_EXPORT const char* ToString(ax::mojom::ActionFlags action_flags); +AX_EXPORT ax::mojom::ActionFlags ParseActionFlags(const char* action_flags); + +// ax::mojom::DefaultActionVerb +AX_EXPORT const char* ToString( + ax::mojom::DefaultActionVerb default_action_verb); +AX_EXPORT ax::mojom::DefaultActionVerb ParseDefaultActionVerb( + const char* default_action_verb); + +// ax::mojom::Mutation +AX_EXPORT const char* ToString(ax::mojom::Mutation mutation); +AX_EXPORT ax::mojom::Mutation ParseMutation(const char* mutation); + +// ax::mojom::StringAttribute +AX_EXPORT const char* ToString(ax::mojom::StringAttribute string_attribute); +AX_EXPORT ax::mojom::StringAttribute ParseStringAttribute( + const char* string_attribute); + +// ax::mojom::IntAttribute +AX_EXPORT const char* ToString(ax::mojom::IntAttribute int_attribute); +AX_EXPORT ax::mojom::IntAttribute ParseIntAttribute(const char* int_attribute); + +// ax::mojom::FloatAttribute +AX_EXPORT const char* ToString(ax::mojom::FloatAttribute float_attribute); +AX_EXPORT ax::mojom::FloatAttribute ParseFloatAttribute( + const char* float_attribute); + +// ax::mojom::BoolAttribute +AX_EXPORT const char* ToString(ax::mojom::BoolAttribute bool_attribute); +AX_EXPORT ax::mojom::BoolAttribute ParseBoolAttribute( + const char* bool_attribute); + +// ax::mojom::IntListAttribute +AX_EXPORT const char* ToString(ax::mojom::IntListAttribute int_list_attribute); +AX_EXPORT ax::mojom::IntListAttribute ParseIntListAttribute( + const char* int_list_attribute); + +// ax::mojom::StringListAttribute +AX_EXPORT const char* ToString( + ax::mojom::StringListAttribute string_list_attribute); +AX_EXPORT ax::mojom::StringListAttribute ParseStringListAttribute( + const char* string_list_attribute); + +// ax::mojom::MarkerType +AX_EXPORT const char* ToString(ax::mojom::MarkerType marker_type); +AX_EXPORT ax::mojom::MarkerType ParseMarkerType(const char* marker_type); + +// ax::mojom::TextDirection +AX_EXPORT const char* ToString(ax::mojom::TextDirection text_direction); +AX_EXPORT ax::mojom::TextDirection ParseTextDirection( + const char* text_direction); + +// ax::mojom::TextStyle +AX_EXPORT const char* ToString(ax::mojom::TextStyle text_style); +AX_EXPORT ax::mojom::TextStyle ParseTextStyle(const char* text_style); + +// ax::mojom::AriaCurrentState +AX_EXPORT const char* ToString(ax::mojom::AriaCurrentState aria_current_state); +AX_EXPORT ax::mojom::AriaCurrentState ParseAriaCurrentState( + const char* aria_current_state); + +// ax::mojom::InvalidState +AX_EXPORT const char* ToString(ax::mojom::InvalidState invalid_state); +AX_EXPORT ax::mojom::InvalidState ParseInvalidState(const char* invalid_state); + +// ax::mojom::Restriction +AX_EXPORT const char* ToString(ax::mojom::Restriction restriction); +AX_EXPORT ax::mojom::Restriction ParseRestriction(const char* restriction); + +// ax::mojom::CheckedState +AX_EXPORT const char* ToString(ax::mojom::CheckedState checked_state); +AX_EXPORT ax::mojom::CheckedState ParseCheckedState(const char* checked_state); + +// ax::mojom::SortDirection +AX_EXPORT const char* ToString(ax::mojom::SortDirection sort_direction); +AX_EXPORT ax::mojom::SortDirection ParseSortDirection( + const char* sort_direction); + +// ax::mojom::NameFrom +AX_EXPORT const char* ToString(ax::mojom::NameFrom name_from); +AX_EXPORT ax::mojom::NameFrom ParseNameFrom(const char* name_from); + +// ax::mojom::DescriptionFrom +AX_EXPORT const char* ToString(ax::mojom::DescriptionFrom description_from); +AX_EXPORT ax::mojom::DescriptionFrom ParseDescriptionFrom( + const char* description_from); + +// ax::mojom::EventFrom +AX_EXPORT const char* ToString(ax::mojom::EventFrom event_from); +AX_EXPORT ax::mojom::EventFrom ParseEventFrom(const char* event_from); + +// ax::mojom::Gesture +AX_EXPORT const char* ToString(ax::mojom::Gesture gesture); +AX_EXPORT ax::mojom::Gesture ParseGesture(const char* gesture); + +// ax::mojom::TextAffinity +AX_EXPORT const char* ToString(ax::mojom::TextAffinity text_affinity); +AX_EXPORT ax::mojom::TextAffinity ParseTextAffinity(const char* text_affinity); + +// ax::mojom::TreeOrder +AX_EXPORT const char* ToString(ax::mojom::TreeOrder tree_order); +AX_EXPORT ax::mojom::TreeOrder ParseTreeOrder(const char* tree_order); + +} // namespace ui diff --git a/chromium/ui/accessibility/ax_enums.idl b/chromium/ui/accessibility/ax_enums.idl deleted file mode 100644 index c3c73442e9b..00000000000 --- a/chromium/ui/accessibility/ax_enums.idl +++ /dev/null @@ -1,756 +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. - -// TODO(nektar): Migrate entire file to Mojoq. -// Must also be kept in sync with chrome/common/extensions/api/automation.idl. -[camel_case_enum_to_string=true] namespace ui { - - // For new entries to the following four enums, also add to - // chrome/common/extensions/api/automation.idl. This is enforced - // by a PRESUBMIT check. - // - // Explanation of the comments next to these events: - // - // Web: this event is only used in web content. Unless a specific platform - // is specified, it fires a native event on multiple platforms. - // - // Native: this event is only used in native UI. - // - // Implicit: it would be cleaner if we just updated the AX node - // and each platform fired the appropriate events to indicate which - // platform-specific attributes changed. - // - // If unspecified, the event is used across web and native on multiple - // platforms. - enum AXEvent { - activedescendantchanged, // Web - alert, - aria_attribute_changed, // Implicit - autocorrection_occured, // Unknown: http://crbug.com/392498 - blur, // Remove: http://crbug.com/392502 - checked_state_changed, // Implicit - children_changed, - clicked, - document_selection_changed, - expanded_changed, // Web - focus, - hide, // Remove: http://crbug.com/392502 - hit_test_result, - hover, - image_frame_updated, // Web - invalid_status_changed, // Implicit - layout_complete, // Web - live_region_created, // Implicit - live_region_changed, // Web - load_complete, // Web - location_changed, // Web - media_started_playing, // Automation - media_stopped_playing, // Automation - menu_end, // Native / Win - menu_list_item_selected, // Web - menu_list_value_changed, // Web - menu_popup_end, // Native / Win - menu_popup_start, // Native / Win - menu_start, // Native / Win - mouse_canceled, - mouse_dragged, - mouse_moved, - mouse_pressed, - mouse_released, - row_collapsed, // Web / Mac - row_count_changed, // Web / Mac - row_expanded, // Web / Mac - scroll_position_changed, // Web - scrolled_to_anchor, // Web - selected_children_changed, // Web - selection, // Native - selection_add, // Native - selection_remove, // Native - show, // Remove: http://crbug.com/392502 - text_changed, - text_selection_changed, - tree_changed, // Accessibility tree changed. Don't - // explicitly fire an accessibility event, - // only implicitly due to the change. - value_changed - }; - - enum AXRole { - abbr, - alert_dialog, - alert, - anchor, - annotation, - application, - article, - audio, - banner, - blockquote, - button, - button_drop_down, // Not used on Web. - canvas, - caption, - caret, - cell, - check_box, - client, - color_well, - column_header, - column, - combo_box_grouping, - combo_box_menu_button, - complementary, - content_info, - date, - date_time, - definition, - description_list_detail, - description_list, - description_list_term, - desktop, - details, - dialog, - directory, - disclosure_triangle, - document, - embedded_object, - feed, - figcaption, - figure, - footer, - form, - generic_container, - grid, - group, - heading, - iframe, - iframe_presentational, - ignored, - image_map, - image, - inline_text_box, - input_time, - label_text, - legend, - line_break, - link, - list_box_option, - list_box, - list_item, - list_marker, - list, - location_bar, - log, - main, - mark, - marquee, - math, - menu, - menu_bar, - menu_button, - menu_item, - menu_item_check_box, - menu_item_radio, - menu_list_option, - menu_list_popup, - meter, - navigation, - note, - pane, - paragraph, - pop_up_button, - pre, - presentational, - progress_indicator, - radio_button, - radio_group, - region, - root_web_area, - row_header, - row, - ruby, - svg_root, - scroll_bar, - search, - search_box, - slider, - slider_thumb, - spin_button_part, - spin_button, - splitter, - static_text, - status, - switch, - tab_list, - tab_panel, - tab, - table_header_container, - table, - term, - text_field, - text_field_with_combo_box, - time, - timer, - title_bar, - toggle_button, - toolbar, - tree_grid, - tree_item, - tree, - unknown, - tooltip, - video, - web_area, - web_view, - window - }; - - enum AXState { - collapsed, - default, - editable, - expanded, - focusable, - haspopup, - // Grows horizontally, e.g. most toolbars and separators. - horizontal, - hovered, - invisible, - linked, - multiline, - multiselectable, - protected, - required, - richly_editable, - selectable, - selected, - // Grows vertically, e.g. menu or combo box. - vertical, - visited - }; - - // An action to be taken on an accessibility node. - // In contrast to |AXDefaultActionVerb|, these describe what happens to the - // object, e.g. "FOCUS". - enum AXAction { - blur, - - custom_action, - - // Decrement a slider or range control by one step value. - decrement, - - // Do the default action for an object, typically this means "click". - do_default, - - focus, - - // Return the content of this image object in the image_data attribute. - get_image_data, - - // Given a point, find the object it corresponds to and fire a - // |AXActionData.hit_test_event_to_fire| event on it in response. - hit_test, - - // Increment a slider or range control by one step value. - increment, - - // Load inline text boxes for this subtree, providing information - // about word boundaries, line layout, and individual character - // bounding boxes. - load_inline_text_boxes, - - // Delete any selected text in the control's text value and - // insert |AXActionData::value| in its place, like when typing or pasting. - replace_selected_text, - - // Scrolls by approximately one screen in a specific direction. Should be - // called on a node that has scrollable boolean set to true. - scroll_backward, - scroll_forward, - scroll_up, - scroll_down, - scroll_left, - scroll_right, - - // Scroll any scrollable containers to make the target object visible - // on the screen. Optionally pass a subfocus rect in - // AXActionData.target_rect, in node-local coordinates. - scroll_to_make_visible, - - // Scroll the given object to a specified point on the screen in - // global screen coordinates. Pass a point in AXActionData.target_point. - scroll_to_point, - - set_scroll_offset, - set_selection, - - // Don't focus this node, but set it as the sequential focus navigation - // starting point, so that pressing Tab moves to the next element - // following this one, for example. - set_sequential_focus_navigation_starting_point, - - // Replace the value of the control with AXActionData::value and - // reset the selection, if applicable. - set_value, - - show_context_menu - }; - - enum AXActionFlags { - request_images, - request_inline_text_boxes - }; - - // A list of valid values for the |AXIntAttribute| |default_action_verb|. - // These will describe the action that will be performed on a given node when - // executing the default action, which is a click. - // In contrast to |AXAction|, these describe what the user can do on the - // object, e.g. "PRESS", not what happens to the object as a result. - // Only one verb can be used at a time to describe the default action. - enum AXDefaultActionVerb { - activate, - check, - click, - - // A click will be performed on one of the node's ancestors. - // This happens when the node itself is not clickable, but one of its - // ancestors has click handlers attached which are able to capture the click - // as it bubbles up. - click_ancestor, - - jump, - open, - press, - select, - uncheck - }; - - // A change to the accessibility tree. - enum AXMutation { - node_created, - subtree_created, - node_changed, - node_removed - }; - - [cpp_enum_prefix_override="ax_attr"] enum AXStringAttribute { - access_key, - // Only used when invalid_state == invalid_state_other. - aria_invalid_value, - auto_complete, - chrome_channel, // Automation only. - class_name, // views and Android - container_live_relevant, - container_live_status, - description, - display, - // Only present when different from parent. - font_family, - html_tag, - image_data_url, - inner_html, - key_shortcuts, - // Only present when different from parent. - language, - name, - live_relevant, - live_status, - placeholder, - role, - role_description, - url, - value - }; - - [cpp_enum_prefix_override="ax_attr"] enum AXIntAttribute { - default_action_verb, - // Scrollable container attributes. - scroll_x, - scroll_x_min, - scroll_x_max, - scroll_y, - scroll_y_min, - scroll_y_max, - - // Attributes for retrieving the endpoints of a selection. - text_sel_start, - text_sel_end, - - // aria_col* and aria_row* attributes - aria_column_count, - aria_cell_column_index, - aria_row_count, - aria_cell_row_index, - - // Table attributes. - table_row_count, - table_column_count, - table_header_id, - - // Table row attributes. - table_row_index, - table_row_header_id, - - // Table column attributes. - table_column_index, - table_column_header_id, - - // Table cell attributes. - table_cell_column_index, - table_cell_column_span, - table_cell_row_index, - table_cell_row_span, - sort_direction, - - // Tree control attributes. - hierarchical_level, - - // What information was used to compute the object's name - // (of type AXNameFrom). - name_from, - - // What information was used to compute the object's description - // (of type AXDescriptionFrom). - description_from, - - // Relationships between this element and other elements. - activedescendant_id, - details_id, - errormessage_id, - in_page_link_target_id, - member_of_id, - next_on_line_id, - previous_on_line_id, - - // Identifies a child tree which this node hosts. - child_tree_id, - - // Input restriction, if any, such as readonly or disabled. - // Of type AXRestriction, see below. - // No value or enabled control or other object that is not disabled. - restriction, - - // Position or Number of items in current set of listitems or treeitems - set_size, - pos_in_set, - - // In the case of AX_ROLE_COLOR_WELL, specifies the selected color. - color_value, - - // Indicates the element that represents the current item within a container - // or set of related elements. - aria_current_state, - - // Text attributes. - - // Foreground and background color in RGBA. - background_color, - color, - - // Indicates if a form control has invalid input or - // if an element has an aria-invalid attribute. - invalid_state, - - // Of type AXCheckedState - checked_state, - - // Specifies the direction of the text, e.g., right-to-left. - text_direction, - - // Bold, italic, underline, etc. - text_style, - - // Focus traversal in views and Android. - previous_focus_id, - next_focus_id - }; - - [cpp_enum_prefix_override="ax_attr"] enum AXFloatAttribute { - // Range attributes. - value_for_range, - min_value_for_range, - max_value_for_range, - step_value_for_range, - - // Text attributes. - // Font size is in pixels. - font_size - }; - - [cpp_enum_prefix_override="ax_attr"] enum AXBoolAttribute { - // Generic busy state, does not have to be on a live region. - busy, - // The object is at the root of an editable field, such as a content - // editable. - editable_root, - - // Live region attributes. - container_live_atomic, - container_live_busy, - live_atomic, - - // If a dialog box is marked as explicitly modal - modal, - - // If this is set, all of the other fields in this struct should - // be ignored and only the locations should change. - update_location_only, - - // Set on a canvas element if it has fallback content. - canvas_has_fallback, - - // Indicates this node is scrollable (Android only). - scrollable, - - // A hint to clients that the node is clickable. - clickable, - - // Indicates that this node clips its children, i.e. may have - // overflow: hidden or clip children by default. - clips_children - }; - - [cpp_enum_prefix_override="ax_attr"] enum AXIntListAttribute { - // Ids of nodes that are children of this node logically, but are - // not children of this node in the tree structure. As an example, - // a table cell is a child of a row, and an 'indirect' child of a - // column. - indirect_child_ids, - - // Relationships between this element and other elements. - controls_ids, - describedby_ids, - flowto_ids, - labelledby_ids, - radio_group_ids, - - // For static text. Character indices where line breaks occur. Note that - // this attribute is only available on Chrome OS and will be deprecated - // soon. - line_breaks, - - // For static text. These int lists must be the same size; they represent - // the start and end character offset of each marker. Examples of markers - // include spelling and grammar errors, and find-in-page matches. - marker_types, - marker_starts, - marker_ends, - - // For a table, the cell ids in row-major order, with duplicate entries - // when there's a rowspan or colspan, and with -1 for missing cells. - // There are always exactly rows * columns entries. - cell_ids, - - // For a table, the unique cell ids in row-major order of their first - // occurrence. - unique_cell_ids, - - // For inline text. This is the pixel position of the end of this - // character within the bounding rectangle of this object, in the - // direction given by AX_ATTR_TEXT_DIRECTION. For example, for left-to-right - // text, the first offset is the right coordinate of the first character - // within the object's bounds, the second offset is the right coordinate - // of the second character, and so on. - character_offsets, - - // Used for caching. Do not read directly. Use - // |AXNode::GetOrComputeLineStartOffsets| - // For all text fields and content editable roots: A list of the start - // offsets of each line inside this object. - cached_line_starts, - - // For inline text. These int lists must be the same size; they represent - // the start and end character offset of each word within this text. - word_starts, - word_ends, - - // Used for an UI element to define custom actions for it. For example, a - // list UI will allow a user to reorder items in the list by dragging the - // items. Developer can expose those actions as custom actions. Currently - // custom actions are used only in Android window. - custom_action_ids - }; - - [cpp_enum_prefix_override="ax_attr"] enum AXStringListAttribute { - // Descriptions for custom actions. This must be aligned with - // custom_action_ids. - custom_action_descriptions - }; - - // TODO(dmazzoni, nektar): make this list not grow exponentially as new - // MarkerTypes are added - enum AXMarkerType { - // Assignments are ignored by the parser, but are kept here for clarity. - spelling = 1, - grammar = 2, - spelling_grammar = 3, - text_match = 4, - spelling_text_match = 5, - grammar_text_match = 6, - spelling_grammar_text_match = 7, - // DocumentMarker::MarkerType::Composition = 8 is ignored for accessibility - // purposes - active_suggestion = 16, - spelling_active_suggestion = 17, - grammar_active_suggestion = 18, - spelling_grammar_active_suggestion = 19, - text_match_active_suggestion = 20, - spelling_text_match_active_suggestion = 21, - grammar_text_match_active_suggestion = 22, - spelling_grammar_text_match_active_suggestion = 23, - suggestion = 32, - spelling_suggestion = 33, - grammar_suggestion = 34, - spelling_grammar_suggestion = 35, - text_match_suggestion = 36, - spelling_text_match_suggestion = 37, - grammar_text_match_suggestion = 38, - spelling_grammar_text_match_suggestion = 39, - // We again skip over DocumentMarker::MarkerType::Composition = 8 here - active_suggestion_suggestion = 48, - spelling_active_suggestion_suggestion = 49, - grammar_active_suggestion_suggestion = 50, - spelling_grammar_active_suggestion_suggestion = 51, - text_match_active_suggestion_suggestion = 52, - spelling_text_match_active_suggestion_suggestion = 53, - grammar_text_match_active_suggestion_suggestion = 54, - spelling_grammar_text_match_active_suggestion_suggestion = 55 - }; - - enum AXTextDirection { - ltr, - rtl, - ttb, - btt - }; - - // A Java counterpart will be generated for this enum. - // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.accessibility - [cpp_enum_prefix_override="ax"] enum AXTextStyle { - // Assignments are ignored by the parser, but are kept here for clarity. - text_style_bold = 1, - text_style_italic = 2, - text_style_bold_italic = 3, - text_style_underline = 4, - text_style_bold_underline = 5, - text_style_italic_underline = 6, - text_style_bold_italic_underline = 7, - text_style_line_through = 8, - text_style_bold_line_through = 9, - text_style_italic_line_through = 10, - text_style_bold_italic_line_through = 11, - text_style_underline_line_through = 12, - text_style_bold_underline_line_through = 13, - text_style_italic_underline_line_through = 14, - text_style_bold_italic_underline_line_through = 15 - }; - - enum AXAriaCurrentState { - false, - true, - page, - step, - location, - unclipped_location, - date, - time - }; - - enum AXInvalidState { - false, - true, - spelling, - grammar, - other - }; - - // Input restriction associated with an object. - // No value for a control means it is enabled. - // Use read_only for a textbox that allows focus/selection but not input. - // Use disabled for a control or group of controls that disallows input. - enum AXRestriction { - read_only, - disabled - }; - - enum AXCheckedState { - false, - true, - mixed - }; - - enum AXSortDirection { - unsorted, - ascending, - descending, - other - }; - - enum AXNameFrom { - uninitialized, - attribute, - attribute_explicitly_empty, - contents, - placeholder, - related_element, - value - }; - - enum AXDescriptionFrom { - uninitialized, - attribute, - contents, - placeholder, - related_element - }; - - enum AXEventFrom { - user, - page, - action - }; - - // Touch gestures on Chrome OS. - enum AXGesture { - click, - swipe_left_1, - swipe_up_1, - swipe_right_1, - swipe_down_1, - swipe_left_2, - swipe_up_2, - swipe_right_2, - swipe_down_2, - swipe_left_3, - swipe_up_3, - swipe_right_3, - swipe_down_3, - swipe_left_4, - swipe_up_4, - swipe_right_4, - swipe_down_4, - tap_2 - }; - - enum AXTextAffinity { - downstream, - upstream - }; - - // Compares two nodes in an accessibility tree in pre-order traversal. - enum AXTreeOrder { - // Not in the same tree, or other error. - undefined, - - // First node is before the second one. - before, - - // Nodes are the same. - equal, - - // First node is after the second one. - after - }; -}; diff --git a/chromium/ui/accessibility/ax_enums.mojom b/chromium/ui/accessibility/ax_enums.mojom new file mode 100644 index 00000000000..7d0d2a3e026 --- /dev/null +++ b/chromium/ui/accessibility/ax_enums.mojom @@ -0,0 +1,820 @@ +// Copyright 2018 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. + +// TODO(nektar): Migrate entire file to Mojoq. +// Must also be kept in sync with chrome/common/extensions/api/automation.idl. +module ax.mojom; + + // For new entries to the following four enums, also add to + // chrome/common/extensions/api/automation.idl. This is enforced + // by a PRESUBMIT check. + // + // Explanation of the comments next to these events: + // + // Web: this event is only used in web content. Unless a specific platform + // is specified, it fires a native event on multiple platforms. + // + // Native: this event is only used in native UI. + // + // Implicit: it would be cleaner if we just updated the AX node + // and each platform fired the appropriate events to indicate which + // platform-specific attributes changed. + // + // If unspecified, the event is used across web and native on multiple + // platforms. +enum Event { + kNone, + kActiveDescendantChanged, // Web + kAlert, + kAriaAttributeChanged, // Implicit + kAutocorrectionOccured, // Unknown: http://crbug.com/392498 + kBlur, // Remove: http://crbug.com/392502 + kCheckedStateChanged, // Implicit + kChildrenChanged, + kClicked, + kDocumentSelectionChanged, + kExpandedChanged, // Web + kFocus, + kHide, // Remove: http://crbug.com/392502 + kHitTestResult, + kHover, + kImageFrameUpdated, // Web + kInvalidStatusChanged, // Implicit + kLayoutComplete, // Web + kLiveRegionCreated, // Implicit + kLiveRegionChanged, // Web + kLoadComplete, // Web + kLocationChanged, // Web + kMediaStartedPlaying, // Automation + kMediaStoppedPlaying, // Automation + kMenuEnd, // Native / Win + kMenuListItemSelected, // Web + kMenuListValueChanged, // Web + kMenuPopupEnd, // Native / Win + kMenuPopupStart, // Native / Win + kMenuStart, // Native / Win + kMouseCanceled, + kMouseDragged, + kMouseMoved, + kMousePressed, + kMouseReleased, + kRowCollapsed, // Web / Mac + kRowCountChanged, // Web / Mac + kRowExpanded, // Web / Mac + kScrollPositionChanged, // Web + kScrolledToAnchor, // Web + kSelectedChildrenChanged, // Web + kSelection, // Native + kSelectionAdd, // Native + kSelectionRemove, // Native + kShow, // Remove: http://crbug.com/392502 + kTextChanged, + kTextSelectionChanged, + kTreeChanged, // Accessibility tree changed. Don't + // explicitly fire an accessibility event, + // only implicitly due to the change. + kValueChanged, + kLast = kValueChanged, +}; + +// Explanation: +// The majority of these roles come from the ARIA specification. Reference +// the latest draft for proper usage. +// +// Roles not included by the ARIA specification should be avoided, especially +// internal roles used by the accessibility infrastructure. +enum Role { + kNone, + kAbbr, + kAlertDialog, + kAlert, + kAnchor, + kAnnotation, + kApplication, + kArticle, + kAudio, + kBanner, + kBlockquote, + kButton, + kCanvas, + kCaption, + kCaret, + kCell, + kCheckBox, + kClient, + kColorWell, + kColumnHeader, + kColumn, + kComboBoxGrouping, + kComboBoxMenuButton, + kComplementary, + kContentInfo, + kDate, + kDateTime, + kDefinition, + kDescriptionListDetail, + kDescriptionList, + kDescriptionListTerm, + kDesktop, // internal + kDetails, + kDialog, + kDirectory, + kDisclosureTriangle, + kDocument, + kEmbeddedObject, + kFeed, + kFigcaption, + kFigure, + kFooter, + kForm, + kGenericContainer, + kGrid, + kGroup, + kHeading, + kIframe, + kIframePresentational, + kIgnored, + kImageMap, + kImage, + kInlineTextBox, + kInputTime, + kLabelText, + kLayoutTable, + kLayoutTableCell, + kLayoutTableColumn, + kLayoutTableRow, + kLegend, + kLineBreak, + kLink, + kListBoxOption, + kListBox, + kListItem, + kListMarker, + kList, + kLocationBar, + kLog, + kMain, + kMark, + kMarquee, + kMath, + kMenu, + kMenuBar, + kMenuButton, + kMenuItem, + kMenuItemCheckBox, + kMenuItemRadio, + kMenuListOption, + kMenuListPopup, + kMeter, + kNavigation, + kNote, + kPane, + kParagraph, + kPopUpButton, + kPre, + kPresentational, + kProgressIndicator, + kRadioButton, + kRadioGroup, + kRegion, + kRootWebArea, + kRowHeader, + kRow, + kRuby, + kSvgRoot, + kScrollBar, + kSearch, + kSearchBox, + kSlider, + kSliderThumb, + kSpinButtonPart, + kSpinButton, + kSplitter, + kStaticText, + kStatus, + kSwitch, + kTabList, + kTabPanel, + kTab, + kTableHeaderContainer, + kTable, + kTerm, + kTextField, + kTextFieldWithComboBox, + kTime, + kTimer, + kTitleBar, + kToggleButton, + kToolbar, + kTreeGrid, + kTreeItem, + kTree, + kUnknown, + kTooltip, + kVideo, + kWebArea, + kWebView, + kWindow, + kLast = kWindow, +}; + +enum State { + kNone, + kCollapsed, + kDefault, + kEditable, + kExpanded, + kFocusable, + kHaspopup, + // Grows horizontally, e.g. most toolbars and separators. + kHorizontal, + kHovered, + // Skip over this node in the accessibility tree, but keep its subtree. + kIgnored, + kInvisible, + kLinked, + kMultiline, + kMultiselectable, + kProtected, + kRequired, + kRichlyEditable, + kSelectable, + kSelected, + // Grows vertically, e.g. menu or combo box. + kVertical, + kVisited, + kLast = kVisited, +}; + + // An action to be taken on an accessibility node. + // In contrast to |AXDefaultActionVerb|, these describe what happens to the + // object, e.g. "FOCUS". +enum Action { + kNone, + kBlur, + + kCustomAction, + + // Decrement a slider or range control by one step value. + kDecrement, + + // Do the default action for an object, typically this means "click". + kDoDefault, + + kFocus, + + // Return the content of this image object in the image_data attribute. + kGetImageData, + + // Given a point, find the object it corresponds to and fire a + // |AXActionData.hit_test_event_to_fire| event on it in response. + kHitTest, + + // Increment a slider or range control by one step value. + kIncrement, + + // Load inline text boxes for this subtree, providing information + // about word boundaries, line layout, and individual character + // bounding boxes. + kLoadInlineTextBoxes, + + // Delete any selected text in the control's text value and + // insert |AXActionData::value| in its place, like when typing or pasting. + kReplaceSelectedText, + + // Scrolls by approximately one screen in a specific direction. Should be + // called on a node that has scrollable boolean set to true. + kScrollBackward, + kScrollForward, + kScrollUp, + kScrollDown, + kScrollLeft, + kScrollRight, + + // Scroll any scrollable containers to make the target object visible + // on the screen. Optionally pass a subfocus rect in + // AXActionData.target_rect, in node-local coordinates. + kScrollToMakeVisible, + + // Scroll the given object to a specified point on the screen in + // global screen coordinates. Pass a point in AXActionData.target_point. + kScrollToPoint, + + kSetScrollOffset, + kSetSelection, + + // Don't focus this node, but set it as the sequential focus navigation + // starting point, so that pressing Tab moves to the next element + // following this one, for example. + kSetSequentialFocusNavigationStartingPoint, + + // Replace the value of the control with AXActionData::value and + // reset the selection, if applicable. + kSetValue, + + kShowContextMenu, + kLast = kShowContextMenu, +}; + +enum ActionFlags { + kNone, + kRequestImages, + kRequestInlineTextBoxes, + kLast = kRequestInlineTextBoxes, +}; + + // A list of valid values for the |AXIntAttribute| |default_action_verb|. + // These will describe the action that will be performed on a given node when + // executing the default action, which is a click. + // In contrast to |AXAction|, these describe what the user can do on the + // object, e.g. "PRESS", not what happens to the object as a result. + // Only one verb can be used at a time to describe the default action. +enum DefaultActionVerb { + kNone, + kActivate, + kCheck, + kClick, + + // A click will be performed on one of the node's ancestors. + // This happens when the node itself is not clickable, but one of its + // ancestors has click handlers attached which are able to capture the click + // as it bubbles up. + kClickAncestor, + + kJump, + kOpen, + kPress, + kSelect, + kUncheck, + kLast = kUncheck, +}; + + // A change to the accessibility tree. +enum Mutation { + kNone, + kNodeCreated, + kSubtreeCreated, + kNodeChanged, + kNodeRemoved, + kLast = kNodeRemoved, +}; + +enum StringAttribute { + kNone, + kAccessKey, + // Only used when invalid_state == invalid_state_other. + kAriaInvalidValue, + kAutoComplete, + kChromeChannel, // Automation only. + kClassName, // views and Android + kContainerLiveRelevant, + kContainerLiveStatus, + kDescription, + kDisplay, + // Only present when different from parent. + kFontFamily, + kHtmlTag, + kImageDataUrl, + kInnerHtml, + kKeyShortcuts, + // Only present when different from parent. + kLanguage, + kName, + kLiveRelevant, + kLiveStatus, + kPlaceholder, + kRole, + kRoleDescription, + kUrl, + kValue, + kLast = kValue, +}; + +enum IntAttribute { + kNone, + kDefaultActionVerb, + // Scrollable container attributes. + kScrollX, + kScrollXMin, + kScrollXMax, + kScrollY, + kScrollYMin, + kScrollYMax, + + // Attributes for retrieving the endpoints of a selection. + kTextSelStart, + kTextSelEnd, + + // aria_col* and aria_row* attributes + kAriaColumnCount, + kAriaCellColumnIndex, + kAriaRowCount, + kAriaCellRowIndex, + + // Table attributes. + kTableRowCount, + kTableColumnCount, + kTableHeaderId, + + // Table row attributes. + kTableRowIndex, + kTableRowHeaderId, + + // Table column attributes. + kTableColumnIndex, + kTableColumnHeaderId, + + // Table cell attributes. + kTableCellColumnIndex, + kTableCellColumnSpan, + kTableCellRowIndex, + kTableCellRowSpan, + kSortDirection, + + // Tree control attributes. + kHierarchicalLevel, + + // What information was used to compute the object's name + // (of type AXNameFrom). + kNameFrom, + + // What information was used to compute the object's description + // (of type AXDescriptionFrom). + kDescriptionFrom, + + // Relationships between this element and other elements. + kActivedescendantId, + kDetailsId, + kErrormessageId, + kInPageLinkTargetId, + kMemberOfId, + kNextOnLineId, + kPreviousOnLineId, + + // Identifies a child tree which this node hosts. + kChildTreeId, + + // Input restriction, if any, such as readonly or disabled. + // Of type AXRestriction, see below. + // No value or enabled control or other object that is not disabled. + kRestriction, + + // Position or Number of items in current set of listitems or treeitems + kSetSize, + kPosInSet, + + // In the case of Role::kColorWell, specifies the selected color. + kColorValue, + + // Indicates the element that represents the current item within a container + // or set of related elements. + kAriaCurrentState, + + // Text attributes. + + // Foreground and background color in RGBA. + kBackgroundColor, + kColor, + + // Indicates if a form control has invalid input or + // if an element has an aria-invalid attribute. + kInvalidState, + + // Of type AXCheckedState + kCheckedState, + + // Specifies the direction of the text, e.g., right-to-left. + kTextDirection, + + // Bold, italic, underline, etc. + kTextStyle, + + // Focus traversal in views and Android. + kPreviousFocusId, + kNextFocusId, + kLast = kNextFocusId, +}; + +enum FloatAttribute { + kNone, + // Range attributes. + kValueForRange, + kMinValueForRange, + kMaxValueForRange, + kStepValueForRange, + + // Text attributes. + // Font size is in pixels. + kFontSize, + kLast = kFontSize, +}; + +enum BoolAttribute { + kNone, + // Generic busy state, does not have to be on a live region. + kBusy, + // The object is at the root of an editable field, such as a content + // editable. + kEditableRoot, + + // Live region attributes. + kContainerLiveAtomic, + kContainerLiveBusy, + kLiveAtomic, + + // If a dialog box is marked as explicitly modal + kModal, + + // If this is set, all of the other fields in this struct should + // be ignored and only the locations should change. + kUpdateLocationOnly, + + // Set on a canvas element if it has fallback content. + kCanvasHasFallback, + + // Indicates this node is scrollable (Android only). + kScrollable, + + // A hint to clients that the node is clickable. + kClickable, + + // Indicates that this node clips its children, i.e. may have + // overflow: hidden or clip children by default. + kClipsChildren, + kLast = kClipsChildren, +}; + +enum IntListAttribute { + kNone, + // Ids of nodes that are children of this node logically, but are + // not children of this node in the tree structure. As an example, + // a table cell is a child of a row, and an 'indirect' child of a + // column. + kIndirectChildIds, + + // Relationships between this element and other elements. + kControlsIds, + kDescribedbyIds, + kFlowtoIds, + kLabelledbyIds, + kRadioGroupIds, + + // For static text. Character indices where line breaks occur. Note that + // this attribute is only available on Chrome OS and will be deprecated + // soon. + kLineBreaks, + + // For static text. These int lists must be the same size; they represent + // the start and end character offset of each marker. Examples of markers + // include spelling and grammar errors, and find-in-page matches. + kMarkerTypes, + kMarkerStarts, + kMarkerEnds, + + // For a table, the cell ids in row-major order, with duplicate entries + // when there's a rowspan or colspan, and with -1 for missing cells. + // There are always exactly rows * columns entries. + kCellIds, + + // For a table, the unique cell ids in row-major order of their first + // occurrence. + kUniqueCellIds, + + // For inline text. This is the pixel position of the end of this + // character within the bounding rectangle of this object, in the + // direction given by StringAttribute::kTextDirection. For example, + // for left-to-right text, the first offset is the right coordinate of + // the first character within the object's bounds, the second offset + // is the right coordinate of the second character, and so on. + kCharacterOffsets, + + // Used for caching. Do not read directly. Use + // |AXNode::GetOrComputeLineStartOffsets| + // For all text fields and content editable roots: A list of the start + // offsets of each line inside this object. + kCachedLineStarts, + + // For inline text. These int lists must be the same size; they represent + // the start and end character offset of each word within this text. + kWordStarts, + kWordEnds, + + // Used for an UI element to define custom actions for it. For example, a + // list UI will allow a user to reorder items in the list by dragging the + // items. Developer can expose those actions as custom actions. Currently + // custom actions are used only in Android window. + kCustomActionIds, + kLast = kCustomActionIds, +}; + +enum StringListAttribute { + kNone, + // Descriptions for custom actions. This must be aligned with + // custom_action_ids. + kCustomActionDescriptions, + kLast = kCustomActionDescriptions, +}; + + // TODO(dmazzoni, nektar): make this list not grow exponentially as new + // MarkerTypes are added +enum MarkerType { + kNone, + // Assignments are ignored by the parser, but are kept here for clarity. + kSpelling = 1, + kGrammar = 2, + kSpellingGrammar = 3, + kTextMatch = 4, + kSpellingTextMatch = 5, + kGrammarTextMatch = 6, + kSpellingGrammarTextMatch = 7, + // DocumentMarker::MarkerType::Composition = 8 is ignored for accessibility + // purposes + kActiveSuggestion = 16, + kSpellingActiveSuggestion = 17, + kGrammarActiveSuggestion = 18, + kSpellingGrammarActiveSuggestion = 19, + kTextMatchActiveSuggestion = 20, + kSpellingTextMatchActiveSuggestion = 21, + kGrammarTextMatchActiveSuggestion = 22, + kSpellingGrammarTextMatchActiveSuggestion = 23, + kSuggestion = 32, + kSpellingSuggestion = 33, + kGrammarSuggestion = 34, + kSpellingGrammarSuggestion = 35, + kTextMatchSuggestion = 36, + kSpellingTextMatchSuggestion = 37, + kGrammarTextMatchSuggestion = 38, + kSpellingGrammarTextMatchSuggestion = 39, + // We again skip over DocumentMarker::MarkerType::Composition = 8 here + kActiveSuggestionSuggestion = 48, + kSpellingActiveSuggestionSuggestion = 49, + kGrammarActiveSuggestionSuggestion = 50, + kSpellingGrammarActiveSuggestionSuggestion = 51, + kTextMatchActiveSuggestionSuggestion = 52, + kSpellingTextMatchActiveSuggestionSuggestion = 53, + kGrammarTextMatchActiveSuggestionSuggestion = 54, + kSpellingGrammarTextMatchActiveSuggestionSuggestion = 55, + kLast = kSpellingGrammarTextMatchActiveSuggestionSuggestion, +}; + +enum TextDirection { + kNone, + kLtr, + kRtl, + kTtb, + kBtt, + kLast = kBtt, +}; + + // A Java counterpart will be generated for this enum. + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.accessibility +enum TextStyle { + kNone, + // Assignments are ignored by the parser, but are kept here for clarity. + kTextStyleBold = 1, + kTextStyleItalic = 2, + kTextStyleBoldItalic = 3, + kTextStyleUnderline = 4, + kTextStyleBoldUnderline = 5, + kTextStyleItalicUnderline = 6, + kTextStyleBoldItalicUnderline = 7, + kTextStyleLineThrough = 8, + kTextStyleBoldLineThrough = 9, + kTextStyleItalicLineThrough = 10, + kTextStyleBoldItalicLineThrough = 11, + kTextStyleUnderlineLineThrough = 12, + kTextStyleBoldUnderlineLineThrough = 13, + kTextStyleItalicUnderlineLineThrough = 14, + kTextStyleBoldItalicUnderlineLineThrough = 15, + kLast = kTextStyleBoldItalicUnderlineLineThrough, +}; + +enum AriaCurrentState { + kNone, + kFalse, + kTrue, + kPage, + kStep, + kLocation, + kUnclippedLocation, + kDate, + kTime, + kLast = kTime, +}; + +enum InvalidState { + kNone, + kFalse, + kTrue, + kSpelling, + kGrammar, + kOther, + kLast = kOther, +}; + + // Input restriction associated with an object. + // No value for a control means it is enabled. + // Use read_only for a textbox that allows focus/selection but not input. + // Use disabled for a control or group of controls that disallows input. +enum Restriction { + kNone, + kReadOnly, + kDisabled, + kLast = kDisabled, +}; + +enum CheckedState { + kNone, + kFalse, + kTrue, + kMixed, + kLast = kMixed, +}; + +enum SortDirection { + kNone, + kUnsorted, + kAscending, + kDescending, + kOther, + kLast = kOther, +}; + +enum NameFrom { + kNone, + kUninitialized, + kAttribute, + kAttributeExplicitlyEmpty, + kContents, + kPlaceholder, + kRelatedElement, + kValue, + kLast = kValue, +}; + +enum DescriptionFrom { + kNone, + kUninitialized, + kAttribute, + kContents, + kPlaceholder, + kRelatedElement, + kLast = kRelatedElement, +}; + +enum EventFrom { + kNone, + kUser, + kPage, + kAction, + kLast = kAction, +}; + + // Touch gestures on Chrome OS. +enum Gesture { + kNone, + kClick, + kSwipeLeft1, + kSwipeUp1, + kSwipeRight1, + kSwipeDown1, + kSwipeLeft2, + kSwipeUp2, + kSwipeRight2, + kSwipeDown2, + kSwipeLeft3, + kSwipeUp3, + kSwipeRight3, + kSwipeDown3, + kSwipeLeft4, + kSwipeUp4, + kSwipeRight4, + kSwipeDown4, + kTap2, + kLast = kTap2, +}; + +enum TextAffinity { + kNone, + kDownstream, + kUpstream, + kLast = kUpstream, +}; + + // Compares two nodes in an accessibility tree in pre-order traversal. +enum TreeOrder { + kNone, + // Not in the same tree, or other error. + kUndefined, + + // First node is before the second one. + kBefore, + + // Nodes are the same. + kEqual, + + // First node is after the second one. + kAfter, + kLast = kAfter, +}; diff --git a/chromium/ui/accessibility/ax_event_generator.cc b/chromium/ui/accessibility/ax_event_generator.cc index caa03843531..52747b1632b 100644 --- a/chromium/ui/accessibility/ax_event_generator.cc +++ b/chromium/ui/accessibility/ax_event_generator.cc @@ -81,7 +81,7 @@ void AXEventGenerator::ClearEvents() { void AXEventGenerator::AddEvent(ui::AXNode* node, AXEventGenerator::Event event) { - if (node->data().role == AX_ROLE_INLINE_TEXT_BOX) + if (node->data().role == ax::mojom::Role::kInlineTextBox) return; // A newly created live region or alert should not *also* fire a @@ -105,7 +105,7 @@ void AXEventGenerator::OnNodeDataWillChange(AXTree* tree, // We don't expose those to platform APIs, though, so suppress // CHILDREN_CHANGED events on static text nodes. if (new_node_data.child_ids != old_node_data.child_ids && - new_node_data.role != ui::AX_ROLE_STATIC_TEXT) { + new_node_data.role != ax::mojom::Role::kStaticText) { AXNode* node = tree_->GetFromId(new_node_data.id); tree_events_[node].insert(Event::CHILDREN_CHANGED); } @@ -113,66 +113,86 @@ void AXEventGenerator::OnNodeDataWillChange(AXTree* tree, void AXEventGenerator::OnRoleChanged(AXTree* tree, AXNode* node, - AXRole old_role, - AXRole new_role) { + ax::mojom::Role old_role, + ax::mojom::Role new_role) { DCHECK_EQ(tree_, tree); AddEvent(node, Event::ROLE_CHANGED); } void AXEventGenerator::OnStateChanged(AXTree* tree, AXNode* node, - AXState state, + ax::mojom::State state, bool new_value) { DCHECK_EQ(tree_, tree); AddEvent(node, Event::STATE_CHANGED); - if (state == ui::AX_STATE_EXPANDED) { - AddEvent(node, new_value ? Event::EXPANDED : Event::COLLAPSED); - if (node->data().role == ui::AX_ROLE_ROW || - node->data().role == ui::AX_ROLE_TREE_ITEM) { + switch (state) { + case ax::mojom::State::kExpanded: + AddEvent(node, new_value ? Event::EXPANDED : Event::COLLAPSED); + + // TODO(accessibility): tree in the midst of updates. Disallow access to + // |node|. + if (node->data().role == ax::mojom::Role::kRow || + node->data().role == ax::mojom::Role::kTreeItem) { + ui::AXNode* container = node; + while (container && !ui::IsRowContainer(container->data().role)) + container = container->parent(); + if (container) + AddEvent(container, Event::ROW_COUNT_CHANGED); + } + break; + case ax::mojom::State::kSelected: { + AddEvent(node, Event::SELECTED_CHANGED); ui::AXNode* container = node; - while (container && !ui::IsRowContainer(container->data().role)) + while (container && + !ui::IsContainerWithSelectableChildrenRole(container->data().role)) container = container->parent(); if (container) - AddEvent(container, Event::ROW_COUNT_CHANGED); + AddEvent(container, Event::SELECTED_CHILDREN_CHANGED); + break; } - } - if (state == ui::AX_STATE_SELECTED) { - AddEvent(node, Event::SELECTED_CHANGED); - ui::AXNode* container = node; - while (container && - !ui::IsContainerWithSelectableChildrenRole(container->data().role)) - container = container->parent(); - if (container) - AddEvent(container, Event::SELECTED_CHILDREN_CHANGED); + case ax::mojom::State::kIgnored: { + ui::AXNode* unignored_parent = node->GetUnignoredParent(); + if (unignored_parent) + AddEvent(unignored_parent, Event::CHILDREN_CHANGED); + break; + } + default: + break; } } void AXEventGenerator::OnStringAttributeChanged(AXTree* tree, AXNode* node, - AXStringAttribute attr, + ax::mojom::StringAttribute attr, const std::string& old_value, const std::string& new_value) { DCHECK_EQ(tree_, tree); switch (attr) { - case ui::AX_ATTR_NAME: + case ax::mojom::StringAttribute::kName: AddEvent(node, Event::NAME_CHANGED); - if (node->data().HasStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS)) { + + // TODO(accessibility): tree in the midst of updates. Disallow + // access to |node|. + if (node->data().HasStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus)) { FireLiveRegionEvents(node); } break; - case ui::AX_ATTR_DESCRIPTION: + case ax::mojom::StringAttribute::kDescription: AddEvent(node, Event::DESCRIPTION_CHANGED); break; - case ui::AX_ATTR_VALUE: + case ax::mojom::StringAttribute::kValue: AddEvent(node, Event::VALUE_CHANGED); break; - case ui::AX_ATTR_ARIA_INVALID_VALUE: + case ax::mojom::StringAttribute::kAriaInvalidValue: AddEvent(node, Event::INVALID_STATUS_CHANGED); break; - case ui::AX_ATTR_LIVE_STATUS: - if (node->data().role != ui::AX_ROLE_ALERT) + case ax::mojom::StringAttribute::kLiveStatus: + // TODO(accessibility): tree in the midst of updates. Disallow access to + // |node|. + if (node->data().role != ax::mojom::Role::kAlert) AddEvent(node, Event::LIVE_REGION_CREATED); break; default: @@ -183,27 +203,27 @@ void AXEventGenerator::OnStringAttributeChanged(AXTree* tree, void AXEventGenerator::OnIntAttributeChanged(AXTree* tree, AXNode* node, - AXIntAttribute attr, + ax::mojom::IntAttribute attr, int32_t old_value, int32_t new_value) { DCHECK_EQ(tree_, tree); switch (attr) { - case ui::AX_ATTR_ACTIVEDESCENDANT_ID: + case ax::mojom::IntAttribute::kActivedescendantId: AddEvent(node, Event::ACTIVE_DESCENDANT_CHANGED); active_descendant_changed_.push_back(node); break; - case ui::AX_ATTR_CHECKED_STATE: + case ax::mojom::IntAttribute::kCheckedState: AddEvent(node, Event::CHECKED_STATE_CHANGED); break; - case ui::AX_ATTR_INVALID_STATE: + case ax::mojom::IntAttribute::kInvalidState: AddEvent(node, Event::INVALID_STATUS_CHANGED); break; - case ui::AX_ATTR_RESTRICTION: + case ax::mojom::IntAttribute::kRestriction: AddEvent(node, Event::STATE_CHANGED); break; - case ui::AX_ATTR_SCROLL_X: - case ui::AX_ATTR_SCROLL_Y: + case ax::mojom::IntAttribute::kScrollX: + case ax::mojom::IntAttribute::kScrollY: AddEvent(node, Event::SCROLL_POSITION_CHANGED); break; default: @@ -214,12 +234,12 @@ void AXEventGenerator::OnIntAttributeChanged(AXTree* tree, void AXEventGenerator::OnFloatAttributeChanged(AXTree* tree, AXNode* node, - AXFloatAttribute attr, + ax::mojom::FloatAttribute attr, float old_value, float new_value) { DCHECK_EQ(tree_, tree); - if (attr == ui::AX_ATTR_VALUE_FOR_RANGE) + if (attr == ax::mojom::FloatAttribute::kValueForRange) AddEvent(node, Event::VALUE_CHANGED); else AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED); @@ -227,7 +247,7 @@ void AXEventGenerator::OnFloatAttributeChanged(AXTree* tree, void AXEventGenerator::OnBoolAttributeChanged(AXTree* tree, AXNode* node, - AXBoolAttribute attr, + ax::mojom::BoolAttribute attr, bool new_value) { DCHECK_EQ(tree_, tree); @@ -237,7 +257,7 @@ void AXEventGenerator::OnBoolAttributeChanged(AXTree* tree, void AXEventGenerator::OnIntListAttributeChanged( AXTree* tree, AXNode* node, - AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, const std::vector<int32_t>& old_value, const std::vector<int32_t>& new_value) { DCHECK_EQ(tree_, tree); @@ -247,7 +267,7 @@ void AXEventGenerator::OnIntListAttributeChanged( void AXEventGenerator::OnStringListAttributeChanged( AXTree* tree, AXNode* node, - AXStringListAttribute attr, + ax::mojom::StringListAttribute attr, const std::vector<std::string>& old_value, const std::vector<std::string>& new_value) { DCHECK_EQ(tree_, tree); @@ -314,17 +334,22 @@ void AXEventGenerator::OnAtomicUpdateFinished( for (const auto& change : changes) { if ((change.type == NODE_CREATED || change.type == SUBTREE_CREATED)) { - if (change.node->data().HasStringAttribute(ui::AX_ATTR_LIVE_STATUS)) { - if (change.node->data().role == ui::AX_ROLE_ALERT) + if (change.node->data().HasStringAttribute( + ax::mojom::StringAttribute::kLiveStatus)) { + if (change.node->data().role == ax::mojom::Role::kAlert) AddEvent(change.node, Event::ALERT); else AddEvent(change.node, Event::LIVE_REGION_CREATED); } else if (change.node->data().HasStringAttribute( - ui::AX_ATTR_CONTAINER_LIVE_STATUS) && - change.node->data().HasStringAttribute(ui::AX_ATTR_NAME)) { + ax::mojom::StringAttribute::kContainerLiveStatus) && + change.node->data().HasStringAttribute( + ax::mojom::StringAttribute::kName)) { FireLiveRegionEvents(change.node); } } + + if (change.type != NODE_CREATED && change.type != SUBTREE_CREATED) + FireRelationSourceEvents(tree, change.node); } FireActiveDescendantEvents(); @@ -332,13 +357,16 @@ void AXEventGenerator::OnAtomicUpdateFinished( void AXEventGenerator::FireLiveRegionEvents(AXNode* node) { ui::AXNode* live_root = node; - while (live_root && - !live_root->data().HasStringAttribute(ui::AX_ATTR_LIVE_STATUS)) + while (live_root && !live_root->data().HasStringAttribute( + ax::mojom::StringAttribute::kLiveStatus)) live_root = live_root->parent(); - if (live_root && !live_root->data().GetBoolAttribute(ui::AX_ATTR_BUSY)) { + if (live_root && + !live_root->data().GetBoolAttribute(ax::mojom::BoolAttribute::kBusy)) { // Fire LIVE_REGION_NODE_CHANGED on each node that changed. - if (!node->data().GetStringAttribute(ui::AX_ATTR_NAME).empty()) + if (!node->data() + .GetStringAttribute(ax::mojom::StringAttribute::kName) + .empty()) AddEvent(node, Event::LIVE_REGION_NODE_CHANGED); // Fire LIVE_REGION_NODE_CHANGED on the root of the live region. AddEvent(live_root, Event::LIVE_REGION_CHANGED); @@ -347,15 +375,15 @@ void AXEventGenerator::FireLiveRegionEvents(AXNode* node) { void AXEventGenerator::FireActiveDescendantEvents() { for (AXNode* node : active_descendant_changed_) { - AXNode* descendant = tree_->GetFromId( - node->data().GetIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID)); + AXNode* descendant = tree_->GetFromId(node->data().GetIntAttribute( + ax::mojom::IntAttribute::kActivedescendantId)); if (!descendant) continue; switch (descendant->data().role) { - case ui::AX_ROLE_MENU_ITEM: - case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: - case ui::AX_ROLE_MENU_ITEM_RADIO: - case ui::AX_ROLE_MENU_LIST_OPTION: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuListOption: AddEvent(descendant, Event::MENU_ITEM_SELECTED); break; default: @@ -365,4 +393,32 @@ void AXEventGenerator::FireActiveDescendantEvents() { active_descendant_changed_.clear(); } +void AXEventGenerator::FireRelationSourceEvents(AXTree* tree, + AXNode* target_node) { + int32_t target_id = target_node->id(); + std::set<AXNode*> source_nodes; + auto callback = [&](const auto& entry) { + const auto& target_to_sources = entry.second; + auto sources_it = target_to_sources.find(target_id); + if (sources_it == target_to_sources.end()) + return; + + auto sources = sources_it->second; + std::for_each(sources.begin(), sources.end(), [&](int32_t source_id) { + AXNode* source_node = tree->GetFromId(source_id); + + if (!source_node || source_nodes.count(source_node) > 0) + return; + + source_nodes.insert(source_node); + AddEvent(source_node, Event::RELATED_NODE_CHANGED); + }); + }; + + std::for_each(tree->int_reverse_relations().begin(), + tree->int_reverse_relations().end(), callback); + std::for_each(tree->intlist_reverse_relations().begin(), + tree->intlist_reverse_relations().end(), callback); +} + } // namespace ui diff --git a/chromium/ui/accessibility/ax_event_generator.h b/chromium/ui/accessibility/ax_event_generator.h index f4d9c26efb5..2b9d57b3edf 100644 --- a/chromium/ui/accessibility/ax_event_generator.h +++ b/chromium/ui/accessibility/ax_event_generator.h @@ -38,6 +38,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate { MENU_ITEM_SELECTED, NAME_CHANGED, OTHER_ATTRIBUTE_CHANGED, + RELATED_NODE_CHANGED, ROLE_CHANGED, ROW_COUNT_CHANGED, SCROLL_POSITION_CHANGED, @@ -115,41 +116,41 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate { const AXNodeData& new_node_data) override; void OnRoleChanged(AXTree* tree, AXNode* node, - AXRole old_role, - AXRole new_role) override; + ax::mojom::Role old_role, + ax::mojom::Role new_role) override; void OnStateChanged(AXTree* tree, AXNode* node, - AXState state, + ax::mojom::State state, bool new_value) override; void OnStringAttributeChanged(AXTree* tree, AXNode* node, - AXStringAttribute attr, + ax::mojom::StringAttribute attr, const std::string& old_value, const std::string& new_value) override; void OnIntAttributeChanged(AXTree* tree, AXNode* node, - AXIntAttribute attr, + ax::mojom::IntAttribute attr, int32_t old_value, int32_t new_value) override; void OnFloatAttributeChanged(AXTree* tree, AXNode* node, - AXFloatAttribute attr, + ax::mojom::FloatAttribute attr, float old_value, float new_value) override; void OnBoolAttributeChanged(AXTree* tree, AXNode* node, - AXBoolAttribute attr, + ax::mojom::BoolAttribute attr, bool new_value) override; void OnIntListAttributeChanged( AXTree* tree, AXNode* node, - AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, const std::vector<int32_t>& old_value, const std::vector<int32_t>& new_value) override; void OnStringListAttributeChanged( AXTree* tree, AXNode* node, - AXStringListAttribute attr, + ax::mojom::StringListAttribute attr, const std::vector<std::string>& old_value, const std::vector<std::string>& new_value) override; void OnTreeDataChanged(AXTree* tree, @@ -169,6 +170,7 @@ class AX_EXPORT AXEventGenerator : public AXTreeDelegate { private: void FireLiveRegionEvents(AXNode* node); void FireActiveDescendantEvents(); + void FireRelationSourceEvents(AXTree* tree, AXNode* target_node); AXTree* tree_ = nullptr; // Not owned. std::map<AXNode*, std::set<Event>> tree_events_; diff --git a/chromium/ui/accessibility/ax_event_generator_unittest.cc b/chromium/ui/accessibility/ax_event_generator_unittest.cc index a9b9ce56889..2d3f192568f 100644 --- a/chromium/ui/accessibility/ax_event_generator_unittest.cc +++ b/chromium/ui/accessibility/ax_event_generator_unittest.cc @@ -71,6 +71,9 @@ std::string DumpEvents(AXEventGenerator* generator) { case AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED: event_name = "OTHER_ATTRIBUTE_CHANGED"; break; + case AXEventGenerator::Event::RELATED_NODE_CHANGED: + event_name = "RELATED_NODE_CHANGED"; + break; case AXEventGenerator::Event::ROLE_CHANGED: event_name = "ROLE_CHANGED"; break; @@ -183,22 +186,22 @@ TEST(AXEventGeneratorTest, ExpandedAndRowCount) { initial_state.root_id = 1; initial_state.nodes.resize(4); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_ROOT_WEB_AREA; + initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea; initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(4); initial_state.nodes[1].id = 2; - initial_state.nodes[1].role = ui::AX_ROLE_TABLE; + initial_state.nodes[1].role = ax::mojom::Role::kTable; initial_state.nodes[1].child_ids.push_back(3); initial_state.nodes[2].id = 3; - initial_state.nodes[2].role = ui::AX_ROLE_ROW; + initial_state.nodes[2].role = ax::mojom::Role::kRow; initial_state.nodes[3].id = 4; - initial_state.nodes[3].role = ui::AX_ROLE_POP_UP_BUTTON; - initial_state.nodes[3].AddState(ui::AX_STATE_EXPANDED); + initial_state.nodes[3].role = ax::mojom::Role::kPopUpButton; + initial_state.nodes[3].AddState(ax::mojom::State::kExpanded); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[2].AddState(ui::AX_STATE_EXPANDED); + update.nodes[2].AddState(ax::mojom::State::kExpanded); update.nodes[3].state = 0; EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ( @@ -215,22 +218,22 @@ TEST(AXEventGeneratorTest, SelectedAndSelectedChildren) { initial_state.root_id = 1; initial_state.nodes.resize(4); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_ROOT_WEB_AREA; + initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea; initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(4); initial_state.nodes[1].id = 2; - initial_state.nodes[1].role = ui::AX_ROLE_MENU; + initial_state.nodes[1].role = ax::mojom::Role::kMenu; initial_state.nodes[1].child_ids.push_back(3); initial_state.nodes[2].id = 3; - initial_state.nodes[2].role = ui::AX_ROLE_MENU_ITEM; + initial_state.nodes[2].role = ax::mojom::Role::kMenuItem; initial_state.nodes[3].id = 4; - initial_state.nodes[3].role = ui::AX_ROLE_LIST_BOX_OPTION; - initial_state.nodes[3].AddState(ui::AX_STATE_SELECTED); + initial_state.nodes[3].role = ax::mojom::Role::kListBoxOption; + initial_state.nodes[3].AddState(ax::mojom::State::kSelected); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[2].AddState(ui::AX_STATE_SELECTED); + update.nodes[2].AddState(ax::mojom::State::kSelected); update.nodes[3].state = 0; EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ( @@ -247,14 +250,16 @@ TEST(AXEventGeneratorTest, StringValueChanged) { initial_state.root_id = 1; initial_state.nodes.resize(1); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_TEXT_FIELD; - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_VALUE, "Before"); + initial_state.nodes[0].role = ax::mojom::Role::kTextField; + initial_state.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kValue, + "Before"); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; update.nodes[0].string_attributes.clear(); - update.nodes[0].AddStringAttribute(ui::AX_ATTR_VALUE, "After"); + update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kValue, + "After"); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("VALUE_CHANGED on 1", DumpEvents(&event_generator)); } @@ -264,14 +269,16 @@ TEST(AXEventGeneratorTest, FloatValueChanged) { initial_state.root_id = 1; initial_state.nodes.resize(1); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_SLIDER; - initial_state.nodes[0].AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, 1.0); + initial_state.nodes[0].role = ax::mojom::Role::kSlider; + initial_state.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kValueForRange, 1.0); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; update.nodes[0].float_attributes.clear(); - update.nodes[0].AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, 2.0); + update.nodes[0].AddFloatAttribute(ax::mojom::FloatAttribute::kValueForRange, + 2.0); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("VALUE_CHANGED on 1", DumpEvents(&event_generator)); } @@ -281,14 +288,14 @@ TEST(AXEventGeneratorTest, InvalidStatusChanged) { initial_state.root_id = 1; initial_state.nodes.resize(1); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_TEXT_FIELD; - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_VALUE, "Text"); + initial_state.nodes[0].role = ax::mojom::Role::kTextField; + initial_state.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kValue, + "Text"); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[0].AddIntAttribute(ui::AX_ATTR_INVALID_STATE, - ui::AX_INVALID_STATE_SPELLING); + update.nodes[0].SetInvalidState(ax::mojom::InvalidState::kSpelling); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("INVALID_STATUS_CHANGED on 1", DumpEvents(&event_generator)); } @@ -302,7 +309,8 @@ TEST(AXEventGeneratorTest, AddLiveRegionAttribute) { AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); + update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus, + "polite"); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("LIVE_REGION_CREATED on 1", DumpEvents(&event_generator)); } @@ -312,13 +320,12 @@ TEST(AXEventGeneratorTest, CheckedStateChanged) { initial_state.root_id = 1; initial_state.nodes.resize(1); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_CHECK_BOX; + initial_state.nodes[0].role = ax::mojom::Role::kCheckBox; AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[0].AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, - ui::AX_CHECKED_STATE_TRUE); + update.nodes[0].SetCheckedState(ax::mojom::CheckedState::kTrue); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("CHECKED_STATE_CHANGED on 1", DumpEvents(&event_generator)); } @@ -328,22 +335,27 @@ TEST(AXEventGeneratorTest, ActiveDescendantChanged) { initial_state.root_id = 1; initial_state.nodes.resize(3); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_LIST_BOX; + initial_state.nodes[0].role = ax::mojom::Role::kListBox; initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(3); - initial_state.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 2); + initial_state.nodes[0].AddIntAttribute( + ax::mojom::IntAttribute::kActivedescendantId, 2); initial_state.nodes[1].id = 2; - initial_state.nodes[1].role = ui::AX_ROLE_LIST_BOX_OPTION; + initial_state.nodes[1].role = ax::mojom::Role::kListBoxOption; initial_state.nodes[2].id = 3; - initial_state.nodes[2].role = ui::AX_ROLE_LIST_BOX_OPTION; + initial_state.nodes[2].role = ax::mojom::Role::kListBoxOption; AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; update.nodes[0].int_attributes.clear(); - update.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 3); + update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId, + 3); EXPECT_TRUE(tree.Unserialize(update)); - EXPECT_EQ("ACTIVE_DESCENDANT_CHANGED on 1", DumpEvents(&event_generator)); + EXPECT_EQ( + "ACTIVE_DESCENDANT_CHANGED on 1, " + "RELATED_NODE_CHANGED on 1", + DumpEvents(&event_generator)); } TEST(AXEventGeneratorTest, CreateAlertAndLiveRegion) { @@ -359,10 +371,12 @@ TEST(AXEventGeneratorTest, CreateAlertAndLiveRegion) { update.nodes[0].child_ids.push_back(2); update.nodes[0].child_ids.push_back(3); update.nodes[1].id = 2; - update.nodes[1].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); + update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus, + "polite"); update.nodes[2].id = 3; - update.nodes[2].role = ui::AX_ROLE_ALERT; - update.nodes[2].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); + update.nodes[2].role = ax::mojom::Role::kAlert; + update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus, + "polite"); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ( @@ -377,33 +391,38 @@ TEST(AXEventGeneratorTest, LiveRegionChanged) { initial_state.root_id = 1; initial_state.nodes.resize(3); initial_state.nodes[0].id = 1; - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); + initial_state.nodes[0].AddStringAttribute( + ax::mojom::StringAttribute::kLiveStatus, "polite"); + initial_state.nodes[0].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(3); initial_state.nodes[1].id = 2; - initial_state.nodes[1].role = ui::AX_ROLE_STATIC_TEXT; - initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "Before 1"); + initial_state.nodes[1].role = ax::mojom::Role::kStaticText; + initial_state.nodes[1].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Before 1"); initial_state.nodes[2].id = 3; - initial_state.nodes[2].role = ui::AX_ROLE_STATIC_TEXT; - initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "Before 2"); + initial_state.nodes[2].role = ax::mojom::Role::kStaticText; + initial_state.nodes[2].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Before 2"); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; update.nodes[1].string_attributes.clear(); - update.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - update.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "After 1"); + update.nodes[1].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName, + "After 1"); update.nodes[2].string_attributes.clear(); - update.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - update.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "After 2"); + update.nodes[2].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName, + "After 2"); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ( @@ -420,28 +439,31 @@ TEST(AXEventGeneratorTest, LiveRegionOnlyTextChanges) { initial_state.root_id = 1; initial_state.nodes.resize(3); initial_state.nodes[0].id = 1; - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); + initial_state.nodes[0].AddStringAttribute( + ax::mojom::StringAttribute::kLiveStatus, "polite"); + initial_state.nodes[0].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(3); initial_state.nodes[1].id = 2; - initial_state.nodes[1].role = ui::AX_ROLE_STATIC_TEXT; - initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "Before 1"); + initial_state.nodes[1].role = ax::mojom::Role::kStaticText; + initial_state.nodes[1].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Before 1"); initial_state.nodes[2].id = 3; - initial_state.nodes[2].role = ui::AX_ROLE_STATIC_TEXT; - initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "Before 2"); + initial_state.nodes[2].role = ax::mojom::Role::kStaticText; + initial_state.nodes[2].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Before 2"); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[1].AddStringAttribute(ui::AX_ATTR_DESCRIPTION, "Description 1"); - update.nodes[2].AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, - ui::AX_CHECKED_STATE_TRUE); + update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kDescription, + "Description 1"); + update.nodes[2].SetCheckedState(ax::mojom::CheckedState::kTrue); // Note that we do NOT expect a LIVE_REGION_CHANGED event here, because // the name did not change. @@ -457,34 +479,40 @@ TEST(AXEventGeneratorTest, BusyLiveRegionChanged) { initial_state.root_id = 1; initial_state.nodes.resize(3); initial_state.nodes[0].id = 1; - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, "polite"); - initial_state.nodes[0].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - initial_state.nodes[0].AddBoolAttribute(ui::AX_ATTR_BUSY, true); + initial_state.nodes[0].AddStringAttribute( + ax::mojom::StringAttribute::kLiveStatus, "polite"); + initial_state.nodes[0].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, + true); initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(3); initial_state.nodes[1].id = 2; - initial_state.nodes[1].role = ui::AX_ROLE_STATIC_TEXT; - initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - initial_state.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "Before 1"); + initial_state.nodes[1].role = ax::mojom::Role::kStaticText; + initial_state.nodes[1].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Before 1"); initial_state.nodes[2].id = 3; - initial_state.nodes[2].role = ui::AX_ROLE_STATIC_TEXT; - initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - initial_state.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "Before 2"); + initial_state.nodes[2].role = ax::mojom::Role::kStaticText; + initial_state.nodes[2].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + initial_state.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Before 2"); AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; update.nodes[1].string_attributes.clear(); - update.nodes[1].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - update.nodes[1].AddStringAttribute(ui::AX_ATTR_NAME, "After 1"); + update.nodes[1].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName, + "After 1"); update.nodes[2].string_attributes.clear(); - update.nodes[2].AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, - "polite"); - update.nodes[2].AddStringAttribute(ui::AX_ATTR_NAME, "After 2"); + update.nodes[2].AddStringAttribute( + ax::mojom::StringAttribute::kContainerLiveStatus, "polite"); + update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName, + "After 2"); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ( @@ -563,7 +591,7 @@ TEST(AXEventGeneratorTest, ScrollPositionChanged) { AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[0].AddIntAttribute(ui::AX_ATTR_SCROLL_Y, 10); + update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollY, 10); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("SCROLL_POSITION_CHANGED on 1", DumpEvents(&event_generator)); } @@ -587,19 +615,24 @@ TEST(AXEventGeneratorTest, OtherAttributeChanged) { AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[1].AddStringAttribute(ui::AX_ATTR_LANGUAGE, "de"); - update.nodes[2].AddIntAttribute(ui::AX_ATTR_ARIA_CELL_COLUMN_INDEX, 7); - update.nodes[3].AddFloatAttribute(ui::AX_ATTR_FONT_SIZE, 12.0f); - update.nodes[4].AddBoolAttribute(ui::AX_ATTR_MODAL, true); + update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kLanguage, + "de"); + update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex, + 7); + update.nodes[3].AddFloatAttribute(ax::mojom::FloatAttribute::kFontSize, + 12.0f); + update.nodes[4].AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true); std::vector<int> ids = {2}; - update.nodes[5].AddIntListAttribute(ui::AX_ATTR_CONTROLS_IDS, ids); + update.nodes[5].AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds, + ids); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ( "OTHER_ATTRIBUTE_CHANGED on 2, " "OTHER_ATTRIBUTE_CHANGED on 3, " "OTHER_ATTRIBUTE_CHANGED on 4, " "OTHER_ATTRIBUTE_CHANGED on 5, " - "OTHER_ATTRIBUTE_CHANGED on 6", + "OTHER_ATTRIBUTE_CHANGED on 6, " + "RELATED_NODE_CHANGED on 6", DumpEvents(&event_generator)); } @@ -612,7 +645,8 @@ TEST(AXEventGeneratorTest, NameChanged) { AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[0].AddStringAttribute(ui::AX_ATTR_NAME, "Hello"); + update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kName, + "Hello"); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("NAME_CHANGED on 1", DumpEvents(&event_generator)); } @@ -626,7 +660,8 @@ TEST(AXEventGeneratorTest, DescriptionChanged) { AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[0].AddStringAttribute(ui::AX_ATTR_DESCRIPTION, "Hello"); + update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kDescription, + "Hello"); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("DESCRIPTION_CHANGED on 1", DumpEvents(&event_generator)); } @@ -640,7 +675,7 @@ TEST(AXEventGeneratorTest, RoleChanged) { AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; - update.nodes[0].role = ui::AX_ROLE_CHECK_BOX; + update.nodes[0].role = ax::mojom::Role::kCheckBox; EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ("ROLE_CHANGED on 1", DumpEvents(&event_generator)); } @@ -650,24 +685,92 @@ TEST(AXEventGeneratorTest, MenuItemSelected) { initial_state.root_id = 1; initial_state.nodes.resize(3); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = ui::AX_ROLE_MENU; + initial_state.nodes[0].role = ax::mojom::Role::kMenu; initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(3); - initial_state.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 2); + initial_state.nodes[0].AddIntAttribute( + ax::mojom::IntAttribute::kActivedescendantId, 2); initial_state.nodes[1].id = 2; - initial_state.nodes[1].role = ui::AX_ROLE_MENU_LIST_OPTION; + initial_state.nodes[1].role = ax::mojom::Role::kMenuListOption; initial_state.nodes[2].id = 3; - initial_state.nodes[2].role = ui::AX_ROLE_MENU_LIST_OPTION; + initial_state.nodes[2].role = ax::mojom::Role::kMenuListOption; AXTree tree(initial_state); AXEventGenerator event_generator(&tree); AXTreeUpdate update = initial_state; update.nodes[0].int_attributes.clear(); - update.nodes[0].AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 3); + update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId, + 3); EXPECT_TRUE(tree.Unserialize(update)); EXPECT_EQ( "ACTIVE_DESCENDANT_CHANGED on 1, " - "MENU_ITEM_SELECTED on 3", + "MENU_ITEM_SELECTED on 3, " + "RELATED_NODE_CHANGED on 1", + DumpEvents(&event_generator)); +} + +TEST(AXEventGeneratorTest, NodeBecomesIgnored) { + AXTreeUpdate initial_state; + initial_state.root_id = 1; + initial_state.nodes.resize(5); + initial_state.nodes[0].id = 1; + initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea; + initial_state.nodes[0].child_ids.push_back(2); + initial_state.nodes[1].id = 2; + initial_state.nodes[1].role = ax::mojom::Role::kArticle; + initial_state.nodes[1].child_ids.push_back(3); + initial_state.nodes[2].id = 3; + initial_state.nodes[2].role = ax::mojom::Role::kGroup; + initial_state.nodes[2].AddState(ax::mojom::State::kIgnored); + initial_state.nodes[2].child_ids.push_back(4); + initial_state.nodes[3].id = 4; + initial_state.nodes[3].role = ax::mojom::Role::kGroup; + initial_state.nodes[3].child_ids.push_back(5); + initial_state.nodes[4].id = 5; + initial_state.nodes[4].role = ax::mojom::Role::kStaticText; + + AXTree tree(initial_state); + + AXEventGenerator event_generator(&tree); + AXTreeUpdate update = initial_state; + update.nodes[3].AddState(ax::mojom::State::kIgnored); + EXPECT_TRUE(tree.Unserialize(update)); + EXPECT_EQ( + "CHILDREN_CHANGED on 2, " + "STATE_CHANGED on 4", + DumpEvents(&event_generator)); +} + +TEST(AXEventGeneratorTest, NodeBecomesUnignored) { + AXTreeUpdate initial_state; + initial_state.root_id = 1; + initial_state.nodes.resize(5); + initial_state.nodes[0].id = 1; + initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea; + initial_state.nodes[0].child_ids.push_back(2); + initial_state.nodes[1].id = 2; + initial_state.nodes[1].role = ax::mojom::Role::kArticle; + initial_state.nodes[1].child_ids.push_back(3); + initial_state.nodes[2].id = 3; + initial_state.nodes[2].role = ax::mojom::Role::kGroup; + initial_state.nodes[2].AddState(ax::mojom::State::kIgnored); + initial_state.nodes[2].child_ids.push_back(4); + initial_state.nodes[3].id = 4; + initial_state.nodes[3].role = ax::mojom::Role::kGroup; + initial_state.nodes[3].AddState(ax::mojom::State::kIgnored); + initial_state.nodes[3].child_ids.push_back(5); + initial_state.nodes[4].id = 5; + initial_state.nodes[4].role = ax::mojom::Role::kStaticText; + + AXTree tree(initial_state); + + AXEventGenerator event_generator(&tree); + AXTreeUpdate update = initial_state; + update.nodes[3].state = 0; + EXPECT_TRUE(tree.Unserialize(update)); + EXPECT_EQ( + "CHILDREN_CHANGED on 2, " + "STATE_CHANGED on 4", DumpEvents(&event_generator)); } diff --git a/chromium/ui/accessibility/ax_node.cc b/chromium/ui/accessibility/ax_node.cc index 8327ccd786e..130d47eeb6c 100644 --- a/chromium/ui/accessibility/ax_node.cc +++ b/chromium/ui/accessibility/ax_node.cc @@ -7,7 +7,8 @@ #include <algorithm> #include "base/strings/string16.h" -#include "ui/accessibility/ax_enums.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/gfx/transform.h" namespace ui { @@ -20,10 +21,62 @@ AXNode::AXNode(AXNode* parent, int32_t id, int32_t index_in_parent) AXNode::~AXNode() { } +int AXNode::GetUnignoredChildCount() const { + int count = 0; + for (int i = 0; i < child_count(); i++) { + AXNode* child = children_[i]; + if (child->data().HasState(ax::mojom::State::kIgnored)) + count += child->GetUnignoredChildCount(); + else + count++; + } + return count; +} + +AXNode* AXNode::GetUnignoredChildAtIndex(int index) const { + int count = 0; + for (int i = 0; i < child_count(); i++) { + AXNode* child = children_[i]; + if (child->data().HasState(ax::mojom::State::kIgnored)) { + int nested_child_count = child->GetUnignoredChildCount(); + if (index < count + nested_child_count) + return child->GetUnignoredChildAtIndex(index - count); + else + count += nested_child_count; + } else { + if (count == index) + return child; + else + count++; + } + } + + return nullptr; +} + +AXNode* AXNode::GetUnignoredParent() const { + AXNode* result = parent(); + while (result && result->data().HasState(ax::mojom::State::kIgnored)) + result = result->parent(); + return result; +} + +int AXNode::GetUnignoredIndexInParent() const { + AXNode* parent = GetUnignoredParent(); + if (parent) { + for (int i = 0; i < parent->GetUnignoredChildCount(); ++i) { + if (parent->GetUnignoredChildAtIndex(i) == this) + return i; + } + } + + return 0; +} + bool AXNode::IsTextNode() const { - return data().role == AX_ROLE_STATIC_TEXT || - data().role == AX_ROLE_LINE_BREAK || - data().role == AX_ROLE_INLINE_TEXT_BOX; + return data().role == ax::mojom::Role::kStaticText || + data().role == ax::mojom::Role::kLineBreak || + data().role == ax::mojom::Role::kInlineTextBox; } void AXNode::SetData(const AXNodeData& src) { @@ -64,12 +117,14 @@ bool AXNode::IsDescendantOf(AXNode* ancestor) { std::vector<int> AXNode::GetOrComputeLineStartOffsets() { std::vector<int> line_offsets; - if (data().GetIntListAttribute(AX_ATTR_CACHED_LINE_STARTS, &line_offsets)) + if (data().GetIntListAttribute(ax::mojom::IntListAttribute::kCachedLineStarts, + &line_offsets)) return line_offsets; int start_offset = 0; ComputeLineStartOffsets(&line_offsets, &start_offset); - data_.AddIntListAttribute(AX_ATTR_CACHED_LINE_STARTS, line_offsets); + data_.AddIntListAttribute(ax::mojom::IntListAttribute::kCachedLineStarts, + line_offsets); return line_offsets; } @@ -85,17 +140,34 @@ void AXNode::ComputeLineStartOffsets(std::vector<int>* line_offsets, } // Don't report if the first piece of text starts a new line or not. - if (*start_offset && - !child->data().HasIntAttribute(ui::AX_ATTR_PREVIOUS_ON_LINE_ID)) { + if (*start_offset && !child->data().HasIntAttribute( + ax::mojom::IntAttribute::kPreviousOnLineId)) { // If there are multiple objects with an empty accessible label at the // start of a line, only include a single line start offset. if (line_offsets->empty() || line_offsets->back() != *start_offset) line_offsets->push_back(*start_offset); } - base::string16 text = child->data().GetString16Attribute(ui::AX_ATTR_NAME); + base::string16 text = + child->data().GetString16Attribute(ax::mojom::StringAttribute::kName); *start_offset += static_cast<int>(text.length()); } } +const std::string& AXNode::GetInheritedStringAttribute( + ax::mojom::StringAttribute attribute) const { + const AXNode* current_node = this; + do { + if (current_node->data().HasStringAttribute(attribute)) + return current_node->data().GetStringAttribute(attribute); + current_node = current_node->parent(); + } while (current_node); + return base::EmptyString(); +} + +base::string16 AXNode::GetInheritedString16Attribute( + ax::mojom::StringAttribute attribute) const { + return base::UTF8ToUTF16(GetInheritedStringAttribute(attribute)); +} + } // namespace ui diff --git a/chromium/ui/accessibility/ax_node.h b/chromium/ui/accessibility/ax_node.h index 6dd907f5a3f..c832a6aadf3 100644 --- a/chromium/ui/accessibility/ax_node.h +++ b/chromium/ui/accessibility/ax_node.h @@ -33,6 +33,12 @@ class AX_EXPORT AXNode { // Get the child at the given index. AXNode* ChildAtIndex(int index) const { return children_[index]; } + // Walking the tree skipping ignored nodes. + int GetUnignoredChildCount() const; + AXNode* GetUnignoredChildAtIndex(int index) const; + AXNode* GetUnignoredParent() const; + int GetUnignoredIndexInParent() const; + // Returns true if the node has any of the text related roles. bool IsTextNode() const; @@ -72,6 +78,11 @@ class AX_EXPORT AXNode { // by computing them and caching the result. std::vector<int> GetOrComputeLineStartOffsets(); + const std::string& GetInheritedStringAttribute( + ax::mojom::StringAttribute attribute) const; + base::string16 GetInheritedString16Attribute( + ax::mojom::StringAttribute attribute) const; + private: // Computes the text offset where each line starts by traversing all child // leaf nodes. diff --git a/chromium/ui/accessibility/ax_node_data.cc b/chromium/ui/accessibility/ax_node_data.cc index ec4ef8b6167..5f8967f3698 100644 --- a/chromium/ui/accessibility/ax_node_data.cc +++ b/chromium/ui/accessibility/ax_node_data.cc @@ -13,6 +13,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/gfx/transform.h" @@ -30,18 +31,21 @@ uint32_t ModifyFlag(uint32_t bitfield, uint32_t flag, bool set) { std::string StateBitfieldToString(uint32_t state) { std::string str; - for (uint32_t i = AX_STATE_NONE + 1; i <= AX_STATE_LAST; ++i) { + for (uint32_t i = static_cast<uint32_t>(ax::mojom::State::kNone) + 1; + i <= static_cast<uint32_t>(ax::mojom::State::kLast); ++i) { if (IsFlagSet(state, i)) - str += " " + base::ToUpperASCII(ui::ToString(static_cast<AXState>(i))); + str += " " + + base::ToUpperASCII(ui::ToString(static_cast<ax::mojom::State>(i))); } return str; } std::string ActionsBitfieldToString(uint32_t actions) { std::string str; - for (uint32_t i = AX_ACTION_NONE + 1; i <= AX_ACTION_LAST; ++i) { + for (uint32_t i = static_cast<uint32_t>(ax::mojom::Action::kNone) + 1; + i <= static_cast<uint32_t>(ax::mojom::Action::kLast); ++i) { if (IsFlagSet(actions, i)) { - str += ui::ToString(static_cast<AXAction>(i)); + str += ui::ToString(static_cast<ax::mojom::Action>(i)); actions = ModifyFlag(actions, i, false); str += actions ? "," : ""; } @@ -86,64 +90,64 @@ typename std::vector<std::pair<FirstType, SecondType>>::const_iterator // Return true if |attr| is a node ID that would need to be mapped when // renumbering the ids in a combined tree. -bool IsNodeIdIntAttribute(AXIntAttribute attr) { +bool IsNodeIdIntAttribute(ax::mojom::IntAttribute attr) { switch (attr) { - case AX_ATTR_ACTIVEDESCENDANT_ID: - case AX_ATTR_DETAILS_ID: - case AX_ATTR_ERRORMESSAGE_ID: - case AX_ATTR_IN_PAGE_LINK_TARGET_ID: - case AX_ATTR_MEMBER_OF_ID: - case AX_ATTR_NEXT_ON_LINE_ID: - case AX_ATTR_PREVIOUS_ON_LINE_ID: - case AX_ATTR_TABLE_HEADER_ID: - case AX_ATTR_TABLE_COLUMN_HEADER_ID: - case AX_ATTR_TABLE_ROW_HEADER_ID: - case AX_ATTR_NEXT_FOCUS_ID: - case AX_ATTR_PREVIOUS_FOCUS_ID: + case ax::mojom::IntAttribute::kActivedescendantId: + case ax::mojom::IntAttribute::kDetailsId: + case ax::mojom::IntAttribute::kErrormessageId: + case ax::mojom::IntAttribute::kInPageLinkTargetId: + case ax::mojom::IntAttribute::kMemberOfId: + case ax::mojom::IntAttribute::kNextOnLineId: + case ax::mojom::IntAttribute::kPreviousOnLineId: + case ax::mojom::IntAttribute::kTableHeaderId: + case ax::mojom::IntAttribute::kTableColumnHeaderId: + case ax::mojom::IntAttribute::kTableRowHeaderId: + case ax::mojom::IntAttribute::kNextFocusId: + case ax::mojom::IntAttribute::kPreviousFocusId: return true; // Note: all of the attributes are included here explicitly, // rather than using "default:", so that it's a compiler error to // add a new attribute without explicitly considering whether it's // a node id attribute or not. - case AX_INT_ATTRIBUTE_NONE: - case AX_ATTR_DEFAULT_ACTION_VERB: - case AX_ATTR_SCROLL_X: - case AX_ATTR_SCROLL_X_MIN: - case AX_ATTR_SCROLL_X_MAX: - case AX_ATTR_SCROLL_Y: - case AX_ATTR_SCROLL_Y_MIN: - case AX_ATTR_SCROLL_Y_MAX: - case AX_ATTR_TEXT_SEL_START: - case AX_ATTR_TEXT_SEL_END: - case AX_ATTR_TABLE_ROW_COUNT: - case AX_ATTR_TABLE_COLUMN_COUNT: - case AX_ATTR_TABLE_ROW_INDEX: - case AX_ATTR_TABLE_COLUMN_INDEX: - case AX_ATTR_TABLE_CELL_COLUMN_INDEX: - case AX_ATTR_TABLE_CELL_COLUMN_SPAN: - case AX_ATTR_TABLE_CELL_ROW_INDEX: - case AX_ATTR_TABLE_CELL_ROW_SPAN: - case AX_ATTR_SORT_DIRECTION: - case AX_ATTR_HIERARCHICAL_LEVEL: - case AX_ATTR_NAME_FROM: - case AX_ATTR_DESCRIPTION_FROM: - case AX_ATTR_CHILD_TREE_ID: - case AX_ATTR_SET_SIZE: - case AX_ATTR_POS_IN_SET: - case AX_ATTR_COLOR_VALUE: - case AX_ATTR_ARIA_CURRENT_STATE: - case AX_ATTR_BACKGROUND_COLOR: - case AX_ATTR_COLOR: - case AX_ATTR_INVALID_STATE: - case AX_ATTR_CHECKED_STATE: - case AX_ATTR_RESTRICTION: - case AX_ATTR_TEXT_DIRECTION: - case AX_ATTR_TEXT_STYLE: - case AX_ATTR_ARIA_COLUMN_COUNT: - case AX_ATTR_ARIA_CELL_COLUMN_INDEX: - case AX_ATTR_ARIA_ROW_COUNT: - case AX_ATTR_ARIA_CELL_ROW_INDEX: + case ax::mojom::IntAttribute::kNone: + case ax::mojom::IntAttribute::kDefaultActionVerb: + case ax::mojom::IntAttribute::kScrollX: + case ax::mojom::IntAttribute::kScrollXMin: + case ax::mojom::IntAttribute::kScrollXMax: + case ax::mojom::IntAttribute::kScrollY: + case ax::mojom::IntAttribute::kScrollYMin: + case ax::mojom::IntAttribute::kScrollYMax: + case ax::mojom::IntAttribute::kTextSelStart: + case ax::mojom::IntAttribute::kTextSelEnd: + case ax::mojom::IntAttribute::kTableRowCount: + case ax::mojom::IntAttribute::kTableColumnCount: + case ax::mojom::IntAttribute::kTableRowIndex: + case ax::mojom::IntAttribute::kTableColumnIndex: + case ax::mojom::IntAttribute::kTableCellColumnIndex: + case ax::mojom::IntAttribute::kTableCellColumnSpan: + case ax::mojom::IntAttribute::kTableCellRowIndex: + case ax::mojom::IntAttribute::kTableCellRowSpan: + case ax::mojom::IntAttribute::kSortDirection: + case ax::mojom::IntAttribute::kHierarchicalLevel: + case ax::mojom::IntAttribute::kNameFrom: + case ax::mojom::IntAttribute::kDescriptionFrom: + case ax::mojom::IntAttribute::kChildTreeId: + case ax::mojom::IntAttribute::kSetSize: + case ax::mojom::IntAttribute::kPosInSet: + case ax::mojom::IntAttribute::kColorValue: + case ax::mojom::IntAttribute::kAriaCurrentState: + case ax::mojom::IntAttribute::kBackgroundColor: + case ax::mojom::IntAttribute::kColor: + case ax::mojom::IntAttribute::kInvalidState: + case ax::mojom::IntAttribute::kCheckedState: + case ax::mojom::IntAttribute::kRestriction: + case ax::mojom::IntAttribute::kTextDirection: + case ax::mojom::IntAttribute::kTextStyle: + case ax::mojom::IntAttribute::kAriaColumnCount: + case ax::mojom::IntAttribute::kAriaCellColumnIndex: + case ax::mojom::IntAttribute::kAriaRowCount: + case ax::mojom::IntAttribute::kAriaCellRowIndex: return false; } @@ -153,32 +157,32 @@ bool IsNodeIdIntAttribute(AXIntAttribute attr) { // Return true if |attr| contains a vector of node ids that would need // to be mapped when renumbering the ids in a combined tree. -bool IsNodeIdIntListAttribute(AXIntListAttribute attr) { +bool IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr) { switch (attr) { - case AX_ATTR_CELL_IDS: - case AX_ATTR_CONTROLS_IDS: - case AX_ATTR_DESCRIBEDBY_IDS: - case AX_ATTR_FLOWTO_IDS: - case AX_ATTR_INDIRECT_CHILD_IDS: - case AX_ATTR_LABELLEDBY_IDS: - case AX_ATTR_RADIO_GROUP_IDS: - case AX_ATTR_UNIQUE_CELL_IDS: + case ax::mojom::IntListAttribute::kCellIds: + case ax::mojom::IntListAttribute::kControlsIds: + case ax::mojom::IntListAttribute::kDescribedbyIds: + case ax::mojom::IntListAttribute::kFlowtoIds: + case ax::mojom::IntListAttribute::kIndirectChildIds: + case ax::mojom::IntListAttribute::kLabelledbyIds: + case ax::mojom::IntListAttribute::kRadioGroupIds: + case ax::mojom::IntListAttribute::kUniqueCellIds: return true; // Note: all of the attributes are included here explicitly, // rather than using "default:", so that it's a compiler error to // add a new attribute without explicitly considering whether it's // a node id attribute or not. - case AX_INT_LIST_ATTRIBUTE_NONE: - case AX_ATTR_LINE_BREAKS: - case AX_ATTR_MARKER_TYPES: - case AX_ATTR_MARKER_STARTS: - case AX_ATTR_MARKER_ENDS: - case AX_ATTR_CHARACTER_OFFSETS: - case AX_ATTR_CACHED_LINE_STARTS: - case AX_ATTR_WORD_STARTS: - case AX_ATTR_WORD_ENDS: - case AX_ATTR_CUSTOM_ACTION_IDS: + case ax::mojom::IntListAttribute::kNone: + case ax::mojom::IntListAttribute::kLineBreaks: + case ax::mojom::IntListAttribute::kMarkerTypes: + case ax::mojom::IntListAttribute::kMarkerStarts: + case ax::mojom::IntListAttribute::kMarkerEnds: + case ax::mojom::IntListAttribute::kCharacterOffsets: + case ax::mojom::IntListAttribute::kCachedLineStarts: + case ax::mojom::IntListAttribute::kWordStarts: + case ax::mojom::IntListAttribute::kWordEnds: + case ax::mojom::IntListAttribute::kCustomActionIds: return false; } @@ -230,20 +234,20 @@ AXNodeData& AXNodeData::operator=(AXNodeData other) { return *this; } -bool AXNodeData::HasBoolAttribute(AXBoolAttribute attribute) const { +bool AXNodeData::HasBoolAttribute(ax::mojom::BoolAttribute attribute) const { auto iter = FindInVectorOfPairs(attribute, bool_attributes); return iter != bool_attributes.end(); } -bool AXNodeData::GetBoolAttribute(AXBoolAttribute attribute) const { +bool AXNodeData::GetBoolAttribute(ax::mojom::BoolAttribute attribute) const { bool result; if (GetBoolAttribute(attribute, &result)) return result; return false; } -bool AXNodeData::GetBoolAttribute( - AXBoolAttribute attribute, bool* value) const { +bool AXNodeData::GetBoolAttribute(ax::mojom::BoolAttribute attribute, + bool* value) const { auto iter = FindInVectorOfPairs(attribute, bool_attributes); if (iter != bool_attributes.end()) { *value = iter->second; @@ -253,20 +257,20 @@ bool AXNodeData::GetBoolAttribute( return false; } -bool AXNodeData::HasFloatAttribute(AXFloatAttribute attribute) const { +bool AXNodeData::HasFloatAttribute(ax::mojom::FloatAttribute attribute) const { auto iter = FindInVectorOfPairs(attribute, float_attributes); return iter != float_attributes.end(); } -float AXNodeData::GetFloatAttribute(AXFloatAttribute attribute) const { +float AXNodeData::GetFloatAttribute(ax::mojom::FloatAttribute attribute) const { float result; if (GetFloatAttribute(attribute, &result)) return result; return 0.0; } -bool AXNodeData::GetFloatAttribute( - AXFloatAttribute attribute, float* value) const { +bool AXNodeData::GetFloatAttribute(ax::mojom::FloatAttribute attribute, + float* value) const { auto iter = FindInVectorOfPairs(attribute, float_attributes); if (iter != float_attributes.end()) { *value = iter->second; @@ -276,20 +280,20 @@ bool AXNodeData::GetFloatAttribute( return false; } -bool AXNodeData::HasIntAttribute(AXIntAttribute attribute) const { +bool AXNodeData::HasIntAttribute(ax::mojom::IntAttribute attribute) const { auto iter = FindInVectorOfPairs(attribute, int_attributes); return iter != int_attributes.end(); } -int AXNodeData::GetIntAttribute(AXIntAttribute attribute) const { +int AXNodeData::GetIntAttribute(ax::mojom::IntAttribute attribute) const { int result; if (GetIntAttribute(attribute, &result)) return result; return 0; } -bool AXNodeData::GetIntAttribute( - AXIntAttribute attribute, int* value) const { +bool AXNodeData::GetIntAttribute(ax::mojom::IntAttribute attribute, + int* value) const { auto iter = FindInVectorOfPairs(attribute, int_attributes); if (iter != int_attributes.end()) { *value = iter->second; @@ -299,20 +303,21 @@ bool AXNodeData::GetIntAttribute( return false; } -bool AXNodeData::HasStringAttribute(AXStringAttribute attribute) const { +bool AXNodeData::HasStringAttribute( + ax::mojom::StringAttribute attribute) const { auto iter = FindInVectorOfPairs(attribute, string_attributes); return iter != string_attributes.end(); } const std::string& AXNodeData::GetStringAttribute( - AXStringAttribute attribute) const { + ax::mojom::StringAttribute attribute) const { CR_DEFINE_STATIC_LOCAL(std::string, empty_string, ()); auto iter = FindInVectorOfPairs(attribute, string_attributes); return iter != string_attributes.end() ? iter->second : empty_string; } -bool AXNodeData::GetStringAttribute( - AXStringAttribute attribute, std::string* value) const { +bool AXNodeData::GetStringAttribute(ax::mojom::StringAttribute attribute, + std::string* value) const { auto iter = FindInVectorOfPairs(attribute, string_attributes); if (iter != string_attributes.end()) { *value = iter->second; @@ -323,16 +328,15 @@ bool AXNodeData::GetStringAttribute( } base::string16 AXNodeData::GetString16Attribute( - AXStringAttribute attribute) const { + ax::mojom::StringAttribute attribute) const { std::string value_utf8; if (!GetStringAttribute(attribute, &value_utf8)) return base::string16(); return base::UTF8ToUTF16(value_utf8); } -bool AXNodeData::GetString16Attribute( - AXStringAttribute attribute, - base::string16* value) const { +bool AXNodeData::GetString16Attribute(ax::mojom::StringAttribute attribute, + base::string16* value) const { std::string value_utf8; if (!GetStringAttribute(attribute, &value_utf8)) return false; @@ -340,13 +344,14 @@ bool AXNodeData::GetString16Attribute( return true; } -bool AXNodeData::HasIntListAttribute(AXIntListAttribute attribute) const { +bool AXNodeData::HasIntListAttribute( + ax::mojom::IntListAttribute attribute) const { auto iter = FindInVectorOfPairs(attribute, intlist_attributes); return iter != intlist_attributes.end(); } const std::vector<int32_t>& AXNodeData::GetIntListAttribute( - AXIntListAttribute attribute) const { + ax::mojom::IntListAttribute attribute) const { CR_DEFINE_STATIC_LOCAL(std::vector<int32_t>, empty_vector, ()); auto iter = FindInVectorOfPairs(attribute, intlist_attributes); if (iter != intlist_attributes.end()) @@ -354,7 +359,7 @@ const std::vector<int32_t>& AXNodeData::GetIntListAttribute( return empty_vector; } -bool AXNodeData::GetIntListAttribute(AXIntListAttribute attribute, +bool AXNodeData::GetIntListAttribute(ax::mojom::IntListAttribute attribute, std::vector<int32_t>* value) const { auto iter = FindInVectorOfPairs(attribute, intlist_attributes); if (iter != intlist_attributes.end()) { @@ -365,13 +370,14 @@ bool AXNodeData::GetIntListAttribute(AXIntListAttribute attribute, return false; } -bool AXNodeData::HasStringListAttribute(AXStringListAttribute attribute) const { +bool AXNodeData::HasStringListAttribute( + ax::mojom::StringListAttribute attribute) const { auto iter = FindInVectorOfPairs(attribute, stringlist_attributes); return iter != stringlist_attributes.end(); } const std::vector<std::string>& AXNodeData::GetStringListAttribute( - AXStringListAttribute attribute) const { + ax::mojom::StringListAttribute attribute) const { CR_DEFINE_STATIC_LOCAL(std::vector<std::string>, empty_vector, ()); auto iter = FindInVectorOfPairs(attribute, stringlist_attributes); if (iter != stringlist_attributes.end()) @@ -379,8 +385,9 @@ const std::vector<std::string>& AXNodeData::GetStringListAttribute( return empty_vector; } -bool AXNodeData::GetStringListAttribute(AXStringListAttribute attribute, - std::vector<std::string>* value) const { +bool AXNodeData::GetStringListAttribute( + ax::mojom::StringListAttribute attribute, + std::vector<std::string>* value) const { auto iter = FindInVectorOfPairs(attribute, stringlist_attributes); if (iter != stringlist_attributes.end()) { *value = iter->second; @@ -392,10 +399,11 @@ bool AXNodeData::GetStringListAttribute(AXStringListAttribute attribute, bool AXNodeData::GetHtmlAttribute( const char* html_attr, std::string* value) const { - for (size_t i = 0; i < html_attributes.size(); ++i) { - const std::string& attr = html_attributes[i].first; + for (const std::pair<std::string, std::string>& html_attribute : + html_attributes) { + const std::string& attr = html_attribute.first; if (base::LowerCaseEqualsASCII(attr, html_attr)) { - *value = html_attributes[i].second; + *value = html_attribute.second; return true; } } @@ -412,82 +420,110 @@ bool AXNodeData::GetHtmlAttribute( return true; } -void AXNodeData::AddStringAttribute( - AXStringAttribute attribute, const std::string& value) { +void AXNodeData::AddStringAttribute(ax::mojom::StringAttribute attribute, + const std::string& value) { string_attributes.push_back(std::make_pair(attribute, value)); } -void AXNodeData::AddIntAttribute( - AXIntAttribute attribute, int value) { +void AXNodeData::AddIntAttribute(ax::mojom::IntAttribute attribute, int value) { int_attributes.push_back(std::make_pair(attribute, value)); } -void AXNodeData::AddFloatAttribute( - AXFloatAttribute attribute, float value) { +void AXNodeData::AddFloatAttribute(ax::mojom::FloatAttribute attribute, + float value) { float_attributes.push_back(std::make_pair(attribute, value)); } -void AXNodeData::AddBoolAttribute( - AXBoolAttribute attribute, bool value) { +void AXNodeData::AddBoolAttribute(ax::mojom::BoolAttribute attribute, + bool value) { bool_attributes.push_back(std::make_pair(attribute, value)); } -void AXNodeData::AddIntListAttribute(AXIntListAttribute attribute, +void AXNodeData::AddIntListAttribute(ax::mojom::IntListAttribute attribute, const std::vector<int32_t>& value) { intlist_attributes.push_back(std::make_pair(attribute, value)); } -void AXNodeData::AddStringListAttribute(AXStringListAttribute attribute, - const std::vector<std::string>& value) { +void AXNodeData::AddStringListAttribute( + ax::mojom::StringListAttribute attribute, + const std::vector<std::string>& value) { stringlist_attributes.push_back(std::make_pair(attribute, value)); } void AXNodeData::SetName(const std::string& name) { - for (size_t i = 0; i < string_attributes.size(); ++i) { - if (string_attributes[i].first == AX_ATTR_NAME) { - string_attributes[i].second = name; - return; - } + auto iter = std::find_if(string_attributes.begin(), string_attributes.end(), + [](const auto& string_attribute) { + return string_attribute.first == + ax::mojom::StringAttribute::kName; + }); + if (iter == string_attributes.end()) { + string_attributes.push_back( + std::make_pair(ax::mojom::StringAttribute::kName, name)); + } else { + iter->second = name; } - - string_attributes.push_back(std::make_pair(AX_ATTR_NAME, name)); } void AXNodeData::SetName(const base::string16& name) { SetName(base::UTF16ToUTF8(name)); } -void AXNodeData::SetValue(const std::string& value) { - for (size_t i = 0; i < string_attributes.size(); ++i) { - if (string_attributes[i].first == AX_ATTR_VALUE) { - string_attributes[i].second = value; - return; - } +void AXNodeData::SetNameExplicitlyEmpty() { + SetNameFrom(ax::mojom::NameFrom::kAttributeExplicitlyEmpty); +} + +void AXNodeData::SetDescription(const std::string& description) { + auto iter = std::find_if(string_attributes.begin(), string_attributes.end(), + [](const auto& string_attribute) { + return string_attribute.first == + ax::mojom::StringAttribute::kDescription; + }); + if (iter == string_attributes.end()) { + string_attributes.push_back( + std::make_pair(ax::mojom::StringAttribute::kDescription, description)); + } else { + iter->second = description; } +} + +void AXNodeData::SetDescription(const base::string16& description) { + SetDescription(base::UTF16ToUTF8(description)); +} - string_attributes.push_back(std::make_pair(AX_ATTR_VALUE, value)); +void AXNodeData::SetValue(const std::string& value) { + auto iter = std::find_if(string_attributes.begin(), string_attributes.end(), + [](const auto& string_attribute) { + return string_attribute.first == + ax::mojom::StringAttribute::kValue; + }); + if (iter == string_attributes.end()) { + string_attributes.push_back( + std::make_pair(ax::mojom::StringAttribute::kValue, value)); + } else { + iter->second = value; + } } void AXNodeData::SetValue(const base::string16& value) { SetValue(base::UTF16ToUTF8(value)); } -bool AXNodeData::HasState(AXState state_enum) const { - return IsFlagSet(state, state_enum); +bool AXNodeData::HasState(ax::mojom::State state_enum) const { + return IsFlagSet(state, static_cast<uint32_t>(state_enum)); } -bool AXNodeData::HasAction(AXAction action_enum) const { - return IsFlagSet(actions, action_enum); +bool AXNodeData::HasAction(ax::mojom::Action action_enum) const { + return IsFlagSet(actions, static_cast<uint32_t>(action_enum)); } -void AXNodeData::AddState(AXState state_enum) { - DCHECK_NE(state_enum, AX_STATE_NONE); - state = ModifyFlag(state, state_enum, true); +void AXNodeData::AddState(ax::mojom::State state_enum) { + DCHECK_NE(state_enum, ax::mojom::State::kNone); + state = ModifyFlag(state, static_cast<uint32_t>(state_enum), true); } -void AXNodeData::AddAction(AXAction action_enum) { +void AXNodeData::AddAction(ax::mojom::Action action_enum) { switch (action_enum) { - case AX_ACTION_NONE: + case ax::mojom::Action::kNone: NOTREACHED(); break; @@ -495,37 +531,38 @@ void AXNodeData::AddAction(AXAction action_enum) { // using "default:", so that it's a compiler error to add a new action // without explicitly considering whether there are mutually exclusive // actions that can be performed on a UI control at the same time. - case AX_ACTION_BLUR: - case AX_ACTION_FOCUS: { - AXAction excluded_action = - (action_enum == AX_ACTION_BLUR) ? AX_ACTION_FOCUS : AX_ACTION_BLUR; + case ax::mojom::Action::kBlur: + case ax::mojom::Action::kFocus: { + ax::mojom::Action excluded_action = + (action_enum == ax::mojom::Action::kBlur) ? ax::mojom::Action::kFocus + : ax::mojom::Action::kBlur; DCHECK(HasAction(excluded_action)); } break; - case AX_ACTION_CUSTOM_ACTION: - case AX_ACTION_DECREMENT: - case AX_ACTION_DO_DEFAULT: - case AX_ACTION_GET_IMAGE_DATA: - case AX_ACTION_HIT_TEST: - case AX_ACTION_INCREMENT: - case AX_ACTION_LOAD_INLINE_TEXT_BOXES: - case AX_ACTION_REPLACE_SELECTED_TEXT: - case AX_ACTION_SCROLL_TO_MAKE_VISIBLE: - case AX_ACTION_SCROLL_TO_POINT: - case AX_ACTION_SET_SCROLL_OFFSET: - case AX_ACTION_SET_SELECTION: - case AX_ACTION_SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT: - case AX_ACTION_SET_VALUE: - case AX_ACTION_SHOW_CONTEXT_MENU: - case AX_ACTION_SCROLL_BACKWARD: - case AX_ACTION_SCROLL_FORWARD: - case AX_ACTION_SCROLL_UP: - case AX_ACTION_SCROLL_DOWN: - case AX_ACTION_SCROLL_LEFT: - case AX_ACTION_SCROLL_RIGHT: + case ax::mojom::Action::kCustomAction: + case ax::mojom::Action::kDecrement: + case ax::mojom::Action::kDoDefault: + case ax::mojom::Action::kGetImageData: + case ax::mojom::Action::kHitTest: + case ax::mojom::Action::kIncrement: + case ax::mojom::Action::kLoadInlineTextBoxes: + case ax::mojom::Action::kReplaceSelectedText: + case ax::mojom::Action::kScrollToMakeVisible: + case ax::mojom::Action::kScrollToPoint: + case ax::mojom::Action::kSetScrollOffset: + case ax::mojom::Action::kSetSelection: + case ax::mojom::Action::kSetSequentialFocusNavigationStartingPoint: + case ax::mojom::Action::kSetValue: + case ax::mojom::Action::kShowContextMenu: + case ax::mojom::Action::kScrollBackward: + case ax::mojom::Action::kScrollForward: + case ax::mojom::Action::kScrollUp: + case ax::mojom::Action::kScrollDown: + case ax::mojom::Action::kScrollLeft: + case ax::mojom::Action::kScrollRight: break; } - actions = ModifyFlag(actions, action_enum, true); + actions = ModifyFlag(actions, static_cast<uint32_t>(action_enum), true); } std::string AXNodeData::ToString() const { @@ -549,450 +586,471 @@ std::string AXNodeData::ToString() const { if (transform && !transform->IsIdentity()) result += " transform=" + transform->ToString(); - for (size_t i = 0; i < int_attributes.size(); ++i) { - std::string value = base::NumberToString(int_attributes[i].second); - switch (int_attributes[i].first) { - case AX_ATTR_DEFAULT_ACTION_VERB: - result += - " action=" + - base::UTF16ToUTF8(ActionVerbToUnlocalizedString( - static_cast<AXDefaultActionVerb>(int_attributes[i].second))); + for (const std::pair<ax::mojom::IntAttribute, int32_t>& int_attribute : + int_attributes) { + std::string value = base::NumberToString(int_attribute.second); + switch (int_attribute.first) { + case ax::mojom::IntAttribute::kDefaultActionVerb: + result += " action=" + base::UTF16ToUTF8(ActionVerbToUnlocalizedString( + static_cast<ax::mojom::DefaultActionVerb>( + int_attribute.second))); break; - case AX_ATTR_SCROLL_X: + case ax::mojom::IntAttribute::kScrollX: result += " scroll_x=" + value; break; - case AX_ATTR_SCROLL_X_MIN: + case ax::mojom::IntAttribute::kScrollXMin: result += " scroll_x_min=" + value; break; - case AX_ATTR_SCROLL_X_MAX: + case ax::mojom::IntAttribute::kScrollXMax: result += " scroll_x_max=" + value; break; - case AX_ATTR_SCROLL_Y: + case ax::mojom::IntAttribute::kScrollY: result += " scroll_y=" + value; break; - case AX_ATTR_SCROLL_Y_MIN: + case ax::mojom::IntAttribute::kScrollYMin: result += " scroll_y_min=" + value; break; - case AX_ATTR_SCROLL_Y_MAX: + case ax::mojom::IntAttribute::kScrollYMax: result += " scroll_y_max=" + value; break; - case AX_ATTR_HIERARCHICAL_LEVEL: + case ax::mojom::IntAttribute::kHierarchicalLevel: result += " level=" + value; break; - case AX_ATTR_TEXT_SEL_START: + case ax::mojom::IntAttribute::kTextSelStart: result += " sel_start=" + value; break; - case AX_ATTR_TEXT_SEL_END: + case ax::mojom::IntAttribute::kTextSelEnd: result += " sel_end=" + value; break; - case AX_ATTR_ARIA_COLUMN_COUNT: + case ax::mojom::IntAttribute::kAriaColumnCount: result += " aria_column_count=" + value; break; - case AX_ATTR_ARIA_CELL_COLUMN_INDEX: + case ax::mojom::IntAttribute::kAriaCellColumnIndex: result += " aria_cell_column_index=" + value; break; - case AX_ATTR_ARIA_ROW_COUNT: + case ax::mojom::IntAttribute::kAriaRowCount: result += " aria_row_count=" + value; break; - case AX_ATTR_ARIA_CELL_ROW_INDEX: + case ax::mojom::IntAttribute::kAriaCellRowIndex: result += " aria_cell_row_index=" + value; break; - case AX_ATTR_TABLE_ROW_COUNT: + case ax::mojom::IntAttribute::kTableRowCount: result += " rows=" + value; break; - case AX_ATTR_TABLE_COLUMN_COUNT: + case ax::mojom::IntAttribute::kTableColumnCount: result += " cols=" + value; break; - case AX_ATTR_TABLE_CELL_COLUMN_INDEX: + case ax::mojom::IntAttribute::kTableCellColumnIndex: result += " col=" + value; break; - case AX_ATTR_TABLE_CELL_ROW_INDEX: + case ax::mojom::IntAttribute::kTableCellRowIndex: result += " row=" + value; break; - case AX_ATTR_TABLE_CELL_COLUMN_SPAN: + case ax::mojom::IntAttribute::kTableCellColumnSpan: result += " colspan=" + value; break; - case AX_ATTR_TABLE_CELL_ROW_SPAN: + case ax::mojom::IntAttribute::kTableCellRowSpan: result += " rowspan=" + value; break; - case AX_ATTR_TABLE_COLUMN_HEADER_ID: + case ax::mojom::IntAttribute::kTableColumnHeaderId: result += " column_header_id=" + value; break; - case AX_ATTR_TABLE_COLUMN_INDEX: + case ax::mojom::IntAttribute::kTableColumnIndex: result += " column_index=" + value; break; - case AX_ATTR_TABLE_HEADER_ID: + case ax::mojom::IntAttribute::kTableHeaderId: result += " header_id=" + value; break; - case AX_ATTR_TABLE_ROW_HEADER_ID: + case ax::mojom::IntAttribute::kTableRowHeaderId: result += " row_header_id=" + value; break; - case AX_ATTR_TABLE_ROW_INDEX: + case ax::mojom::IntAttribute::kTableRowIndex: result += " row_index=" + value; break; - case AX_ATTR_SORT_DIRECTION: - switch (int_attributes[i].second) { - case AX_SORT_DIRECTION_UNSORTED: + case ax::mojom::IntAttribute::kSortDirection: + switch (static_cast<ax::mojom::SortDirection>(int_attribute.second)) { + case ax::mojom::SortDirection::kUnsorted: result += " sort_direction=none"; break; - case AX_SORT_DIRECTION_ASCENDING: + case ax::mojom::SortDirection::kAscending: result += " sort_direction=ascending"; break; - case AX_SORT_DIRECTION_DESCENDING: + case ax::mojom::SortDirection::kDescending: result += " sort_direction=descending"; break; - case AX_SORT_DIRECTION_OTHER: + case ax::mojom::SortDirection::kOther: result += " sort_direction=other"; break; + default: + break; } break; - case AX_ATTR_NAME_FROM: + case ax::mojom::IntAttribute::kNameFrom: result += " name_from="; - result += - ui::ToString(static_cast<AXNameFrom>(int_attributes[i].second)); + result += ui::ToString( + static_cast<ax::mojom::NameFrom>(int_attribute.second)); break; - case AX_ATTR_DESCRIPTION_FROM: + case ax::mojom::IntAttribute::kDescriptionFrom: result += " description_from="; result += ui::ToString( - static_cast<AXDescriptionFrom>(int_attributes[i].second)); + static_cast<ax::mojom::DescriptionFrom>(int_attribute.second)); break; - case AX_ATTR_ACTIVEDESCENDANT_ID: + case ax::mojom::IntAttribute::kActivedescendantId: result += " activedescendant=" + value; break; - case AX_ATTR_DETAILS_ID: + case ax::mojom::IntAttribute::kDetailsId: result += " details=" + value; break; - case AX_ATTR_ERRORMESSAGE_ID: + case ax::mojom::IntAttribute::kErrormessageId: result += " errormessage=" + value; break; - case AX_ATTR_IN_PAGE_LINK_TARGET_ID: + case ax::mojom::IntAttribute::kInPageLinkTargetId: result += " in_page_link_target_id=" + value; break; - case AX_ATTR_MEMBER_OF_ID: + case ax::mojom::IntAttribute::kMemberOfId: result += " member_of_id=" + value; break; - case AX_ATTR_NEXT_ON_LINE_ID: + case ax::mojom::IntAttribute::kNextOnLineId: result += " next_on_line_id=" + value; break; - case AX_ATTR_PREVIOUS_ON_LINE_ID: + case ax::mojom::IntAttribute::kPreviousOnLineId: result += " previous_on_line_id=" + value; break; - case AX_ATTR_CHILD_TREE_ID: + case ax::mojom::IntAttribute::kChildTreeId: result += " child_tree_id=" + value; break; - case AX_ATTR_COLOR_VALUE: - result += base::StringPrintf(" color_value=&%X", - int_attributes[i].second); + case ax::mojom::IntAttribute::kColorValue: + result += base::StringPrintf(" color_value=&%X", int_attribute.second); break; - case AX_ATTR_ARIA_CURRENT_STATE: - switch (int_attributes[i].second) { - case AX_ARIA_CURRENT_STATE_FALSE: + case ax::mojom::IntAttribute::kAriaCurrentState: + switch ( + static_cast<ax::mojom::AriaCurrentState>(int_attribute.second)) { + case ax::mojom::AriaCurrentState::kFalse: result += " aria_current_state=false"; break; - case AX_ARIA_CURRENT_STATE_TRUE: + case ax::mojom::AriaCurrentState::kTrue: result += " aria_current_state=true"; break; - case AX_ARIA_CURRENT_STATE_PAGE: + case ax::mojom::AriaCurrentState::kPage: result += " aria_current_state=page"; break; - case AX_ARIA_CURRENT_STATE_STEP: + case ax::mojom::AriaCurrentState::kStep: result += " aria_current_state=step"; break; - case AX_ARIA_CURRENT_STATE_LOCATION: + case ax::mojom::AriaCurrentState::kLocation: result += " aria_current_state=location"; break; - case AX_ARIA_CURRENT_STATE_DATE: + case ax::mojom::AriaCurrentState::kDate: result += " aria_current_state=date"; break; - case AX_ARIA_CURRENT_STATE_TIME: + case ax::mojom::AriaCurrentState::kTime: result += " aria_current_state=time"; break; + default: + break; } break; - case AX_ATTR_BACKGROUND_COLOR: - result += base::StringPrintf(" background_color=&%X", - int_attributes[i].second); + case ax::mojom::IntAttribute::kBackgroundColor: + result += + base::StringPrintf(" background_color=&%X", int_attribute.second); break; - case AX_ATTR_COLOR: - result += base::StringPrintf(" color=&%X", int_attributes[i].second); + case ax::mojom::IntAttribute::kColor: + result += base::StringPrintf(" color=&%X", int_attribute.second); break; - case AX_ATTR_TEXT_DIRECTION: - switch (int_attributes[i].second) { - case AX_TEXT_DIRECTION_LTR: + case ax::mojom::IntAttribute::kTextDirection: + switch (static_cast<ax::mojom::TextDirection>(int_attribute.second)) { + case ax::mojom::TextDirection::kLtr: result += " text_direction=ltr"; break; - case AX_TEXT_DIRECTION_RTL: + case ax::mojom::TextDirection::kRtl: result += " text_direction=rtl"; break; - case AX_TEXT_DIRECTION_TTB: + case ax::mojom::TextDirection::kTtb: result += " text_direction=ttb"; break; - case AX_TEXT_DIRECTION_BTT: + case ax::mojom::TextDirection::kBtt: result += " text_direction=btt"; break; + default: + break; } break; - case AX_ATTR_TEXT_STYLE: { - auto text_style = static_cast<AXTextStyle>(int_attributes[i].second); - if (text_style == AX_TEXT_STYLE_NONE) + case ax::mojom::IntAttribute::kTextStyle: { + int32_t text_style = int_attribute.second; + if (text_style == static_cast<int32_t>(ax::mojom::TextStyle::kNone)) break; std::string text_style_value(" text_style="); - if (text_style & AX_TEXT_STYLE_BOLD) + if (text_style & + static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleBold)) text_style_value += "bold,"; - if (text_style & AX_TEXT_STYLE_ITALIC) + if (text_style & + static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleItalic)) text_style_value += "italic,"; - if (text_style & AX_TEXT_STYLE_UNDERLINE) + if (text_style & + static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleUnderline)) text_style_value += "underline,"; - if (text_style & AX_TEXT_STYLE_LINE_THROUGH) + if (text_style & + static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleLineThrough)) text_style_value += "line-through,"; result += text_style_value.substr(0, text_style_value.size() - 1); break; } - case AX_ATTR_SET_SIZE: + case ax::mojom::IntAttribute::kSetSize: result += " setsize=" + value; break; - case AX_ATTR_POS_IN_SET: + case ax::mojom::IntAttribute::kPosInSet: result += " posinset=" + value; break; - case AX_ATTR_INVALID_STATE: - switch (int_attributes[i].second) { - case AX_INVALID_STATE_FALSE: + case ax::mojom::IntAttribute::kInvalidState: + switch (static_cast<ax::mojom::InvalidState>(int_attribute.second)) { + case ax::mojom::InvalidState::kFalse: result += " invalid_state=false"; break; - case AX_INVALID_STATE_TRUE: + case ax::mojom::InvalidState::kTrue: result += " invalid_state=true"; break; - case AX_INVALID_STATE_SPELLING: + case ax::mojom::InvalidState::kSpelling: result += " invalid_state=spelling"; break; - case AX_INVALID_STATE_GRAMMAR: + case ax::mojom::InvalidState::kGrammar: result += " invalid_state=grammar"; break; - case AX_INVALID_STATE_OTHER: + case ax::mojom::InvalidState::kOther: result += " invalid_state=other"; break; + default: + break; } break; - case AX_ATTR_CHECKED_STATE: - switch (int_attributes[i].second) { - case AX_CHECKED_STATE_FALSE: + case ax::mojom::IntAttribute::kCheckedState: + switch (static_cast<ax::mojom::CheckedState>(int_attribute.second)) { + case ax::mojom::CheckedState::kFalse: result += " checked_state=false"; break; - case AX_CHECKED_STATE_TRUE: + case ax::mojom::CheckedState::kTrue: result += " checked_state=true"; break; - case AX_CHECKED_STATE_MIXED: + case ax::mojom::CheckedState::kMixed: result += " checked_state=mixed"; break; + default: + break; } break; - case AX_ATTR_RESTRICTION: - switch (int_attributes[i].second) { - case AX_RESTRICTION_READ_ONLY: + case ax::mojom::IntAttribute::kRestriction: + switch (static_cast<ax::mojom::Restriction>(int_attribute.second)) { + case ax::mojom::Restriction::kReadOnly: result += " restriction=readonly"; break; - case AX_RESTRICTION_DISABLED: + case ax::mojom::Restriction::kDisabled: result += " restriction=disabled"; break; + default: + break; } break; - case AX_ATTR_NEXT_FOCUS_ID: + case ax::mojom::IntAttribute::kNextFocusId: result += " next_focus_id=" + value; break; - case AX_ATTR_PREVIOUS_FOCUS_ID: + case ax::mojom::IntAttribute::kPreviousFocusId: result += " previous_focus_id=" + value; break; - case AX_INT_ATTRIBUTE_NONE: + case ax::mojom::IntAttribute::kNone: break; } } - for (size_t i = 0; i < string_attributes.size(); ++i) { - std::string value = string_attributes[i].second; - switch (string_attributes[i].first) { - case AX_ATTR_ACCESS_KEY: + for (const std::pair<ax::mojom::StringAttribute, std::string>& + string_attribute : string_attributes) { + std::string value = string_attribute.second; + switch (string_attribute.first) { + case ax::mojom::StringAttribute::kAccessKey: result += " access_key=" + value; break; - case AX_ATTR_ARIA_INVALID_VALUE: + case ax::mojom::StringAttribute::kAriaInvalidValue: result += " aria_invalid_value=" + value; break; - case AX_ATTR_AUTO_COMPLETE: + case ax::mojom::StringAttribute::kAutoComplete: result += " autocomplete=" + value; break; - case AX_ATTR_CHROME_CHANNEL: + case ax::mojom::StringAttribute::kChromeChannel: result += " chrome_channel=" + value; break; - case AX_ATTR_CLASS_NAME: + case ax::mojom::StringAttribute::kClassName: result += " class_name=" + value; break; - case AX_ATTR_DESCRIPTION: + case ax::mojom::StringAttribute::kDescription: result += " description=" + value; break; - case AX_ATTR_DISPLAY: + case ax::mojom::StringAttribute::kDisplay: result += " display=" + value; break; - case AX_ATTR_FONT_FAMILY: + case ax::mojom::StringAttribute::kFontFamily: result += " font-family=" + value; break; - case AX_ATTR_HTML_TAG: + case ax::mojom::StringAttribute::kHtmlTag: result += " html_tag=" + value; break; - case AX_ATTR_IMAGE_DATA_URL: + case ax::mojom::StringAttribute::kImageDataUrl: result += " image_data_url=(" + base::NumberToString(static_cast<int>(value.size())) + " bytes)"; break; - case AX_ATTR_INNER_HTML: + case ax::mojom::StringAttribute::kInnerHtml: result += " inner_html=" + value; break; - case AX_ATTR_KEY_SHORTCUTS: + case ax::mojom::StringAttribute::kKeyShortcuts: result += " key_shortcuts=" + value; break; - case AX_ATTR_LANGUAGE: + case ax::mojom::StringAttribute::kLanguage: result += " language=" + value; break; - case AX_ATTR_LIVE_RELEVANT: + case ax::mojom::StringAttribute::kLiveRelevant: result += " relevant=" + value; break; - case AX_ATTR_LIVE_STATUS: + case ax::mojom::StringAttribute::kLiveStatus: result += " live=" + value; break; - case AX_ATTR_CONTAINER_LIVE_RELEVANT: + case ax::mojom::StringAttribute::kContainerLiveRelevant: result += " container_relevant=" + value; break; - case AX_ATTR_CONTAINER_LIVE_STATUS: + case ax::mojom::StringAttribute::kContainerLiveStatus: result += " container_live=" + value; break; - case AX_ATTR_PLACEHOLDER: + case ax::mojom::StringAttribute::kPlaceholder: result += " placeholder=" + value; break; - case AX_ATTR_ROLE: + case ax::mojom::StringAttribute::kRole: result += " role=" + value; break; - case AX_ATTR_ROLE_DESCRIPTION: + case ax::mojom::StringAttribute::kRoleDescription: result += " role_description=" + value; break; - case AX_ATTR_URL: + case ax::mojom::StringAttribute::kUrl: result += " url=" + value; break; - case AX_ATTR_NAME: + case ax::mojom::StringAttribute::kName: result += " name=" + value; break; - case AX_ATTR_VALUE: + case ax::mojom::StringAttribute::kValue: result += " value=" + value; break; - case AX_STRING_ATTRIBUTE_NONE: + case ax::mojom::StringAttribute::kNone: break; } } - for (size_t i = 0; i < float_attributes.size(); ++i) { - std::string value = base::NumberToString(float_attributes[i].second); - switch (float_attributes[i].first) { - case AX_ATTR_VALUE_FOR_RANGE: + for (const std::pair<ax::mojom::FloatAttribute, float>& float_attribute : + float_attributes) { + std::string value = base::NumberToString(float_attribute.second); + switch (float_attribute.first) { + case ax::mojom::FloatAttribute::kValueForRange: result += " value_for_range=" + value; break; - case AX_ATTR_MAX_VALUE_FOR_RANGE: + case ax::mojom::FloatAttribute::kMaxValueForRange: result += " max_value=" + value; break; - case AX_ATTR_MIN_VALUE_FOR_RANGE: + case ax::mojom::FloatAttribute::kMinValueForRange: result += " min_value=" + value; break; - case AX_ATTR_STEP_VALUE_FOR_RANGE: + case ax::mojom::FloatAttribute::kStepValueForRange: result += " step_value=" + value; break; - case AX_ATTR_FONT_SIZE: + case ax::mojom::FloatAttribute::kFontSize: result += " font_size=" + value; break; - case AX_FLOAT_ATTRIBUTE_NONE: + case ax::mojom::FloatAttribute::kNone: break; } } - for (size_t i = 0; i < bool_attributes.size(); ++i) { - std::string value = bool_attributes[i].second ? "true" : "false"; - switch (bool_attributes[i].first) { - case AX_ATTR_EDITABLE_ROOT: + for (const std::pair<ax::mojom::BoolAttribute, bool>& bool_attribute : + bool_attributes) { + std::string value = bool_attribute.second ? "true" : "false"; + switch (bool_attribute.first) { + case ax::mojom::BoolAttribute::kEditableRoot: result += " editable_root=" + value; break; - case AX_ATTR_LIVE_ATOMIC: + case ax::mojom::BoolAttribute::kLiveAtomic: result += " atomic=" + value; break; - case AX_ATTR_BUSY: + case ax::mojom::BoolAttribute::kBusy: result += " busy=" + value; break; - case AX_ATTR_CONTAINER_LIVE_ATOMIC: + case ax::mojom::BoolAttribute::kContainerLiveAtomic: result += " container_atomic=" + value; break; - case AX_ATTR_CONTAINER_LIVE_BUSY: + case ax::mojom::BoolAttribute::kContainerLiveBusy: result += " container_busy=" + value; break; - case AX_ATTR_UPDATE_LOCATION_ONLY: + case ax::mojom::BoolAttribute::kUpdateLocationOnly: result += " update_location_only=" + value; break; - case AX_ATTR_CANVAS_HAS_FALLBACK: + case ax::mojom::BoolAttribute::kCanvasHasFallback: result += " has_fallback=" + value; break; - case AX_ATTR_MODAL: + case ax::mojom::BoolAttribute::kModal: result += " modal=" + value; break; - case AX_ATTR_SCROLLABLE: + case ax::mojom::BoolAttribute::kScrollable: result += " scrollable=" + value; break; - case AX_ATTR_CLICKABLE: + case ax::mojom::BoolAttribute::kClickable: result += " clickable=" + value; break; - case AX_ATTR_CLIPS_CHILDREN: + case ax::mojom::BoolAttribute::kClipsChildren: result += " clips_children=" + value; break; - case AX_BOOL_ATTRIBUTE_NONE: + case ax::mojom::BoolAttribute::kNone: break; } } - for (size_t i = 0; i < intlist_attributes.size(); ++i) { - const std::vector<int32_t>& values = intlist_attributes[i].second; - switch (intlist_attributes[i].first) { - case AX_ATTR_INDIRECT_CHILD_IDS: + for (const std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>& + intlist_attribute : intlist_attributes) { + const std::vector<int32_t>& values = intlist_attribute.second; + switch (intlist_attribute.first) { + case ax::mojom::IntListAttribute::kIndirectChildIds: result += " indirect_child_ids=" + IntVectorToString(values); break; - case AX_ATTR_CONTROLS_IDS: + case ax::mojom::IntListAttribute::kControlsIds: result += " controls_ids=" + IntVectorToString(values); break; - case AX_ATTR_DESCRIBEDBY_IDS: + case ax::mojom::IntListAttribute::kDescribedbyIds: result += " describedby_ids=" + IntVectorToString(values); break; - case AX_ATTR_FLOWTO_IDS: + case ax::mojom::IntListAttribute::kFlowtoIds: result += " flowto_ids=" + IntVectorToString(values); break; - case AX_ATTR_LABELLEDBY_IDS: + case ax::mojom::IntListAttribute::kLabelledbyIds: result += " labelledby_ids=" + IntVectorToString(values); break; - case AX_ATTR_RADIO_GROUP_IDS: + case ax::mojom::IntListAttribute::kRadioGroupIds: result += " radio_group_ids=" + IntVectorToString(values); break; - case AX_ATTR_LINE_BREAKS: + case ax::mojom::IntListAttribute::kLineBreaks: result += " line_breaks=" + IntVectorToString(values); break; - case AX_ATTR_MARKER_TYPES: { + case ax::mojom::IntListAttribute::kMarkerTypes: { std::string types_str; for (size_t i = 0; i < values.size(); ++i) { - auto type = static_cast<AXMarkerType>(values[i]); - if (type == AX_MARKER_TYPE_NONE) + int32_t type = values[i]; + if (type == static_cast<int32_t>(ax::mojom::MarkerType::kNone)) continue; if (i > 0) types_str += ','; - if (type & AX_MARKER_TYPE_SPELLING) + if (type & static_cast<int32_t>(ax::mojom::MarkerType::kSpelling)) types_str += "spelling&"; - if (type & AX_MARKER_TYPE_GRAMMAR) + if (type & static_cast<int32_t>(ax::mojom::MarkerType::kGrammar)) types_str += "grammar&"; - if (type & AX_MARKER_TYPE_TEXT_MATCH) + if (type & static_cast<int32_t>(ax::mojom::MarkerType::kTextMatch)) types_str += "text_match&"; - if (type & AX_MARKER_TYPE_ACTIVE_SUGGESTION) + if (type & + static_cast<int32_t>(ax::mojom::MarkerType::kActiveSuggestion)) types_str += "active_suggestion&"; - if (type & AX_MARKER_TYPE_SUGGESTION) + if (type & static_cast<int32_t>(ax::mojom::MarkerType::kSuggestion)) types_str += "suggestion&"; if (!types_str.empty()) @@ -1003,46 +1061,48 @@ std::string AXNodeData::ToString() const { result += " marker_types=" + types_str; break; } - case AX_ATTR_MARKER_STARTS: + case ax::mojom::IntListAttribute::kMarkerStarts: result += " marker_starts=" + IntVectorToString(values); break; - case AX_ATTR_MARKER_ENDS: + case ax::mojom::IntListAttribute::kMarkerEnds: result += " marker_ends=" + IntVectorToString(values); break; - case AX_ATTR_CELL_IDS: + case ax::mojom::IntListAttribute::kCellIds: result += " cell_ids=" + IntVectorToString(values); break; - case AX_ATTR_UNIQUE_CELL_IDS: + case ax::mojom::IntListAttribute::kUniqueCellIds: result += " unique_cell_ids=" + IntVectorToString(values); break; - case AX_ATTR_CHARACTER_OFFSETS: + case ax::mojom::IntListAttribute::kCharacterOffsets: result += " character_offsets=" + IntVectorToString(values); break; - case AX_ATTR_CACHED_LINE_STARTS: + case ax::mojom::IntListAttribute::kCachedLineStarts: result += " cached_line_start_offsets=" + IntVectorToString(values); break; - case AX_ATTR_WORD_STARTS: + case ax::mojom::IntListAttribute::kWordStarts: result += " word_starts=" + IntVectorToString(values); break; - case AX_ATTR_WORD_ENDS: + case ax::mojom::IntListAttribute::kWordEnds: result += " word_ends=" + IntVectorToString(values); break; - case AX_ATTR_CUSTOM_ACTION_IDS: + case ax::mojom::IntListAttribute::kCustomActionIds: result += " custom_action_ids=" + IntVectorToString(values); break; - case AX_INT_LIST_ATTRIBUTE_NONE: + case ax::mojom::IntListAttribute::kNone: break; } } - for (size_t i = 0; i < stringlist_attributes.size(); ++i) { - const std::vector<std::string>& values = stringlist_attributes[i].second; - switch (stringlist_attributes[i].first) { - case AX_ATTR_CUSTOM_ACTION_DESCRIPTIONS: + for (const std::pair<ax::mojom::StringListAttribute, + std::vector<std::string>>& stringlist_attribute : + stringlist_attributes) { + const std::vector<std::string>& values = stringlist_attribute.second; + switch (stringlist_attribute.first) { + case ax::mojom::StringListAttribute::kCustomActionDescriptions: result += " custom_action_descriptions: " + base::JoinString(values, ","); break; - case AX_STRING_LIST_ATTRIBUTE_NONE: + case ax::mojom::StringListAttribute::kNone: break; } } diff --git a/chromium/ui/accessibility/ax_node_data.h b/chromium/ui/accessibility/ax_node_data.h index 0f2194e421d..5741f15c40b 100644 --- a/chromium/ui/accessibility/ax_node_data.h +++ b/chromium/ui/accessibility/ax_node_data.h @@ -14,7 +14,7 @@ #include "base/strings/string16.h" #include "base/strings/string_split.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" #include "ui/gfx/geometry/rect_f.h" @@ -26,11 +26,11 @@ namespace ui { // Return true if |attr| should be interpreted as the id of another node // in the same tree. -AX_EXPORT bool IsNodeIdIntAttribute(AXIntAttribute attr); +AX_EXPORT bool IsNodeIdIntAttribute(ax::mojom::IntAttribute attr); // Return true if |attr| should be interpreted as a list of ids of // nodes in the same tree. -AX_EXPORT bool IsNodeIdIntListAttribute(AXIntListAttribute attr); +AX_EXPORT bool IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr); // A compact representation of the accessibility information for a // single accessible object, in a form that can be serialized and sent from @@ -57,70 +57,134 @@ struct AX_EXPORT AXNodeData { // attribute is not present. In addition, strings can be returned as // either std::string or base::string16, for convenience. - bool HasBoolAttribute(AXBoolAttribute attr) const; - bool GetBoolAttribute(AXBoolAttribute attr) const; - bool GetBoolAttribute(AXBoolAttribute attr, bool* value) const; + bool HasBoolAttribute(ax::mojom::BoolAttribute attr) const; + bool GetBoolAttribute(ax::mojom::BoolAttribute attr) const; + bool GetBoolAttribute(ax::mojom::BoolAttribute attr, bool* value) const; - bool HasFloatAttribute(AXFloatAttribute attr) const; - float GetFloatAttribute(AXFloatAttribute attr) const; - bool GetFloatAttribute(AXFloatAttribute attr, float* value) const; + bool HasFloatAttribute(ax::mojom::FloatAttribute attr) const; + float GetFloatAttribute(ax::mojom::FloatAttribute attr) const; + bool GetFloatAttribute(ax::mojom::FloatAttribute attr, float* value) const; - bool HasIntAttribute(AXIntAttribute attribute) const; - int GetIntAttribute(AXIntAttribute attribute) const; - bool GetIntAttribute(AXIntAttribute attribute, int* value) const; + bool HasIntAttribute(ax::mojom::IntAttribute attribute) const; + int32_t GetIntAttribute(ax::mojom::IntAttribute attribute) const; + bool GetIntAttribute(ax::mojom::IntAttribute attribute, int* value) const; - bool HasStringAttribute( - AXStringAttribute attribute) const; - const std::string& GetStringAttribute(AXStringAttribute attribute) const; - bool GetStringAttribute(AXStringAttribute attribute, + bool HasStringAttribute(ax::mojom::StringAttribute attribute) const; + const std::string& GetStringAttribute( + ax::mojom::StringAttribute attribute) const; + bool GetStringAttribute(ax::mojom::StringAttribute attribute, std::string* value) const; - bool GetString16Attribute(AXStringAttribute attribute, + bool GetString16Attribute(ax::mojom::StringAttribute attribute, base::string16* value) const; base::string16 GetString16Attribute( - AXStringAttribute attribute) const; + ax::mojom::StringAttribute attribute) const; - bool HasIntListAttribute(AXIntListAttribute attribute) const; + bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const; const std::vector<int32_t>& GetIntListAttribute( - AXIntListAttribute attribute) const; - bool GetIntListAttribute(AXIntListAttribute attribute, + ax::mojom::IntListAttribute attribute) const; + bool GetIntListAttribute(ax::mojom::IntListAttribute attribute, std::vector<int32_t>* value) const; - bool HasStringListAttribute(AXStringListAttribute attribute) const; + bool HasStringListAttribute(ax::mojom::StringListAttribute attribute) const; const std::vector<std::string>& GetStringListAttribute( - AXStringListAttribute attribute) const; - bool GetStringListAttribute(AXStringListAttribute attribute, + ax::mojom::StringListAttribute attribute) const; + bool GetStringListAttribute(ax::mojom::StringListAttribute attribute, std::vector<std::string>* value) const; bool GetHtmlAttribute(const char* attr, base::string16* value) const; bool GetHtmlAttribute(const char* attr, std::string* value) const; // Setting accessibility attributes. - void AddStringAttribute(AXStringAttribute attribute, + void AddStringAttribute(ax::mojom::StringAttribute attribute, const std::string& value); - void AddIntAttribute(AXIntAttribute attribute, int value); - void AddFloatAttribute(AXFloatAttribute attribute, float value); - void AddBoolAttribute(AXBoolAttribute attribute, bool value); - void AddIntListAttribute(AXIntListAttribute attribute, + void AddIntAttribute(ax::mojom::IntAttribute attribute, int32_t value); + void AddFloatAttribute(ax::mojom::FloatAttribute attribute, float value); + void AddBoolAttribute(ax::mojom::BoolAttribute attribute, bool value); + void AddIntListAttribute(ax::mojom::IntListAttribute attribute, const std::vector<int32_t>& value); - void AddStringListAttribute(AXStringListAttribute attribute, + void AddStringListAttribute(ax::mojom::StringListAttribute attribute, const std::vector<std::string>& value); - // Convenience functions, mainly for writing unit tests. - // Equivalent to AddStringAttribute(ATTR_NAME, name). + // + // Convenience functions. + // + + // Adds the name attribute or replaces it if already present. void SetName(const std::string& name); void SetName(const base::string16& name); - // Equivalent to AddStringAttribute(ATTR_VALUE, value). + + // Allows nameless objects to pass accessibility checks. + void SetNameExplicitlyEmpty(); + + // Adds the description attribute or replaces it if already present. + void SetDescription(const std::string& description); + void SetDescription(const base::string16& description); + + // Adds the value attribute or replaces it if already present. void SetValue(const std::string& value); void SetValue(const base::string16& value); // Returns true if the given enum bit is 1. - bool HasState(ui::AXState state_enum) const; - bool HasAction(ui::AXAction state_enum) const; + bool HasState(ax::mojom::State state_enum) const; + bool HasAction(ax::mojom::Action state_enum) const; // Set bits in the given enum's corresponding bitfield. - void AddState(ui::AXState state_enum); - void AddAction(ui::AXAction action_enum); + void AddState(ax::mojom::State state_enum); + void AddAction(ax::mojom::Action action_enum); + + // Helper functions to get some common int attributes with some specific + // enum types: + ax::mojom::CheckedState GetCheckedState() const { + return static_cast<ax::mojom::CheckedState>( + GetIntAttribute(ax::mojom::IntAttribute::kCheckedState)); + } + ax::mojom::DefaultActionVerb GetDefaultActionVerb() const { + return static_cast<ax::mojom::DefaultActionVerb>( + GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb)); + } + ax::mojom::InvalidState GetInvalidState() const { + return static_cast<ax::mojom::InvalidState>( + GetIntAttribute(ax::mojom::IntAttribute::kInvalidState)); + } + ax::mojom::NameFrom GetNameFrom() const { + return static_cast<ax::mojom::NameFrom>( + GetIntAttribute(ax::mojom::IntAttribute::kNameFrom)); + } + ax::mojom::Restriction GetRestriction() const { + return static_cast<ax::mojom::Restriction>( + GetIntAttribute(ax::mojom::IntAttribute::kRestriction)); + } + ax::mojom::TextDirection GetTextDirection() const { + return static_cast<ax::mojom::TextDirection>( + GetIntAttribute(ax::mojom::IntAttribute::kTextDirection)); + } + + // Helper functions to set some common int attributes. + void SetCheckedState(ax::mojom::CheckedState checked_state) { + AddIntAttribute(ax::mojom::IntAttribute::kCheckedState, + static_cast<int32_t>(checked_state)); + } + void SetDefaultActionVerb(ax::mojom::DefaultActionVerb default_action_verb) { + AddIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, + static_cast<int32_t>(default_action_verb)); + } + void SetInvalidState(ax::mojom::InvalidState invalid_state) { + AddIntAttribute(ax::mojom::IntAttribute::kInvalidState, + static_cast<int32_t>(invalid_state)); + } + void SetNameFrom(ax::mojom::NameFrom name_from) { + AddIntAttribute(ax::mojom::IntAttribute::kNameFrom, + static_cast<int32_t>(name_from)); + } + void SetRestriction(ax::mojom::Restriction restriction) { + AddIntAttribute(ax::mojom::IntAttribute::kRestriction, + static_cast<int32_t>(restriction)); + } + void SetTextDirection(ax::mojom::TextDirection text_direction) { + AddIntAttribute(ax::mojom::IntAttribute::kTextDirection, + static_cast<int32_t>(text_direction)); + } // Return a string representation of this data, for debugging. virtual std::string ToString() const; @@ -128,16 +192,18 @@ struct AX_EXPORT AXNodeData { // As much as possible this should behave as a simple, serializable, // copyable struct. int32_t id = -1; - AXRole role = AX_ROLE_UNKNOWN; - uint32_t state = AX_STATE_NONE; - uint32_t actions = AX_ACTION_NONE; - std::vector<std::pair<AXStringAttribute, std::string>> string_attributes; - std::vector<std::pair<AXIntAttribute, int32_t>> int_attributes; - std::vector<std::pair<AXFloatAttribute, float>> float_attributes; - std::vector<std::pair<AXBoolAttribute, bool>> bool_attributes; - std::vector<std::pair<AXIntListAttribute, std::vector<int32_t>>> + ax::mojom::Role role = ax::mojom::Role::kUnknown; + uint32_t state = static_cast<uint32_t>(ax::mojom::State::kNone); + uint32_t actions = static_cast<uint32_t>(ax::mojom::Action::kNone); + std::vector<std::pair<ax::mojom::StringAttribute, std::string>> + string_attributes; + std::vector<std::pair<ax::mojom::IntAttribute, int32_t>> int_attributes; + std::vector<std::pair<ax::mojom::FloatAttribute, float>> float_attributes; + std::vector<std::pair<ax::mojom::BoolAttribute, bool>> bool_attributes; + std::vector<std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>> intlist_attributes; - std::vector<std::pair<AXStringListAttribute, std::vector<std::string>>> + std::vector< + std::pair<ax::mojom::StringListAttribute, std::vector<std::string>>> stringlist_attributes; base::StringPairs html_attributes; std::vector<int32_t> child_ids; diff --git a/chromium/ui/accessibility/ax_node_position.cc b/chromium/ui/accessibility/ax_node_position.cc index 95318cc7fb6..9711f344677 100644 --- a/chromium/ui/accessibility/ax_node_position.cc +++ b/chromium/ui/accessibility/ax_node_position.cc @@ -5,7 +5,7 @@ #include "ui/accessibility/ax_node_position.h" #include "base/strings/string_util.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" namespace ui { @@ -24,11 +24,12 @@ base::string16 AXNodePosition::GetInnerText() const { return base::string16(); DCHECK(GetAnchor()); - base::string16 value = - GetAnchor()->data().GetString16Attribute(AX_ATTR_VALUE); + base::string16 value = GetAnchor()->data().GetString16Attribute( + ax::mojom::StringAttribute::kValue); if (!value.empty()) return value; - return GetAnchor()->data().GetString16Attribute(AX_ATTR_NAME); + return GetAnchor()->data().GetString16Attribute( + ax::mojom::StringAttribute::kName); } void AXNodePosition::AnchorChild(int child_index, @@ -100,14 +101,16 @@ std::vector<int32_t> AXNodePosition::GetWordStartOffsets() const { if (IsNullPosition()) return std::vector<int32_t>(); DCHECK(GetAnchor()); - return GetAnchor()->data().GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); + return GetAnchor()->data().GetIntListAttribute( + ax::mojom::IntListAttribute::kWordStarts); } std::vector<int32_t> AXNodePosition::GetWordEndOffsets() const { if (IsNullPosition()) return std::vector<int32_t>(); DCHECK(GetAnchor()); - return GetAnchor()->data().GetIntListAttribute(ui::AX_ATTR_WORD_ENDS); + return GetAnchor()->data().GetIntListAttribute( + ax::mojom::IntListAttribute::kWordEnds); } int32_t AXNodePosition::GetNextOnLineID(int32_t node_id) const { @@ -115,9 +118,8 @@ int32_t AXNodePosition::GetNextOnLineID(int32_t node_id) const { return INVALID_ANCHOR_ID; AXNode* node = GetNodeInTree(tree_id(), node_id); int next_on_line_id; - if (!node || - !node->data().GetIntAttribute(AX_ATTR_NEXT_ON_LINE_ID, - &next_on_line_id)) { + if (!node || !node->data().GetIntAttribute( + ax::mojom::IntAttribute::kNextOnLineId, &next_on_line_id)) { return INVALID_ANCHOR_ID; } return static_cast<int32_t>(next_on_line_id); @@ -129,7 +131,7 @@ int32_t AXNodePosition::GetPreviousOnLineID(int32_t node_id) const { AXNode* node = GetNodeInTree(tree_id(), node_id); int previous_on_line_id; if (!node || - !node->data().GetIntAttribute(AX_ATTR_PREVIOUS_ON_LINE_ID, + !node->data().GetIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId, &previous_on_line_id)) { return INVALID_ANCHOR_ID; } diff --git a/chromium/ui/accessibility/ax_node_position.h b/chromium/ui/accessibility/ax_node_position.h index a7640bfcfcb..ec8d7715b3e 100644 --- a/chromium/ui/accessibility/ax_node_position.h +++ b/chromium/ui/accessibility/ax_node_position.h @@ -10,6 +10,7 @@ #include <vector> #include "base/strings/string16.h" +#include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_position.h" diff --git a/chromium/ui/accessibility/ax_node_position_unittest.cc b/chromium/ui/accessibility/ax_node_position_unittest.cc index 326c7ce5191..243e7f883f7 100644 --- a/chromium/ui/accessibility/ax_node_position_unittest.cc +++ b/chromium/ui/accessibility/ax_node_position_unittest.cc @@ -14,7 +14,7 @@ #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_node_position.h" @@ -115,71 +115,78 @@ void AXPositionTest::SetUp() { static_text2_.id = STATIC_TEXT2_ID; inline_box2_.id = INLINE_BOX2_ID; - root_.role = AX_ROLE_DIALOG; - root_.AddState(AX_STATE_FOCUSABLE); + root_.role = ax::mojom::Role::kDialog; + root_.AddState(ax::mojom::State::kFocusable); root_.SetName(std::string("ButtonCheck box") + TEXT_VALUE); root_.location = gfx::RectF(0, 0, 800, 600); - button_.role = AX_ROLE_BUTTON; - button_.AddState(AX_STATE_HASPOPUP); + button_.role = ax::mojom::Role::kButton; + button_.AddState(ax::mojom::State::kHaspopup); button_.SetName("Button"); button_.location = gfx::RectF(20, 20, 200, 30); - button_.AddIntListAttribute(AX_ATTR_WORD_STARTS, std::vector<int32_t>{0}); - button_.AddIntListAttribute(AX_ATTR_WORD_ENDS, std::vector<int32_t>{6}); - button_.AddIntAttribute(AX_ATTR_NEXT_ON_LINE_ID, check_box_.id); + button_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, + std::vector<int32_t>{0}); + button_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, + std::vector<int32_t>{6}); + button_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId, + check_box_.id); root_.child_ids.push_back(button_.id); - check_box_.role = AX_ROLE_CHECK_BOX; - check_box_.AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, - ui::AX_CHECKED_STATE_TRUE); + check_box_.role = ax::mojom::Role::kCheckBox; + check_box_.SetCheckedState(ax::mojom::CheckedState::kTrue); check_box_.SetName("Check box"); check_box_.location = gfx::RectF(20, 50, 200, 30); - check_box_.AddIntListAttribute(AX_ATTR_WORD_STARTS, + check_box_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0, 6}); - check_box_.AddIntListAttribute(AX_ATTR_WORD_ENDS, std::vector<int32_t>{5, 9}); - check_box_.AddIntAttribute(AX_ATTR_PREVIOUS_ON_LINE_ID, button_.id); + check_box_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, + std::vector<int32_t>{5, 9}); + check_box_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId, + button_.id); root_.child_ids.push_back(check_box_.id); - text_field_.role = AX_ROLE_TEXT_FIELD; - text_field_.AddState(AX_STATE_EDITABLE); + text_field_.role = ax::mojom::Role::kTextField; + text_field_.AddState(ax::mojom::State::kEditable); text_field_.SetValue(TEXT_VALUE); - text_field_.AddIntListAttribute(AX_ATTR_CACHED_LINE_STARTS, - std::vector<int32_t>{0, 7}); + text_field_.AddIntListAttribute( + ax::mojom::IntListAttribute::kCachedLineStarts, + std::vector<int32_t>{0, 7}); text_field_.child_ids.push_back(static_text1_.id); text_field_.child_ids.push_back(line_break_.id); text_field_.child_ids.push_back(static_text2_.id); root_.child_ids.push_back(text_field_.id); - static_text1_.role = AX_ROLE_STATIC_TEXT; - static_text1_.AddState(AX_STATE_EDITABLE); + static_text1_.role = ax::mojom::Role::kStaticText; + static_text1_.AddState(ax::mojom::State::kEditable); static_text1_.SetName("Line 1"); static_text1_.child_ids.push_back(inline_box1_.id); - inline_box1_.role = AX_ROLE_INLINE_TEXT_BOX; - inline_box1_.AddState(AX_STATE_EDITABLE); + inline_box1_.role = ax::mojom::Role::kInlineTextBox; + inline_box1_.AddState(ax::mojom::State::kEditable); inline_box1_.SetName("Line 1"); - inline_box1_.AddIntListAttribute(AX_ATTR_WORD_STARTS, + inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0, 5}); - inline_box1_.AddIntListAttribute(AX_ATTR_WORD_ENDS, + inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, std::vector<int32_t>{4, 6}); - inline_box1_.AddIntAttribute(AX_ATTR_NEXT_ON_LINE_ID, line_break_.id); + inline_box1_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId, + line_break_.id); - line_break_.role = AX_ROLE_LINE_BREAK; - line_break_.AddState(AX_STATE_EDITABLE); + line_break_.role = ax::mojom::Role::kLineBreak; + line_break_.AddState(ax::mojom::State::kEditable); line_break_.SetName("\n"); - line_break_.AddIntAttribute(AX_ATTR_PREVIOUS_ON_LINE_ID, inline_box1_.id); + line_break_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId, + inline_box1_.id); - static_text2_.role = AX_ROLE_STATIC_TEXT; - static_text2_.AddState(AX_STATE_EDITABLE); + static_text2_.role = ax::mojom::Role::kStaticText; + static_text2_.AddState(ax::mojom::State::kEditable); static_text2_.SetName("Line 2"); static_text2_.child_ids.push_back(inline_box2_.id); - inline_box2_.role = AX_ROLE_INLINE_TEXT_BOX; - inline_box2_.AddState(AX_STATE_EDITABLE); + inline_box2_.role = ax::mojom::Role::kInlineTextBox; + inline_box2_.AddState(ax::mojom::State::kEditable); inline_box2_.SetName("Line 2"); - inline_box2_.AddIntListAttribute(AX_ATTR_WORD_STARTS, + inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0, 5}); - inline_box2_.AddIntListAttribute(AX_ATTR_WORD_ENDS, + inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds, std::vector<int32_t>{4, 6}); AXTreeUpdate initial_state; @@ -243,25 +250,25 @@ TEST_F(AXPositionTest, Clone) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); copy_position = text_position->Clone(); ASSERT_NE(nullptr, copy_position); EXPECT_TRUE(copy_position->IsTextPosition()); EXPECT_EQ(text_field_.id, copy_position->anchor_id()); EXPECT_EQ(1, copy_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_UPSTREAM, copy_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, copy_position->affinity()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); copy_position = text_position->Clone(); ASSERT_NE(nullptr, copy_position); EXPECT_TRUE(copy_position->IsTextPosition()); EXPECT_EQ(text_field_.id, copy_position->anchor_id()); EXPECT_EQ(1, copy_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, copy_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, copy_position->affinity()); EXPECT_EQ(AXNodePosition::INVALID_INDEX, copy_position->child_index()); } @@ -303,19 +310,19 @@ TEST_F(AXPositionTest, AtStartOfAnchorWithTreePosition) { TEST_F(AXPositionTest, AtStartOfAnchorWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); EXPECT_TRUE(text_position->AtStartOfAnchor()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtStartOfAnchor()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtStartOfAnchor()); } @@ -346,19 +353,19 @@ TEST_F(AXPositionTest, AtEndOfAnchorWithTreePosition) { TEST_F(AXPositionTest, AtEndOfAnchorWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_TRUE(text_position->AtEndOfAnchor()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtEndOfAnchor()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtEndOfAnchor()); } @@ -368,19 +375,19 @@ TEST_F(AXPositionTest, AtStartOfLineWithTextPosition) { // line break. TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); EXPECT_TRUE(text_position->AtStartOfLine()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtStartOfLine()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtStartOfLine()); @@ -388,7 +395,7 @@ TEST_F(AXPositionTest, AtStartOfLineWithTextPosition) { // as a text position at the start of the next line. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtStartOfLine()); @@ -396,13 +403,13 @@ TEST_F(AXPositionTest, AtStartOfLineWithTextPosition) { // line break. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); EXPECT_TRUE(text_position->AtStartOfLine()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtStartOfLine()); } @@ -410,13 +417,13 @@ TEST_F(AXPositionTest, AtStartOfLineWithTextPosition) { TEST_F(AXPositionTest, AtEndOfLineWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtEndOfLine()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_TRUE(text_position->AtEndOfLine()); @@ -424,7 +431,7 @@ TEST_F(AXPositionTest, AtEndOfLineWithTextPosition) { // same as a text position at the end of the previous line. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_TRUE(text_position->AtEndOfLine()); @@ -432,19 +439,19 @@ TEST_F(AXPositionTest, AtEndOfLineWithTextPosition) { // marked as the end of the line. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtEndOfLine()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_FALSE(text_position->AtEndOfLine()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); EXPECT_TRUE(text_position->AtEndOfLine()); } @@ -471,11 +478,11 @@ TEST_F(AXPositionTest, LowestCommonAncestor) { ASSERT_NE(nullptr, static_text2_position); TestPositionType inline_box1_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, inline_box1_position); TestPositionType inline_box2_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, inline_box2_position); TestPositionType test_position = @@ -556,7 +563,7 @@ TEST_F(AXPositionTest, AsTreePositionWithTextPosition) { // Create a text position pointing to the last character in the text field. TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 12 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->AsTreePosition(); ASSERT_NE(nullptr, test_position); @@ -572,7 +579,7 @@ TEST_F(AXPositionTest, AsTreePositionWithTextPosition) { // Test for a "before text" position. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsTreePosition(); ASSERT_NE(nullptr, test_position); @@ -585,7 +592,7 @@ TEST_F(AXPositionTest, AsTreePositionWithTextPosition) { // Test for an "after text" position. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsTreePosition(); ASSERT_NE(nullptr, test_position); @@ -649,7 +656,7 @@ TEST_F(AXPositionTest, AsTextPositionWithTreePosition) { TEST_F(AXPositionTest, AsTextPositionWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->AsTextPosition(); ASSERT_NE(nullptr, test_position); @@ -657,7 +664,7 @@ TEST_F(AXPositionTest, AsTextPositionWithTextPosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(text_field_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); EXPECT_EQ(AXNodePosition::INVALID_INDEX, test_position->child_index()); } @@ -681,7 +688,7 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTreePosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); // Create a tree position pointing to the line break node inside the text // field. @@ -694,7 +701,7 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTreePosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(line_break_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); // Create a text position pointing to the second static text node inside the // text field. @@ -707,7 +714,7 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTreePosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); } TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { @@ -715,7 +722,7 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { // position). TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, root_.id, 28 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -723,11 +730,11 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); EXPECT_EQ(6, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -735,11 +742,11 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -749,7 +756,7 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(1, test_position->text_offset()); // Even though upstream affinity doesn't make sense on a leaf node, there is // no need to reset it to downstream. - EXPECT_EQ(AX_TEXT_AFFINITY_UPSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity()); // Create a text position on the root, pointing to the line break character // inside the text field but with an upstream affinity which will cause the @@ -757,7 +764,7 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { // box. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, root_.id, 21 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -767,14 +774,14 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(6, test_position->text_offset()); // Even though upstream affinity doesn't make sense on a leaf node, there is // no need to reset it to downstream. - EXPECT_EQ(AX_TEXT_AFFINITY_UPSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity()); // Create a text position pointing to the line break character inside the text // field but with an upstream affinity which will cause the leaf text position // to be placed after the text of the first inline text box. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -784,13 +791,13 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(6, test_position->text_offset()); // Even though upstream affinity doesn't make sense on a leaf node, there is // no need to reset it to downstream. - EXPECT_EQ(AX_TEXT_AFFINITY_UPSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity()); // Create a text position on the root, pointing to the line break character // inside the text field. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, root_.id, 21 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -798,13 +805,13 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(line_break_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); // Create a text position pointing to the line break character inside the text // field. text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -812,13 +819,13 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(line_break_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); // Create a text position pointing to the offset after the last character in // the text field, (an "after text" position). text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 13 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->AsLeafTextPosition(); ASSERT_NE(nullptr, test_position); @@ -826,7 +833,7 @@ TEST_F(AXPositionTest, AsLeafTextPositionWithTextPosition) { EXPECT_EQ(tree_.data().tree_id, test_position->tree_id()); EXPECT_EQ(inline_box2_.id, test_position->anchor_id()); EXPECT_EQ(6, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); } TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithNullPosition) { @@ -872,7 +879,7 @@ TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTreePosition) { TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->CreatePositionAtStartOfAnchor(); @@ -880,11 +887,11 @@ TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTextPosition) { EXPECT_TRUE(test_position->IsTextPosition()); EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreatePositionAtStartOfAnchor(); EXPECT_NE(nullptr, test_position); @@ -892,7 +899,7 @@ TEST_F(AXPositionTest, CreatePositionAtStartOfAnchorWithTextPosition) { EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); // Affinity should have been reset to the default value. - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); } TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithNullPosition) { @@ -926,18 +933,18 @@ TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithTreePosition) { TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->CreatePositionAtEndOfAnchor(); EXPECT_NE(nullptr, test_position); EXPECT_TRUE(test_position->IsTextPosition()); EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); EXPECT_EQ(6, test_position->text_offset()); - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreatePositionAtEndOfAnchor(); EXPECT_NE(nullptr, test_position); @@ -945,7 +952,7 @@ TEST_F(AXPositionTest, CreatePositionAtEndOfAnchorWithTextPosition) { EXPECT_EQ(inline_box1_.id, test_position->anchor_id()); EXPECT_EQ(6, test_position->text_offset()); // Affinity should have been reset to the default value. - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); } TEST_F(AXPositionTest, CreateChildPositionAtWithNullPosition) { @@ -979,7 +986,7 @@ TEST_F(AXPositionTest, CreateChildPositionAtWithTreePosition) { TEST_F(AXPositionTest, CreateChildPositionAtWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, static_text1_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->CreateChildPositionAt(0); EXPECT_NE(nullptr, test_position); @@ -989,7 +996,7 @@ TEST_F(AXPositionTest, CreateChildPositionAtWithTextPosition) { text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, static_text2_.id, 4 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreateChildPositionAt(1); EXPECT_NE(nullptr, test_position); @@ -1026,7 +1033,7 @@ TEST_F(AXPositionTest, CreateParentPositionWithTreePosition) { TEST_F(AXPositionTest, CreateParentPositionWithTextPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->CreateParentPosition(); EXPECT_NE(nullptr, test_position); @@ -1072,7 +1079,7 @@ TEST_F(AXPositionTest, CreateNextTextAnchorPosition) { // box. check_box_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, root_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, check_box_position); test_position = check_box_position->CreateNextTextAnchorPosition(); EXPECT_NE(nullptr, test_position); @@ -1083,7 +1090,7 @@ TEST_F(AXPositionTest, CreateNextTextAnchorPosition) { TestPositionType button_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, button_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, button_position); test_position = button_position->CreateNextTextAnchorPosition(); EXPECT_NE(nullptr, test_position); @@ -1131,7 +1138,7 @@ TEST_F(AXPositionTest, CreateNextTextAnchorPosition) { TEST_F(AXPositionTest, CreatePreviousTextAnchorPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->CreatePreviousTextAnchorPosition(); @@ -1191,7 +1198,7 @@ TEST_F(AXPositionTest, CreatePreviousTextAnchorPosition) { // box. TestPositionType check_box_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, check_box_.id, 6 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, check_box_position); test_position = check_box_position->CreatePreviousTextAnchorPosition(); EXPECT_NE(nullptr, test_position); @@ -1217,7 +1224,7 @@ TEST_F(AXPositionTest, CreateNextAndPreviousCharacterPositionWithNullPosition) { TEST_F(AXPositionTest, CreateNextCharacterPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 4 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->CreateNextCharacterPosition( AXBoundaryBehavior::CrossBoundary); @@ -1228,7 +1235,7 @@ TEST_F(AXPositionTest, CreateNextCharacterPosition) { text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreateNextCharacterPosition( AXBoundaryBehavior::StopAtAnchorBoundary); @@ -1265,7 +1272,7 @@ TEST_F(AXPositionTest, CreateNextCharacterPosition) { text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, check_box_.id, 9 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreateNextCharacterPosition( AXBoundaryBehavior::StopAtAnchorBoundary); @@ -1282,7 +1289,7 @@ TEST_F(AXPositionTest, CreateNextCharacterPosition) { text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreateNextCharacterPosition( AXBoundaryBehavior::CrossBoundary); @@ -1291,13 +1298,13 @@ TEST_F(AXPositionTest, CreateNextCharacterPosition) { EXPECT_EQ(text_field_.id, test_position->anchor_id()); EXPECT_EQ(1, test_position->text_offset()); // Affinity should have been reset to downstream. - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); } TEST_F(AXPositionTest, CreatePreviousCharacterPosition) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); TestPositionType test_position = text_position->CreatePreviousCharacterPosition( @@ -1309,7 +1316,7 @@ TEST_F(AXPositionTest, CreatePreviousCharacterPosition) { text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreatePreviousCharacterPosition( AXBoundaryBehavior::StopAtAnchorBoundary); @@ -1346,7 +1353,7 @@ TEST_F(AXPositionTest, CreatePreviousCharacterPosition) { text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreatePreviousCharacterPosition( AXBoundaryBehavior::StopAtAnchorBoundary); @@ -1363,7 +1370,7 @@ TEST_F(AXPositionTest, CreatePreviousCharacterPosition) { text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position); test_position = text_position->CreatePreviousCharacterPosition( AXBoundaryBehavior::CrossBoundary); @@ -1372,7 +1379,7 @@ TEST_F(AXPositionTest, CreatePreviousCharacterPosition) { EXPECT_EQ(text_field_.id, test_position->anchor_id()); EXPECT_EQ(0, test_position->text_offset()); // Affinity should have been reset to downstream. - EXPECT_EQ(AX_TEXT_AFFINITY_DOWNSTREAM, test_position->affinity()); + EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity()); } TEST_F(AXPositionTest, CreateNextAndPreviousWordStartPositionWithNullPosition) { @@ -1459,46 +1466,46 @@ TEST_F(AXPositionTest, OperatorEquals) { // positions. TestPositionType text_position1 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 15 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position1); TestPositionType text_position2 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, text_field_.id, -1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position2); EXPECT_EQ(*text_position1, *text_position2); text_position1 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position1); text_position2 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position2); EXPECT_EQ(*text_position1, *text_position2); // Affinities should match. text_position2 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position2); EXPECT_NE(*text_position1, *text_position2); // Text offsets should match. text_position1 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 5 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position1); EXPECT_NE(*text_position1, *text_position2); // Two "after text" positions on the same node should be equivalent. text_position1 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position1); text_position2 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position2); EXPECT_EQ(*text_position1, *text_position2); } @@ -1543,11 +1550,11 @@ TEST_F(AXPositionTest, OperatorsLessThanAndGreaterThan) { TestPositionType text_position1 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 2 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position1); TestPositionType text_position2 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); ASSERT_NE(nullptr, text_position2); EXPECT_GT(*text_position1, *text_position2); EXPECT_LT(*text_position2, *text_position1); @@ -1555,7 +1562,7 @@ TEST_F(AXPositionTest, OperatorsLessThanAndGreaterThan) { // Affinities should not matter. text_position2 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position2); EXPECT_GT(*text_position1, *text_position2); EXPECT_LT(*text_position2, *text_position1); @@ -1563,12 +1570,12 @@ TEST_F(AXPositionTest, OperatorsLessThanAndGreaterThan) { // An "after text" position. text_position1 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 1 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position1); // A "before text" position. text_position2 = AXNodePosition::CreateTextPosition( tree_.data().tree_id, line_break_.id, 0 /* text_offset */, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); ASSERT_NE(nullptr, text_position2); EXPECT_GT(*text_position1, *text_position2); EXPECT_LT(*text_position2, *text_position1); @@ -1581,7 +1588,7 @@ TEST_F(AXPositionTest, OperatorsLessThanAndGreaterThan) { TEST_P(AXPositionTestWithParam, TraverseTreeStartingWithAffinityDownstream) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, GetParam().start_node_id_, GetParam().start_offset_, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); for (const std::string& expectation : GetParam().expectations) { text_position = GetParam().TestMethod.Run(text_position); EXPECT_NE(nullptr, text_position); @@ -1592,7 +1599,7 @@ TEST_P(AXPositionTestWithParam, TraverseTreeStartingWithAffinityDownstream) { TEST_P(AXPositionTestWithParam, TraverseTreeStartingWithAffinityUpstream) { TestPositionType text_position = AXNodePosition::CreateTextPosition( tree_.data().tree_id, GetParam().start_node_id_, GetParam().start_offset_, - AX_TEXT_AFFINITY_UPSTREAM); + ax::mojom::TextAffinity::kUpstream); for (const std::string& expectation : GetParam().expectations) { text_position = GetParam().TestMethod.Run(text_position); EXPECT_NE(nullptr, text_position); @@ -3015,7 +3022,7 @@ TEST_F(AXPositionTest, AXRangeGetTextWithWholeObjects) { tree_.data().tree_id, root_.id, 0 /* child_index */); TestPositionType end = AXNodePosition::CreateTextPosition( tree_.data().tree_id, root_.id, 28 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); AXRange<AXPosition<AXNodePosition, AXNode>> forward_range(start->Clone(), end->Clone()); EXPECT_EQ(all_text, forward_range.GetText()); @@ -3030,10 +3037,10 @@ TEST_F(AXPositionTest, AXRangeGetTextWithTextOffsets) { // ending two characters before the end of the root. TestPositionType start = AXNodePosition::CreateTextPosition( tree_.data().tree_id, button_.id, 3 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); TestPositionType end = AXNodePosition::CreateTextPosition( tree_.data().tree_id, static_text2_.id, 4 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); AXRange<AXPosition<AXNodePosition, AXNode>> forward_range(start->Clone(), end->Clone()); EXPECT_EQ(most_text, forward_range.GetText()); diff --git a/chromium/ui/accessibility/ax_position.h b/chromium/ui/accessibility/ax_position.h index 8c263dff3b3..e3ed7ee6a46 100644 --- a/chromium/ui/accessibility/ax_position.h +++ b/chromium/ui/accessibility/ax_position.h @@ -17,7 +17,8 @@ #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enum_util.h" +#include "ui/accessibility/ax_enums.mojom.h" namespace ui { @@ -94,7 +95,7 @@ class AXPosition { AXPositionInstance new_position(new AXPositionType()); new_position->Initialize(AXPositionKind::NULL_POSITION, INVALID_TREE_ID, INVALID_ANCHOR_ID, INVALID_INDEX, INVALID_OFFSET, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); return new_position; } @@ -104,14 +105,15 @@ class AXPosition { AXPositionInstance new_position(new AXPositionType()); new_position->Initialize(AXPositionKind::TREE_POSITION, tree_id, anchor_id, child_index, INVALID_OFFSET, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); return new_position; } - static AXPositionInstance CreateTextPosition(int tree_id, - int32_t anchor_id, - int text_offset, - AXTextAffinity affinity) { + static AXPositionInstance CreateTextPosition( + int tree_id, + int32_t anchor_id, + int text_offset, + ax::mojom::TextAffinity affinity) { AXPositionInstance new_position(new AXPositionType()); new_position->Initialize(AXPositionKind::TEXT_POSITION, tree_id, anchor_id, INVALID_INDEX, text_offset, affinity); @@ -150,9 +152,9 @@ class AXPosition { str_text_offset = base::IntToString(text_offset_); } str = "TextPosition tree_id=" + base::IntToString(tree_id_) + - " anchor_id=" + base::IntToString(anchor_id_) + " text_offset=" + - str_text_offset + " affinity=" + - ui::ToString(static_cast<AXTextAffinity>(affinity_)); + " anchor_id=" + base::IntToString(anchor_id_) + + " text_offset=" + str_text_offset + " affinity=" + + ui::ToString(static_cast<ax::mojom::TextAffinity>(affinity_)); break; } } @@ -188,7 +190,7 @@ class AXPosition { AXPositionKind kind() const { return kind_; } int child_index() const { return child_index_; } int text_offset() const { return text_offset_; } - AXTextAffinity affinity() const { return affinity_; } + ax::mojom::TextAffinity affinity() const { return affinity_; } bool IsNullPosition() const { return kind_ == AXPositionKind::NULL_POSITION || !GetAnchor(); @@ -376,7 +378,7 @@ class AXPosition { int child_length = child->MaxTextOffsetInParent(); if (copy->text_offset_ >= current_offset && (copy->text_offset_ < (current_offset + child_length) || - (copy->affinity_ == AX_TEXT_AFFINITY_UPSTREAM && + (copy->affinity_ == ax::mojom::TextAffinity::kUpstream && copy->text_offset_ == (current_offset + child_length)))) { copy->child_index_ = i; break; @@ -474,7 +476,7 @@ class AXPosition { return CreateTreePosition(tree_id_, anchor_id_, 0 /* child_index */); case AXPositionKind::TEXT_POSITION: return CreateTextPosition(tree_id_, anchor_id_, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); } return CreateNullPosition(); } @@ -487,7 +489,7 @@ class AXPosition { return CreateTreePosition(tree_id_, anchor_id_, AnchorChildCount()); case AXPositionKind::TEXT_POSITION: return CreateTextPosition(tree_id_, anchor_id_, MaxTextOffset(), - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); } return CreateNullPosition(); } @@ -519,7 +521,7 @@ class AXPosition { } case AXPositionKind::TEXT_POSITION: return CreateTextPosition(tree_id, child_id, 0 /* text_offset */, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); } return CreateNullPosition(); @@ -547,12 +549,12 @@ class AXPosition { // before or after the child and we don't maintain the affinity when the // position is after the child. int parent_offset = AnchorTextOffsetInParent(); - AXTextAffinity parent_affinity = affinity_; + ax::mojom::TextAffinity parent_affinity = affinity_; if (MaxTextOffset() == MaxTextOffsetInParent()) { parent_offset += text_offset_; } else if (text_offset_ > 0) { parent_offset += MaxTextOffsetInParent(); - parent_affinity = AX_TEXT_AFFINITY_DOWNSTREAM; + parent_affinity = ax::mojom::TextAffinity::kDownstream; } return CreateTextPosition(tree_id, parent_id, parent_offset, parent_affinity); @@ -606,7 +608,7 @@ class AXPosition { text_position->text_offset_ += 1; // Even if our affinity was upstream, moving to the next character should // inevitably reset it to downstream. - text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + text_position->affinity_ = ax::mojom::TextAffinity::kDownstream; } else { // Moving to the end of the current anchor first is essential. Otherwise // |CreateNextAnchorPosition| might return our deepest left-most child @@ -639,7 +641,7 @@ class AXPosition { text_position->text_offset_ -= 1; // Even if the new position is at the beginning of the line, the affinity // is defaulted to downstream for simplicity. - text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + text_position->affinity_ = ax::mojom::TextAffinity::kDownstream; } else { text_position = text_position->CreatePreviousTextAnchorPosition(); text_position = text_position->CreatePositionAtEndOfAnchor(); @@ -661,7 +663,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtStartOfWord()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -689,7 +691,7 @@ class AXPosition { text_position->text_offset_ = static_cast<int>(updated_word_starts[0]); } else { text_position->text_offset_ = static_cast<int>(*iterator); - text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + text_position->affinity_ = ax::mojom::TextAffinity::kDownstream; } // If the word boundary is in the same subtree, return a position rooted @@ -716,7 +718,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtStartOfWord()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -755,7 +757,7 @@ class AXPosition { static_cast<int>(*(updated_word_starts.end() - 1)); } else { text_position->text_offset_ = static_cast<int>(*(--iterator)); - text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + text_position->affinity_ = ax::mojom::TextAffinity::kDownstream; } // If the word boundary is in the same subtree, return a position rooted @@ -783,7 +785,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtEndOfWord()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -818,7 +820,7 @@ class AXPosition { text_position->text_offset_ = static_cast<int>(updated_word_ends[0]); } else { text_position->text_offset_ = static_cast<int>(*iterator); - text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + text_position->affinity_ = ax::mojom::TextAffinity::kDownstream; } // If the word boundary is in the same subtree, return a position rooted @@ -846,7 +848,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtEndOfWord()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -884,7 +886,7 @@ class AXPosition { static_cast<int>(*(updated_word_ends.end() - 1)); } else { text_position->text_offset_ = static_cast<int>(*(--iterator)); - text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + text_position->affinity_ = ax::mojom::TextAffinity::kDownstream; } // If the word boundary is in the same subtree, return a position rooted @@ -913,7 +915,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtStartOfLine()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -951,7 +953,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtStartOfLine()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -997,7 +999,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtEndOfLine()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -1048,7 +1050,7 @@ class AXPosition { if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary && text_position->AtEndOfLine()) { AXPositionInstance clone = Clone(); - clone->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + clone->affinity_ = ax::mojom::TextAffinity::kDownstream; return clone; } @@ -1100,7 +1102,7 @@ class AXPosition { int32_t anchor_id, int child_index, int text_offset, - AXTextAffinity affinity) { + ax::mojom::TextAffinity affinity) { kind_ = kind; tree_id_ = tree_id; anchor_id_ = anchor_id; @@ -1120,7 +1122,7 @@ class AXPosition { anchor_id_ = INVALID_ANCHOR_ID; child_index_ = INVALID_INDEX; text_offset_ = INVALID_OFFSET; - affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; + affinity_ = ax::mojom::TextAffinity::kDownstream; } } @@ -1241,7 +1243,7 @@ class AXPosition { // TODO(nektar): Get rid of affinity and make Blink handle affinity // internally since inline text objects don't span lines. - AXTextAffinity affinity_; + ax::mojom::TextAffinity affinity_; }; template <class AXPositionType, class AXNodeType> diff --git a/chromium/ui/accessibility/ax_role_properties.cc b/chromium/ui/accessibility/ax_role_properties.cc index 7540c674cb6..02235b33af3 100644 --- a/chromium/ui/accessibility/ax_role_properties.cc +++ b/chromium/ui/accessibility/ax_role_properties.cc @@ -3,141 +3,167 @@ // found in the LICENSE file. #include "ui/accessibility/ax_role_properties.h" +#include "build/build_config.h" namespace ui { -bool IsRoleClickable(AXRole role) { +namespace { +#if defined(OS_WIN) +static bool kExposeLayoutTableAsDataTable = true; +#else +static bool kExposeLayoutTableAsDataTable = false; +#endif +} // namespace + +bool IsRoleClickable(ax::mojom::Role role) { + switch (role) { + case ax::mojom::Role::kButton: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kColorWell: + case ax::mojom::Role::kDisclosureTriangle: + case ax::mojom::Role::kLink: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kMenuListPopup: + case ax::mojom::Role::kPopUpButton: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kTab: + case ax::mojom::Role::kToggleButton: + return true; + default: + return false; + } +} + +bool IsDocument(ax::mojom::Role role) { switch (role) { - case AX_ROLE_BUTTON: - case AX_ROLE_CHECK_BOX: - case AX_ROLE_COLOR_WELL: - case AX_ROLE_DISCLOSURE_TRIANGLE: - case AX_ROLE_LINK: - case AX_ROLE_LIST_BOX_OPTION: - case AX_ROLE_MENU_BUTTON: - case AX_ROLE_MENU_ITEM: - case AX_ROLE_MENU_ITEM_CHECK_BOX: - case AX_ROLE_MENU_ITEM_RADIO: - case AX_ROLE_MENU_LIST_OPTION: - case AX_ROLE_MENU_LIST_POPUP: - case AX_ROLE_POP_UP_BUTTON: - case AX_ROLE_RADIO_BUTTON: - case AX_ROLE_SWITCH: - case AX_ROLE_TAB: - case AX_ROLE_TOGGLE_BUTTON: + case ax::mojom::Role::kRootWebArea: + case ax::mojom::Role::kWebArea: return true; default: return false; } } -bool IsDocument(ui::AXRole role) { +bool IsCellOrTableHeaderRole(ax::mojom::Role role) { switch (role) { - case ui::AX_ROLE_ROOT_WEB_AREA: - case ui::AX_ROLE_WEB_AREA: + case ax::mojom::Role::kCell: + case ax::mojom::Role::kColumnHeader: + case ax::mojom::Role::kRowHeader: return true; + case ax::mojom::Role::kLayoutTableCell: + return kExposeLayoutTableAsDataTable; default: return false; } } -bool IsCellOrTableHeaderRole(ui::AXRole role) { +bool IsTableLikeRole(ax::mojom::Role role) { switch (role) { - case ui::AX_ROLE_CELL: - case ui::AX_ROLE_COLUMN_HEADER: - case ui::AX_ROLE_ROW_HEADER: + case ax::mojom::Role::kTable: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kTreeGrid: return true; + case ax::mojom::Role::kLayoutTable: + return kExposeLayoutTableAsDataTable; default: return false; } } -bool IsTableLikeRole(ui::AXRole role) { +bool IsContainerWithSelectableChildrenRole(ax::mojom::Role role) { switch (role) { - case ui::AX_ROLE_TABLE: - case ui::AX_ROLE_GRID: - case ui::AX_ROLE_TREE_GRID: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kRadioGroup: + case ax::mojom::Role::kTabList: + case ax::mojom::Role::kToolbar: + case ax::mojom::Role::kTree: + case ax::mojom::Role::kTreeGrid: return true; default: return false; } } -bool IsContainerWithSelectableChildrenRole(ui::AXRole role) { +bool IsRowContainer(ax::mojom::Role role) { switch (role) { - case ui::AX_ROLE_COMBO_BOX_GROUPING: - case ui::AX_ROLE_COMBO_BOX_MENU_BUTTON: - case ui::AX_ROLE_GRID: - case ui::AX_ROLE_LIST_BOX: - case ui::AX_ROLE_MENU: - case ui::AX_ROLE_MENU_BAR: - case ui::AX_ROLE_RADIO_GROUP: - case ui::AX_ROLE_TAB_LIST: - case ui::AX_ROLE_TOOLBAR: - case ui::AX_ROLE_TREE: - case ui::AX_ROLE_TREE_GRID: + case ax::mojom::Role::kTree: + case ax::mojom::Role::kTreeGrid: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kTable: return true; default: return false; } } -bool IsRowContainer(ui::AXRole role) { +bool IsControl(ax::mojom::Role role) { switch (role) { - case ui::AX_ROLE_TREE: - case ui::AX_ROLE_TREE_GRID: - case ui::AX_ROLE_GRID: - case ui::AX_ROLE_TABLE: + case ax::mojom::Role::kButton: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kColorWell: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kDisclosureTriangle: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kMenuListPopup: + case ax::mojom::Role::kPopUpButton: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSearchBox: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSpinButton: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kTab: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kToggleButton: + case ax::mojom::Role::kTree: return true; default: return false; } } -bool IsControl(ui::AXRole role) { +bool IsMenuRelated(ax::mojom::Role role) { switch (role) { - case ui::AX_ROLE_BUTTON: - case ui::AX_ROLE_CHECK_BOX: - case ui::AX_ROLE_COLOR_WELL: - case ui::AX_ROLE_COMBO_BOX_MENU_BUTTON: - case ui::AX_ROLE_DISCLOSURE_TRIANGLE: - case ui::AX_ROLE_LIST_BOX: - case ui::AX_ROLE_MENU: - case ui::AX_ROLE_MENU_BAR: - case ui::AX_ROLE_MENU_BUTTON: - case ui::AX_ROLE_MENU_ITEM: - case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: - case ui::AX_ROLE_MENU_ITEM_RADIO: - case ui::AX_ROLE_MENU_LIST_OPTION: - case ui::AX_ROLE_MENU_LIST_POPUP: - case ui::AX_ROLE_POP_UP_BUTTON: - case ui::AX_ROLE_RADIO_BUTTON: - case ui::AX_ROLE_SCROLL_BAR: - case ui::AX_ROLE_SEARCH_BOX: - case ui::AX_ROLE_SLIDER: - case ui::AX_ROLE_SPIN_BUTTON: - case ui::AX_ROLE_SWITCH: - case ui::AX_ROLE_TAB: - case ui::AX_ROLE_TEXT_FIELD: - case ui::AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX: - case ui::AX_ROLE_TOGGLE_BUTTON: - case ui::AX_ROLE_TREE: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kMenuBar: + case ax::mojom::Role::kMenuButton: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kMenuListPopup: return true; default: return false; } } -bool IsMenuRelated(ui::AXRole role) { +bool IsImage(ax::mojom::Role role) { switch (role) { - case ui::AX_ROLE_MENU: - case ui::AX_ROLE_MENU_BAR: - case ui::AX_ROLE_MENU_BUTTON: - case ui::AX_ROLE_MENU_ITEM: - case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: - case ui::AX_ROLE_MENU_ITEM_RADIO: - case ui::AX_ROLE_MENU_LIST_OPTION: - case ui::AX_ROLE_MENU_LIST_POPUP: + case ax::mojom::Role::kCanvas: + case ax::mojom::Role::kImageMap: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kSvgRoot: + case ax::mojom::Role::kVideo: return true; default: return false; diff --git a/chromium/ui/accessibility/ax_role_properties.h b/chromium/ui/accessibility/ax_role_properties.h index 81893bcf87c..9b1793eeda6 100644 --- a/chromium/ui/accessibility/ax_role_properties.h +++ b/chromium/ui/accessibility/ax_role_properties.h @@ -5,35 +5,38 @@ #ifndef UI_ACCESSIBILITY_AX_ROLE_PROPERTIES_H_ #define UI_ACCESSIBILITY_AX_ROLE_PROPERTIES_H_ -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" namespace ui { // Checks if the given role should belong to a control that can respond to // clicks. -AX_EXPORT bool IsRoleClickable(AXRole role); +AX_EXPORT bool IsRoleClickable(ax::mojom::Role role); // Returns true if this node is a document -AX_EXPORT bool IsDocument(ui::AXRole role); +AX_EXPORT bool IsDocument(ax::mojom::Role role); // Returns true if this node is a cell or a table header. -AX_EXPORT bool IsCellOrTableHeaderRole(AXRole role); +AX_EXPORT bool IsCellOrTableHeaderRole(ax::mojom::Role role); // Returns true if this node is a table, a grid or a treegrid. -AX_EXPORT bool IsTableLikeRole(AXRole role); +AX_EXPORT bool IsTableLikeRole(ax::mojom::Role role); // Returns true if this node is a container with selectable children. -AX_EXPORT bool IsContainerWithSelectableChildrenRole(ui::AXRole role); +AX_EXPORT bool IsContainerWithSelectableChildrenRole(ax::mojom::Role role); // Returns true if this node is a row container. -AX_EXPORT bool IsRowContainer(ui::AXRole role); +AX_EXPORT bool IsRowContainer(ax::mojom::Role role); // Returns true if this node is a control. -AX_EXPORT bool IsControl(ui::AXRole role); +AX_EXPORT bool IsControl(ax::mojom::Role role); // Returns true if this node is a menu or related role. -AX_EXPORT bool IsMenuRelated(ui::AXRole role); +AX_EXPORT bool IsMenuRelated(ax::mojom::Role role); + +// Returns true if it's an image, graphic, canvas, etc. +AX_EXPORT bool IsImage(ax::mojom::Role role); } // namespace ui diff --git a/chromium/ui/accessibility/ax_text_utils.cc b/chromium/ui/accessibility/ax_text_utils.cc index fd0457763f4..d2d9ffef3ad 100644 --- a/chromium/ui/accessibility/ax_text_utils.cc +++ b/chromium/ui/accessibility/ax_text_utils.cc @@ -21,7 +21,7 @@ size_t FindAccessibleTextBoundary(const base::string16& text, TextBoundaryType boundary, size_t start_offset, TextBoundaryDirection direction, - AXTextAffinity affinity) { + ax::mojom::TextAffinity affinity) { size_t text_size = text.size(); DCHECK_LE(start_offset, text_size); @@ -43,20 +43,20 @@ size_t FindAccessibleTextBoundary(const base::string16& text, if (direction == FORWARDS_DIRECTION) { for (size_t j = 0; j < line_breaks.size(); ++j) { size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0; - if ((affinity == AX_TEXT_AFFINITY_DOWNSTREAM && - line_break > start_offset) || - (affinity == AX_TEXT_AFFINITY_UPSTREAM && - line_break >= start_offset)) { - return line_break; + if ((affinity == ax::mojom::TextAffinity::kDownstream && + line_break > start_offset) || + (affinity == ax::mojom::TextAffinity::kUpstream && + line_break >= start_offset)) { + return line_break; } } return text_size; } else { for (size_t j = line_breaks.size(); j != 0; --j) { size_t line_break = line_breaks[j - 1] >= 0 ? line_breaks[j - 1] : 0; - if ((affinity == AX_TEXT_AFFINITY_DOWNSTREAM && + if ((affinity == ax::mojom::TextAffinity::kDownstream && line_break <= start_offset) || - (affinity == AX_TEXT_AFFINITY_UPSTREAM && + (affinity == ax::mojom::TextAffinity::kUpstream && line_break < start_offset)) { return line_break; } @@ -116,27 +116,27 @@ size_t FindAccessibleTextBoundary(const base::string16& text, } base::string16 ActionVerbToLocalizedString( - const AXDefaultActionVerb action_verb) { + const ax::mojom::DefaultActionVerb action_verb) { switch (action_verb) { - case AX_DEFAULT_ACTION_VERB_NONE: + case ax::mojom::DefaultActionVerb::kNone: return base::string16(); - case AX_DEFAULT_ACTION_VERB_ACTIVATE: + case ax::mojom::DefaultActionVerb::kActivate: return l10n_util::GetStringUTF16(IDS_AX_ACTIVATE_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_CHECK: + case ax::mojom::DefaultActionVerb::kCheck: return l10n_util::GetStringUTF16(IDS_AX_CHECK_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_CLICK: + case ax::mojom::DefaultActionVerb::kClick: return l10n_util::GetStringUTF16(IDS_AX_CLICK_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_CLICK_ANCESTOR: + case ax::mojom::DefaultActionVerb::kClickAncestor: return l10n_util::GetStringUTF16(IDS_AX_CLICK_ANCESTOR_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_JUMP: + case ax::mojom::DefaultActionVerb::kJump: return l10n_util::GetStringUTF16(IDS_AX_JUMP_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_OPEN: + case ax::mojom::DefaultActionVerb::kOpen: return l10n_util::GetStringUTF16(IDS_AX_OPEN_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_PRESS: + case ax::mojom::DefaultActionVerb::kPress: return l10n_util::GetStringUTF16(IDS_AX_PRESS_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_SELECT: + case ax::mojom::DefaultActionVerb::kSelect: return l10n_util::GetStringUTF16(IDS_AX_SELECT_ACTION_VERB); - case AX_DEFAULT_ACTION_VERB_UNCHECK: + case ax::mojom::DefaultActionVerb::kUncheck: return l10n_util::GetStringUTF16(IDS_AX_UNCHECK_ACTION_VERB); } NOTREACHED(); @@ -145,27 +145,27 @@ base::string16 ActionVerbToLocalizedString( // Some APIs on Linux and Windows need to return non-localized action names. base::string16 ActionVerbToUnlocalizedString( - const AXDefaultActionVerb action_verb) { + const ax::mojom::DefaultActionVerb action_verb) { switch (action_verb) { - case ui::AX_DEFAULT_ACTION_VERB_NONE: + case ax::mojom::DefaultActionVerb::kNone: return base::UTF8ToUTF16("none"); - case ui::AX_DEFAULT_ACTION_VERB_ACTIVATE: + case ax::mojom::DefaultActionVerb::kActivate: return base::UTF8ToUTF16("activate"); - case ui::AX_DEFAULT_ACTION_VERB_CHECK: + case ax::mojom::DefaultActionVerb::kCheck: return base::UTF8ToUTF16("check"); - case ui::AX_DEFAULT_ACTION_VERB_CLICK: + case ax::mojom::DefaultActionVerb::kClick: return base::UTF8ToUTF16("click"); - case ui::AX_DEFAULT_ACTION_VERB_CLICK_ANCESTOR: + case ax::mojom::DefaultActionVerb::kClickAncestor: return base::UTF8ToUTF16("click-ancestor"); - case ui::AX_DEFAULT_ACTION_VERB_JUMP: + case ax::mojom::DefaultActionVerb::kJump: return base::UTF8ToUTF16("jump"); - case ui::AX_DEFAULT_ACTION_VERB_OPEN: + case ax::mojom::DefaultActionVerb::kOpen: return base::UTF8ToUTF16("open"); - case ui::AX_DEFAULT_ACTION_VERB_PRESS: + case ax::mojom::DefaultActionVerb::kPress: return base::UTF8ToUTF16("press"); - case ui::AX_DEFAULT_ACTION_VERB_SELECT: + case ax::mojom::DefaultActionVerb::kSelect: return base::UTF8ToUTF16("select"); - case ui::AX_DEFAULT_ACTION_VERB_UNCHECK: + case ax::mojom::DefaultActionVerb::kUncheck: return base::UTF8ToUTF16("uncheck"); } NOTREACHED(); diff --git a/chromium/ui/accessibility/ax_text_utils.h b/chromium/ui/accessibility/ax_text_utils.h index 5a4c0717870..3b9a78fdcf8 100644 --- a/chromium/ui/accessibility/ax_text_utils.h +++ b/chromium/ui/accessibility/ax_text_utils.h @@ -10,7 +10,7 @@ #include <vector> #include "base/strings/string16.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" namespace ui { @@ -44,22 +44,21 @@ enum TextBoundaryDirection { // (depending on |direction|) from the given |start_offset| until the // given boundary is found, and return the offset of that boundary, // using the vector of line break character offsets in |line_breaks|. -size_t AX_EXPORT - FindAccessibleTextBoundary(const base::string16& text, - const std::vector<int>& line_breaks, - TextBoundaryType boundary, - size_t start_offset, - TextBoundaryDirection direction, - AXTextAffinity affinity); +size_t AX_EXPORT FindAccessibleTextBoundary(const base::string16& text, + const std::vector<int>& line_breaks, + TextBoundaryType boundary, + size_t start_offset, + TextBoundaryDirection direction, + ax::mojom::TextAffinity affinity); // Returns a string ID that corresponds to the name of the given action. base::string16 AX_EXPORT -ActionVerbToLocalizedString(const AXDefaultActionVerb action_verb); +ActionVerbToLocalizedString(const ax::mojom::DefaultActionVerb action_verb); // Returns the non-localized string representation of a supported action. // Some APIs on Linux and Windows need to return non-localized action names. base::string16 AX_EXPORT -ActionVerbToUnlocalizedString(const AXDefaultActionVerb action_verb); +ActionVerbToUnlocalizedString(const ax::mojom::DefaultActionVerb action_verb); } // namespace ui diff --git a/chromium/ui/accessibility/ax_text_utils_unittest.cc b/chromium/ui/accessibility/ax_text_utils_unittest.cc index 0f1ad1de714..7915cdd24cc 100644 --- a/chromium/ui/accessibility/ax_text_utils_unittest.cc +++ b/chromium/ui/accessibility/ax_text_utils_unittest.cc @@ -6,7 +6,7 @@ #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_text_utils.h" namespace ui { @@ -21,47 +21,47 @@ TEST(AXTextUtils, FindAccessibleTextBoundaryWord) { result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 0, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(6UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 5, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(0UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 6, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(12UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 11, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(6UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 12, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(12UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 15, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(17UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 15, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(12UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 16, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(17UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 17, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(20UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, 20, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(text_length, result); result = FindAccessibleTextBoundary(text, line_start_offsets, WORD_BOUNDARY, text_length, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(20UL, result); } @@ -76,56 +76,56 @@ TEST(AXTextUtils, FindAccessibleTextBoundaryLine) { // Basic cases. result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 5, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(8UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 9, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(8UL, result); result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 10, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // Edge cases. result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, text_length, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // When the start_offset is at the start of the next line and we are searching // backwards, it should not move. result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 15, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // When the start_offset is at a hard line break and we are searching // backwards, it should return the start of the previous line. result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 14, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(8UL, result); // When the start_offset is at the start of a line and we are searching // forwards, it should return the start of the next line. result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 8, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // When there is no previous line break and we are searching backwards, // it should return 0. result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 4, BACKWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(0UL, result); // When we are at the start of the last line and we are searching forwards. // it should return the text length. result = FindAccessibleTextBoundary(text, line_start_offsets, LINE_BOUNDARY, 15, FORWARDS_DIRECTION, - AX_TEXT_AFFINITY_DOWNSTREAM); + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(text_length, result); } diff --git a/chromium/ui/accessibility/ax_tree.cc b/chromium/ui/accessibility/ax_tree.cc index 3758d0b7a1b..b6fe217c0b0 100644 --- a/chromium/ui/accessibility/ax_tree.cc +++ b/chromium/ui/accessibility/ax_tree.cc @@ -219,8 +219,10 @@ gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node, int scroll_x = 0; int scroll_y = 0; - if (container->data().GetIntAttribute(ui::AX_ATTR_SCROLL_X, &scroll_x) && - container->data().GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &scroll_y)) { + if (container->data().GetIntAttribute(ax::mojom::IntAttribute::kScrollX, + &scroll_x) && + container->data().GetIntAttribute(ax::mojom::IntAttribute::kScrollY, + &scroll_y)) { bounds.Offset(-scroll_x, -scroll_y); } @@ -231,7 +233,8 @@ gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node, // Calculate the clipped bounds to determine offscreen state. gfx::RectF clipped = bounds; // If this is the root web area, make sure we clip the node to fit. - if (container->data().GetBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN)) { + if (container->data().GetBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren)) { if (!intersection.IsEmpty()) { // We can simply clip it to the container. clipped = intersection; @@ -258,7 +261,8 @@ gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node, if (clip_bounds) bounds = clipped; - if (container->data().GetBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN) && + if (container->data().GetBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren) && intersection.IsEmpty() && !clipped.IsEmpty()) { // If it is offscreen with respect to its parent, and the node itself is // not empty, label it offscreen. @@ -283,7 +287,7 @@ gfx::RectF AXTree::GetTreeBounds(const AXNode* node, return RelativeToTreeBounds(node, gfx::RectF(), offscreen, clip_bounds); } -std::set<int32_t> AXTree::GetReverseRelations(AXIntAttribute attr, +std::set<int32_t> AXTree::GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) const { DCHECK(IsNodeIdIntAttribute(attr)); @@ -298,7 +302,7 @@ std::set<int32_t> AXTree::GetReverseRelations(AXIntAttribute attr, return std::set<int32_t>(); } -std::set<int32_t> AXTree::GetReverseRelations(AXIntListAttribute attr, +std::set<int32_t> AXTree::GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) const { DCHECK(IsNodeIdIntListAttribute(attr)); @@ -460,6 +464,10 @@ bool AXTree::UpdateNode(const AXNodeData& src, AXNode* node = GetFromId(src.id); if (node) { update_state->pending_nodes.erase(node); + + // TODO(accessibility): CallNodeChangeCallbacks should not pass |node|, + // since the tree and the node data are not yet in a consistent + // state. Possibly only pass id. if (update_state->new_nodes.find(node) == update_state->new_nodes.end()) CallNodeChangeCallbacks(node, src); UpdateReverseRelations(node, src); @@ -535,14 +543,15 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) { delegate_->OnRoleChanged(this, node, old_data.role, new_data.role); if (old_data.state != new_data.state) { - for (int i = AX_STATE_NONE + 1; i <= AX_STATE_LAST; ++i) { - AXState state = static_cast<AXState>(i); + for (int32_t i = static_cast<int32_t>(ax::mojom::State::kNone) + 1; + i <= static_cast<int32_t>(ax::mojom::State::kLast); ++i) { + ax::mojom::State state = static_cast<ax::mojom::State>(i); if (old_data.HasState(state) != new_data.HasState(state)) delegate_->OnStateChanged(this, node, state, new_data.HasState(state)); } } - auto string_callback = [this, node](AXStringAttribute attr, + auto string_callback = [this, node](ax::mojom::StringAttribute attr, const std::string& old_string, const std::string& new_string) { delegate_->OnStringAttributeChanged(this, node, attr, old_string, @@ -552,14 +561,15 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) { new_data.string_attributes, std::string(), string_callback); - auto bool_callback = [this, node](AXBoolAttribute attr, const bool& old_bool, + auto bool_callback = [this, node](ax::mojom::BoolAttribute attr, + const bool& old_bool, const bool& new_bool) { delegate_->OnBoolAttributeChanged(this, node, attr, new_bool); }; CallIfAttributeValuesChanged(old_data.bool_attributes, new_data.bool_attributes, false, bool_callback); - auto float_callback = [this, node](AXFloatAttribute attr, + auto float_callback = [this, node](ax::mojom::FloatAttribute attr, const float& old_float, const float& new_float) { delegate_->OnFloatAttributeChanged(this, node, attr, old_float, new_float); @@ -567,15 +577,15 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) { CallIfAttributeValuesChanged(old_data.float_attributes, new_data.float_attributes, 0.0f, float_callback); - auto int_callback = [this, node](AXIntAttribute attr, const int& old_int, - const int& new_int) { + auto int_callback = [this, node](ax::mojom::IntAttribute attr, + const int& old_int, const int& new_int) { delegate_->OnIntAttributeChanged(this, node, attr, old_int, new_int); }; CallIfAttributeValuesChanged(old_data.int_attributes, new_data.int_attributes, 0, int_callback); auto intlist_callback = [this, node]( - AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, const std::vector<int32_t>& old_intlist, const std::vector<int32_t>& new_intlist) { delegate_->OnIntListAttributeChanged(this, node, attr, old_intlist, @@ -586,7 +596,7 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) { std::vector<int32_t>(), intlist_callback); auto stringlist_callback = - [this, node](AXStringListAttribute attr, + [this, node](ax::mojom::StringListAttribute attr, const std::vector<std::string>& old_stringlist, const std::vector<std::string>& new_stringlist) { delegate_->OnStringListAttributeChanged(this, node, attr, @@ -600,8 +610,8 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) { void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) { const AXNodeData& old_data = node->data(); int id = new_data.id; - auto int_callback = [this, node, id](AXIntAttribute attr, const int& old_int, - const int& new_int) { + auto int_callback = [this, node, id](ax::mojom::IntAttribute attr, + const int& old_int, const int& new_int) { if (!IsNodeIdIntAttribute(attr)) return; @@ -612,7 +622,7 @@ void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) { 0, int_callback); auto intlist_callback = [this, node, id]( - AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, const std::vector<int32_t>& old_intlist, const std::vector<int32_t>& new_intlist) { if (!IsNodeIdIntListAttribute(attr)) diff --git a/chromium/ui/accessibility/ax_tree.h b/chromium/ui/accessibility/ax_tree.h index d733df9fd1d..ac3eeeabe5e 100644 --- a/chromium/ui/accessibility/ax_tree.h +++ b/chromium/ui/accessibility/ax_tree.h @@ -52,41 +52,41 @@ class AX_EXPORT AXTreeDelegate { // Individual callbacks for every attribute of AXNodeData that can change. virtual void OnRoleChanged(AXTree* tree, AXNode* node, - AXRole old_role, - AXRole new_role) {} + ax::mojom::Role old_role, + ax::mojom::Role new_role) {} virtual void OnStateChanged(AXTree* tree, AXNode* node, - AXState state, + ax::mojom::State state, bool new_value) {} virtual void OnStringAttributeChanged(AXTree* tree, AXNode* node, - AXStringAttribute attr, + ax::mojom::StringAttribute attr, const std::string& old_value, const std::string& new_value) {} virtual void OnIntAttributeChanged(AXTree* tree, AXNode* node, - AXIntAttribute attr, + ax::mojom::IntAttribute attr, int32_t old_value, int32_t new_value) {} virtual void OnFloatAttributeChanged(AXTree* tree, AXNode* node, - AXFloatAttribute attr, + ax::mojom::FloatAttribute attr, float old_value, float new_value) {} virtual void OnBoolAttributeChanged(AXTree* tree, AXNode* node, - AXBoolAttribute attr, + ax::mojom::BoolAttribute attr, bool new_value) {} virtual void OnIntListAttributeChanged( AXTree* tree, AXNode* node, - AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, const std::vector<int32_t>& old_value, const std::vector<int32_t>& new_value) {} virtual void OnStringListAttributeChanged( AXTree* tree, AXNode* node, - AXStringListAttribute attr, + ax::mojom::StringListAttribute attr, const std::vector<std::string>& old_value, const std::vector<std::string>& new_value) {} @@ -158,6 +158,13 @@ class AX_EXPORT AXTreeDelegate { // accessibility APIs on a specific platform. class AX_EXPORT AXTree { public: + typedef std::map<ax::mojom::IntAttribute, + std::map<int32_t, std::set<int32_t>>> + IntReverseRelationMap; + typedef std::map<ax::mojom::IntListAttribute, + std::map<int32_t, std::set<int32_t>>> + IntListReverseRelationMap; + AXTree(); explicit AXTree(const AXTreeUpdate& initial_state); virtual ~AXTree(); @@ -204,16 +211,23 @@ class AX_EXPORT AXTree { // Given a node ID attribute (one where IsNodeIdIntAttribute is true), // and a destination node ID, return a set of all source node IDs that // have that relationship attribute between them and the destination. - std::set<int32_t> GetReverseRelations(AXIntAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) const; // Given a node ID list attribute (one where // IsNodeIdIntListAttribute is true), and a destination node ID, // return a set of all source node IDs that have that relationship // attribute between them and the destination. - std::set<int32_t> GetReverseRelations(AXIntListAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) const; + // Map from a relation attribute to a map from a target id to source ids. + const IntReverseRelationMap& int_reverse_relations() { + return int_reverse_relations_; + } + const IntListReverseRelationMap& intlist_reverse_relations() { + return intlist_reverse_relations_; + } // Return a multi-line indented string representation, for logging. std::string ToString() const; @@ -273,12 +287,10 @@ class AX_EXPORT AXTree { // Map from an int attribute (if IsNodeIdIntAttribute is true) to // a reverse mapping from target nodes to source nodes. - std::map<AXIntAttribute, std::map<int32_t, std::set<int32_t>>> - int_reverse_relations_; + IntReverseRelationMap int_reverse_relations_; // Map from an int list attribute (if IsNodeIdIntListAttribute is true) to // a reverse mapping from target nodes to source nodes. - std::map<AXIntListAttribute, std::map<int32_t, std::set<int32_t>>> - intlist_reverse_relations_; + IntListReverseRelationMap intlist_reverse_relations_; }; } // namespace ui diff --git a/chromium/ui/accessibility/ax_tree_combiner.cc b/chromium/ui/accessibility/ax_tree_combiner.cc index 68a9c8b22ac..06a6ac15726 100644 --- a/chromium/ui/accessibility/ax_tree_combiner.cc +++ b/chromium/ui/accessibility/ax_tree_combiner.cc @@ -80,7 +80,8 @@ void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) { int32_t tree_id = tree->tree_data.tree_id; for (size_t i = 0; i < tree->nodes.size(); ++i) { AXNodeData node = tree->nodes[i]; - int32_t child_tree_id = node.GetIntAttribute(AX_ATTR_CHILD_TREE_ID); + int32_t child_tree_id = + node.GetIntAttribute(ax::mojom::IntAttribute::kChildTreeId); // Map the node's ID. node.id = MapId(tree_id, node.id); @@ -94,13 +95,13 @@ void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) { node.offset_container_id = MapId(tree_id, node.offset_container_id); // Map other int attributes that refer to node IDs, and remove the - // AX_ATTR_CHILD_TREE_ID attribute. + // ax::mojom::IntAttribute::kChildTreeId attribute. for (size_t j = 0; j < node.int_attributes.size(); ++j) { auto& attr = node.int_attributes[j]; if (IsNodeIdIntAttribute(attr.first)) attr.second = MapId(tree_id, attr.second); - if (attr.first == AX_ATTR_CHILD_TREE_ID) { - attr.first = AX_INT_ATTRIBUTE_NONE; + if (attr.first == ax::mojom::IntAttribute::kChildTreeId) { + attr.first = ax::mojom::IntAttribute::kNone; attr.second = 0; } } diff --git a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc index 70f861c0966..6e0aaf498fc 100644 --- a/chromium/ui/accessibility/ax_tree_combiner_unittest.cc +++ b/chromium/ui/accessibility/ax_tree_combiner_unittest.cc @@ -45,10 +45,11 @@ TEST(CombineAXTreesTest, EmbedChildTree) { parent_tree.nodes[0].child_ids.push_back(2); parent_tree.nodes[0].child_ids.push_back(3); parent_tree.nodes[1].id = 2; - parent_tree.nodes[1].role = AX_ROLE_BUTTON; + parent_tree.nodes[1].role = ax::mojom::Role::kButton; parent_tree.nodes[2].id = 3; - parent_tree.nodes[2].role = AX_ROLE_IFRAME; - parent_tree.nodes[2].AddIntAttribute(AX_ATTR_CHILD_TREE_ID, 2); + parent_tree.nodes[2].role = ax::mojom::Role::kIframe; + parent_tree.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kChildTreeId, + 2); AXTreeUpdate child_tree; child_tree.root_id = 1; @@ -60,9 +61,9 @@ TEST(CombineAXTreesTest, EmbedChildTree) { child_tree.nodes[0].child_ids.push_back(2); child_tree.nodes[0].child_ids.push_back(3); child_tree.nodes[1].id = 2; - child_tree.nodes[1].role = AX_ROLE_CHECK_BOX; + child_tree.nodes[1].role = ax::mojom::Role::kCheckBox; child_tree.nodes[2].id = 3; - child_tree.nodes[2].role = AX_ROLE_RADIO_BUTTON; + child_tree.nodes[2].role = ax::mojom::Role::kRadioButton; AXTreeCombiner combiner; combiner.AddTree(parent_tree, true); @@ -78,16 +79,16 @@ TEST(CombineAXTreesTest, EmbedChildTree) { EXPECT_EQ(2, combined.nodes[0].child_ids[0]); EXPECT_EQ(3, combined.nodes[0].child_ids[1]); EXPECT_EQ(2, combined.nodes[1].id); - EXPECT_EQ(AX_ROLE_BUTTON, combined.nodes[1].role); + EXPECT_EQ(ax::mojom::Role::kButton, combined.nodes[1].role); EXPECT_EQ(3, combined.nodes[2].id); - EXPECT_EQ(AX_ROLE_IFRAME, combined.nodes[2].role); + EXPECT_EQ(ax::mojom::Role::kIframe, combined.nodes[2].role); EXPECT_EQ(1U, combined.nodes[2].child_ids.size()); EXPECT_EQ(4, combined.nodes[2].child_ids[0]); EXPECT_EQ(4, combined.nodes[3].id); EXPECT_EQ(5, combined.nodes[4].id); - EXPECT_EQ(AX_ROLE_CHECK_BOX, combined.nodes[4].role); + EXPECT_EQ(ax::mojom::Role::kCheckBox, combined.nodes[4].role); EXPECT_EQ(6, combined.nodes[5].id); - EXPECT_EQ(AX_ROLE_RADIO_BUTTON, combined.nodes[5].role); + EXPECT_EQ(ax::mojom::Role::kRadioButton, combined.nodes[5].role); } TEST(CombineAXTreesTest, MapAllIdAttributes) { @@ -101,18 +102,26 @@ TEST(CombineAXTreesTest, MapAllIdAttributes) { tree.nodes.resize(2); tree.nodes[0].id = 11; tree.nodes[0].child_ids.push_back(22); - tree.nodes[0].AddIntAttribute(AX_ATTR_TABLE_HEADER_ID, 22); - tree.nodes[0].AddIntAttribute(AX_ATTR_TABLE_ROW_HEADER_ID, 22); - tree.nodes[0].AddIntAttribute(AX_ATTR_TABLE_COLUMN_HEADER_ID, 22); - tree.nodes[0].AddIntAttribute(AX_ATTR_ACTIVEDESCENDANT_ID, 22); + tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableHeaderId, 22); + tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableRowHeaderId, 22); + tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableColumnHeaderId, + 22); + tree.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId, + 22); std::vector<int32_t> ids { 22 }; - tree.nodes[0].AddIntListAttribute(AX_ATTR_INDIRECT_CHILD_IDS, ids); - tree.nodes[0].AddIntListAttribute(AX_ATTR_CONTROLS_IDS, ids); - tree.nodes[0].AddIntListAttribute(AX_ATTR_DESCRIBEDBY_IDS, ids); - tree.nodes[0].AddIntListAttribute(AX_ATTR_FLOWTO_IDS, ids); - tree.nodes[0].AddIntListAttribute(AX_ATTR_LABELLEDBY_IDS, ids); - tree.nodes[0].AddIntListAttribute(AX_ATTR_CELL_IDS, ids); - tree.nodes[0].AddIntListAttribute(AX_ATTR_UNIQUE_CELL_IDS, ids); + tree.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kIndirectChildIds, ids); + tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds, + ids); + tree.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kDescribedbyIds, ids); + tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, + ids); + tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds, + ids); + tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kCellIds, ids); + tree.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kUniqueCellIds, + ids); tree.nodes[1].id = 22; AXTreeCombiner combiner; @@ -128,25 +137,28 @@ TEST(CombineAXTreesTest, MapAllIdAttributes) { EXPECT_EQ(2, combined.nodes[0].child_ids[0]); EXPECT_EQ(2, combined.nodes[1].id); - EXPECT_EQ(2, combined.nodes[0].GetIntAttribute(AX_ATTR_TABLE_HEADER_ID)); - EXPECT_EQ(2, combined.nodes[0].GetIntAttribute(AX_ATTR_TABLE_ROW_HEADER_ID)); EXPECT_EQ(2, combined.nodes[0].GetIntAttribute( - AX_ATTR_TABLE_COLUMN_HEADER_ID)); - EXPECT_EQ(2, combined.nodes[0].GetIntAttribute(AX_ATTR_ACTIVEDESCENDANT_ID)); + ax::mojom::IntAttribute::kTableHeaderId)); + EXPECT_EQ(2, combined.nodes[0].GetIntAttribute( + ax::mojom::IntAttribute::kTableRowHeaderId)); + EXPECT_EQ(2, combined.nodes[0].GetIntAttribute( + ax::mojom::IntAttribute::kTableColumnHeaderId)); + EXPECT_EQ(2, combined.nodes[0].GetIntAttribute( + ax::mojom::IntAttribute::kActivedescendantId)); EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute( - AX_ATTR_INDIRECT_CHILD_IDS)[0]); + ax::mojom::IntListAttribute::kIndirectChildIds)[0]); EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute( - AX_ATTR_CONTROLS_IDS)[0]); + ax::mojom::IntListAttribute::kControlsIds)[0]); EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute( - AX_ATTR_DESCRIBEDBY_IDS)[0]); + ax::mojom::IntListAttribute::kDescribedbyIds)[0]); EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute( - AX_ATTR_FLOWTO_IDS)[0]); + ax::mojom::IntListAttribute::kFlowtoIds)[0]); EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute( - AX_ATTR_LABELLEDBY_IDS)[0]); + ax::mojom::IntListAttribute::kLabelledbyIds)[0]); EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute( - AX_ATTR_CELL_IDS)[0]); + ax::mojom::IntListAttribute::kCellIds)[0]); EXPECT_EQ(2, combined.nodes[0].GetIntListAttribute( - AX_ATTR_UNIQUE_CELL_IDS)[0]); + ax::mojom::IntListAttribute::kUniqueCellIds)[0]); } TEST(CombineAXTreesTest, FocusedTree) { @@ -161,10 +173,11 @@ TEST(CombineAXTreesTest, FocusedTree) { parent_tree.nodes[0].child_ids.push_back(2); parent_tree.nodes[0].child_ids.push_back(3); parent_tree.nodes[1].id = 2; - parent_tree.nodes[1].role = AX_ROLE_BUTTON; + parent_tree.nodes[1].role = ax::mojom::Role::kButton; parent_tree.nodes[2].id = 3; - parent_tree.nodes[2].role = AX_ROLE_IFRAME; - parent_tree.nodes[2].AddIntAttribute(AX_ATTR_CHILD_TREE_ID, 2); + parent_tree.nodes[2].role = ax::mojom::Role::kIframe; + parent_tree.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kChildTreeId, + 2); AXTreeUpdate child_tree; child_tree.has_tree_data = true; @@ -177,9 +190,9 @@ TEST(CombineAXTreesTest, FocusedTree) { child_tree.nodes[0].child_ids.push_back(2); child_tree.nodes[0].child_ids.push_back(3); child_tree.nodes[1].id = 2; - child_tree.nodes[1].role = AX_ROLE_CHECK_BOX; + child_tree.nodes[1].role = ax::mojom::Role::kCheckBox; child_tree.nodes[2].id = 3; - child_tree.nodes[2].role = AX_ROLE_RADIO_BUTTON; + child_tree.nodes[2].role = ax::mojom::Role::kRadioButton; AXTreeCombiner combiner; combiner.AddTree(parent_tree, true); diff --git a/chromium/ui/accessibility/ax_tree_data.cc b/chromium/ui/accessibility/ax_tree_data.cc index 3639b8dbebf..20e5f1ccce8 100644 --- a/chromium/ui/accessibility/ax_tree_data.cc +++ b/chromium/ui/accessibility/ax_tree_data.cc @@ -10,6 +10,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_enum_util.h" namespace ui { diff --git a/chromium/ui/accessibility/ax_tree_data.h b/chromium/ui/accessibility/ax_tree_data.h index d637bf2b45d..0233764b109 100644 --- a/chromium/ui/accessibility/ax_tree_data.h +++ b/chromium/ui/accessibility/ax_tree_data.h @@ -13,7 +13,7 @@ #include "base/strings/string16.h" #include "base/strings/string_split.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" #include "ui/gfx/geometry/rect.h" @@ -61,10 +61,12 @@ struct AX_EXPORT AXTreeData { // line, otherwise it's on the second line. int32_t sel_anchor_object_id = -1; int32_t sel_anchor_offset = -1; - ui::AXTextAffinity sel_anchor_affinity = AX_TEXT_AFFINITY_UPSTREAM; + ax::mojom::TextAffinity sel_anchor_affinity = + ax::mojom::TextAffinity::kUpstream; int32_t sel_focus_object_id = -1; int32_t sel_focus_offset = -1; - ui::AXTextAffinity sel_focus_affinity = AX_TEXT_AFFINITY_DOWNSTREAM; + ax::mojom::TextAffinity sel_focus_affinity = + ax::mojom::TextAffinity::kDownstream; }; AX_EXPORT bool operator==(const AXTreeData& lhs, const AXTreeData& rhs); diff --git a/chromium/ui/accessibility/ax_tree_unittest.cc b/chromium/ui/accessibility/ax_tree_unittest.cc index 5d9b52b33b8..81d8fb536eb 100644 --- a/chromium/ui/accessibility/ax_tree_unittest.cc +++ b/chromium/ui/accessibility/ax_tree_unittest.cc @@ -14,6 +14,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_serializable_tree.h" #include "ui/accessibility/ax_tree_serializer.h" @@ -119,15 +120,15 @@ class FakeAXTreeDelegate : public AXTreeDelegate { void OnRoleChanged(AXTree* tree, AXNode* node, - AXRole old_role, - AXRole new_role) override { + ax::mojom::Role old_role, + ax::mojom::Role new_role) override { attribute_change_log_.push_back(base::StringPrintf( "Role changed from %s to %s", ToString(old_role), ToString(new_role))); } void OnStateChanged(AXTree* tree, AXNode* node, - AXState state, + ax::mojom::State state, bool new_value) override { attribute_change_log_.push_back(base::StringPrintf( "%s changed to %s", ToString(state), new_value ? "true" : "false")); @@ -135,7 +136,7 @@ class FakeAXTreeDelegate : public AXTreeDelegate { void OnStringAttributeChanged(AXTree* tree, AXNode* node, - AXStringAttribute attr, + ax::mojom::StringAttribute attr, const std::string& old_value, const std::string& new_value) override { attribute_change_log_.push_back( @@ -145,7 +146,7 @@ class FakeAXTreeDelegate : public AXTreeDelegate { void OnIntAttributeChanged(AXTree* tree, AXNode* node, - AXIntAttribute attr, + ax::mojom::IntAttribute attr, int32_t old_value, int32_t new_value) override { attribute_change_log_.push_back(base::StringPrintf( @@ -154,7 +155,7 @@ class FakeAXTreeDelegate : public AXTreeDelegate { void OnFloatAttributeChanged(AXTree* tree, AXNode* node, - AXFloatAttribute attr, + ax::mojom::FloatAttribute attr, float old_value, float new_value) override { attribute_change_log_.push_back( @@ -165,7 +166,7 @@ class FakeAXTreeDelegate : public AXTreeDelegate { void OnBoolAttributeChanged(AXTree* tree, AXNode* node, - AXBoolAttribute attr, + ax::mojom::BoolAttribute attr, bool new_value) override { attribute_change_log_.push_back(base::StringPrintf( "%s changed to %s", ToString(attr), new_value ? "true" : "false")); @@ -174,7 +175,7 @@ class FakeAXTreeDelegate : public AXTreeDelegate { void OnIntListAttributeChanged( AXTree* tree, AXNode* node, - AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, const std::vector<int32_t>& old_value, const std::vector<int32_t>& new_value) override { attribute_change_log_.push_back( @@ -229,20 +230,20 @@ class FakeAXTreeDelegate : public AXTreeDelegate { TEST(AXTreeTest, SerializeSimpleAXTree) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_DIALOG; - root.AddState(AX_STATE_FOCUSABLE); + root.role = ax::mojom::Role::kDialog; + root.AddState(ax::mojom::State::kFocusable); root.location = gfx::RectF(0, 0, 800, 600); root.child_ids.push_back(2); root.child_ids.push_back(3); AXNodeData button; button.id = 2; - button.role = AX_ROLE_BUTTON; + button.role = ax::mojom::Role::kButton; button.location = gfx::RectF(20, 20, 200, 30); AXNodeData checkbox; checkbox.id = 3; - checkbox.role = AX_ROLE_CHECK_BOX; + checkbox.role = ax::mojom::Role::kCheckBox; checkbox.location = gfx::RectF(20, 50, 200, 30); AXTreeUpdate initial_state; @@ -290,22 +291,22 @@ TEST(AXTreeTest, SerializeSimpleAXTree) { TEST(AXTreeTest, SerializeAXTreeUpdate) { AXNodeData list; list.id = 3; - list.role = AX_ROLE_LIST; + list.role = ax::mojom::Role::kList; list.child_ids.push_back(4); list.child_ids.push_back(5); list.child_ids.push_back(6); AXNodeData list_item_2; list_item_2.id = 5; - list_item_2.role = AX_ROLE_LIST_ITEM; + list_item_2.role = ax::mojom::Role::kListItem; AXNodeData list_item_3; list_item_3.id = 6; - list_item_3.role = AX_ROLE_LIST_ITEM; + list_item_3.role = ax::mojom::Role::kListItem; AXNodeData button; button.id = 7; - button.role = AX_ROLE_BUTTON; + button.role = ax::mojom::Role::kButton; AXTreeUpdate update; update.root_id = 3; @@ -742,10 +743,9 @@ TEST(AXTreeTest, RoleAndStateChangeCallbacks) { initial_state.root_id = 1; initial_state.nodes.resize(1); initial_state.nodes[0].id = 1; - initial_state.nodes[0].role = AX_ROLE_BUTTON; - initial_state.nodes[0].AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, - ui::AX_CHECKED_STATE_TRUE); - initial_state.nodes[0].AddState(AX_STATE_FOCUSABLE); + initial_state.nodes[0].role = ax::mojom::Role::kButton; + initial_state.nodes[0].SetCheckedState(ax::mojom::CheckedState::kTrue); + initial_state.nodes[0].AddState(ax::mojom::State::kFocusable); AXTree tree(initial_state); FakeAXTreeDelegate fake_delegate; @@ -756,11 +756,10 @@ TEST(AXTreeTest, RoleAndStateChangeCallbacks) { update.root_id = 1; update.nodes.resize(1); update.nodes[0].id = 1; - update.nodes[0].role = AX_ROLE_CHECK_BOX; - update.nodes[0].AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, - ui::AX_CHECKED_STATE_FALSE); - update.nodes[0].AddState(AX_STATE_FOCUSABLE); - update.nodes[0].AddState(AX_STATE_VISITED); + update.nodes[0].role = ax::mojom::Role::kCheckBox; + update.nodes[0].SetCheckedState(ax::mojom::CheckedState::kFalse); + update.nodes[0].AddState(ax::mojom::State::kFocusable); + update.nodes[0].AddState(ax::mojom::State::kVisited); EXPECT_TRUE(tree.Unserialize(update)); const std::vector<std::string>& change_log = @@ -778,15 +777,23 @@ TEST(AXTreeTest, AttributeChangeCallbacks) { initial_state.root_id = 1; initial_state.nodes.resize(1); initial_state.nodes[0].id = 1; - initial_state.nodes[0].AddStringAttribute(AX_ATTR_NAME, "N1"); - initial_state.nodes[0].AddStringAttribute(AX_ATTR_DESCRIPTION, "D1"); - initial_state.nodes[0].AddBoolAttribute(AX_ATTR_LIVE_ATOMIC, true); - initial_state.nodes[0].AddBoolAttribute(AX_ATTR_BUSY, false); - initial_state.nodes[0].AddFloatAttribute(AX_ATTR_MIN_VALUE_FOR_RANGE, 1.0); - initial_state.nodes[0].AddFloatAttribute(AX_ATTR_MAX_VALUE_FOR_RANGE, 10.0); - initial_state.nodes[0].AddFloatAttribute(AX_ATTR_STEP_VALUE_FOR_RANGE, 3.0); - initial_state.nodes[0].AddIntAttribute(AX_ATTR_SCROLL_X, 5); - initial_state.nodes[0].AddIntAttribute(AX_ATTR_SCROLL_X_MIN, 1); + initial_state.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kName, + "N1"); + initial_state.nodes[0].AddStringAttribute( + ax::mojom::StringAttribute::kDescription, "D1"); + initial_state.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kLiveAtomic, + true); + initial_state.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, + false); + initial_state.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kMinValueForRange, 1.0); + initial_state.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kMaxValueForRange, 10.0); + initial_state.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kStepValueForRange, 3.0); + initial_state.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 5); + initial_state.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollXMin, + 1); AXTree tree(initial_state); FakeAXTreeDelegate fake_delegate; @@ -797,15 +804,20 @@ TEST(AXTreeTest, AttributeChangeCallbacks) { update0.root_id = 1; update0.nodes.resize(1); update0.nodes[0].id = 1; - update0.nodes[0].AddStringAttribute(AX_ATTR_NAME, "N2"); - update0.nodes[0].AddStringAttribute(AX_ATTR_DESCRIPTION, "D2"); - update0.nodes[0].AddBoolAttribute(AX_ATTR_LIVE_ATOMIC, false); - update0.nodes[0].AddBoolAttribute(AX_ATTR_BUSY, true); - update0.nodes[0].AddFloatAttribute(AX_ATTR_MIN_VALUE_FOR_RANGE, 2.0); - update0.nodes[0].AddFloatAttribute(AX_ATTR_MAX_VALUE_FOR_RANGE, 9.0); - update0.nodes[0].AddFloatAttribute(AX_ATTR_STEP_VALUE_FOR_RANGE, 0.5); - update0.nodes[0].AddIntAttribute(AX_ATTR_SCROLL_X, 6); - update0.nodes[0].AddIntAttribute(AX_ATTR_SCROLL_X_MIN, 2); + update0.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kName, "N2"); + update0.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kDescription, + "D2"); + update0.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kLiveAtomic, + false); + update0.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, true); + update0.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kMinValueForRange, 2.0); + update0.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kMaxValueForRange, 9.0); + update0.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kStepValueForRange, 0.5); + update0.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 6); + update0.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollXMin, 2); EXPECT_TRUE(tree.Unserialize(update0)); const std::vector<std::string>& change_log = @@ -829,13 +841,16 @@ TEST(AXTreeTest, AttributeChangeCallbacks) { update1.root_id = 1; update1.nodes.resize(1); update1.nodes[0].id = 1; - update1.nodes[0].AddStringAttribute(AX_ATTR_DESCRIPTION, "D3"); - update1.nodes[0].AddStringAttribute(AX_ATTR_VALUE, "V3"); - update1.nodes[0].AddBoolAttribute(AX_ATTR_MODAL, true); - update1.nodes[0].AddFloatAttribute(AX_ATTR_VALUE_FOR_RANGE, 5.0); - update1.nodes[0].AddFloatAttribute(AX_ATTR_MAX_VALUE_FOR_RANGE, 9.0); - update1.nodes[0].AddIntAttribute(AX_ATTR_SCROLL_X, 7); - update1.nodes[0].AddIntAttribute(AX_ATTR_SCROLL_X_MAX, 10); + update1.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kDescription, + "D3"); + update1.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kValue, "V3"); + update1.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true); + update1.nodes[0].AddFloatAttribute(ax::mojom::FloatAttribute::kValueForRange, + 5.0); + update1.nodes[0].AddFloatAttribute( + ax::mojom::FloatAttribute::kMaxValueForRange, 9.0); + update1.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 7); + update1.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollXMax, 10); EXPECT_TRUE(tree.Unserialize(update1)); const std::vector<std::string>& change_log2 = @@ -871,8 +886,10 @@ TEST(AXTreeTest, IntListChangeCallbacks) { initial_state.root_id = 1; initial_state.nodes.resize(1); initial_state.nodes[0].id = 1; - initial_state.nodes[0].AddIntListAttribute(AX_ATTR_CONTROLS_IDS, one); - initial_state.nodes[0].AddIntListAttribute(AX_ATTR_RADIO_GROUP_IDS, two); + initial_state.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kControlsIds, one); + initial_state.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kRadioGroupIds, two); AXTree tree(initial_state); FakeAXTreeDelegate fake_delegate; @@ -883,8 +900,10 @@ TEST(AXTreeTest, IntListChangeCallbacks) { update0.root_id = 1; update0.nodes.resize(1); update0.nodes[0].id = 1; - update0.nodes[0].AddIntListAttribute(AX_ATTR_CONTROLS_IDS, two); - update0.nodes[0].AddIntListAttribute(AX_ATTR_RADIO_GROUP_IDS, three); + update0.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kControlsIds, two); + update0.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kRadioGroupIds, three); EXPECT_TRUE(tree.Unserialize(update0)); const std::vector<std::string>& change_log = @@ -901,8 +920,10 @@ TEST(AXTreeTest, IntListChangeCallbacks) { update1.root_id = 1; update1.nodes.resize(1); update1.nodes[0].id = 1; - update1.nodes[0].AddIntListAttribute(AX_ATTR_RADIO_GROUP_IDS, two); - update1.nodes[0].AddIntListAttribute(AX_ATTR_FLOWTO_IDS, three); + update1.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kRadioGroupIds, two); + update1.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds, + three); EXPECT_TRUE(tree.Unserialize(update1)); const std::vector<std::string>& change_log2 = @@ -962,8 +983,9 @@ TEST(AXTreeTest, EmptyNodeNotOffscreenEvenIfAllChildrenOffscreen) { tree_update.nodes.resize(4); tree_update.nodes[0].id = 1; tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600); - tree_update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; - tree_update.nodes[0].AddBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN, true); + tree_update.nodes[0].role = ax::mojom::Role::kRootWebArea; + tree_update.nodes[0].AddBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren, true); tree_update.nodes[0].child_ids.push_back(2); tree_update.nodes[1].id = 2; tree_update.nodes[1].location = gfx::RectF(); // Deliberately empty. @@ -1040,8 +1062,8 @@ TEST(AXTreeTest, GetBoundsWithScrolling) { tree_update.nodes[0].child_ids.push_back(2); tree_update.nodes[1].id = 2; tree_update.nodes[1].location = gfx::RectF(100, 50, 600, 500); - tree_update.nodes[1].AddIntAttribute(ui::AX_ATTR_SCROLL_X, 5); - tree_update.nodes[1].AddIntAttribute(ui::AX_ATTR_SCROLL_Y, 10); + tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 5); + tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kScrollY, 10); tree_update.nodes[1].child_ids.push_back(3); tree_update.nodes[2].id = 3; tree_update.nodes[2].offset_container_id = 2; @@ -1057,7 +1079,8 @@ TEST(AXTreeTest, GetBoundsEmptyBoundsInheritsFromParent) { tree_update.nodes.resize(3); tree_update.nodes[0].id = 1; tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600); - tree_update.nodes[1].AddBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN, true); + tree_update.nodes[1].AddBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren, true); tree_update.nodes[0].child_ids.push_back(2); tree_update.nodes[1].id = 2; tree_update.nodes[1].location = gfx::RectF(300, 200, 100, 100); @@ -1083,7 +1106,8 @@ TEST(AXTreeTest, GetBoundsCropsChildToRoot) { tree_update.nodes.resize(5); tree_update.nodes[0].id = 1; tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600); - tree_update.nodes[0].AddBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN, true); + tree_update.nodes[0].AddBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren, true); tree_update.nodes[0].child_ids.push_back(2); tree_update.nodes[0].child_ids.push_back(3); tree_update.nodes[0].child_ids.push_back(4); @@ -1121,13 +1145,15 @@ TEST(AXTreeTest, GetBoundsSetsOffscreenIfClipsChildren) { tree_update.nodes.resize(5); tree_update.nodes[0].id = 1; tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600); - tree_update.nodes[0].AddBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN, true); + tree_update.nodes[0].AddBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren, true); tree_update.nodes[0].child_ids.push_back(2); tree_update.nodes[0].child_ids.push_back(3); tree_update.nodes[1].id = 2; tree_update.nodes[1].location = gfx::RectF(0, 0, 200, 200); - tree_update.nodes[1].AddBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN, true); + tree_update.nodes[1].AddBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren, true); tree_update.nodes[1].child_ids.push_back(4); tree_update.nodes[2].id = 3; @@ -1156,8 +1182,9 @@ TEST(AXTreeTest, GetBoundsUpdatesOffscreen) { tree_update.nodes.resize(5); tree_update.nodes[0].id = 1; tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600); - tree_update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA; - tree_update.nodes[0].AddBoolAttribute(ui::AX_ATTR_CLIPS_CHILDREN, true); + tree_update.nodes[0].role = ax::mojom::Role::kRootWebArea; + tree_update.nodes[0].AddBoolAttribute( + ax::mojom::BoolAttribute::kClipsChildren, true); tree_update.nodes[0].child_ids.push_back(2); tree_update.nodes[0].child_ids.push_back(3); tree_update.nodes[0].child_ids.push_back(4); @@ -1187,32 +1214,35 @@ TEST(AXTreeTest, IntReverseRelations) { initial_state.root_id = 1; initial_state.nodes.resize(4); initial_state.nodes[0].id = 1; - initial_state.nodes[0].AddIntAttribute(AX_ATTR_ACTIVEDESCENDANT_ID, 2); + initial_state.nodes[0].AddIntAttribute( + ax::mojom::IntAttribute::kActivedescendantId, 2); initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(3); initial_state.nodes[0].child_ids.push_back(4); initial_state.nodes[1].id = 2; initial_state.nodes[2].id = 3; - initial_state.nodes[2].AddIntAttribute(AX_ATTR_MEMBER_OF_ID, 1); + initial_state.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kMemberOfId, + 1); initial_state.nodes[3].id = 4; - initial_state.nodes[3].AddIntAttribute(AX_ATTR_MEMBER_OF_ID, 1); + initial_state.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kMemberOfId, + 1); AXTree tree(initial_state); auto reverse_active_descendant = - tree.GetReverseRelations(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 2); + tree.GetReverseRelations(ax::mojom::IntAttribute::kActivedescendantId, 2); ASSERT_EQ(1U, reverse_active_descendant.size()); EXPECT_TRUE(base::ContainsKey(reverse_active_descendant, 1)); reverse_active_descendant = - tree.GetReverseRelations(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 1); + tree.GetReverseRelations(ax::mojom::IntAttribute::kActivedescendantId, 1); ASSERT_EQ(0U, reverse_active_descendant.size()); auto reverse_errormessage = - tree.GetReverseRelations(ui::AX_ATTR_ERRORMESSAGE_ID, 1); + tree.GetReverseRelations(ax::mojom::IntAttribute::kErrormessageId, 1); ASSERT_EQ(0U, reverse_errormessage.size()); auto reverse_member_of = - tree.GetReverseRelations(ui::AX_ATTR_MEMBER_OF_ID, 1); + tree.GetReverseRelations(ax::mojom::IntAttribute::kMemberOfId, 1); ASSERT_EQ(2U, reverse_member_of.size()); EXPECT_TRUE(base::ContainsKey(reverse_member_of, 3)); EXPECT_TRUE(base::ContainsKey(reverse_member_of, 4)); @@ -1220,24 +1250,26 @@ TEST(AXTreeTest, IntReverseRelations) { AXTreeUpdate update = initial_state; update.nodes.resize(5); update.nodes[0].int_attributes.clear(); - update.nodes[0].AddIntAttribute(AX_ATTR_ACTIVEDESCENDANT_ID, 5); + update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId, + 5); update.nodes[0].child_ids.push_back(5); update.nodes[2].int_attributes.clear(); update.nodes[4].id = 5; - update.nodes[4].AddIntAttribute(AX_ATTR_MEMBER_OF_ID, 1); + update.nodes[4].AddIntAttribute(ax::mojom::IntAttribute::kMemberOfId, 1); EXPECT_TRUE(tree.Unserialize(update)); reverse_active_descendant = - tree.GetReverseRelations(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 2); + tree.GetReverseRelations(ax::mojom::IntAttribute::kActivedescendantId, 2); ASSERT_EQ(0U, reverse_active_descendant.size()); reverse_active_descendant = - tree.GetReverseRelations(ui::AX_ATTR_ACTIVEDESCENDANT_ID, 5); + tree.GetReverseRelations(ax::mojom::IntAttribute::kActivedescendantId, 5); ASSERT_EQ(1U, reverse_active_descendant.size()); EXPECT_TRUE(base::ContainsKey(reverse_active_descendant, 1)); - reverse_member_of = tree.GetReverseRelations(ui::AX_ATTR_MEMBER_OF_ID, 1); + reverse_member_of = + tree.GetReverseRelations(ax::mojom::IntAttribute::kMemberOfId, 1); ASSERT_EQ(2U, reverse_member_of.size()); EXPECT_TRUE(base::ContainsKey(reverse_member_of, 4)); EXPECT_TRUE(base::ContainsKey(reverse_member_of, 5)); @@ -1255,7 +1287,8 @@ TEST(AXTreeTest, IntListReverseRelations) { initial_state.root_id = 1; initial_state.nodes.resize(3); initial_state.nodes[0].id = 1; - initial_state.nodes[0].AddIntListAttribute(AX_ATTR_LABELLEDBY_IDS, node_two); + initial_state.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kLabelledbyIds, node_two); initial_state.nodes[0].child_ids.push_back(2); initial_state.nodes[0].child_ids.push_back(3); initial_state.nodes[1].id = 2; @@ -1264,22 +1297,55 @@ TEST(AXTreeTest, IntListReverseRelations) { AXTree tree(initial_state); auto reverse_labelled_by = - tree.GetReverseRelations(ui::AX_ATTR_LABELLEDBY_IDS, 2); + tree.GetReverseRelations(ax::mojom::IntListAttribute::kLabelledbyIds, 2); ASSERT_EQ(1U, reverse_labelled_by.size()); EXPECT_TRUE(base::ContainsKey(reverse_labelled_by, 1)); - reverse_labelled_by = tree.GetReverseRelations(ui::AX_ATTR_LABELLEDBY_IDS, 3); + reverse_labelled_by = + tree.GetReverseRelations(ax::mojom::IntListAttribute::kLabelledbyIds, 3); ASSERT_EQ(0U, reverse_labelled_by.size()); // Change existing attributes. AXTreeUpdate update = initial_state; update.nodes[0].intlist_attributes.clear(); - update.nodes[0].AddIntListAttribute(AX_ATTR_LABELLEDBY_IDS, nodes_two_three); + update.nodes[0].AddIntListAttribute( + ax::mojom::IntListAttribute::kLabelledbyIds, nodes_two_three); EXPECT_TRUE(tree.Unserialize(update)); - reverse_labelled_by = tree.GetReverseRelations(ui::AX_ATTR_LABELLEDBY_IDS, 3); + reverse_labelled_by = + tree.GetReverseRelations(ax::mojom::IntListAttribute::kLabelledbyIds, 3); ASSERT_EQ(1U, reverse_labelled_by.size()); EXPECT_TRUE(base::ContainsKey(reverse_labelled_by, 1)); } +TEST(AXTreeTest, SkipIgnoredNodes) { + AXTreeUpdate tree_update; + tree_update.root_id = 1; + tree_update.nodes.resize(5); + tree_update.nodes[0].id = 1; + tree_update.nodes[0].child_ids = {2, 3}; + tree_update.nodes[1].id = 2; + tree_update.nodes[1].AddState(ax::mojom::State::kIgnored); + tree_update.nodes[1].child_ids = {4, 5}; + tree_update.nodes[2].id = 3; + tree_update.nodes[3].id = 4; + tree_update.nodes[4].id = 5; + + AXTree tree(tree_update); + AXNode* root = tree.root(); + ASSERT_EQ(2, root->child_count()); + ASSERT_EQ(2, root->ChildAtIndex(0)->id()); + ASSERT_EQ(3, root->ChildAtIndex(1)->id()); + + EXPECT_EQ(3, root->GetUnignoredChildCount()); + EXPECT_EQ(4, root->GetUnignoredChildAtIndex(0)->id()); + EXPECT_EQ(5, root->GetUnignoredChildAtIndex(1)->id()); + EXPECT_EQ(3, root->GetUnignoredChildAtIndex(2)->id()); + EXPECT_EQ(0, root->GetUnignoredChildAtIndex(0)->GetUnignoredIndexInParent()); + EXPECT_EQ(1, root->GetUnignoredChildAtIndex(1)->GetUnignoredIndexInParent()); + EXPECT_EQ(2, root->GetUnignoredChildAtIndex(2)->GetUnignoredIndexInParent()); + + EXPECT_EQ(1, root->GetUnignoredChildAtIndex(0)->GetUnignoredParent()->id()); +} + } // namespace ui diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_ar.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_ar.xtb index 31de2f8cb75..3443de9d455 100644 --- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_ar.xtb +++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_ar.xtb @@ -6,7 +6,7 @@ <translation id="145360476452865422">سياسة الصور المتحركة:</translation> <translation id="1555130319947370107">أزرق</translation> <translation id="1588438908519853928">عادي</translation> -<translation id="1591070050619849194">عطّل جميع صور الرسوم المتحركة.</translation> +<translation id="1591070050619849194">أوقف جميع صور الرسوم المتحركة.</translation> <translation id="1703735871906654364">التصفح النصي بالمؤشر</translation> <translation id="1791496371305830581">اسمح بجميع الصور المتحركة.</translation> <translation id="1996252509865389616">هل تريد التمكين؟</translation> @@ -21,26 +21,26 @@ <translation id="2965611304828530558"><p>عندما تصل إلى رابط أو عنصر تحكم فإنه يتم التركيز عليه تلقائيًا. انقر على <span class='key'>Enter</span> للنقر على رابط أو زر. </ P> <p> عندما يقوم عنصر تحكم مُركز عليه بالتقاط مفاتيح الأسهم (مثل مربع نص أو مربع قائمة)، اضغط على <span class='key'>Esc</span> SPAN> تليها السهم الأيمن أو الأيسر لمواصلة التصفح النصي بالمؤشر </ P> <P> وبدلاً من ذلك، اضغط <span class='key'>Tab</span> للانتقال إلى عنصر التحكم التالي القابل للتركيز عليه </ P></translation> <translation id="3252573918265662711">الإعداد</translation> <translation id="3410969471888629217">نسيان تخصيصات موقع الويب</translation> -<translation id="3435896845095436175">تمكين الإضافات</translation> -<translation id="3622586652998721735">تعيين كمخطط افتراضي</translation> +<translation id="3435896845095436175">تفعيل الإضافات</translation> +<translation id="3622586652998721735">تعيين كمخطط تلقائي</translation> <translation id="3812541808639806898">عارض النص "Alt" للصورة</translation> <translation id="381767806621926835">انقر بزر الماوس الأيمن على أي شيء يعمل بخاصية "longdesc" أو "aria-describedat" للدخول إلى الوصف المفصل.</translation> <translation id="4023902424053835668">تصفح نص صفحات الويب باستخدام مفاتيح الأسهم.</translation> <translation id="4388820049312272371">أبرز موضع المؤشر بومضة سريعة.</translation> -<translation id="4394049700291259645">تعطيل</translation> +<translation id="4394049700291259645">إيقاف</translation> <translation id="4769065380738716500">تم استبدال الصور بواسطة النص البديل</translation> <translation id="4896660567607030658">لا توجد تعليقات، فقط أعرض المؤشر.</translation> <translation id="4937901943818762779">السماح بالصور المتحركة، ولكن لمرة واحدة فقط.</translation> -<translation id="4954450790315188152">عندما يتم تمكين التصفح النصي بالمؤشر.</translation> +<translation id="4954450790315188152">عندما يتم تفعيل التصفح النصي بالمؤشر.</translation> <translation id="5041932793799765940">تعديل اللون</translation> <translation id="5094574508723441140">زيادة التباين</translation> <translation id="5173942593318174089">أبرز موضع المؤشر بالرسوم المتحركة.</translation> <translation id="5287723860611749454"><p>استخدام مفاتيح الأسهم للتحرك في جميع أنحاء المستند </ P> <P> انقر في أي مكان لتحريك المؤشر إلى ذلك الموقع. </ P> <P> اضغط على <span class='key'>Shift</span> + الأسهم لتحديد النص.</ P></translation> <translation id="5331422999063554397">لون معكوس</translation> -<translation id="5555153510860501336">التباين العالي مُعطل</translation> +<translation id="5555153510860501336">التباين العالي غير مفعّل</translation> <translation id="5558600050691192317">أوامر لوحة المفاتيح</translation> -<translation id="5594989420907487559">شغّل الصور المتحركة مرة واحدة فقط، أو عطّل الصور المتحركة تمامًا.</translation> -<translation id="5631241868147802353">مخطط اللون الافتراضي:</translation> +<translation id="5594989420907487559">شغّل الصور المتحركة مرة واحدة فقط، أو أوقف الصور المتحركة تمامًا.</translation> +<translation id="5631241868147802353">مخطط اللون التلقائي:</translation> <translation id="5650358096585648000">التعليقات البصرية</translation> <translation id="5710185147685935461">تغيير أو عكس نظام الألوان لتسهيل قراءة صفحات الويب.</translation> <translation id="5939518447894949180">إعادة</translation> @@ -54,7 +54,7 @@ <translation id="690628312087070417">عندما يقفز مؤشر النص لمسافة كبيرة:</translation> <translation id="6965382102122355670">موافق</translation> <translation id="7379645913608427028">درجة</translation> -<translation id="7384431257964758081">تم تمكين التباين العالي</translation> +<translation id="7384431257964758081">تم تفعيل التباين العالي</translation> <translation id="7586636300921797327">الخطوة الثانية: ضبط شريط التمرير؛ حتى تكون جميع النجوم مرئية في الصف المحدد</translation> <translation id="7658239707568436148">إلغاء</translation> @@ -65,5 +65,5 @@ <translation id="8321034316479930120">سياسة الصور المتحركة</translation> <translation id="8480209185614411573">تباين مرتفع</translation> <translation id="8609925175482059018">لتشغيل التصفح النصي بالمؤشر انقر فوق <span class='key'>F7</span> ولإيقاف تشغيله انقر فوقه مرة أخرى.</translation> -<translation id="894241283505723656">وصف مفصل في قائمة السياق</translation> +<translation id="894241283505723656">وصف مفصل في قائمة السياقات</translation> </translationbundle>
\ No newline at end of file diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_de.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_de.xtb index 2ac6b2b8284..d810acfeeb1 100644 --- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_de.xtb +++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_de.xtb @@ -35,7 +35,7 @@ <translation id="5041932793799765940">Farbanpassung</translation> <translation id="5094574508723441140">Kontrasterhöhung</translation> <translation id="5173942593318174089">Cursorposition mit Animation markieren</translation> -<translation id="5287723860611749454"><p>Mit den Pfeiltasten können Sie durch das Dokument navigieren. </p><p>Klicken Sie an einer Stelle, um den Cursor dort zu platzieren. </p> <p> Mit <span class='key'>Shift</span> + Pfeiltaste können Sie Text auswählen.</p></translation> +<translation id="5287723860611749454"><p>Mit den Pfeiltasten können Sie durch das Dokument navigieren. </p><p>Klicken Sie an einer Stelle, um den Cursor dort zu platzieren. </p> <p> Mit <span class='key'>Umschalttaste</span> + Pfeiltaste können Sie Text auswählen.</p></translation> <translation id="5331422999063554397">Farbumkehrung</translation> <translation id="5555153510860501336">Hoher Kontrast ist deaktiviert.</translation> <translation id="5558600050691192317">Tastaturbefehle</translation> diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_es-419.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_es-419.xtb index 39649f27dcf..65569b6c1fc 100644 --- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_es-419.xtb +++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_es-419.xtb @@ -58,7 +58,7 @@ <translation id="7586636300921797327">Paso 2. Ajusta el control deslizante hasta que todas las estrellas sean visibles en la fila seleccionada.</translation> <translation id="7658239707568436148">Cancelar</translation> -<translation id="786423340267544509">Agregar límite a elementos con atributos aria-describedat o longdesc</translation> +<translation id="786423340267544509">Agregar borde a elementos con atributos aria-describedat o longdesc</translation> <translation id="7942349550061667556">Rojo</translation> <translation id="8254860724243898966">Presiona <span class='key'>Alt</span> + <img src='increase_brightness.png'> (la tecla de Aumentar brillo o F7) para habilitar la navegación por cursor de texto. Vuelve a presionar la misma tecla para inhabilitarla.</translation> <translation id="8260673944985561857">Opciones de navegación por cursor de texto</translation> diff --git a/chromium/ui/accessibility/platform/aura_window_properties.cc b/chromium/ui/accessibility/platform/aura_window_properties.cc index 20775b9ff1a..e72b2d26e9a 100644 --- a/chromium/ui/accessibility/platform/aura_window_properties.cc +++ b/chromium/ui/accessibility/platform/aura_window_properties.cc @@ -6,7 +6,7 @@ #include "ui/base/class_property.h" -DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AX_EXPORT, AXRole) +DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AX_EXPORT, ax::mojom::Role) namespace ui { @@ -14,6 +14,8 @@ DEFINE_UI_CLASS_PROPERTY_KEY(AXTreeIDRegistry::AXTreeID, kChildAXTreeID, AXTreeIDRegistry::kNoAXTreeID); -DEFINE_UI_CLASS_PROPERTY_KEY(AXRole, kAXRoleOverride, ui::AX_ROLE_NONE); +DEFINE_UI_CLASS_PROPERTY_KEY(ax::mojom::Role, + kAXRoleOverride, + ax::mojom::Role::kNone); } // namespace ui diff --git a/chromium/ui/accessibility/platform/aura_window_properties.h b/chromium/ui/accessibility/platform/aura_window_properties.h index 5f25a8e5c18..c78850da22f 100644 --- a/chromium/ui/accessibility/platform/aura_window_properties.h +++ b/chromium/ui/accessibility/platform/aura_window_properties.h @@ -5,7 +5,7 @@ #ifndef UI_ACCESSIBILITY_PLATFORM_AURA_WINDOW_PROPERTIES_H_ #define UI_ACCESSIBILITY_PLATFORM_AURA_WINDOW_PROPERTIES_H_ -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_tree_id_registry.h" #include "ui/aura/window.h" @@ -15,7 +15,8 @@ namespace ui { AX_EXPORT extern const aura::WindowProperty<AXTreeIDRegistry::AXTreeID>* const kChildAXTreeID; -AX_EXPORT extern const aura::WindowProperty<AXRole>* const kAXRoleOverride; +AX_EXPORT extern const aura::WindowProperty<ax::mojom::Role>* const + kAXRoleOverride; } // namespace ui diff --git a/chromium/ui/accessibility/platform/ax_platform_atk_hyperlink.cc b/chromium/ui/accessibility/platform/ax_platform_atk_hyperlink.cc index 3a66c1d7141..c13f6dbdf5d 100644 --- a/chromium/ui/accessibility/platform/ax_platform_atk_hyperlink.cc +++ b/chromium/ui/accessibility/platform/ax_platform_atk_hyperlink.cc @@ -35,7 +35,8 @@ static gchar* ax_platform_atk_hyperlink_get_uri(AtkHyperlink* atk_hyperlink, if (index != 0) return nullptr; - return g_strdup(obj->GetStringAttribute(ui::AX_ATTR_URL).c_str()); + return g_strdup( + obj->GetStringAttribute(ax::mojom::StringAttribute::kUrl).c_str()); } static AtkObject* ax_platform_atk_hyperlink_get_object( @@ -155,7 +156,8 @@ static const gchar* ax_platform_atk_hyperlink_get_keybinding(AtkAction* action, if (!obj) return nullptr; - return obj->GetStringAttribute(ui::AX_ATTR_ACCESS_KEY).c_str(); + return obj->GetStringAttribute(ax::mojom::StringAttribute::kAccessKey) + .c_str(); } static const gchar* ax_platform_atk_hyperlink_get_name(AtkAction* atk_action, @@ -169,10 +171,11 @@ static const gchar* ax_platform_atk_hyperlink_get_name(AtkAction* atk_action, return nullptr; int action; - if (!obj->GetIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, &action)) + if (!obj->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, + &action)) return nullptr; base::string16 action_verb = ui::ActionVerbToUnlocalizedString( - static_cast<ui::AXDefaultActionVerb>(action)); + static_cast<ax::mojom::DefaultActionVerb>(action)); ATK_AURALINUX_RETURN_STRING(base::UTF16ToUTF8(action_verb)); } @@ -188,10 +191,11 @@ static const gchar* ax_platform_atk_hyperlink_get_localized_name( return nullptr; int action; - if (!obj->GetIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, &action)) + if (!obj->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, + &action)) return nullptr; base::string16 action_verb = ui::ActionVerbToLocalizedString( - static_cast<ui::AXDefaultActionVerb>(action)); + static_cast<ax::mojom::DefaultActionVerb>(action)); ATK_AURALINUX_RETURN_STRING(base::UTF16ToUTF8(action_verb)); } diff --git a/chromium/ui/accessibility/platform/ax_platform_node.h b/chromium/ui/accessibility/platform/ax_platform_node.h index f2e7e7a0556..f723bf064c4 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node.h +++ b/chromium/ui/accessibility/platform/ax_platform_node.h @@ -9,7 +9,7 @@ #include "base/lazy_instance.h" #include "base/observer_list.h" #include "build/build_config.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_mode_observer.h" #include "ui/gfx/native_widget_types.h" @@ -64,7 +64,7 @@ class AX_EXPORT AXPlatformNode { // Fire a platform-specific notification that an event has occurred on // this object. - virtual void NotifyAccessibilityEvent(AXEvent event_type) = 0; + virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type) = 0; // Return this object's delegate. virtual AXPlatformNodeDelegate* GetDelegate() const = 0; diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc index 06bbf6949fd..b502a6786c6 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc @@ -80,12 +80,12 @@ static const gchar* ax_platform_node_auralinux_get_name(AtkObject* atk_object) { if (!obj) return nullptr; - if (obj->GetStringAttribute(ui::AX_ATTR_NAME).empty() && - !(obj->GetIntAttribute(ui::AX_ATTR_NAME_FROM) == - ui::AX_NAME_FROM_ATTRIBUTE_EXPLICITLY_EMPTY)) + ax::mojom::NameFrom name_from = obj->GetData().GetNameFrom(); + if (obj->GetStringAttribute(ax::mojom::StringAttribute::kName).empty() && + name_from != ax::mojom::NameFrom::kAttributeExplicitlyEmpty) return nullptr; - return obj->GetStringAttribute(ui::AX_ATTR_NAME).c_str(); + return obj->GetStringAttribute(ax::mojom::StringAttribute::kName).c_str(); } static const gchar* ax_platform_node_auralinux_get_description( @@ -95,8 +95,8 @@ static const gchar* ax_platform_node_auralinux_get_description( if (!obj) return nullptr; - return obj->GetStringAttribute( - ui::AX_ATTR_DESCRIPTION).c_str(); + return obj->GetStringAttribute(ax::mojom::StringAttribute::kDescription) + .c_str(); } static gint ax_platform_node_auralinux_get_index_in_parent( @@ -374,7 +374,8 @@ static const gchar* ax_platform_node_auralinux_get_action_keybinding( if (!obj) return nullptr; - return obj->GetStringAttribute(ui::AX_ATTR_ACCESS_KEY).c_str(); + return obj->GetStringAttribute(ax::mojom::StringAttribute::kAccessKey) + .c_str(); } void ax_action_interface_base_init(AtkActionIface* iface) { @@ -459,7 +460,8 @@ static const gchar* ax_platform_node_auralinux_get_image_description( if (!obj) return nullptr; - return obj->GetStringAttribute(ui::AX_ATTR_DESCRIPTION).c_str(); + return obj->GetStringAttribute(ax::mojom::StringAttribute::kDescription) + .c_str(); } static void ax_platform_node_auralinux_get_image_size(AtkImage* atk_img, @@ -501,7 +503,8 @@ static void ax_platform_node_auralinux_get_current_value(AtkValue* atk_value, if (!obj) return; - obj->GetFloatAttributeInGValue(ui::AX_ATTR_VALUE_FOR_RANGE, value); + obj->GetFloatAttributeInGValue(ax::mojom::FloatAttribute::kValueForRange, + value); } static void ax_platform_node_auralinux_get_minimum_value(AtkValue* atk_value, @@ -514,7 +517,8 @@ static void ax_platform_node_auralinux_get_minimum_value(AtkValue* atk_value, if (!obj) return; - obj->GetFloatAttributeInGValue(ui::AX_ATTR_MIN_VALUE_FOR_RANGE, value); + obj->GetFloatAttributeInGValue(ax::mojom::FloatAttribute::kMinValueForRange, + value); } static void ax_platform_node_auralinux_get_maximum_value(AtkValue* atk_value, @@ -527,7 +531,8 @@ static void ax_platform_node_auralinux_get_maximum_value(AtkValue* atk_value, if (!obj) return; - obj->GetFloatAttributeInGValue(ui::AX_ATTR_MAX_VALUE_FOR_RANGE, value); + obj->GetFloatAttributeInGValue(ax::mojom::FloatAttribute::kMaxValueForRange, + value); } static void ax_platform_node_auralinux_get_minimum_increment( @@ -541,7 +546,8 @@ static void ax_platform_node_auralinux_get_minimum_increment( if (!obj) return; - obj->GetFloatAttributeInGValue(ui::AX_ATTR_STEP_VALUE_FOR_RANGE, value); + obj->GetFloatAttributeInGValue(ax::mojom::FloatAttribute::kStepValueForRange, + value); } static void ax_value_interface_base_init(AtkValueIface* iface) { @@ -810,13 +816,13 @@ void AXPlatformNodeAuraLinux::StaticInitialize() { AtkRole AXPlatformNodeAuraLinux::GetAtkRole() { switch (GetData().role) { - case ui::AX_ROLE_ALERT: + case ax::mojom::Role::kAlert: return ATK_ROLE_ALERT; - case ui::AX_ROLE_ALERT_DIALOG: + case ax::mojom::Role::kAlertDialog: return ATK_ROLE_ALERT; - case ui::AX_ROLE_APPLICATION: + case ax::mojom::Role::kApplication: return ATK_ROLE_APPLICATION; - case ui::AX_ROLE_AUDIO: + case ax::mojom::Role::kAudio: #if defined(ATK_CHECK_VERSION) #if ATK_CHECK_VERSION(2, 12, 0) return ATK_ROLE_AUDIO; @@ -826,53 +832,62 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() { #else return ATK_ROLE_SECTION; #endif - case ui::AX_ROLE_BUTTON: + case ax::mojom::Role::kButton: return ATK_ROLE_PUSH_BUTTON; - case ui::AX_ROLE_CANVAS: + case ax::mojom::Role::kCanvas: return ATK_ROLE_CANVAS; - case ui::AX_ROLE_CAPTION: + case ax::mojom::Role::kCaption: return ATK_ROLE_CAPTION; - case ui::AX_ROLE_CHECK_BOX: + case ax::mojom::Role::kCheckBox: return ATK_ROLE_CHECK_BOX; - case ui::AX_ROLE_COLOR_WELL: + case ax::mojom::Role::kColorWell: return ATK_ROLE_COLOR_CHOOSER; - case ui::AX_ROLE_COLUMN_HEADER: + case ax::mojom::Role::kColumnHeader: return ATK_ROLE_COLUMN_HEADER; - case ui::AX_ROLE_COMBO_BOX_GROUPING: + case ax::mojom::Role::kComboBoxGrouping: return ATK_ROLE_COMBO_BOX; - case ui::AX_ROLE_COMBO_BOX_MENU_BUTTON: + case ax::mojom::Role::kComboBoxMenuButton: return ATK_ROLE_COMBO_BOX; - case ui::AX_ROLE_DATE: + case ax::mojom::Role::kDate: return ATK_ROLE_DATE_EDITOR; - case ui::AX_ROLE_DATE_TIME: + case ax::mojom::Role::kDateTime: return ATK_ROLE_DATE_EDITOR; - case ui::AX_ROLE_DIALOG: + case ax::mojom::Role::kDialog: return ATK_ROLE_DIALOG; - case ui::AX_ROLE_DOCUMENT: + case ax::mojom::Role::kDocument: return ATK_ROLE_DOCUMENT_WEB; - case ui::AX_ROLE_FORM: + case ax::mojom::Role::kForm: return ATK_ROLE_FORM; - case ui::AX_ROLE_GENERIC_CONTAINER: + case ax::mojom::Role::kGenericContainer: return ATK_ROLE_PANEL; - case ui::AX_ROLE_GROUP: + case ax::mojom::Role::kGroup: return ATK_ROLE_PANEL; - case ui::AX_ROLE_IGNORED: + case ax::mojom::Role::kIgnored: return ATK_ROLE_REDUNDANT_OBJECT; - case ui::AX_ROLE_IMAGE: + case ax::mojom::Role::kImage: return ATK_ROLE_IMAGE; - case ui::AX_ROLE_IMAGE_MAP: + case ax::mojom::Role::kImageMap: return ATK_ROLE_IMAGE_MAP; - case ui::AX_ROLE_LABEL_TEXT: + case ax::mojom::Role::kLabelText: return ATK_ROLE_LABEL; - case ui::AX_ROLE_LINK: + // Layout table objects are treated the same as Role::kGenericContainer. + case ax::mojom::Role::kLayoutTable: + return ATK_ROLE_PANEL; + case ax::mojom::Role::kLayoutTableCell: + return ATK_ROLE_PANEL; + case ax::mojom::Role::kLayoutTableColumn: + return ATK_ROLE_PANEL; + case ax::mojom::Role::kLayoutTableRow: + return ATK_ROLE_PANEL; + case ax::mojom::Role::kLink: return ATK_ROLE_LINK; - case ui::AX_ROLE_LIST: + case ax::mojom::Role::kList: return ATK_ROLE_LIST; - case ui::AX_ROLE_LIST_BOX: + case ax::mojom::Role::kListBox: return ATK_ROLE_LIST_BOX; - case ui::AX_ROLE_LIST_ITEM: + case ax::mojom::Role::kListItem: return ATK_ROLE_LIST_ITEM; - case ui::AX_ROLE_MATH: + case ax::mojom::Role::kMath: #if defined(ATK_CHECK_VERSION) #if ATK_CHECK_VERSION(2, 12, 0) return ATK_ROLE_MATH; @@ -882,61 +897,61 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() { #else return ATK_ROLE_TEXT; #endif - case ui::AX_ROLE_MENU: + case ax::mojom::Role::kMenu: return ATK_ROLE_MENU; - case ui::AX_ROLE_MENU_BAR: + case ax::mojom::Role::kMenuBar: return ATK_ROLE_MENU_BAR; - case ui::AX_ROLE_MENU_ITEM: + case ax::mojom::Role::kMenuItem: return ATK_ROLE_MENU_ITEM; - case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: + case ax::mojom::Role::kMenuItemCheckBox: return ATK_ROLE_CHECK_MENU_ITEM; - case ui::AX_ROLE_MENU_ITEM_RADIO: + case ax::mojom::Role::kMenuItemRadio: return ATK_ROLE_RADIO_MENU_ITEM; - case ui::AX_ROLE_METER: + case ax::mojom::Role::kMeter: return ATK_ROLE_PROGRESS_BAR; - case ui::AX_ROLE_PARAGRAPH: + case ax::mojom::Role::kParagraph: return ATK_ROLE_PARAGRAPH; - case ui::AX_ROLE_RADIO_BUTTON: + case ax::mojom::Role::kRadioButton: return ATK_ROLE_RADIO_BUTTON; - case ui::AX_ROLE_ROW_HEADER: + case ax::mojom::Role::kRowHeader: return ATK_ROLE_ROW_HEADER; - case ui::AX_ROLE_ROOT_WEB_AREA: + case ax::mojom::Role::kRootWebArea: return ATK_ROLE_DOCUMENT_WEB; - case ui::AX_ROLE_SCROLL_BAR: + case ax::mojom::Role::kScrollBar: return ATK_ROLE_SCROLL_BAR; - case ui::AX_ROLE_SLIDER: + case ax::mojom::Role::kSlider: return ATK_ROLE_SLIDER; - case ui::AX_ROLE_SPIN_BUTTON: + case ax::mojom::Role::kSpinButton: return ATK_ROLE_SPIN_BUTTON; - case ui::AX_ROLE_SPLITTER: + case ax::mojom::Role::kSplitter: return ATK_ROLE_SEPARATOR; - case ui::AX_ROLE_STATIC_TEXT: + case ax::mojom::Role::kStaticText: return ATK_ROLE_TEXT; - case ui::AX_ROLE_STATUS: + case ax::mojom::Role::kStatus: return ATK_ROLE_STATUSBAR; - case ui::AX_ROLE_TAB: + case ax::mojom::Role::kTab: return ATK_ROLE_PAGE_TAB; - case ui::AX_ROLE_TABLE: + case ax::mojom::Role::kTable: return ATK_ROLE_TABLE; - case ui::AX_ROLE_TAB_LIST: + case ax::mojom::Role::kTabList: return ATK_ROLE_PAGE_TAB_LIST; - case ui::AX_ROLE_TEXT_FIELD: + case ax::mojom::Role::kTextField: return ATK_ROLE_ENTRY; - case ui::AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX: + case ax::mojom::Role::kTextFieldWithComboBox: return ATK_ROLE_COMBO_BOX; - case ui::AX_ROLE_TOGGLE_BUTTON: + case ax::mojom::Role::kToggleButton: return ATK_ROLE_TOGGLE_BUTTON; - case ui::AX_ROLE_TOOLBAR: + case ax::mojom::Role::kToolbar: return ATK_ROLE_TOOL_BAR; - case ui::AX_ROLE_TOOLTIP: + case ax::mojom::Role::kTooltip: return ATK_ROLE_TOOL_TIP; - case ui::AX_ROLE_TREE: + case ax::mojom::Role::kTree: return ATK_ROLE_TREE; - case ui::AX_ROLE_TREE_ITEM: + case ax::mojom::Role::kTreeItem: return ATK_ROLE_TREE_ITEM; - case ui::AX_ROLE_TREE_GRID: + case ax::mojom::Role::kTreeGrid: return ATK_ROLE_TREE_TABLE; - case ui::AX_ROLE_VIDEO: + case ax::mojom::Role::kVideo: #if defined(ATK_CHECK_VERSION) #if ATK_CHECK_VERSION(2, 12, 0) return ATK_ROLE_VIDEO; @@ -946,9 +961,9 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() { #else return ATK_ROLE_SECTION; #endif - case ui::AX_ROLE_WEB_AREA: + case ax::mojom::Role::kWebArea: return ATK_ROLE_DOCUMENT_WEB; - case ui::AX_ROLE_WINDOW: + case ax::mojom::Role::kWindow: return ATK_ROLE_WINDOW; default: return ATK_ROLE_UNKNOWN; @@ -957,35 +972,34 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() { void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) { AXNodeData data = GetData(); - if (data.HasState(ui::AX_STATE_DEFAULT)) + if (data.HasState(ax::mojom::State::kDefault)) atk_state_set_add_state(atk_state_set, ATK_STATE_DEFAULT); - if (data.HasState(ui::AX_STATE_EDITABLE)) + if (data.HasState(ax::mojom::State::kEditable)) atk_state_set_add_state(atk_state_set, ATK_STATE_EDITABLE); - if (data.HasState(ui::AX_STATE_EXPANDED)) + if (data.HasState(ax::mojom::State::kExpanded)) atk_state_set_add_state(atk_state_set, ATK_STATE_EXPANDED); - if (data.HasState(ui::AX_STATE_FOCUSABLE)) + if (data.HasState(ax::mojom::State::kFocusable)) atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSABLE); #if defined(ATK_CHECK_VERSION) #if ATK_CHECK_VERSION(2, 11, 2) - if (data.HasState(ui::AX_STATE_HASPOPUP)) + if (data.HasState(ax::mojom::State::kHaspopup)) atk_state_set_add_state(atk_state_set, ATK_STATE_HAS_POPUP); #endif #endif - if (data.HasState(ui::AX_STATE_SELECTED)) + if (data.HasState(ax::mojom::State::kSelected)) atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTED); - if (data.HasState(ui::AX_STATE_SELECTABLE)) + if (data.HasState(ax::mojom::State::kSelectable)) atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTABLE); // Checked state - const auto checked_state = static_cast<ui::AXCheckedState>( - GetIntAttribute(ui::AX_ATTR_CHECKED_STATE)); + const auto checked_state = GetData().GetCheckedState(); switch (checked_state) { - case ui::AX_CHECKED_STATE_MIXED: + case ax::mojom::CheckedState::kMixed: atk_state_set_add_state(atk_state_set, ATK_STATE_INDETERMINATE); break; - case ui::AX_CHECKED_STATE_TRUE: + case ax::mojom::CheckedState::kTrue: atk_state_set_add_state(atk_state_set, - data.role == ui::AX_ROLE_TOGGLE_BUTTON + data.role == ax::mojom::Role::kToggleButton ? ATK_STATE_PRESSED : ATK_STATE_CHECKED); break; @@ -993,17 +1007,19 @@ void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) { break; } - switch (GetIntAttribute(ui::AX_ATTR_RESTRICTION)) { - case ui::AX_RESTRICTION_NONE: + switch (GetData().GetRestriction()) { + case ax::mojom::Restriction::kNone: atk_state_set_add_state(atk_state_set, ATK_STATE_ENABLED); break; - case ui::AX_RESTRICTION_READ_ONLY: + case ax::mojom::Restriction::kReadOnly: #if defined(ATK_CHECK_VERSION) #if ATK_CHECK_VERSION(2, 16, 0) atk_state_set_add_state(atk_state_set, ATK_STATE_READ_ONLY); #endif #endif break; + default: + break; } if (delegate_->GetFocus() == GetNativeViewAccessible()) @@ -1093,9 +1109,10 @@ void AXPlatformNodeAuraLinux::OnFocused() { true); } -void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(ui::AXEvent event_type) { +void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent( + ax::mojom::Event event_type) { switch (event_type) { - case AX_EVENT_FOCUS: + case ax::mojom::Event::kFocus: OnFocused(); break; default: @@ -1112,7 +1129,7 @@ int AXPlatformNodeAuraLinux::GetIndexInParent() { void AXPlatformNodeAuraLinux::SetExtentsRelativeToAtkCoordinateType( gint* x, gint* y, gint* width, gint* height, AtkCoordType coord_type) { - gfx::Rect extents = GetBoundsInScreen(); + gfx::Rect extents = delegate_->GetUnclippedScreenBoundsRect(); if (x) *x = extents.x(); @@ -1172,23 +1189,23 @@ AXPlatformNodeAuraLinux::HitTestSync(gint x, gint y, AtkCoordType coord_type) { bool AXPlatformNodeAuraLinux::GrabFocus() { AXActionData action_data; - action_data.action = AX_ACTION_FOCUS; + action_data.action = ax::mojom::Action::kFocus; return delegate_->AccessibilityPerformAction(action_data); } bool AXPlatformNodeAuraLinux::DoDefaultAction() { AXActionData action_data; - action_data.action = AX_ACTION_DO_DEFAULT; + action_data.action = ax::mojom::Action::kDoDefault; return delegate_->AccessibilityPerformAction(action_data); } const gchar* AXPlatformNodeAuraLinux::GetDefaultActionName() { int action; - if (!GetIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, &action)) + if (!GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, &action)) return nullptr; base::string16 action_verb = ui::ActionVerbToUnlocalizedString( - static_cast<ui::AXDefaultActionVerb>(action)); + static_cast<ax::mojom::DefaultActionVerb>(action)); ATK_AURALINUX_RETURN_STRING(base::UTF16ToUTF8(action_verb)); } @@ -1250,8 +1267,9 @@ AtkHyperlink* AXPlatformNodeAuraLinux::GetAtkHyperlink() { // Misc helpers // -void AXPlatformNodeAuraLinux::GetFloatAttributeInGValue(AXFloatAttribute attr, - GValue* value) { +void AXPlatformNodeAuraLinux::GetFloatAttributeInGValue( + ax::mojom::FloatAttribute attr, + GValue* value) { float float_val; if (GetFloatAttribute(attr, &float_val)) { memset(value, 0, sizeof(*value)); diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h index 6eaa14ab84f..e0c31e92000 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h +++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h @@ -70,14 +70,14 @@ class AXPlatformNodeAuraLinux : public AXPlatformNodeBase { AtkHyperlink* GetAtkHyperlink(); // Misc helpers - void GetFloatAttributeInGValue(AXFloatAttribute attr, GValue* value); + void GetFloatAttributeInGValue(ax::mojom::FloatAttribute attr, GValue* value); // Event helpers void OnFocused(); // AXPlatformNode overrides. gfx::NativeViewAccessible GetNativeViewAccessible() override; - void NotifyAccessibilityEvent(ui::AXEvent event_type) override; + void NotifyAccessibilityEvent(ax::mojom::Event event_type) override; // AXPlatformNodeBase overrides. void Init(AXPlatformNodeDelegate* delegate) override; diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc index e20de0f8cdd..b9714a2b866 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc +++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc @@ -87,7 +87,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectName) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectDescription) { AXNodeData root; root.id = 1; - root.AddStringAttribute(AX_ATTR_DESCRIPTION, "Description"); + root.AddStringAttribute(ax::mojom::StringAttribute::kDescription, + "Description"); Init(root); AtkObject* root_obj(GetRootAtkObject()); @@ -111,7 +112,7 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectRole) { Init(root, child); AXNode* child_node = GetRootNode()->children()[0]; - child.role = AX_ROLE_ALERT; + child.role = ax::mojom::Role::kAlert; child_node->SetData(child); AtkObject* child_obj(AtkObjectFromNode(child_node)); ASSERT_TRUE(ATK_IS_OBJECT(child_obj)); @@ -119,7 +120,7 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectRole) { EXPECT_EQ(ATK_ROLE_ALERT, atk_object_get_role(child_obj)); g_object_unref(child_obj); - child.role = AX_ROLE_BUTTON; + child.role = ax::mojom::Role::kButton; child_node->SetData(child); child_obj = AtkObjectFromNode(child_node); ASSERT_TRUE(ATK_IS_OBJECT(child_obj)); @@ -127,7 +128,7 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectRole) { EXPECT_EQ(ATK_ROLE_PUSH_BUTTON, atk_object_get_role(child_obj)); g_object_unref(child_obj); - child.role = AX_ROLE_CANVAS; + child.role = ax::mojom::Role::kCanvas; child_node->SetData(child); child_obj = AtkObjectFromNode(child_node); ASSERT_TRUE(ATK_IS_OBJECT(child_obj)); @@ -139,8 +140,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectRole) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectState) { AXNodeData root; root.id = 1; - root.AddState(AX_STATE_DEFAULT); - root.AddState(AX_STATE_EXPANDED); + root.AddState(ax::mojom::State::kDefault); + root.AddState(ax::mojom::State::kExpanded); Init(root); @@ -165,11 +166,11 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectChildAndParent) { root.child_ids.push_back(3); AXNodeData button; - button.role = AX_ROLE_BUTTON; + button.role = ax::mojom::Role::kButton; button.id = 2; AXNodeData checkbox; - checkbox.role = AX_ROLE_CHECK_BOX; + checkbox.role = ax::mojom::Role::kCheckBox; checkbox.id = 3; Init(root, button, checkbox); @@ -291,7 +292,7 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkComponentRefAtPoint) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkComponentsGetExtentsPositionSize) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_WINDOW; + root.role = ax::mojom::Role::kWindow; root.location = gfx::RectF(10, 40, 800, 600); root.child_ids.push_back(2); @@ -380,8 +381,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkComponentsGetExtentsPositionSize) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetCurrentValue) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_SLIDER; - root.AddFloatAttribute(AX_ATTR_VALUE_FOR_RANGE, 5.0); + root.role = ax::mojom::Role::kSlider; + root.AddFloatAttribute(ax::mojom::FloatAttribute::kValueForRange, 5.0); Init(root); AtkObject* root_obj(GetRootAtkObject()); @@ -402,8 +403,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetCurrentValue) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetMaximumValue) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_SLIDER; - root.AddFloatAttribute(AX_ATTR_MAX_VALUE_FOR_RANGE, 5.0); + root.role = ax::mojom::Role::kSlider; + root.AddFloatAttribute(ax::mojom::FloatAttribute::kMaxValueForRange, 5.0); Init(root); AtkObject* root_obj(GetRootAtkObject()); @@ -424,8 +425,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetMaximumValue) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetMinimumValue) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_SLIDER; - root.AddFloatAttribute(AX_ATTR_MIN_VALUE_FOR_RANGE, 5.0); + root.role = ax::mojom::Role::kSlider; + root.AddFloatAttribute(ax::mojom::FloatAttribute::kMinValueForRange, 5.0); Init(root); AtkObject* root_obj(GetRootAtkObject()); @@ -446,8 +447,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetMinimumValue) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetMinimumIncrement) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_SLIDER; - root.AddFloatAttribute(AX_ATTR_STEP_VALUE_FOR_RANGE, 5.0); + root.role = ax::mojom::Role::kSlider; + root.AddFloatAttribute(ax::mojom::FloatAttribute::kStepValueForRange, 5.0); Init(root); AtkObject* root_obj(GetRootAtkObject()); @@ -472,8 +473,8 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueGetMinimumIncrement) { TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkHyperlink) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_LINK; - root.AddStringAttribute(AX_ATTR_URL, "http://foo.com"); + root.role = ax::mojom::Role::kLink; + root.AddStringAttribute(ax::mojom::StringAttribute::kUrl, "http://foo.com"); Init(root); AtkObject* root_obj(GetRootAtkObject()); diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.cc b/chromium/ui/accessibility/platform/ax_platform_node_base.cc index 97afb682632..613ade4d498 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_base.cc +++ b/chromium/ui/accessibility/platform/ax_platform_node_base.cc @@ -26,12 +26,6 @@ const AXNodeData& AXPlatformNodeBase::GetData() const { return empty_data; } -gfx::Rect AXPlatformNodeBase::GetBoundsInScreen() const { - if (delegate_) - return delegate_->GetScreenBoundsRect(); - return gfx::Rect(); -} - gfx::NativeViewAccessible AXPlatformNodeBase::GetParent() { if (delegate_) return delegate_->GetParent(); @@ -116,107 +110,116 @@ bool AXPlatformNodeBase::IsDescendant(AXPlatformNodeBase* node) { return IsDescendant(parent); } -bool AXPlatformNodeBase::HasBoolAttribute(AXBoolAttribute attribute) const { +bool AXPlatformNodeBase::HasBoolAttribute( + ax::mojom::BoolAttribute attribute) const { if (!delegate_) return false; return GetData().HasBoolAttribute(attribute); } -bool AXPlatformNodeBase::GetBoolAttribute(AXBoolAttribute attribute) const { +bool AXPlatformNodeBase::GetBoolAttribute( + ax::mojom::BoolAttribute attribute) const { if (!delegate_) return false; return GetData().GetBoolAttribute(attribute); } -bool AXPlatformNodeBase::GetBoolAttribute(AXBoolAttribute attribute, +bool AXPlatformNodeBase::GetBoolAttribute(ax::mojom::BoolAttribute attribute, bool* value) const { if (!delegate_) return false; return GetData().GetBoolAttribute(attribute, value); } -bool AXPlatformNodeBase::HasFloatAttribute(AXFloatAttribute attribute) const { +bool AXPlatformNodeBase::HasFloatAttribute( + ax::mojom::FloatAttribute attribute) const { if (!delegate_) return false; return GetData().HasFloatAttribute(attribute); } -float AXPlatformNodeBase::GetFloatAttribute(AXFloatAttribute attribute) const { +float AXPlatformNodeBase::GetFloatAttribute( + ax::mojom::FloatAttribute attribute) const { if (!delegate_) return false; return GetData().GetFloatAttribute(attribute); } -bool AXPlatformNodeBase::GetFloatAttribute(AXFloatAttribute attribute, +bool AXPlatformNodeBase::GetFloatAttribute(ax::mojom::FloatAttribute attribute, float* value) const { if (!delegate_) return false; return GetData().GetFloatAttribute(attribute, value); } -bool AXPlatformNodeBase::HasIntAttribute(AXIntAttribute attribute) const { +bool AXPlatformNodeBase::HasIntAttribute( + ax::mojom::IntAttribute attribute) const { if (!delegate_) return false; return GetData().HasIntAttribute(attribute); } -int AXPlatformNodeBase::GetIntAttribute(AXIntAttribute attribute) const { +int AXPlatformNodeBase::GetIntAttribute( + ax::mojom::IntAttribute attribute) const { if (!delegate_) return false; return GetData().GetIntAttribute(attribute); } -bool AXPlatformNodeBase::GetIntAttribute(AXIntAttribute attribute, +bool AXPlatformNodeBase::GetIntAttribute(ax::mojom::IntAttribute attribute, int* value) const { if (!delegate_) return false; return GetData().GetIntAttribute(attribute, value); } -bool AXPlatformNodeBase::HasStringAttribute(AXStringAttribute attribute) const { +bool AXPlatformNodeBase::HasStringAttribute( + ax::mojom::StringAttribute attribute) const { if (!delegate_) return false; return GetData().HasStringAttribute(attribute); } const std::string& AXPlatformNodeBase::GetStringAttribute( - AXStringAttribute attribute) const { + ax::mojom::StringAttribute attribute) const { CR_DEFINE_STATIC_LOCAL(std::string, empty_data, ()); if (!delegate_) return empty_data; return GetData().GetStringAttribute(attribute); } -bool AXPlatformNodeBase::GetStringAttribute(AXStringAttribute attribute, - std::string* value) const { +bool AXPlatformNodeBase::GetStringAttribute( + ax::mojom::StringAttribute attribute, + std::string* value) const { if (!delegate_) return false; return GetData().GetStringAttribute(attribute, value); } base::string16 AXPlatformNodeBase::GetString16Attribute( - AXStringAttribute attribute) const { + ax::mojom::StringAttribute attribute) const { if (!delegate_) return base::string16(); return GetData().GetString16Attribute(attribute); } -bool AXPlatformNodeBase::GetString16Attribute(AXStringAttribute attribute, - base::string16* value) const { +bool AXPlatformNodeBase::GetString16Attribute( + ax::mojom::StringAttribute attribute, + base::string16* value) const { if (!delegate_) return false; return GetData().GetString16Attribute(attribute, value); } bool AXPlatformNodeBase::HasIntListAttribute( - AXIntListAttribute attribute) const { + ax::mojom::IntListAttribute attribute) const { if (!delegate_) return false; return GetData().HasIntListAttribute(attribute); } const std::vector<int32_t>& AXPlatformNodeBase::GetIntListAttribute( - AXIntListAttribute attribute) const { + ax::mojom::IntListAttribute attribute) const { CR_DEFINE_STATIC_LOCAL(std::vector<int32_t>, empty_data, ()); if (!delegate_) return empty_data; @@ -224,7 +227,7 @@ const std::vector<int32_t>& AXPlatformNodeBase::GetIntListAttribute( } bool AXPlatformNodeBase::GetIntListAttribute( - AXIntListAttribute attribute, + ax::mojom::IntListAttribute attribute, std::vector<int32_t>* value) const { if (!delegate_) return false; @@ -246,7 +249,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::FromNativeViewAccessible( bool AXPlatformNodeBase::SetTextSelection(int start_offset, int end_offset) { AXActionData action_data; - action_data.action = AX_ACTION_SET_SELECTION; + action_data.action = ax::mojom::Action::kSetSelection; action_data.anchor_node_id = action_data.focus_node_id = GetData().id; action_data.anchor_offset = start_offset; action_data.focus_offset = end_offset; @@ -257,30 +260,30 @@ bool AXPlatformNodeBase::SetTextSelection(int start_offset, int end_offset) { } bool AXPlatformNodeBase::IsTextOnlyObject() const { - return GetData().role == AX_ROLE_STATIC_TEXT || - GetData().role == AX_ROLE_LINE_BREAK || - GetData().role == AX_ROLE_INLINE_TEXT_BOX; + return GetData().role == ax::mojom::Role::kStaticText || + GetData().role == ax::mojom::Role::kLineBreak || + GetData().role == ax::mojom::Role::kInlineTextBox; } bool AXPlatformNodeBase::IsPlainTextField() const { // We need to check both the role and editable state, because some ARIA text // fields may in fact not be editable, whilst some editable fields might not // have the role. - return !GetData().HasState(AX_STATE_RICHLY_EDITABLE) && - (GetData().role == AX_ROLE_TEXT_FIELD || - GetData().role == AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX || - GetData().role == AX_ROLE_SEARCH_BOX || - GetBoolAttribute(AX_ATTR_EDITABLE_ROOT)); + return !GetData().HasState(ax::mojom::State::kRichlyEditable) && + (GetData().role == ax::mojom::Role::kTextField || + GetData().role == ax::mojom::Role::kTextFieldWithComboBox || + GetData().role == ax::mojom::Role::kSearchBox || + GetBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot)); } bool AXPlatformNodeBase::IsRichTextField() const { - return GetBoolAttribute(AX_ATTR_EDITABLE_ROOT) && - GetData().HasState(AX_STATE_RICHLY_EDITABLE); + return GetBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot) && + GetData().HasState(ax::mojom::State::kRichlyEditable); } base::string16 AXPlatformNodeBase::GetInnerText() { if (IsTextOnlyObject()) - return GetString16Attribute(AX_ATTR_NAME); + return GetString16Attribute(ax::mojom::StringAttribute::kName); base::string16 text; for (int i = 0; i < GetChildCount(); ++i) { @@ -296,14 +299,14 @@ base::string16 AXPlatformNodeBase::GetInnerText() { bool AXPlatformNodeBase::IsRangeValueSupported() const { switch (GetData().role) { - case AX_ROLE_METER: - case AX_ROLE_PROGRESS_INDICATOR: - case AX_ROLE_SLIDER: - case AX_ROLE_SPIN_BUTTON: - case AX_ROLE_SCROLL_BAR: + case ax::mojom::Role::kMeter: + case ax::mojom::Role::kProgressIndicator: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSpinButton: + case ax::mojom::Role::kScrollBar: return true; - case AX_ROLE_SPLITTER: - return GetData().HasState(AX_STATE_FOCUSABLE); + case ax::mojom::Role::kSplitter: + return GetData().HasState(ax::mojom::State::kFocusable); default: return false; } @@ -311,9 +314,11 @@ bool AXPlatformNodeBase::IsRangeValueSupported() const { base::string16 AXPlatformNodeBase::GetRangeValueText() { float fval; - base::string16 value = GetString16Attribute(AX_ATTR_VALUE); + base::string16 value = + GetString16Attribute(ax::mojom::StringAttribute::kValue); - if (value.empty() && GetFloatAttribute(AX_ATTR_VALUE_FOR_RANGE, &fval)) { + if (value.empty() && + GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange, &fval)) { value = base::NumberToString16(fval); } return value; @@ -343,7 +348,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::GetTableCell(int index) const { if (!table) return nullptr; const std::vector<int32_t>& unique_cell_ids = - table->GetIntListAttribute(AX_ATTR_UNIQUE_CELL_IDS); + table->GetIntListAttribute(ax::mojom::IntListAttribute::kUniqueCellIds); if (index < 0 || index >= static_cast<int>(unique_cell_ids.size())) return nullptr; @@ -369,7 +374,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::GetTableCell(int row, // In contrast to unique cell IDs, these are duplicated whenever a cell spans // multiple columns or rows. const std::vector<int32_t>& cell_ids = - table->GetIntListAttribute(AX_ATTR_CELL_IDS); + table->GetIntListAttribute(ax::mojom::IntListAttribute::kCellIds); DCHECK_EQ(GetTableRowCount() * GetTableColumnCount(), static_cast<int>(cell_ids.size())); int position = row * GetTableColumnCount() + column; @@ -389,7 +394,7 @@ int AXPlatformNodeBase::GetTableCellIndex() const { return -1; const std::vector<int32_t>& unique_cell_ids = - table->GetIntListAttribute(AX_ATTR_UNIQUE_CELL_IDS); + table->GetIntListAttribute(ax::mojom::IntListAttribute::kUniqueCellIds); auto iter = std::find(unique_cell_ids.begin(), unique_cell_ids.end(), GetData().id); if (iter == unique_cell_ids.end()) @@ -399,7 +404,7 @@ int AXPlatformNodeBase::GetTableCellIndex() const { } int AXPlatformNodeBase::GetTableColumn() const { - return GetIntAttribute(AX_ATTR_TABLE_CELL_COLUMN_INDEX); + return GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex); } int AXPlatformNodeBase::GetTableColumnCount() const { @@ -407,7 +412,7 @@ int AXPlatformNodeBase::GetTableColumnCount() const { if (!table) return 0; - return table->GetIntAttribute(AX_ATTR_TABLE_COLUMN_COUNT); + return table->GetIntAttribute(ax::mojom::IntAttribute::kTableColumnCount); } int AXPlatformNodeBase::GetTableColumnSpan() const { @@ -415,13 +420,14 @@ int AXPlatformNodeBase::GetTableColumnSpan() const { return 0; int column_span; - if (GetIntAttribute(AX_ATTR_TABLE_CELL_COLUMN_SPAN, &column_span)) + if (GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan, + &column_span)) return column_span; return 1; } int AXPlatformNodeBase::GetTableRow() const { - return GetIntAttribute(AX_ATTR_TABLE_CELL_ROW_INDEX); + return GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex); } int AXPlatformNodeBase::GetTableRowCount() const { @@ -429,7 +435,7 @@ int AXPlatformNodeBase::GetTableRowCount() const { if (!table) return 0; - return table->GetIntAttribute(AX_ATTR_TABLE_ROW_COUNT); + return table->GetIntAttribute(ax::mojom::IntAttribute::kTableRowCount); } int AXPlatformNodeBase::GetTableRowSpan() const { @@ -437,14 +443,15 @@ int AXPlatformNodeBase::GetTableRowSpan() const { return 0; int row_span; - if (GetIntAttribute(AX_ATTR_TABLE_CELL_ROW_SPAN, &row_span)) + if (GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowSpan, &row_span)) return row_span; return 1; } bool AXPlatformNodeBase::HasCaret() { - if (IsPlainTextField() && HasIntAttribute(ui::AX_ATTR_TEXT_SEL_START) && - HasIntAttribute(ui::AX_ATTR_TEXT_SEL_END)) { + if (IsPlainTextField() && + HasIntAttribute(ax::mojom::IntAttribute::kTextSelStart) && + HasIntAttribute(ax::mojom::IntAttribute::kTextSelEnd)) { return true; } @@ -489,12 +496,12 @@ bool AXPlatformNodeBase::IsLeaf() { // (Note that whilst ARIA buttons can have only presentational children, HTML5 // buttons are allowed to have content.) switch (GetData().role) { - case ui::AX_ROLE_IMAGE: - case ui::AX_ROLE_METER: - case ui::AX_ROLE_SCROLL_BAR: - case ui::AX_ROLE_SLIDER: - case ui::AX_ROLE_SPLITTER: - case ui::AX_ROLE_PROGRESS_INDICATOR: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kMeter: + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kProgressIndicator: return true; default: return false; @@ -525,7 +532,8 @@ base::string16 AXPlatformNodeBase::GetValue() { // On Windows, the value of a document should be its URL. return base::UTF8ToUTF16(delegate_->GetTreeData().url); } - base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); + base::string16 value = + GetString16Attribute(ax::mojom::StringAttribute::kValue); // Some screen readers like Jaws and VoiceOver require a // value to be set in text fields with rich content, even though the same diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.h b/chromium/ui/accessibility/platform/ax_platform_node_base.h index 7a3a93f7cc5..2525833c6c0 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_base.h +++ b/chromium/ui/accessibility/platform/ax_platform_node_base.h @@ -6,7 +6,7 @@ #define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_BASE_H_ #include "base/macros.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/platform/ax_platform_node.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" @@ -22,7 +22,6 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode { // These are simple wrappers to our delegate. const AXNodeData& GetData() const; - gfx::Rect GetBoundsInScreen() const; gfx::NativeViewAccessible GetParent(); int GetChildCount(); gfx::NativeViewAccessible ChildAtIndex(int index); @@ -40,31 +39,33 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode { AXPlatformNodeBase* GetNextSibling(); bool IsDescendant(AXPlatformNodeBase* descendant); - bool HasBoolAttribute(AXBoolAttribute attr) const; - bool GetBoolAttribute(AXBoolAttribute attr) const; - bool GetBoolAttribute(AXBoolAttribute attr, bool* value) const; + bool HasBoolAttribute(ax::mojom::BoolAttribute attr) const; + bool GetBoolAttribute(ax::mojom::BoolAttribute attr) const; + bool GetBoolAttribute(ax::mojom::BoolAttribute attr, bool* value) const; - bool HasFloatAttribute(AXFloatAttribute attr) const; - float GetFloatAttribute(AXFloatAttribute attr) const; - bool GetFloatAttribute(AXFloatAttribute attr, float* value) const; + bool HasFloatAttribute(ax::mojom::FloatAttribute attr) const; + float GetFloatAttribute(ax::mojom::FloatAttribute attr) const; + bool GetFloatAttribute(ax::mojom::FloatAttribute attr, float* value) const; - bool HasIntAttribute(AXIntAttribute attribute) const; - int GetIntAttribute(AXIntAttribute attribute) const; - bool GetIntAttribute(AXIntAttribute attribute, int* value) const; + bool HasIntAttribute(ax::mojom::IntAttribute attribute) const; + int GetIntAttribute(ax::mojom::IntAttribute attribute) const; + bool GetIntAttribute(ax::mojom::IntAttribute attribute, int* value) const; - bool HasStringAttribute(AXStringAttribute attribute) const; - const std::string& GetStringAttribute(AXStringAttribute attribute) const; - bool GetStringAttribute(AXStringAttribute attribute, + bool HasStringAttribute(ax::mojom::StringAttribute attribute) const; + const std::string& GetStringAttribute( + ax::mojom::StringAttribute attribute) const; + bool GetStringAttribute(ax::mojom::StringAttribute attribute, std::string* value) const; - bool GetString16Attribute(AXStringAttribute attribute, + bool GetString16Attribute(ax::mojom::StringAttribute attribute, base::string16* value) const; - base::string16 GetString16Attribute(AXStringAttribute attribute) const; + base::string16 GetString16Attribute( + ax::mojom::StringAttribute attribute) const; - bool HasIntListAttribute(AXIntListAttribute attribute) const; + bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const; const std::vector<int32_t>& GetIntListAttribute( - AXIntListAttribute attribute) const; + ax::mojom::IntListAttribute attribute) const; - bool GetIntListAttribute(AXIntListAttribute attribute, + bool GetIntListAttribute(ax::mojom::IntListAttribute attribute, std::vector<int32_t>* value) const; // Returns the table or ARIA grid if inside one. diff --git a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h index 704bc5e9a4c..3b5bc807e65 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h +++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h @@ -7,7 +7,7 @@ #include <set> -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" #include "ui/accessibility/platform/ax_unique_id.h" #include "ui/gfx/geometry/vector2d.h" @@ -59,8 +59,13 @@ class AX_EXPORT AXPlatformNodeDelegate { // Get the child of a node given a 0-based index. virtual gfx::NativeViewAccessible ChildAtIndex(int index) = 0; - // Get the bounds of this node in screen coordinates. - virtual gfx::Rect GetScreenBoundsRect() const = 0; + // Get the bounds of this node in screen coordinates, applying clipping + // to all bounding boxes so that the resulting rect is within the window. + virtual gfx::Rect GetClippedScreenBoundsRect() const = 0; + + // Get the bounds of this node in screen coordinates without applying + // any clipping; it may be outside of the window or offscreen. + virtual gfx::Rect GetUnclippedScreenBoundsRect() const = 0; // Do a *synchronous* hit test of the given location in global screen // coordinates, and the node within this node's subtree (inclusive) that's @@ -87,15 +92,16 @@ class AX_EXPORT AXPlatformNodeDelegate { // Given a node ID attribute (one where IsNodeIdIntAttribute is true), // and a destination node ID, return a set of all source node IDs that // have that relationship attribute between them and the destination. - virtual std::set<int32_t> GetReverseRelations(AXIntAttribute attr, + virtual std::set<int32_t> GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) = 0; // Given a node ID list attribute (one where // IsNodeIdIntListAttribute is true), and a destination node ID, // return a set of all source node IDs that have that relationship // attribute between them and the destination. - virtual std::set<int32_t> GetReverseRelations(AXIntListAttribute attr, - int32_t dst_id) = 0; + virtual std::set<int32_t> GetReverseRelations( + ax::mojom::IntListAttribute attr, + int32_t dst_id) = 0; virtual const AXUniqueId& GetUniqueId() const = 0; @@ -111,7 +117,7 @@ class AX_EXPORT AXPlatformNodeDelegate { // Actions. // - // Perform an accessibility action, switching on the AXAction + // Perform an accessibility action, switching on the ax::mojom::Action // provided in |data|. virtual bool AccessibilityPerformAction(const AXActionData& data) = 0; diff --git a/chromium/ui/accessibility/platform/ax_platform_node_mac.h b/chromium/ui/accessibility/platform/ax_platform_node_mac.h index 36ee00335e2..0ae797818b0 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_mac.h +++ b/chromium/ui/accessibility/platform/ax_platform_node_mac.h @@ -22,7 +22,7 @@ class AXPlatformNodeMac : public AXPlatformNodeBase { // AXPlatformNode. gfx::NativeViewAccessible GetNativeViewAccessible() override; - void NotifyAccessibilityEvent(ui::AXEvent event_type) override; + void NotifyAccessibilityEvent(ax::mojom::Event event_type) override; // AXPlatformNodeBase. void Destroy() override; @@ -38,7 +38,7 @@ class AXPlatformNodeMac : public AXPlatformNodeBase { // Convenience function to determine whether an internal object role should // expose its accessible name in AXValue (as opposed to AXTitle/AXDescription). -AX_EXPORT bool IsNameExposedInAXValueForRole(AXRole role); +AX_EXPORT bool IsNameExposedInAXValueForRole(ax::mojom::Role role); } // namespace ui @@ -47,13 +47,13 @@ AX_EXPORT // Maps AX roles to native roles. Returns NSAccessibilityUnknownRole if not // found. -+ (NSString*)nativeRoleFromAXRole:(ui::AXRole)role; ++ (NSString*)nativeRoleFromAXRole:(ax::mojom::Role)role; // Maps AX roles to native subroles. Returns nil if not found. -+ (NSString*)nativeSubroleFromAXRole:(ui::AXRole)role; ++ (NSString*)nativeSubroleFromAXRole:(ax::mojom::Role)role; // Maps AX events to native notifications. Returns nil if not found. -+ (NSString*)nativeNotificationFromAXEvent:(ui::AXEvent)event; ++ (NSString*)nativeNotificationFromAXEvent:(ax::mojom::Event)event; - (instancetype)initWithNode:(ui::AXPlatformNodeBase*)node; - (void)detach; diff --git a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm index 4c0b3f9f467..6a439f162f8 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm @@ -20,133 +20,139 @@ namespace { -using RoleMap = std::map<ui::AXRole, NSString*>; -using EventMap = std::map<ui::AXEvent, NSString*>; -using ActionList = std::vector<std::pair<ui::AXAction, NSString*>>; +using RoleMap = std::map<ax::mojom::Role, NSString*>; +using EventMap = std::map<ax::mojom::Event, NSString*>; +using ActionList = std::vector<std::pair<ax::mojom::Action, NSString*>>; RoleMap BuildRoleMap() { const RoleMap::value_type roles[] = { - {ui::AX_ROLE_ABBR, NSAccessibilityGroupRole}, - {ui::AX_ROLE_ALERT, NSAccessibilityGroupRole}, - {ui::AX_ROLE_ALERT_DIALOG, NSAccessibilityGroupRole}, - {ui::AX_ROLE_ANCHOR, NSAccessibilityGroupRole}, - {ui::AX_ROLE_ANNOTATION, NSAccessibilityUnknownRole}, - {ui::AX_ROLE_APPLICATION, NSAccessibilityGroupRole}, - {ui::AX_ROLE_ARTICLE, NSAccessibilityGroupRole}, - {ui::AX_ROLE_AUDIO, NSAccessibilityGroupRole}, - {ui::AX_ROLE_BANNER, NSAccessibilityGroupRole}, - {ui::AX_ROLE_BLOCKQUOTE, NSAccessibilityGroupRole}, - {ui::AX_ROLE_BUTTON, NSAccessibilityButtonRole}, - {ui::AX_ROLE_CANVAS, NSAccessibilityImageRole}, - {ui::AX_ROLE_CAPTION, NSAccessibilityGroupRole}, - {ui::AX_ROLE_CELL, @"AXCell"}, - {ui::AX_ROLE_CHECK_BOX, NSAccessibilityCheckBoxRole}, - {ui::AX_ROLE_COLOR_WELL, NSAccessibilityColorWellRole}, - {ui::AX_ROLE_COLUMN, NSAccessibilityColumnRole}, - {ui::AX_ROLE_COLUMN_HEADER, @"AXCell"}, - {ui::AX_ROLE_COMBO_BOX_GROUPING, NSAccessibilityGroupRole}, - {ui::AX_ROLE_COMBO_BOX_MENU_BUTTON, NSAccessibilityButtonRole}, - {ui::AX_ROLE_COMPLEMENTARY, NSAccessibilityGroupRole}, - {ui::AX_ROLE_CONTENT_INFO, NSAccessibilityGroupRole}, - {ui::AX_ROLE_DATE, @"AXDateField"}, - {ui::AX_ROLE_DATE_TIME, @"AXDateField"}, - {ui::AX_ROLE_DEFINITION, NSAccessibilityGroupRole}, - {ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, NSAccessibilityGroupRole}, - {ui::AX_ROLE_DESCRIPTION_LIST, NSAccessibilityListRole}, - {ui::AX_ROLE_DESCRIPTION_LIST_TERM, NSAccessibilityGroupRole}, - {ui::AX_ROLE_DIALOG, NSAccessibilityGroupRole}, - {ui::AX_ROLE_DETAILS, NSAccessibilityGroupRole}, - {ui::AX_ROLE_DIRECTORY, NSAccessibilityListRole}, + {ax::mojom::Role::kAbbr, NSAccessibilityGroupRole}, + {ax::mojom::Role::kAlert, NSAccessibilityGroupRole}, + {ax::mojom::Role::kAlertDialog, NSAccessibilityGroupRole}, + {ax::mojom::Role::kAnchor, NSAccessibilityGroupRole}, + {ax::mojom::Role::kAnnotation, NSAccessibilityUnknownRole}, + {ax::mojom::Role::kApplication, NSAccessibilityGroupRole}, + {ax::mojom::Role::kArticle, NSAccessibilityGroupRole}, + {ax::mojom::Role::kAudio, NSAccessibilityGroupRole}, + {ax::mojom::Role::kBanner, NSAccessibilityGroupRole}, + {ax::mojom::Role::kBlockquote, NSAccessibilityGroupRole}, + {ax::mojom::Role::kButton, NSAccessibilityButtonRole}, + {ax::mojom::Role::kCanvas, NSAccessibilityImageRole}, + {ax::mojom::Role::kCaption, NSAccessibilityGroupRole}, + {ax::mojom::Role::kCell, @"AXCell"}, + {ax::mojom::Role::kCheckBox, NSAccessibilityCheckBoxRole}, + {ax::mojom::Role::kColorWell, NSAccessibilityColorWellRole}, + {ax::mojom::Role::kColumn, NSAccessibilityColumnRole}, + {ax::mojom::Role::kColumnHeader, @"AXCell"}, + {ax::mojom::Role::kComboBoxGrouping, NSAccessibilityGroupRole}, + {ax::mojom::Role::kComboBoxMenuButton, NSAccessibilityButtonRole}, + {ax::mojom::Role::kComplementary, NSAccessibilityGroupRole}, + {ax::mojom::Role::kContentInfo, NSAccessibilityGroupRole}, + {ax::mojom::Role::kDate, @"AXDateField"}, + {ax::mojom::Role::kDateTime, @"AXDateField"}, + {ax::mojom::Role::kDefinition, NSAccessibilityGroupRole}, + {ax::mojom::Role::kDescriptionListDetail, NSAccessibilityGroupRole}, + {ax::mojom::Role::kDescriptionList, NSAccessibilityListRole}, + {ax::mojom::Role::kDescriptionListTerm, NSAccessibilityGroupRole}, + {ax::mojom::Role::kDialog, NSAccessibilityGroupRole}, + {ax::mojom::Role::kDetails, NSAccessibilityGroupRole}, + {ax::mojom::Role::kDirectory, NSAccessibilityListRole}, // If Mac supports AXExpandedChanged event with // NSAccessibilityDisclosureTriangleRole, We should update - // AX_ROLE_DISCLOSURE_TRIANGLE mapping to + // ax::mojom::Role::kDisclosureTriangle mapping to // NSAccessibilityDisclosureTriangleRole. http://crbug.com/558324 - {ui::AX_ROLE_DISCLOSURE_TRIANGLE, NSAccessibilityButtonRole}, - {ui::AX_ROLE_DOCUMENT, NSAccessibilityGroupRole}, - {ui::AX_ROLE_EMBEDDED_OBJECT, NSAccessibilityGroupRole}, - {ui::AX_ROLE_FIGCAPTION, NSAccessibilityGroupRole}, - {ui::AX_ROLE_FIGURE, NSAccessibilityGroupRole}, - {ui::AX_ROLE_FOOTER, NSAccessibilityGroupRole}, - {ui::AX_ROLE_FORM, NSAccessibilityGroupRole}, - {ui::AX_ROLE_GENERIC_CONTAINER, NSAccessibilityGroupRole}, + {ax::mojom::Role::kDisclosureTriangle, NSAccessibilityButtonRole}, + {ax::mojom::Role::kDocument, NSAccessibilityGroupRole}, + {ax::mojom::Role::kEmbeddedObject, NSAccessibilityGroupRole}, + {ax::mojom::Role::kFigcaption, NSAccessibilityGroupRole}, + {ax::mojom::Role::kFigure, NSAccessibilityGroupRole}, + {ax::mojom::Role::kFooter, NSAccessibilityGroupRole}, + {ax::mojom::Role::kForm, NSAccessibilityGroupRole}, + {ax::mojom::Role::kGenericContainer, NSAccessibilityGroupRole}, // Should be NSAccessibilityGridRole but VoiceOver treating it like // a list as of 10.12.6, so following WebKit and using table role: - {ui::AX_ROLE_GRID, NSAccessibilityTableRole}, // crbug.com/753925 - {ui::AX_ROLE_GROUP, NSAccessibilityGroupRole}, - {ui::AX_ROLE_HEADING, @"AXHeading"}, - {ui::AX_ROLE_IFRAME, NSAccessibilityGroupRole}, - {ui::AX_ROLE_IFRAME_PRESENTATIONAL, NSAccessibilityGroupRole}, - {ui::AX_ROLE_IGNORED, NSAccessibilityUnknownRole}, - {ui::AX_ROLE_IMAGE, NSAccessibilityImageRole}, - {ui::AX_ROLE_IMAGE_MAP, NSAccessibilityGroupRole}, - {ui::AX_ROLE_INPUT_TIME, @"AXTimeField"}, - {ui::AX_ROLE_LABEL_TEXT, NSAccessibilityGroupRole}, - {ui::AX_ROLE_LEGEND, NSAccessibilityGroupRole}, - {ui::AX_ROLE_LINE_BREAK, NSAccessibilityGroupRole}, - {ui::AX_ROLE_LINK, NSAccessibilityLinkRole}, - {ui::AX_ROLE_LIST, NSAccessibilityListRole}, - {ui::AX_ROLE_LIST_BOX, NSAccessibilityListRole}, - {ui::AX_ROLE_LIST_BOX_OPTION, NSAccessibilityStaticTextRole}, - {ui::AX_ROLE_LIST_ITEM, NSAccessibilityGroupRole}, - {ui::AX_ROLE_LIST_MARKER, @"AXListMarker"}, - {ui::AX_ROLE_LOG, NSAccessibilityGroupRole}, - {ui::AX_ROLE_MAIN, NSAccessibilityGroupRole}, - {ui::AX_ROLE_MARK, NSAccessibilityGroupRole}, - {ui::AX_ROLE_MARQUEE, NSAccessibilityGroupRole}, - {ui::AX_ROLE_MATH, NSAccessibilityGroupRole}, - {ui::AX_ROLE_MENU, NSAccessibilityMenuRole}, - {ui::AX_ROLE_MENU_BAR, NSAccessibilityMenuBarRole}, - {ui::AX_ROLE_MENU_BUTTON, NSAccessibilityButtonRole}, - {ui::AX_ROLE_MENU_ITEM, NSAccessibilityMenuItemRole}, - {ui::AX_ROLE_MENU_ITEM_CHECK_BOX, NSAccessibilityMenuItemRole}, - {ui::AX_ROLE_MENU_ITEM_RADIO, NSAccessibilityMenuItemRole}, - {ui::AX_ROLE_MENU_LIST_OPTION, NSAccessibilityMenuItemRole}, - {ui::AX_ROLE_MENU_LIST_POPUP, NSAccessibilityUnknownRole}, - {ui::AX_ROLE_METER, NSAccessibilityProgressIndicatorRole}, - {ui::AX_ROLE_NAVIGATION, NSAccessibilityGroupRole}, - {ui::AX_ROLE_NONE, NSAccessibilityGroupRole}, - {ui::AX_ROLE_NOTE, NSAccessibilityGroupRole}, - {ui::AX_ROLE_PARAGRAPH, NSAccessibilityGroupRole}, - {ui::AX_ROLE_POP_UP_BUTTON, NSAccessibilityPopUpButtonRole}, - {ui::AX_ROLE_PRE, NSAccessibilityGroupRole}, - {ui::AX_ROLE_PRESENTATIONAL, NSAccessibilityGroupRole}, - {ui::AX_ROLE_PROGRESS_INDICATOR, NSAccessibilityProgressIndicatorRole}, - {ui::AX_ROLE_RADIO_BUTTON, NSAccessibilityRadioButtonRole}, - {ui::AX_ROLE_RADIO_GROUP, NSAccessibilityRadioGroupRole}, - {ui::AX_ROLE_REGION, NSAccessibilityGroupRole}, - {ui::AX_ROLE_ROOT_WEB_AREA, @"AXWebArea"}, - {ui::AX_ROLE_ROW, NSAccessibilityRowRole}, - {ui::AX_ROLE_ROW_HEADER, @"AXCell"}, - {ui::AX_ROLE_SCROLL_BAR, NSAccessibilityScrollBarRole}, - {ui::AX_ROLE_SEARCH, NSAccessibilityGroupRole}, - {ui::AX_ROLE_SEARCH_BOX, NSAccessibilityTextFieldRole}, - {ui::AX_ROLE_SLIDER, NSAccessibilitySliderRole}, - {ui::AX_ROLE_SLIDER_THUMB, NSAccessibilityValueIndicatorRole}, - {ui::AX_ROLE_SPIN_BUTTON, NSAccessibilityIncrementorRole}, - {ui::AX_ROLE_SPLITTER, NSAccessibilitySplitterRole}, - {ui::AX_ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole}, - {ui::AX_ROLE_STATUS, NSAccessibilityGroupRole}, - {ui::AX_ROLE_SVG_ROOT, NSAccessibilityGroupRole}, - {ui::AX_ROLE_SWITCH, NSAccessibilityCheckBoxRole}, - {ui::AX_ROLE_TAB, NSAccessibilityRadioButtonRole}, - {ui::AX_ROLE_TABLE, NSAccessibilityTableRole}, - {ui::AX_ROLE_TABLE_HEADER_CONTAINER, NSAccessibilityGroupRole}, - {ui::AX_ROLE_TAB_LIST, NSAccessibilityTabGroupRole}, - {ui::AX_ROLE_TAB_PANEL, NSAccessibilityGroupRole}, - {ui::AX_ROLE_TERM, NSAccessibilityGroupRole}, - {ui::AX_ROLE_TEXT_FIELD, NSAccessibilityTextFieldRole}, - {ui::AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX, NSAccessibilityComboBoxRole}, - {ui::AX_ROLE_TIME, NSAccessibilityGroupRole}, - {ui::AX_ROLE_TIMER, NSAccessibilityGroupRole}, - {ui::AX_ROLE_TOGGLE_BUTTON, NSAccessibilityCheckBoxRole}, - {ui::AX_ROLE_TOOLBAR, NSAccessibilityToolbarRole}, - {ui::AX_ROLE_TOOLTIP, NSAccessibilityGroupRole}, - {ui::AX_ROLE_TREE, NSAccessibilityOutlineRole}, - {ui::AX_ROLE_TREE_GRID, NSAccessibilityTableRole}, - {ui::AX_ROLE_TREE_ITEM, NSAccessibilityRowRole}, - {ui::AX_ROLE_VIDEO, NSAccessibilityGroupRole}, - {ui::AX_ROLE_WEB_AREA, @"AXWebArea"}, - {ui::AX_ROLE_WINDOW, NSAccessibilityWindowRole}, + {ax::mojom::Role::kGrid, NSAccessibilityTableRole}, // crbug.com/753925 + {ax::mojom::Role::kGroup, NSAccessibilityGroupRole}, + {ax::mojom::Role::kHeading, @"AXHeading"}, + {ax::mojom::Role::kIframe, NSAccessibilityGroupRole}, + {ax::mojom::Role::kIframePresentational, NSAccessibilityGroupRole}, + {ax::mojom::Role::kIgnored, NSAccessibilityUnknownRole}, + {ax::mojom::Role::kImage, NSAccessibilityImageRole}, + {ax::mojom::Role::kImageMap, NSAccessibilityGroupRole}, + {ax::mojom::Role::kInputTime, @"AXTimeField"}, + {ax::mojom::Role::kLabelText, NSAccessibilityGroupRole}, + {ax::mojom::Role::kLayoutTable, NSAccessibilityGroupRole}, + {ax::mojom::Role::kLayoutTableCell, NSAccessibilityGroupRole}, + {ax::mojom::Role::kLayoutTableColumn, NSAccessibilityGroupRole}, + {ax::mojom::Role::kLayoutTableRow, NSAccessibilityGroupRole}, + {ax::mojom::Role::kLegend, NSAccessibilityGroupRole}, + {ax::mojom::Role::kLineBreak, NSAccessibilityGroupRole}, + {ax::mojom::Role::kLink, NSAccessibilityLinkRole}, + {ax::mojom::Role::kList, NSAccessibilityListRole}, + {ax::mojom::Role::kListBox, NSAccessibilityListRole}, + {ax::mojom::Role::kListBoxOption, NSAccessibilityStaticTextRole}, + {ax::mojom::Role::kListItem, NSAccessibilityGroupRole}, + {ax::mojom::Role::kListMarker, @"AXListMarker"}, + {ax::mojom::Role::kLog, NSAccessibilityGroupRole}, + {ax::mojom::Role::kMain, NSAccessibilityGroupRole}, + {ax::mojom::Role::kMark, NSAccessibilityGroupRole}, + {ax::mojom::Role::kMarquee, NSAccessibilityGroupRole}, + {ax::mojom::Role::kMath, NSAccessibilityGroupRole}, + {ax::mojom::Role::kMenu, NSAccessibilityMenuRole}, + {ax::mojom::Role::kMenuBar, NSAccessibilityMenuBarRole}, + {ax::mojom::Role::kMenuButton, NSAccessibilityButtonRole}, + {ax::mojom::Role::kMenuItem, NSAccessibilityMenuItemRole}, + {ax::mojom::Role::kMenuItemCheckBox, NSAccessibilityMenuItemRole}, + {ax::mojom::Role::kMenuItemRadio, NSAccessibilityMenuItemRole}, + {ax::mojom::Role::kMenuListOption, NSAccessibilityMenuItemRole}, + {ax::mojom::Role::kMenuListPopup, NSAccessibilityUnknownRole}, + {ax::mojom::Role::kMeter, NSAccessibilityProgressIndicatorRole}, + {ax::mojom::Role::kNavigation, NSAccessibilityGroupRole}, + {ax::mojom::Role::kNone, NSAccessibilityGroupRole}, + {ax::mojom::Role::kNote, NSAccessibilityGroupRole}, + {ax::mojom::Role::kParagraph, NSAccessibilityGroupRole}, + {ax::mojom::Role::kPopUpButton, NSAccessibilityPopUpButtonRole}, + {ax::mojom::Role::kPre, NSAccessibilityGroupRole}, + {ax::mojom::Role::kPresentational, NSAccessibilityGroupRole}, + {ax::mojom::Role::kProgressIndicator, + NSAccessibilityProgressIndicatorRole}, + {ax::mojom::Role::kRadioButton, NSAccessibilityRadioButtonRole}, + {ax::mojom::Role::kRadioGroup, NSAccessibilityRadioGroupRole}, + {ax::mojom::Role::kRegion, NSAccessibilityGroupRole}, + {ax::mojom::Role::kRootWebArea, @"AXWebArea"}, + {ax::mojom::Role::kRow, NSAccessibilityRowRole}, + {ax::mojom::Role::kRowHeader, @"AXCell"}, + {ax::mojom::Role::kScrollBar, NSAccessibilityScrollBarRole}, + {ax::mojom::Role::kSearch, NSAccessibilityGroupRole}, + {ax::mojom::Role::kSearchBox, NSAccessibilityTextFieldRole}, + {ax::mojom::Role::kSlider, NSAccessibilitySliderRole}, + {ax::mojom::Role::kSliderThumb, NSAccessibilityValueIndicatorRole}, + {ax::mojom::Role::kSpinButton, NSAccessibilityIncrementorRole}, + {ax::mojom::Role::kSplitter, NSAccessibilitySplitterRole}, + {ax::mojom::Role::kStaticText, NSAccessibilityStaticTextRole}, + {ax::mojom::Role::kStatus, NSAccessibilityGroupRole}, + {ax::mojom::Role::kSvgRoot, NSAccessibilityGroupRole}, + {ax::mojom::Role::kSwitch, NSAccessibilityCheckBoxRole}, + {ax::mojom::Role::kTab, NSAccessibilityRadioButtonRole}, + {ax::mojom::Role::kTable, NSAccessibilityTableRole}, + {ax::mojom::Role::kTableHeaderContainer, NSAccessibilityGroupRole}, + {ax::mojom::Role::kTabList, NSAccessibilityTabGroupRole}, + {ax::mojom::Role::kTabPanel, NSAccessibilityGroupRole}, + {ax::mojom::Role::kTerm, NSAccessibilityGroupRole}, + {ax::mojom::Role::kTextField, NSAccessibilityTextFieldRole}, + {ax::mojom::Role::kTextFieldWithComboBox, NSAccessibilityComboBoxRole}, + {ax::mojom::Role::kTime, NSAccessibilityGroupRole}, + {ax::mojom::Role::kTimer, NSAccessibilityGroupRole}, + {ax::mojom::Role::kTitleBar, NSAccessibilityStaticTextRole}, + {ax::mojom::Role::kToggleButton, NSAccessibilityCheckBoxRole}, + {ax::mojom::Role::kToolbar, NSAccessibilityToolbarRole}, + {ax::mojom::Role::kTooltip, NSAccessibilityGroupRole}, + {ax::mojom::Role::kTree, NSAccessibilityOutlineRole}, + {ax::mojom::Role::kTreeGrid, NSAccessibilityTableRole}, + {ax::mojom::Role::kTreeItem, NSAccessibilityRowRole}, + {ax::mojom::Role::kVideo, NSAccessibilityGroupRole}, + {ax::mojom::Role::kWebArea, @"AXWebArea"}, + {ax::mojom::Role::kWindow, NSAccessibilityWindowRole}, }; return RoleMap(begin(roles), end(roles)); @@ -154,37 +160,37 @@ RoleMap BuildRoleMap() { RoleMap BuildSubroleMap() { const RoleMap::value_type subroles[] = { - {ui::AX_ROLE_ALERT, @"AXApplicationAlert"}, - {ui::AX_ROLE_ALERT_DIALOG, @"AXApplicationAlertDialog"}, - {ui::AX_ROLE_APPLICATION, @"AXLandmarkApplication"}, - {ui::AX_ROLE_ARTICLE, @"AXDocumentArticle"}, - {ui::AX_ROLE_BANNER, @"AXLandmarkBanner"}, - {ui::AX_ROLE_COMPLEMENTARY, @"AXLandmarkComplementary"}, - {ui::AX_ROLE_CONTENT_INFO, @"AXLandmarkContentInfo"}, - {ui::AX_ROLE_DEFINITION, @"AXDefinition"}, - {ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, @"AXDefinition"}, - {ui::AX_ROLE_DESCRIPTION_LIST_TERM, @"AXTerm"}, - {ui::AX_ROLE_DIALOG, @"AXApplicationDialog"}, - {ui::AX_ROLE_DOCUMENT, @"AXDocument"}, - {ui::AX_ROLE_FOOTER, @"AXLandmarkContentInfo"}, - {ui::AX_ROLE_FORM, @"AXLandmarkForm"}, - {ui::AX_ROLE_LOG, @"AXApplicationLog"}, - {ui::AX_ROLE_MAIN, @"AXLandmarkMain"}, - {ui::AX_ROLE_MARQUEE, @"AXApplicationMarquee"}, - {ui::AX_ROLE_MATH, @"AXDocumentMath"}, - {ui::AX_ROLE_NAVIGATION, @"AXLandmarkNavigation"}, - {ui::AX_ROLE_NOTE, @"AXDocumentNote"}, - {ui::AX_ROLE_REGION, @"AXDocumentRegion"}, - {ui::AX_ROLE_SEARCH, @"AXLandmarkSearch"}, - {ui::AX_ROLE_SEARCH_BOX, @"AXSearchField"}, - {ui::AX_ROLE_STATUS, @"AXApplicationStatus"}, - {ui::AX_ROLE_SWITCH, @"AXSwitch"}, - {ui::AX_ROLE_TAB_PANEL, @"AXTabPanel"}, - {ui::AX_ROLE_TERM, @"AXTerm"}, - {ui::AX_ROLE_TIMER, @"AXApplicationTimer"}, - {ui::AX_ROLE_TOGGLE_BUTTON, @"AXToggleButton"}, - {ui::AX_ROLE_TOOLTIP, @"AXUserInterfaceTooltip"}, - {ui::AX_ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole}, + {ax::mojom::Role::kAlert, @"AXApplicationAlert"}, + {ax::mojom::Role::kAlertDialog, @"AXApplicationAlertDialog"}, + {ax::mojom::Role::kApplication, @"AXLandmarkApplication"}, + {ax::mojom::Role::kArticle, @"AXDocumentArticle"}, + {ax::mojom::Role::kBanner, @"AXLandmarkBanner"}, + {ax::mojom::Role::kComplementary, @"AXLandmarkComplementary"}, + {ax::mojom::Role::kContentInfo, @"AXLandmarkContentInfo"}, + {ax::mojom::Role::kDefinition, @"AXDefinition"}, + {ax::mojom::Role::kDescriptionListDetail, @"AXDefinition"}, + {ax::mojom::Role::kDescriptionListTerm, @"AXTerm"}, + {ax::mojom::Role::kDialog, @"AXApplicationDialog"}, + {ax::mojom::Role::kDocument, @"AXDocument"}, + {ax::mojom::Role::kFooter, @"AXLandmarkContentInfo"}, + {ax::mojom::Role::kForm, @"AXLandmarkForm"}, + {ax::mojom::Role::kLog, @"AXApplicationLog"}, + {ax::mojom::Role::kMain, @"AXLandmarkMain"}, + {ax::mojom::Role::kMarquee, @"AXApplicationMarquee"}, + {ax::mojom::Role::kMath, @"AXDocumentMath"}, + {ax::mojom::Role::kNavigation, @"AXLandmarkNavigation"}, + {ax::mojom::Role::kNote, @"AXDocumentNote"}, + {ax::mojom::Role::kRegion, @"AXDocumentRegion"}, + {ax::mojom::Role::kSearch, @"AXLandmarkSearch"}, + {ax::mojom::Role::kSearchBox, @"AXSearchField"}, + {ax::mojom::Role::kStatus, @"AXApplicationStatus"}, + {ax::mojom::Role::kSwitch, @"AXSwitch"}, + {ax::mojom::Role::kTabPanel, @"AXTabPanel"}, + {ax::mojom::Role::kTerm, @"AXTerm"}, + {ax::mojom::Role::kTimer, @"AXApplicationTimer"}, + {ax::mojom::Role::kToggleButton, @"AXToggleButton"}, + {ax::mojom::Role::kTooltip, @"AXUserInterfaceTooltip"}, + {ax::mojom::Role::kTreeItem, NSAccessibilityOutlineRowSubrole}, }; return RoleMap(begin(subroles), end(subroles)); @@ -192,10 +198,12 @@ RoleMap BuildSubroleMap() { EventMap BuildEventMap() { const EventMap::value_type events[] = { - {ui::AX_EVENT_FOCUS, NSAccessibilityFocusedUIElementChangedNotification}, - {ui::AX_EVENT_TEXT_CHANGED, NSAccessibilityTitleChangedNotification}, - {ui::AX_EVENT_VALUE_CHANGED, NSAccessibilityValueChangedNotification}, - {ui::AX_EVENT_TEXT_SELECTION_CHANGED, + {ax::mojom::Event::kFocus, + NSAccessibilityFocusedUIElementChangedNotification}, + {ax::mojom::Event::kTextChanged, NSAccessibilityTitleChangedNotification}, + {ax::mojom::Event::kValueChanged, + NSAccessibilityValueChangedNotification}, + {ax::mojom::Event::kTextSelectionChanged, NSAccessibilitySelectedTextChangedNotification}, // TODO(patricialor): Add more events. }; @@ -206,11 +214,11 @@ EventMap BuildEventMap() { ActionList BuildActionList() { const ActionList::value_type entries[] = { // NSAccessibilityPressAction must come first in this list. - {ui::AX_ACTION_DO_DEFAULT, NSAccessibilityPressAction}, + {ax::mojom::Action::kDoDefault, NSAccessibilityPressAction}, - {ui::AX_ACTION_DECREMENT, NSAccessibilityDecrementAction}, - {ui::AX_ACTION_INCREMENT, NSAccessibilityIncrementAction}, - {ui::AX_ACTION_SHOW_CONTEXT_MENU, NSAccessibilityShowMenuAction}, + {ax::mojom::Action::kDecrement, NSAccessibilityDecrementAction}, + {ax::mojom::Action::kIncrement, NSAccessibilityIncrementAction}, + {ax::mojom::Action::kShowContextMenu, NSAccessibilityShowMenuAction}, }; return ActionList(begin(entries), end(entries)); } @@ -220,30 +228,31 @@ const ActionList& GetActionList() { return action_map; } -void NotifyMacEvent(AXPlatformNodeCocoa* target, ui::AXEvent event_type) { +void NotifyMacEvent(AXPlatformNodeCocoa* target, ax::mojom::Event event_type) { NSAccessibilityPostNotification( target, [AXPlatformNodeCocoa nativeNotificationFromAXEvent:event_type]); } // Returns true if |action| should be added implicitly for |data|. -bool HasImplicitAction(const ui::AXNodeData& data, ui::AXAction action) { - return action == ui::AX_ACTION_DO_DEFAULT && ui::IsRoleClickable(data.role); +bool HasImplicitAction(const ui::AXNodeData& data, ax::mojom::Action action) { + return action == ax::mojom::Action::kDoDefault && + ui::IsRoleClickable(data.role); } // For roles that show a menu for the default action, ensure "show menu" also // appears in available actions, but only if that's not already used for a // context menu. It will be mapped back to the default action when performed. bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { - return HasImplicitAction(data, ui::AX_ACTION_DO_DEFAULT) && - !data.HasAction(ui::AX_ACTION_SHOW_CONTEXT_MENU) && - data.role == ui::AX_ROLE_POP_UP_BUTTON; + return HasImplicitAction(data, ax::mojom::Action::kDoDefault) && + !data.HasAction(ax::mojom::Action::kShowContextMenu) && + data.role == ax::mojom::Role::kPopUpButton; } } // namespace @interface AXPlatformNodeCocoa () // Helper function for string attributes that don't require extra processing. -- (NSString*)getStringAttribute:(ui::AXStringAttribute)attribute; +- (NSString*)getStringAttribute:(ax::mojom::StringAttribute)attribute; // Returns AXValue, or nil if AXValue isn't an NSString. - (NSString*)getAXValueAsString; @end @@ -254,19 +263,19 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { @synthesize node = node_; -+ (NSString*)nativeRoleFromAXRole:(ui::AXRole)role { ++ (NSString*)nativeRoleFromAXRole:(ax::mojom::Role)role { CR_DEFINE_STATIC_LOCAL(const RoleMap, role_map, (BuildRoleMap())); RoleMap::const_iterator it = role_map.find(role); return it != role_map.end() ? it->second : NSAccessibilityUnknownRole; } -+ (NSString*)nativeSubroleFromAXRole:(ui::AXRole)role { ++ (NSString*)nativeSubroleFromAXRole:(ax::mojom::Role)role { CR_DEFINE_STATIC_LOCAL(const RoleMap, subrole_map, (BuildSubroleMap())); RoleMap::const_iterator it = subrole_map.find(role); return it != subrole_map.end() ? it->second : nil; } -+ (NSString*)nativeNotificationFromAXEvent:(ui::AXEvent)event { ++ (NSString*)nativeNotificationFromAXEvent:(ax::mojom::Event)event { CR_DEFINE_STATIC_LOCAL(const EventMap, event_map, (BuildEventMap())); EventMap::const_iterator it = event_map.find(event); return it != event_map.end() ? it->second : nil; @@ -288,12 +297,13 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { } - (NSRect)boundsInScreen { - if (!node_) + if (!node_ || !node_->GetDelegate()) return NSZeroRect; - return gfx::ScreenRectToNSRect(node_->GetBoundsInScreen()); + return gfx::ScreenRectToNSRect( + node_->GetDelegate()->GetClippedScreenBoundsRect()); } -- (NSString*)getStringAttribute:(ui::AXStringAttribute)attribute { +- (NSString*)getStringAttribute:(ax::mojom::StringAttribute)attribute { std::string attributeValue; if (node_->GetStringAttribute(attribute, &attributeValue)) return base::SysUTF8ToNSString(attributeValue); @@ -312,7 +322,7 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { return YES; return [[self AXRole] isEqualToString:NSAccessibilityUnknownRole] || - node_->GetData().HasState(ui::AX_STATE_INVISIBLE); + node_->GetData().HasState(ax::mojom::State::kInvisible); } - (id)accessibilityHitTest:(NSPoint)point { @@ -366,7 +376,7 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { ui::AXActionData data; if ([action isEqualToString:NSAccessibilityShowMenuAction] && AlsoUseShowMenuActionForDefaultAction(node_->GetData())) { - data.action = ui::AX_ACTION_DO_DEFAULT; + data.action = ax::mojom::Action::kDoDefault; } else { for (const ActionList::value_type& entry : GetActionList()) { if ([action isEqualToString:entry.second]) { @@ -380,7 +390,7 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { // are already implemented in -accessibilitySetValue:forAttribute:, so ignore // those here. - if (data.action != ui::AX_ACTION_NONE) + if (data.action != ax::mojom::Action::kNone) node_->GetDelegate()->AccessibilityPerformAction(data); } @@ -431,22 +441,22 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { [axAttributes addObjectsFromArray:kAllRoleAttributes]; switch (node_->GetData().role) { - case ui::AX_ROLE_TEXT_FIELD: - case ui::AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX: - case ui::AX_ROLE_STATIC_TEXT: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kStaticText: [axAttributes addObject:kTextAttributes]; - if (!node_->GetData().HasState(ui::AX_STATE_PROTECTED)) + if (!node_->GetData().HasState(ax::mojom::State::kProtected)) [axAttributes addObjectsFromArray:kUnprotectedTextAttributes]; - // Fallthrough. - case ui::AX_ROLE_CHECK_BOX: - case ui::AX_ROLE_COMBO_BOX_MENU_BUTTON: - case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: - case ui::AX_ROLE_MENU_ITEM_RADIO: - case ui::AX_ROLE_RADIO_BUTTON: - case ui::AX_ROLE_SEARCH_BOX: - case ui::AX_ROLE_SLIDER: - case ui::AX_ROLE_SLIDER_THUMB: - case ui::AX_ROLE_TOGGLE_BUTTON: + FALLTHROUGH; + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: + case ax::mojom::Role::kRadioButton: + case ax::mojom::Role::kSearchBox: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSliderThumb: + case ax::mojom::Role::kToggleButton: [axAttributes addObjectsFromArray:kValueAttributes]; break; // TODO(tapted): Add additional attributes based on role. @@ -473,8 +483,8 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { ] retain]; switch (node_->GetData().role) { - case ui::AX_ROLE_TEXT_FIELD: - case ui::AX_ROLE_STATIC_TEXT: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kStaticText: return kSelectableTextAttributes; default: break; @@ -486,9 +496,8 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { if (!node_) return NO; - const int restriction = - node_->GetData().GetIntAttribute(ui::AX_ATTR_RESTRICTION); - if (restriction == ui::AX_RESTRICTION_DISABLED) + const ax::mojom::Restriction restriction = node_->GetData().GetRestriction(); + if (restriction == ax::mojom::Restriction::kDisabled) return NO; // Allow certain attributes to be written via an accessibility client. A @@ -504,10 +513,10 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { if ([attributeName isEqualToString:NSAccessibilityValueAttribute]) { // Since tabs use the Radio Button role on Mac, the standard way to set // them is via the value attribute rather than the selected attribute. - if (node_->GetData().role == ui::AX_ROLE_TAB) - return !node_->GetData().HasState(ui::AX_STATE_SELECTED); + if (node_->GetData().role == ax::mojom::Role::kTab) + return !node_->GetData().HasState(ax::mojom::State::kSelected); - return restriction != ui::AX_RESTRICTION_READ_ONLY; + return restriction != ax::mojom::Restriction::kReadOnly; } // Readonly fields and selected text operations: @@ -517,10 +526,10 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { // NSAccessibilitySelectedTextAttribute is prevented, which is correct. if ([attributeName isEqualToString:NSAccessibilitySelectedTextAttribute] || [attributeName isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) - return restriction != ui::AX_RESTRICTION_READ_ONLY; + return restriction != ax::mojom::Restriction::kReadOnly; if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { - return node_->GetData().HasState(ui::AX_STATE_FOCUSABLE); + return node_->GetData().HasState(ax::mojom::State::kFocusable); } // TODO(patricialor): Add callbacks for updating the above attributes except @@ -537,32 +546,32 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { // Check for attributes first. Only the |data.action| should be set here - any // type-specific information, if needed, should be set below. if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { - data.action = node_->GetData().role == ui::AX_ROLE_TAB - ? ui::AX_ACTION_SET_SELECTION - : ui::AX_ACTION_SET_VALUE; + data.action = node_->GetData().role == ax::mojom::Role::kTab + ? ax::mojom::Action::kSetSelection + : ax::mojom::Action::kSetValue; } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { - data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; + data.action = ax::mojom::Action::kReplaceSelectedText; } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { - data.action = ui::AX_ACTION_SET_SELECTION; + data.action = ax::mojom::Action::kSetSelection; } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { if ([value isKindOfClass:[NSNumber class]]) { - data.action = - [value boolValue] ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; + data.action = [value boolValue] ? ax::mojom::Action::kFocus + : ax::mojom::Action::kBlur; } } // Set type-specific information as necessary for actions set above. if ([value isKindOfClass:[NSString class]]) { data.value = base::SysNSStringToUTF16(value); - } else if (data.action == ui::AX_ACTION_SET_SELECTION && + } else if (data.action == ax::mojom::Action::kSetSelection && [value isKindOfClass:[NSValue class]]) { NSRange range = [value rangeValue]; data.anchor_offset = range.location; data.focus_offset = NSMaxRange(range); } - if (data.action != ui::AX_ACTION_NONE) + if (data.action != ax::mojom::Action::kNone) node_->GetDelegate()->AccessibilityPerformAction(data); // TODO(patricialor): Plumb through all the other writable attributes as @@ -571,7 +580,7 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { - (id)accessibilityAttributeValue:(NSString*)attribute { if (!node_) - return nil; // Return nil when detached. Even for AXRole. + return nil; // Return nil when detached. Even for ax::mojom::Role. SEL selector = NSSelectorFromString(attribute); if ([self respondsToSelector:selector]) @@ -602,12 +611,12 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { - (NSString*)AXRoleDescription { switch (node_->GetData().role) { - case ui::AX_ROLE_TAB: + case ax::mojom::Role::kTab: // There is no NSAccessibilityTabRole or similar (AXRadioButton is used // instead). Do the same as NSTabView and put "tab" in the description. return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION) lowercaseString]; - case ui::AX_ROLE_DISCLOSURE_TRIANGLE: + case ax::mojom::Role::kDisclosureTriangle: return [l10n_util::GetNSStringWithFixup( IDS_ACCNAME_DISCLOSURE_TRIANGLE_ROLE_DESCRIPTION) lowercaseString]; default: @@ -617,10 +626,10 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { } - (NSString*)AXSubrole { - ui::AXRole role = node_->GetData().role; + ax::mojom::Role role = node_->GetData().role; switch (role) { - case ui::AX_ROLE_TEXT_FIELD: - if (node_->GetData().HasState(ui::AX_STATE_PROTECTED)) + case ax::mojom::Role::kTextField: + if (node_->GetData().HasState(ax::mojom::State::kProtected)) return NSAccessibilitySecureTextFieldSubrole; break; default: @@ -633,8 +642,10 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { // TODO(aleventhal) Key shortcuts attribute should eventually get // its own field. Follow what WebKit does for aria-keyshortcuts, see // https://bugs.webkit.org/show_bug.cgi?id=159215 (WebKit bug). - NSString* desc = [self getStringAttribute:ui::AX_ATTR_DESCRIPTION]; - NSString* key = [self getStringAttribute:ui::AX_ATTR_KEY_SHORTCUTS]; + NSString* desc = + [self getStringAttribute:ax::mojom::StringAttribute::kDescription]; + NSString* key = + [self getStringAttribute:ax::mojom::StringAttribute::kKeyShortcuts]; if (!desc.length) return key.length ? key : @""; if (!key.length) @@ -643,23 +654,23 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { } - (id)AXValue { - ui::AXRole role = node_->GetData().role; - if (role == ui::AX_ROLE_TAB) + ax::mojom::Role role = node_->GetData().role; + if (role == ax::mojom::Role::kTab) return [self AXSelected]; if (ui::IsNameExposedInAXValueForRole(role)) - return [self getStringAttribute:ui::AX_ATTR_NAME]; + return [self getStringAttribute:ax::mojom::StringAttribute::kName]; - return [self getStringAttribute:ui::AX_ATTR_VALUE]; + return [self getStringAttribute:ax::mojom::StringAttribute::kValue]; } - (NSNumber*)AXEnabled { - return @(node_->GetData().GetIntAttribute(ui::AX_ATTR_RESTRICTION) != - ui::AX_RESTRICTION_DISABLED); + return + @(node_->GetData().GetRestriction() != ax::mojom::Restriction::kDisabled); } - (NSNumber*)AXFocused { - if (node_->GetData().HasState(ui::AX_STATE_FOCUSABLE)) + if (node_->GetData().HasState(ax::mojom::State::kFocusable)) return @(node_->GetDelegate()->GetFocus() == node_->GetNativeViewAccessible()); return @NO; @@ -702,17 +713,17 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { if (ui::IsNameExposedInAXValueForRole(node_->GetData().role)) return @""; - return [self getStringAttribute:ui::AX_ATTR_NAME]; + return [self getStringAttribute:ax::mojom::StringAttribute::kName]; } // Misc attributes. - (NSNumber*)AXSelected { - return @(node_->GetData().HasState(ui::AX_STATE_SELECTED)); + return @(node_->GetData().HasState(ax::mojom::State::kSelected)); } - (NSString*)AXPlaceholderValue { - return [self getStringAttribute:ui::AX_ATTR_PLACEHOLDER]; + return [self getStringAttribute:ax::mojom::StringAttribute::kPlaceholder]; } // Text-specific attributes. @@ -726,8 +737,8 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) { - (NSValue*)AXSelectedTextRange { // Selection might not be supported. Return (NSRange){0,0} in that case. int start = 0, end = 0; - node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, &start); - node_->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, &end); + node_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart, &start); + node_->GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, &end); // NSRange cannot represent the direction the text was selected in. return [NSValue valueWithRange:{std::min(start, end), abs(end - start)}]; @@ -846,15 +857,16 @@ gfx::NativeViewAccessible AXPlatformNodeMac::GetNativeViewAccessible() { return native_node_.get(); } -void AXPlatformNodeMac::NotifyAccessibilityEvent(ui::AXEvent event_type) { +void AXPlatformNodeMac::NotifyAccessibilityEvent(ax::mojom::Event event_type) { GetNativeViewAccessible(); - // Add mappings between ui::AXEvent and NSAccessibility notifications using - // the EventMap above. This switch contains exceptions to those mappings. + // Add mappings between ax::mojom::Event and NSAccessibility notifications + // using the EventMap above. This switch contains exceptions to those + // mappings. switch (event_type) { - case ui::AX_EVENT_TEXT_CHANGED: + case ax::mojom::Event::kTextChanged: // If the view is a user-editable textfield, this should change the value. - if (GetData().role == ui::AX_ROLE_TEXT_FIELD) { - NotifyMacEvent(native_node_, ui::AX_EVENT_VALUE_CHANGED); + if (GetData().role == ax::mojom::Role::kTextField) { + NotifyMacEvent(native_node_, ax::mojom::Event::kValueChanged); return; } break; @@ -869,12 +881,13 @@ int AXPlatformNodeMac::GetIndexInParent() { return -1; } -bool IsNameExposedInAXValueForRole(AXRole role) { +bool IsNameExposedInAXValueForRole(ax::mojom::Role role) { switch (role) { - case AX_ROLE_LIST_BOX_OPTION: - case AX_ROLE_LIST_MARKER: - case AX_ROLE_MENU_LIST_OPTION: - case AX_ROLE_STATIC_TEXT: + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kListMarker: + case ax::mojom::Role::kMenuListOption: + case ax::mojom::Role::kStaticText: + case ax::mojom::Role::kTitleBar: return true; default: return false; diff --git a/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc index de424716d22..9cb8b4428a3 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc +++ b/chromium/ui/accessibility/platform/ax_platform_node_unittest.cc @@ -57,8 +57,8 @@ void AXPlatformNodeTest::Init(const AXNodeData& node1, AXTreeUpdate AXPlatformNodeTest::BuildTextField() { AXNodeData text_field_node; text_field_node.id = 1; - text_field_node.role = AX_ROLE_TEXT_FIELD; - text_field_node.AddState(AX_STATE_EDITABLE); + text_field_node.role = ax::mojom::Role::kTextField; + text_field_node.AddState(ax::mojom::State::kEditable); text_field_node.SetValue("How now brown cow."); AXTreeUpdate update; @@ -72,11 +72,12 @@ AXTreeUpdate AXPlatformNodeTest::BuildTextFieldWithSelectionRange( int32_t stop) { AXNodeData text_field_node; text_field_node.id = 1; - text_field_node.role = AX_ROLE_TEXT_FIELD; - text_field_node.AddState(AX_STATE_EDITABLE); - text_field_node.AddState(AX_STATE_SELECTED); - text_field_node.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, start); - text_field_node.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, stop); + text_field_node.role = ax::mojom::Role::kTextField; + text_field_node.AddState(ax::mojom::State::kEditable); + text_field_node.AddState(ax::mojom::State::kSelected); + text_field_node.AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart, + start); + text_field_node.AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, stop); text_field_node.SetValue("How now brown cow."); AXTreeUpdate update; @@ -88,9 +89,10 @@ AXTreeUpdate AXPlatformNodeTest::BuildTextFieldWithSelectionRange( AXTreeUpdate AXPlatformNodeTest::BuildContentEditable() { AXNodeData content_editable_node; content_editable_node.id = 1; - content_editable_node.role = AX_ROLE_GROUP; - content_editable_node.AddState(AX_STATE_RICHLY_EDITABLE); - content_editable_node.AddBoolAttribute(ui::AX_ATTR_EDITABLE_ROOT, true); + content_editable_node.role = ax::mojom::Role::kGroup; + content_editable_node.AddState(ax::mojom::State::kRichlyEditable); + content_editable_node.AddBoolAttribute( + ax::mojom::BoolAttribute::kEditableRoot, true); content_editable_node.SetValue("How now brown cow."); AXTreeUpdate update; @@ -104,10 +106,11 @@ AXTreeUpdate AXPlatformNodeTest::BuildContentEditableWithSelectionRange( int32_t end) { AXNodeData content_editable_node; content_editable_node.id = 1; - content_editable_node.role = AX_ROLE_GROUP; - content_editable_node.AddState(AX_STATE_RICHLY_EDITABLE); - content_editable_node.AddState(AX_STATE_SELECTED); - content_editable_node.AddBoolAttribute(ui::AX_ATTR_EDITABLE_ROOT, true); + content_editable_node.role = ax::mojom::Role::kGroup; + content_editable_node.AddState(ax::mojom::State::kRichlyEditable); + content_editable_node.AddState(ax::mojom::State::kSelected); + content_editable_node.AddBoolAttribute( + ax::mojom::BoolAttribute::kEditableRoot, true); content_editable_node.SetValue("How now brown cow."); AXTreeUpdate update; @@ -138,18 +141,18 @@ AXTreeUpdate AXPlatformNodeTest::AXPlatformNodeTest::Build3X3Table() { AXNodeData table; table.id = 0; - table.role = AX_ROLE_TABLE; + table.role = ax::mojom::Role::kTable; - table.AddIntAttribute(AX_ATTR_TABLE_ROW_COUNT, 3); - table.AddIntAttribute(AX_ATTR_TABLE_COLUMN_COUNT, 3); + table.AddIntAttribute(ax::mojom::IntAttribute::kTableRowCount, 3); + table.AddIntAttribute(ax::mojom::IntAttribute::kTableColumnCount, 3); // Ordering in this list matters. It is used in the calculation // of where cells are by the following: // int position = row * GetTableColumnCount() + column; std::vector<int32_t> ids{51, 52, 53, 2, 3, 4, 11, 12, 13}; - table.AddIntListAttribute(AX_ATTR_CELL_IDS, ids); - table.AddIntListAttribute(AX_ATTR_UNIQUE_CELL_IDS, ids); + table.AddIntListAttribute(ax::mojom::IntListAttribute::kCellIds, ids); + table.AddIntListAttribute(ax::mojom::IntListAttribute::kUniqueCellIds, ids); table.child_ids.push_back(50); // Header table.child_ids.push_back(1); // Row 1 @@ -158,74 +161,75 @@ AXTreeUpdate AXPlatformNodeTest::AXPlatformNodeTest::Build3X3Table() { // Table column header AXNodeData table_row_header; table_row_header.id = 50; - table_row_header.role = AX_ROLE_ROW; + table_row_header.role = ax::mojom::Role::kRow; table_row_header.child_ids.push_back(51); table_row_header.child_ids.push_back(52); table_row_header.child_ids.push_back(53); AXNodeData table_column_header_1; table_column_header_1.id = 51; - table_column_header_1.role = AX_ROLE_COLUMN_HEADER; + table_column_header_1.role = ax::mojom::Role::kColumnHeader; AXNodeData table_column_header_2; table_column_header_2.id = 52; - table_column_header_2.role = AX_ROLE_COLUMN_HEADER; + table_column_header_2.role = ax::mojom::Role::kColumnHeader; table_column_header_2.SetName("column header 1"); AXNodeData table_column_header_3; table_column_header_3.id = 53; - table_column_header_3.role = AX_ROLE_COLUMN_HEADER; - // Either AX_ATTR_NAME -or- AX_ATTR_DESCRIPTION is acceptable for a - // description - table_column_header_3.AddStringAttribute(AX_ATTR_DESCRIPTION, - "column header 2"); + table_column_header_3.role = ax::mojom::Role::kColumnHeader; + // Either ax::mojom::StringAttribute::kName -or- + // ax::mojom::StringAttribute::kDescription is acceptable for a description + table_column_header_3.AddStringAttribute( + ax::mojom::StringAttribute::kDescription, "column header 2"); // Row 1 AXNodeData table_row_1; table_row_1.id = 1; - table_row_1.role = AX_ROLE_ROW; + table_row_1.role = ax::mojom::Role::kRow; table_row_1.child_ids.push_back(2); table_row_1.child_ids.push_back(3); table_row_1.child_ids.push_back(4); AXNodeData table_row_header_1; table_row_header_1.id = 2; - table_row_header_1.role = AX_ROLE_ROW_HEADER; + table_row_header_1.role = ax::mojom::Role::kRowHeader; table_row_header_1.SetName("row header 1"); AXNodeData table_cell_1; table_cell_1.id = 3; - table_cell_1.role = AX_ROLE_CELL; + table_cell_1.role = ax::mojom::Role::kCell; table_cell_1.SetName("1"); AXNodeData table_cell_2; table_cell_2.id = 4; - table_cell_2.role = AX_ROLE_CELL; + table_cell_2.role = ax::mojom::Role::kCell; table_cell_2.SetName("2"); // Row 2 AXNodeData table_row_2; table_row_2.id = 10; - table_row_2.role = AX_ROLE_ROW; + table_row_2.role = ax::mojom::Role::kRow; table_row_2.child_ids.push_back(11); table_row_2.child_ids.push_back(12); table_row_2.child_ids.push_back(13); AXNodeData table_row_header_2; table_row_header_2.id = 11; - table_row_header_2.role = AX_ROLE_ROW_HEADER; - // Either AX_ATTR_NAME -or- AX_ATTR_DESCRIPTION is acceptable for a - // description - table_row_header_2.AddStringAttribute(AX_ATTR_DESCRIPTION, "row header 2"); + table_row_header_2.role = ax::mojom::Role::kRowHeader; + // Either ax::mojom::StringAttribute::kName -or- + // ax::mojom::StringAttribute::kDescription is acceptable for a description + table_row_header_2.AddStringAttribute( + ax::mojom::StringAttribute::kDescription, "row header 2"); AXNodeData table_cell_3; table_cell_3.id = 12; - table_cell_3.role = AX_ROLE_CELL; + table_cell_3.role = ax::mojom::Role::kCell; table_cell_3.SetName("3"); AXNodeData table_cell_4; table_cell_4.id = 13; - table_cell_4.role = AX_ROLE_CELL; + table_cell_4.role = ax::mojom::Role::kCell; table_cell_4.SetName("4"); AXTreeUpdate update; diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc index 7d3ead2c186..f266a181e11 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc +++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc @@ -283,7 +283,7 @@ void AXPlatformNodeWin::SanitizeStringAttributeForIA2( void AXPlatformNodeWin::StringAttributeToIA2( std::vector<base::string16>& attributes, - AXStringAttribute attribute, + ax::mojom::StringAttribute attribute, const char* ia2_attr) { base::string16 value; if (GetString16Attribute(attribute, &value)) { @@ -294,7 +294,7 @@ void AXPlatformNodeWin::StringAttributeToIA2( void AXPlatformNodeWin::BoolAttributeToIA2( std::vector<base::string16>& attributes, - AXBoolAttribute attribute, + ax::mojom::BoolAttribute attribute, const char* ia2_attr) { bool value; if (GetBoolAttribute(attribute, &value)) { @@ -305,7 +305,7 @@ void AXPlatformNodeWin::BoolAttributeToIA2( void AXPlatformNodeWin::IntAttributeToIA2( std::vector<base::string16>& attributes, - AXIntAttribute attribute, + ax::mojom::IntAttribute attribute, const char* ia2_attr) { int value; if (GetIntAttribute(attribute, &value)) { @@ -340,15 +340,16 @@ gfx::NativeViewAccessible AXPlatformNodeWin::GetNativeViewAccessible() { return this; } -void AXPlatformNodeWin::NotifyAccessibilityEvent(AXEvent event_type) { +void AXPlatformNodeWin::NotifyAccessibilityEvent(ax::mojom::Event event_type) { HWND hwnd = delegate_->GetTargetForNativeAccessibilityEvent(); if (!hwnd) return; // Menu items fire selection events but Windows screen readers work reliably // with focus events. Remap here. - if (event_type == AX_EVENT_SELECTION && GetData().role == AX_ROLE_MENU_ITEM) - event_type = AX_EVENT_FOCUS; + if (event_type == ax::mojom::Event::kSelection && + GetData().role == ax::mojom::Role::kMenuItem) + event_type = ax::mojom::Event::kFocus; int native_event = MSAAEvent(event_type); if (native_event < EVENT_MIN) @@ -357,7 +358,7 @@ void AXPlatformNodeWin::NotifyAccessibilityEvent(AXEvent event_type) { ::NotifyWinEvent(native_event, hwnd, OBJID_CLIENT, -GetUniqueId()); // Keep track of objects that are a target of an alert event. - if (event_type == AX_EVENT_ALERT) + if (event_type == ax::mojom::Event::kAlert) AddAlertTarget(); } @@ -403,7 +404,7 @@ STDMETHODIMP AXPlatformNodeWin::accHitTest( COM_OBJECT_VALIDATE_1_ARG(child); gfx::Point point(x_left, y_top); - if (!delegate_->GetScreenBoundsRect().Contains(point)) { + if (!delegate_->GetClippedScreenBoundsRect().Contains(point)) { // Return S_FALSE and VT_EMPTY when outside the object's boundaries. child->vt = VT_EMPTY; return S_FALSE; @@ -446,7 +447,7 @@ HRESULT AXPlatformNodeWin::accDoDefaultAction(VARIANT var_id) { AXPlatformNodeWin* target; COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_id, target); AXActionData data; - data.action = AX_ACTION_DO_DEFAULT; + data.action = ax::mojom::Action::kDoDefault; if (target->delegate_->AccessibilityPerformAction(data)) return S_OK; @@ -460,7 +461,7 @@ STDMETHODIMP AXPlatformNodeWin::accLocation( COM_OBJECT_VALIDATE_VAR_ID_4_ARGS_AND_GET_TARGET(var_id, x_left, y_top, width, height, target); - gfx::Rect bounds = target->delegate_->GetScreenBoundsRect(); + gfx::Rect bounds = target->delegate_->GetUnclippedScreenBoundsRect(); *x_left = bounds.x(); *y_top = bounds.y(); *width = bounds.width(); @@ -612,13 +613,14 @@ STDMETHODIMP AXPlatformNodeWin::get_accDefaultAction( AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes); int action; - if (!target->GetIntAttribute(AX_ATTR_DEFAULT_ACTION_VERB, &action)) { + if (!target->GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb, + &action)) { *def_action = nullptr; return S_FALSE; } - base::string16 action_verb = - ActionVerbToLocalizedString(static_cast<AXDefaultActionVerb>(action)); + base::string16 action_verb = ActionVerbToLocalizedString( + static_cast<ax::mojom::DefaultActionVerb>(action)); if (action_verb.empty()) { *def_action = nullptr; return S_FALSE; @@ -635,7 +637,8 @@ STDMETHODIMP AXPlatformNodeWin::get_accDescription( AXPlatformNodeWin* target; COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, desc, target); - return target->GetStringAttributeAsBstr(AX_ATTR_DESCRIPTION, desc); + return target->GetStringAttributeAsBstr( + ax::mojom::StringAttribute::kDescription, desc); } STDMETHODIMP AXPlatformNodeWin::get_accFocus(VARIANT* focus_child) { @@ -663,7 +666,8 @@ STDMETHODIMP AXPlatformNodeWin::get_accKeyboardShortcut( AXPlatformNodeWin* target; COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, acc_key, target); - return target->GetStringAttributeAsBstr(AX_ATTR_KEY_SHORTCUTS, acc_key); + return target->GetStringAttributeAsBstr( + ax::mojom::StringAttribute::kKeyShortcuts, acc_key); } STDMETHODIMP AXPlatformNodeWin::get_accName( @@ -672,7 +676,8 @@ STDMETHODIMP AXPlatformNodeWin::get_accName( AXPlatformNodeWin* target; COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, name, target); - HRESULT result = target->GetStringAttributeAsBstr(AX_ATTR_NAME, name); + HRESULT result = + target->GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName, name); if (FAILED(result) && MSAARole() == ROLE_SYSTEM_DOCUMENT && GetParent()) { // Hack: Some versions of JAWS crash if they get an empty name on // a document that's the child of an iframe, so always return a @@ -747,19 +752,20 @@ STDMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) { // get_accValue() has two sets of special cases depending on the node's role. // The first set apply without regard for the nodes |value| attribute. That is // the nodes value attribute isn't consider for the first set of special - // cases. For example, if the node role is AX_ROLE_COLOR_WELL, we do not care - // at all about the node's AX_ATTR_VALUE attribute. The second set of special - // cases only apply if the value attribute for the node is empty. That is, if - // AX_ATTR_VALUE is empty, we do something special. + // cases. For example, if the node role is ax::mojom::Role::kColorWell, we do + // not care at all about the node's ax::mojom::StringAttribute::kValue + // attribute. The second set of special cases only apply if the value + // attribute for the node is empty. That is, if + // ax::mojom::StringAttribute::kValue is empty, we do something special. base::string16 result; // - // Color Well special case (Use AX_ATTR_COLOR_VALUE) + // Color Well special case (Use ax::mojom::IntAttribute::kColorValue) // - if (target->GetData().role == AX_ROLE_COLOR_WELL) { + if (target->GetData().role == ax::mojom::Role::kColorWell) { unsigned int color = static_cast<unsigned int>(target->GetIntAttribute( - AX_ATTR_COLOR_VALUE)); // todo, why the static cast? + ax::mojom::IntAttribute::kColorValue)); // todo, why the static cast? unsigned int red = SkColorGetR(color); unsigned int green = SkColorGetG(color); @@ -776,8 +782,8 @@ STDMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) { // // Document special case (Use the document's URL) // - if (target->GetData().role == AX_ROLE_ROOT_WEB_AREA || - target->GetData().role == AX_ROLE_WEB_AREA) { + if (target->GetData().role == ax::mojom::Role::kRootWebArea || + target->GetData().role == ax::mojom::Role::kWebArea) { result = base::UTF8ToUTF16(target->delegate_->GetTreeData().url); *value = SysAllocString(result.c_str()); DCHECK(*value); @@ -785,10 +791,10 @@ STDMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) { } // - // Links (Use AX_ATTR_URL) + // Links (Use ax::mojom::StringAttribute::kUrl) // - if (target->GetData().role == AX_ROLE_LINK) { - result = target->GetString16Attribute(AX_ATTR_URL); + if (target->GetData().role == ax::mojom::Role::kLink) { + result = target->GetString16Attribute(ax::mojom::StringAttribute::kUrl); *value = SysAllocString(result.c_str()); DCHECK(*value); return S_OK; @@ -797,11 +803,12 @@ STDMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) { // For range controls, e.g. sliders and spin buttons, |ax_attr_value| holds // the aria-valuetext if present but not the inner text. The actual value, // provided either via aria-valuenow or the actual control's value is held in - // |AX_ATTR_VALUE_FOR_RANGE|. - result = target->GetString16Attribute(AX_ATTR_VALUE); + // |ax::mojom::FloatAttribute::kValueForRange|. + result = target->GetString16Attribute(ax::mojom::StringAttribute::kValue); if (result.empty() && target->IsRangeValueSupported()) { float fval; - if (target->GetFloatAttribute(AX_ATTR_VALUE_FOR_RANGE, &fval)) { + if (target->GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange, + &fval)) { result = base::NumberToString16(fval); *value = SysAllocString(result.c_str()); DCHECK(*value); @@ -823,7 +830,7 @@ STDMETHODIMP AXPlatformNodeWin::put_accValue(VARIANT var_id, COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_id, target); AXActionData data; - data.action = AX_ACTION_SET_VALUE; + data.action = ax::mojom::Action::kSetValue; data.value = new_value; if (target->delegate_->AccessibilityPerformAction(data)) return S_OK; @@ -837,7 +844,7 @@ STDMETHODIMP AXPlatformNodeWin::get_accSelection(VARIANT* selected) { for (int i = 0; i < delegate_->GetChildCount(); ++i) { auto* node = static_cast<AXPlatformNodeWin*>( FromNativeViewAccessible(delegate_->ChildAtIndex(i))); - if (node && node->GetData().HasState(AX_STATE_SELECTED)) + if (node && node->GetData().HasState(ax::mojom::State::kSelected)) selected_nodes.emplace_back(node); } @@ -874,7 +881,7 @@ STDMETHODIMP AXPlatformNodeWin::accSelect( if (flagsSelect & SELFLAG_TAKEFOCUS) { AXActionData action_data; - action_data.action = AX_ACTION_FOCUS; + action_data.action = ax::mojom::Action::kFocus; target->delegate_->AccessibilityPerformAction(action_data); return S_OK; } @@ -1120,9 +1127,9 @@ STDMETHODIMP AXPlatformNodeWin::get_groupPosition(LONG* group_level, position_in_group); AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes); - *group_level = GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL); - *similar_items_in_group = GetIntAttribute(ui::AX_ATTR_SET_SIZE); - *position_in_group = GetIntAttribute(ui::AX_ATTR_POS_IN_SET); + *group_level = GetIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel); + *similar_items_in_group = GetIntAttribute(ax::mojom::IntAttribute::kSetSize); + *position_in_group = GetIntAttribute(ax::mojom::IntAttribute::kPosInSet); if (!*group_level && !*similar_items_in_group && !*position_in_group) return S_FALSE; @@ -1135,7 +1142,7 @@ STDMETHODIMP AXPlatformNodeWin::get_localizedExtendedRole( COM_OBJECT_VALIDATE_1_ARG(localized_extended_role); AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes); - return GetStringAttributeAsBstr(ui::AX_ATTR_ROLE_DESCRIPTION, + return GetStringAttributeAsBstr(ax::mojom::StringAttribute::kRoleDescription, localized_extended_role); } @@ -1154,7 +1161,8 @@ STDMETHODIMP AXPlatformNodeWin::scrollTo(enum IA2ScrollType scroll_type) { COM_OBJECT_VALIDATE(); WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IA2_SCROLL_TO); - // AX_ACTION_SCROLL_TO_MAKE_VISIBLE wants a target rect in *local* coords. + // ax::mojom::Action::kScrollToMakeVisible wants a target rect in *local* + // coords. gfx::Rect r = gfx::ToEnclosingRect(GetData().location); r.Offset(-r.OffsetFromOrigin()); switch (scroll_type) { @@ -1183,7 +1191,7 @@ STDMETHODIMP AXPlatformNodeWin::scrollTo(enum IA2ScrollType scroll_type) { ui::AXActionData action_data; action_data.target_node_id = GetData().id; - action_data.action = ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE; + action_data.action = ax::mojom::Action::kScrollToMakeVisible; action_data.target_rect = r; delegate_->AccessibilityPerformAction(action_data); return S_OK; @@ -1200,11 +1208,12 @@ STDMETHODIMP AXPlatformNodeWin::scrollToPoint( gfx::Point scroll_to(x, y); if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) { - scroll_to -= delegate_->GetScreenBoundsRect().OffsetFromOrigin(); + scroll_to -= delegate_->GetUnclippedScreenBoundsRect().OffsetFromOrigin(); } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) { if (GetParent()) { AXPlatformNodeBase* base = FromNativeViewAccessible(GetParent()); - scroll_to += base->delegate_->GetScreenBoundsRect().OffsetFromOrigin(); + scroll_to += + base->delegate_->GetUnclippedScreenBoundsRect().OffsetFromOrigin(); } } else { return E_INVALIDARG; @@ -1212,7 +1221,7 @@ STDMETHODIMP AXPlatformNodeWin::scrollToPoint( ui::AXActionData action_data; action_data.target_node_id = GetData().id; - action_data.action = ui::AX_ACTION_SCROLL_TO_POINT; + action_data.action = ax::mojom::Action::kScrollToPoint; action_data.target_point = scroll_to; delegate_->AccessibilityPerformAction(action_data); return S_OK; @@ -1328,14 +1337,16 @@ STDMETHODIMP AXPlatformNodeWin::get_columnDescription(LONG column, for (int r = 0; r < rows; ++r) { AXPlatformNodeBase* cell = GetTableCell(r, column); - if (cell && cell->GetData().role == AX_ROLE_COLUMN_HEADER) { - base::string16 cell_name = cell->GetString16Attribute(AX_ATTR_NAME); + if (cell && cell->GetData().role == ax::mojom::Role::kColumnHeader) { + base::string16 cell_name = + cell->GetString16Attribute(ax::mojom::StringAttribute::kName); if (cell_name.size() > 0) { *description = SysAllocString(cell_name.c_str()); return S_OK; } - cell_name = cell->GetString16Attribute(AX_ATTR_DESCRIPTION); + cell_name = + cell->GetString16Attribute(ax::mojom::StringAttribute::kDescription); if (cell_name.size() > 0) { *description = SysAllocString(cell_name.c_str()); return S_OK; @@ -1429,7 +1440,7 @@ STDMETHODIMP AXPlatformNodeWin::get_nSelectedChildren(LONG* cell_count) { for (int r = 0; r < rows; ++r) { for (int c = 0; c < columns; ++c) { AXPlatformNodeBase* cell = GetTableCell(r, c); - if (cell && cell->GetData().HasState(AX_STATE_SELECTED)) + if (cell && cell->GetData().HasState(ax::mojom::State::kSelected)) result++; } } @@ -1456,7 +1467,7 @@ STDMETHODIMP AXPlatformNodeWin::get_nSelectedColumns(LONG* column_count) { bool selected = true; for (int r = 0; r < rows && selected == true; ++r) { AXPlatformNodeBase* cell = GetTableCell(r, c); - if (!cell || !(cell->GetData().HasState(AX_STATE_SELECTED))) + if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected))) selected = false; } if (selected) @@ -1486,7 +1497,7 @@ STDMETHODIMP AXPlatformNodeWin::get_nSelectedRows(LONG* row_count) { bool selected = true; for (int c = 0; c < columns && selected == true; ++c) { AXPlatformNodeBase* cell = GetTableCell(r, c); - if (!cell || !(cell->GetData().HasState(AX_STATE_SELECTED))) + if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected))) selected = false; } if (selected) @@ -1516,13 +1527,15 @@ STDMETHODIMP AXPlatformNodeWin::get_rowDescription(LONG row, for (int c = 0; c < columns; ++c) { AXPlatformNodeBase* cell = GetTableCell(row, c); - if (cell && cell->GetData().role == AX_ROLE_ROW_HEADER) { - base::string16 cell_name = cell->GetString16Attribute(AX_ATTR_NAME); + if (cell && cell->GetData().role == ax::mojom::Role::kRowHeader) { + base::string16 cell_name = + cell->GetString16Attribute(ax::mojom::StringAttribute::kName); if (cell_name.size() > 0) { *description = SysAllocString(cell_name.c_str()); return S_OK; } - cell_name = cell->GetString16Attribute(AX_ATTR_DESCRIPTION); + cell_name = + cell->GetString16Attribute(ax::mojom::StringAttribute::kDescription); if (cell_name.size() > 0) { *description = SysAllocString(cell_name.c_str()); return S_OK; @@ -1594,7 +1607,7 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedChildren(LONG max_children, for (int r = 0; r < rows; ++r) { for (int c = 0; c < columns; ++c) { AXPlatformNodeBase* cell = GetTableCell(r, c); - if (cell && cell->GetData().HasState(AX_STATE_SELECTED)) + if (cell && cell->GetData().HasState(ax::mojom::State::kSelected)) // index is row index * column count + column index. results.push_back(r * columns + c); } @@ -1623,7 +1636,7 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedColumns(LONG max_columns, bool selected = true; for (int r = 0; r < row_count && selected == true; ++r) { AXPlatformNodeBase* cell = GetTableCell(r, c); - if (!cell || !(cell->GetData().HasState(AX_STATE_SELECTED))) + if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected))) selected = false; } if (selected) @@ -1651,7 +1664,7 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedRows(LONG max_rows, bool selected = true; for (int c = 0; c < column_count && selected == true; ++c) { AXPlatformNodeBase* cell = GetTableCell(r, c); - if (!cell || !(cell->GetData().HasState(AX_STATE_SELECTED))) + if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected))) selected = false; } if (selected) @@ -1688,7 +1701,7 @@ STDMETHODIMP AXPlatformNodeWin::get_isColumnSelected(LONG column, for (int r = 0; r < rows; ++r) { AXPlatformNodeBase* cell = GetTableCell(r, column); - if (!cell || !(cell->GetData().HasState(AX_STATE_SELECTED))) + if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected))) return S_OK; } @@ -1711,7 +1724,7 @@ STDMETHODIMP AXPlatformNodeWin::get_isRowSelected(LONG row, for (int c = 0; c < columns; ++c) { AXPlatformNodeBase* cell = GetTableCell(row, c); - if (!cell || !(cell->GetData().HasState(AX_STATE_SELECTED))) + if (!cell || !(cell->GetData().HasState(ax::mojom::State::kSelected))) return S_OK; } @@ -1735,7 +1748,7 @@ STDMETHODIMP AXPlatformNodeWin::get_isSelected(LONG row, return S_FALSE; AXPlatformNodeBase* cell = GetTableCell(row, column); - if (cell && cell->GetData().HasState(AX_STATE_SELECTED)) + if (cell && cell->GetData().HasState(ax::mojom::State::kSelected)) *is_selected = true; return S_OK; @@ -1852,7 +1865,7 @@ STDMETHODIMP AXPlatformNodeWin::get_selectedCells(IUnknown*** cells, for (int r = 0; r < rows; ++r) { for (int c = 0; c < columns; ++c) { AXPlatformNodeBase* cell = GetTableCell(r, c); - if (cell && cell->GetData().HasState(AX_STATE_SELECTED)) + if (cell && cell->GetData().HasState(ax::mojom::State::kSelected)) selected.push_back(cell); } } @@ -1901,7 +1914,7 @@ STDMETHODIMP AXPlatformNodeWin::get_columnHeaderCells( return E_INVALIDARG; *n_column_header_cells = 0; - if (GetData().role != AX_ROLE_CELL) + if (GetData().role != ax::mojom::Role::kCell) return S_FALSE; AXPlatformNodeBase* table = GetTable(); @@ -1917,7 +1930,7 @@ STDMETHODIMP AXPlatformNodeWin::get_columnHeaderCells( for (int r = 0; r < rows; ++r) { AXPlatformNodeBase* cell = GetTableCell(r, column); - if (cell && cell->GetData().role == AX_ROLE_COLUMN_HEADER) + if (cell && cell->GetData().role == ax::mojom::Role::kColumnHeader) (*n_column_header_cells)++; } @@ -1926,7 +1939,7 @@ STDMETHODIMP AXPlatformNodeWin::get_columnHeaderCells( int index = 0; for (int r = 0; r < rows; ++r) { AXPlatformNodeBase* cell = GetTableCell(r, column); - if (cell && cell->GetData().role == AX_ROLE_COLUMN_HEADER) { + if (cell && cell->GetData().role == ax::mojom::Role::kColumnHeader) { auto* node_win = static_cast<AXPlatformNodeWin*>(cell); node_win->AddRef(); @@ -1969,7 +1982,7 @@ STDMETHODIMP AXPlatformNodeWin::get_rowHeaderCells(IUnknown*** cell_accessibles, return E_INVALIDARG; *n_row_header_cells = 0; - if (GetData().role != AX_ROLE_CELL) + if (GetData().role != ax::mojom::Role::kCell) return S_FALSE; AXPlatformNodeBase* table = GetTable(); @@ -1985,7 +1998,7 @@ STDMETHODIMP AXPlatformNodeWin::get_rowHeaderCells(IUnknown*** cell_accessibles, for (int c = 0; c < columns; ++c) { AXPlatformNodeBase* cell = GetTableCell(row, c); - if (cell && cell->GetData().role == AX_ROLE_ROW_HEADER) + if (cell && cell->GetData().role == ax::mojom::Role::kRowHeader) (*n_row_header_cells)++; } @@ -1994,7 +2007,7 @@ STDMETHODIMP AXPlatformNodeWin::get_rowHeaderCells(IUnknown*** cell_accessibles, int index = 0; for (int c = 0; c < columns; ++c) { AXPlatformNodeBase* cell = GetTableCell(row, c); - if (cell && cell->GetData().role == AX_ROLE_ROW_HEADER) { + if (cell && cell->GetData().role == ax::mojom::Role::kRowHeader) { auto* node_win = static_cast<AXPlatformNodeWin*>(cell); node_win->AddRef(); @@ -2284,7 +2297,7 @@ STDMETHODIMP AXPlatformNodeWin::removeSelection(LONG selection_index) { return E_INVALIDARG; // Simply collapse the selection to the position of the caret if a caret is // visible, otherwise set the selection to 0. - return setCaretOffset(GetIntAttribute(AX_ATTR_TEXT_SEL_END)); + return setCaretOffset(GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd)); } STDMETHODIMP AXPlatformNodeWin::setCaretOffset(LONG offset) { @@ -2394,345 +2407,360 @@ int AXPlatformNodeWin::MSAARole() { return ROLE_SYSTEM_GROUPING; switch (GetData().role) { - case AX_ROLE_ALERT: + case ax::mojom::Role::kAlert: return ROLE_SYSTEM_ALERT; - case AX_ROLE_ALERT_DIALOG: + case ax::mojom::Role::kAlertDialog: return ROLE_SYSTEM_DIALOG; - case AX_ROLE_ANCHOR: + case ax::mojom::Role::kAnchor: return ROLE_SYSTEM_LINK; - case AX_ROLE_APPLICATION: + case ax::mojom::Role::kApplication: return ROLE_SYSTEM_APPLICATION; - case AX_ROLE_ARTICLE: + case ax::mojom::Role::kArticle: return ROLE_SYSTEM_DOCUMENT; - case AX_ROLE_AUDIO: + case ax::mojom::Role::kAudio: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_BANNER: + case ax::mojom::Role::kBanner: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_BUTTON: + case ax::mojom::Role::kButton: return ROLE_SYSTEM_PUSHBUTTON; - case AX_ROLE_CANVAS: + case ax::mojom::Role::kCanvas: return ROLE_SYSTEM_GRAPHIC; - case AX_ROLE_CAPTION: + case ax::mojom::Role::kCaption: return ROLE_SYSTEM_TEXT; - case AX_ROLE_CELL: + case ax::mojom::Role::kCell: return ROLE_SYSTEM_CELL; - case AX_ROLE_CHECK_BOX: + case ax::mojom::Role::kCheckBox: return ROLE_SYSTEM_CHECKBUTTON; - case AX_ROLE_COLOR_WELL: + case ax::mojom::Role::kColorWell: return ROLE_SYSTEM_TEXT; - case AX_ROLE_COLUMN: + case ax::mojom::Role::kColumn: return ROLE_SYSTEM_COLUMN; - case AX_ROLE_COLUMN_HEADER: + case ax::mojom::Role::kColumnHeader: return ROLE_SYSTEM_COLUMNHEADER; - case AX_ROLE_COMBO_BOX_GROUPING: - case AX_ROLE_COMBO_BOX_MENU_BUTTON: + case ax::mojom::Role::kComboBoxGrouping: + case ax::mojom::Role::kComboBoxMenuButton: return ROLE_SYSTEM_COMBOBOX; - case AX_ROLE_COMPLEMENTARY: + case ax::mojom::Role::kComplementary: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_CONTENT_INFO: + case ax::mojom::Role::kContentInfo: return ROLE_SYSTEM_TEXT; - case AX_ROLE_DATE: - case AX_ROLE_DATE_TIME: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kDateTime: return ROLE_SYSTEM_DROPLIST; - case AX_ROLE_DESCRIPTION_LIST_DETAIL: + case ax::mojom::Role::kDescriptionListDetail: return ROLE_SYSTEM_TEXT; - case AX_ROLE_DESCRIPTION_LIST: + case ax::mojom::Role::kDescriptionList: return ROLE_SYSTEM_LIST; - case AX_ROLE_DESCRIPTION_LIST_TERM: + case ax::mojom::Role::kDescriptionListTerm: return ROLE_SYSTEM_LISTITEM; - case AX_ROLE_DETAILS: + case ax::mojom::Role::kDetails: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_DIALOG: + case ax::mojom::Role::kDialog: return ROLE_SYSTEM_DIALOG; - case AX_ROLE_DISCLOSURE_TRIANGLE: + case ax::mojom::Role::kDisclosureTriangle: return ROLE_SYSTEM_PUSHBUTTON; - case AX_ROLE_DOCUMENT: - case AX_ROLE_ROOT_WEB_AREA: - case AX_ROLE_WEB_AREA: + case ax::mojom::Role::kDocument: + case ax::mojom::Role::kRootWebArea: + case ax::mojom::Role::kWebArea: return ROLE_SYSTEM_DOCUMENT; - case AX_ROLE_EMBEDDED_OBJECT: + case ax::mojom::Role::kEmbeddedObject: if (delegate_->GetChildCount()) { return ROLE_SYSTEM_GROUPING; } else { return ROLE_SYSTEM_CLIENT; } - case AX_ROLE_FIGURE: + case ax::mojom::Role::kFigure: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_FEED: + case ax::mojom::Role::kFeed: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_GENERIC_CONTAINER: + case ax::mojom::Role::kGenericContainer: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_GRID: + case ax::mojom::Role::kGrid: return ROLE_SYSTEM_TABLE; - case AX_ROLE_GROUP: + case ax::mojom::Role::kGroup: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_HEADING: + case ax::mojom::Role::kHeading: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_IFRAME: + case ax::mojom::Role::kIframe: return ROLE_SYSTEM_DOCUMENT; - case AX_ROLE_IFRAME_PRESENTATIONAL: + case ax::mojom::Role::kIframePresentational: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_IMAGE: + case ax::mojom::Role::kImage: return ROLE_SYSTEM_GRAPHIC; - case AX_ROLE_INPUT_TIME: + case ax::mojom::Role::kInputTime: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_LABEL_TEXT: - case AX_ROLE_LEGEND: + case ax::mojom::Role::kLabelText: + case ax::mojom::Role::kLegend: return ROLE_SYSTEM_TEXT; - case AX_ROLE_LINK: + case ax::mojom::Role::kLayoutTable: + return ROLE_SYSTEM_TABLE; + + case ax::mojom::Role::kLayoutTableCell: + return ROLE_SYSTEM_CELL; + + case ax::mojom::Role::kLayoutTableColumn: + return ROLE_SYSTEM_COLUMN; + + case ax::mojom::Role::kLayoutTableRow: + return ROLE_SYSTEM_ROW; + + case ax::mojom::Role::kLink: return ROLE_SYSTEM_LINK; - case AX_ROLE_LIST: + case ax::mojom::Role::kList: return ROLE_SYSTEM_LIST; - case AX_ROLE_LIST_BOX: + case ax::mojom::Role::kListBox: return ROLE_SYSTEM_LIST; - case AX_ROLE_LIST_BOX_OPTION: + case ax::mojom::Role::kListBoxOption: return ROLE_SYSTEM_LISTITEM; - case AX_ROLE_LIST_ITEM: + case ax::mojom::Role::kListItem: return ROLE_SYSTEM_LISTITEM; - case AX_ROLE_MAIN: + case ax::mojom::Role::kMain: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_MARK: + case ax::mojom::Role::kMark: return ROLE_SYSTEM_TEXT; - case AX_ROLE_MARQUEE: + case ax::mojom::Role::kMarquee: return ROLE_SYSTEM_ANIMATION; - case AX_ROLE_MATH: + case ax::mojom::Role::kMath: return ROLE_SYSTEM_EQUATION; - case AX_ROLE_MENU: - case AX_ROLE_MENU_BUTTON: + case ax::mojom::Role::kMenu: + case ax::mojom::Role::kMenuButton: return ROLE_SYSTEM_MENUPOPUP; - case AX_ROLE_MENU_BAR: + case ax::mojom::Role::kMenuBar: return ROLE_SYSTEM_MENUBAR; - case AX_ROLE_MENU_ITEM: + case ax::mojom::Role::kMenuItem: return ROLE_SYSTEM_MENUITEM; - case AX_ROLE_MENU_ITEM_CHECK_BOX: + case ax::mojom::Role::kMenuItemCheckBox: return ROLE_SYSTEM_MENUITEM; - case AX_ROLE_MENU_ITEM_RADIO: + case ax::mojom::Role::kMenuItemRadio: return ROLE_SYSTEM_MENUITEM; - case ui::AX_ROLE_MENU_LIST_POPUP: + case ax::mojom::Role::kMenuListPopup: if (IsAncestorComboBox()) return ROLE_SYSTEM_LIST; return ROLE_SYSTEM_MENUPOPUP; - case ui::AX_ROLE_MENU_LIST_OPTION: + case ax::mojom::Role::kMenuListOption: if (IsAncestorComboBox()) return ROLE_SYSTEM_LISTITEM; return ROLE_SYSTEM_MENUITEM; - case AX_ROLE_METER: + case ax::mojom::Role::kMeter: return ROLE_SYSTEM_PROGRESSBAR; - case AX_ROLE_NAVIGATION: + case ax::mojom::Role::kNavigation: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_NOTE: + case ax::mojom::Role::kNote: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_POP_UP_BUTTON: { - std::string html_tag = GetData().GetStringAttribute(AX_ATTR_HTML_TAG); + case ax::mojom::Role::kPopUpButton: { + std::string html_tag = + GetData().GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); if (html_tag == "select") return ROLE_SYSTEM_COMBOBOX; return ROLE_SYSTEM_BUTTONMENU; } - case AX_ROLE_PRE: + case ax::mojom::Role::kPre: return ROLE_SYSTEM_TEXT; - case AX_ROLE_PROGRESS_INDICATOR: + case ax::mojom::Role::kProgressIndicator: return ROLE_SYSTEM_PROGRESSBAR; - case AX_ROLE_RADIO_BUTTON: + case ax::mojom::Role::kRadioButton: return ROLE_SYSTEM_RADIOBUTTON; - case AX_ROLE_RADIO_GROUP: + case ax::mojom::Role::kRadioGroup: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_REGION: { - std::string html_tag = GetData().GetStringAttribute(AX_ATTR_HTML_TAG); + case ax::mojom::Role::kRegion: { + std::string html_tag = + GetData().GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); if (html_tag == "section") return ROLE_SYSTEM_GROUPING; return ROLE_SYSTEM_PANE; } - case AX_ROLE_ROW: { + case ax::mojom::Role::kRow: { // Role changes depending on whether row is inside a treegrid // https://www.w3.org/TR/core-aam-1.1/#role-map-row return IsInTreeGrid() ? ROLE_SYSTEM_OUTLINEITEM : ROLE_SYSTEM_ROW; } - case AX_ROLE_ROW_HEADER: + case ax::mojom::Role::kRowHeader: return ROLE_SYSTEM_ROWHEADER; - case AX_ROLE_RUBY: + case ax::mojom::Role::kRuby: return ROLE_SYSTEM_TEXT; - case AX_ROLE_SCROLL_BAR: + case ax::mojom::Role::kScrollBar: return ROLE_SYSTEM_SCROLLBAR; - case AX_ROLE_SEARCH: + case ax::mojom::Role::kSearch: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_SLIDER: + case ax::mojom::Role::kSlider: return ROLE_SYSTEM_SLIDER; - case AX_ROLE_SPIN_BUTTON: + case ax::mojom::Role::kSpinButton: return ROLE_SYSTEM_SPINBUTTON; - case AX_ROLE_SPIN_BUTTON_PART: + case ax::mojom::Role::kSpinButtonPart: return ROLE_SYSTEM_PUSHBUTTON; - case AX_ROLE_ANNOTATION: - case AX_ROLE_LIST_MARKER: - case AX_ROLE_STATIC_TEXT: + case ax::mojom::Role::kAnnotation: + case ax::mojom::Role::kListMarker: + case ax::mojom::Role::kStaticText: return ROLE_SYSTEM_STATICTEXT; - case AX_ROLE_STATUS: + case ax::mojom::Role::kStatus: return ROLE_SYSTEM_STATUSBAR; - case AX_ROLE_SPLITTER: + case ax::mojom::Role::kSplitter: return ROLE_SYSTEM_SEPARATOR; - case AX_ROLE_SVG_ROOT: + case ax::mojom::Role::kSvgRoot: return ROLE_SYSTEM_GRAPHIC; - case AX_ROLE_TAB: + case ax::mojom::Role::kTab: return ROLE_SYSTEM_PAGETAB; - case AX_ROLE_TABLE: + case ax::mojom::Role::kTable: return ROLE_SYSTEM_TABLE; - case AX_ROLE_TABLE_HEADER_CONTAINER: + case ax::mojom::Role::kTableHeaderContainer: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_TAB_LIST: + case ax::mojom::Role::kTabList: return ROLE_SYSTEM_PAGETABLIST; - case AX_ROLE_TAB_PANEL: + case ax::mojom::Role::kTabPanel: return ROLE_SYSTEM_PROPERTYPAGE; - case AX_ROLE_TERM: + case ax::mojom::Role::kTerm: return ROLE_SYSTEM_LISTITEM; - case AX_ROLE_TOGGLE_BUTTON: + case ax::mojom::Role::kTitleBar: + return ROLE_SYSTEM_TITLEBAR; + + case ax::mojom::Role::kToggleButton: return ROLE_SYSTEM_PUSHBUTTON; - case AX_ROLE_TEXT_FIELD: - case AX_ROLE_SEARCH_BOX: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kSearchBox: return ROLE_SYSTEM_TEXT; - case AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX: + case ax::mojom::Role::kTextFieldWithComboBox: return ROLE_SYSTEM_COMBOBOX; - case AX_ROLE_ABBR: - case AX_ROLE_TIME: + case ax::mojom::Role::kAbbr: + case ax::mojom::Role::kTime: return ROLE_SYSTEM_TEXT; - case AX_ROLE_TIMER: + case ax::mojom::Role::kTimer: return ROLE_SYSTEM_CLOCK; - case AX_ROLE_TOOLBAR: + case ax::mojom::Role::kToolbar: return ROLE_SYSTEM_TOOLBAR; - case AX_ROLE_TOOLTIP: + case ax::mojom::Role::kTooltip: return ROLE_SYSTEM_TOOLTIP; - case AX_ROLE_TREE: + case ax::mojom::Role::kTree: return ROLE_SYSTEM_OUTLINE; - case AX_ROLE_TREE_GRID: + case ax::mojom::Role::kTreeGrid: return ROLE_SYSTEM_OUTLINE; - case AX_ROLE_TREE_ITEM: + case ax::mojom::Role::kTreeItem: return ROLE_SYSTEM_OUTLINEITEM; - case AX_ROLE_LINE_BREAK: + case ax::mojom::Role::kLineBreak: return ROLE_SYSTEM_WHITESPACE; - case AX_ROLE_VIDEO: + case ax::mojom::Role::kVideo: return ROLE_SYSTEM_GROUPING; - case AX_ROLE_WINDOW: + case ax::mojom::Role::kWindow: // Do not return ROLE_SYSTEM_WINDOW as that is a special MSAA system role // used to indicate a real native window object. It is automatically // created by oleacc.dll as a parent of the root of our hierarchy, // matching the HWND. - return ROLE_SYSTEM_APPLICATION; + return ROLE_SYSTEM_PANE; // TODO(dmazzoni): figure out the proper MSAA role for roles listed below. - case AX_ROLE_BLOCKQUOTE: - case AX_ROLE_BUTTON_DROP_DOWN: - case AX_ROLE_CARET: - case AX_ROLE_CLIENT: - case AX_ROLE_DEFINITION: - case AX_ROLE_DESKTOP: - case AX_ROLE_DIRECTORY: - case AX_ROLE_FIGCAPTION: - case AX_ROLE_FOOTER: - case AX_ROLE_FORM: - case AX_ROLE_IGNORED: - case AX_ROLE_IMAGE_MAP: - case AX_ROLE_INLINE_TEXT_BOX: - case AX_ROLE_LOCATION_BAR: - case AX_ROLE_LOG: - case AX_ROLE_NONE: - case AX_ROLE_PANE: - case AX_ROLE_PARAGRAPH: - case AX_ROLE_PRESENTATIONAL: - case AX_ROLE_SLIDER_THUMB: - case AX_ROLE_SWITCH: - case AX_ROLE_TITLE_BAR: - case AX_ROLE_UNKNOWN: - case AX_ROLE_WEB_VIEW: + case ax::mojom::Role::kBlockquote: + case ax::mojom::Role::kCaret: + case ax::mojom::Role::kClient: + case ax::mojom::Role::kDefinition: + case ax::mojom::Role::kDesktop: + case ax::mojom::Role::kDirectory: + case ax::mojom::Role::kFigcaption: + case ax::mojom::Role::kFooter: + case ax::mojom::Role::kForm: + case ax::mojom::Role::kIgnored: + case ax::mojom::Role::kImageMap: + case ax::mojom::Role::kInlineTextBox: + case ax::mojom::Role::kLocationBar: + case ax::mojom::Role::kLog: + case ax::mojom::Role::kNone: + case ax::mojom::Role::kPane: + case ax::mojom::Role::kParagraph: + case ax::mojom::Role::kPresentational: + case ax::mojom::Role::kSliderThumb: + case ax::mojom::Role::kSwitch: + case ax::mojom::Role::kUnknown: + case ax::mojom::Role::kWebView: return ROLE_SYSTEM_CLIENT; } @@ -2741,40 +2769,42 @@ int AXPlatformNodeWin::MSAARole() { } std::string AXPlatformNodeWin::StringOverrideForMSAARole() { - std::string html_tag = GetData().GetStringAttribute(AX_ATTR_HTML_TAG); + std::string html_tag = + GetData().GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); switch (GetData().role) { - case AX_ROLE_BLOCKQUOTE: - case AX_ROLE_DEFINITION: - case AX_ROLE_IMAGE_MAP: + case ax::mojom::Role::kBlockquote: + case ax::mojom::Role::kDefinition: + case ax::mojom::Role::kImageMap: return html_tag; - case AX_ROLE_CANVAS: - if (GetData().GetBoolAttribute(AX_ATTR_CANVAS_HAS_FALLBACK)) { + case ax::mojom::Role::kCanvas: + if (GetData().GetBoolAttribute( + ax::mojom::BoolAttribute::kCanvasHasFallback)) { return html_tag; } break; - case AX_ROLE_FORM: + case ax::mojom::Role::kForm: // This could be a div with the role of form // so we return just the string "form". return "form"; - case AX_ROLE_HEADING: + case ax::mojom::Role::kHeading: if (!html_tag.empty()) return html_tag; break; - case AX_ROLE_PARAGRAPH: + case ax::mojom::Role::kParagraph: return html_tag; - case AX_ROLE_GENERIC_CONTAINER: + case ax::mojom::Role::kGenericContainer: // TODO(dougt) why can't we always use div in this case? if (html_tag.empty()) return "div"; return html_tag; - case AX_ROLE_SWITCH: + case ax::mojom::Role::kSwitch: return "switch"; default: @@ -2785,8 +2815,8 @@ std::string AXPlatformNodeWin::StringOverrideForMSAARole() { } bool AXPlatformNodeWin::IsWebAreaForPresentationalIframe() { - if (GetData().role != AX_ROLE_WEB_AREA && - GetData().role != AX_ROLE_ROOT_WEB_AREA) { + if (GetData().role != ax::mojom::Role::kWebArea && + GetData().role != ax::mojom::Role::kRootWebArea) { return false; } @@ -2794,34 +2824,34 @@ bool AXPlatformNodeWin::IsWebAreaForPresentationalIframe() { if (!parent) return false; - return parent->GetData().role == AX_ROLE_IFRAME_PRESENTATIONAL; + return parent->GetData().role == ax::mojom::Role::kIframePresentational; } int32_t AXPlatformNodeWin::ComputeIA2State() { const AXNodeData& data = GetData(); int32_t ia2_state = IA2_STATE_OPAQUE; - const auto checked_state = - static_cast<AXCheckedState>(GetIntAttribute(AX_ATTR_CHECKED_STATE)); - if (checked_state) { + const auto checked_state = data.GetCheckedState(); + if (checked_state != ax::mojom::CheckedState::kNone) { ia2_state |= IA2_STATE_CHECKABLE; } - if (HasIntAttribute(AX_ATTR_INVALID_STATE) && - GetIntAttribute(AX_ATTR_INVALID_STATE) != AX_INVALID_STATE_FALSE) + if (HasIntAttribute(ax::mojom::IntAttribute::kInvalidState) && + GetIntAttribute(ax::mojom::IntAttribute::kInvalidState) != + static_cast<int32_t>(ax::mojom::InvalidState::kFalse)) ia2_state |= IA2_STATE_INVALID_ENTRY; - if (data.HasState(AX_STATE_REQUIRED)) + if (data.HasState(ax::mojom::State::kRequired)) ia2_state |= IA2_STATE_REQUIRED; - if (data.HasState(AX_STATE_VERTICAL)) + if (data.HasState(ax::mojom::State::kVertical)) ia2_state |= IA2_STATE_VERTICAL; - if (data.HasState(AX_STATE_HORIZONTAL)) + if (data.HasState(ax::mojom::State::kHorizontal)) ia2_state |= IA2_STATE_HORIZONTAL; - if (data.HasState(AX_STATE_EDITABLE)) + if (data.HasState(ax::mojom::State::kEditable)) ia2_state |= IA2_STATE_EDITABLE; if (IsPlainTextField() || IsRichTextField()) { - if (data.HasState(AX_STATE_MULTILINE)) { + if (data.HasState(ax::mojom::State::kMultiline)) { ia2_state |= IA2_STATE_MULTI_LINE; } else { ia2_state |= IA2_STATE_SINGLE_LINE; @@ -2829,15 +2859,15 @@ int32_t AXPlatformNodeWin::ComputeIA2State() { ia2_state |= IA2_STATE_SELECTABLE_TEXT; } - if (!GetStringAttribute(AX_ATTR_AUTO_COMPLETE).empty()) + if (!GetStringAttribute(ax::mojom::StringAttribute::kAutoComplete).empty()) ia2_state |= IA2_STATE_SUPPORTS_AUTOCOMPLETION; - if (GetBoolAttribute(AX_ATTR_MODAL)) + if (GetBoolAttribute(ax::mojom::BoolAttribute::kModal)) ia2_state |= IA2_STATE_MODAL; switch (data.role) { - case AX_ROLE_MENU_LIST_POPUP: - case AX_ROLE_MENU_LIST_OPTION: + case ax::mojom::Role::kMenuListPopup: + case ax::mojom::Role::kMenuListOption: ia2_state &= ~(IA2_STATE_EDITABLE); break; default: @@ -2859,117 +2889,118 @@ int32_t AXPlatformNodeWin::ComputeIA2Role() { int32_t ia2_role = 0; switch (GetData().role) { - case AX_ROLE_BANNER: + case ax::mojom::Role::kBanner: ia2_role = IA2_ROLE_HEADER; break; - case AX_ROLE_BLOCKQUOTE: + case ax::mojom::Role::kBlockquote: ia2_role = IA2_ROLE_SECTION; break; - case AX_ROLE_CANVAS: - if (GetBoolAttribute(AX_ATTR_CANVAS_HAS_FALLBACK)) { + case ax::mojom::Role::kCanvas: + if (GetBoolAttribute(ax::mojom::BoolAttribute::kCanvasHasFallback)) { ia2_role = IA2_ROLE_CANVAS; } break; - case AX_ROLE_CAPTION: + case ax::mojom::Role::kCaption: ia2_role = IA2_ROLE_CAPTION; break; - case AX_ROLE_COLOR_WELL: + case ax::mojom::Role::kColorWell: ia2_role = IA2_ROLE_COLOR_CHOOSER; break; - case AX_ROLE_COMPLEMENTARY: + case ax::mojom::Role::kComplementary: ia2_role = IA2_ROLE_NOTE; break; - case AX_ROLE_CONTENT_INFO: + case ax::mojom::Role::kContentInfo: ia2_role = IA2_ROLE_PARAGRAPH; break; - case AX_ROLE_DATE: - case AX_ROLE_DATE_TIME: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kDateTime: ia2_role = IA2_ROLE_DATE_EDITOR; break; - case AX_ROLE_DEFINITION: + case ax::mojom::Role::kDefinition: ia2_role = IA2_ROLE_PARAGRAPH; break; - case AX_ROLE_DESCRIPTION_LIST_DETAIL: + case ax::mojom::Role::kDescriptionListDetail: ia2_role = IA2_ROLE_PARAGRAPH; break; - case AX_ROLE_EMBEDDED_OBJECT: + case ax::mojom::Role::kEmbeddedObject: if (!delegate_->GetChildCount()) { ia2_role = IA2_ROLE_EMBEDDED_OBJECT; } break; - case AX_ROLE_FIGCAPTION: + case ax::mojom::Role::kFigcaption: ia2_role = IA2_ROLE_CAPTION; break; - case AX_ROLE_FORM: + case ax::mojom::Role::kForm: ia2_role = IA2_ROLE_FORM; break; - case AX_ROLE_FOOTER: + case ax::mojom::Role::kFooter: ia2_role = IA2_ROLE_FOOTER; break; - case AX_ROLE_GENERIC_CONTAINER: + case ax::mojom::Role::kGenericContainer: ia2_role = IA2_ROLE_SECTION; break; - case AX_ROLE_HEADING: + case ax::mojom::Role::kHeading: ia2_role = IA2_ROLE_HEADING; break; - case AX_ROLE_IFRAME: + case ax::mojom::Role::kIframe: ia2_role = IA2_ROLE_INTERNAL_FRAME; break; - case AX_ROLE_IMAGE_MAP: + case ax::mojom::Role::kImageMap: ia2_role = IA2_ROLE_IMAGE_MAP; break; - case AX_ROLE_LABEL_TEXT: - case AX_ROLE_LEGEND: + case ax::mojom::Role::kLabelText: + case ax::mojom::Role::kLegend: ia2_role = IA2_ROLE_LABEL; break; - case AX_ROLE_MAIN: + case ax::mojom::Role::kMain: ia2_role = IA2_ROLE_PARAGRAPH; break; - case AX_ROLE_MARK: + case ax::mojom::Role::kMark: ia2_role = IA2_ROLE_TEXT_FRAME; break; - case AX_ROLE_MENU_ITEM_CHECK_BOX: + case ax::mojom::Role::kMenuItemCheckBox: ia2_role = IA2_ROLE_CHECK_MENU_ITEM; break; - case AX_ROLE_MENU_ITEM_RADIO: + case ax::mojom::Role::kMenuItemRadio: ia2_role = IA2_ROLE_RADIO_MENU_ITEM; break; - case AX_ROLE_NAVIGATION: + case ax::mojom::Role::kNavigation: ia2_role = IA2_ROLE_SECTION; break; - case AX_ROLE_NOTE: + case ax::mojom::Role::kNote: ia2_role = IA2_ROLE_NOTE; break; - case AX_ROLE_PARAGRAPH: + case ax::mojom::Role::kParagraph: ia2_role = IA2_ROLE_PARAGRAPH; break; - case AX_ROLE_PRE: + case ax::mojom::Role::kPre: ia2_role = IA2_ROLE_PARAGRAPH; break; - case AX_ROLE_REGION: { - base::string16 html_tag = GetString16Attribute(AX_ATTR_HTML_TAG); + case ax::mojom::Role::kRegion: { + base::string16 html_tag = + GetString16Attribute(ax::mojom::StringAttribute::kHtmlTag); if (html_tag == L"section") { ia2_role = IA2_ROLE_SECTION; } } break; - case AX_ROLE_RUBY: + case ax::mojom::Role::kRuby: ia2_role = IA2_ROLE_TEXT_FRAME; break; - case AX_ROLE_SEARCH: + case ax::mojom::Role::kSearch: ia2_role = IA2_ROLE_SECTION; break; - case AX_ROLE_SWITCH: + case ax::mojom::Role::kSwitch: ia2_role = IA2_ROLE_TOGGLE_BUTTON; break; - case AX_ROLE_TABLE_HEADER_CONTAINER: + case ax::mojom::Role::kTableHeaderContainer: ia2_role = IA2_ROLE_SECTION; break; - case AX_ROLE_TOGGLE_BUTTON: + case ax::mojom::Role::kToggleButton: ia2_role = IA2_ROLE_TOGGLE_BUTTON; break; - case AX_ROLE_ABBR: - case AX_ROLE_TIME: + case ax::mojom::Role::kAbbr: + case ax::mojom::Role::kTime: ia2_role = IA2_ROLE_TEXT_FRAME; break; default: @@ -2985,71 +3016,82 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() { // historical reasons. Aside from that virtually every ARIA attribute // is exposed in a really straightforward way, i.e. "aria-foo" is exposed // as "foo". - StringAttributeToIA2(result, AX_ATTR_DISPLAY, "display"); - StringAttributeToIA2(result, AX_ATTR_HTML_TAG, "tag"); - StringAttributeToIA2(result, AX_ATTR_ROLE, "xml-roles"); - StringAttributeToIA2(result, AX_ATTR_PLACEHOLDER, "placeholder"); - - StringAttributeToIA2(result, AX_ATTR_AUTO_COMPLETE, "autocomplete"); - StringAttributeToIA2(result, AX_ATTR_ROLE_DESCRIPTION, "roledescription"); - StringAttributeToIA2(result, AX_ATTR_KEY_SHORTCUTS, "keyshortcuts"); - - IntAttributeToIA2(result, AX_ATTR_HIERARCHICAL_LEVEL, "level"); - IntAttributeToIA2(result, AX_ATTR_SET_SIZE, "setsize"); - IntAttributeToIA2(result, AX_ATTR_POS_IN_SET, "posinset"); - - if (HasIntAttribute(AX_ATTR_CHECKED_STATE)) + StringAttributeToIA2(result, ax::mojom::StringAttribute::kDisplay, "display"); + StringAttributeToIA2(result, ax::mojom::StringAttribute::kHtmlTag, "tag"); + StringAttributeToIA2(result, ax::mojom::StringAttribute::kRole, "xml-roles"); + StringAttributeToIA2(result, ax::mojom::StringAttribute::kPlaceholder, + "placeholder"); + + StringAttributeToIA2(result, ax::mojom::StringAttribute::kAutoComplete, + "autocomplete"); + StringAttributeToIA2(result, ax::mojom::StringAttribute::kRoleDescription, + "roledescription"); + StringAttributeToIA2(result, ax::mojom::StringAttribute::kKeyShortcuts, + "keyshortcuts"); + + IntAttributeToIA2(result, ax::mojom::IntAttribute::kHierarchicalLevel, + "level"); + IntAttributeToIA2(result, ax::mojom::IntAttribute::kSetSize, "setsize"); + IntAttributeToIA2(result, ax::mojom::IntAttribute::kPosInSet, "posinset"); + + if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState)) result.push_back(L"checkable:true"); // Expose live region attributes. - StringAttributeToIA2(result, AX_ATTR_LIVE_STATUS, "live"); - StringAttributeToIA2(result, AX_ATTR_LIVE_RELEVANT, "relevant"); - BoolAttributeToIA2(result, AX_ATTR_LIVE_ATOMIC, "atomic"); + StringAttributeToIA2(result, ax::mojom::StringAttribute::kLiveStatus, "live"); + StringAttributeToIA2(result, ax::mojom::StringAttribute::kLiveRelevant, + "relevant"); + BoolAttributeToIA2(result, ax::mojom::BoolAttribute::kLiveAtomic, "atomic"); // Busy is usually associated with live regions but can occur anywhere: - BoolAttributeToIA2(result, AX_ATTR_BUSY, "busy"); + BoolAttributeToIA2(result, ax::mojom::BoolAttribute::kBusy, "busy"); // Expose container live region attributes. - StringAttributeToIA2(result, AX_ATTR_CONTAINER_LIVE_STATUS, "container-live"); - StringAttributeToIA2(result, AX_ATTR_CONTAINER_LIVE_RELEVANT, + StringAttributeToIA2(result, ax::mojom::StringAttribute::kContainerLiveStatus, + "container-live"); + StringAttributeToIA2(result, + ax::mojom::StringAttribute::kContainerLiveRelevant, "container-relevant"); - BoolAttributeToIA2(result, AX_ATTR_CONTAINER_LIVE_ATOMIC, "container-atomic"); - BoolAttributeToIA2(result, AX_ATTR_CONTAINER_LIVE_BUSY, "container-busy"); + BoolAttributeToIA2(result, ax::mojom::BoolAttribute::kContainerLiveAtomic, + "container-atomic"); + BoolAttributeToIA2(result, ax::mojom::BoolAttribute::kContainerLiveBusy, + "container-busy"); // Expose the non-standard explicit-name IA2 attribute. int name_from; - if (GetIntAttribute(AX_ATTR_NAME_FROM, &name_from) && - name_from != AX_NAME_FROM_CONTENTS) { + if (GetIntAttribute(ax::mojom::IntAttribute::kNameFrom, &name_from) && + name_from != static_cast<int32_t>(ax::mojom::NameFrom::kContents)) { result.push_back(L"explicit-name:true"); } // Expose the aria-current attribute. int32_t aria_current_state; - if (GetIntAttribute(AX_ATTR_ARIA_CURRENT_STATE, &aria_current_state)) { - switch (static_cast<AXAriaCurrentState>(aria_current_state)) { - case AX_ARIA_CURRENT_STATE_NONE: + if (GetIntAttribute(ax::mojom::IntAttribute::kAriaCurrentState, + &aria_current_state)) { + switch (static_cast<ax::mojom::AriaCurrentState>(aria_current_state)) { + case ax::mojom::AriaCurrentState::kNone: break; - case AX_ARIA_CURRENT_STATE_FALSE: + case ax::mojom::AriaCurrentState::kFalse: result.push_back(L"current:false"); break; - case AX_ARIA_CURRENT_STATE_TRUE: + case ax::mojom::AriaCurrentState::kTrue: result.push_back(L"current:true"); break; - case AX_ARIA_CURRENT_STATE_PAGE: + case ax::mojom::AriaCurrentState::kPage: result.push_back(L"current:page"); break; - case AX_ARIA_CURRENT_STATE_STEP: + case ax::mojom::AriaCurrentState::kStep: result.push_back(L"current:step"); break; - case AX_ARIA_CURRENT_STATE_LOCATION: + case ax::mojom::AriaCurrentState::kLocation: result.push_back(L"current:location"); break; - case AX_ARIA_CURRENT_STATE_UNCLIPPED_LOCATION: + case ax::mojom::AriaCurrentState::kUnclippedLocation: result.push_back(L"current:unclippedLocation"); break; - case AX_ARIA_CURRENT_STATE_DATE: + case ax::mojom::AriaCurrentState::kDate: result.push_back(L"current:date"); break; - case AX_ARIA_CURRENT_STATE_TIME: + case ax::mojom::AriaCurrentState::kTime: result.push_back(L"current:time"); break; } @@ -3063,8 +3105,8 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() { table = FromNativeViewAccessible(table->GetParent()); if (table) { - const std::vector<int32_t>& unique_cell_ids = - table->GetIntListAttribute(AX_ATTR_UNIQUE_CELL_IDS); + const std::vector<int32_t>& unique_cell_ids = table->GetIntListAttribute( + ax::mojom::IntListAttribute::kUniqueCellIds); for (size_t i = 0; i < unique_cell_ids.size(); ++i) { if (unique_cell_ids[i] == GetData().id) { result.push_back(base::string16(L"table-cell-index:") + @@ -3073,19 +3115,25 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() { } } } + if (GetData().role == ax::mojom::Role::kLayoutTable) + result.push_back(base::string16(L"layout-guess:true")); // Expose aria-colcount and aria-rowcount in a table, grid or treegrid. if (IsTableLikeRole(GetData().role)) { - IntAttributeToIA2(result, AX_ATTR_ARIA_COLUMN_COUNT, "colcount"); - IntAttributeToIA2(result, AX_ATTR_ARIA_ROW_COUNT, "rowcount"); + IntAttributeToIA2(result, ax::mojom::IntAttribute::kAriaColumnCount, + "colcount"); + IntAttributeToIA2(result, ax::mojom::IntAttribute::kAriaRowCount, + "rowcount"); } // Expose aria-colindex and aria-rowindex in a cell or row. if (IsCellOrTableHeaderRole(GetData().role) || - GetData().role == AX_ROLE_ROW) { - if (GetData().role != AX_ROLE_ROW) - IntAttributeToIA2(result, AX_ATTR_ARIA_CELL_COLUMN_INDEX, "colindex"); - IntAttributeToIA2(result, AX_ATTR_ARIA_CELL_ROW_INDEX, "rowindex"); + GetData().role == ax::mojom::Role::kRow) { + if (GetData().role != ax::mojom::Role::kRow) + IntAttributeToIA2(result, ax::mojom::IntAttribute::kAriaCellColumnIndex, + "colindex"); + IntAttributeToIA2(result, ax::mojom::IntAttribute::kAriaCellRowIndex, + "rowindex"); // Experimental: expose aria-rowtext / aria-coltext. Not standardized // yet, but obscure enough that it's safe to expose. @@ -3108,20 +3156,21 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() { int32_t sort_direction; if ((MSAARole() == ROLE_SYSTEM_COLUMNHEADER || MSAARole() == ROLE_SYSTEM_ROWHEADER) && - GetIntAttribute(AX_ATTR_SORT_DIRECTION, &sort_direction)) { - switch (static_cast<AXSortDirection>(sort_direction)) { - case AX_SORT_DIRECTION_NONE: + GetIntAttribute(ax::mojom::IntAttribute::kSortDirection, + &sort_direction)) { + switch (static_cast<ax::mojom::SortDirection>(sort_direction)) { + case ax::mojom::SortDirection::kNone: break; - case AX_SORT_DIRECTION_UNSORTED: + case ax::mojom::SortDirection::kUnsorted: result.push_back(L"sort:none"); break; - case AX_SORT_DIRECTION_ASCENDING: + case ax::mojom::SortDirection::kAscending: result.push_back(L"sort:ascending"); break; - case AX_SORT_DIRECTION_DESCENDING: + case ax::mojom::SortDirection::kDescending: result.push_back(L"sort:descending"); break; - case AX_SORT_DIRECTION_OTHER: + case ax::mojom::SortDirection::kOther: result.push_back(L"sort:other"); break; } @@ -3166,14 +3215,16 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() { // Expose class attribute. base::string16 class_attr; - if (GetData().GetHtmlAttribute("class", &class_attr)) { + if (GetData().GetHtmlAttribute("class", &class_attr) || + GetData().GetString16Attribute(ax::mojom::StringAttribute::kClassName, + &class_attr)) { SanitizeStringAttributeForIA2(class_attr, &class_attr); result.push_back(L"class:" + class_attr); } // Expose datetime attribute. base::string16 datetime; - if (GetData().role == AX_ROLE_TIME && + if (GetData().role == ax::mojom::Role::kTime && GetData().GetHtmlAttribute("datetime", &datetime)) { SanitizeStringAttributeForIA2(datetime, &datetime); result.push_back(L"datetime:" + datetime); @@ -3188,7 +3239,7 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() { // Expose src attribute. base::string16 src; - if (GetData().role == AX_ROLE_IMAGE && + if (GetData().role == ax::mojom::Role::kImage && GetData().GetHtmlAttribute("src", &src)) { SanitizeStringAttributeForIA2(src, &src); result.push_back(L"src:" + src); @@ -3204,7 +3255,8 @@ std::vector<base::string16> AXPlatformNodeWin::ComputeIA2Attributes() { // Expose input-text type attribute. base::string16 type; - base::string16 html_tag = GetString16Attribute(AX_ATTR_HTML_TAG); + base::string16 html_tag = + GetString16Attribute(ax::mojom::StringAttribute::kHtmlTag); if (IsPlainTextField() && html_tag == L"input" && GetData().GetHtmlAttribute("type", &type)) { SanitizeStringAttributeForIA2(type, &type); @@ -3223,7 +3275,7 @@ base::string16 AXPlatformNodeWin::GetValue() { // TODO(dougt): Look into ensuring that on click handlers correctly provide // a value here. if (value.empty() && (MSAAState() & STATE_SYSTEM_LINKED)) - value = GetString16Attribute(ui::AX_ATTR_URL); + value = GetString16Attribute(ax::mojom::StringAttribute::kUrl); return value; } @@ -3243,7 +3295,7 @@ AXHypertext AXPlatformNodeWin::ComputeHypertext() { // We don't want to expose any associated label in IA2 Hypertext. return result; } - result.hypertext = GetString16Attribute(ui::AX_ATTR_NAME); + result.hypertext = GetString16Attribute(ax::mojom::StringAttribute::kName); return result; } @@ -3260,7 +3312,8 @@ AXHypertext AXPlatformNodeWin::ComputeHypertext() { DCHECK(child); // Similar to Firefox, we don't expose text-only objects in IA2 hypertext. if (child->IsTextOnlyObject()) { - hypertext += child->GetString16Attribute(ui::AX_ATTR_NAME); + hypertext += + child->GetString16Attribute(ax::mojom::StringAttribute::kName); } else { int32_t char_offset = static_cast<int32_t>(hypertext.size()); int32_t child_unique_id = child->GetUniqueId(); @@ -3277,26 +3330,26 @@ AXHypertext AXPlatformNodeWin::ComputeHypertext() { bool AXPlatformNodeWin::ShouldNodeHaveReadonlyStateByDefault( const AXNodeData& data) const { switch (data.role) { - case AX_ROLE_ARTICLE: - case AX_ROLE_DEFINITION: - case AX_ROLE_DESCRIPTION_LIST: - case AX_ROLE_DESCRIPTION_LIST_TERM: - case AX_ROLE_DOCUMENT: - case AX_ROLE_IFRAME: - case AX_ROLE_IMAGE: - case AX_ROLE_IMAGE_MAP: - case AX_ROLE_LIST: - case AX_ROLE_LIST_ITEM: - case AX_ROLE_PROGRESS_INDICATOR: - case AX_ROLE_ROOT_WEB_AREA: - case AX_ROLE_TERM: - case AX_ROLE_TIMER: - case AX_ROLE_TOOLBAR: - case AX_ROLE_TOOLTIP: - case AX_ROLE_WEB_AREA: + case ax::mojom::Role::kArticle: + case ax::mojom::Role::kDefinition: + case ax::mojom::Role::kDescriptionList: + case ax::mojom::Role::kDescriptionListTerm: + case ax::mojom::Role::kDocument: + case ax::mojom::Role::kIframe: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kImageMap: + case ax::mojom::Role::kList: + case ax::mojom::Role::kListItem: + case ax::mojom::Role::kProgressIndicator: + case ax::mojom::Role::kRootWebArea: + case ax::mojom::Role::kTerm: + case ax::mojom::Role::kTimer: + case ax::mojom::Role::kToolbar: + case ax::mojom::Role::kTooltip: + case ax::mojom::Role::kWebArea: return true; - case AX_ROLE_GRID: + case ax::mojom::Role::kGrid: // TODO(aleventhal) this changed between ARIA 1.0 and 1.1, // need to determine whether grids/treegrids should really be readonly // or editable by default @@ -3312,56 +3365,57 @@ bool AXPlatformNodeWin::ShouldNodeHaveReadonlyStateByDefault( bool AXPlatformNodeWin::ShouldNodeHaveFocusableState( const AXNodeData& data) const { switch (data.role) { - case AX_ROLE_DOCUMENT: - case AX_ROLE_ROOT_WEB_AREA: - case AX_ROLE_WEB_AREA: + case ax::mojom::Role::kDocument: + case ax::mojom::Role::kRootWebArea: + case ax::mojom::Role::kWebArea: return true; - case AX_ROLE_IFRAME: + case ax::mojom::Role::kIframe: return false; - case AX_ROLE_LIST_BOX_OPTION: - case AX_ROLE_MENU_LIST_OPTION: - if (data.HasState(AX_STATE_SELECTABLE)) + case ax::mojom::Role::kListBoxOption: + case ax::mojom::Role::kMenuListOption: + if (data.HasState(ax::mojom::State::kSelectable)) return true; + break; default: break; } - return data.HasState(AX_STATE_FOCUSABLE); + return data.HasState(ax::mojom::State::kFocusable); } int AXPlatformNodeWin::MSAAState() { const AXNodeData& data = GetData(); int msaa_state = 0; - // Map the AXState to MSAA state. Note that some of the states are not - // currently handled. + // Map the ax::mojom::State to MSAA state. Note that some of the states are + // not currently handled. - if (data.GetBoolAttribute(AX_ATTR_BUSY)) + if (data.GetBoolAttribute(ax::mojom::BoolAttribute::kBusy)) msaa_state |= STATE_SYSTEM_BUSY; - if (data.HasState(AX_STATE_COLLAPSED)) + if (data.HasState(ax::mojom::State::kCollapsed)) msaa_state |= STATE_SYSTEM_COLLAPSED; - if (data.HasState(AX_STATE_DEFAULT)) + if (data.HasState(ax::mojom::State::kDefault)) msaa_state |= STATE_SYSTEM_DEFAULT; - // TODO(dougt) unhandled ux::AX_STATE_EDITABLE + // TODO(dougt) unhandled ux::ax::mojom::State::kEditable - if (data.HasState(AX_STATE_EXPANDED)) + if (data.HasState(ax::mojom::State::kExpanded)) msaa_state |= STATE_SYSTEM_EXPANDED; if (ShouldNodeHaveFocusableState(data)) msaa_state |= STATE_SYSTEM_FOCUSABLE; - if (data.HasState(AX_STATE_HASPOPUP)) + if (data.HasState(ax::mojom::State::kHaspopup)) msaa_state |= STATE_SYSTEM_HASPOPUP; - // TODO(dougt) unhandled ux::AX_STATE_HORIZONTAL + // TODO(dougt) unhandled ux::ax::mojom::State::kHorizontal - if (data.HasState(AX_STATE_HOVERED)) { + if (data.HasState(ax::mojom::State::kHovered)) { // Expose whether or not the mouse is over an element, but suppress // this for tests because it can make the test results flaky depending // on the position of the mouse. @@ -3371,15 +3425,16 @@ int AXPlatformNodeWin::MSAAState() { // If the role is IGNORED, we want these elements to be invisible so that // these nodes are hidden from the screen reader. - if (data.HasState(AX_STATE_INVISIBLE) || GetData().role == AX_ROLE_IGNORED) { + if (data.HasState(ax::mojom::State::kInvisible) || + GetData().role == ax::mojom::Role::kIgnored) { msaa_state |= STATE_SYSTEM_INVISIBLE; } - if (data.HasState(AX_STATE_LINKED)) + if (data.HasState(ax::mojom::State::kLinked)) msaa_state |= STATE_SYSTEM_LINKED; - // TODO(dougt) unhandled ux::AX_STATE_MULTILINE + // TODO(dougt) unhandled ux::ax::mojom::State::kMultiline - if (data.HasState(AX_STATE_MULTISELECTABLE)) { + if (data.HasState(ax::mojom::State::kMultiselectable)) { msaa_state |= STATE_SYSTEM_EXTSELECTABLE; msaa_state |= STATE_SYSTEM_MULTISELECTABLE; } @@ -3387,47 +3442,48 @@ int AXPlatformNodeWin::MSAAState() { if (delegate_->IsOffscreen()) msaa_state |= STATE_SYSTEM_OFFSCREEN; - if (data.HasState(AX_STATE_PROTECTED)) + if (data.HasState(ax::mojom::State::kProtected)) msaa_state |= STATE_SYSTEM_PROTECTED; - // TODO(dougt) unhandled ux::AX_STATE_REQUIRED - // TODO(dougt) unhandled ux::AX_STATE_RICHLY_EDITABLE + // TODO(dougt) unhandled ux::ax::mojom::State::kRequired + // TODO(dougt) unhandled ux::ax::mojom::State::kRichlyEditable - if (data.HasState(AX_STATE_SELECTABLE)) + if (data.HasState(ax::mojom::State::kSelectable)) msaa_state |= STATE_SYSTEM_SELECTABLE; - if (data.HasState(AX_STATE_SELECTED)) + if (data.HasState(ax::mojom::State::kSelected)) msaa_state |= STATE_SYSTEM_SELECTED; // TODO(dougt) unhandled VERTICAL - if (data.HasState(AX_STATE_VISITED)) + if (data.HasState(ax::mojom::State::kVisited)) msaa_state |= STATE_SYSTEM_TRAVERSED; // // Checked state // - const auto checked_state = - static_cast<AXCheckedState>(GetIntAttribute(AX_ATTR_CHECKED_STATE)); + const auto checked_state = static_cast<ax::mojom::CheckedState>( + GetIntAttribute(ax::mojom::IntAttribute::kCheckedState)); switch (checked_state) { - case AX_CHECKED_STATE_TRUE: - msaa_state |= data.role == AX_ROLE_TOGGLE_BUTTON ? STATE_SYSTEM_PRESSED - : STATE_SYSTEM_CHECKED; + case ax::mojom::CheckedState::kTrue: + msaa_state |= data.role == ax::mojom::Role::kToggleButton + ? STATE_SYSTEM_PRESSED + : STATE_SYSTEM_CHECKED; break; - case AX_CHECKED_STATE_MIXED: + case ax::mojom::CheckedState::kMixed: msaa_state |= STATE_SYSTEM_MIXED; break; default: break; } - const auto restriction = - static_cast<AXRestriction>(GetIntAttribute(AX_ATTR_RESTRICTION)); + const auto restriction = static_cast<ax::mojom::Restriction>( + GetIntAttribute(ax::mojom::IntAttribute::kRestriction)); switch (restriction) { - case AX_RESTRICTION_DISABLED: + case ax::mojom::Restriction::kDisabled: msaa_state |= STATE_SYSTEM_UNAVAILABLE; break; - case AX_RESTRICTION_READ_ONLY: + case ax::mojom::Restriction::kReadOnly: msaa_state |= STATE_SYSTEM_READONLY; break; default: @@ -3435,7 +3491,7 @@ int AXPlatformNodeWin::MSAAState() { // on *some* document structure roles such as paragraph, heading or list // even if the node data isn't marked as read only, as long as the // node is not editable. - if (!data.HasState(AX_STATE_RICHLY_EDITABLE) && + if (!data.HasState(ax::mojom::State::kRichlyEditable) && ShouldNodeHaveReadonlyStateByDefault(data)) msaa_state |= STATE_SYSTEM_READONLY; break; @@ -3454,55 +3510,59 @@ int AXPlatformNodeWin::MSAAState() { // TODO(dmazzoni): this should probably check if focus is actually inside // the menu bar, but we don't currently track focus inside menu pop-ups, // and Chrome only has one menu visible at a time so this works for now. - if (data.role == AX_ROLE_MENU_BAR && !(data.HasState(AX_STATE_INVISIBLE))) { + if (data.role == ax::mojom::Role::kMenuBar && + !(data.HasState(ax::mojom::State::kInvisible))) { msaa_state |= STATE_SYSTEM_FOCUSED; } // Handle STATE_SYSTEM_LINKED - if (GetData().role == AX_ROLE_LINK) + if (GetData().role == ax::mojom::Role::kLink) msaa_state |= STATE_SYSTEM_LINKED; // Special case for indeterminate progressbar. - if (GetData().role == AX_ROLE_PROGRESS_INDICATOR && - !HasFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE)) + if (GetData().role == ax::mojom::Role::kProgressIndicator && + !HasFloatAttribute(ax::mojom::FloatAttribute::kValueForRange)) msaa_state |= STATE_SYSTEM_MIXED; return msaa_state; } -int AXPlatformNodeWin::MSAAEvent(AXEvent event) { +int AXPlatformNodeWin::MSAAEvent(ax::mojom::Event event) { switch (event) { - case AX_EVENT_ALERT: + case ax::mojom::Event::kAlert: return EVENT_SYSTEM_ALERT; - case AX_EVENT_FOCUS: + case ax::mojom::Event::kExpandedChanged: + return EVENT_OBJECT_STATECHANGE; + case ax::mojom::Event::kFocus: return EVENT_OBJECT_FOCUS; - case AX_EVENT_MENU_START: + case ax::mojom::Event::kMenuStart: return EVENT_SYSTEM_MENUSTART; - case AX_EVENT_MENU_END: + case ax::mojom::Event::kMenuEnd: return EVENT_SYSTEM_MENUEND; - case AX_EVENT_MENU_POPUP_START: + case ax::mojom::Event::kMenuPopupStart: return EVENT_SYSTEM_MENUPOPUPSTART; - case AX_EVENT_MENU_POPUP_END: + case ax::mojom::Event::kMenuPopupEnd: return EVENT_SYSTEM_MENUPOPUPEND; - case AX_EVENT_SELECTION: + case ax::mojom::Event::kSelection: return EVENT_OBJECT_SELECTION; - case AX_EVENT_SELECTION_ADD: + case ax::mojom::Event::kSelectionAdd: return EVENT_OBJECT_SELECTIONADD; - case AX_EVENT_SELECTION_REMOVE: + case ax::mojom::Event::kSelectionRemove: return EVENT_OBJECT_SELECTIONREMOVE; - case AX_EVENT_TEXT_CHANGED: + case ax::mojom::Event::kTextChanged: return EVENT_OBJECT_NAMECHANGE; - case AX_EVENT_TEXT_SELECTION_CHANGED: + case ax::mojom::Event::kTextSelectionChanged: return IA2_EVENT_TEXT_CARET_MOVED; - case AX_EVENT_VALUE_CHANGED: + case ax::mojom::Event::kValueChanged: return EVENT_OBJECT_VALUECHANGE; default: return -1; } } -HRESULT AXPlatformNodeWin::GetStringAttributeAsBstr(AXStringAttribute attribute, - BSTR* value_bstr) const { +HRESULT AXPlatformNodeWin::GetStringAttributeAsBstr( + ax::mojom::StringAttribute attribute, + BSTR* value_bstr) const { base::string16 str; if (!GetString16Attribute(attribute, &str)) @@ -3526,7 +3586,7 @@ void AXPlatformNodeWin::RemoveAlertTarget() { base::string16 AXPlatformNodeWin::TextForIAccessibleText() { // Special case allows us to get text even in non-HTML case, e.g. browser UI. if (IsPlainTextField()) - return GetString16Attribute(AX_ATTR_VALUE); + return GetString16Attribute(ax::mojom::StringAttribute::kValue); return GetText(); } @@ -3536,9 +3596,12 @@ void AXPlatformNodeWin::HandleSpecialTextOffset(LONG* offset) { } else if (*offset == IA2_TEXT_OFFSET_CARET) { int selection_start, selection_end; GetSelectionOffsets(&selection_start, &selection_end); + // TODO(nektar): Deprecate selection_start and selection_end in favor of + // sel_anchor_offset/sel_focus_offset. See https://crbug.com/645596. if (selection_end < 0) *offset = 0; - *offset = static_cast<LONG>(selection_end); + else + *offset = static_cast<LONG>(selection_end); } } @@ -3570,9 +3633,9 @@ LONG AXPlatformNodeWin::FindBoundary(const base::string16& text, HandleSpecialTextOffset(&start_offset); TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); std::vector<int32_t> line_breaks; - return static_cast<LONG>( - FindAccessibleTextBoundary(text, line_breaks, boundary, start_offset, - direction, AX_TEXT_AFFINITY_DOWNSTREAM)); + return static_cast<LONG>(FindAccessibleTextBoundary( + text, line_breaks, boundary, start_offset, direction, + ax::mojom::TextAffinity::kDownstream)); } AXPlatformNodeWin* AXPlatformNodeWin::GetTargetFromChildID( @@ -3612,13 +3675,13 @@ bool AXPlatformNodeWin::IsInTreeGrid() { AXPlatformNodeBase* container = FromNativeViewAccessible(GetParent()); // If parent was a rowgroup, we need to look at the grandparent - if (container && container->GetData().role == AX_ROLE_GROUP) + if (container && container->GetData().role == ax::mojom::Role::kGroup) container = FromNativeViewAccessible(container->GetParent()); if (!container) return false; - return container->GetData().role == AX_ROLE_TREE_GRID; + return container->GetData().role == ax::mojom::Role::kTreeGrid; } HRESULT AXPlatformNodeWin::AllocateComArrayFromVector( @@ -3923,8 +3986,9 @@ void AXPlatformNodeWin::GetSelectionOffsets(int* selection_start, DCHECK(selection_start && selection_end); if (IsPlainTextField() && - GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START, selection_start) && - GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END, selection_end)) { + GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart, + selection_start) && + GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, selection_end)) { return; } diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.h b/chromium/ui/accessibility/platform/ax_platform_node_win.h index 7b49fa9b316..4efab44077a 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_win.h +++ b/chromium/ui/accessibility/platform/ax_platform_node_win.h @@ -270,7 +270,7 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2")) // AXPlatformNode overrides. gfx::NativeViewAccessible GetNativeViewAccessible() override; - void NotifyAccessibilityEvent(AXEvent event_type) override; + void NotifyAccessibilityEvent(ax::mojom::Event event_type) override; // AXPlatformNodeBase overrides. void Destroy() override; @@ -708,12 +708,12 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2")) TextBoundaryType IA2TextBoundaryToTextBoundary(IA2TextBoundaryType type); private: - int MSAAEvent(AXEvent event); + int MSAAEvent(ax::mojom::Event event); bool IsWebAreaForPresentationalIframe(); bool ShouldNodeHaveReadonlyStateByDefault(const AXNodeData& data) const; bool ShouldNodeHaveFocusableState(const AXNodeData& data) const; - HRESULT GetStringAttributeAsBstr(AXStringAttribute attribute, + HRESULT GetStringAttributeAsBstr(ax::mojom::StringAttribute attribute, BSTR* value_bstr) const; // Escapes characters in string attributes as required by the IA2 Spec. @@ -727,19 +727,19 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2")) // If the string attribute |attribute| is present, add its value as an // IAccessible2 attribute with the name |ia2_attr|. void StringAttributeToIA2(std::vector<base::string16>& attributes, - AXStringAttribute attribute, + ax::mojom::StringAttribute attribute, const char* ia2_attr); // If the bool attribute |attribute| is present, add its value as an // IAccessible2 attribute with the name |ia2_attr|. void BoolAttributeToIA2(std::vector<base::string16>& attributes, - AXBoolAttribute attribute, + ax::mojom::BoolAttribute attribute, const char* ia2_attr); // If the int attribute |attribute| is present, add its value as an // IAccessible2 attribute with the name |ia2_attr|. void IntAttributeToIA2(std::vector<base::string16>& attributes, - AXIntAttribute attribute, + ax::mojom::IntAttribute attribute, const char* ia2_attr); void AddAlertTarget(); diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc index 7a7ea0db3e1..20de83957ca 100644 --- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc +++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc @@ -206,7 +206,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleName) { TEST_F(AXPlatformNodeWinTest, TestIAccessibleDescription) { AXNodeData root; root.id = 1; - root.AddStringAttribute(AX_ATTR_DESCRIPTION, "Description"); + root.AddStringAttribute(ax::mojom::StringAttribute::kDescription, + "Description"); Init(root); ComPtr<IAccessible> root_obj(GetRootIAccessible()); @@ -223,7 +224,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleDescription) { TEST_F(AXPlatformNodeWinTest, TestIAccessibleValue) { AXNodeData root; root.id = 1; - root.AddStringAttribute(AX_ATTR_VALUE, "Value"); + root.AddStringAttribute(ax::mojom::StringAttribute::kValue, "Value"); Init(root); ComPtr<IAccessible> root_obj(GetRootIAccessible()); @@ -240,7 +241,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleValue) { TEST_F(AXPlatformNodeWinTest, TestIAccessibleShortcut) { AXNodeData root; root.id = 1; - root.AddStringAttribute(AX_ATTR_KEY_SHORTCUTS, "Shortcut"); + root.AddStringAttribute(ax::mojom::StringAttribute::kKeyShortcuts, + "Shortcut"); Init(root); ComPtr<IAccessible> root_obj(GetRootIAccessible()); @@ -259,16 +261,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionListBoxOptionNothingSelected) { AXNodeData list; list.id = 0; - list.role = AX_ROLE_LIST_BOX; + list.role = ax::mojom::Role::kListBox; AXNodeData list_item_1; list_item_1.id = 1; - list_item_1.role = AX_ROLE_LIST_BOX_OPTION; + list_item_1.role = ax::mojom::Role::kListBoxOption; list_item_1.SetName("Name1"); AXNodeData list_item_2; list_item_2.id = 2; - list_item_2.role = AX_ROLE_LIST_BOX_OPTION; + list_item_2.role = ax::mojom::Role::kListBoxOption; list_item_2.SetName("Name2"); list.child_ids.push_back(list_item_1.id); @@ -288,17 +290,17 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionListBoxOptionOneSelected) { AXNodeData list; list.id = 0; - list.role = AX_ROLE_LIST_BOX; + list.role = ax::mojom::Role::kListBox; AXNodeData list_item_1; list_item_1.id = 1; - list_item_1.role = AX_ROLE_LIST_BOX_OPTION; - list_item_1.AddState(AX_STATE_SELECTED); + list_item_1.role = ax::mojom::Role::kListBoxOption; + list_item_1.AddState(ax::mojom::State::kSelected); list_item_1.SetName("Name1"); AXNodeData list_item_2; list_item_2.id = 2; - list_item_2.role = AX_ROLE_LIST_BOX_OPTION; + list_item_2.role = ax::mojom::Role::kListBoxOption; list_item_2.SetName("Name2"); list.child_ids.push_back(list_item_1.id); @@ -320,23 +322,23 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionListBoxOptionMultipleSelected) { AXNodeData list; list.id = 0; - list.role = AX_ROLE_LIST_BOX; + list.role = ax::mojom::Role::kListBox; AXNodeData list_item_1; list_item_1.id = 1; - list_item_1.role = AX_ROLE_LIST_BOX_OPTION; - list_item_1.AddState(AX_STATE_SELECTED); + list_item_1.role = ax::mojom::Role::kListBoxOption; + list_item_1.AddState(ax::mojom::State::kSelected); list_item_1.SetName("Name1"); AXNodeData list_item_2; list_item_2.id = 2; - list_item_2.role = AX_ROLE_LIST_BOX_OPTION; - list_item_2.AddState(AX_STATE_SELECTED); + list_item_2.role = ax::mojom::Role::kListBoxOption; + list_item_2.AddState(ax::mojom::State::kSelected); list_item_2.SetName("Name2"); AXNodeData list_item_3; list_item_3.id = 3; - list_item_3.role = AX_ROLE_LIST_BOX_OPTION; + list_item_3.role = ax::mojom::Role::kListBoxOption; list_item_3.SetName("Name3"); list.child_ids.push_back(list_item_1.id); @@ -413,7 +415,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionTableRowOneSelected) { AXTreeUpdate update = Build3X3Table(); // 5 == table_row_1 - update.nodes[5].AddState(AX_STATE_SELECTED); + update.nodes[5].AddState(ax::mojom::State::kSelected); Init(update); @@ -441,8 +443,8 @@ TEST_F(AXPlatformNodeWinTest, // 5 == table_row_1 // 9 == table_row_2 - update.nodes[5].AddState(AX_STATE_SELECTED); - update.nodes[9].AddState(AX_STATE_SELECTED); + update.nodes[5].AddState(ax::mojom::State::kSelected); + update.nodes[9].AddState(ax::mojom::State::kSelected); Init(update); @@ -503,7 +505,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleSelectionTableCellOneSelected) { AXTreeUpdate update = Build3X3Table(); // 7 == table_cell_1 - update.nodes[7].AddState(AX_STATE_SELECTED); + update.nodes[7].AddState(ax::mojom::State::kSelected); Init(update); @@ -541,8 +543,8 @@ TEST_F(AXPlatformNodeWinTest, // 11 == table_cell_3 // 12 == table_cell_4 - update.nodes[11].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[11].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -619,17 +621,17 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleRole) { ScopedVariant role; - child.role = AX_ROLE_ALERT; + child.role = ax::mojom::Role::kAlert; child_node->SetData(child); EXPECT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive())); EXPECT_EQ(ROLE_SYSTEM_ALERT, V_I4(role.ptr())); - child.role = AX_ROLE_BUTTON; + child.role = ax::mojom::Role::kButton; child_node->SetData(child); EXPECT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive())); EXPECT_EQ(ROLE_SYSTEM_PUSHBUTTON, V_I4(role.ptr())); - child.role = AX_ROLE_POP_UP_BUTTON; + child.role = ax::mojom::Role::kPopUpButton; child_node->SetData(child); EXPECT_EQ(S_OK, child_iaccessible->get_accRole(SELF, role.Receive())); EXPECT_EQ(ROLE_SYSTEM_BUTTONMENU, V_I4(role.ptr())); @@ -676,11 +678,11 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleChildAndParent) { root.child_ids.push_back(3); AXNodeData button; - button.role = AX_ROLE_BUTTON; + button.role = ax::mojom::Role::kButton; button.id = 2; AXNodeData checkbox; - checkbox.role = AX_ROLE_CHECK_BOX; + checkbox.role = ax::mojom::Role::kCheckBox; checkbox.id = 3; Init(root, button, checkbox); @@ -809,16 +811,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2IndexInParent) { TEST_F(AXPlatformNodeWinTest, TestAccNavigate) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_ROOT_WEB_AREA; + root.role = ax::mojom::Role::kRootWebArea; AXNodeData child1; child1.id = 2; - child1.role = AX_ROLE_STATIC_TEXT; + child1.role = ax::mojom::Role::kStaticText; root.child_ids.push_back(2); AXNodeData child2; child2.id = 3; - child2.role = AX_ROLE_STATIC_TEXT; + child2.role = ax::mojom::Role::kStaticText; root.child_ids.push_back(3); Init(root, child1, child2); @@ -1003,12 +1005,12 @@ TEST_F(AXPlatformNodeWinTest, TEST_F(AXPlatformNodeWinTest, TestIAccessible2ScrollToPoint) { AXNodeData root; root.id = 1; - root.role = ui::AX_ROLE_ROOT_WEB_AREA; + root.role = ax::mojom::Role::kRootWebArea; root.location = gfx::RectF(0, 0, 2000, 2000); AXNodeData child1; child1.id = 2; - child1.role = AX_ROLE_STATIC_TEXT; + child1.role = ax::mojom::Role::kStaticText; child1.location = gfx::RectF(10, 10, 10, 10); root.child_ids.push_back(2); @@ -1055,12 +1057,12 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2ScrollToPoint) { TEST_F(AXPlatformNodeWinTest, TestIAccessible2ScrollTo) { AXNodeData root; root.id = 1; - root.role = ui::AX_ROLE_ROOT_WEB_AREA; + root.role = ax::mojom::Role::kRootWebArea; root.location = gfx::RectF(0, 0, 2000, 2000); AXNodeData child1; child1.id = 2; - child1.role = AX_ROLE_STATIC_TEXT; + child1.role = ax::mojom::Role::kStaticText; child1.location = gfx::RectF(10, 10, 10, 10); root.child_ids.push_back(2); @@ -1373,8 +1375,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableCellGetRowHeaderCells) { long number_cells; EXPECT_EQ(S_OK, cell->get_rowHeaderCells(&cell_accessibles, &number_cells)); - // Since we do not have AX_ATTR_TABLE_CELL_ROW_INDEX set, the evaluated row - // will be 0. In this case, we do not expect any row headers. + // Since we do not have ax::mojom::IntAttribute::kTableCellRowIndex set, the + // evaluated row will be 0. In this case, we do not expect any row headers. EXPECT_EQ(number_cells, 0); } @@ -1430,20 +1432,21 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetNRelations) { // specific COM/BrowserAccessibility knowledge. AXNodeData root; root.id = 1; - root.role = AX_ROLE_ROOT_WEB_AREA; + root.role = ax::mojom::Role::kRootWebArea; std::vector<int32_t> describedby_ids = {1, 2, 3}; - root.AddIntListAttribute(AX_ATTR_DESCRIBEDBY_IDS, describedby_ids); + root.AddIntListAttribute(ax::mojom::IntListAttribute::kDescribedbyIds, + describedby_ids); AXNodeData child1; child1.id = 2; - child1.role = AX_ROLE_STATIC_TEXT; + child1.role = ax::mojom::Role::kStaticText; root.child_ids.push_back(2); AXNodeData child2; child2.id = 3; - child2.role = AX_ROLE_STATIC_TEXT; + child2.role = ax::mojom::Role::kStaticText; root.child_ids.push_back(3); @@ -1538,27 +1541,28 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetNRelations) { TEST_F(AXPlatformNodeWinTest, TestRelationTargetsOfType) { AXNodeData root; root.id = 1; - root.role = AX_ROLE_ROOT_WEB_AREA; - root.AddIntAttribute(AX_ATTR_DETAILS_ID, 2); + root.role = ax::mojom::Role::kRootWebArea; + root.AddIntAttribute(ax::mojom::IntAttribute::kDetailsId, 2); AXNodeData child1; child1.id = 2; - child1.role = AX_ROLE_STATIC_TEXT; + child1.role = ax::mojom::Role::kStaticText; root.child_ids.push_back(2); AXNodeData child2; child2.id = 3; - child2.role = AX_ROLE_STATIC_TEXT; + child2.role = ax::mojom::Role::kStaticText; std::vector<int32_t> labelledby_ids = {1, 4}; - child2.AddIntListAttribute(AX_ATTR_LABELLEDBY_IDS, labelledby_ids); + child2.AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds, + labelledby_ids); root.child_ids.push_back(3); AXNodeData child3; child3.id = 4; - child3.role = AX_ROLE_STATIC_TEXT; - child3.AddIntAttribute(AX_ATTR_DETAILS_ID, 2); + child3.role = ax::mojom::Role::kStaticText; + child3.AddIntAttribute(ax::mojom::IntAttribute::kDetailsId, 2); root.child_ids.push_back(4); @@ -1643,7 +1647,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedChildrenOne) { AXTreeUpdate update = Build3X3Table(); // 7 == table_cell_1 - update.nodes[7].AddState(AX_STATE_SELECTED); + update.nodes[7].AddState(ax::mojom::State::kSelected); Init(update); ComPtr<IAccessibleTableCell> cell = GetCellInTable(); @@ -1668,10 +1672,10 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedChildrenMany) { // 8 == table_cell_2 // 11 == table_cell_3 // 12 == table_cell_4 - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -1714,9 +1718,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedColumnsOne) { // 3 == table_column_header_2 // 7 == table_cell_1 // 11 == table_cell_3 - update.nodes[3].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); + update.nodes[3].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); Init(update); @@ -1741,16 +1745,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedColumnsMany) { // 3 == table_column_header_2 // 7 == table_cell_1 // 11 == table_cell_3 - update.nodes[3].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); + update.nodes[3].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); // 4 == table_column_header_3 // 8 == table_cell_2 // 12 == table_cell_4 - update.nodes[4].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[4].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -1793,9 +1797,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedRowsOne) { // 6 == table_row_header_1 // 7 == table_cell_1 // 8 == table_cell_2 - update.nodes[6].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); + update.nodes[6].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); Init(update); @@ -1820,16 +1824,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetNSelectedRowsMany) { // 6 == table_row_header_3 // 7 == table_cell_1 // 8 == table_cell_2 - update.nodes[6].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); + update.nodes[6].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); // 10 == table_row_header_3 // 11 == table_cell_1 // 12 == table_cell_2 - update.nodes[10].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[10].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -1853,8 +1857,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedChildren) { // 7 == table_cell_1 // 12 == table_cell_4 - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -1882,8 +1886,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedChildrenZeroMax) { // 7 == table_cell_1 // 12 == table_cell_4 - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -1907,8 +1911,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedColumnsZero) { // 7 == table_cell_1 // 11 == table_cell_3 - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); Init(update); @@ -1936,9 +1940,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedColumnsOne) { // 3 == table_column_header_2 // 7 == table_cell_1 // 11 == table_cell_3 - update.nodes[3].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); + update.nodes[3].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); Init(update); @@ -1967,16 +1971,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedColumnsMany) { // 3 == table_column_header_2 // 7 == table_cell_1 // 11 == table_cell_3 - update.nodes[3].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); + update.nodes[3].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); // 4 == table_column_header_3 // 8 == table_cell_2 // 12 == table_cell_4 - update.nodes[4].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[4].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -2026,9 +2030,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedRowsOne) { // 6 == table_row_header_1 // 7 == table_cell_1 // 8 == table_cell_2 - update.nodes[6].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); + update.nodes[6].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); Init(update); @@ -2056,16 +2060,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetSelectedRowsMany) { // 6 == table_row_header_3 // 7 == table_cell_1 // 8 == table_cell_2 - update.nodes[6].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); + update.nodes[6].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); // 10 == table_row_header_3 // 11 == table_cell_1 // 12 == table_cell_2 - update.nodes[10].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[10].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -2094,9 +2098,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableIsColumnSelected) { // 3 == table_column_header_2 // 7 == table_cell_1 // 11 == table_cell_3 - update.nodes[3].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[11].AddState(AX_STATE_SELECTED); + update.nodes[3].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[11].AddState(ax::mojom::State::kSelected); Init(update); @@ -2130,9 +2134,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableIsRowSelected) { // 6 == table_row_header_3 // 7 == table_cell_1 // 8 == table_cell_2 - update.nodes[6].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); + update.nodes[6].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); Init(update); @@ -2166,9 +2170,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableIsSelected) { // 6 == table_row_header_3 // 7 == table_cell_1 // 8 == table_cell_2 - update.nodes[6].AddState(AX_STATE_SELECTED); - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[8].AddState(AX_STATE_SELECTED); + update.nodes[6].AddState(ax::mojom::State::kSelected); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[8].AddState(ax::mojom::State::kSelected); Init(update); @@ -2231,8 +2235,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTable2GetSelectedChildren) { // 7 == table_cell_1 // 12 == table_cell_4 - update.nodes[7].AddState(AX_STATE_SELECTED); - update.nodes[12].AddState(AX_STATE_SELECTED); + update.nodes[7].AddState(ax::mojom::State::kSelected); + update.nodes[12].AddState(ax::mojom::State::kSelected); Init(update); @@ -2261,9 +2265,9 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleTable2GetSelectedChildren) { TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetGroupPosition) { AXNodeData root; root.id = 1; - root.AddIntAttribute(AX_ATTR_HIERARCHICAL_LEVEL, 1); - root.AddIntAttribute(AX_ATTR_SET_SIZE, 1); - root.AddIntAttribute(AX_ATTR_POS_IN_SET, 1); + root.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 1); + root.AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 1); + root.AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 1); Init(root); ComPtr<IAccessible> root_obj(GetRootIAccessible()); @@ -2281,7 +2285,8 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetGroupPosition) { TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetLocalizedExtendedRole) { AXNodeData root; root.id = 1; - root.AddStringAttribute(AX_ATTR_ROLE_DESCRIPTION, "extended role"); + root.AddStringAttribute(ax::mojom::StringAttribute::kRoleDescription, + "extended role"); Init(root); ComPtr<IAccessible> root_obj(GetRootIAccessible()); @@ -2294,12 +2299,12 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2GetLocalizedExtendedRole) { TEST_F(AXPlatformNodeWinTest, TestIAccessibleTextGetNCharacters) { AXNodeData root; root.id = 0; - root.role = AX_ROLE_STATIC_TEXT; + root.role = ax::mojom::Role::kStaticText; root.child_ids.push_back(1); AXNodeData node; node.id = 1; - node.role = AX_ROLE_STATIC_TEXT; + node.role = ax::mojom::Role::kStaticText; node.SetName("Name"); Init(root, node); diff --git a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc index 83480eba1d1..803fc97e4d8 100644 --- a/chromium/ui/accessibility/platform/ax_platform_relation_win.cc +++ b/chromium/ui/accessibility/platform/ax_platform_relation_win.cc @@ -41,13 +41,13 @@ AXPlatformRelationWin::AXPlatformRelationWin() { AXPlatformRelationWin::~AXPlatformRelationWin() {} -base::string16 GetIA2RelationFromIntAttr(ui::AXIntAttribute attribute) { +base::string16 GetIA2RelationFromIntAttr(ax::mojom::IntAttribute attribute) { switch (attribute) { - case AX_ATTR_DETAILS_ID: + case ax::mojom::IntAttribute::kDetailsId: return IA2_RELATION_DETAILS; - case AX_ATTR_MEMBER_OF_ID: + case ax::mojom::IntAttribute::kMemberOfId: return IA2_RELATION_MEMBER_OF; - case AX_ATTR_ERRORMESSAGE_ID: + case ax::mojom::IntAttribute::kErrormessageId: return IA2_RELATION_ERROR_MESSAGE; default: break; @@ -55,15 +55,16 @@ base::string16 GetIA2RelationFromIntAttr(ui::AXIntAttribute attribute) { return base::string16(); } -base::string16 GetIA2RelationFromIntListAttr(ui::AXIntListAttribute attribute) { +base::string16 GetIA2RelationFromIntListAttr( + ax::mojom::IntListAttribute attribute) { switch (attribute) { - case AX_ATTR_CONTROLS_IDS: + case ax::mojom::IntListAttribute::kControlsIds: return IA2_RELATION_CONTROLLER_FOR; - case AX_ATTR_DESCRIBEDBY_IDS: + case ax::mojom::IntListAttribute::kDescribedbyIds: return IA2_RELATION_DESCRIBED_BY; - case AX_ATTR_FLOWTO_IDS: + case ax::mojom::IntListAttribute::kFlowtoIds: return IA2_RELATION_FLOWS_TO; - case AX_ATTR_LABELLEDBY_IDS: + case ax::mojom::IntListAttribute::kLabelledbyIds: return IA2_RELATION_LABELLED_BY; default: break; @@ -71,9 +72,10 @@ base::string16 GetIA2RelationFromIntListAttr(ui::AXIntListAttribute attribute) { return base::string16(); } -base::string16 GetIA2ReverseRelationFromIntAttr(ui::AXIntAttribute attribute) { +base::string16 GetIA2ReverseRelationFromIntAttr( + ax::mojom::IntAttribute attribute) { switch (attribute) { - case AX_ATTR_DETAILS_ID: + case ax::mojom::IntAttribute::kDetailsId: return IA2_RELATION_DETAILS_FOR; default: break; @@ -82,15 +84,15 @@ base::string16 GetIA2ReverseRelationFromIntAttr(ui::AXIntAttribute attribute) { } base::string16 GetIA2ReverseRelationFromIntListAttr( - ui::AXIntListAttribute attribute) { + ax::mojom::IntListAttribute attribute) { switch (attribute) { - case AX_ATTR_CONTROLS_IDS: + case ax::mojom::IntListAttribute::kControlsIds: return IA2_RELATION_CONTROLLED_BY; - case AX_ATTR_DESCRIBEDBY_IDS: + case ax::mojom::IntListAttribute::kDescribedbyIds: return IA2_RELATION_DESCRIPTION_FOR; - case AX_ATTR_FLOWTO_IDS: + case ax::mojom::IntListAttribute::kFlowtoIds: return IA2_RELATION_FLOWS_FROM; - case AX_ATTR_LABELLEDBY_IDS: + case ax::mojom::IntListAttribute::kLabelledbyIds: return IA2_RELATION_LABEL_FOR; default: break; @@ -112,20 +114,25 @@ int AXPlatformRelationWin::EnumerateRelationships( // GetIA2ReverseRelationFrom{Int|IntList}Attr on every possible attribute // simplifies the work needed to support an additional relation // attribute in the future. - static std::vector<AXIntAttribute> int_attributes_with_reverse_relations; - static std::vector<AXIntListAttribute> + static std::vector<ax::mojom::IntAttribute> + int_attributes_with_reverse_relations; + static std::vector<ax::mojom::IntListAttribute> intlist_attributes_with_reverse_relations; static bool first_time = true; if (first_time) { - for (int attr_index = AX_INT_ATTRIBUTE_NONE; - attr_index <= AX_INT_ATTRIBUTE_LAST; ++attr_index) { - auto attr = static_cast<AXIntAttribute>(attr_index); + for (int32_t attr_index = + static_cast<int32_t>(ax::mojom::IntAttribute::kNone); + attr_index <= static_cast<int32_t>(ax::mojom::IntAttribute::kLast); + ++attr_index) { + auto attr = static_cast<ax::mojom::IntAttribute>(attr_index); if (!GetIA2ReverseRelationFromIntAttr(attr).empty()) int_attributes_with_reverse_relations.push_back(attr); } - for (int attr_index = AX_INT_LIST_ATTRIBUTE_NONE; - attr_index <= AX_INT_LIST_ATTRIBUTE_LAST; ++attr_index) { - auto attr = static_cast<AXIntListAttribute>(attr_index); + for (int32_t attr_index = + static_cast<int32_t>(ax::mojom::IntListAttribute::kNone); + attr_index <= static_cast<int32_t>(ax::mojom::IntListAttribute::kLast); + ++attr_index) { + auto attr = static_cast<ax::mojom::IntListAttribute>(attr_index); if (!GetIA2ReverseRelationFromIntListAttr(attr).empty()) intlist_attributes_with_reverse_relations.push_back(attr); } @@ -142,7 +149,7 @@ int AXPlatformRelationWin::EnumerateRelationships( // Iterate over all int attributes on this node to check the ones // that correspond to IAccessible2 relations. for (size_t i = 0; i < node_data.int_attributes.size(); ++i) { - AXIntAttribute int_attribute = node_data.int_attributes[i].first; + ax::mojom::IntAttribute int_attribute = node_data.int_attributes[i].first; base::string16 relation = GetIA2RelationFromIntAttr(int_attribute); if (!relation.empty() && (desired_ia2_relation.empty() || desired_ia2_relation == relation)) { @@ -160,7 +167,8 @@ int AXPlatformRelationWin::EnumerateRelationships( // Iterate over all of the int attributes that have reverse relations // in IAccessible2, and query AXTree to see if the reverse relation exists. - for (AXIntAttribute int_attribute : int_attributes_with_reverse_relations) { + for (ax::mojom::IntAttribute int_attribute : + int_attributes_with_reverse_relations) { base::string16 relation = GetIA2ReverseRelationFromIntAttr(int_attribute); std::set<int32_t> targets = delegate->GetReverseRelations(int_attribute, node_data.id); @@ -182,7 +190,7 @@ int AXPlatformRelationWin::EnumerateRelationships( // Iterate over all intlist attributes on this node to check the ones // that correspond to IAccessible2 relations. for (size_t i = 0; i < node_data.intlist_attributes.size(); ++i) { - AXIntListAttribute intlist_attribute = + ax::mojom::IntListAttribute intlist_attribute = node_data.intlist_attributes[i].first; base::string16 relation = GetIA2RelationFromIntListAttr(intlist_attribute); if (!relation.empty() && @@ -205,7 +213,7 @@ int AXPlatformRelationWin::EnumerateRelationships( // Iterate over all of the intlist attributes that have reverse relations // in IAccessible2, and query AXTree to see if the reverse relation exists. - for (AXIntListAttribute intlist_attribute : + for (ax::mojom::IntListAttribute intlist_attribute : intlist_attributes_with_reverse_relations) { base::string16 relation = GetIA2ReverseRelationFromIntListAttr(intlist_attribute); diff --git a/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc b/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc index 83e083901df..998ae65757c 100644 --- a/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc +++ b/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.cc @@ -10,7 +10,7 @@ #include "base/memory/ptr_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_role_properties.h" #include "ui/accessibility/ax_serializable_tree.h" @@ -24,7 +24,7 @@ namespace { bool HasFocusableChild(const AXNode* node) { for (auto* child : node->children()) { - if (child->data().HasState(AX_STATE_FOCUSABLE) || + if (child->data().HasState(ax::mojom::State::kFocusable) || HasFocusableChild(child)) { return true; } @@ -42,22 +42,24 @@ bool HasOnlyTextChildren(const AXNode* node) { // TODO(muyuanli): share with BrowserAccessibility. bool IsSimpleTextControl(const AXNode* node, uint32_t state) { - return (node->data().role == AX_ROLE_TEXT_FIELD || - node->data().role == AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX || - node->data().role == AX_ROLE_SEARCH_BOX || - node->data().HasBoolAttribute(AX_ATTR_EDITABLE_ROOT)) && - !node->data().HasState(AX_STATE_RICHLY_EDITABLE); + return (node->data().role == ax::mojom::Role::kTextField || + node->data().role == ax::mojom::Role::kTextFieldWithComboBox || + node->data().role == ax::mojom::Role::kSearchBox || + node->data().HasBoolAttribute( + ax::mojom::BoolAttribute::kEditableRoot)) && + !node->data().HasState(ax::mojom::State::kRichlyEditable); } bool IsRichTextEditable(const AXNode* node) { const AXNode* parent = node->parent(); - return node->data().HasState(AX_STATE_RICHLY_EDITABLE) && - (!parent || !parent->data().HasState(AX_STATE_RICHLY_EDITABLE)); + return node->data().HasState(ax::mojom::State::kRichlyEditable) && + (!parent || + !parent->data().HasState(ax::mojom::State::kRichlyEditable)); } bool IsNativeTextControl(const AXNode* node) { const std::string& html_tag = - node->data().GetStringAttribute(AX_ATTR_HTML_TAG); + node->data().GetStringAttribute(ax::mojom::StringAttribute::kHtmlTag); if (html_tag == "input") { std::string input_type; if (!node->data().GetHtmlAttribute("type", &input_type)) @@ -79,15 +81,15 @@ bool IsLeaf(const AXNode* node) { } switch (node->data().role) { - case AX_ROLE_IMAGE: - case AX_ROLE_METER: - case AX_ROLE_SCROLL_BAR: - case AX_ROLE_SLIDER: - case AX_ROLE_SPLITTER: - case AX_ROLE_PROGRESS_INDICATOR: - case AX_ROLE_DATE: - case AX_ROLE_DATE_TIME: - case AX_ROLE_INPUT_TIME: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kMeter: + case ax::mojom::Role::kScrollBar: + case ax::mojom::Role::kSlider: + case ax::mojom::Role::kSplitter: + case ax::mojom::Role::kProgressIndicator: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kDateTime: + case ax::mojom::Role::kInputTime: return true; default: return false; @@ -96,7 +98,7 @@ bool IsLeaf(const AXNode* node) { base::string16 GetInnerText(const AXNode* node) { if (node->IsTextNode()) { - return node->data().GetString16Attribute(AX_ATTR_NAME); + return node->data().GetString16Attribute(ax::mojom::StringAttribute::kName); } base::string16 text; for (auto* child : node->children()) { @@ -106,7 +108,8 @@ base::string16 GetInnerText(const AXNode* node) { } base::string16 GetValue(const AXNode* node, bool show_password) { - base::string16 value = node->data().GetString16Attribute(AX_ATTR_VALUE); + base::string16 value = + node->data().GetString16Attribute(ax::mojom::StringAttribute::kValue); if (value.empty() && (IsSimpleTextControl(node, node->data().state) || @@ -115,7 +118,7 @@ base::string16 GetValue(const AXNode* node, bool show_password) { value = GetInnerText(node); } - if (node->data().HasState(AX_STATE_PROTECTED)) { + if (node->data().HasState(ax::mojom::State::kProtected)) { if (!show_password) { value = base::string16(value.size(), kSecurePasswordBullet); } @@ -126,8 +129,8 @@ base::string16 GetValue(const AXNode* node, bool show_password) { bool HasOnlyTextAndImageChildren(const AXNode* node) { for (auto* child : node->children()) { - if (child->data().role != AX_ROLE_STATIC_TEXT && - child->data().role != AX_ROLE_IMAGE) { + if (child->data().role != ax::mojom::Role::kStaticText && + child->data().role != ax::mojom::Role::kImage) { return false; } } @@ -135,24 +138,25 @@ bool HasOnlyTextAndImageChildren(const AXNode* node) { } bool IsFocusable(const AXNode* node) { - if (node->data().role == AX_ROLE_IFRAME || - node->data().role == AX_ROLE_IFRAME_PRESENTATIONAL || - (node->data().role == AX_ROLE_ROOT_WEB_AREA && node->parent())) { - return node->data().HasStringAttribute(AX_ATTR_NAME); + if (node->data().role == ax::mojom::Role::kIframe || + node->data().role == ax::mojom::Role::kIframePresentational || + (node->data().role == ax::mojom::Role::kRootWebArea && node->parent())) { + return node->data().HasStringAttribute(ax::mojom::StringAttribute::kName); } - return node->data().HasState(AX_STATE_FOCUSABLE); + return node->data().HasState(ax::mojom::State::kFocusable); } base::string16 GetText(const AXNode* node, bool show_password) { - if (node->data().role == AX_ROLE_WEB_AREA || - node->data().role == AX_ROLE_IFRAME || - node->data().role == AX_ROLE_IFRAME_PRESENTATIONAL) { + if (node->data().role == ax::mojom::Role::kWebArea || + node->data().role == ax::mojom::Role::kIframe || + node->data().role == ax::mojom::Role::kIframePresentational) { return base::string16(); } - if (node->data().role == AX_ROLE_LIST_ITEM && - node->data().GetIntAttribute(AX_ATTR_NAME_FROM) == - AX_NAME_FROM_CONTENTS) { + ax::mojom::NameFrom name_from = static_cast<ax::mojom::NameFrom>( + node->data().GetIntAttribute(ax::mojom::IntAttribute::kNameFrom)); + if (node->data().role == ax::mojom::Role::kListItem && + name_from == ax::mojom::NameFrom::kContents) { if (node->child_count() > 0 && !HasOnlyTextChildren(node)) return base::string16(); } @@ -160,23 +164,23 @@ base::string16 GetText(const AXNode* node, bool show_password) { base::string16 value = GetValue(node, show_password); if (!value.empty()) { - if (node->data().HasState(AX_STATE_EDITABLE)) + if (node->data().HasState(ax::mojom::State::kEditable)) return value; switch (node->data().role) { - case AX_ROLE_COMBO_BOX_MENU_BUTTON: - case AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX: - case AX_ROLE_POP_UP_BUTTON: - case AX_ROLE_TEXT_FIELD: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kTextFieldWithComboBox: + case ax::mojom::Role::kPopUpButton: + case ax::mojom::Role::kTextField: return value; default: break; } } - if (node->data().role == AX_ROLE_COLOR_WELL) { + if (node->data().role == ax::mojom::Role::kColorWell) { unsigned int color = static_cast<unsigned int>( - node->data().GetIntAttribute(AX_ATTR_COLOR_VALUE)); + node->data().GetIntAttribute(ax::mojom::IntAttribute::kColorValue)); unsigned int red = color >> 16 & 0xFF; unsigned int green = color >> 8 & 0xFF; unsigned int blue = color >> 0 & 0xFF; @@ -184,9 +188,10 @@ base::string16 GetText(const AXNode* node, bool show_password) { base::StringPrintf("#%02X%02X%02X", red, green, blue)); } - base::string16 text = node->data().GetString16Attribute(AX_ATTR_NAME); - base::string16 description = - node->data().GetString16Attribute(AX_ATTR_DESCRIPTION); + base::string16 text = + node->data().GetString16Attribute(ax::mojom::StringAttribute::kName); + base::string16 description = node->data().GetString16Attribute( + ax::mojom::StringAttribute::kDescription); if (!description.empty()) { if (!text.empty()) text += base::ASCIIToUTF16(" "); @@ -196,7 +201,7 @@ base::string16 GetText(const AXNode* node, bool show_password) { if (text.empty()) text = value; - if (node->data().role == AX_ROLE_ROOT_WEB_AREA) + if (node->data().role == ax::mojom::Role::kRootWebArea) return text; if (text.empty() && @@ -208,51 +213,52 @@ base::string16 GetText(const AXNode* node, bool show_password) { } if (text.empty() && (AXSnapshotNodeAndroid::AXRoleIsLink(node->data().role) || - node->data().role == AX_ROLE_IMAGE)) { - base::string16 url = node->data().GetString16Attribute(AX_ATTR_URL); + node->data().role == ax::mojom::Role::kImage)) { + base::string16 url = + node->data().GetString16Attribute(ax::mojom::StringAttribute::kUrl); text = AXSnapshotNodeAndroid::AXUrlBaseText(url); } return text; } -// Get string representation of AXRole. We are not using ToString() in +// Get string representation of ax::mojom::Role. We are not using ToString() in // ax_enums.h since the names are subject to change in the future and // we are only interested in a subset of the roles. -base::Optional<std::string> AXRoleToString(AXRole role) { +base::Optional<std::string> AXRoleToString(ax::mojom::Role role) { switch (role) { - case AX_ROLE_ARTICLE: + case ax::mojom::Role::kArticle: return base::Optional<std::string>("article"); - case AX_ROLE_BANNER: + case ax::mojom::Role::kBanner: return base::Optional<std::string>("banner"); - case AX_ROLE_CAPTION: + case ax::mojom::Role::kCaption: return base::Optional<std::string>("caption"); - case AX_ROLE_COMPLEMENTARY: + case ax::mojom::Role::kComplementary: return base::Optional<std::string>("complementary"); - case AX_ROLE_DATE: + case ax::mojom::Role::kDate: return base::Optional<std::string>("date"); - case AX_ROLE_DATE_TIME: + case ax::mojom::Role::kDateTime: return base::Optional<std::string>("date_time"); - case AX_ROLE_DEFINITION: + case ax::mojom::Role::kDefinition: return base::Optional<std::string>("definition"); - case AX_ROLE_DETAILS: + case ax::mojom::Role::kDetails: return base::Optional<std::string>("details"); - case AX_ROLE_DOCUMENT: + case ax::mojom::Role::kDocument: return base::Optional<std::string>("document"); - case AX_ROLE_FEED: + case ax::mojom::Role::kFeed: return base::Optional<std::string>("feed"); - case AX_ROLE_HEADING: + case ax::mojom::Role::kHeading: return base::Optional<std::string>("heading"); - case AX_ROLE_IFRAME: + case ax::mojom::Role::kIframe: return base::Optional<std::string>("iframe"); - case AX_ROLE_IFRAME_PRESENTATIONAL: + case ax::mojom::Role::kIframePresentational: return base::Optional<std::string>("iframe_presentational"); - case AX_ROLE_LIST: + case ax::mojom::Role::kList: return base::Optional<std::string>("list"); - case AX_ROLE_LIST_ITEM: + case ax::mojom::Role::kListItem: return base::Optional<std::string>("list_item"); - case AX_ROLE_MAIN: + case ax::mojom::Role::kMain: return base::Optional<std::string>("main"); - case AX_ROLE_PARAGRAPH: + case ax::mojom::Role::kParagraph: return base::Optional<std::string>("paragraph"); default: return base::Optional<std::string>(); @@ -282,8 +288,8 @@ AX_EXPORT std::unique_ptr<AXSnapshotNodeAndroid> AXSnapshotNodeAndroid::Create( } // static -AX_EXPORT bool AXSnapshotNodeAndroid::AXRoleIsLink(AXRole role) { - return role == AX_ROLE_LINK; +AX_EXPORT bool AXSnapshotNodeAndroid::AXRoleIsLink(ax::mojom::Role role) { + return role == ax::mojom::Role::kLink; } // static @@ -309,56 +315,56 @@ AX_EXPORT base::string16 AXSnapshotNodeAndroid::AXUrlBaseText( // static AX_EXPORT const char* AXSnapshotNodeAndroid::AXRoleToAndroidClassName( - AXRole role, + ax::mojom::Role role, bool has_parent) { switch (role) { - case AX_ROLE_SEARCH_BOX: - case AX_ROLE_SPIN_BUTTON: - case AX_ROLE_TEXT_FIELD: - case AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX: + case ax::mojom::Role::kSearchBox: + case ax::mojom::Role::kSpinButton: + case ax::mojom::Role::kTextField: + case ax::mojom::Role::kTextFieldWithComboBox: return kAXEditTextClassname; - case AX_ROLE_SLIDER: + case ax::mojom::Role::kSlider: return kAXSeekBarClassname; - case AX_ROLE_COLOR_WELL: - case AX_ROLE_COMBO_BOX_MENU_BUTTON: - case AX_ROLE_DATE: - case AX_ROLE_POP_UP_BUTTON: - case AX_ROLE_INPUT_TIME: + case ax::mojom::Role::kColorWell: + case ax::mojom::Role::kComboBoxMenuButton: + case ax::mojom::Role::kDate: + case ax::mojom::Role::kPopUpButton: + case ax::mojom::Role::kInputTime: return kAXSpinnerClassname; - case AX_ROLE_BUTTON: - case AX_ROLE_MENU_BUTTON: + case ax::mojom::Role::kButton: + case ax::mojom::Role::kMenuButton: return kAXButtonClassname; - case AX_ROLE_CHECK_BOX: - case AX_ROLE_SWITCH: + case ax::mojom::Role::kCheckBox: + case ax::mojom::Role::kSwitch: return kAXCheckBoxClassname; - case AX_ROLE_RADIO_BUTTON: + case ax::mojom::Role::kRadioButton: return kAXRadioButtonClassname; - case AX_ROLE_TOGGLE_BUTTON: + case ax::mojom::Role::kToggleButton: return kAXToggleButtonClassname; - case AX_ROLE_CANVAS: - case AX_ROLE_IMAGE: - case AX_ROLE_SVG_ROOT: + case ax::mojom::Role::kCanvas: + case ax::mojom::Role::kImage: + case ax::mojom::Role::kSvgRoot: return kAXImageClassname; - case AX_ROLE_METER: - case AX_ROLE_PROGRESS_INDICATOR: + case ax::mojom::Role::kMeter: + case ax::mojom::Role::kProgressIndicator: return kAXProgressBarClassname; - case AX_ROLE_TAB_LIST: + case ax::mojom::Role::kTabList: return kAXTabWidgetClassname; - case AX_ROLE_GRID: - case AX_ROLE_TREE_GRID: - case AX_ROLE_TABLE: + case ax::mojom::Role::kGrid: + case ax::mojom::Role::kTreeGrid: + case ax::mojom::Role::kTable: return kAXGridViewClassname; - case AX_ROLE_LIST: - case AX_ROLE_LIST_BOX: - case AX_ROLE_DESCRIPTION_LIST: + case ax::mojom::Role::kList: + case ax::mojom::Role::kListBox: + case ax::mojom::Role::kDescriptionList: return kAXListViewClassname; - case AX_ROLE_DIALOG: + case ax::mojom::Role::kDialog: return kAXDialogClassname; - case AX_ROLE_ROOT_WEB_AREA: + case ax::mojom::Role::kRootWebArea: return has_parent ? kAXViewClassname : kAXWebViewClassname; - case AX_ROLE_MENU_ITEM: - case AX_ROLE_MENU_ITEM_CHECK_BOX: - case AX_ROLE_MENU_ITEM_RADIO: + case ax::mojom::Role::kMenuItem: + case ax::mojom::Role::kMenuItemCheckBox: + case ax::mojom::Role::kMenuItemRadio: return kAXMenuItemClassname; default: return kAXViewClassname; @@ -388,20 +394,32 @@ AXSnapshotNodeAndroid::WalkAXTreeDepthFirst( result->line_through = 0; result->underline = 0; - if (node->data().HasFloatAttribute(AX_ATTR_FONT_SIZE)) { + if (node->data().HasFloatAttribute(ax::mojom::FloatAttribute::kFontSize)) { gfx::RectF text_size_rect( - 0, 0, 1, node->data().GetFloatAttribute(AX_ATTR_FONT_SIZE)); + 0, 0, 1, + node->data().GetFloatAttribute(ax::mojom::FloatAttribute::kFontSize)); gfx::Rect scaled_text_size_rect = gfx::ToEnclosingRect(tree->RelativeToTreeBounds(node, text_size_rect)); result->text_size = scaled_text_size_rect.height(); - const int text_style = node->data().GetIntAttribute(AX_ATTR_TEXT_STYLE); - result->color = node->data().GetIntAttribute(AX_ATTR_COLOR); - result->bgcolor = node->data().GetIntAttribute(AX_ATTR_BACKGROUND_COLOR); - result->bold = (text_style & AX_TEXT_STYLE_BOLD) != 0; - result->italic = (text_style & AX_TEXT_STYLE_ITALIC) != 0; - result->line_through = (text_style & AX_TEXT_STYLE_LINE_THROUGH) != 0; - result->underline = (text_style & AX_TEXT_STYLE_UNDERLINE) != 0; + const int32_t text_style = + node->data().GetIntAttribute(ax::mojom::IntAttribute::kTextStyle); + result->color = + node->data().GetIntAttribute(ax::mojom::IntAttribute::kColor); + result->bgcolor = + node->data().GetIntAttribute(ax::mojom::IntAttribute::kBackgroundColor); + result->bold = + (text_style & + static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleBold)) != 0; + result->italic = + (text_style & + static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleItalic)) != 0; + result->line_through = + (text_style & static_cast<int32_t>( + ax::mojom::TextStyle::kTextStyleLineThrough)) != 0; + result->underline = + (text_style & + static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleUnderline)) != 0; } const gfx::Rect& absolute_rect = diff --git a/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.h b/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.h index be01b51bcee..f5502219fd5 100644 --- a/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.h +++ b/chromium/ui/accessibility/platform/ax_snapshot_node_android_platform.h @@ -11,7 +11,7 @@ #include "base/optional.h" #include "base/strings/string16.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_tree_update.h" #include "ui/gfx/geometry/rect.h" @@ -32,11 +32,11 @@ struct AXSnapshotNodeAndroid { bool show_password); // Returns a fake Android view class that is a closest - // approximation of the AXRole. - AX_EXPORT static const char* AXRoleToAndroidClassName(AXRole role, + // approximation of the ax::mojom::Role. + AX_EXPORT static const char* AXRoleToAndroidClassName(ax::mojom::Role role, bool has_parent); - AX_EXPORT static bool AXRoleIsLink(AXRole role); + AX_EXPORT static bool AXRoleIsLink(ax::mojom::Role role); AX_EXPORT static base::string16 AXUrlBaseText(base::string16 url); diff --git a/chromium/ui/accessibility/platform/ax_system_caret_win.cc b/chromium/ui/accessibility/platform/ax_system_caret_win.cc index 7547cd669a9..d173583715a 100644 --- a/chromium/ui/accessibility/platform/ax_system_caret_win.cc +++ b/chromium/ui/accessibility/platform/ax_system_caret_win.cc @@ -7,7 +7,7 @@ #include <windows.h> #include "base/logging.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/platform/ax_platform_node_win.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_f.h" @@ -21,7 +21,7 @@ AXSystemCaretWin::AXSystemCaretWin(gfx::AcceleratedWidget event_target) // a node ID. A globally unique ID is used when firing Win events, retrieved // via |unique_id|. data_.id = -1; - data_.role = AX_ROLE_CARET; + data_.role = ax::mojom::Role::kCaret; // |get_accState| should return 0 which means that the caret is visible. data_.state = 0; // According to MSDN, "Edit" should be the name of the caret object. @@ -95,9 +95,13 @@ gfx::NativeViewAccessible AXSystemCaretWin::ChildAtIndex(int index) { return nullptr; } -gfx::Rect AXSystemCaretWin::GetScreenBoundsRect() const { - gfx::Rect bounds = ToEnclosingRect(data_.location); - return bounds; +gfx::Rect AXSystemCaretWin::GetClippedScreenBoundsRect() const { + // We could optionally add clipping here if ever needed. + return ToEnclosingRect(data_.location); +} + +gfx::Rect AXSystemCaretWin::GetUnclippedScreenBoundsRect() const { + return ToEnclosingRect(data_.location); } gfx::NativeViewAccessible AXSystemCaretWin::HitTestSync(int x, int y) { @@ -133,13 +137,15 @@ bool AXSystemCaretWin::IsOffscreen() const { return false; } -std::set<int32_t> AXSystemCaretWin::GetReverseRelations(AXIntAttribute attr, - int32_t dst_id) { +std::set<int32_t> AXSystemCaretWin::GetReverseRelations( + ax::mojom::IntAttribute attr, + int32_t dst_id) { return std::set<int32_t>(); } -std::set<int32_t> AXSystemCaretWin::GetReverseRelations(AXIntListAttribute attr, - int32_t dst_id) { +std::set<int32_t> AXSystemCaretWin::GetReverseRelations( + ax::mojom::IntListAttribute attr, + int32_t dst_id) { return std::set<int32_t>(); } diff --git a/chromium/ui/accessibility/platform/ax_system_caret_win.h b/chromium/ui/accessibility/platform/ax_system_caret_win.h index 6a4ec9686ee..56e26854f47 100644 --- a/chromium/ui/accessibility/platform/ax_system_caret_win.h +++ b/chromium/ui/accessibility/platform/ax_system_caret_win.h @@ -40,7 +40,8 @@ class AX_EXPORT AXSystemCaretWin : private AXPlatformNodeDelegate { gfx::NativeViewAccessible GetParent() override; int GetChildCount() override; gfx::NativeViewAccessible ChildAtIndex(int index) override; - gfx::Rect GetScreenBoundsRect() const override; + gfx::Rect GetClippedScreenBoundsRect() const override; + gfx::Rect GetUnclippedScreenBoundsRect() const override; gfx::NativeViewAccessible HitTestSync(int x, int y) override; gfx::NativeViewAccessible GetFocus() override; AXPlatformNode* GetFromNodeID(int32_t id) override; @@ -50,9 +51,9 @@ class AX_EXPORT AXSystemCaretWin : private AXPlatformNodeDelegate { bool ShouldIgnoreHoveredStateForTesting() override; bool IsOffscreen() const override; const ui::AXUniqueId& GetUniqueId() const override; - std::set<int32_t> GetReverseRelations(AXIntAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) override; - std::set<int32_t> GetReverseRelations(AXIntListAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) override; AXPlatformNodeWin* caret_; diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc index 045e04cef2b..bba0ceb1da3 100644 --- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc @@ -105,7 +105,14 @@ gfx::NativeViewAccessible TestAXNodeWrapper::ChildAtIndex(int index) { nullptr; } -gfx::Rect TestAXNodeWrapper::GetScreenBoundsRect() const { +gfx::Rect TestAXNodeWrapper::GetClippedScreenBoundsRect() const { + // We could add clipping here if needed. + gfx::RectF bounds = GetData().location; + bounds.Offset(g_offset); + return gfx::ToEnclosingRect(bounds); +} + +gfx::Rect TestAXNodeWrapper::GetUnclippedScreenBoundsRect() const { gfx::RectF bounds = GetData().location; bounds.Offset(g_offset); return gfx::ToEnclosingRect(bounds); @@ -115,7 +122,7 @@ TestAXNodeWrapper* TestAXNodeWrapper::HitTestSyncInternal(int x, int y) { // Here we find the deepest child whose bounding box contains the given point. // The assuptions are that there are no overlapping bounding rects and that // all children have smaller bounding rects than their parents. - if (!GetScreenBoundsRect().Contains(gfx::Rect(x, y))) + if (!GetClippedScreenBoundsRect().Contains(gfx::Rect(x, y))) return nullptr; for (int i = 0; i < GetChildCount(); i++) { @@ -176,7 +183,7 @@ TestAXNodeWrapper::GetTargetForNativeAccessibilityEvent() { } void TestAXNodeWrapper::ReplaceIntAttribute(int32_t node_id, - AXIntAttribute attribute, + ax::mojom::IntAttribute attribute, int32_t value) { if (!tree_) return; @@ -186,7 +193,7 @@ void TestAXNodeWrapper::ReplaceIntAttribute(int32_t node_id, return; AXNodeData new_data = node->data(); - std::vector<std::pair<AXIntAttribute, int32_t>>& attributes = + std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>& attributes = new_data.int_attributes; auto deleted = std::remove_if( @@ -200,21 +207,23 @@ void TestAXNodeWrapper::ReplaceIntAttribute(int32_t node_id, bool TestAXNodeWrapper::AccessibilityPerformAction( const ui::AXActionData& data) { - if (data.action == ui::AX_ACTION_SCROLL_TO_POINT) { + if (data.action == ax::mojom::Action::kScrollToPoint) { g_offset = gfx::Vector2d(data.target_point.x(), data.target_point.y()); return true; } - if (data.action == ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE) { + if (data.action == ax::mojom::Action::kScrollToMakeVisible) { auto offset = node_->data().location.OffsetFromOrigin(); g_offset = gfx::Vector2d(-offset.x(), -offset.y()); return true; } - if (data.action == ui::AX_ACTION_SET_SELECTION) { - ReplaceIntAttribute(data.anchor_node_id, AX_ATTR_TEXT_SEL_START, + if (data.action == ax::mojom::Action::kSetSelection) { + ReplaceIntAttribute(data.anchor_node_id, + ax::mojom::IntAttribute::kTextSelStart, data.anchor_offset); - ReplaceIntAttribute(data.anchor_node_id, AX_ATTR_TEXT_SEL_END, + ReplaceIntAttribute(data.anchor_node_id, + ax::mojom::IntAttribute::kTextSelEnd, data.focus_offset); return true; } @@ -230,13 +239,14 @@ bool TestAXNodeWrapper::IsOffscreen() const { return false; } -std::set<int32_t> TestAXNodeWrapper::GetReverseRelations(AXIntAttribute attr, - int32_t dst_id) { +std::set<int32_t> TestAXNodeWrapper::GetReverseRelations( + ax::mojom::IntAttribute attr, + int32_t dst_id) { return tree_->GetReverseRelations(attr, dst_id); } std::set<int32_t> TestAXNodeWrapper::GetReverseRelations( - AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, int32_t dst_id) { return tree_->GetReverseRelations(attr, dst_id); } diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h index 4327748de82..5dd47a649bc 100644 --- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h +++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h @@ -37,7 +37,8 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegate { gfx::NativeViewAccessible GetParent() override; int GetChildCount() override; gfx::NativeViewAccessible ChildAtIndex(int index) override; - gfx::Rect GetScreenBoundsRect() const override; + gfx::Rect GetClippedScreenBoundsRect() const override; + gfx::Rect GetUnclippedScreenBoundsRect() const override; gfx::NativeViewAccessible HitTestSync(int x, int y) override; gfx::NativeViewAccessible GetFocus() override; AXPlatformNode* GetFromNodeID(int32_t id) override; @@ -47,15 +48,15 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegate { bool ShouldIgnoreHoveredStateForTesting() override; bool IsOffscreen() const override; const ui::AXUniqueId& GetUniqueId() const override; - std::set<int32_t> GetReverseRelations(AXIntAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) override; - std::set<int32_t> GetReverseRelations(AXIntListAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) override; private: TestAXNodeWrapper(AXTree* tree, AXNode* node); void ReplaceIntAttribute(int32_t node_id, - AXIntAttribute attribute, + ax::mojom::IntAttribute attribute, int32_t value); TestAXNodeWrapper* HitTestSyncInternal(int x, int y); diff --git a/chromium/ui/android/BUILD.gn b/chromium/ui/android/BUILD.gn index d79dff14bfa..a9196e95dc7 100644 --- a/chromium/ui/android/BUILD.gn +++ b/chromium/ui/android/BUILD.gn @@ -242,10 +242,13 @@ android_library("ui_full_java") { "java/src/org/chromium/ui/resources/system/SystemResourceLoader.java", "java/src/org/chromium/ui/text/NoUnderlineClickableSpan.java", "java/src/org/chromium/ui/text/SpanApplier.java", + "java/src/org/chromium/ui/widget/AnchoredPopupWindow.java", "java/src/org/chromium/ui/widget/ButtonCompat.java", + "java/src/org/chromium/ui/widget/RectProvider.java", "java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java", "java/src/org/chromium/ui/widget/TextViewWithLeading.java", "java/src/org/chromium/ui/widget/Toast.java", + "java/src/org/chromium/ui/widget/ViewRectProvider.java", ] deps = [ ":ui_java_resources", @@ -280,11 +283,13 @@ junit_binary("ui_junit_tests") { "junit/src/org/chromium/ui/base/ClipboardTest.java", "junit/src/org/chromium/ui/base/SelectFileDialogTest.java", "junit/src/org/chromium/ui/text/SpanApplierTest.java", + "junit/src/org/chromium/ui/widget/AnchoredPopupWindowTest.java", ] deps = [ ":ui_java", "//base:base_java", "//base:base_java_test_support", + "//base:base_junit_test_support", ] } diff --git a/chromium/ui/android/OWNERS b/chromium/ui/android/OWNERS index 8dd68c8015f..2a99c692980 100644 --- a/chromium/ui/android/OWNERS +++ b/chromium/ui/android/OWNERS @@ -9,5 +9,8 @@ jaekyun@chromium.org boliu@chromium.org jinsukkim@chromium.org +# for CC and Viz integration +khushalsagar@chromium.org + # COMPONENT: UI # OS: Android diff --git a/chromium/ui/android/delegated_frame_host_android.cc b/chromium/ui/android/delegated_frame_host_android.cc index 5520cfc9fc5..07798eaf868 100644 --- a/chromium/ui/android/delegated_frame_host_android.cc +++ b/chromium/ui/android/delegated_frame_host_android.cc @@ -14,9 +14,9 @@ #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/host/host_frame_sink_manager.h" -#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface.h" #include "ui/android/view_android.h" +#include "ui/android/window_android.h" #include "ui/android/window_android_compositor.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -27,12 +27,12 @@ namespace ui { namespace { scoped_refptr<cc::SurfaceLayer> CreateSurfaceLayer( - viz::SurfaceManager* surface_manager, viz::SurfaceInfo surface_info, bool surface_opaque) { // manager must outlive compositors using it. - auto layer = cc::SurfaceLayer::Create(surface_manager->reference_factory()); - layer->SetPrimarySurfaceId(surface_info.id(), base::nullopt); + auto layer = cc::SurfaceLayer::Create(); + layer->SetPrimarySurfaceId(surface_info.id(), + cc::DeadlinePolicy::UseDefaultDeadline()); layer->SetFallbackSurfaceId(surface_info.id()); layer->SetBounds(surface_info.size_in_pixels()); layer->SetIsDrawable(true); @@ -41,26 +41,16 @@ scoped_refptr<cc::SurfaceLayer> CreateSurfaceLayer( return layer; } -void CopyOutputRequestCallback( - scoped_refptr<cc::Layer> readback_layer, - viz::CopyOutputRequest::CopyOutputRequestCallback result_callback, - std::unique_ptr<viz::CopyOutputResult> copy_output_result) { - readback_layer->RemoveFromParent(); - std::move(result_callback).Run(std::move(copy_output_result)); -} - } // namespace DelegatedFrameHostAndroid::DelegatedFrameHostAndroid( ui::ViewAndroid* view, viz::HostFrameSinkManager* host_frame_sink_manager, - viz::FrameSinkManagerImpl* frame_sink_manager, Client* client, const viz::FrameSinkId& frame_sink_id) : frame_sink_id_(frame_sink_id), view_(view), host_frame_sink_manager_(host_frame_sink_manager), - frame_sink_manager_(frame_sink_manager), client_(client), begin_frame_source_(this), enable_surface_synchronization_( @@ -69,10 +59,8 @@ DelegatedFrameHostAndroid::DelegatedFrameHostAndroid( DCHECK(client_); host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this); -#if DCHECK_IS_ON() host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_, "DelegatedFrameHostAndroid"); -#endif CreateNewCompositorFrameSinkSupport(); } @@ -85,7 +73,8 @@ DelegatedFrameHostAndroid::~DelegatedFrameHostAndroid() { void DelegatedFrameHostAndroid::SubmitCompositorFrame( const viz::LocalSurfaceId& local_surface_id, - viz::CompositorFrame frame) { + viz::CompositorFrame frame, + viz::mojom::HitTestRegionListPtr hit_test_region_list) { if (local_surface_id != surface_info_.id().local_surface_id()) { DestroyDelegatedContent(); DCHECK(!content_layer_); @@ -96,16 +85,15 @@ void DelegatedFrameHostAndroid::SubmitCompositorFrame( viz::SurfaceId(frame_sink_id_, local_surface_id), 1.f, frame_size); has_transparent_background_ = root_pass->has_transparent_background; - bool result = - support_->SubmitCompositorFrame(local_surface_id, std::move(frame)); - DCHECK(result); + support_->SubmitCompositorFrame(local_surface_id, std::move(frame), + std::move(hit_test_region_list)); content_layer_ = - CreateSurfaceLayer(frame_sink_manager_->surface_manager(), - surface_info_, !has_transparent_background_); + CreateSurfaceLayer(surface_info_, !has_transparent_background_); view_->GetLayer()->AddChild(content_layer_); } else { - support_->SubmitCompositorFrame(local_surface_id, std::move(frame)); + support_->SubmitCompositorFrame(local_surface_id, std::move(frame), + std::move(hit_test_region_list)); } compositor_attach_until_frame_lock_.reset(); } @@ -119,28 +107,52 @@ viz::FrameSinkId DelegatedFrameHostAndroid::GetFrameSinkId() const { return frame_sink_id_; } -void DelegatedFrameHostAndroid::RequestCopyOfSurface( - WindowAndroidCompositor* compositor, - const gfx::Rect& src_subrect_in_pixel, - viz::CopyOutputRequest::CopyOutputRequestCallback result_callback) { - DCHECK(surface_info_.is_valid()); - DCHECK(!result_callback.is_null()); +void DelegatedFrameHostAndroid::CopyFromCompositingSurface( + const gfx::Rect& src_subrect, + const gfx::Size& output_size, + base::OnceCallback<void(const SkBitmap&)> callback) { + if (!CanCopyFromCompositingSurface()) { + std::move(callback).Run(SkBitmap()); + return; + } scoped_refptr<cc::Layer> readback_layer = - CreateSurfaceLayer(frame_sink_manager_->surface_manager(), surface_info_, - !has_transparent_background_); + CreateSurfaceLayer(surface_info_, !has_transparent_background_); readback_layer->SetHideLayerAndSubtree(true); - compositor->AttachLayerForReadback(readback_layer); - std::unique_ptr<viz::CopyOutputRequest> copy_output_request = + view_->GetWindowAndroid()->GetCompositor()->AttachLayerForReadback( + readback_layer); + std::unique_ptr<viz::CopyOutputRequest> request = std::make_unique<viz::CopyOutputRequest>( - viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, - base::BindOnce(&CopyOutputRequestCallback, readback_layer, - std::move(result_callback))); + viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, + base::BindOnce( + [](base::OnceCallback<void(const SkBitmap&)> callback, + scoped_refptr<cc::Layer> readback_layer, + std::unique_ptr<viz::CopyOutputResult> result) { + readback_layer->RemoveFromParent(); + std::move(callback).Run(result->AsSkBitmap()); + }, + std::move(callback), std::move(readback_layer))); + + if (src_subrect.IsEmpty()) { + request->set_area(gfx::Rect(surface_info_.size_in_pixels())); + } else { + request->set_area( + gfx::ConvertRectToPixel(view_->GetDipScale(), src_subrect)); + } + + if (!output_size.IsEmpty()) { + request->set_result_selection(gfx::Rect(output_size)); + request->SetScaleRatio( + gfx::Vector2d(request->area().width(), request->area().height()), + gfx::Vector2d(output_size.width(), output_size.height())); + } - if (!src_subrect_in_pixel.IsEmpty()) - copy_output_request->set_area(src_subrect_in_pixel); + support_->RequestCopyOfSurface(std::move(request)); +} - support_->RequestCopyOfSurface(std::move(copy_output_request)); +bool DelegatedFrameHostAndroid::CanCopyFromCompositingSurface() const { + return support_ && surface_info_.is_valid() && view_->GetWindowAndroid() && + view_->GetWindowAndroid()->GetCompositor(); } void DelegatedFrameHostAndroid::DestroyDelegatedContent() { @@ -151,7 +163,7 @@ void DelegatedFrameHostAndroid::DestroyDelegatedContent() { content_layer_->RemoveFromParent(); content_layer_ = nullptr; - support_->EvictCurrentSurface(); + support_->EvictLastActivatedSurface(); surface_info_ = viz::SurfaceInfo(); } diff --git a/chromium/ui/android/delegated_frame_host_android.h b/chromium/ui/android/delegated_frame_host_android.h index 5fbfd413119..c0fbac92d08 100644 --- a/chromium/ui/android/delegated_frame_host_android.h +++ b/chromium/ui/android/delegated_frame_host_android.h @@ -24,7 +24,6 @@ enum class SurfaceDrawStatus; namespace viz { class CompositorFrame; -class FrameSinkManagerImpl; class HostFrameSinkManager; } // namespace viz @@ -50,14 +49,15 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid DelegatedFrameHostAndroid(ViewAndroid* view, viz::HostFrameSinkManager* host_frame_sink_manager, - viz::FrameSinkManagerImpl* frame_sink_manager, Client* client, const viz::FrameSinkId& frame_sink_id); ~DelegatedFrameHostAndroid() override; - void SubmitCompositorFrame(const viz::LocalSurfaceId& local_surface_id, - viz::CompositorFrame frame); + void SubmitCompositorFrame( + const viz::LocalSurfaceId& local_surface_id, + viz::CompositorFrame frame, + viz::mojom::HitTestRegionListPtr hit_test_region_list); void DidNotProduceFrame(const viz::BeginFrameAck& ack); void DestroyDelegatedContent(); @@ -69,10 +69,11 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid // Should only be called when the host has a content layer. Use this for one- // off screen capture, not for video. Always provides RGBA_BITMAP // CopyOutputResults. - void RequestCopyOfSurface( - WindowAndroidCompositor* compositor, - const gfx::Rect& src_subrect_in_pixel, - viz::CopyOutputRequest::CopyOutputRequestCallback result_callback); + void CopyFromCompositingSurface( + const gfx::Rect& src_subrect, + const gfx::Size& output_size, + base::OnceCallback<void(const SkBitmap&)> callback); + bool CanCopyFromCompositingSurface() const; void CompositorFrameSinkChanged(); @@ -121,7 +122,6 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid ViewAndroid* view_; viz::HostFrameSinkManager* const host_frame_sink_manager_; - viz::FrameSinkManagerImpl* const frame_sink_manager_; WindowAndroidCompositor* registered_parent_compositor_ = nullptr; Client* client_; diff --git a/chromium/ui/android/event_forwarder.cc b/chromium/ui/android/event_forwarder.cc index dd63f7babf0..7be0652c95d 100644 --- a/chromium/ui/android/event_forwarder.cc +++ b/chromium/ui/android/event_forwarder.cc @@ -12,6 +12,7 @@ #include "ui/base/ui_base_switches_util.h" #include "ui/events/android/drag_event_android.h" #include "ui/events/android/gesture_event_android.h" +#include "ui/events/android/gesture_event_type.h" #include "ui/events/android/motion_event_android.h" #include "ui/events/base_event_utils.h" @@ -175,16 +176,42 @@ bool EventForwarder::OnGestureEvent(JNIEnv* env, const JavaParamRef<jobject>& jobj, jint type, jlong time_ms, - jfloat delta) { + jfloat scale) { float dip_scale = view_->GetDipScale(); auto size = view_->GetSize(); float x = size.width() / 2; float y = size.height() / 2; gfx::PointF root_location = ScalePoint(view_->GetLocationOnScreen(x, y), 1.f / dip_scale); - return view_->OnGestureEvent( - GestureEventAndroid(type, gfx::PointF(x / dip_scale, y / dip_scale), - root_location, time_ms, delta)); + return view_->OnGestureEvent(GestureEventAndroid( + type, gfx::PointF(x / dip_scale, y / dip_scale), root_location, time_ms, + scale, 0, 0, 0, 0, false, false)); +} + +void EventForwarder::OnStartFling(JNIEnv* env, + const JavaParamRef<jobject>& jobj, + jlong time_ms, + jfloat velocity_x, + jfloat velocity_y, + jboolean synthetic_scroll) { + OnCancelFling(env, jobj, time_ms); + if (velocity_x == 0 && velocity_y == 0) + return; + // Use velocity as delta in scroll event. + view_->OnGestureEvent(GestureEventAndroid( + GESTURE_EVENT_TYPE_SCROLL_START, gfx::PointF(), gfx::PointF(), time_ms, 0, + velocity_x, velocity_y, 0, 0, true, synthetic_scroll)); + view_->OnGestureEvent(GestureEventAndroid( + GESTURE_EVENT_TYPE_FLING_START, gfx::PointF(), gfx::PointF(), time_ms, 0, + 0, 0, velocity_x, velocity_y, true, synthetic_scroll)); +} + +void EventForwarder::OnCancelFling(JNIEnv* env, + const JavaParamRef<jobject>& jobj, + jlong time_ms) { + view_->OnGestureEvent( + GestureEventAndroid(GESTURE_EVENT_TYPE_FLING_CANCEL, gfx::PointF(), + gfx::PointF(), time_ms, 0, 0, 0, 0, 0, false, false)); } } // namespace ui diff --git a/chromium/ui/android/event_forwarder.h b/chromium/ui/android/event_forwarder.h index 5081190f623..68bd4db9735 100644 --- a/chromium/ui/android/event_forwarder.h +++ b/chromium/ui/android/event_forwarder.h @@ -88,7 +88,18 @@ class EventForwarder { const base::android::JavaParamRef<jobject>& jobj, jint type, jlong time_ms, - jfloat delta); + jfloat scale); + + void OnStartFling(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + jlong time_ms, + jfloat velocity_x, + jfloat velocity_y, + jboolean synthetic_scroll); + + void OnCancelFling(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj, + jlong time_ms); private: friend class ViewAndroid; diff --git a/chromium/ui/android/resources/resource_manager_impl.cc b/chromium/ui/android/resources/resource_manager_impl.cc index d59d5e1faaf..24ac7b3661a 100644 --- a/chromium/ui/android/resources/resource_manager_impl.cc +++ b/chromium/ui/android/resources/resource_manager_impl.cc @@ -34,6 +34,27 @@ using base::android::JavaArrayOfIntArrayToIntVector; using base::android::JavaParamRef; using base::android::JavaRef; +namespace { + +base::trace_event::MemoryAllocatorDump* CreateMemoryDump( + const std::string& name, + size_t memory_usage, + base::trace_event::ProcessMemoryDump* pmd) { + base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(name); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + memory_usage); + + static const char* system_allocator_name = + base::trace_event::MemoryDumpManager::GetInstance() + ->system_allocator_pool_name(); + if (system_allocator_name) + pmd->AddSuballocation(dump->guid(), system_allocator_name); + return dump; +} + +} // namespace + namespace ui { // static @@ -212,24 +233,21 @@ void ResourceManagerImpl::RemoveResource( bool ResourceManagerImpl::OnMemoryDump( const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) { - size_t memory_usage = - base::trace_event::EstimateMemoryUsage(resources_) + - base::trace_event::EstimateMemoryUsage(tinted_resources_); - - base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump( - base::StringPrintf("ui/resource_manager_0x%" PRIXPTR, - reinterpret_cast<uintptr_t>(this))); - dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, - base::trace_event::MemoryAllocatorDump::kUnitsBytes, - memory_usage); - - const char* system_allocator_name = - base::trace_event::MemoryDumpManager::GetInstance() - ->system_allocator_pool_name(); - if (system_allocator_name) { - pmd->AddSuballocation(dump->guid(), system_allocator_name); + std::string prefix = base::StringPrintf("ui/resource_manager_0x%" PRIXPTR, + reinterpret_cast<uintptr_t>(this)); + for (uint32_t type = static_cast<uint32_t>(ANDROID_RESOURCE_TYPE_FIRST); + type <= static_cast<uint32_t>(ANDROID_RESOURCE_TYPE_LAST); ++type) { + size_t usage = base::trace_event::EstimateMemoryUsage(resources_[type]); + auto* dump = CreateMemoryDump( + prefix + base::StringPrintf("/default_resource/0x%u", + static_cast<uint32_t>(type)), + usage, pmd); + dump->AddScalar("resource_count", "objects", resources_[type].size()); } + size_t tinted_resource_usage = + base::trace_event::EstimateMemoryUsage(tinted_resources_); + CreateMemoryDump(prefix + "/tinted_resource", tinted_resource_usage, pmd); return true; } diff --git a/chromium/ui/android/resources/resource_manager_impl_unittest.cc b/chromium/ui/android/resources/resource_manager_impl_unittest.cc index 441a43337cd..58a16219901 100644 --- a/chromium/ui/android/resources/resource_manager_impl_unittest.cc +++ b/chromium/ui/android/resources/resource_manager_impl_unittest.cc @@ -154,8 +154,8 @@ TEST_F(ResourceManagerTest, TestOnMemoryDumpEmitsData) { const char* system_allocator_pool_name = base::trace_event::MemoryDumpManager::GetInstance() ->system_allocator_pool_name(); - size_t expected_dump_count = system_allocator_pool_name ? 2 : 1; - EXPECT_EQ(expected_dump_count, allocator_dumps.size()); + size_t kExpectedDumpCount = 10; + EXPECT_EQ(kExpectedDumpCount, allocator_dumps.size()); for (const auto& dump : allocator_dumps) { ASSERT_TRUE(dump.first.find("ui/resource_manager") == 0 || dump.first.find(system_allocator_pool_name) == 0); diff --git a/chromium/ui/app_list/BUILD.gn b/chromium/ui/app_list/BUILD.gn index d5a40a53aec..56706f28bd1 100644 --- a/chromium/ui/app_list/BUILD.gn +++ b/chromium/ui/app_list/BUILD.gn @@ -5,6 +5,8 @@ import("//build/config/ui.gni") import("//testing/test.gni") +assert(is_chromeos) + component("app_list") { sources = [ "app_list_constants.cc", @@ -12,6 +14,8 @@ component("app_list") { "app_list_export.h", "app_list_features.cc", "app_list_features.h", + "app_list_metrics.cc", + "app_list_metrics.h", "app_list_switches.cc", "app_list_switches.h", "app_list_util.cc", @@ -63,16 +67,12 @@ component("app_list") { "views/image_shadow_animator.h", "views/indicator_chip_view.cc", "views/indicator_chip_view.h", + "views/page_switcher.cc", "views/page_switcher.h", - "views/page_switcher_horizontal.cc", - "views/page_switcher_horizontal.h", - "views/page_switcher_vertical.cc", - "views/page_switcher_vertical.h", "views/pulsing_block_view.cc", "views/pulsing_block_view.h", "views/search_box_view.cc", "views/search_box_view.h", - "views/search_box_view_delegate.h", "views/search_result_actions_view.cc", "views/search_result_actions_view.h", "views/search_result_actions_view_delegate.h", @@ -92,8 +92,6 @@ component("app_list") { "views/search_result_tile_item_view.h", "views/search_result_view.cc", "views/search_result_view.h", - "views/speech_view.cc", - "views/speech_view.h", "views/suggestions_container_view.cc", "views/suggestions_container_view.h", "views/top_icon_animation_view.cc", @@ -121,6 +119,7 @@ component("app_list") { "//ui/aura", "//ui/base", "//ui/base/ime", + "//ui/chromeos/search_box", "//ui/compositor", "//ui/display", "//ui/events", @@ -137,7 +136,6 @@ component("app_list") { public_deps = [ "//ash/app_list/model:app_list_model", "//ash/app_list/model:search_model", - "//ash/app_list/model:speech_ui_model", "//ash/public/cpp:cpp", ] } @@ -185,7 +183,6 @@ executable("app_list_demo") { "//ui/resources", "//ui/resources:ui_test_pak", "//ui/views", - "//ui/views/controls/webview", "//ui/views_content_client", "//url", ] @@ -213,7 +210,6 @@ test("app_list_unittests") { "views/search_result_list_view_unittest.cc", "views/search_result_page_view_unittest.cc", "views/search_result_tile_item_list_view_unittest.cc", - "views/speech_view_unittest.cc", ] configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] @@ -229,6 +225,7 @@ test("app_list_unittests") { "//ui/accessibility", "//ui/app_list/vector_icons", "//ui/base", + "//ui/chromeos/search_box", "//ui/compositor", "//ui/events:test_support", "//ui/gfx:test_support", diff --git a/chromium/ui/app_list/presenter/BUILD.gn b/chromium/ui/app_list/presenter/BUILD.gn index 58cc1463e83..82d6dae01c9 100644 --- a/chromium/ui/app_list/presenter/BUILD.gn +++ b/chromium/ui/app_list/presenter/BUILD.gn @@ -51,7 +51,7 @@ component("presenter") { # Temporary dependency to fix compile flake in http://crbug.com/611898. # TODO(tapted): Remove once http://crbug.com/612382 is fixed. - "//ui/accessibility:ax_gen", + "//ui/accessibility:ax_enums_mojo", ] } @@ -66,7 +66,7 @@ static_library("test_support") { # Temporary dependency to fix compile flake in http://crbug.com/611898. # TODO(tapted): Remove once http://crbug.com/612382 is fixed. - "//ui/accessibility:ax_gen", + "//ui/accessibility:ax_enums_mojo", ] public_deps = [ @@ -105,7 +105,7 @@ test("app_list_presenter_unittests") { # Temporary dependency to fix compile flake in http://crbug.com/611898. # TODO(tapted): Remove once http://crbug.com/612382 is fixed. - "//ui/accessibility:ax_gen", + "//ui/accessibility:ax_enums_mojo", ] data_deps = [ diff --git a/chromium/ui/arc/notification/arc_notification_content_view.cc b/chromium/ui/arc/notification/arc_notification_content_view.cc index 214f35bda01..baecc8484c1 100644 --- a/chromium/ui/arc/notification/arc_notification_content_view.cc +++ b/chromium/ui/arc/notification/arc_notification_content_view.cc @@ -9,7 +9,6 @@ #include "base/memory/ptr_util.h" #include "components/exo/notification_surface.h" #include "components/exo/surface.h" -#include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_node_data.h" #include "ui/arc/notification/arc_notification_surface.h" #include "ui/arc/notification/arc_notification_view.h" @@ -238,18 +237,6 @@ class ArcNotificationContentView::ContentViewDelegate explicit ContentViewDelegate(ArcNotificationContentView* owner) : owner_(owner) {} - bool IsCloseButtonFocused() const override { - if (!owner_->control_buttons_view_) - return false; - return owner_->control_buttons_view_->IsCloseButtonFocused(); - } - - void RequestFocusOnCloseButton() override { - if (owner_->control_buttons_view_) - owner_->control_buttons_view_->RequestFocusOnCloseButton(); - owner_->UpdateControlButtonsVisibility(); - } - void UpdateControlButtonsVisibility() override { owner_->UpdateControlButtonsVisibility(); } @@ -264,10 +251,6 @@ class ArcNotificationContentView::ContentViewDelegate return owner_->control_buttons_view_; } - bool IsExpanded() const override { return owner_->IsExpanded(); } - - void SetExpanded(bool expanded) override { owner_->SetExpanded(expanded); } - void OnContainerAnimationStarted() override { owner_->OnContainerAnimationStarted(); } @@ -514,21 +497,6 @@ void ArcNotificationContentView::UpdateAccessibleName() { accessible_name_ = item_->GetAccessibleName(); } -bool ArcNotificationContentView::IsExpanded() const { - return item_->GetExpandState() == mojom::ArcNotificationExpandState::EXPANDED; -} - -void ArcNotificationContentView::SetExpanded(bool expanded) { - auto expand_state = item_->GetExpandState(); - if (expanded) { - if (expand_state == mojom::ArcNotificationExpandState::COLLAPSED) - item_->ToggleExpansion(); - } else { - if (expand_state == mojom::ArcNotificationExpandState::EXPANDED) - item_->ToggleExpansion(); - } -} - void ArcNotificationContentView::OnContainerAnimationStarted() { ShowCopiedSurface(); } @@ -699,25 +667,16 @@ views::FocusTraversable* ArcNotificationContentView::GetFocusTraversable() { return nullptr; } -bool ArcNotificationContentView::HandleAccessibleAction( - const ui::AXActionData& action_data) { - if (item_ && action_data.action == ui::AX_ACTION_DO_DEFAULT) { - item_->ToggleExpansion(); - return true; - } - return false; -} - void ArcNotificationContentView::GetAccessibleNodeData( ui::AXNodeData* node_data) { if (surface_ && surface_->GetAXTreeId() != -1) { - node_data->role = ui::AX_ROLE_CLIENT; - node_data->AddIntAttribute(ui::AX_ATTR_CHILD_TREE_ID, + node_data->role = ax::mojom::Role::kClient; + node_data->AddIntAttribute(ax::mojom::IntAttribute::kChildTreeId, surface_->GetAXTreeId()); } else { - node_data->role = ui::AX_ROLE_BUTTON; + node_data->role = ax::mojom::Role::kButton; node_data->AddStringAttribute( - ui::AX_ATTR_ROLE_DESCRIPTION, + ax::mojom::StringAttribute::kRoleDescription, l10n_util::GetStringUTF8( IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME)); } @@ -766,11 +725,11 @@ void ArcNotificationContentView::OnNotificationSurfaceAdded( SetSurface(surface); - // Notify AX_EVENT_CHILDREN_CHANGED to force AXNodeData of this view updated. - // As order of OnNotificationSurfaceAdded call is not guaranteed, we are - // dispatching the event in both ArcNotificationContentView and + // Notify ax::mojom::Event::kChildrenChanged to force AXNodeData of this view + // updated. As order of OnNotificationSurfaceAdded call is not guaranteed, we + // are dispatching the event in both ArcNotificationContentView and // ArcAccessibilityHelperBridge. - NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, false); + NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false); } void ArcNotificationContentView::OnNotificationSurfaceRemoved( diff --git a/chromium/ui/arc/notification/arc_notification_content_view.h b/chromium/ui/arc/notification/arc_notification_content_view.h index 49a64cc7efc..fe405a0c4dd 100644 --- a/chromium/ui/arc/notification/arc_notification_content_view.h +++ b/chromium/ui/arc/notification/arc_notification_content_view.h @@ -20,7 +20,6 @@ class NotificationControlButtonsView; } namespace ui { -struct AXActionData; class LayerTreeOwner; } @@ -73,6 +72,8 @@ class ArcNotificationContentView void UpdateAccessibleName(); void SetExpanded(bool expanded); bool IsExpanded() const; + void SetManuallyExpandedOrCollapsed(bool value); + bool IsManuallyExpandedOrCollapsed() const; void OnContainerAnimationStarted(); void OnContainerAnimationEnded(); @@ -89,7 +90,6 @@ class ArcNotificationContentView void OnFocus() override; void OnBlur() override; views::FocusTraversable* GetFocusTraversable() override; - bool HandleAccessibleAction(const ui::AXActionData& action) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; // aura::WindowObserver @@ -109,7 +109,7 @@ class ArcNotificationContentView // If |item_| is null, we may be about to be destroyed. In this case, // we have to be careful about what we do. - ArcNotificationItem* item_ = nullptr; + ArcNotificationItem* item_; ArcNotificationSurface* surface_ = nullptr; // The flag to prevent an infinite loop of changing the visibility. diff --git a/chromium/ui/arc/notification/arc_notification_content_view_delegate.h b/chromium/ui/arc/notification/arc_notification_content_view_delegate.h index c2268bd3cda..2d8e4d04ffc 100644 --- a/chromium/ui/arc/notification/arc_notification_content_view_delegate.h +++ b/chromium/ui/arc/notification/arc_notification_content_view_delegate.h @@ -17,14 +17,10 @@ namespace arc { class ArcNotificationContentViewDelegate { public: virtual ~ArcNotificationContentViewDelegate() = default; - virtual bool IsCloseButtonFocused() const = 0; - virtual void RequestFocusOnCloseButton() = 0; virtual void UpdateControlButtonsVisibility() = 0; virtual void OnSlideChanged() = 0; virtual message_center::NotificationControlButtonsView* GetControlButtonsView() const = 0; - virtual bool IsExpanded() const = 0; - virtual void SetExpanded(bool expanded) = 0; virtual void OnContainerAnimationStarted() = 0; virtual void OnContainerAnimationEnded() = 0; }; diff --git a/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc b/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc index b6773b11efa..d69a751faf4 100644 --- a/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc +++ b/chromium/ui/arc/notification/arc_notification_content_view_unittest.cc @@ -32,7 +32,7 @@ #include "ui/aura/window.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/test/event_generator.h" -#include "ui/message_center/notification.h" +#include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/views/message_view_factory.h" #include "ui/message_center/views/notification_control_buttons_view.h" #include "ui/message_center/views/padded_button.h" @@ -113,6 +113,7 @@ class MockArcNotificationItem : public ArcNotificationItem { return base::EmptyString16(); }; void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data) override {} + bool IsManuallyExpandedOrCollapsed() const override { return false; } private: std::string notification_key_; diff --git a/chromium/ui/arc/notification/arc_notification_delegate.cc b/chromium/ui/arc/notification/arc_notification_delegate.cc index ff764a801f1..4a3ddb0ac03 100644 --- a/chromium/ui/arc/notification/arc_notification_delegate.cc +++ b/chromium/ui/arc/notification/arc_notification_delegate.cc @@ -7,7 +7,7 @@ #include "ui/arc/notification/arc_notification_content_view.h" #include "ui/arc/notification/arc_notification_item.h" #include "ui/arc/notification/arc_notification_view.h" -#include "ui/message_center/notification.h" +#include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/views/message_view.h" namespace arc { @@ -28,8 +28,9 @@ ArcNotificationDelegate::CreateCustomMessageView( auto view = std::make_unique<ArcNotificationContentView>(item_.get()); auto content_view_delegate = view->CreateContentViewDelegate(); - return std::make_unique<ArcNotificationView>( - std::move(view), std::move(content_view_delegate), notification); + return std::make_unique<ArcNotificationView>(item_.get(), std::move(view), + std::move(content_view_delegate), + notification); } void ArcNotificationDelegate::Close(bool by_user) { diff --git a/chromium/ui/arc/notification/arc_notification_delegate.h b/chromium/ui/arc/notification/arc_notification_delegate.h index 66223939779..c90da5dc3c5 100644 --- a/chromium/ui/arc/notification/arc_notification_delegate.h +++ b/chromium/ui/arc/notification/arc_notification_delegate.h @@ -7,7 +7,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "ui/message_center/notification_delegate.h" +#include "ui/message_center/public/cpp/notification_delegate.h" namespace message_center { diff --git a/chromium/ui/arc/notification/arc_notification_item.h b/chromium/ui/arc/notification/arc_notification_item.h index d5d1f973fbe..cbe94104602 100644 --- a/chromium/ui/arc/notification/arc_notification_item.h +++ b/chromium/ui/arc/notification/arc_notification_item.h @@ -69,6 +69,9 @@ class ArcNotificationItem { virtual const gfx::ImageSkia& GetSnapshot() const = 0; // Returns the current expand state. virtual mojom::ArcNotificationExpandState GetExpandState() const = 0; + + virtual bool IsManuallyExpandedOrCollapsed() const = 0; + // Returns the current type of shown contents. virtual mojom::ArcNotificationShownContents GetShownContents() const = 0; // Returns the rect for which Android wants to handle all swipe events. diff --git a/chromium/ui/arc/notification/arc_notification_item_impl.cc b/chromium/ui/arc/notification/arc_notification_item_impl.cc index df632b0bb44..a889206a543 100644 --- a/chromium/ui/arc/notification/arc_notification_item_impl.cc +++ b/chromium/ui/arc/notification/arc_notification_item_impl.cc @@ -13,10 +13,10 @@ #include "ui/arc/notification/arc_notification_delegate.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_types.h" -#include "ui/message_center/notifier_id.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" +#include "ui/message_center/public/cpp/notifier_id.h" namespace arc { @@ -104,6 +104,14 @@ void ArcNotificationItemImpl::OnUpdatedFromAndroid( new ArcNotificationDelegate(weak_ptr_factory_.GetWeakPtr())); notification->set_timestamp(base::Time::FromJavaTime(data->time)); + if (expand_state_ != mojom::ArcNotificationExpandState::FIXED_SIZE && + data->expand_state != mojom::ArcNotificationExpandState::FIXED_SIZE && + expand_state_ != data->expand_state) { + // Assuming changing the expand status on Android-side is manually tiggered + // by user. + manually_expanded_or_collapsed_ = true; + } + expand_state_ = data->expand_state; shown_contents_ = data->shown_contents; swipe_input_rect_ = @@ -156,6 +164,18 @@ bool ArcNotificationItemImpl::IsOpeningSettingsSupported() const { } void ArcNotificationItemImpl::ToggleExpansion() { + switch (expand_state_) { + case mojom::ArcNotificationExpandState::EXPANDED: + expand_state_ = mojom::ArcNotificationExpandState::COLLAPSED; + break; + case mojom::ArcNotificationExpandState::COLLAPSED: + expand_state_ = mojom::ArcNotificationExpandState::EXPANDED; + break; + case mojom::ArcNotificationExpandState::FIXED_SIZE: + // Do not change the state. + break; + } + manager_->SendNotificationToggleExpansionOnChrome(notification_key_); } @@ -193,6 +213,10 @@ mojom::ArcNotificationExpandState ArcNotificationItemImpl::GetExpandState() return expand_state_; } +bool ArcNotificationItemImpl::IsManuallyExpandedOrCollapsed() const { + return manually_expanded_or_collapsed_; +} + mojom::ArcNotificationShownContents ArcNotificationItemImpl::GetShownContents() const { return shown_contents_; diff --git a/chromium/ui/arc/notification/arc_notification_item_impl.h b/chromium/ui/arc/notification/arc_notification_item_impl.h index 72c77d32641..33bea528b40 100644 --- a/chromium/ui/arc/notification/arc_notification_item_impl.h +++ b/chromium/ui/arc/notification/arc_notification_item_impl.h @@ -44,6 +44,7 @@ class ArcNotificationItemImpl : public ArcNotificationItem { void DecrementWindowRefCount() override; const gfx::ImageSkia& GetSnapshot() const override; mojom::ArcNotificationExpandState GetExpandState() const override; + bool IsManuallyExpandedOrCollapsed() const override; mojom::ArcNotificationShownContents GetShownContents() const override; gfx::Rect GetSwipeInputRect() const override; const std::string& GetNotificationKey() const override; @@ -85,6 +86,8 @@ class ArcNotificationItemImpl : public ArcNotificationItem { // (2) the removing is initiated by manager bool being_removed_by_manager_ = false; + bool manually_expanded_or_collapsed_ = false; + base::ThreadChecker thread_checker_; base::WeakPtrFactory<ArcNotificationItemImpl> weak_ptr_factory_; diff --git a/chromium/ui/arc/notification/arc_notification_manager_unittest.cc b/chromium/ui/arc/notification/arc_notification_manager_unittest.cc index 6a03147aef8..98f586105d2 100644 --- a/chromium/ui/arc/notification/arc_notification_manager_unittest.cc +++ b/chromium/ui/arc/notification/arc_notification_manager_unittest.cc @@ -86,9 +86,6 @@ class ArcNotificationManagerTest : public testing::Test { data->title = "TITLE"; data->message = "MESSAGE"; - std::vector<unsigned char> icon_data; - data->icon_data = icon_data; - arc_notification_manager()->OnNotificationPosted(std::move(data)); return key; diff --git a/chromium/ui/arc/notification/arc_notification_view.cc b/chromium/ui/arc/notification/arc_notification_view.cc index 0e33fe23c68..6977d6d385f 100644 --- a/chromium/ui/arc/notification/arc_notification_view.cc +++ b/chromium/ui/arc/notification/arc_notification_view.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "ui/accessibility/ax_action_data.h" #include "ui/arc/notification/arc_notification_content_view_delegate.h" #include "ui/arc/notification/arc_notification_item.h" #include "ui/base/ime/input_method.h" @@ -25,14 +26,18 @@ namespace arc { const char ArcNotificationView::kViewClassName[] = "ArcNotificationView"; ArcNotificationView::ArcNotificationView( + ArcNotificationItem* item, std::unique_ptr<views::View> contents_view, std::unique_ptr<ArcNotificationContentViewDelegate> contents_view_delegate, const message_center::Notification& notification) : message_center::MessageView(notification), + item_(item), contents_view_(contents_view.get()), contents_view_delegate_(std::move(contents_view_delegate)) { DCHECK_EQ(message_center::NOTIFICATION_TYPE_CUSTOM, notification.type()); + item_->AddObserver(this); + DCHECK(contents_view); AddChildView(contents_view.release()); @@ -49,7 +54,10 @@ ArcNotificationView::ArcNotificationView( message_center::kFocusBorderColor, gfx::Insets(0, 1, 3, 2)); } -ArcNotificationView::~ArcNotificationView() = default; +ArcNotificationView::~ArcNotificationView() { + if (item_) + item_->RemoveObserver(this); +} void ArcNotificationView::OnContentFocused() { SchedulePaint(); @@ -75,14 +83,17 @@ void ArcNotificationView::SetDrawBackgroundAsActive(bool active) { } bool ArcNotificationView::IsCloseButtonFocused() const { - if (!contents_view_delegate_) + if (!GetControlButtonsView()) return false; - return contents_view_delegate_->IsCloseButtonFocused(); + return GetControlButtonsView()->IsCloseButtonFocused(); } void ArcNotificationView::RequestFocusOnCloseButton() { - if (contents_view_delegate_) - contents_view_delegate_->RequestFocusOnCloseButton(); + if (GetControlButtonsView()) { + GetControlButtonsView()->RequestFocusOnCloseButton(); + if (contents_view_delegate_) + contents_view_delegate_->UpdateControlButtonsVisibility(); + } } const char* ArcNotificationView::GetClassName() const { @@ -105,14 +116,28 @@ ArcNotificationView::GetControlButtonsView() const { } bool ArcNotificationView::IsExpanded() const { - if (contents_view_delegate_) - return contents_view_delegate_->IsExpanded(); - return false; + return item_ && + item_->GetExpandState() == mojom::ArcNotificationExpandState::EXPANDED; } void ArcNotificationView::SetExpanded(bool expanded) { - if (contents_view_delegate_) - contents_view_delegate_->SetExpanded(expanded); + if (!item_) + return; + + auto expand_state = item_->GetExpandState(); + if (expanded) { + if (expand_state == mojom::ArcNotificationExpandState::COLLAPSED) + item_->ToggleExpansion(); + } else { + if (expand_state == mojom::ArcNotificationExpandState::EXPANDED) + item_->ToggleExpansion(); + } +} + +bool ArcNotificationView::IsManuallyExpandedOrCollapsed() const { + if (item_) + return item_->IsManuallyExpandedOrCollapsed(); + return false; } void ArcNotificationView::OnContainerAnimationStarted() { @@ -197,11 +222,21 @@ void ArcNotificationView::ChildPreferredSizeChanged(View* child) { bool ArcNotificationView::HandleAccessibleAction( const ui::AXActionData& action) { - if (contents_view_) - return contents_view_->HandleAccessibleAction(action); + if (item_ && action.action == ax::mojom::Action::kDoDefault) { + item_->ToggleExpansion(); + return true; + } return false; } +void ArcNotificationView::OnItemDestroying() { + DCHECK(item_); + item_->RemoveObserver(this); + item_ = nullptr; +} + +void ArcNotificationView::OnItemUpdated() {} + // TODO(yoshiki): move this to MessageView and share the code among // NotificationView and NotificationViewMD. void ArcNotificationView::UpdateControlButtonsVisibilityWithNotification( diff --git a/chromium/ui/arc/notification/arc_notification_view.h b/chromium/ui/arc/notification/arc_notification_view.h index c8dedeebbe5..e54838bb0b5 100644 --- a/chromium/ui/arc/notification/arc_notification_view.h +++ b/chromium/ui/arc/notification/arc_notification_view.h @@ -6,6 +6,7 @@ #define UI_ARC_NOTIFICATION_ARC_NOTIFICATION_VIEW_H_ #include "base/macros.h" +#include "ui/arc/notification/arc_notification_item.h" #include "ui/message_center/views/message_view.h" namespace views { @@ -18,12 +19,14 @@ class ArcNotificationContentViewDelegate; // View for custom notification with NOTIFICATION_TYPE_CUSTOM which hosts the // ArcNotificationContentView which shows content of the notification. -class ArcNotificationView : public message_center::MessageView { +class ArcNotificationView : public message_center::MessageView, + public ArcNotificationItem::Observer { public: static const char kViewClassName[]; // |content_view| is a view to be hosted in this view. - ArcNotificationView(std::unique_ptr<views::View> content_view, + ArcNotificationView(ArcNotificationItem* item, + std::unique_ptr<views::View> content_view, std::unique_ptr<ArcNotificationContentViewDelegate> contents_view_delegate, const message_center::Notification& notification); @@ -46,6 +49,7 @@ class ArcNotificationView : public message_center::MessageView { const override; bool IsExpanded() const override; void SetExpanded(bool expanded) override; + bool IsManuallyExpandedOrCollapsed() const override; void OnContainerAnimationStarted() override; void OnContainerAnimationEnded() override; @@ -63,6 +67,10 @@ class ArcNotificationView : public message_center::MessageView { void ChildPreferredSizeChanged(View* child) override; bool HandleAccessibleAction(const ui::AXActionData& action) override; + // ArcNotificationItem::Observer + void OnItemDestroying() override; + void OnItemUpdated() override; + private: friend class ArcNotificationContentViewTest; friend class ArcNotificationViewTest; @@ -71,6 +79,8 @@ class ArcNotificationView : public message_center::MessageView { void UpdateControlButtonsVisibilityWithNotification( const message_center::Notification& notification); + ArcNotificationItem* item_; + // The view for the custom content. Owned by view hierarchy. views::View* contents_view_ = nullptr; std::unique_ptr<ArcNotificationContentViewDelegate> contents_view_delegate_; diff --git a/chromium/ui/arc/notification/arc_notification_view_unittest.cc b/chromium/ui/arc/notification/arc_notification_view_unittest.cc index 54935541f4e..e988fdd763b 100644 --- a/chromium/ui/arc/notification/arc_notification_view_unittest.cc +++ b/chromium/ui/arc/notification/arc_notification_view_unittest.cc @@ -10,6 +10,7 @@ #include "base/strings/utf_string_conversions.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/arc/notification/arc_notification_content_view_delegate.h" +#include "ui/arc/notification/arc_notification_item.h" #include "ui/arc/notification/arc_notification_view.h" #include "ui/base/ime/dummy_text_input_client.h" #include "ui/base/ime/input_method.h" @@ -19,7 +20,7 @@ #include "ui/events/event_utils.h" #include "ui/events/test/event_generator.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" +#include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/views/message_view_factory.h" #include "ui/views/background.h" #include "ui/views/controls/button/image_button.h" @@ -32,6 +33,7 @@ namespace arc { namespace { +constexpr char kNotificationIdPrefix[] = "ARC_NOTIFICATION_"; const SkColor kBackgroundColor = SK_ColorGREEN; class TestNotificationContentsView : public views::View { @@ -76,24 +78,68 @@ class TestNotificationContentsView : public views::View { class TestContentViewDelegate : public ArcNotificationContentViewDelegate { public: - bool IsCloseButtonFocused() const override { return false; } - void RequestFocusOnCloseButton() override {} void UpdateControlButtonsVisibility() override {} void OnSlideChanged() override {} message_center::NotificationControlButtonsView* GetControlButtonsView() const override { return nullptr; } - bool IsExpanded() const override { return false; } - void SetExpanded(bool expanded) override {} void OnContainerAnimationStarted() override {} void OnContainerAnimationEnded() override {} }; +class MockArcNotificationItem : public ArcNotificationItem { + public: + MockArcNotificationItem(const std::string& notification_key) + : notification_key_(notification_key), + notification_id_(kNotificationIdPrefix + notification_key) {} + + // Overriding methods for testing. + void Close(bool by_user) override {} + const gfx::ImageSkia& GetSnapshot() const override { return snapshot_; } + const std::string& GetNotificationKey() const override { + return notification_key_; + } + const std::string& GetNotificationId() const override { + return notification_id_; + } + + // Overriding methods for returning dummy data or doing nothing. + void OnClosedFromAndroid() override {} + void Click() override {} + void ToggleExpansion() override {} + void OpenSettings() override {} + void AddObserver(Observer* observer) override {} + void RemoveObserver(Observer* observer) override {} + void IncrementWindowRefCount() override {} + void DecrementWindowRefCount() override {} + bool IsOpeningSettingsSupported() const override { return true; } + mojom::ArcNotificationExpandState GetExpandState() const override { + return mojom::ArcNotificationExpandState::FIXED_SIZE; + } + mojom::ArcNotificationShownContents GetShownContents() const override { + return mojom::ArcNotificationShownContents::CONTENTS_SHOWN; + } + gfx::Rect GetSwipeInputRect() const override { return gfx::Rect(); } + const base::string16& GetAccessibleName() const override { + return base::EmptyString16(); + }; + void OnUpdatedFromAndroid(mojom::ArcNotificationDataPtr data) override {} + bool IsManuallyExpandedOrCollapsed() const override { return false; } + + private: + std::string notification_key_; + std::string notification_id_; + gfx::ImageSkia snapshot_; + + DISALLOW_COPY_AND_ASSIGN(MockArcNotificationItem); +}; + std::unique_ptr<message_center::MessageView> CreateCustomMessageViewForTest( + ArcNotificationItem* item, const Notification& notification) { return std::make_unique<ArcNotificationView>( - std::make_unique<TestNotificationContentsView>(), + item, std::make_unique<TestNotificationContentsView>(), std::make_unique<TestContentViewDelegate>(), notification); } @@ -124,13 +170,14 @@ class ArcNotificationViewTest : public views::ViewsTestBase { MessageCenter::Initialize(); + const std::string notification_id("notification id"); + item_ = std::make_unique<MockArcNotificationItem>(notification_id); message_center::MessageViewFactory::SetCustomNotificationViewFactory( - base::Bind(&CreateCustomMessageViewForTest)); + base::BindRepeating(&CreateCustomMessageViewForTest, item_.get())); notification_ = std::make_unique<Notification>( - message_center::NOTIFICATION_TYPE_CUSTOM, - std::string("notification id"), base::UTF8ToUTF16("title"), - base::UTF8ToUTF16("message"), gfx::Image(), + message_center::NOTIFICATION_TYPE_CUSTOM, notification_id, + base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), gfx::Image(), base::UTF8ToUTF16("display source"), GURL(), message_center::NotifierId(message_center::NotifierId::ARC_APPLICATION, "test_app_id"), @@ -233,6 +280,8 @@ class ArcNotificationViewTest : public views::ViewsTestBase { std::unique_ptr<Notification> notification_; std::unique_ptr<ArcNotificationView> notification_view_; + std::unique_ptr<MockArcNotificationItem> item_; + DISALLOW_COPY_AND_ASSIGN(ArcNotificationViewTest); }; @@ -313,6 +362,7 @@ TEST_F(ArcNotificationViewTest, SlideOutPinned) { ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); notification()->set_pinned(true); + notification_view()->SetIsNested(); UpdateNotificationViews(); std::string notification_id = notification()->id(); diff --git a/chromium/ui/aura/BUILD.gn b/chromium/ui/aura/BUILD.gn index 0e63f4b6fb1..04f009d70b7 100644 --- a/chromium/ui/aura/BUILD.gn +++ b/chromium/ui/aura/BUILD.gn @@ -67,6 +67,7 @@ jumbo_component("aura") { "mus/window_tree_host_mus.h", "mus/window_tree_host_mus_delegate.h", "mus/window_tree_host_mus_init_params.h", + "scoped_keyboard_hook.h", "scoped_window_targeter.h", "window.h", "window_delegate.h", @@ -126,6 +127,7 @@ jumbo_component("aura") { "mus/window_tree_client_delegate.cc", "mus/window_tree_host_mus.cc", "mus/window_tree_host_mus_init_params.cc", + "scoped_keyboard_hook.cc", "scoped_window_targeter.cc", "window.cc", "window_event_dispatcher.cc", @@ -155,6 +157,7 @@ jumbo_component("aura") { "//mojo/public/cpp/system", "//net", "//services/service_manager/public/cpp", + "//services/ui/common:mus_common", "//services/ui/public/cpp", "//services/ui/public/interfaces", "//skia", @@ -176,10 +179,6 @@ jumbo_component("aura") { "//ui/compositor", ] - data_deps = [ - "//services/ui", - ] - if (use_x11) { deps += [ "//ui/events/platform/x11", @@ -268,6 +267,7 @@ jumbo_static_library("test_support") { public_deps = [ ":aura", + "//services/ui/common:mus_common", # Must be public as headers include ui_features.h. "//ui/base:ui_features", diff --git a/chromium/ui/aura/DEPS b/chromium/ui/aura/DEPS index 7a319fed221..8deffa55def 100644 --- a/chromium/ui/aura/DEPS +++ b/chromium/ui/aura/DEPS @@ -11,7 +11,8 @@ include_rules = [ "+mojo/public/cpp/bindings", "+net/base/filename_util.h", "+services/service_manager/public/cpp", - "+services/service_manager/public/interfaces", + "+services/service_manager/public/mojom", + "+services/ui/common", "+services/ui/public/interfaces", "+skia/ext", "+third_party/skia", diff --git a/chromium/ui/aura/client/aura_constants.cc b/chromium/ui/aura/client/aura_constants.cc index 618b51e3121..c171556d287 100644 --- a/chromium/ui/aura/client/aura_constants.cc +++ b/chromium/ui/aura/client/aura_constants.cc @@ -73,6 +73,7 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(base::string16, kTitleKey, nullptr); DEFINE_UI_CLASS_PROPERTY_KEY(int, kTopViewInset, 0); DEFINE_UI_CLASS_PROPERTY_KEY(SkColor, kTopViewColor, SK_ColorTRANSPARENT); DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kWindowIconKey, nullptr); +DEFINE_UI_CLASS_PROPERTY_KEY(int, kWindowCornerRadiusKey, -1); DEFINE_UI_CLASS_PROPERTY_KEY(ui::mojom::WindowType, kWindowTypeKey, ui::mojom::WindowType::UNKNOWN); diff --git a/chromium/ui/aura/client/aura_constants.h b/chromium/ui/aura/client/aura_constants.h index 3730ab710ee..f0f8b6cbf53 100644 --- a/chromium/ui/aura/client/aura_constants.h +++ b/chromium/ui/aura/client/aura_constants.h @@ -152,6 +152,10 @@ AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kWindowIconKey; // Indicates the type of embedding within the given window. AURA_EXPORT extern const WindowProperty<WindowEmbedType>* const kEmbedType; +// The corner radius of a window in DIPs. Currently only used for shadows. +// Default is -1, meaning "unspecified". 0 Ensures corners are square. +AURA_EXPORT extern const WindowProperty<int>* const kWindowCornerRadiusKey; + AURA_EXPORT extern const WindowProperty<ui::mojom::WindowType>* const kWindowTypeKey; diff --git a/chromium/ui/aura/env.cc b/chromium/ui/aura/env.cc index 08d1d4db88a..b62fcc15aba 100644 --- a/chromium/ui/aura/env.cc +++ b/chromium/ui/aura/env.cc @@ -25,8 +25,10 @@ #include "ui/events/platform/platform_event_source.h" #if defined(USE_OZONE) +#include "ui/gfx/client_native_pixmap_factory.h" #include "ui/ozone/public/client_native_pixmap_factory_ozone.h" #include "ui/ozone/public/ozone_platform.h" +#include "ui/ozone/public/ozone_switches.h" #endif namespace aura { @@ -163,9 +165,6 @@ Env::Env(Mode mode) is_touch_down_(false), get_last_mouse_location_from_mus_(mode_ == Mode::MUS), input_state_lookup_(InputStateLookup::Create()), -#if defined(USE_OZONE) - native_pixmap_factory_(ui::CreateClientNativePixmapFactoryOzone()), -#endif context_factory_(nullptr), context_factory_private_(nullptr) { DCHECK(lazy_tls_ptr.Pointer()->Get() == NULL); @@ -173,13 +172,13 @@ Env::Env(Mode mode) } void Env::Init() { +#if defined(USE_OZONE) + ui::CreateClientNativePixmapFactoryOzone(); + DCHECK(gfx::ClientNativePixmapFactory::GetInstance()); +#endif if (mode_ == Mode::MUS) { EnableMusOSExchangeDataProvider(); EnableMusOverrideInputInjector(); -#if defined(USE_OZONE) - // Required by all Aura-using clients of services/ui - gfx::ClientNativePixmapFactory::SetInstance(native_pixmap_factory_.get()); -#endif return; } @@ -193,8 +192,9 @@ void Env::Init() { // instead of checking flags here. params.single_process = command_line->HasSwitch("single-process") || command_line->HasSwitch("in-process-gpu"); + params.using_mojo = command_line->HasSwitch(switches::kEnableDrmMojo); + ui::OzonePlatform::InitializeForUI(params); - gfx::ClientNativePixmapFactory::SetInstance(native_pixmap_factory_.get()); #endif if (!ui::PlatformEventSource::GetInstance()) event_source_ = ui::PlatformEventSource::CreateDefault(); diff --git a/chromium/ui/aura/env.h b/chromium/ui/aura/env.h index bf0e401979b..bc615fdb3a1 100644 --- a/chromium/ui/aura/env.h +++ b/chromium/ui/aura/env.h @@ -26,12 +26,6 @@ namespace base { class UnguessableToken; } -#if defined(USE_OZONE) -namespace gfx { -class ClientNativePixmapFactory; -} -#endif - namespace mojo { template <typename MojoInterface> class InterfacePtr; @@ -214,12 +208,6 @@ class AURA_EXPORT Env : public ui::EventTarget, std::unique_ptr<InputStateLookup> input_state_lookup_; std::unique_ptr<ui::PlatformEventSource> event_source_; -#if defined(USE_OZONE) - // Factory for pixmaps that can use be transported from the client to the GPU - // process using a low-level ozone-provided platform specific mechanism. - std::unique_ptr<gfx::ClientNativePixmapFactory> native_pixmap_factory_; -#endif - ui::ContextFactory* context_factory_; ui::ContextFactoryPrivate* context_factory_private_; diff --git a/chromium/ui/aura/env_input_state_controller.cc b/chromium/ui/aura/env_input_state_controller.cc index 6807055790b..0478abf599c 100644 --- a/chromium/ui/aura/env_input_state_controller.cc +++ b/chromium/ui/aura/env_input_state_controller.cc @@ -47,7 +47,7 @@ void EnvInputStateController::UpdateStateForTouchEvent( case ui::ET_TOUCH_CANCELLED: if (!event.HasNativeEvent()) break; - // fallthrough + FALLTHROUGH; case ui::ET_TOUCH_RELEASED: touch_ids_down_ = (touch_ids_down_ | (1 << event.pointer_details().id)) ^ (1 << event.pointer_details().id); diff --git a/chromium/ui/aura/hit_test_data_provider_aura.cc b/chromium/ui/aura/hit_test_data_provider_aura.cc index 1b35ed642b4..0f7600aae12 100644 --- a/chromium/ui/aura/hit_test_data_provider_aura.cc +++ b/chromium/ui/aura/hit_test_data_provider_aura.cc @@ -44,8 +44,8 @@ HitTestDataProviderAura::HitTestDataProviderAura(aura::Window* window) HitTestDataProviderAura::~HitTestDataProviderAura() {} -viz::mojom::HitTestRegionListPtr HitTestDataProviderAura::GetHitTestData() - const { +viz::mojom::HitTestRegionListPtr HitTestDataProviderAura::GetHitTestData( + const viz::CompositorFrame& compositor_frame) const { const ui::mojom::EventTargetingPolicy event_targeting_policy = window_->event_targeting_policy(); if (!window_->IsVisible() || @@ -58,6 +58,7 @@ viz::mojom::HitTestRegionListPtr HitTestDataProviderAura::GetHitTestData() ui::mojom::EventTargetingPolicy::DESCENDANTS_ONLY ? viz::mojom::kHitTestIgnore : viz::mojom::kHitTestMine; + // TODO(crbug.com/805416): Use pixels instead of DIP units for bounds. hit_test_region_list->bounds = window_->bounds(); GetHitTestDataRecursively(window_, hit_test_region_list.get()); diff --git a/chromium/ui/aura/hit_test_data_provider_aura.h b/chromium/ui/aura/hit_test_data_provider_aura.h index 9993a31ae2c..5887e821702 100644 --- a/chromium/ui/aura/hit_test_data_provider_aura.h +++ b/chromium/ui/aura/hit_test_data_provider_aura.h @@ -22,7 +22,8 @@ class AURA_EXPORT HitTestDataProviderAura : public viz::HitTestDataProvider { ~HitTestDataProviderAura() override; // HitTestDataProvider: - viz::mojom::HitTestRegionListPtr GetHitTestData() const override; + viz::mojom::HitTestRegionListPtr GetHitTestData( + const viz::CompositorFrame& compositor_frame) const override; private: // Recursively walks the children of |window| and uses |window|'s diff --git a/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc b/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc index b157f28fc7d..96a6d82decd 100644 --- a/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc +++ b/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc @@ -118,6 +118,7 @@ class HitTestDataProviderAuraTest : public test::AuraTestBaseMus { root_->AddChild(window2_); root_->AddChild(window3_); + compositor_frame_ = viz::CompositorFrame(); hit_test_data_provider_ = std::make_unique<HitTestDataProviderAura>(root()); } @@ -130,6 +131,7 @@ class HitTestDataProviderAuraTest : public test::AuraTestBaseMus { Window* window2() { return window2_; } Window* window3() { return window3_; } Window* window4() { return window4_; } + viz::CompositorFrame compositor_frame_; private: std::unique_ptr<Window> root_; @@ -146,7 +148,8 @@ class HitTestDataProviderAuraTest : public test::AuraTestBaseMus { // Tests that the order of reported hit-test regions matches windows Z-order. TEST_F(HitTestDataProviderAuraTest, Stacking) { - const auto hit_test_data_1 = hit_test_data_provider()->GetHitTestData(); + const auto hit_test_data_1 = + hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data_1); EXPECT_EQ(hit_test_data_1->flags, viz::mojom::kHitTestMine); EXPECT_EQ(hit_test_data_1->bounds, root()->bounds()); @@ -164,7 +167,8 @@ TEST_F(HitTestDataProviderAuraTest, Stacking) { } root()->StackChildAbove(window2(), window3()); - const auto hit_test_data_2 = hit_test_data_provider()->GetHitTestData(); + const auto hit_test_data_2 = + hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data_2); EXPECT_EQ(hit_test_data_2->flags, viz::mojom::kHitTestMine); EXPECT_EQ(hit_test_data_2->bounds, root()->bounds()); @@ -186,8 +190,9 @@ TEST_F(HitTestDataProviderAuraTest, Stacking) { // Tests that the hit-test regions get expanded with a custom event targeter. TEST_F(HitTestDataProviderAuraTest, CustomTargeter) { window3()->SetEventTargeter(std::make_unique<TestWindowTargeter>()); - window2()->set_embed_frame_sink_id(viz::FrameSinkId(1, 2)); - const auto hit_test_data = hit_test_data_provider()->GetHitTestData(); + window2()->SetEmbedFrameSinkId(viz::FrameSinkId(1, 2)); + const auto hit_test_data = + hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->flags, viz::mojom::kHitTestMine); EXPECT_EQ(hit_test_data->bounds, root()->bounds()); @@ -229,7 +234,8 @@ TEST_F(HitTestDataProviderAuraTest, CustomTargeter) { // Tests that the complex hit-test shape can be set with a custom targeter. TEST_F(HitTestDataProviderAuraTest, HoleTargeter) { window3()->SetEventTargeter(std::make_unique<TestHoleWindowTargeter>()); - const auto hit_test_data = hit_test_data_provider()->GetHitTestData(); + const auto hit_test_data = + hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->flags, viz::mojom::kHitTestMine); EXPECT_EQ(hit_test_data->bounds, root()->bounds()); @@ -263,13 +269,14 @@ TEST_F(HitTestDataProviderAuraTest, HoleTargeter) { TEST_F(HitTestDataProviderAuraTest, TargetingPolicies) { root()->SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy::NONE); - auto hit_test_data = hit_test_data_provider()->GetHitTestData(); + auto hit_test_data = + hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_FALSE(hit_test_data); root()->SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy::TARGET_ONLY); window3()->SetEventTargetingPolicy( ui::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->flags, viz::mojom::kHitTestMine); EXPECT_EQ(hit_test_data->regions.size(), 3u); @@ -277,7 +284,7 @@ TEST_F(HitTestDataProviderAuraTest, TargetingPolicies) { root()->SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy::TARGET_ONLY); window3()->SetEventTargetingPolicy( ui::mojom::EventTargetingPolicy::TARGET_ONLY); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->flags, viz::mojom::kHitTestMine); EXPECT_EQ(hit_test_data->regions.size(), 2u); @@ -286,7 +293,7 @@ TEST_F(HitTestDataProviderAuraTest, TargetingPolicies) { ui::mojom::EventTargetingPolicy::DESCENDANTS_ONLY); window3()->SetEventTargetingPolicy( ui::mojom::EventTargetingPolicy::DESCENDANTS_ONLY); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->flags, viz::mojom::kHitTestIgnore); EXPECT_EQ(hit_test_data->regions.size(), 2u); @@ -295,7 +302,7 @@ TEST_F(HitTestDataProviderAuraTest, TargetingPolicies) { ui::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); window3()->SetEventTargetingPolicy( ui::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->flags, viz::mojom::kHitTestMine); EXPECT_EQ(hit_test_data->regions.size(), 3u); @@ -304,30 +311,31 @@ TEST_F(HitTestDataProviderAuraTest, TargetingPolicies) { // Tests that we do not submit hit-test data for invisible windows and for // children of a child surface. TEST_F(HitTestDataProviderAuraTest, DoNotSubmit) { - auto hit_test_data = hit_test_data_provider()->GetHitTestData(); + auto hit_test_data = + hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->regions.size(), 3u); window2()->Hide(); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->regions.size(), 2u); - window3()->set_embed_frame_sink_id(viz::FrameSinkId(1, 3)); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + window3()->SetEmbedFrameSinkId(viz::FrameSinkId(1, 3)); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->regions.size(), 1u); root()->Hide(); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_FALSE(hit_test_data); root()->Show(); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->regions.size(), 1u); - root()->set_embed_frame_sink_id(viz::FrameSinkId(1, 1)); - hit_test_data = hit_test_data_provider()->GetHitTestData(); + root()->SetEmbedFrameSinkId(viz::FrameSinkId(1, 1)); + hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_); ASSERT_TRUE(hit_test_data); EXPECT_EQ(hit_test_data->regions.size(), 0u); } diff --git a/chromium/ui/aura/local/layer_tree_frame_sink_local.cc b/chromium/ui/aura/local/layer_tree_frame_sink_local.cc index 954176f0fcf..a5ce5a4d677 100644 --- a/chromium/ui/aura/local/layer_tree_frame_sink_local.cc +++ b/chromium/ui/aura/local/layer_tree_frame_sink_local.cc @@ -23,12 +23,9 @@ LayerTreeFrameSinkLocal::LayerTreeFrameSinkLocal( const std::string& debug_label) : cc::LayerTreeFrameSink(nullptr, nullptr, nullptr, nullptr, nullptr), frame_sink_id_(frame_sink_id), - host_frame_sink_manager_(host_frame_sink_manager), - weak_factory_(this) { + host_frame_sink_manager_(host_frame_sink_manager) { host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this); -#if DCHECK_IS_ON() host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_, debug_label); -#endif } LayerTreeFrameSinkLocal::~LayerTreeFrameSinkLocal() { @@ -56,16 +53,11 @@ void LayerTreeFrameSinkLocal::SetSurfaceChangedCallback( surface_changed_callback_ = callback; } -base::WeakPtr<LayerTreeFrameSinkLocal> LayerTreeFrameSinkLocal::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); -} - void LayerTreeFrameSinkLocal::DetachFromClient() { DCHECK(thread_checker_); DCHECK(thread_checker_->CalledOnValidThread()); client_->SetBeginFrameSource(nullptr); begin_frame_source_.reset(); - support_->EvictCurrentSurface(); support_.reset(); thread_checker_.reset(); cc::LayerTreeFrameSink::DetachFromClient(); @@ -87,9 +79,7 @@ void LayerTreeFrameSinkLocal::SubmitCompositorFrame( DCHECK(local_surface_id_.is_valid()); - bool result = - support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)); - DCHECK(result); + support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)); } void LayerTreeFrameSinkLocal::DidNotProduceFrame( @@ -101,6 +91,19 @@ void LayerTreeFrameSinkLocal::DidNotProduceFrame( support_->DidNotProduceFrame(ack); } +void LayerTreeFrameSinkLocal::DidAllocateSharedBitmap( + mojo::ScopedSharedBufferHandle buffer, + const viz::SharedBitmapId& id) { + // No software compositing used with this implementation. + NOTIMPLEMENTED(); +} + +void LayerTreeFrameSinkLocal::DidDeleteSharedBitmap( + const viz::SharedBitmapId& id) { + // No software compositing used with this implementation. + NOTIMPLEMENTED(); +} + void LayerTreeFrameSinkLocal::DidReceiveCompositorFrameAck( const std::vector<viz::ReturnedResource>& resources) { DCHECK(thread_checker_); diff --git a/chromium/ui/aura/local/layer_tree_frame_sink_local.h b/chromium/ui/aura/local/layer_tree_frame_sink_local.h index 25dc6cf74b9..83217f46ce8 100644 --- a/chromium/ui/aura/local/layer_tree_frame_sink_local.h +++ b/chromium/ui/aura/local/layer_tree_frame_sink_local.h @@ -42,8 +42,6 @@ class LayerTreeFrameSinkLocal : public cc::LayerTreeFrameSink, // Set a callback which will be called when the surface is changed. void SetSurfaceChangedCallback(const SurfaceChangedCallback& callback); - base::WeakPtr<LayerTreeFrameSinkLocal> GetWeakPtr(); - const viz::LocalSurfaceId& local_surface_id() const { return local_surface_id_; } @@ -54,6 +52,9 @@ class LayerTreeFrameSinkLocal : public cc::LayerTreeFrameSink, void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id) override; void SubmitCompositorFrame(viz::CompositorFrame frame) override; void DidNotProduceFrame(const viz::BeginFrameAck& ack) override; + void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer, + const viz::SharedBitmapId& id) override; + void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override; // viz::mojom::CompositorFrameSinkClient: void DidReceiveCompositorFrameAck( @@ -84,7 +85,6 @@ class LayerTreeFrameSinkLocal : public cc::LayerTreeFrameSink, std::unique_ptr<viz::ExternalBeginFrameSource> begin_frame_source_; std::unique_ptr<base::ThreadChecker> thread_checker_; SurfaceChangedCallback surface_changed_callback_; - base::WeakPtrFactory<LayerTreeFrameSinkLocal> weak_factory_; DISALLOW_COPY_AND_ASSIGN(LayerTreeFrameSinkLocal); }; diff --git a/chromium/ui/aura/local/window_port_local.cc b/chromium/ui/aura/local/window_port_local.cc index c9b3213d26f..787fbc5e7cc 100644 --- a/chromium/ui/aura/local/window_port_local.cc +++ b/chromium/ui/aura/local/window_port_local.cc @@ -4,7 +4,7 @@ #include "ui/aura/local/window_port_local.h" -#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" +#include "components/viz/host/host_frame_sink_manager.h" #include "ui/aura/client/cursor_client.h" #include "ui/aura/env.h" #include "ui/aura/local/layer_tree_frame_sink_local.h" @@ -118,26 +118,20 @@ void WindowPortLocal::OnPropertyChanged( std::unique_ptr<cc::LayerTreeFrameSink> WindowPortLocal::CreateLayerTreeFrameSink() { - DCHECK(!frame_sink_id_.is_valid()); auto* context_factory_private = aura::Env::GetInstance()->context_factory_private(); - frame_sink_id_ = context_factory_private->AllocateFrameSinkId(); + auto frame_sink_id = context_factory_private->AllocateFrameSinkId(); auto frame_sink = std::make_unique<LayerTreeFrameSinkLocal>( - frame_sink_id_, context_factory_private->GetHostFrameSinkManager(), + frame_sink_id, context_factory_private->GetHostFrameSinkManager(), window_->GetName()); + window_->SetEmbedFrameSinkId(frame_sink_id); frame_sink->SetSurfaceChangedCallback(base::Bind( &WindowPortLocal::OnSurfaceChanged, weak_factory_.GetWeakPtr())); frame_sink_ = frame_sink->GetWeakPtr(); AllocateLocalSurfaceId(); - if (window_->GetRootWindow()) - window_->layer()->GetCompositor()->AddFrameSink(frame_sink_id_); return std::move(frame_sink); } -viz::SurfaceId WindowPortLocal::GetSurfaceId() const { - return viz::SurfaceId(frame_sink_id_, local_surface_id_); -} - void WindowPortLocal::AllocateLocalSurfaceId() { last_device_scale_factor_ = ui::GetScaleFactorForNativeView(window_); last_size_ = window_->bounds().size(); @@ -152,34 +146,14 @@ const viz::LocalSurfaceId& WindowPortLocal::GetLocalSurfaceId() { return local_surface_id_; } -viz::FrameSinkId WindowPortLocal::GetFrameSinkId() const { - return frame_sink_id_; -} - -void WindowPortLocal::OnWindowAddedToRootWindow() { - if (frame_sink_id_.is_valid()) - window_->layer()->GetCompositor()->AddFrameSink(frame_sink_id_); -} - -void WindowPortLocal::OnWillRemoveWindowFromRootWindow() { - if (frame_sink_id_.is_valid()) - window_->layer()->GetCompositor()->RemoveFrameSink(frame_sink_id_); -} - void WindowPortLocal::OnEventTargetingPolicyChanged() {} void WindowPortLocal::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) { - DCHECK_EQ(surface_info.id().frame_sink_id(), frame_sink_id_); + DCHECK_EQ(surface_info.id().frame_sink_id(), window_->GetFrameSinkId()); DCHECK_EQ(surface_info.id().local_surface_id(), local_surface_id_); - scoped_refptr<viz::SurfaceReferenceFactory> reference_factory = - aura::Env::GetInstance() - ->context_factory_private() - ->GetFrameSinkManager() - ->surface_manager() - ->reference_factory(); - window_->layer()->SetShowPrimarySurface(surface_info.id(), - window_->bounds().size(), - SK_ColorWHITE, reference_factory); + window_->layer()->SetShowPrimarySurface( + surface_info.id(), window_->bounds().size(), SK_ColorWHITE, + cc::DeadlinePolicy::UseDefaultDeadline()); window_->layer()->SetFallbackSurfaceId(surface_info.id()); } diff --git a/chromium/ui/aura/local/window_port_local.h b/chromium/ui/aura/local/window_port_local.h index be24ab4f8d9..58abd724537 100644 --- a/chromium/ui/aura/local/window_port_local.h +++ b/chromium/ui/aura/local/window_port_local.h @@ -46,12 +46,8 @@ class AURA_EXPORT WindowPortLocal : public WindowPort { int64_t old_value, std::unique_ptr<ui::PropertyData> data) override; std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override; - viz::SurfaceId GetSurfaceId() const override; void AllocateLocalSurfaceId() override; const viz::LocalSurfaceId& GetLocalSurfaceId() override; - viz::FrameSinkId GetFrameSinkId() const override; - void OnWindowAddedToRootWindow() override; - void OnWillRemoveWindowFromRootWindow() override; void OnEventTargetingPolicyChanged() override; bool ShouldRestackTransientChildren() override; @@ -59,12 +55,11 @@ class AURA_EXPORT WindowPortLocal : public WindowPort { void OnSurfaceChanged(const viz::SurfaceInfo& surface_info); Window* const window_; - viz::FrameSinkId frame_sink_id_; gfx::Size last_size_; float last_device_scale_factor_ = 1.0f; viz::LocalSurfaceId local_surface_id_; viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_; - base::WeakPtr<aura::LayerTreeFrameSinkLocal> frame_sink_; + base::WeakPtr<cc::LayerTreeFrameSink> frame_sink_; base::WeakPtrFactory<WindowPortLocal> weak_factory_; diff --git a/chromium/ui/aura/mus/client_surface_embedder.cc b/chromium/ui/aura/mus/client_surface_embedder.cc index 17029d25b7b..7863b68f365 100644 --- a/chromium/ui/aura/mus/client_surface_embedder.cc +++ b/chromium/ui/aura/mus/client_surface_embedder.cc @@ -5,7 +5,6 @@ #include "ui/aura/mus/client_surface_embedder.h" #include "base/memory/ptr_util.h" -#include "components/viz/common/surfaces/stub_surface_reference_factory.h" #include "ui/aura/window.h" #include "ui/gfx/geometry/dip_util.h" @@ -30,15 +29,15 @@ ClientSurfaceEmbedder::ClientSurfaceEmbedder( // this is the case with window decorations provided by Window Manager. // This content should appear underneath the content of the embedded client. window_->layer()->StackAtTop(surface_layer_.get()); - ref_factory_ = new viz::StubSurfaceReferenceFactory(); } ClientSurfaceEmbedder::~ClientSurfaceEmbedder() = default; void ClientSurfaceEmbedder::SetPrimarySurfaceId( const viz::SurfaceId& surface_id) { - surface_layer_->SetShowPrimarySurface(surface_id, window_->bounds().size(), - SK_ColorWHITE, ref_factory_); + surface_layer_->SetShowPrimarySurface( + surface_id, window_->bounds().size(), SK_ColorWHITE, + cc::DeadlinePolicy::UseDefaultDeadline()); } void ClientSurfaceEmbedder::SetFallbackSurfaceInfo( @@ -95,4 +94,9 @@ void ClientSurfaceEmbedder::UpdateSizeAndGutters() { window_->layer()->StackAtTop(surface_layer_.get()); } +const viz::SurfaceId& ClientSurfaceEmbedder::GetPrimarySurfaceIdForTesting() + const { + return *surface_layer_->GetPrimarySurfaceId(); +} + } // namespace aura diff --git a/chromium/ui/aura/mus/client_surface_embedder.h b/chromium/ui/aura/mus/client_surface_embedder.h index e5085af030e..5017c44951a 100644 --- a/chromium/ui/aura/mus/client_surface_embedder.h +++ b/chromium/ui/aura/mus/client_surface_embedder.h @@ -8,19 +8,15 @@ #include <memory> #include "base/macros.h" -#include "base/memory/ref_counted.h" #include "components/viz/common/surfaces/surface_info.h" -#include "components/viz/common/surfaces/surface_reference_factory.h" +#include "ui/aura/aura_export.h" +#include "ui/compositor/layer.h" #include "ui/gfx/geometry/insets.h" namespace gfx { class Insets; } -namespace ui { -class Layer; -} - namespace aura { class Window; @@ -28,7 +24,7 @@ class Window; // Used by WindowPortMus when it is embedding a client. Responsible for setting // up layers containing content from the client, parenting them to the window's // layer, and updating them when the client submits new surfaces. -class ClientSurfaceEmbedder { +class AURA_EXPORT ClientSurfaceEmbedder { public: // TODO(fsamuel): Insets might differ when the window is maximized. We should // deal with that case as well. @@ -53,6 +49,8 @@ class ClientSurfaceEmbedder { ui::Layer* BottomGutterForTesting() { return bottom_gutter_.get(); } + const viz::SurfaceId& GetPrimarySurfaceIdForTesting() const; + private: // The window which embeds the client. Window* window_; @@ -70,8 +68,6 @@ class ClientSurfaceEmbedder { bool inject_gutter_; gfx::Insets client_area_insets_; - scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_; - DISALLOW_COPY_AND_ASSIGN(ClientSurfaceEmbedder); }; diff --git a/chromium/ui/aura/mus/drag_drop_controller_mus.cc b/chromium/ui/aura/mus/drag_drop_controller_mus.cc index 55d271583bf..532b0364807 100644 --- a/chromium/ui/aura/mus/drag_drop_controller_mus.cc +++ b/chromium/ui/aura/mus/drag_drop_controller_mus.cc @@ -40,7 +40,7 @@ namespace aura { // State related to a drag initiated by this client. struct DragDropControllerMus::CurrentDragState { - Id window_id; + ui::Id window_id; // The change id of the drag. Used to identify the drag on the server. uint32_t change_id; diff --git a/chromium/ui/aura/mus/mus_context_factory.cc b/chromium/ui/aura/mus/mus_context_factory.cc index f95b744e593..f2b4dc0c60e 100644 --- a/chromium/ui/aura/mus/mus_context_factory.cc +++ b/chromium/ui/aura/mus/mus_context_factory.cc @@ -21,9 +21,6 @@ namespace aura { MusContextFactory::MusContextFactory(ui::Gpu* gpu) : gpu_(gpu), - resource_settings_( - // TODO(sad): http://crbug.com/675431 - viz::CreateResourceSettings()), weak_ptr_factory_(this) {} MusContextFactory::~MusContextFactory() {} @@ -89,8 +86,4 @@ cc::TaskGraphRunner* MusContextFactory::GetTaskGraphRunner() { return raster_thread_helper_.task_graph_runner(); } -const viz::ResourceSettings& MusContextFactory::GetResourceSettings() const { - return resource_settings_; -} - } // namespace aura diff --git a/chromium/ui/aura/mus/mus_context_factory.h b/chromium/ui/aura/mus/mus_context_factory.h index ab1b1950f62..532af0fad23 100644 --- a/chromium/ui/aura/mus/mus_context_factory.h +++ b/chromium/ui/aura/mus/mus_context_factory.h @@ -17,10 +17,6 @@ #include "ui/aura/aura_export.h" #include "ui/compositor/compositor.h" -namespace cc { -class ResourceSettings; -} - namespace gpu { class GpuChannelHost; } @@ -51,13 +47,11 @@ class AURA_EXPORT MusContextFactory : public ui::ContextFactory { double GetRefreshRate() const override; gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override; cc::TaskGraphRunner* GetTaskGraphRunner() override; - const viz::ResourceSettings& GetResourceSettings() const override; void AddObserver(ui::ContextFactoryObserver* observer) override {} void RemoveObserver(ui::ContextFactoryObserver* observer) override {} ui::RasterThreadHelper raster_thread_helper_; ui::Gpu* gpu_; - const viz::ResourceSettings resource_settings_; scoped_refptr<viz::ContextProvider> shared_main_thread_context_provider_; base::WeakPtrFactory<MusContextFactory> weak_ptr_factory_; diff --git a/chromium/ui/aura/mus/mus_types.h b/chromium/ui/aura/mus/mus_types.h index 8c4f305f3b2..84b95f65da8 100644 --- a/chromium/ui/aura/mus/mus_types.h +++ b/chromium/ui/aura/mus/mus_types.h @@ -7,20 +7,14 @@ #include <stdint.h> +#include "services/ui/common/types.h" + // Typedefs for the transport types. These typedefs match that of the mojom // file, see it for specifics. namespace aura { -// Used to identify windows and change ids. -using Id = uint32_t; - -// Used to identify a client as well as a client-specific window id. For -// example, the Id for a window consists of the ClientSpecificId of the client -// and the ClientSpecificId of the window. -using ClientSpecificId = uint16_t; - -constexpr Id kInvalidServerId = 0; +constexpr ui::Id kInvalidServerId = 0; enum class WindowMusType { // The window is an embed root. That is, the client received this window by diff --git a/chromium/ui/aura/mus/property_converter.cc b/chromium/ui/aura/mus/property_converter.cc index 8839c507cb6..7a0a67e0177 100644 --- a/chromium/ui/aura/mus/property_converter.cc +++ b/chromium/ui/aura/mus/property_converter.cc @@ -49,6 +49,10 @@ bool ValidateShowState(int64_t value) { value == int64_t(ui::mojom::ShowState::FULLSCREEN); } +bool ValidateWindowCornerRadius(int64_t value) { + return value >= -1; +} + } // namespace PropertyConverter::PrimitiveProperty::PrimitiveProperty() {} @@ -96,6 +100,10 @@ PropertyConverter::PropertyConverter() { ui::mojom::WindowManager::kName_Property); RegisterString16Property(client::kTitleKey, ui::mojom::WindowManager::kWindowTitle_Property); + RegisterPrimitiveProperty( + client::kWindowCornerRadiusKey, + ui::mojom::WindowManager::kWindowCornerRadius_Property, + base::BindRepeating(&ValidateWindowCornerRadius)); } PropertyConverter::~PropertyConverter() {} diff --git a/chromium/ui/aura/mus/system_input_injector_mus.cc b/chromium/ui/aura/mus/system_input_injector_mus.cc index 7b062808248..1aa83e5a10f 100644 --- a/chromium/ui/aura/mus/system_input_injector_mus.cc +++ b/chromium/ui/aura/mus/system_input_injector_mus.cc @@ -76,6 +76,7 @@ void SystemInputInjectorMus::InjectMouseButton(ui::EventFlags button, break; case ui::EF_MIDDLE_MOUSE_BUTTON: modifier = ui::MODIFIER_MIDDLE_MOUSE_BUTTON; + break; default: LOG(WARNING) << "Invalid flag: " << button << " for the button parameter"; return; diff --git a/chromium/ui/aura/mus/text_input_client_impl.cc b/chromium/ui/aura/mus/text_input_client_impl.cc index 9f926a779c0..514a69a5611 100644 --- a/chromium/ui/aura/mus/text_input_client_impl.cc +++ b/chromium/ui/aura/mus/text_input_client_impl.cc @@ -39,8 +39,8 @@ void TextInputClientImpl::ClearCompositionText() { text_input_client_->ClearCompositionText(); } -void TextInputClientImpl::InsertText(const std::string& text) { - text_input_client_->InsertText(base::UTF8ToUTF16(text)); +void TextInputClientImpl::InsertText(const base::string16& text) { + text_input_client_->InsertText(text); } void TextInputClientImpl::InsertChar(std::unique_ptr<ui::Event> event) { diff --git a/chromium/ui/aura/mus/text_input_client_impl.h b/chromium/ui/aura/mus/text_input_client_impl.h index 46bf153d5c3..5f5b98d4807 100644 --- a/chromium/ui/aura/mus/text_input_client_impl.h +++ b/chromium/ui/aura/mus/text_input_client_impl.h @@ -31,7 +31,7 @@ class TextInputClientImpl : public ui::mojom::TextInputClient { void SetCompositionText(const ui::CompositionText& composition) override; void ConfirmCompositionText() override; void ClearCompositionText() override; - void InsertText(const std::string& text) override; + void InsertText(const base::string16& text) override; void InsertChar(std::unique_ptr<ui::Event> event) override; void DispatchKeyEventPostIME( std::unique_ptr<ui::Event> event, diff --git a/chromium/ui/aura/mus/window_mus.h b/chromium/ui/aura/mus/window_mus.h index 355b4805bac..ade1846d660 100644 --- a/chromium/ui/aura/mus/window_mus.h +++ b/chromium/ui/aura/mus/window_mus.h @@ -67,7 +67,7 @@ class AURA_EXPORT WindowMus { } static WindowMus* Get(Window* window); - Id server_id() const { return server_id_; } + ui::Id server_id() const { return server_id_; } WindowMusType window_mus_type() const { return window_mus_type_; } @@ -135,9 +135,9 @@ class AURA_EXPORT WindowMus { // Just for set_server_id(), which other places should not call. friend class WindowTreeClient; - void set_server_id(Id id) { server_id_ = id; } + void set_server_id(ui::Id id) { server_id_ = id; } - Id server_id_ = kInvalidServerId; + ui::Id server_id_ = kInvalidServerId; const WindowMusType window_mus_type_; }; diff --git a/chromium/ui/aura/mus/window_port_mus.cc b/chromium/ui/aura/mus/window_port_mus.cc index 5b4bcab052d..45dd67e18ef 100644 --- a/chromium/ui/aura/mus/window_port_mus.cc +++ b/chromium/ui/aura/mus/window_port_mus.cc @@ -6,7 +6,7 @@ #include "base/memory/ptr_util.h" #include "components/viz/client/local_surface_id_provider.h" -#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" +#include "components/viz/host/host_frame_sink_manager.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/transient_window_client.h" #include "ui/aura/env.h" @@ -19,6 +19,7 @@ #include "ui/aura/window_delegate.h" #include "ui/aura/window_observer.h" #include "ui/base/class_property.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches_util.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -131,10 +132,12 @@ WindowPortMus::RequestLayerTreeFrameSink( return layer_tree_frame_sink; } -viz::FrameSinkId WindowPortMus::GetFrameSinkId() const { - if (window_->IsEmbeddingClient()) - return window_->embed_frame_sink_id(); - return viz::FrameSinkId(0, server_id()); +viz::FrameSinkId WindowPortMus::GenerateFrameSinkIdFromServerId() const { + // With mus, the client does not know its own client id. So it uses a constant + // value of 0. This gets replaced in the server side with the correct value + // where appropriate. + constexpr int kClientSelfId = 0; + return viz::FrameSinkId(kClientSelfId, server_id()); } WindowPortMus::ServerChangeIdType WindowPortMus::ScheduleChange( @@ -302,7 +305,7 @@ void WindowPortMus::SetFrameSinkIdFromServer( const viz::FrameSinkId& frame_sink_id) { DCHECK(window_mus_type() == WindowMusType::TOP_LEVEL_IN_WM || window_mus_type() == WindowMusType::EMBED_IN_OWNER); - window_->set_embed_frame_sink_id(frame_sink_id); + window_->SetEmbedFrameSinkId(frame_sink_id); UpdatePrimarySurfaceId(); } @@ -331,14 +334,14 @@ void WindowPortMus::SetFallbackSurfaceInfo( const viz::SurfaceInfo& surface_info) { if (!window_->IsEmbeddingClient()) { // |primary_surface_id_| shold not be valid, since we didn't know the - // |window_->embed_frame_sink_id()|. + // |window_->frame_sink_id()|. DCHECK(!primary_surface_id_.is_valid()); - window_->set_embed_frame_sink_id(surface_info.id().frame_sink_id()); + window_->SetEmbedFrameSinkId(surface_info.id().frame_sink_id()); UpdatePrimarySurfaceId(); } // The frame sink id should never be changed. - DCHECK_EQ(surface_info.id().frame_sink_id(), window_->embed_frame_sink_id()); + DCHECK_EQ(surface_info.id().frame_sink_id(), window_->GetFrameSinkId()); fallback_surface_info_ = surface_info; UpdateClientSurfaceEmbedder(); @@ -403,10 +406,11 @@ WindowPortMus::ChangeSource WindowPortMus::OnTransientChildRemoved( void WindowPortMus::AllocateLocalSurfaceId() { local_surface_id_ = parent_local_surface_id_allocator_.GenerateId(); + UpdatePrimarySurfaceId(); } const viz::LocalSurfaceId& WindowPortMus::GetLocalSurfaceId() { - if (switches::IsMusHostingViz()) + if (base::FeatureList::IsEnabled(features::kMash)) return local_surface_id_; if (!window_->IsEmbeddingClient() && !window_->IsRootWindow()) return local_surface_id_; @@ -559,17 +563,18 @@ WindowPortMus::CreateLayerTreeFrameSink() { DCHECK(!local_layer_tree_frame_sink_); std::unique_ptr<cc::LayerTreeFrameSink> frame_sink; - if (switches::IsMusHostingViz()) { + if (base::FeatureList::IsEnabled(features::kMash)) { auto client_layer_tree_frame_sink = RequestLayerTreeFrameSink(nullptr, aura::Env::GetInstance() ->context_factory() ->GetGpuMemoryBufferManager()); local_layer_tree_frame_sink_ = client_layer_tree_frame_sink->GetWeakPtr(); frame_sink = std::move(client_layer_tree_frame_sink); + window_->SetEmbedFrameSinkId(GenerateFrameSinkIdFromServerId()); } else { auto* context_factory_private = aura::Env::GetInstance()->context_factory_private(); - auto frame_sink_id = GetFrameSinkId(); + auto frame_sink_id = window_->GetFrameSinkId(); DCHECK(frame_sink_id.is_valid()); auto layer_tree_frame_sink_local = std::make_unique<LayerTreeFrameSinkLocal>( @@ -577,10 +582,7 @@ WindowPortMus::CreateLayerTreeFrameSink() { window_->GetName()); layer_tree_frame_sink_local->SetSurfaceChangedCallback(base::BindRepeating( &WindowPortMus::OnSurfaceChanged, weak_ptr_factory_.GetWeakPtr())); - if (window_->layer()->GetCompositor()) { - window_->layer()->GetCompositor()->AddFrameSink(GetFrameSinkId()); - is_frame_sink_id_added_to_compositor_ = true; - } + window_->SetEmbedFrameSinkId(frame_sink_id); local_layer_tree_frame_sink_ = layer_tree_frame_sink_local->GetWeakPtr(); frame_sink = std::move(layer_tree_frame_sink_local); } @@ -593,29 +595,6 @@ WindowPortMus::CreateLayerTreeFrameSink() { return frame_sink; } -viz::SurfaceId WindowPortMus::GetSurfaceId() const { - return viz::SurfaceId(window_->embed_frame_sink_id(), local_surface_id_); -} - -void WindowPortMus::OnWindowAddedToRootWindow() { - if (switches::IsMusHostingViz()) - return; - if (local_layer_tree_frame_sink_) { - DCHECK(!is_frame_sink_id_added_to_compositor_); - window_->layer()->GetCompositor()->AddFrameSink(GetFrameSinkId()); - is_frame_sink_id_added_to_compositor_ = true; - } -} - -void WindowPortMus::OnWillRemoveWindowFromRootWindow() { - if (switches::IsMusHostingViz()) - return; - if (is_frame_sink_id_added_to_compositor_) { - window_->layer()->GetCompositor()->RemoveFrameSink(GetFrameSinkId()); - is_frame_sink_id_added_to_compositor_ = false; - } -} - void WindowPortMus::OnEventTargetingPolicyChanged() { SetEventTargetingPolicy(window_->event_targeting_policy()); } @@ -636,12 +615,12 @@ void WindowPortMus::UpdatePrimarySurfaceId() { return; primary_surface_id_ = - viz::SurfaceId(window_->embed_frame_sink_id(), local_surface_id_); + viz::SurfaceId(window_->GetFrameSinkId(), local_surface_id_); UpdateClientSurfaceEmbedder(); } void WindowPortMus::UpdateClientSurfaceEmbedder() { - if (!switches::IsMusHostingViz()) + if (!base::FeatureList::IsEnabled(features::kMash)) return; if (window_mus_type() != WindowMusType::TOP_LEVEL_IN_WM && window_mus_type() != WindowMusType::EMBED_IN_OWNER && @@ -661,18 +640,14 @@ void WindowPortMus::UpdateClientSurfaceEmbedder() { } void WindowPortMus::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) { - DCHECK(!switches::IsMusHostingViz()); - DCHECK_EQ(surface_info.id().frame_sink_id(), GetFrameSinkId()); + // TODO(fsamuel): Rename OnFirstSurfaceActivation() and set primary earlier + // based on feedback from LayerTreeFrameSinkLocal. + DCHECK(!base::FeatureList::IsEnabled(features::kMash)); + DCHECK_EQ(surface_info.id().frame_sink_id(), window_->GetFrameSinkId()); DCHECK_EQ(surface_info.id().local_surface_id(), local_surface_id_); - scoped_refptr<viz::SurfaceReferenceFactory> reference_factory = - aura::Env::GetInstance() - ->context_factory_private() - ->GetFrameSinkManager() - ->surface_manager() - ->reference_factory(); - window_->layer()->SetShowPrimarySurface(surface_info.id(), - window_->bounds().size(), - SK_ColorWHITE, reference_factory); + window_->layer()->SetShowPrimarySurface( + surface_info.id(), window_->bounds().size(), SK_ColorWHITE, + cc::DeadlinePolicy::UseDefaultDeadline()); window_->layer()->SetFallbackSurfaceId(surface_info.id()); } diff --git a/chromium/ui/aura/mus/window_port_mus.h b/chromium/ui/aura/mus/window_port_mus.h index 318ea8fc5bf..8228ff89d3c 100644 --- a/chromium/ui/aura/mus/window_port_mus.h +++ b/chromium/ui/aura/mus/window_port_mus.h @@ -99,10 +99,7 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus { scoped_refptr<viz::ContextProvider> context_provider, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager); - // WindowPort: - // Returns either the FrameSinkId set by window server or its server_id with - // the client id part 0. - viz::FrameSinkId GetFrameSinkId() const override; + viz::FrameSinkId GenerateFrameSinkIdFromServerId() const; private: friend class WindowPortMusTest; @@ -157,7 +154,7 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus { // Contains data needed to identify a change from the server. struct ServerChangeData { // Applies to ADD, ADD_TRANSIENT, REMOVE, REMOVE_TRANSIENT, and REORDER. - Id child_id; + ui::Id child_id; // Applies to BOUNDS. This should be in dip. gfx::Rect bounds_in_dip; // Applies to VISIBLE. @@ -275,11 +272,8 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus { int64_t old_value, std::unique_ptr<ui::PropertyData> data) override; std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override; - viz::SurfaceId GetSurfaceId() const override; void AllocateLocalSurfaceId() override; const viz::LocalSurfaceId& GetLocalSurfaceId() override; - void OnWindowAddedToRootWindow() override; - void OnWillRemoveWindowFromRootWindow() override; void OnEventTargetingPolicyChanged() override; bool ShouldRestackTransientChildren() override; @@ -314,7 +308,6 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus { // for a local aura::Window, we need keep a weak ptr of it, so we can update // the local surface id when necessary. base::WeakPtr<cc::LayerTreeFrameSink> local_layer_tree_frame_sink_; - bool is_frame_sink_id_added_to_compositor_ = false; base::WeakPtrFactory<WindowPortMus> weak_ptr_factory_; diff --git a/chromium/ui/aura/mus/window_port_mus_unittest.cc b/chromium/ui/aura/mus/window_port_mus_unittest.cc index 107d663e87c..8425624d63c 100644 --- a/chromium/ui/aura/mus/window_port_mus_unittest.cc +++ b/chromium/ui/aura/mus/window_port_mus_unittest.cc @@ -7,9 +7,10 @@ #include "components/viz/client/client_layer_tree_frame_sink.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/local/layer_tree_frame_sink_local.h" +#include "ui/aura/mus/client_surface_embedder.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/window.h" -#include "ui/base/ui_base_switches_util.h" +#include "ui/base/ui_base_features.h" namespace aura { @@ -34,7 +35,7 @@ TEST_F(WindowPortMusTest, LayerTreeFrameSinkGetsCorrectLocalSurfaceId) { window.SetBounds(gfx::Rect(300, 300)); // Notify the window that it will embed an external client, so that it // correctly generates LocalSurfaceId. - window.set_embed_frame_sink_id(viz::FrameSinkId(0, 1)); + window.SetEmbedFrameSinkId(viz::FrameSinkId(0, 1)); viz::LocalSurfaceId local_surface_id = window.GetLocalSurfaceId(); ASSERT_TRUE(local_surface_id.is_valid()); @@ -46,7 +47,7 @@ TEST_F(WindowPortMusTest, LayerTreeFrameSinkGetsCorrectLocalSurfaceId) { auto mus_frame_sink = GetFrameSinkFor(&window); ASSERT_TRUE(mus_frame_sink); auto frame_sink_local_surface_id = - switches::IsMusHostingViz() + base::FeatureList::IsEnabled(features::kMash) ? static_cast<viz::ClientLayerTreeFrameSink*>(mus_frame_sink.get()) ->local_surface_id() : static_cast<LayerTreeFrameSinkLocal*>(mus_frame_sink.get()) @@ -55,4 +56,24 @@ TEST_F(WindowPortMusTest, LayerTreeFrameSinkGetsCorrectLocalSurfaceId) { EXPECT_EQ(frame_sink_local_surface_id, local_surface_id); } +TEST_F(WindowPortMusTest, ClientSurfaceEmbedderUpdatesLayer) { + // If mus is not hosting viz, we don't have ClientSurfaceEmbedder. + if (!base::FeatureList::IsEnabled(features::kMash)) + return; + + Window window(nullptr); + window.Init(ui::LAYER_NOT_DRAWN); + window.SetBounds(gfx::Rect(300, 300)); + window.SetEmbedFrameSinkId(viz::FrameSinkId(0, 1)); + + // Allocate a new LocalSurfaceId. The ui::Layer should be updated. + window.AllocateLocalSurfaceId(); + + auto* window_mus = WindowPortMus::Get(&window); + viz::LocalSurfaceId local_surface_id = window.GetLocalSurfaceId(); + viz::SurfaceId primary_surface_id = + window_mus->client_surface_embedder()->GetPrimarySurfaceIdForTesting(); + EXPECT_EQ(local_surface_id, primary_surface_id.local_surface_id()); +} + } // namespace aura diff --git a/chromium/ui/aura/mus/window_tree_client.cc b/chromium/ui/aura/mus/window_tree_client.cc index 760d35f4c9d..a75ee126a46 100644 --- a/chromium/ui/aura/mus/window_tree_client.cc +++ b/chromium/ui/aura/mus/window_tree_client.cc @@ -24,6 +24,7 @@ #include "mojo/public/cpp/bindings/map.h" #include "services/service_manager/public/cpp/connector.h" #include "services/ui/common/accelerator_util.h" +#include "services/ui/common/util.h" #include "services/ui/public/cpp/gpu/gpu.h" #include "services/ui/public/cpp/property_type_converters.h" #include "services/ui/public/interfaces/constants.mojom.h" @@ -57,6 +58,7 @@ #include "ui/aura/window_port_for_shutdown.h" #include "ui/aura/window_tracker.h" #include "ui/base/layout.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches_util.h" #include "ui/base/ui_base_types.h" #include "ui/display/screen.h" @@ -69,10 +71,6 @@ namespace aura { namespace { -inline uint16_t HiWord(uint32_t id) { - return static_cast<uint16_t>((id >> 16) & 0xFFFF); -} - struct WindowPortPropertyDataMus : public ui::PropertyData { std::string transport_name; std::unique_ptr<std::vector<uint8_t>> transport_value; @@ -166,24 +164,13 @@ std::unique_ptr<ui::Event> MapEvent(const ui::Event& event) { return ui::Event::Clone(event); } -// Set the |target| to be the target window of this |event| and send it to -// the EventSink. -void DispatchEventToTarget(ui::Event* event, WindowMus* target) { - ui::Event::DispatcherApi dispatch_helper(event); - // Ignore the target for key events. They need to go to the focused window, - // which may have changed by the time we process the event. - if (!event->IsKeyEvent()) - dispatch_helper.set_target(target->GetWindow()); - GetWindowTreeHostMus(target)->SendEventToSink(event); -} - // Use for acks from mus that are expected to always succeed and if they don't // a crash is triggered. void OnAckMustSucceed(const base::Location& from_here, bool success) { CHECK(success) << "Context: " << from_here.ToString(); } -Id GetServerIdForWindow(Window* window) { +ui::Id GetServerIdForWindow(Window* window) { return window ? WindowMus::Get(window)->server_id() : kInvalidServerId; } @@ -225,7 +212,7 @@ WindowTreeClient::WindowTreeClient( io_task_runner = io_thread_->task_runner(); } - if (switches::IsMusHostingViz()) { + if (base::FeatureList::IsEnabled(features::kMash)) { gpu_ = ui::Gpu::Create(connector, ui::mojom::kServiceName, io_task_runner); compositor_context_factory_ = @@ -402,7 +389,7 @@ void WindowTreeClient::ScheduleEmbed( } void WindowTreeClient::AttachCompositorFrameSink( - Id window_id, + ui::Id window_id, viz::mojom::CompositorFrameSinkRequest compositor_frame_sink, viz::mojom::CompositorFrameSinkClientPtr client) { DCHECK(tree_); @@ -413,9 +400,14 @@ void WindowTreeClient::AttachCompositorFrameSink( void WindowTreeClient::RegisterWindowMus(WindowMus* window) { DCHECK(windows_.find(window->server_id()) == windows_.end()); windows_[window->server_id()] = window; + if (window->GetWindow()) { + auto* port = WindowPortMus::Get(window->GetWindow()); + window->GetWindow()->set_frame_sink_id( + port->GenerateFrameSinkIdFromServerId()); + } } -WindowMus* WindowTreeClient::GetWindowByServerId(Id id) { +WindowMus* WindowTreeClient::GetWindowByServerId(ui::Id id) { IdToWindowMap::const_iterator it = windows_.find(id); return it != windows_.end() ? it->second : nullptr; } @@ -606,7 +598,8 @@ std::unique_ptr<WindowTreeHostMus> WindowTreeClient::CreateWindowTreeHost( if (window_manager_delegate_ && (window_mus_type == WindowMusType::EMBED || window_mus_type == WindowMusType::DISPLAY_AUTOMATICALLY_CREATED)) { - init_params.uses_real_accelerated_widget = !::switches::IsMusHostingViz(); + init_params.uses_real_accelerated_widget = + !::base::FeatureList::IsEnabled(features::kMash); } std::unique_ptr<WindowTreeHostMus> window_tree_host = std::make_unique<WindowTreeHostMus>(std::move(init_params)); @@ -712,7 +705,7 @@ void WindowTreeClient::OnEmbedImpl( ui::mojom::WindowTree* window_tree, ui::mojom::WindowDataPtr root_data, int64_t display_id, - Id focused_window_id, + ui::Id focused_window_id, bool drawn, const base::Optional<viz::LocalSurfaceId>& local_surface_id) { WindowTreeConnectionEstablished(window_tree); @@ -886,8 +879,9 @@ void WindowTreeClient::OnWindowMusCreated(WindowMus* window) { window_manager_client_->SetDisplayRoot( display, display_init_params->viewport_metrics.Clone(), display_init_params->is_primary_display, window->server_id(), - switches::IsMusHostingViz() ? display_init_params->mirrors - : std::vector<display::Display>(), + base::FeatureList::IsEnabled(features::kMash) + ? display_init_params->mirrors + : std::vector<display::Display>(), base::Bind(&OnAckMustSucceed, FROM_HERE)); } } @@ -1101,7 +1095,7 @@ std::set<Window*> WindowTreeClient::GetRoots() { bool WindowTreeClient::WasCreatedByThisClient(const WindowMus* window) const { // Windows created via CreateTopLevelWindow() are not owned by us, but don't // have high-word set. const_cast is required by set. - return !HiWord(window->server_id()) && + return !ui::ClientIdFromTransportId(window->server_id()) && roots_.count(const_cast<WindowMus*>(window)) == 0; } @@ -1163,7 +1157,7 @@ void WindowTreeClient::OnEmbed( ui::mojom::WindowDataPtr root_data, ui::mojom::WindowTreePtr tree, int64_t display_id, - Id focused_window_id, + ui::Id focused_window_id, bool drawn, const base::Optional<viz::LocalSurfaceId>& local_surface_id) { DCHECK(!tree_ptr_); @@ -1181,13 +1175,13 @@ void WindowTreeClient::OnEmbed( focused_window_id, drawn, local_surface_id); } -void WindowTreeClient::OnEmbeddedAppDisconnected(Id window_id) { +void WindowTreeClient::OnEmbeddedAppDisconnected(ui::Id window_id) { WindowMus* window = GetWindowByServerId(window_id); if (window) window->NotifyEmbeddedAppDisconnected(); } -void WindowTreeClient::OnUnembed(Id window_id) { +void WindowTreeClient::OnUnembed(ui::Id window_id) { WindowMus* window = GetWindowByServerId(window_id); if (!window) return; @@ -1196,8 +1190,8 @@ void WindowTreeClient::OnUnembed(Id window_id) { delete window; } -void WindowTreeClient::OnCaptureChanged(Id new_capture_window_id, - Id old_capture_window_id) { +void WindowTreeClient::OnCaptureChanged(ui::Id new_capture_window_id, + ui::Id old_capture_window_id) { WindowMus* new_capture_window = GetWindowByServerId(new_capture_window_id); WindowMus* lost_capture_window = GetWindowByServerId(old_capture_window_id); if (!new_capture_window && !lost_capture_window) @@ -1212,8 +1206,10 @@ void WindowTreeClient::OnCaptureChanged(Id new_capture_window_id, } void WindowTreeClient::OnFrameSinkIdAllocated( - Id window_id, + ui::Id window_id, const viz::FrameSinkId& frame_sink_id) { + if (!base::FeatureList::IsEnabled(features::kMash)) + return; WindowMus* window = GetWindowByServerId(window_id); if (!window) return; @@ -1295,7 +1291,7 @@ void WindowTreeClient::OnTopLevelCreated( } void WindowTreeClient::OnWindowBoundsChanged( - Id window_id, + ui::Id window_id, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds, const base::Optional<viz::LocalSurfaceId>& local_surface_id) { @@ -1311,7 +1307,7 @@ void WindowTreeClient::OnWindowBoundsChanged( } void WindowTreeClient::OnWindowTransformChanged( - Id window_id, + ui::Id window_id, const gfx::Transform& old_transform, const gfx::Transform& new_transform) { WindowMus* window = GetWindowByServerId(window_id); @@ -1326,7 +1322,7 @@ void WindowTreeClient::OnWindowTransformChanged( } void WindowTreeClient::OnClientAreaChanged( - uint32_t window_id, + ui::Id window_id, const gfx::Insets& new_client_area, const std::vector<gfx::Rect>& new_additional_client_areas) { WindowMus* window = GetWindowByServerId(window_id); @@ -1345,8 +1341,8 @@ void WindowTreeClient::OnClientAreaChanged( new_additional_client_areas_in_dip); } -void WindowTreeClient::OnTransientWindowAdded(uint32_t window_id, - uint32_t transient_window_id) { +void WindowTreeClient::OnTransientWindowAdded(ui::Id window_id, + ui::Id transient_window_id) { WindowMus* window = GetWindowByServerId(window_id); WindowMus* transient_window = GetWindowByServerId(transient_window_id); // window or transient_window or both may be null if a local delete occurs @@ -1355,8 +1351,8 @@ void WindowTreeClient::OnTransientWindowAdded(uint32_t window_id, window->AddTransientChildFromServer(transient_window); } -void WindowTreeClient::OnTransientWindowRemoved(uint32_t window_id, - uint32_t transient_window_id) { +void WindowTreeClient::OnTransientWindowRemoved(ui::Id window_id, + ui::Id transient_window_id) { WindowMus* window = GetWindowByServerId(window_id); WindowMus* transient_window = GetWindowByServerId(transient_window_id); // window or transient_window or both may be null if a local delete occurs @@ -1366,9 +1362,9 @@ void WindowTreeClient::OnTransientWindowRemoved(uint32_t window_id, } void WindowTreeClient::OnWindowHierarchyChanged( - Id window_id, - Id old_parent_id, - Id new_parent_id, + ui::Id window_id, + ui::Id old_parent_id, + ui::Id new_parent_id, std::vector<ui::mojom::WindowDataPtr> windows) { const bool was_window_known = GetWindowByServerId(window_id) != nullptr; @@ -1388,8 +1384,8 @@ void WindowTreeClient::OnWindowHierarchyChanged( old_parent->RemoveChildFromServer(window); } -void WindowTreeClient::OnWindowReordered(Id window_id, - Id relative_window_id, +void WindowTreeClient::OnWindowReordered(ui::Id window_id, + ui::Id relative_window_id, ui::mojom::OrderDirection direction) { WindowMus* window = GetWindowByServerId(window_id); WindowMus* relative_window = GetWindowByServerId(relative_window_id); @@ -1400,7 +1396,7 @@ void WindowTreeClient::OnWindowReordered(Id window_id, } } -void WindowTreeClient::OnWindowDeleted(Id window_id) { +void WindowTreeClient::OnWindowDeleted(ui::Id window_id) { WindowMus* window = GetWindowByServerId(window_id); if (!window) return; @@ -1418,7 +1414,8 @@ void WindowTreeClient::OnWindowDeleted(Id window_id) { } } -void WindowTreeClient::OnWindowVisibilityChanged(Id window_id, bool visible) { +void WindowTreeClient::OnWindowVisibilityChanged(ui::Id window_id, + bool visible) { WindowMus* window = GetWindowByServerId(window_id); if (!window) return; @@ -1430,7 +1427,7 @@ void WindowTreeClient::OnWindowVisibilityChanged(Id window_id, bool visible) { SetWindowVisibleFromServer(window, visible); } -void WindowTreeClient::OnWindowOpacityChanged(Id window_id, +void WindowTreeClient::OnWindowOpacityChanged(ui::Id window_id, float old_opacity, float new_opacity) { WindowMus* window = GetWindowByServerId(window_id); @@ -1444,7 +1441,7 @@ void WindowTreeClient::OnWindowOpacityChanged(Id window_id, window->SetOpacityFromServer(new_opacity); } -void WindowTreeClient::OnWindowParentDrawnStateChanged(Id window_id, +void WindowTreeClient::OnWindowParentDrawnStateChanged(ui::Id window_id, bool drawn) { // TODO: route to WindowTreeHost. /* @@ -1455,7 +1452,7 @@ void WindowTreeClient::OnWindowParentDrawnStateChanged(Id window_id, } void WindowTreeClient::OnWindowSharedPropertyChanged( - Id window_id, + ui::Id window_id, const std::string& name, const base::Optional<std::vector<uint8_t>>& transport_data) { WindowMus* window = GetWindowByServerId(window_id); @@ -1476,14 +1473,13 @@ void WindowTreeClient::OnWindowSharedPropertyChanged( void WindowTreeClient::OnWindowInputEvent( uint32_t event_id, - Id window_id, + ui::Id window_id, int64_t display_id, - Id display_root_window_id, + ui::Id display_root_window_id, const gfx::PointF& event_location_in_screen_pixel_layout, std::unique_ptr<ui::Event> event, bool matches_pointer_watcher) { DCHECK(event); - WindowMus* window = GetWindowByServerId(window_id); // May be null. if (matches_pointer_watcher && has_pointer_watcher_) { @@ -1549,23 +1545,30 @@ void WindowTreeClient::OnWindowInputEvent( #endif WindowMus* display_root_window = GetWindowByServerId(display_root_window_id); - if (display_root_window && window && event->IsLocatedEvent() && + if (display_root_window && event->IsLocatedEvent() && display::Screen::GetScreen()->GetPrimaryDisplay().id() == display::kUnifiedDisplayId) { - // Dispatch to the root window of the display supplying the event. This - // allows Ash to determine the event position in the unified desktop mode, - // where each physical display mirrors part of a single virtual display. - // This paralells the behavior of unified desktop mode in classic Ash mode. - DispatchEventToTarget(event_to_dispatch, display_root_window); - } else { - DispatchEventToTarget(event_to_dispatch, window); - } + // In Ash's unified desktop mode, each physical display mirrors part of a + // single virtual display. Dispatch events to the root window of the mirror + // display supplying the event, using locations relative to that display. + // Use a null target to ensure events reach the MusUnifiedEventTargeter. + // This paralells the behavior of unified desktop mode in classic Ash. + ui::Event::DispatcherApi(event_to_dispatch).set_target(nullptr); + ui::LocatedEvent* located_event = event_to_dispatch->AsLocatedEvent(); + located_event->set_location_f(located_event->root_location_f()); + window = display_root_window; + } else if (!event->IsKeyEvent()) { + // Set |window| as the target, except for key events. Key events go to the + // focused window, which may have changed by the time we process the event. + ui::Event::DispatcherApi(event_to_dispatch).set_target(window->GetWindow()); + } + GetWindowTreeHostMus(window)->SendEventToSink(event_to_dispatch); ack_handler.set_handled(event_to_dispatch->handled()); } void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event, - uint32_t window_id, + ui::Id window_id, int64_t display_id) { DCHECK(event); DCHECK(event->IsPointerEvent()); @@ -1580,7 +1583,7 @@ void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event, target_window ? target_window->GetWindow() : nullptr); } -void WindowTreeClient::OnWindowFocused(Id focused_window_id) { +void WindowTreeClient::OnWindowFocused(ui::Id focused_window_id) { WindowMus* focused_window = GetWindowByServerId(focused_window_id); InFlightFocusChange new_change(this, focus_synchronizer_.get(), focused_window); @@ -1590,7 +1593,7 @@ void WindowTreeClient::OnWindowFocused(Id focused_window_id) { focus_synchronizer_->SetFocusFromServer(focused_window); } -void WindowTreeClient::OnWindowCursorChanged(Id window_id, +void WindowTreeClient::OnWindowCursorChanged(ui::Id window_id, ui::CursorData cursor) { WindowMus* window = GetWindowByServerId(window_id); if (!window) @@ -1604,7 +1607,7 @@ void WindowTreeClient::OnWindowCursorChanged(Id window_id, } void WindowTreeClient::OnWindowSurfaceChanged( - Id window_id, + ui::Id window_id, const viz::SurfaceInfo& surface_info) { WindowMus* window = GetWindowByServerId(window_id); if (!window) @@ -1623,7 +1626,7 @@ void WindowTreeClient::OnDragDropStart( drag_drop_controller_->OnDragDropStart(mojo::UnorderedMapToMap(mime_data)); } -void WindowTreeClient::OnDragEnter(Id window_id, +void WindowTreeClient::OnDragEnter(ui::Id window_id, uint32_t key_state, const gfx::Point& position, uint32_t effect_bitmask, @@ -1632,7 +1635,7 @@ void WindowTreeClient::OnDragEnter(Id window_id, GetWindowByServerId(window_id), key_state, position, effect_bitmask)); } -void WindowTreeClient::OnDragOver(Id window_id, +void WindowTreeClient::OnDragOver(ui::Id window_id, uint32_t key_state, const gfx::Point& position, uint32_t effect_bitmask, @@ -1641,7 +1644,7 @@ void WindowTreeClient::OnDragOver(Id window_id, GetWindowByServerId(window_id), key_state, position, effect_bitmask)); } -void WindowTreeClient::OnDragLeave(Id window_id) { +void WindowTreeClient::OnDragLeave(ui::Id window_id) { drag_drop_controller_->OnDragLeave(GetWindowByServerId(window_id)); } @@ -1649,7 +1652,7 @@ void WindowTreeClient::OnDragDropDone() { drag_drop_controller_->OnDragDropDone(); } -void WindowTreeClient::OnCompleteDrop(Id window_id, +void WindowTreeClient::OnCompleteDrop(ui::Id window_id, uint32_t key_state, const gfx::Point& position, uint32_t effect_bitmask, @@ -1723,7 +1726,7 @@ void WindowTreeClient::GetWindowManager( this, std::move(internal))); } -void WindowTreeClient::RequestClose(uint32_t window_id) { +void WindowTreeClient::RequestClose(ui::Id window_id) { WindowMus* window = GetWindowByServerId(window_id); if (!window || !IsRoot(window)) return; @@ -1797,7 +1800,7 @@ void WindowTreeClient::WmDisplayModified(const display::Display& display) { } void WindowTreeClient::WmSetBounds(uint32_t change_id, - Id window_id, + ui::Id window_id, const gfx::Rect& transit_bounds_in_pixels) { WindowMus* window = GetWindowByServerId(window_id); if (window) { @@ -1816,7 +1819,7 @@ void WindowTreeClient::WmSetBounds(uint32_t change_id, void WindowTreeClient::WmSetProperty( uint32_t change_id, - Id window_id, + ui::Id window_id, const std::string& name, const base::Optional<std::vector<uint8_t>>& transit_data) { WindowMus* window = GetWindowByServerId(window_id); @@ -1838,13 +1841,13 @@ void WindowTreeClient::WmSetProperty( window_manager_client_->WmResponse(change_id, result); } -void WindowTreeClient::WmSetModalType(Id window_id, ui::ModalType type) { +void WindowTreeClient::WmSetModalType(ui::Id window_id, ui::ModalType type) { WindowMus* window = GetWindowByServerId(window_id); if (window) window_manager_delegate_->OnWmSetModalType(window->GetWindow(), type); } -void WindowTreeClient::WmSetCanFocus(Id window_id, bool can_focus) { +void WindowTreeClient::WmSetCanFocus(ui::Id window_id, bool can_focus) { WindowMus* window = GetWindowByServerId(window_id); if (window) window_manager_delegate_->OnWmSetCanFocus(window->GetWindow(), can_focus); @@ -1873,7 +1876,7 @@ void WindowTreeClient::WmCreateTopLevelWindow( kInvalidServerId); return; } - embedded_windows_[base::checked_cast<ClientSpecificId>( + embedded_windows_[base::checked_cast<ui::ClientSpecificId>( frame_sink_id.client_id())] .insert(window); if (window_manager_client_) { @@ -1883,7 +1886,7 @@ void WindowTreeClient::WmCreateTopLevelWindow( } } -void WindowTreeClient::WmClientJankinessChanged(ClientSpecificId client_id, +void WindowTreeClient::WmClientJankinessChanged(ui::ClientSpecificId client_id, bool janky) { if (window_manager_delegate_) { auto it = embedded_windows_.find(client_id); @@ -1926,7 +1929,7 @@ void WindowTreeClient::WmDestroyDragImage() { } void WindowTreeClient::WmPerformMoveLoop(uint32_t change_id, - Id window_id, + ui::Id window_id, ui::mojom::MoveLoopSource source, const gfx::Point& cursor_location) { if (!window_manager_delegate_ || current_wm_move_loop_change_ != 0) { @@ -1956,7 +1959,7 @@ void WindowTreeClient::WmCancelMoveLoop(uint32_t change_id) { window_manager_delegate_->OnWmCancelMoveLoop(window->GetWindow()); } -void WindowTreeClient::WmDeactivateWindow(Id window_id) { +void WindowTreeClient::WmDeactivateWindow(ui::Id window_id) { if (!window_manager_delegate_) return; @@ -1974,8 +1977,9 @@ void WindowTreeClient::WmDeactivateWindow(Id window_id) { window_manager_delegate_->OnWmDeactivateWindow(window->GetWindow()); } -void WindowTreeClient::WmStackAbove(uint32_t wm_change_id, Id above_id, - Id below_id) { +void WindowTreeClient::WmStackAbove(uint32_t wm_change_id, + ui::Id above_id, + ui::Id below_id) { if (!window_manager_delegate_) return; @@ -2011,7 +2015,7 @@ void WindowTreeClient::WmStackAbove(uint32_t wm_change_id, Id above_id, window_manager_client_->WmResponse(wm_change_id, true); } -void WindowTreeClient::WmStackAtTop(uint32_t wm_change_id, uint32_t window_id) { +void WindowTreeClient::WmStackAtTop(uint32_t wm_change_id, ui::Id window_id) { if (!window_manager_delegate_) return; @@ -2030,7 +2034,7 @@ void WindowTreeClient::WmStackAtTop(uint32_t wm_change_id, uint32_t window_id) { window_manager_client_->WmResponse(wm_change_id, true); } -void WindowTreeClient::WmPerformWmAction(Id window_id, +void WindowTreeClient::WmPerformWmAction(ui::Id window_id, const std::string& action) { if (!window_manager_delegate_) return; @@ -2056,7 +2060,7 @@ void WindowTreeClient::OnCursorTouchVisibleChanged(bool enabled) { window_manager_delegate_->OnCursorTouchVisibleChanged(enabled); } -void WindowTreeClient::OnEventBlockedByModalWindow(Id window_id) { +void WindowTreeClient::OnEventBlockedByModalWindow(ui::Id window_id) { if (!window_manager_delegate_) return; @@ -2162,7 +2166,7 @@ void WindowTreeClient::InjectEvent(const ui::Event& event, int64_t display_id) { // refused. if (event_injector_) { event_injector_->DispatchEvent(display_id, ui::Event::Clone(event), - base::Bind([](bool result) {})); + base::DoNothing()); } } diff --git a/chromium/ui/aura/mus/window_tree_client.h b/chromium/ui/aura/mus/window_tree_client.h index de8395f2627..1a887b9a322 100644 --- a/chromium/ui/aura/mus/window_tree_client.h +++ b/chromium/ui/aura/mus/window_tree_client.h @@ -165,7 +165,7 @@ class AURA_EXPORT WindowTreeClient base::OnceCallback<void(const base::UnguessableToken&)> callback); void AttachCompositorFrameSink( - Id window_id, + ui::Id window_id, viz::mojom::CompositorFrameSinkRequest compositor_frame_sink, viz::mojom::CompositorFrameSinkClientPtr client); @@ -207,14 +207,14 @@ class AURA_EXPORT WindowTreeClient SERVER, }; - using IdToWindowMap = std::map<Id, WindowMus*>; + using IdToWindowMap = std::map<ui::Id, WindowMus*>; // TODO(sky): this assumes change_ids never wrap, which is a bad assumption. using InFlightMap = std::map<uint32_t, std::unique_ptr<InFlightChange>>; void RegisterWindowMus(WindowMus* window); - WindowMus* GetWindowByServerId(Id id); + WindowMus* GetWindowByServerId(ui::Id id); bool IsWindowKnown(aura::Window* window); @@ -296,7 +296,7 @@ class AURA_EXPORT WindowTreeClient void OnEmbedImpl(ui::mojom::WindowTree* window_tree, ui::mojom::WindowDataPtr root_data, int64_t display_id, - Id focused_window_id, + ui::Id focused_window_id, bool drawn, const base::Optional<viz::LocalSurfaceId>& local_surface_id); @@ -361,14 +361,14 @@ class AURA_EXPORT WindowTreeClient ui::mojom::WindowDataPtr root, ui::mojom::WindowTreePtr tree, int64_t display_id, - Id focused_window_id, + ui::Id focused_window_id, bool drawn, const base::Optional<viz::LocalSurfaceId>& local_surface_id) override; - void OnEmbeddedAppDisconnected(Id window_id) override; - void OnUnembed(Id window_id) override; - void OnCaptureChanged(Id new_capture_window_id, - Id old_capture_window_id) override; - void OnFrameSinkIdAllocated(Id window_id, + void OnEmbeddedAppDisconnected(ui::Id window_id) override; + void OnUnembed(ui::Id window_id) override; + void OnCaptureChanged(ui::Id new_capture_window_id, + ui::Id old_capture_window_id) override; + void OnFrameSinkIdAllocated(ui::Id window_id, const viz::FrameSinkId& frame_sink_id) override; void OnTopLevelCreated( uint32_t change_id, @@ -377,79 +377,79 @@ class AURA_EXPORT WindowTreeClient bool drawn, const base::Optional<viz::LocalSurfaceId>& local_surface_id) override; void OnWindowBoundsChanged( - Id window_id, + ui::Id window_id, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds, const base::Optional<viz::LocalSurfaceId>& local_surface_id) override; - void OnWindowTransformChanged(Id window_id, + void OnWindowTransformChanged(ui::Id window_id, const gfx::Transform& old_transform, const gfx::Transform& new_transform) override; void OnClientAreaChanged( - uint32_t window_id, + ui::Id window_id, const gfx::Insets& new_client_area, const std::vector<gfx::Rect>& new_additional_client_areas) override; - void OnTransientWindowAdded(uint32_t window_id, - uint32_t transient_window_id) override; - void OnTransientWindowRemoved(uint32_t window_id, - uint32_t transient_window_id) override; + void OnTransientWindowAdded(ui::Id window_id, + ui::Id transient_window_id) override; + void OnTransientWindowRemoved(ui::Id window_id, + ui::Id transient_window_id) override; void OnWindowHierarchyChanged( - Id window_id, - Id old_parent_id, - Id new_parent_id, + ui::Id window_id, + ui::Id old_parent_id, + ui::Id new_parent_id, std::vector<ui::mojom::WindowDataPtr> windows) override; - void OnWindowReordered(Id window_id, - Id relative_window_id, + void OnWindowReordered(ui::Id window_id, + ui::Id relative_window_id, ui::mojom::OrderDirection direction) override; - void OnWindowDeleted(Id window_id) override; - void OnWindowVisibilityChanged(Id window_id, bool visible) override; - void OnWindowOpacityChanged(Id window_id, + void OnWindowDeleted(ui::Id window_id) override; + void OnWindowVisibilityChanged(ui::Id window_id, bool visible) override; + void OnWindowOpacityChanged(ui::Id window_id, float old_opacity, float new_opacity) override; - void OnWindowParentDrawnStateChanged(Id window_id, bool drawn) override; + void OnWindowParentDrawnStateChanged(ui::Id window_id, bool drawn) override; void OnWindowSharedPropertyChanged( - Id window_id, + ui::Id window_id, const std::string& name, const base::Optional<std::vector<uint8_t>>& transport_data) override; void OnWindowInputEvent( uint32_t event_id, - Id window_id, + ui::Id window_id, int64_t display_id, - Id display_root_window_id, + ui::Id display_root_window_id, const gfx::PointF& event_location_in_screen_pixel_layout, std::unique_ptr<ui::Event> event, bool matches_pointer_watcher) override; void OnPointerEventObserved(std::unique_ptr<ui::Event> event, - uint32_t window_id, + ui::Id window_id, int64_t display_id) override; - void OnWindowFocused(Id focused_window_id) override; - void OnWindowCursorChanged(Id window_id, ui::CursorData cursor) override; - void OnWindowSurfaceChanged(Id window_id, + void OnWindowFocused(ui::Id focused_window_id) override; + void OnWindowCursorChanged(ui::Id window_id, ui::CursorData cursor) override; + void OnWindowSurfaceChanged(ui::Id window_id, const viz::SurfaceInfo& surface_info) override; void OnDragDropStart( const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data) override; - void OnDragEnter(Id window_id, + void OnDragEnter(ui::Id window_id, uint32_t event_flags, const gfx::Point& position, uint32_t effect_bitmask, const OnDragEnterCallback& callback) override; - void OnDragOver(Id window_id, + void OnDragOver(ui::Id window_id, uint32_t event_flags, const gfx::Point& position, uint32_t effect_bitmask, const OnDragOverCallback& callback) override; - void OnDragLeave(Id window_id) override; - void OnCompleteDrop(Id window_id, + void OnDragLeave(ui::Id window_id) override; + void OnCompleteDrop(ui::Id window_id, uint32_t event_flags, const gfx::Point& position, uint32_t effect_bitmask, const OnCompleteDropCallback& callback) override; - void OnPerformDragDropCompleted(uint32_t window, + void OnPerformDragDropCompleted(uint32_t change_id, bool success, uint32_t action_taken) override; void OnDragDropDone() override; void OnChangeCompleted(uint32_t change_id, bool success) override; - void RequestClose(uint32_t window_id) override; + void RequestClose(ui::Id window_id) override; void SetBlockingContainers( const std::vector<BlockingContainers>& all_blocking_containers) override; void GetWindowManager( @@ -468,21 +468,21 @@ class AURA_EXPORT WindowTreeClient void WmDisplayRemoved(int64_t display_id) override; void WmDisplayModified(const display::Display& display) override; void WmSetBounds(uint32_t change_id, - Id window_id, + ui::Id window_id, const gfx::Rect& transit_bounds_in_pixels) override; void WmSetProperty( uint32_t change_id, - Id window_id, + ui::Id window_id, const std::string& name, const base::Optional<std::vector<uint8_t>>& transit_data) override; - void WmSetModalType(Id window_id, ui::ModalType type) override; - void WmSetCanFocus(Id window_id, bool can_focus) override; + void WmSetModalType(ui::Id window_id, ui::ModalType type) override; + void WmSetCanFocus(ui::Id window_id, bool can_focus) override; void WmCreateTopLevelWindow( uint32_t change_id, const viz::FrameSinkId& frame_sink_id, const std::unordered_map<std::string, std::vector<uint8_t>>& transport_properties) override; - void WmClientJankinessChanged(ClientSpecificId client_id, + void WmClientJankinessChanged(ui::ClientSpecificId client_id, bool janky) override; void WmBuildDragImage(const gfx::Point& screen_location, const SkBitmap& drag_image, @@ -492,19 +492,21 @@ class AURA_EXPORT WindowTreeClient const WmMoveDragImageCallback& callback) override; void WmDestroyDragImage() override; void WmPerformMoveLoop(uint32_t change_id, - Id window_id, + ui::Id window_id, ui::mojom::MoveLoopSource source, const gfx::Point& cursor_location) override; - void WmCancelMoveLoop(uint32_t window_id) override; - void WmDeactivateWindow(Id window_id) override; - void WmStackAbove(uint32_t change_id, Id above_id, Id below_id) override; - void WmStackAtTop(uint32_t change_id, uint32_t window_id) override; - void WmPerformWmAction(Id window_id, const std::string& action) override; + void WmCancelMoveLoop(uint32_t change_id) override; + void WmDeactivateWindow(ui::Id window_id) override; + void WmStackAbove(uint32_t change_id, + ui::Id above_id, + ui::Id below_id) override; + void WmStackAtTop(uint32_t change_id, ui::Id window_id) override; + void WmPerformWmAction(ui::Id window_id, const std::string& action) override; void OnAccelerator(uint32_t ack_id, uint32_t accelerator_id, std::unique_ptr<ui::Event> event) override; void OnCursorTouchVisibleChanged(bool enabled) override; - void OnEventBlockedByModalWindow(Id window_id) override; + void OnEventBlockedByModalWindow(ui::Id window_id) override; // Overridden from WindowManagerClient: void SetFrameDecorationValues( @@ -602,7 +604,7 @@ class AURA_EXPORT WindowTreeClient service_manager::Connector* connector_; // Id assigned to the next window created. - ClientSpecificId next_window_id_; + ui::ClientSpecificId next_window_id_; // Id used for the next change id supplied to the server. uint32_t next_change_id_; @@ -615,7 +617,7 @@ class AURA_EXPORT WindowTreeClient std::set<WindowMus*> roots_; IdToWindowMap windows_; - std::map<ClientSpecificId, std::set<Window*>> embedded_windows_; + std::map<ui::ClientSpecificId, std::set<Window*>> embedded_windows_; std::unique_ptr<CaptureSynchronizer> capture_synchronizer_; @@ -660,7 +662,7 @@ class AURA_EXPORT WindowTreeClient // The current change id for the window manager. uint32_t current_wm_move_loop_change_ = 0u; - Id current_wm_move_loop_window_id_ = 0u; + ui::Id current_wm_move_loop_window_id_ = 0u; std::unique_ptr<DragDropControllerMus> drag_drop_controller_; diff --git a/chromium/ui/aura/mus/window_tree_client_delegate.h b/chromium/ui/aura/mus/window_tree_client_delegate.h index e76d2efbac0..2481d0e0fdf 100644 --- a/chromium/ui/aura/mus/window_tree_client_delegate.h +++ b/chromium/ui/aura/mus/window_tree_client_delegate.h @@ -8,7 +8,7 @@ #include <memory> #include <string> -#include "services/service_manager/public/interfaces/interface_provider.mojom.h" +#include "services/service_manager/public/mojom/interface_provider.mojom.h" #include "services/ui/public/interfaces/window_tree.mojom.h" #include "ui/aura/aura_export.h" diff --git a/chromium/ui/aura/mus/window_tree_client_unittest.cc b/chromium/ui/aura/mus/window_tree_client_unittest.cc index 07e385325c5..1ed6c0c3428 100644 --- a/chromium/ui/aura/mus/window_tree_client_unittest.cc +++ b/chromium/ui/aura/mus/window_tree_client_unittest.cc @@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "cc/base/switches.h" #include "components/viz/common/surfaces/surface_info.h" @@ -44,6 +45,7 @@ #include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host_observer.h" #include "ui/base/class_property.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches.h" #include "ui/compositor/compositor.h" #include "ui/display/display.h" @@ -68,13 +70,13 @@ const char kTestPropertyServerKey1[] = "test-property-server1"; const char kTestPropertyServerKey2[] = "test-property-server2"; const char kTestPropertyServerKey3[] = "test-property-server3"; -Id server_id(Window* window) { +ui::Id server_id(Window* window) { return window ? WindowMus::Get(window)->server_id() : 0; } std::unique_ptr<Window> CreateWindowUsingId( WindowTreeClient* window_tree_client, - Id server_id, + ui::Id server_id, Window* parent = nullptr) { ui::mojom::WindowData window_data; window_data.window_id = server_id; @@ -194,9 +196,7 @@ class WindowTreeClientWmTestSurfaceSync // WindowTreeClientWmTest: void SetUp() override { - base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMus); - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kMusHostingViz); + feature_list_.InitAndEnableFeature(features::kMash); if (GetParam()) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( switches::kForceDeviceScaleFactor, "2"); @@ -205,6 +205,8 @@ class WindowTreeClientWmTestSurfaceSync } private: + base::test::ScopedFeatureList feature_list_; + DISALLOW_COPY_AND_ASSIGN(WindowTreeClientWmTestSurfaceSync); }; @@ -485,7 +487,7 @@ TEST_P(WindowTreeClientWmTestSurfaceSync, SetBoundsLocalSurfaceIdChanges) { // Verifies a new window from the server doesn't result in attempting to add // the window back to the server. TEST_F(WindowTreeClientWmTest, AddFromServerDoesntAddAgain) { - const Id child_window_id = server_id(root_window()) + 11; + const ui::Id child_window_id = server_id(root_window()) + 11; ui::mojom::WindowDataPtr data = ui::mojom::WindowData::New(); data->parent_id = server_id(root_window()); data->window_id = child_window_id; @@ -527,7 +529,7 @@ TEST_F(WindowTreeClientWmTest, ReparentFromServerDoesntAddAgain) { TEST_F(WindowTreeClientWmTest, OnWindowHierarchyChangedWithProperties) { RegisterTestProperties(GetPropertyConverter()); window_tree()->AckAllChanges(); - const Id child_window_id = server_id(root_window()) + 11; + const ui::Id child_window_id = server_id(root_window()) + 11; ui::mojom::WindowDataPtr data = ui::mojom::WindowData::New(); const uint8_t server_test_property1_value = 91; data->properties[kTestPropertyServerKey1] = @@ -535,6 +537,9 @@ TEST_F(WindowTreeClientWmTest, OnWindowHierarchyChangedWithProperties) { data->properties[ui::mojom::WindowManager::kWindowType_InitProperty] = mojo::ConvertTo<std::vector<uint8_t>>( static_cast<int32_t>(ui::mojom::WindowType::BUBBLE)); + constexpr int kWindowCornerRadiusValue = 6; + data->properties[ui::mojom::WindowManager::kWindowCornerRadius_Property] = + ConvertToPropertyTransportValue(kWindowCornerRadiusValue); data->parent_id = server_id(root_window()); data->window_id = child_window_id; data->bounds = gfx::Rect(1, 2, 3, 4); @@ -549,6 +554,8 @@ TEST_F(WindowTreeClientWmTest, OnWindowHierarchyChangedWithProperties) { Window* child = root_window()->children()[0]; EXPECT_FALSE(child->TargetVisibility()); EXPECT_EQ(server_test_property1_value, child->GetProperty(kTestPropertyKey1)); + EXPECT_EQ(kWindowCornerRadiusValue, + child->GetProperty(client::kWindowCornerRadiusKey)); EXPECT_EQ(child->type(), client::WINDOW_TYPE_POPUP); EXPECT_EQ(ui::mojom::WindowType::BUBBLE, child->GetProperty(client::kWindowTypeKey)); @@ -1009,7 +1016,7 @@ TEST_F(WindowTreeClientClientTest, InputEventBasic) { new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location_in_child, gfx::Point(), ui::EventTimeForNow(), ui::EF_NONE, 0)); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child), window_tree_host.display_id(), Id(), + event_id, server_id(&child), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location_in_child), ui::Event::Clone(*ui_event.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); @@ -1045,7 +1052,7 @@ TEST_F(WindowTreeClientClientTest, InputEventPointerEvent) { ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0), base::TimeTicks()); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child), window_tree_host.display_id(), Id(), + event_id, server_id(&child), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(pointer_event), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, @@ -1081,7 +1088,7 @@ TEST_F(WindowTreeClientClientTest, InputEventPen) { ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 0), ui::EventTimeForNow()); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child), window_tree_host.display_id(), Id(), + event_id, server_id(&child), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(pointer_event), 0); // Pen event was handled. @@ -1129,7 +1136,7 @@ TEST_F(WindowTreeClientClientTest, InputEventFindTargetAndConversion) { new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location, gfx::Point(), ui::EventTimeForNow(), ui::EF_NONE, 0)); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child1), window_tree_host.display_id(), Id(), + event_id, server_id(&child1), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(*ui_event.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, @@ -1150,7 +1157,7 @@ TEST_F(WindowTreeClientClientTest, InputEventFindTargetAndConversion) { new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location, gfx::Point(), ui::EventTimeForNow(), ui::EF_NONE, 0)); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child1), window_tree_host.display_id(), Id(), + event_id, server_id(&child1), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(*ui_event1.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, @@ -1198,7 +1205,7 @@ TEST_F(WindowTreeClientClientTest, InputEventCustomWindowTargeter) { new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location, gfx::Point(), ui::EventTimeForNow(), ui::EF_NONE, 0)); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child1), window_tree_host.display_id(), Id(), + event_id, server_id(&child1), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(*ui_event.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, @@ -1215,7 +1222,7 @@ TEST_F(WindowTreeClientClientTest, InputEventCustomWindowTargeter) { window_delegate1.set_event_id(event_id); window_delegate2.set_event_id(event_id); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child2), window_tree_host.display_id(), Id(), + event_id, server_id(&child2), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(*ui_event.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, @@ -1268,8 +1275,9 @@ TEST_F(WindowTreeClientClientTest, InputEventCaptureWindow) { new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location, root_location, ui::EventTimeForNow(), ui::EF_NONE, 0)); window_tree_client()->OnWindowInputEvent( - event_id, server_id(child1.get()), window_tree_host->display_id(), Id(), - gfx::PointF(root_location), ui::Event::Clone(*ui_event.get()), 0); + event_id, server_id(child1.get()), window_tree_host->display_id(), + ui::Id(), gfx::PointF(root_location), ui::Event::Clone(*ui_event.get()), + 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, window_tree()->GetEventResult(event_id)); @@ -1291,8 +1299,9 @@ TEST_F(WindowTreeClientClientTest, InputEventCaptureWindow) { window_delegate1->set_event_id(event_id); window_delegate2->set_event_id(event_id); window_tree_client()->OnWindowInputEvent( - event_id, server_id(child1.get()), window_tree_host->display_id(), Id(), - gfx::PointF(root_location), ui::Event::Clone(*ui_event.get()), 0); + event_id, server_id(child1.get()), window_tree_host->display_id(), + ui::Id(), gfx::PointF(root_location), ui::Event::Clone(*ui_event.get()), + 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, window_tree()->GetEventResult(event_id)); @@ -1338,7 +1347,7 @@ TEST_F(WindowTreeClientClientTest, InputEventRootWindow) { new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location_in_child, gfx::Point(), ui::EventTimeForNow(), ui::EF_NONE, 0)); window_tree_client()->OnWindowInputEvent( - event_id, server_id(top_level), window_tree_host.display_id(), Id(), + event_id, server_id(top_level), window_tree_host.display_id(), ui::Id(), gfx::PointF(), ui::Event::Clone(*ui_event.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); @@ -1382,14 +1391,14 @@ TEST_F(WindowTreeClientClientTest, InputMouseEventNoWindow) { ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0), ui::EventTimeForNow()); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child), window_tree_host.display_id(), Id(), + event_id, server_id(&child), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(pointer_event_down), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, window_tree()->GetEventResult(event_id)); EXPECT_EQ(1, window_delegate.press_count()); EXPECT_TRUE(env->IsMouseButtonDown()); - EXPECT_EQ(1024, env->mouse_button_flags()); // ui::EF_LEFT_MOUSE_BUTTON + EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, env->mouse_button_flags()); EXPECT_EQ(event_location, env->last_mouse_location()); window_delegate.reset(); @@ -1402,7 +1411,7 @@ TEST_F(WindowTreeClientClientTest, InputMouseEventNoWindow) { ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0), ui::EventTimeForNow()); window_tree_client()->OnWindowInputEvent( - event_id, kInvalidServerId, window_tree_host.display_id(), Id(), + event_id, kInvalidServerId, window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location), ui::Event::Clone(pointer_event_up), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); // WindowTreeClient::OnWindowInputEvent cannot find a target window with @@ -1445,7 +1454,7 @@ TEST_F(WindowTreeClientClientTest, InputTouchEventNoWindow) { ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0), ui::EventTimeForNow()); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child), window_tree_host.display_id(), Id(), + event_id, server_id(&child), window_tree_host.display_id(), ui::Id(), gfx::PointF(), ui::Event::Clone(pointer_event_down), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); EXPECT_EQ(ui::mojom::EventResult::HANDLED, @@ -1461,7 +1470,7 @@ TEST_F(WindowTreeClientClientTest, InputTouchEventNoWindow) { ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0), ui::EventTimeForNow()); window_tree_client()->OnWindowInputEvent( - event_id, kInvalidServerId, window_tree_host.display_id(), Id(), + event_id, kInvalidServerId, window_tree_host.display_id(), ui::Id(), gfx::PointF(), ui::Event::Clone(pointer_event_up), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); // WindowTreeClient::OnWindowInputEvent cannot find a target window with @@ -1557,7 +1566,7 @@ TEST_F(WindowTreeClientPointerObserverTest, ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 0, ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1), base::TimeTicks::Now())); - window_tree_client()->OnWindowInputEvent(1, server_id(top_level), 0, Id(), + window_tree_client()->OnWindowInputEvent(1, server_id(top_level), 0, ui::Id(), gfx::PointF(), std::move(pointer_event_down), true); @@ -2483,7 +2492,7 @@ TEST_F(WindowTreeClientWmTest, OnWindowHierarchyChangedWithExistingWindow) { Window* window2 = new Window(nullptr); window2->Init(ui::LAYER_NOT_DRAWN); window_tree()->AckAllChanges(); - const Id server_window_id = server_id(root_window()) + 11; + const ui::Id server_window_id = server_id(root_window()) + 11; ui::mojom::WindowDataPtr data1 = ui::mojom::WindowData::New(); ui::mojom::WindowDataPtr data2 = ui::mojom::WindowData::New(); ui::mojom::WindowDataPtr data3 = ui::mojom::WindowData::New(); @@ -2602,7 +2611,7 @@ TEST_F(WindowTreeClientWmTest, FocusInDifferentDisplayThanEvent) { std::unique_ptr<ui::KeyEvent> key_event = std::make_unique<ui::KeyEvent>( ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, ui::EF_NONE); window_tree_client()->OnWindowInputEvent(1, server_id(&child2), kDisplayId2, - Id(), gfx::PointF(), + ui::Id(), gfx::PointF(), std::move(key_event), false); } @@ -2820,7 +2829,7 @@ TEST_F(WindowTreeClientClientTestHighDPI, InputEventsInDip) { ui::ET_MOUSE_MOVED, event_location_in_pixels, event_location_in_pixels, ui::EventTimeForNow(), ui::EF_NONE, 0)); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child1), window_tree_host.display_id(), Id(), + event_id, server_id(&child1), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location_in_pixels), ui::Event::Clone(*ui_event.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); @@ -2845,7 +2854,7 @@ TEST_F(WindowTreeClientClientTestHighDPI, InputEventsInDip) { window_delegate1.set_event_id(event_id); window_delegate2.set_event_id(event_id); window_tree_client()->OnWindowInputEvent( - event_id, server_id(&child2), window_tree_host.display_id(), Id(), + event_id, server_id(&child2), window_tree_host.display_id(), ui::Id(), gfx::PointF(event_location_in_pixels), ui::Event::Clone(*ui_event.get()), 0); EXPECT_TRUE(window_tree()->WasEventAcked(event_id)); diff --git a/chromium/ui/aura/mus/window_tree_host_mus.cc b/chromium/ui/aura/mus/window_tree_host_mus.cc index a146cfc41b3..3acab45d4e2 100644 --- a/chromium/ui/aura/mus/window_tree_host_mus.cc +++ b/chromium/ui/aura/mus/window_tree_host_mus.cc @@ -15,6 +15,7 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host_observer.h" #include "ui/base/class_property.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches_util.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -60,8 +61,9 @@ WindowTreeHostMus::WindowTreeHostMus(WindowTreeHostMusInitParams init_params) // If window-server is hosting viz, then use the FrameSinkId from the server. // In other cases, let a valid FrameSinkId be selected by // context_factory_private(). - CreateCompositor(switches::IsMusHostingViz() ? window_mus->GetFrameSinkId() - : viz::FrameSinkId()); + CreateCompositor(base::FeatureList::IsEnabled(features::kMash) + ? window_mus->GenerateFrameSinkIdFromServerId() + : viz::FrameSinkId()); if (!init_params.uses_real_accelerated_widget) { gfx::AcceleratedWidget accelerated_widget; // We need accelerated widget numbers to be different for each window and diff --git a/chromium/ui/aura/scoped_keyboard_hook.cc b/chromium/ui/aura/scoped_keyboard_hook.cc new file mode 100644 index 00000000000..96d9d778439 --- /dev/null +++ b/chromium/ui/aura/scoped_keyboard_hook.cc @@ -0,0 +1,24 @@ +// Copyright 2018 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/scoped_keyboard_hook.h" + +#include "base/macros.h" +#include "ui/aura/window_tree_host.h" + +namespace aura { + +ScopedKeyboardHook::ScopedKeyboardHook( + base::WeakPtr<WindowTreeHost> window_tree_host) + : window_tree_host_(window_tree_host) { + DCHECK(window_tree_host_); +} + +ScopedKeyboardHook::~ScopedKeyboardHook() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (window_tree_host_) + window_tree_host_->ReleaseSystemKeyEventCapture(); +} + +} // namespace aura diff --git a/chromium/ui/aura/scoped_keyboard_hook.h b/chromium/ui/aura/scoped_keyboard_hook.h new file mode 100644 index 00000000000..d061544aff2 --- /dev/null +++ b/chromium/ui/aura/scoped_keyboard_hook.h @@ -0,0 +1,35 @@ +// Copyright 2018 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_SCOPED_KEYBOARD_HOOK_H_ +#define UI_AURA_SCOPED_KEYBOARD_HOOK_H_ + +#include "base/memory/weak_ptr.h" +#include "base/threading/thread_checker.h" +#include "ui/aura/aura_export.h" + +namespace aura { + +class WindowTreeHost; + +// Destroying an instance of this class will clean up the KeyboardHook instance +// owned by WindowTreeHost and prevent future system key events from being +// captured. If the KeyboardHook or WindowTreeHost instances were already +// destroyed, then destroying this instance is a noop. +class AURA_EXPORT ScopedKeyboardHook { + public: + explicit ScopedKeyboardHook(base::WeakPtr<WindowTreeHost> weak_ptr); + ~ScopedKeyboardHook(); + + private: + THREAD_CHECKER(thread_checker_); + + base::WeakPtr<WindowTreeHost> window_tree_host_; + + DISALLOW_COPY_AND_ASSIGN(ScopedKeyboardHook); +}; + +} // namespace aura + +#endif // UI_AURA_SCOPED_KEYBOARD_HOOK_H_ diff --git a/chromium/ui/aura/window.cc b/chromium/ui/aura/window.cc index 063a2861247..0f224d897e0 100644 --- a/chromium/ui/aura/window.cc +++ b/chromium/ui/aura/window.cc @@ -32,6 +32,7 @@ #include "ui/aura/env.h" #include "ui/aura/layout_manager.h" #include "ui/aura/local/layer_tree_frame_sink_local.h" +#include "ui/aura/scoped_keyboard_hook.h" #include "ui/aura/window_delegate.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_observer.h" @@ -39,6 +40,7 @@ #include "ui/aura/window_port.h" #include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host.h" +#include "ui/base/ui_base_features.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animator.h" @@ -643,6 +645,19 @@ bool Window::HasCapture() { return capture_client && capture_client->GetCaptureWindow() == this; } +std::unique_ptr<ScopedKeyboardHook> Window::CaptureSystemKeyEvents( + base::Optional<base::flat_set<int>> keys) { + Window* root_window = GetRootWindow(); + if (!root_window) + return nullptr; + + WindowTreeHost* host = root_window->GetHost(); + if (!host) + return nullptr; + + return host->CaptureSystemKeyEvents(std::move(keys)); +} + void Window::SuppressPaint() { layer()->SuppressPaint(); } @@ -779,13 +794,11 @@ void Window::SetVisible(bool visible) { NotifyWindowVisibilityChanged(this, visible); } -void Window::SetOccluded(bool occluded) { - OcclusionState occlusion_state = - occluded ? OcclusionState::OCCLUDED : OcclusionState::NOT_OCCLUDED; +void Window::SetOcclusionState(OcclusionState occlusion_state) { if (occlusion_state != occlusion_state_) { occlusion_state_ = occlusion_state; if (delegate_) - delegate_->OnWindowOcclusionChanged(occluded); + delegate_->OnWindowOcclusionChanged(occlusion_state); } } @@ -943,7 +956,8 @@ void Window::OnStackingChanged() { } void Window::NotifyRemovingFromRootWindow(Window* new_root) { - port_->OnWillRemoveWindowFromRootWindow(); + if (IsEmbeddingClient()) + UnregisterFrameSinkId(); for (WindowObserver& observer : observers_) observer.OnWindowRemovingFromRootWindow(this, new_root); for (Window::Windows::const_iterator it = children_.begin(); @@ -953,7 +967,8 @@ void Window::NotifyRemovingFromRootWindow(Window* new_root) { } void Window::NotifyAddedToRootWindow() { - port_->OnWindowAddedToRootWindow(); + if (IsEmbeddingClient()) + RegisterFrameSinkId(); for (WindowObserver& observer : observers_) observer.OnWindowAddedToRootWindow(this); for (Window::Windows::const_iterator it = children_.begin(); @@ -1032,23 +1047,18 @@ bool Window::NotifyWindowVisibilityChangedDown(aura::Window* target, bool visible) { if (!NotifyWindowVisibilityChangedAtReceiver(target, visible)) return false; // |this| was deleted. - std::set<const Window*> child_already_processed; - bool child_destroyed = false; - do { - child_destroyed = false; - for (Window::Windows::const_iterator it = children_.begin(); - it != children_.end(); ++it) { - if (!child_already_processed.insert(*it).second) - continue; - if (!(*it)->NotifyWindowVisibilityChangedDown(target, visible)) { - // |*it| was deleted, |it| is invalid and |children_| has changed. - // We exit the current for-loop and enter a new one. - child_destroyed = true; - break; - } - } - } while (child_destroyed); - return true; + + WindowTracker this_tracker; + this_tracker.Add(this); + // Copy |children_| in case iterating mutates |children_|, or destroys an + // existing child. + WindowTracker children(children_); + + while (!this_tracker.windows().empty() && !children.windows().empty()) + children.Pop()->NotifyWindowVisibilityChangedDown(target, visible); + + const bool this_still_valid = !this_tracker.windows().empty(); + return this_still_valid; } void Window::NotifyWindowVisibilityChangedUp(aura::Window* target, @@ -1075,11 +1085,15 @@ bool Window::CleanupGestureState() { } std::unique_ptr<cc::LayerTreeFrameSink> Window::CreateLayerTreeFrameSink() { - return port_->CreateLayerTreeFrameSink(); + auto sink = port_->CreateLayerTreeFrameSink(); + DCHECK(frame_sink_id_.is_valid()); + DCHECK(embeds_external_client_); + DCHECK(GetLocalSurfaceId().is_valid()); + return sink; } viz::SurfaceId Window::GetSurfaceId() const { - return port_->GetSurfaceId(); + return viz::SurfaceId(GetFrameSinkId(), port_->GetLocalSurfaceId()); } void Window::AllocateLocalSurfaceId() { @@ -1090,18 +1104,25 @@ const viz::LocalSurfaceId& Window::GetLocalSurfaceId() const { return port_->GetLocalSurfaceId(); } -viz::FrameSinkId Window::GetFrameSinkId() const { +const viz::FrameSinkId& Window::GetFrameSinkId() const { if (IsRootWindow()) { DCHECK(host_); auto* compositor = host_->compositor(); DCHECK(compositor); return compositor->frame_sink_id(); } - return port_->GetFrameSinkId(); + return frame_sink_id_; +} + +void Window::SetEmbedFrameSinkId(const viz::FrameSinkId& frame_sink_id) { + DCHECK(frame_sink_id.is_valid()); + frame_sink_id_ = frame_sink_id; + embeds_external_client_ = true; + RegisterFrameSinkId(); } bool Window::IsEmbeddingClient() const { - return embed_frame_sink_id_.is_valid(); + return embeds_external_client_; } void Window::OnPaintLayer(const ui::PaintContext& context) { @@ -1241,4 +1262,23 @@ void Window::UpdateLayerName() { #endif } +void Window::RegisterFrameSinkId() { + DCHECK(frame_sink_id_.is_valid()); + DCHECK(IsEmbeddingClient()); + if (registered_frame_sink_id_ || disable_frame_sink_id_registration_) + return; + if (auto* compositor = layer()->GetCompositor()) { + compositor->AddFrameSink(frame_sink_id_); + registered_frame_sink_id_ = true; + } +} + +void Window::UnregisterFrameSinkId() { + if (!registered_frame_sink_id_) + return; + registered_frame_sink_id_ = false; + if (auto* compositor = layer()->GetCompositor()) + compositor->RemoveFrameSink(frame_sink_id_); +} + } // namespace aura diff --git a/chromium/ui/aura/window.h b/chromium/ui/aura/window.h index d2ef6774f3c..b6e2dcfb871 100644 --- a/chromium/ui/aura/window.h +++ b/chromium/ui/aura/window.h @@ -14,8 +14,10 @@ #include <vector> #include "base/compiler_specific.h" +#include "base/containers/flat_set.h" #include "base/macros.h" #include "base/observer_list.h" +#include "base/optional.h" #include "base/strings/string16.h" #include "ui/aura/aura_export.h" #include "ui/aura/client/window_types.h" @@ -53,6 +55,7 @@ enum class EventTargetingPolicy; namespace aura { class LayoutManager; +class ScopedKeyboardHook; class WindowDelegate; class WindowObserver; class WindowPort; @@ -88,12 +91,26 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // The window's occlusion state isn't tracked // (WindowOcclusionTracker::Track) or hasn't been computed yet. UNKNOWN, - // The window is occluded, i.e. one of these conditions is true: - // - The window is hidden (Window::IsVisible() is true). - // - The bounds of the window are completely covered by opaque windows. + // The window or one of its descendants IsVisible() [1] and: + // - Its bounds aren't completely covered by fully opaque windows [2], or, + // - Its transform, bounds or opacity is animated. + VISIBLE, + // The window or one of its descendants IsVisible() [1], but they all: + // - Have bounds completely covered by fully opaque windows [2], and, + // - Have no transform, bounds or opacity animation. OCCLUDED, - // The window is not occluded. - NOT_OCCLUDED, + // The window is not IsVisible() [1]. + HIDDEN, + // [1] A window can only be IsVisible() if all its parent are IsVisible(). + // [2] A window is "fully opaque" if: + // - It's visible (IsVisible()). + // - It's not transparent (transparent()). + // - It's transform, bounds and opacity aren't animated. + // - Its combined opacity is 1 (GetCombinedOpacity()). + // - The type of its layer is not ui::LAYER_NOT_DRAWN. + // + // TODO(fdoray): A window that clips its children shouldn't be VISIBLE just + // because it has an animated child. }; typedef std::vector<Window*> Windows; @@ -167,10 +184,10 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // account the visibility of the layer and ancestors, where as this tracks // whether Show() without a Hide() has been invoked. bool TargetVisibility() const { return visible_; } - // Returns the occlusion state of this window. Will be UNKNOWN if the - // occlusion state of this window isn't tracked - // (WindowOcclusionTracker::Track). Will be stale if called within the scope - // of a WindowOcclusionTracker::ScopedPauseOcclusionTracking. + // Returns the occlusion state of this window. Is UNKNOWN if the occlusion + // state of this window isn't tracked (WindowOcclusionTracker::Track) or + // hasn't been computed yet. Is stale if called within the scope of a + // WindowOcclusionTracker::ScopedPauseOcclusionTracking. OcclusionState occlusion_state() const { return occlusion_state_; } // Returns the window's bounds in root window's coordinates. @@ -321,6 +338,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Returns true if this window has capture. bool HasCapture(); + // Requests that |keys| be intercepted at the platform level and routed + // directly to the web content. If |keys| has no value, all keys will be + // intercepted. Returns a ScopedKeyboardHook instance which stops capturing + // system key events when destroyed. + std::unique_ptr<ScopedKeyboardHook> CaptureSystemKeyEvents( + base::Optional<base::flat_set<int>> keys); + // Suppresses painting window content by disgarding damaged rect and ignoring // new paint requests. This is a one way operation and there is no way to // reenable painting. @@ -368,15 +392,18 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Returns the FrameSinkId. In LOCAL mode, this returns a valid FrameSinkId // only if a LayerTreeFrameSink has been created. In MUS mode, this always // return a valid FrameSinkId. - viz::FrameSinkId GetFrameSinkId() const; - - const viz::FrameSinkId& embed_frame_sink_id() const { - return embed_frame_sink_id_; - } - void set_embed_frame_sink_id(const viz::FrameSinkId& embed_frame_sink_id) { - embed_frame_sink_id_ = embed_frame_sink_id; + const viz::FrameSinkId& GetFrameSinkId() const; + + // Use SetEmbedFrameSinkId() when this window is embedding another client. + // See comment for |frame_sink_id_| below for more details. + void SetEmbedFrameSinkId(const viz::FrameSinkId& embed_frame_sink_id); + void set_frame_sink_id(const viz::FrameSinkId& frame_sink_id) { + DCHECK(!embeds_external_client_); + DCHECK(!frame_sink_id_.is_valid()); + frame_sink_id_ = frame_sink_id; } - // Returns whether this window is an embed window. + + // Returns whether this window is embedding another client. bool IsEmbeddingClient() const; protected: @@ -415,7 +442,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate, void SetVisible(bool visible); // Updates the occlusion state of the window. - void SetOccluded(bool occluded); + void SetOcclusionState(OcclusionState occlusion_state); // Schedules a paint for the Window's entire bounds. void SchedulePaint(); @@ -505,6 +532,11 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Updates the layer name based on the window's name and id. void UpdateLayerName(); + void RegisterFrameSinkId(); + void UnregisterFrameSinkId(); + bool registered_frame_sink_id_ = false; + bool disable_frame_sink_id_registration_ = false; + // Window owns its corresponding WindowPort, but the ref is held as a raw // pointer in |port_| so that it can still be accessed during destruction. // This is important as deleting the WindowPort may result in trying to lookup @@ -547,8 +579,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate, int id_; - // Only set when it is embedding another client inside. - viz::FrameSinkId embed_frame_sink_id_; + // The FrameSinkId associated with this window. If this window is embedding + // another client, then this should be set to the FrameSinkId of that client, + // and |embeds_external_client_| is turned on. However, a window can still + // have a valid FrameSinkId without embedding another client, to facilitate + // hit-testing. + viz::FrameSinkId frame_sink_id_; + bool embeds_external_client_ = false; // Whether layer is initialized as non-opaque. Defaults to false. bool transparent_; diff --git a/chromium/ui/aura/window_delegate.h b/chromium/ui/aura/window_delegate.h index a1ec4d98c72..2b24e2eb0ea 100644 --- a/chromium/ui/aura/window_delegate.h +++ b/chromium/ui/aura/window_delegate.h @@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "ui/aura/aura_export.h" +#include "ui/aura/window.h" #include "ui/events/event_constants.h" #include "ui/events/event_handler.h" #include "ui/gfx/native_widget_types.h" @@ -90,9 +91,10 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler { virtual void OnWindowTargetVisibilityChanged(bool visible) = 0; // Called when the occlusion state of the Window changes while tracked (see - // WindowOcclusionTracker::Track). |is_occluded| indicates whether the Window - // is occluded. Impls must not change any aura::Window. - virtual void OnWindowOcclusionChanged(bool is_occluded) {} + // WindowOcclusionTracker::Track). |occlusion_state| is the new occlusion + // state of the Window. + virtual void OnWindowOcclusionChanged( + Window::OcclusionState occlusion_state) {} // Called from Window::HitTest to check if the window has a custom hit test // mask. It works similar to the views counterparts. That is, if the function diff --git a/chromium/ui/aura/window_event_dispatcher.cc b/chromium/ui/aura/window_event_dispatcher.cc index 6fb791a6183..8bfba9421b2 100644 --- a/chromium/ui/aura/window_event_dispatcher.cc +++ b/chromium/ui/aura/window_event_dispatcher.cc @@ -204,15 +204,22 @@ void WindowEventDispatcher::HoldPointerMoves() { void WindowEventDispatcher::ReleasePointerMoves() { --move_hold_count_; DCHECK_GE(move_hold_count_, 0); - if (!move_hold_count_ && held_move_event_) { - // We don't want to call DispatchHeldEvents directly, because this might be - // called from a deep stack while another event, in which case dispatching - // another one may not be safe/expected. Instead we post a task, that we - // may cancel if HoldPointerMoves is called again before it executes. - base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask( - FROM_HERE, base::Bind( - base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), - held_event_factory_.GetWeakPtr())); + if (!move_hold_count_) { + if (held_move_event_) { + // We don't want to call DispatchHeldEvents directly, because this might + // be called from a deep stack while another event, in which case + // dispatching another one may not be safe/expected. Instead we post a + // task, that we may cancel if HoldPointerMoves is called again before it + // executes. + base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask( + FROM_HERE, + base::BindOnce( + base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), + held_event_factory_.GetWeakPtr())); + } else { + if (did_dispatch_held_move_event_callback_) + base::ResetAndReturn(&did_dispatch_held_move_event_callback_).Run(); + } } TRACE_EVENT_ASYNC_END0("ui", "WindowEventDispatcher::HoldPointerMoves", this); } @@ -765,8 +772,11 @@ void WindowEventDispatcher::OnWindowInitialized(Window* window) { // WindowEventDispatcher, private: ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() { - if (!held_repostable_event_ && !held_move_event_) + if (!held_repostable_event_ && !held_move_event_) { + if (did_dispatch_held_move_event_callback_) + base::ResetAndReturn(&did_dispatch_held_move_event_callback_).Run(); return DispatchDetails(); + } CHECK(!dispatching_held_event_); @@ -798,8 +808,12 @@ ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() { held_move_event_.reset(); } - if (!dispatch_details.dispatcher_destroyed) + if (!dispatch_details.dispatcher_destroyed) { dispatching_held_event_ = nullptr; + if (did_dispatch_held_move_event_callback_) + base::ResetAndReturn(&did_dispatch_held_move_event_callback_).Run(); + } + return dispatch_details; } diff --git a/chromium/ui/aura/window_event_dispatcher.h b/chromium/ui/aura/window_event_dispatcher.h index 4772bd1c962..283866d50b1 100644 --- a/chromium/ui/aura/window_event_dispatcher.h +++ b/chromium/ui/aura/window_event_dispatcher.h @@ -293,6 +293,10 @@ class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor, bool skip_ime_; + // This callback is called when the held move event is dispatched, or when + // pointer moves are released and there is no held move event. + base::OnceClosure did_dispatch_held_move_event_callback_; + // Used to schedule reposting an event. base::WeakPtrFactory<WindowEventDispatcher> repost_event_factory_; diff --git a/chromium/ui/aura/window_event_dispatcher_unittest.cc b/chromium/ui/aura/window_event_dispatcher_unittest.cc index f70d4b415d9..dc9571ef34e 100644 --- a/chromium/ui/aura/window_event_dispatcher_unittest.cc +++ b/chromium/ui/aura/window_event_dispatcher_unittest.cc @@ -35,6 +35,7 @@ #include "ui/aura/window_targeter.h" #include "ui/aura/window_tracker.h" #include "ui/base/hit_test.h" +#include "ui/base/ui_base_features.h" #include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_handler.h" @@ -2959,19 +2960,19 @@ INSTANTIATE_TEST_CASE_P(/* no prefix */, WindowEventDispatcherTest, ::testing::Values(test::BackendType::CLASSIC, test::BackendType::MUS, - test::BackendType::MUS_HOSTING_VIZ)); + test::BackendType::MASH)); INSTANTIATE_TEST_CASE_P(/* no prefix */, WindowEventDispatcherTestWithMessageLoop, ::testing::Values(test::BackendType::CLASSIC, test::BackendType::MUS, - test::BackendType::MUS_HOSTING_VIZ)); + test::BackendType::MASH)); INSTANTIATE_TEST_CASE_P(/* no prefix */, WindowEventDispatcherTestInHighDPI, ::testing::Values(test::BackendType::CLASSIC, test::BackendType::MUS, - test::BackendType::MUS_HOSTING_VIZ)); + test::BackendType::MASH)); using WindowEventDispatcherMusTest = test::AuraTestBaseMus; diff --git a/chromium/ui/aura/window_occlusion_tracker.cc b/chromium/ui/aura/window_occlusion_tracker.cc index 80cc8830197..dff18bd85e7 100644 --- a/chromium/ui/aura/window_occlusion_tracker.cc +++ b/chromium/ui/aura/window_occlusion_tracker.cc @@ -4,11 +4,13 @@ #include "ui/aura/window_occlusion_tracker.h" +#include "base/auto_reset.h" #include "base/containers/adapters.h" +#include "base/debug/dump_without_crashing.h" #include "base/stl_util.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRegion.h" -#include "ui/aura/window.h" +#include "ui/aura/window_tracker.h" #include "ui/gfx/geometry/safe_integer_conversions.h" #include "ui/gfx/transform.h" @@ -23,6 +25,10 @@ constexpr ui::LayerAnimationElement::AnimatableProperties ui::LayerAnimationElement::TRANSFORM | ui::LayerAnimationElement::BOUNDS | ui::LayerAnimationElement::OPACITY; +// Maximum number of times that MaybeComputeOcclusion() should have to recompute +// occlusion states before they become stable. +constexpr int kMaxRecomputeOcclusion = 2; + WindowOcclusionTracker* g_tracker = nullptr; int g_num_pause_occlusion_tracking = 0; @@ -80,6 +86,17 @@ SkIRect GetWindowBoundsInRootWindow( return skirect_bounds; } +// Returns true iff the occlusion states in |tracked_windows| match those +// returned by Window::occlusion_state(). +bool OcclusionStatesMatch( + const base::flat_map<Window*, Window::OcclusionState>& tracked_windows) { + for (const auto& tracked_window : tracked_windows) { + if (tracked_window.second != tracked_window.first->occlusion_state()) + return false; + } + return true; +} + } // namespace WindowOcclusionTracker::ScopedPauseOcclusionTracking:: @@ -92,7 +109,7 @@ WindowOcclusionTracker::ScopedPauseOcclusionTracking:: --g_num_pause_occlusion_tracking; DCHECK_GE(g_num_pause_occlusion_tracking, 0); if (g_tracker) - g_tracker->MaybeRecomputeOcclusion(); + g_tracker->MaybeComputeOcclusion(); } void WindowOcclusionTracker::Track(Window* window) { @@ -102,7 +119,8 @@ void WindowOcclusionTracker::Track(Window* window) { if (!g_tracker) g_tracker = new WindowOcclusionTracker(); - auto insert_result = g_tracker->tracked_windows_.insert(window); + auto insert_result = g_tracker->tracked_windows_.insert( + {window, Window::OcclusionState::UNKNOWN}); DCHECK(insert_result.second); if (!window->HasObserver(g_tracker)) window->AddObserver(g_tracker); @@ -114,39 +132,90 @@ WindowOcclusionTracker::WindowOcclusionTracker() = default; WindowOcclusionTracker::~WindowOcclusionTracker() = default; -void WindowOcclusionTracker::MaybeRecomputeOcclusion() { - if (g_num_pause_occlusion_tracking) +void WindowOcclusionTracker::MaybeComputeOcclusion() { + if (g_num_pause_occlusion_tracking || num_times_occlusion_recomputed_ != 0) return; - for (auto& root_window_pair : root_windows_) { - RootWindowState& root_window_state = root_window_pair.second; - if (root_window_state.dirty == true) { - ScopedPauseOcclusionTracking scoped_pause_occlusion_tracking; - root_window_state.dirty = false; - SkRegion occluded_region; - RecomputeOcclusionImpl(root_window_pair.first, gfx::Transform(), nullptr, - &occluded_region); - // WindowDelegate::OnWindowOcclusionChanged() impls must not change any - // Window. - DCHECK(!root_window_state.dirty); + + base::AutoReset<int> auto_reset(&num_times_occlusion_recomputed_, 0); + + // Recompute occlusion states until either: + // - They are stable, i.e. calling Window::SetOcclusionState() on all tracked + // windows does not provoke changes that could affect occlusion. + // - Occlusion states have been recomputed + // |kMaxComputeOcclusionIterationsBeforeStable| + // times. + // If occlusion states have been recomputed + // |kMaxComputeOcclusionIterationsBeforeStable| times and are still not + // stable, iterate one last time to set the occlusion state of all tracked + // windows based on IsVisible(). + while (num_times_occlusion_recomputed_ <= kMaxRecomputeOcclusion) { + const bool exceeded_max_num_times_occlusion_recomputed = + num_times_occlusion_recomputed_ == kMaxRecomputeOcclusion; + bool found_dirty_root = false; + + // Compute occlusion states and store them in |tracked_windows_|. Do not + // call Window::SetOcclusionState() in this phase to prevent changes to the + // window tree while it is being traversed. + for (auto& root_window_pair : root_windows_) { + if (root_window_pair.second.dirty) { + found_dirty_root = true; + root_window_pair.second.dirty = false; + if (!exceeded_max_num_times_occlusion_recomputed) { + SkRegion occluded_region; + RecomputeOcclusionImpl(root_window_pair.first, gfx::Transform(), + nullptr, &occluded_region); + } + } + } + + ++num_times_occlusion_recomputed_; + + if (!found_dirty_root) + break; + + // Call Window::SetOcclusionState() on tracked windows. A WindowDelegate may + // change the window tree in response to this. + WindowTracker tracked_windows_list; + for (const auto& tracked_window : tracked_windows_) + tracked_windows_list.Add(tracked_window.first); + + while (!tracked_windows_list.windows().empty()) { + Window* window = tracked_windows_list.Pop(); + auto it = tracked_windows_.find(window); + if (it != tracked_windows_.end() && + it->second != Window::OcclusionState::UNKNOWN) { + // Fallback to VISIBLE/HIDDEN if the maximum number of times that + // occlusion can be recomputed was exceeded. + if (exceeded_max_num_times_occlusion_recomputed) { + it->second = window->IsVisible() ? Window::OcclusionState::VISIBLE + : Window::OcclusionState::HIDDEN; + } + + window->SetOcclusionState(it->second); + } } } + + // Sanity check: Occlusion states in |tracked_windows_| should match those + // returned by Window::occlusion_state(). + DCHECK(OcclusionStatesMatch(tracked_windows_)); } -void WindowOcclusionTracker::RecomputeOcclusionImpl( +bool WindowOcclusionTracker::RecomputeOcclusionImpl( Window* window, const gfx::Transform& parent_transform_relative_to_root, const SkIRect* clipped_bounds, SkRegion* occluded_region) { DCHECK(window); - if (WindowIsAnimated(window)) { - SetWindowAndDescendantsAreOccluded(window, false); - return; - } - if (!window->IsVisible()) { SetWindowAndDescendantsAreOccluded(window, true); - return; + return false; + } + + if (WindowIsAnimated(window)) { + SetWindowAndDescendantsAreOccluded(window, false); + return true; } // Compute window bounds. @@ -157,7 +226,7 @@ void WindowOcclusionTracker::RecomputeOcclusionImpl( // For simplicity, windows that are not axis-aligned are considered // unoccluded and do not occlude other windows. SetWindowAndDescendantsAreOccluded(window, false); - return; + return true; } const SkIRect window_bounds = GetWindowBoundsInRootWindow( window, transform_relative_to_root, clipped_bounds); @@ -165,19 +234,23 @@ void WindowOcclusionTracker::RecomputeOcclusionImpl( // Compute children occlusion states. const SkIRect* clipped_bounds_for_children = window->layer()->GetMasksToBounds() ? &window_bounds : clipped_bounds; + bool has_visible_child = false; for (auto* child : base::Reversed(window->children())) { - RecomputeOcclusionImpl(child, transform_relative_to_root, - clipped_bounds_for_children, occluded_region); + has_visible_child |= + RecomputeOcclusionImpl(child, transform_relative_to_root, + clipped_bounds_for_children, occluded_region); } // Compute window occlusion state. if (occluded_region->contains(window_bounds)) { - SetOccluded(window, true); - } else { - SetOccluded(window, false); - if (VisibleWindowIsOpaque(window)) - occluded_region->op(window_bounds, SkRegion::kUnion_Op); + SetOccluded(window, !has_visible_child); + return has_visible_child; } + + SetOccluded(window, false); + if (VisibleWindowIsOpaque(window)) + occluded_region->op(window_bounds, SkRegion::kUnion_Op); + return true; } void WindowOcclusionTracker::CleanupAnimatedWindows() { @@ -188,7 +261,7 @@ void WindowOcclusionTracker::CleanupAnimatedWindows() { animator->RemoveObserver(this); auto root_window_state_it = root_windows_.find(window->GetRootWindow()); if (root_window_state_it != root_windows_.end()) - root_window_state_it->second.dirty = true; + MarkRootWindowAsDirty(&root_window_state_it->second); return true; }); } @@ -219,9 +292,17 @@ void WindowOcclusionTracker::SetWindowAndDescendantsAreOccluded( SetWindowAndDescendantsAreOccluded(child_window, is_occluded); } -void WindowOcclusionTracker::SetOccluded(Window* window, bool occluded) { - if (WindowIsTracked(window)) - window->SetOccluded(occluded); +void WindowOcclusionTracker::SetOccluded(Window* window, bool is_occluded) { + auto tracked_window = tracked_windows_.find(window); + if (tracked_window == tracked_windows_.end()) + return; + + if (!window->IsVisible()) + tracked_window->second = Window::OcclusionState::HIDDEN; + else if (is_occluded) + tracked_window->second = Window::OcclusionState::OCCLUDED; + else + tracked_window->second = Window::OcclusionState::VISIBLE; } bool WindowOcclusionTracker::WindowIsTracked(Window* window) const { @@ -233,7 +314,7 @@ bool WindowOcclusionTracker::WindowIsAnimated(Window* window) const { } template <typename Predicate> -void WindowOcclusionTracker::MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf( +void WindowOcclusionTracker::MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf( Window* window, Predicate predicate) { Window* root_window = window->GetRootWindow(); @@ -253,11 +334,28 @@ void WindowOcclusionTracker::MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf( if (root_window_state_it->second.dirty) return; if (predicate()) { - root_window_state_it->second.dirty = true; - MaybeRecomputeOcclusion(); + MarkRootWindowAsDirty(&root_window_state_it->second); + MaybeComputeOcclusion(); } } +void WindowOcclusionTracker::MarkRootWindowAsDirty( + RootWindowState* root_window_state) { + root_window_state->dirty = true; + + // Generate a crash report when a root window is marked as dirty and occlusion + // states have been recomputed |kMaxRecomputeOcclusion| times, because it + // indicates that they are not stabilizing. Don't report it when + // |num_times_occlusion_recomputed_| is greater than |kMaxRecomputeOcclusion| + // to avoid generating multiple reports from the same client. + // + // TODO(fdoray): Remove this once we are confident that occlusion states are + // stable after |kMaxRecomputeOcclusion| iterations in production. + // https://crbug.com/813076 + if (num_times_occlusion_recomputed_ == kMaxRecomputeOcclusion) + base::debug::DumpWithoutCrashing(); +} + bool WindowOcclusionTracker::WindowOrParentIsAnimated(Window* window) const { while (window && !WindowIsAnimated(window)) window = window->parent(); @@ -315,8 +413,8 @@ void WindowOcclusionTracker::TrackedWindowAddedToRoot(Window* window) { ++root_window_state.num_tracked_windows; if (root_window_state.num_tracked_windows == 1) AddObserverToWindowAndDescendants(root_window); - root_window_state.dirty = true; - MaybeRecomputeOcclusion(); + MarkRootWindowAsDirty(&root_window_state); + MaybeComputeOcclusion(); } void WindowOcclusionTracker::TrackedWindowRemovedFromRoot(Window* window) { @@ -356,13 +454,13 @@ void WindowOcclusionTracker::AddObserverToWindowAndDescendants(Window* window) { void WindowOcclusionTracker::OnLayerAnimationEnded( ui::LayerAnimationSequence* sequence) { CleanupAnimatedWindows(); - MaybeRecomputeOcclusion(); + MaybeComputeOcclusion(); } void WindowOcclusionTracker::OnLayerAnimationAborted( ui::LayerAnimationSequence* sequence) { CleanupAnimatedWindows(); - MaybeRecomputeOcclusion(); + MaybeComputeOcclusion(); } void WindowOcclusionTracker::OnLayerAnimationScheduled( @@ -379,12 +477,12 @@ void WindowOcclusionTracker::OnWindowHierarchyChanged( } void WindowOcclusionTracker::OnWindowAdded(Window* window) { - MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf( + MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf( window, [=]() { return WindowMoveMayAffectOcclusionStates(window); }); } void WindowOcclusionTracker::OnWillRemoveWindow(Window* window) { - MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf(window, [=]() { + MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(window, [=]() { return !WindowOrParentIsAnimated(window) && WindowOrDescendantIsOpaque(window); }); @@ -392,7 +490,7 @@ void WindowOcclusionTracker::OnWillRemoveWindow(Window* window) { void WindowOcclusionTracker::OnWindowVisibilityChanged(Window* window, bool visible) { - MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf( + MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf( window, [=]() { return !WindowOrParentIsAnimated(window); }); } @@ -406,7 +504,7 @@ void WindowOcclusionTracker::OnWindowBoundsChanged( const bool animation_started = (reason == ui::PropertyChangeReason::FROM_ANIMATION) && MaybeObserveAnimatedWindow(window); - MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf(window, [=]() { + MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(window, [=]() { return animation_started || WindowMoveMayAffectOcclusionStates(window); }); } @@ -419,7 +517,7 @@ void WindowOcclusionTracker::OnWindowOpacitySet( const bool animation_started = (reason == ui::PropertyChangeReason::FROM_ANIMATION) && MaybeObserveAnimatedWindow(window); - MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf(window, [=]() { + MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(window, [=]() { return animation_started || !WindowOrParentIsAnimated(window); }); } @@ -432,13 +530,13 @@ void WindowOcclusionTracker::OnWindowTransformed( const bool animation_started = (reason == ui::PropertyChangeReason::FROM_ANIMATION) && MaybeObserveAnimatedWindow(window); - MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf(window, [=]() { + MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(window, [=]() { return animation_started || WindowMoveMayAffectOcclusionStates(window); }); } void WindowOcclusionTracker::OnWindowStackingChanged(Window* window) { - MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf( + MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf( window, [=]() { return WindowMoveMayAffectOcclusionStates(window); }); } @@ -483,8 +581,8 @@ void WindowOcclusionTracker::OnWindowLayerRecreated(Window* window) { animator->RemoveObserver(this); auto root_window_state_it = root_windows_.find(window->GetRootWindow()); if (root_window_state_it != root_windows_.end()) { - root_window_state_it->second.dirty = true; - MaybeRecomputeOcclusion(); + MarkRootWindowAsDirty(&root_window_state_it->second); + MaybeComputeOcclusion(); } } diff --git a/chromium/ui/aura/window_occlusion_tracker.h b/chromium/ui/aura/window_occlusion_tracker.h index d3aa02b1ee8..c76f4f4eee0 100644 --- a/chromium/ui/aura/window_occlusion_tracker.h +++ b/chromium/ui/aura/window_occlusion_tracker.h @@ -9,6 +9,7 @@ #include "base/containers/flat_set.h" #include "base/macros.h" #include "ui/aura/aura_export.h" +#include "ui/aura/window.h" #include "ui/aura/window_observer.h" #include "ui/compositor/layer_animation_observer.h" @@ -21,8 +22,6 @@ class Transform; namespace aura { -class Window; - // Notifies tracked Windows when their occlusion state change. // // To start tracking the occlusion state of a Window, call @@ -55,20 +54,30 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver, static void Track(Window* window); private: + struct RootWindowState { + // Number of Windows whose occlusion state is tracked under this root + // Window. + int num_tracked_windows = 0; + + // Whether the occlusion state of tracked Windows under this root is stale. + bool dirty = false; + }; + WindowOcclusionTracker(); ~WindowOcclusionTracker() override; // Recomputes the occlusion state of tracked windows under roots marked as // dirty in |root_windows_| if there are no active // ScopedPauseOcclusionTracking instance. - void MaybeRecomputeOcclusion(); + void MaybeComputeOcclusion(); // Recomputes the occlusion state of |window| and its descendants. // |parent_transform_relative_to_root| is the transform of |window->parent()| // relative to the root window. |clipped_bounds| is an optional mask for the // bounds of |window| and its descendants. |occluded_region| is a region - // covered by windows which are on top of |window|. - void RecomputeOcclusionImpl( + // covered by windows which are on top of |window|. Returns true if at least + // one window in the hierarchy starting at |window| is NOT_OCCLUDED. + bool RecomputeOcclusionImpl( Window* window, const gfx::Transform& parent_transform_relative_to_root, const SkIRect* clipped_bounds, @@ -82,13 +91,14 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver, // |animated_windows_|, adds |window| to |animated_windows_| and returns true. bool MaybeObserveAnimatedWindow(Window* window); - // Calls SetOccluded(|is_occluded|) on |window| and its descendants if they - // are in |tracked_windows_|. + // Calls SetOccluded() with |is_occluded| as argument for |window| and its + // descendants. void SetWindowAndDescendantsAreOccluded(Window* window, bool is_occluded); - // Calls SetOccluded() on |window| with |occluded| as argument if |window| is - // in |tracked_windows_|. - void SetOccluded(Window* window, bool occluded); + // Updates the occlusion state of |window| in |tracked_windows_|, based on + // |is_occluded| and window->IsVisible(). No-op if |window| is not in + // |tracked_windows_|. + void SetOccluded(Window* window, bool is_occluded); // Returns true if |window| is in |tracked_windows_|. bool WindowIsTracked(Window* window) const; @@ -97,12 +107,15 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver, bool WindowIsAnimated(Window* window) const; // If the root of |window| is not dirty and |predicate| is true, marks the - // root of |window| as dirty. Then, calls MaybeRecomputeOcclusion(). + // root of |window| as dirty. Then, calls MaybeComputeOcclusion(). // |predicate| is not evaluated if the root of |window| is already dirty when // this is called. template <typename Predicate> - void MarkRootWindowAsDirtyAndMaybeRecomputeOcclusionIf(Window* window, - Predicate predicate); + void MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(Window* window, + Predicate predicate); + + // Marks |root_window| as dirty. + void MarkRootWindowAsDirty(RootWindowState* root_window_state); // Returns true if |window| or one of its parents is in |animated_windows_|. bool WindowOrParentIsAnimated(Window* window) const; @@ -162,17 +175,8 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver, Window* new_root) override; void OnWindowLayerRecreated(Window* window) override; - struct RootWindowState { - // Number of Windows whose occlusion state is tracked under this root - // Window. - int num_tracked_windows = 0; - - // Whether the occlusion state of tracked Windows under this root is stale. - bool dirty = false; - }; - // Windows whose occlusion state is tracked. - base::flat_set<Window*> tracked_windows_; + base::flat_map<Window*, Window::OcclusionState> tracked_windows_; // Windows whose bounds or transform are animated. // @@ -186,6 +190,10 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver, // Root Windows of Windows in |tracked_windows_|. base::flat_map<Window*, RootWindowState> root_windows_; + // Number of times that the current call to MaybeComputeOcclusion() has + // recomputed occlusion states. Always 0 when not in MaybeComputeOcclusion(). + int num_times_occlusion_recomputed_ = 0; + DISALLOW_COPY_AND_ASSIGN(WindowOcclusionTracker); }; diff --git a/chromium/ui/aura/window_occlusion_tracker_unittest.cc b/chromium/ui/aura/window_occlusion_tracker_unittest.cc index 1e04ab52382..6394bd7e42f 100644 --- a/chromium/ui/aura/window_occlusion_tracker_unittest.cc +++ b/chromium/ui/aura/window_occlusion_tracker_unittest.cc @@ -27,17 +27,6 @@ namespace { constexpr base::TimeDelta kTransitionDuration = base::TimeDelta::FromSeconds(3); -enum class WindowOcclusionChangedExpectation { - // Expect OnWindowOcclusionChanged() to be called with true as argument. - OCCLUDED, - - // Expect OnWindowOcclusionChanged() to be called with false as argument. - NOT_OCCLUDED, - - // Don't expect OnWindowOcclusionChanged() to be called. - NO_CALL, -}; - class MockWindowDelegate : public test::ColorTestWindowDelegate { public: MockWindowDelegate() : test::ColorTestWindowDelegate(SK_ColorWHITE) {} @@ -45,33 +34,24 @@ class MockWindowDelegate : public test::ColorTestWindowDelegate { void set_window(Window* window) { window_ = window; } - void set_expectation(WindowOcclusionChangedExpectation expectation) { + void set_expectation(Window::OcclusionState expectation) { expectation_ = expectation; } bool is_expecting_call() const { - return expectation_ != WindowOcclusionChangedExpectation::NO_CALL; + return expectation_ != Window::OcclusionState::UNKNOWN; } - void OnWindowOcclusionChanged(bool occluded) override { + void OnWindowOcclusionChanged( + Window::OcclusionState occlusion_state) override { ASSERT_TRUE(window_); - if (expectation_ == WindowOcclusionChangedExpectation::OCCLUDED) { - EXPECT_TRUE(occluded); - EXPECT_EQ(Window::OcclusionState::OCCLUDED, window_->occlusion_state()); - } else if (expectation_ == - WindowOcclusionChangedExpectation::NOT_OCCLUDED) { - EXPECT_FALSE(occluded); - EXPECT_EQ(Window::OcclusionState::NOT_OCCLUDED, - window_->occlusion_state()); - } else { - ADD_FAILURE() << "Unexpected call to OnWindowOcclusionChanged."; - } - expectation_ = WindowOcclusionChangedExpectation::NO_CALL; + EXPECT_NE(occlusion_state, Window::OcclusionState::UNKNOWN); + EXPECT_EQ(occlusion_state, expectation_); + expectation_ = Window::OcclusionState::UNKNOWN; } private: - WindowOcclusionChangedExpectation expectation_ = - WindowOcclusionChangedExpectation::NO_CALL; + Window::OcclusionState expectation_ = Window::OcclusionState::UNKNOWN; Window* window_ = nullptr; DISALLOW_COPY_AND_ASSIGN(MockWindowDelegate); @@ -113,34 +93,34 @@ class WindowOcclusionTrackerTest : public test::AuraTestBase { } // namespace -// Verify that the non-overlapping windows are notified are not occluded. +// Verify that non-overlapping windows have a VISIBLE occlusion state. // _____ _____ // | | | | // |____| |____| TEST_F(WindowOcclusionTrackerTest, NonOverlappingWindows) { MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(15, 0, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); } -// Verify that partially overlapping windows are not occluded. +// Verify that partially overlapping windows have a VISIBLE occlusion state. // ______ // |__| | // |_____| TEST_F(WindowOcclusionTrackerTest, PartiallyOverlappingWindow) { MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); } @@ -154,31 +134,31 @@ TEST_F(WindowOcclusionTrackerTest, PartiallyOverlappingWindow) { TEST_F(WindowOcclusionTrackerTest, HiddenWindowCoversWindow) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b. Expect it to be non-occluded and expect window a to be // occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 15, 15)); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); // Hide window b. Expect window a to be non-occluded and window b to be // occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + delegate_b->set_expectation(Window::OcclusionState::HIDDEN); window_b->Hide(); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); // Show window b. Expect window a to be occluded and window b to be non- // occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); window_b->Show(); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -193,15 +173,15 @@ TEST_F(WindowOcclusionTrackerTest, HiddenWindowCoversWindow) { TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b. Expect it to be non-occluded and expect window a to be // occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 15, 15)); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -209,13 +189,13 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) { // Change the opacity of window b to 0.5f. Expect both windows to be non- // occluded. EXPECT_FALSE(delegate_a->is_expecting_call()); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); window_b->layer()->SetOpacity(0.5f); EXPECT_FALSE(delegate_a->is_expecting_call()); // Change the opacity of window b back to 1.0f. Expect window a to be // occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); window_b->layer()->SetOpacity(1.0f); EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -225,24 +205,24 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) { TEST_F(WindowOcclusionTrackerTest, SemiTransparentUntrackedWindowCoversWindow) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create untracked window b. Expect window a to be occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 15, 15)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Change the opacity of window b to 0.5f. Expect both windows to be non- // occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); window_b->layer()->SetOpacity(0.5f); EXPECT_FALSE(delegate_a->is_expecting_call()); // Change the opacity of window b back to 1.0f. Expect window a to be // occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); window_b->layer()->SetOpacity(1.0f); EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -255,14 +235,14 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentUntrackedWindowCoversWindow) { TEST_F(WindowOcclusionTrackerTest, TwoWindowsOccludeOneWindow) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b with bounds that partially cover window a. Expect both // windows to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -270,63 +250,115 @@ TEST_F(WindowOcclusionTrackerTest, TwoWindowsOccludeOneWindow) { // already covered by window b. Expect window a to be occluded and window a/b // to be non-occluded. MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_c, gfx::Rect(5, 0, 5, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); } -// Verify that when the bounds of a child window do not cover the bounds of a -// parent window, both windows are non-occluded. -TEST_F(WindowOcclusionTrackerTest, ChildDoesNotOccludeParent) { +// Verify that a window and its child that are covered by a sibling are +// occluded. +TEST_F(WindowOcclusionTrackerTest, SiblingOccludesWindowAndChild) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20)); EXPECT_FALSE(delegate_a->is_expecting_call()); - // Create window b with window a as parent. The bounds of window b do not - // fully cover window a. Expect both windows to be non-occluded. + // Create window b, with bounds that occlude half of its parent window a. + // Expect it to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5), window_a); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a); EXPECT_FALSE(delegate_b->is_expecting_call()); + + // Create window c, with bounds that occlude window a and window b. Expect it + // to be non-occluded, and window a and b to be occluded. + MockWindowDelegate* delegate_c = new MockWindowDelegate(); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 20, 20)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + EXPECT_FALSE(delegate_b->is_expecting_call()); + EXPECT_FALSE(delegate_c->is_expecting_call()); } -// Verify that when the bounds of a child window cover the bounds of a parent -// window, the parent is occluded and the child is non-occluded. Also, verify -// that when the parent of a window changes, occlusion states are updated. -TEST_F(WindowOcclusionTrackerTest, ChildOccludesParent) { +// Verify that a window with one half covered by a child and the other half +// covered by a sibling is non-occluded. +TEST_F(WindowOcclusionTrackerTest, ChildAndSiblingOccludeOneWindow) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + + // Create window b, with bounds that occlude half of its parent window a. + // Expect it to be non-occluded. + MockWindowDelegate* delegate_b = new MockWindowDelegate(); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a); + EXPECT_FALSE(delegate_b->is_expecting_call()); + + // Create window c, with bounds that occlude the other half of window a. + // Expect it to be non-occluded and expect window a to remain non-occluded. + MockWindowDelegate* delegate_c = new MockWindowDelegate(); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 20)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + EXPECT_FALSE(delegate_c->is_expecting_call()); +} + +// Verify that a window covered by 2 non-occluded children is non-occluded. +TEST_F(WindowOcclusionTrackerTest, ChildrenOccludeOneWindow) { + // Create window a. Expect it to be non-occluded. + MockWindowDelegate* delegate_a = new MockWindowDelegate(); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + + // Create window b, with bounds that cover half of its parent window a. Expect + // it to be non-occluded. + MockWindowDelegate* delegate_b = new MockWindowDelegate(); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a); + EXPECT_FALSE(delegate_b->is_expecting_call()); + + // Create window c, with bounds that cover the other half of its parent window + // a. Expect it to be non-occluded. Expect window a to remain non-occluded. + MockWindowDelegate* delegate_c = new MockWindowDelegate(); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 20), window_a); + EXPECT_FALSE(delegate_c->is_expecting_call()); +} + +// Verify that when the bounds of a child window covers the bounds of a parent +// window but is itself visible, the parent window is visible. +TEST_F(WindowOcclusionTrackerTest, ChildDoesNotOccludeParent) { + // Create window a. Expect it to be non-occluded. + MockWindowDelegate* delegate_a = new MockWindowDelegate(); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b with window a as parent. The bounds of window b fully cover - // window a. Expect window a to be occluded but not window b. + // window a. Expect both windows to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10), window_a); - EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); // Create window c whose bounds don't overlap existing windows. MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(15, 0, 10, 10)); EXPECT_FALSE(delegate_c->is_expecting_call()); - // Change the parent of window b from window a to window c. Expect window a to - // be non-occluded and window c to be occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + // Change the parent of window b from window a to window c. Expect all windows + // to remain non-occluded. window_c->AddChild(window_b); - EXPECT_FALSE(delegate_a->is_expecting_call()); - EXPECT_FALSE(delegate_c->is_expecting_call()); } // Verify that when the stacking order of windows change, occlusion states are @@ -335,28 +367,28 @@ TEST_F(WindowOcclusionTrackerTest, StackingChanged) { // Create three windows that have the same bounds. Expect window on top of the // stack to be non-occluded and other windows to be occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); // Move window a on top of the stack. Expect it to be non-occluded and expect // window c to be occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + delegate_c->set_expectation(Window::OcclusionState::OCCLUDED); root_window()->StackChildAtTop(window_a); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); @@ -369,46 +401,47 @@ TEST_F(WindowOcclusionTrackerTest, StackingChanged) { TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) { // Create window a which is transparent. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10), root_window(), true); EXPECT_FALSE(delegate_a->is_expecting_call()); - // Create window b which has the same bounds as its parent window a. Expect - // window b to be non-occluded and window a to be occluded. + // Create window b which has the same bounds as its parent window a. Expect it + // to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10), window_a); - EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); // Create window c which is transparent and has the same bounds as window a // and window b. Expect it to be non-occluded. MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10), root_window(), true); - EXPECT_FALSE(delegate_b->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); // Create window d which has the same bounds as its parent window c. Expect - // window d to be non-occluded and all other windows to be occluded. + // window d to be non-occluded and window a and b to be occluded. MockWindowDelegate* delegate_d = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_d->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_d->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_d, gfx::Rect(0, 0, 10, 10), window_c); + EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); - EXPECT_FALSE(delegate_c->is_expecting_call()); EXPECT_FALSE(delegate_d->is_expecting_call()); - // Move window a on top of the stack. Expect its child window b to be non- - // occluded and all other windows to be occluded. - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - delegate_d->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + // Move window a on top of the stack. Expect window a and b to be non-occluded + // and window c and d to be occluded. + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + delegate_c->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_d->set_expectation(Window::OcclusionState::OCCLUDED); root_window()->StackChildAtTop(window_a); + EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); + EXPECT_FALSE(delegate_c->is_expecting_call()); EXPECT_FALSE(delegate_d->is_expecting_call()); } @@ -419,12 +452,12 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowStackingChanged) { // Create window b. Expect it to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); // Stack window a on top of window b. Expect window b to be occluded. - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); root_window()->StackChildAtTop(window_a); EXPECT_FALSE(delegate_b->is_expecting_call()); } @@ -433,17 +466,17 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowStackingChanged) { TEST_F(WindowOcclusionTrackerTest, BoundsChanged) { // Create two non-overlapping windows. Expect them to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); // Move window b on top of window a. Expect window a to be occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); window_b->SetBounds(window_a->bounds()); EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -464,26 +497,26 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowBoundsAnimated) { // Create 3 windows. Window a is unoccluded. Window c occludes window b. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); window_b->layer()->SetAnimator(test_controller.animator()); MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); // Start animating the bounds of window b so that it moves on top of window a. // Window b should be non-occluded when the animation starts. - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); window_b->SetBounds(window_a->bounds()); test_controller.Step(kTransitionDuration / 3); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -492,7 +525,7 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowBoundsAnimated) { test_controller.Step(kTransitionDuration / 3); // Window b should occlude window a at the end of the animation. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); test_controller.Step(kTransitionDuration / 3); EXPECT_FALSE(delegate_a->is_expecting_call()); @@ -511,18 +544,18 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) { // Create 3 windows. Window a is unoccluded. Window c occludes window b. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); @@ -530,7 +563,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) { // Start animating the bounds of window c so that it moves on top of window a. // Window b should be non-occluded when the animation starts. - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); window_c->SetBounds(window_a->bounds()); test_controller.Step(kTransitionDuration / 3); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -539,7 +572,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) { test_controller.Step(kTransitionDuration / 3); // Window c should occlude window a at the end of the animation. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); test_controller.Step(kTransitionDuration / 3); EXPECT_FALSE(delegate_a->is_expecting_call()); @@ -551,14 +584,14 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) { TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b which doesn't overlap window a and is transparent. Expect // it to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10), root_window(), true); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -566,13 +599,13 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) { // Create window c which has window b as parent and doesn't occlude any // window. MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b); EXPECT_FALSE(delegate_c->is_expecting_call()); // Move window b so that window c occludes window a. Expect window a to be // occluded and other windows to be non-occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); window_b->SetBounds(gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -582,7 +615,7 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) { TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); @@ -590,7 +623,7 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) { Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 10, 5, 5)); // Move window b on top of window a. Expect window a to be occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); window_b->SetBounds(window_a->bounds()); EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -600,18 +633,18 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) { TEST_F(WindowOcclusionTrackerTest, TransformChanged) { // Create two non-overlapping windows. Expect them to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); // Scale and translate window b so that it covers window a. Expect window a to // be occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); gfx::Transform transform; transform.Translate(0.0f, -10.0f); transform.Scale(2.0f, 2.0f); @@ -635,26 +668,26 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowTransformAnimated) { // Create 3 windows. Window a is unoccluded. Window c occludes window b. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); window_b->layer()->SetAnimator(test_controller.animator()); MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); // Start animating the transform of window b so that it moves on top of window // a. Window b should be non-occluded when the animation starts. - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); auto transform = std::make_unique<ui::InterpolatedScale>( gfx::Point3F(1, 1, 1), gfx::Point3F(2.0f, 2.0f, 1)); transform->SetChild(std::make_unique<ui::InterpolatedTranslation>( @@ -669,7 +702,7 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowTransformAnimated) { test_controller.Step(kTransitionDuration / 3); // Window b should occlude window a at the end of the animation. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); test_controller.Step(kTransitionDuration / 3); EXPECT_FALSE(delegate_a->is_expecting_call()); @@ -688,18 +721,18 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) { // Create 3 windows. Window a is unoccluded. Window c occludes window b. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20)); EXPECT_FALSE(delegate_a->is_expecting_call()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 20, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 20, 10, 10)); EXPECT_FALSE(delegate_b->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); @@ -707,7 +740,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) { // Start animating the bounds of window c so that it moves on top of window a. // Window b should be non-occluded when the animation starts. - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); auto transform = std::make_unique<ui::InterpolatedScale>( gfx::Point3F(1, 1, 1), gfx::Point3F(2.0f, 2.0f, 1)); transform->SetChild(std::make_unique<ui::InterpolatedTranslation>( @@ -722,7 +755,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) { test_controller.Step(kTransitionDuration / 3); // Window c should occlude window a at the end of the animation. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); test_controller.Step(kTransitionDuration / 3); EXPECT_FALSE(delegate_a->is_expecting_call()); @@ -734,14 +767,14 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) { TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b which doesn't overlap window a and is transparent. Expect // it to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10), root_window(), true); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -749,13 +782,13 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) { // Create window c which has window b as parent and doesn't occlude any // window. MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b); EXPECT_FALSE(delegate_c->is_expecting_call()); // Scale and translate window b so that window c occludes window a. Expect // window a to be occluded and other windows to be non-occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); gfx::Transform transform; transform.Translate(0.0f, -10.0f); transform.Scale(2.0f, 2.0f); @@ -768,7 +801,7 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) { TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); @@ -777,7 +810,7 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) { // Scale and translate window b so that it occludes window a. Expect window a // to be occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); gfx::Transform transform; transform.Translate(0.0f, -10.0f); transform.Scale(2.0f, 2.0f); @@ -790,17 +823,17 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) { TEST_F(WindowOcclusionTrackerTest, DeleteUntrackedWindow) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b which occludes window a. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Delete window b. Expect a to be non-occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); delete window_b; EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -810,17 +843,17 @@ TEST_F(WindowOcclusionTrackerTest, DeleteUntrackedWindow) { TEST_F(WindowOcclusionTrackerTest, RemoveUntrackedWindow) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b which occludes window a. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Delete window b. Expect a to be non-occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); root_window()->RemoveChild(window_b); EXPECT_FALSE(delegate_a->is_expecting_call()); delete window_b; @@ -834,7 +867,7 @@ TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) { // Create window b. Expect it to be non-occluded. MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_c->is_expecting_call()); @@ -846,19 +879,19 @@ TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) { // Create untracked window d which covers window a. Expect window a to be // occluded. - delegate_c->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::OCCLUDED); Window* window_d = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_c->is_expecting_call()); // Move window d so that it doesn't cover window c. - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); window_d->SetBounds(gfx::Rect(0, 10, 5, 5)); EXPECT_FALSE(delegate_c->is_expecting_call()); // Stack window a on top of window c. Expect window c to be non-occluded. This // won't work if WindowOcclusionTracked didn't register as an observer of // window a when window c was made a child of root_window(). - delegate_c->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::OCCLUDED); root_window()->StackChildAtTop(window_a); EXPECT_FALSE(delegate_c->is_expecting_call()); } @@ -874,7 +907,7 @@ class ResizeWindowObserver : public WindowObserver { const gfx::Rect& old_bounds, const gfx::Rect& new_bounds, ui::PropertyChangeReason reason) override { - window_to_resize_->SetBounds(window->bounds()); + window_to_resize_->SetBounds(old_bounds); } private: @@ -891,29 +924,35 @@ class ResizeWindowObserver : public WindowObserver { TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); - // Create window b, which is a child of window a. Expect it to be non- - // occluded. + // Create window b. Expect it to be non-occluded and to occlude window a. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); - Window* window_b = - CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5), window_a); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10)); + EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); - // Create an observer that will resize window b when window a is resized. - ResizeWindowObserver resize_window_observer(window_b); - window_a->AddObserver(&resize_window_observer); - - // Resize window a. Expect window b to be resized so that window a is + // Create window c, which is a child of window b. Expect it to be non- // occluded. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - window_a->SetBounds(gfx::Rect(0, 0, 20, 20)); - EXPECT_FALSE(delegate_a->is_expecting_call()); + MockWindowDelegate* delegate_c = new MockWindowDelegate(); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_c = + CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b); + EXPECT_FALSE(delegate_b->is_expecting_call()); + + // Create an observer that will resize window c when window b is resized. + ResizeWindowObserver resize_window_observer(window_c); + window_b->AddObserver(&resize_window_observer); + + // Resize window b. Expect window c to be resized so that window a stays + // occluded. Window a should not temporarily be non-occluded. + window_b->SetBounds(gfx::Rect(0, 0, 5, 5)); - window_a->RemoveObserver(&resize_window_observer); + window_b->RemoveObserver(&resize_window_observer); } // Verify that the bounds of windows are changed multiple times within the scope @@ -922,14 +961,14 @@ TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) { TEST_F(WindowOcclusionTrackerTest, ScopedPauseOcclusionTracking) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b which doesn't overlap window a. Expect it to be non- // occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -942,7 +981,7 @@ TEST_F(WindowOcclusionTrackerTest, ScopedPauseOcclusionTracking) { window_a->SetBounds(gfx::Rect(0, 10, 5, 5)); window_b->SetBounds(window_a->bounds()); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); } EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -951,14 +990,14 @@ TEST_F(WindowOcclusionTrackerTest, ScopedPauseOcclusionTracking) { TEST_F(WindowOcclusionTrackerTest, NestedScopedPauseOcclusionTracking) { // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b which doesn't overlap window a. Expect it to be non- // occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); @@ -984,7 +1023,7 @@ TEST_F(WindowOcclusionTrackerTest, NestedScopedPauseOcclusionTracking) { window_b->SetBounds(window_a->bounds()); } - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); } EXPECT_FALSE(delegate_a->is_expecting_call()); } @@ -1006,15 +1045,15 @@ TEST_F(WindowOcclusionTrackerTest, HierarchyOfTransforms) { CreateUntrackedWindow(gfx::Rect(15, 16, 4, 5), window_b); MockWindowDelegate* delegate_d = new MockWindowDelegate(); - delegate_d->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_d->set_expectation(Window::OcclusionState::VISIBLE); Window* window_d = CreateTrackedWindow(delegate_d, gfx::Rect(34, 36, 8, 10)); EXPECT_FALSE(delegate_d->is_expecting_call()); - delegate_d->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_d->set_expectation(Window::OcclusionState::OCCLUDED); root_window()->StackChildAtBottom(window_d); EXPECT_FALSE(delegate_d->is_expecting_call()); - delegate_d->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_d->set_expectation(Window::OcclusionState::VISIBLE); window_d->SetBounds(gfx::Rect(35, 36, 8, 10)); EXPECT_FALSE(delegate_d->is_expecting_call()); @@ -1026,26 +1065,24 @@ TEST_F(WindowOcclusionTrackerTest, HierarchyOfTransforms) { // Verify that clipping is taken into account when computing occlusion. TEST_F(WindowOcclusionTrackerTest, Clipping) { - // Create window b. Expect it to be non-occluded. + // Create window a. Expect it to be non-occluded. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); // Create window b. Expect it to be non-occluded. MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5)); EXPECT_FALSE(delegate_b->is_expecting_call()); window_b->layer()->SetMasksToBounds(true); - // Create window c which has window b as parent. Expect it to occlude window - // b, but not window a since it's clipped. + // Create window c which has window b as parent. Don't expect it to occlude + // window a since its bounds are clipped by window b. MockWindowDelegate* delegate_c = new MockWindowDelegate(); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_c->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10), window_b); - EXPECT_FALSE(delegate_b->is_expecting_call()); EXPECT_FALSE(delegate_c->is_expecting_call()); } @@ -1064,7 +1101,7 @@ TEST_F(WindowOcclusionTrackerTest, DestroyWindowWithPendingAnimation) { layer_animation_settings.SetTransitionDuration(kTransitionDuration); MockWindowDelegate* delegate = new MockWindowDelegate(); - delegate->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate->set_expectation(Window::OcclusionState::VISIBLE); Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate->is_expecting_call()); window->layer()->SetAnimator(test_controller.animator()); @@ -1092,28 +1129,28 @@ TEST_F(WindowOcclusionTrackerTest, RecreateLayerOfAnimatedWindow) { // Create 2 windows. Window b occludes window a. MockWindowDelegate* delegate_a = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(2, 2, 1, 1)); EXPECT_FALSE(delegate_a->is_expecting_call()); window_a->layer()->SetAnimator(test_controller.animator()); MockWindowDelegate* delegate_b = new MockWindowDelegate(); - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); - delegate_b->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate_a->is_expecting_call()); EXPECT_FALSE(delegate_b->is_expecting_call()); // Start animating the bounds of window a. Window a should be non-occluded // when the animation starts. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); window_a->SetBounds(gfx::Rect(6, 6, 1, 1)); test_controller.Step(kTransitionDuration / 2); EXPECT_FALSE(delegate_a->is_expecting_call()); // Recreate the layer of window b. Expect this to behave the same as if the // animation was abandoned. - delegate_a->set_expectation(WindowOcclusionChangedExpectation::OCCLUDED); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); std::unique_ptr<ui::Layer> old_layer = window_a->RecreateLayer(); EXPECT_FALSE(delegate_a->is_expecting_call()); @@ -1143,7 +1180,7 @@ class ObserverChangingWindowBounds : public WindowObserver { TEST_F(WindowOcclusionTrackerTest, ChangeTrackedWindowBeforeObserveAddToRoot) { // Create a window. Expect it to be non-occluded. MockWindowDelegate* delegate = new MockWindowDelegate(); - delegate->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate->set_expectation(Window::OcclusionState::VISIBLE); Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate->is_expecting_call()); @@ -1205,7 +1242,7 @@ TEST_F(WindowOcclusionTrackerTest, // Create a window. Expect it to be non-occluded. MockWindowDelegate* delegate = new MockWindowDelegate(); - delegate->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate->set_expectation(Window::OcclusionState::VISIBLE); Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate->is_expecting_call()); window->layer()->SetAnimator(test_controller.animator()); @@ -1237,7 +1274,7 @@ TEST_F(WindowOcclusionTrackerTest, // Create a tracked window. Expect it to be non-occluded. MockWindowDelegate* delegate = new MockWindowDelegate(); - delegate->set_expectation(WindowOcclusionChangedExpectation::NOT_OCCLUDED); + delegate->set_expectation(Window::OcclusionState::VISIBLE); CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10)); EXPECT_FALSE(delegate->is_expecting_call()); @@ -1264,4 +1301,224 @@ TEST_F(WindowOcclusionTrackerTest, window->layer()->GetAnimator()->StopAnimating(); } +namespace { + +class WindowDelegateHidingWindowIfOccluded : public MockWindowDelegate { + public: + WindowDelegateHidingWindowIfOccluded(Window* other_window, + MockWindowDelegate* other_delegate) + : other_window_(other_window), other_delegate_(other_delegate) {} + + // MockWindowDelegate: + void OnWindowOcclusionChanged( + Window::OcclusionState occlusion_state) override { + MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state); + if (occlusion_state == Window::OcclusionState::HIDDEN) { + other_window_->Hide(); + other_delegate_->set_expectation(Window::OcclusionState::HIDDEN); + } + } + + private: + Window* other_window_; + MockWindowDelegate* other_delegate_; + + DISALLOW_COPY_AND_ASSIGN(WindowDelegateHidingWindowIfOccluded); +}; + +} // namespace + +// Verify that a window delegate can change the visibility of another window +// when it is notified that its occlusion changed. +TEST_F(WindowOcclusionTrackerTest, HideFromOnWindowOcclusionChanged) { + // Create a tracked window. Expect it to be visible. + MockWindowDelegate* delegate_a = new MockWindowDelegate(); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + + // Create a tracked window. Expect it to be visible. + MockWindowDelegate* delegate_b = + new WindowDelegateHidingWindowIfOccluded(window_a, delegate_a); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(5, 5, 10, 10)); + EXPECT_FALSE(delegate_b->is_expecting_call()); + + // Hide the tracked window. It should be able to hide |window_a|. + delegate_b->set_expectation(Window::OcclusionState::HIDDEN); + window_b->Hide(); + EXPECT_FALSE(delegate_a->is_expecting_call()); + EXPECT_FALSE(delegate_b->is_expecting_call()); + EXPECT_FALSE(window_a->IsVisible()); + EXPECT_FALSE(window_b->IsVisible()); +} + +namespace { + +class WindowDelegateDeletingWindow : public MockWindowDelegate { + public: + WindowDelegateDeletingWindow() = default; + + void set_other_window(Window* other_window) { other_window_ = other_window; } + + // MockWindowDelegate: + void OnWindowOcclusionChanged( + Window::OcclusionState occlusion_state) override { + MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state); + if (occlusion_state == Window::OcclusionState::OCCLUDED) { + delete other_window_; + other_window_ = nullptr; + } + } + + private: + Window* other_window_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(WindowDelegateDeletingWindow); +}; + +} // namespace + +// Verify that a window can delete a window that is on top of it when it is +// notified that its occlusion changed (a crash would occur if +// WindowOcclusionTracker accessed that window after it was deleted). +TEST_F(WindowOcclusionTrackerTest, DeleteFromOnWindowOcclusionChanged) { + // Create a tracked window. Expect it to be visible. + WindowDelegateDeletingWindow* delegate_a = new WindowDelegateDeletingWindow(); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + + // Create a tracked window. Expect it to be visible. + MockWindowDelegate* delegate_b = new MockWindowDelegate(); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(10, 0, 10, 10)); + EXPECT_FALSE(delegate_b->is_expecting_call()); + + // Create a tracked window. Expect it to be visible. + MockWindowDelegate* delegate_c = new MockWindowDelegate(); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(20, 0, 10, 10)); + EXPECT_FALSE(delegate_c->is_expecting_call()); + + // |window_c| will be deleted when |window_a| is occluded. + delegate_a->set_other_window(window_c); + + // Move |window_b| on top of |window_a|. + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + window_b->SetBounds(window_a->bounds()); + EXPECT_FALSE(delegate_a->is_expecting_call()); +} + +namespace { + +class WindowDelegateChangingWindowVisibility : public MockWindowDelegate { + public: + WindowDelegateChangingWindowVisibility() = default; + + void set_window_to_update(Window* window) { window_to_update_ = window; } + + // MockWindowDelegate: + void OnWindowOcclusionChanged( + Window::OcclusionState occlusion_state) override { + MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state); + if (!window_to_update_) + return; + + if (window_to_update_->IsVisible()) { + window_to_update_->Hide(); + EXPECT_FALSE(did_set_expectation_from_occlusion_changed_); + set_expectation(Window::OcclusionState::HIDDEN); + did_set_expectation_from_occlusion_changed_ = true; + } else { + window_to_update_->Show(); + if (!did_set_expectation_from_occlusion_changed_) + set_expectation(Window::OcclusionState::VISIBLE); + } + } + + private: + Window* window_to_update_ = nullptr; + bool did_set_expectation_from_occlusion_changed_ = false; + + DISALLOW_COPY_AND_ASSIGN(WindowDelegateChangingWindowVisibility); +}; +} // namespace + +// Verify that if a window changes its visibility every time it is notified that +// its occlusion state changed, the occlusion state of all IsVisible() windows +// is set to NOT_OCCLUDED and no infinite loop is entered. +TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) { + // Create 2 superposed tracked windows. + MockWindowDelegate* delegate_a = new MockWindowDelegate(); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + + MockWindowDelegate* delegate_b = new MockWindowDelegate(); + delegate_a->set_expectation(Window::OcclusionState::OCCLUDED); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + EXPECT_FALSE(delegate_b->is_expecting_call()); + + // Create a hidden tracked window. + MockWindowDelegate* delegate_c = new MockWindowDelegate(); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 10)); + EXPECT_FALSE(delegate_c->is_expecting_call()); + delegate_c->set_expectation(Window::OcclusionState::HIDDEN); + window_c->Hide(); + EXPECT_FALSE(delegate_c->is_expecting_call()); + + // Create a tracked window. Expect it to be non-occluded. + auto* delegate_d = new WindowDelegateChangingWindowVisibility(); + delegate_d->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_d = CreateTrackedWindow(delegate_d, gfx::Rect(20, 0, 10, 10)); + EXPECT_FALSE(delegate_d->is_expecting_call()); + + // Store a pointer to |window_d| in |delegate_d|. This will cause a call to + // Show()/Hide() every time |delegate_d| is notified of an occlusion change. + delegate_d->set_window_to_update(window_d); + + // Hide |window_d|. This will cause occlusion to be recomputed multiple times. + // Once the maximum number of times that occlusion can be recomputed is + // reached, the occlusion state of all IsVisible() windows should be set to + // NOT_OCCLUDED. + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + delegate_d->set_expectation(Window::OcclusionState::HIDDEN); + window_d->Hide(); + EXPECT_FALSE(delegate_a->is_expecting_call()); + EXPECT_FALSE(delegate_d->is_expecting_call()); +} + +// Verify that the occlusion states are correctly update when a branch of the +// tree is hidden. +TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) { + // Create a branch of 3 tracked windows. Expect them to be visible. + MockWindowDelegate* delegate_a = new MockWindowDelegate(); + delegate_a->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10)); + EXPECT_FALSE(delegate_a->is_expecting_call()); + + MockWindowDelegate* delegate_b = new MockWindowDelegate(); + delegate_b->set_expectation(Window::OcclusionState::VISIBLE); + Window* window_b = + CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10), window_a); + EXPECT_FALSE(delegate_b->is_expecting_call()); + + MockWindowDelegate* delegate_c = new MockWindowDelegate(); + delegate_c->set_expectation(Window::OcclusionState::VISIBLE); + CreateTrackedWindow(delegate_c, gfx::Rect(0, 20, 10, 10), window_b); + EXPECT_FALSE(delegate_c->is_expecting_call()); + + // Hide |window_b| (and hence |window_c|). Expect |window_b| and |window_c| to + // be hidden. + delegate_b->set_expectation(Window::OcclusionState::HIDDEN); + delegate_c->set_expectation(Window::OcclusionState::HIDDEN); + window_b->Hide(); + EXPECT_FALSE(delegate_b->is_expecting_call()); + EXPECT_FALSE(delegate_c->is_expecting_call()); +} + } // namespace aura diff --git a/chromium/ui/aura/window_port.h b/chromium/ui/aura/window_port.h index 46e4c1bb811..a57c5134920 100644 --- a/chromium/ui/aura/window_port.h +++ b/chromium/ui/aura/window_port.h @@ -85,9 +85,6 @@ class AURA_EXPORT WindowPort { virtual std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() = 0; - // Get the current viz::SurfaceId. - virtual viz::SurfaceId GetSurfaceId() const = 0; - // Forces the window to allocate a new viz::LocalSurfaceId for the next // CompositorFrame submission in anticipation of a synchronization operation // that does not involve a resize or a device scale factor change. @@ -98,12 +95,6 @@ class AURA_EXPORT WindowPort { // factor. virtual const viz::LocalSurfaceId& GetLocalSurfaceId() = 0; - // This can return invalid FrameSinkId. - virtual viz::FrameSinkId GetFrameSinkId() const = 0; - - virtual void OnWindowAddedToRootWindow() = 0; - virtual void OnWillRemoveWindowFromRootWindow() = 0; - virtual void OnEventTargetingPolicyChanged() = 0; // See description of function with same name in transient_window_client. diff --git a/chromium/ui/aura/window_port_for_shutdown.cc b/chromium/ui/aura/window_port_for_shutdown.cc index c29e4faad4e..a11a2eed846 100644 --- a/chromium/ui/aura/window_port_for_shutdown.cc +++ b/chromium/ui/aura/window_port_for_shutdown.cc @@ -57,24 +57,12 @@ WindowPortForShutdown::CreateLayerTreeFrameSink() { return nullptr; } -viz::SurfaceId WindowPortForShutdown::GetSurfaceId() const { - return viz::SurfaceId(); -} - void WindowPortForShutdown::AllocateLocalSurfaceId() {} const viz::LocalSurfaceId& WindowPortForShutdown::GetLocalSurfaceId() { return local_surface_id_; } -viz::FrameSinkId WindowPortForShutdown::GetFrameSinkId() const { - return frame_sink_id_; -} - -void WindowPortForShutdown::OnWindowAddedToRootWindow() {} - -void WindowPortForShutdown::OnWillRemoveWindowFromRootWindow() {} - void WindowPortForShutdown::OnEventTargetingPolicyChanged() {} bool WindowPortForShutdown::ShouldRestackTransientChildren() { diff --git a/chromium/ui/aura/window_port_for_shutdown.h b/chromium/ui/aura/window_port_for_shutdown.h index f9b0be555e5..e3d97a5b64d 100644 --- a/chromium/ui/aura/window_port_for_shutdown.h +++ b/chromium/ui/aura/window_port_for_shutdown.h @@ -39,18 +39,13 @@ class WindowPortForShutdown : public WindowPort { int64_t old_value, std::unique_ptr<ui::PropertyData> data) override; std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override; - viz::SurfaceId GetSurfaceId() const override; void AllocateLocalSurfaceId() override; const viz::LocalSurfaceId& GetLocalSurfaceId() override; - viz::FrameSinkId GetFrameSinkId() const override; - void OnWindowAddedToRootWindow() override; - void OnWillRemoveWindowFromRootWindow() override; void OnEventTargetingPolicyChanged() override; bool ShouldRestackTransientChildren() override; private: viz::LocalSurfaceId local_surface_id_; - viz::FrameSinkId frame_sink_id_; DISALLOW_COPY_AND_ASSIGN(WindowPortForShutdown); }; diff --git a/chromium/ui/aura/window_targeter_unittest.cc b/chromium/ui/aura/window_targeter_unittest.cc index d81560ae534..a87f7647241 100644 --- a/chromium/ui/aura/window_targeter_unittest.cc +++ b/chromium/ui/aura/window_targeter_unittest.cc @@ -303,6 +303,6 @@ INSTANTIATE_TEST_CASE_P(/* no prefix */, WindowTargeterTest, ::testing::Values(test::BackendType::CLASSIC, test::BackendType::MUS, - test::BackendType::MUS_HOSTING_VIZ)); + test::BackendType::MASH)); } // namespace aura diff --git a/chromium/ui/aura/window_tree_host.cc b/chromium/ui/aura/window_tree_host.cc index de85e1d8f2d..cbade2495bb 100644 --- a/chromium/ui/aura/window_tree_host.cc +++ b/chromium/ui/aura/window_tree_host.cc @@ -12,6 +12,7 @@ #include "ui/aura/client/capture_client.h" #include "ui/aura/client/cursor_client.h" #include "ui/aura/env.h" +#include "ui/aura/scoped_keyboard_hook.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_port.h" @@ -242,6 +243,13 @@ void WindowTreeHost::Hide() { compositor()->SetVisible(false); } +std::unique_ptr<ScopedKeyboardHook> WindowTreeHost::CaptureSystemKeyEvents( + base::Optional<base::flat_set<int>> keys) { + if (CaptureSystemKeyEventsImpl(std::move(keys))) + return std::make_unique<ScopedKeyboardHook>(weak_factory_.GetWeakPtr()); + return nullptr; +} + //////////////////////////////////////////////////////////////////////////////// // WindowTreeHost, protected: @@ -252,7 +260,8 @@ WindowTreeHost::WindowTreeHost(std::unique_ptr<WindowPort> window_port) : window_(new Window(nullptr, std::move(window_port))), last_cursor_(ui::CursorType::kNull), input_method_(nullptr), - owned_input_method_(false) { + owned_input_method_(false), + weak_factory_(this) { display::Screen::GetScreen()->AddObserver(this); } diff --git a/chromium/ui/aura/window_tree_host.h b/chromium/ui/aura/window_tree_host.h index b83f6494fb1..4a3e90b7b55 100644 --- a/chromium/ui/aura/window_tree_host.h +++ b/chromium/ui/aura/window_tree_host.h @@ -8,11 +8,13 @@ #include <stdint.h> #include <memory> -#include <vector> +#include "base/containers/flat_set.h" #include "base/event_types.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" +#include "base/optional.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "ui/aura/aura_export.h" #include "ui/base/cursor/cursor.h" @@ -39,6 +41,8 @@ class ViewProp; } namespace aura { +class ScopedKeyboardHook; + namespace test { class WindowTreeHostTestApi; } @@ -197,7 +201,15 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate, // Releases OS capture of the root window. virtual void ReleaseCapture() = 0; + // Requests that |keys| be intercepted at the platform level and routed + // directly to the web content. If |keys| is empty, all keys will be + // intercepted. Returns a ScopedKeyboardHook instance which stops capturing + // system key events when destroyed. + std::unique_ptr<ScopedKeyboardHook> CaptureSystemKeyEvents( + base::Optional<base::flat_set<int>> keys); + protected: + friend class ScopedKeyboardHook; friend class TestScreen; // TODO(beng): see if we can remove/consolidate. WindowTreeHost(); @@ -252,6 +264,13 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate, void OnDisplayMetricsChanged(const display::Display& display, uint32_t metrics) override; + // Begins capturing system key events. Returns true if successful. + virtual bool CaptureSystemKeyEventsImpl( + base::Optional<base::flat_set<int>> keys) = 0; + + // Stops capturing system keyboard events. + virtual void ReleaseSystemKeyEventCapture() = 0; + protected: const base::ObserverList<WindowTreeHostObserver>& observers() const { return observers_; @@ -308,6 +327,8 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate, // Set to true if this WindowTreeHost is currently holding pointer moves. bool holding_pointer_moves_ = false; + base::WeakPtrFactory<WindowTreeHost> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(WindowTreeHost); }; diff --git a/chromium/ui/aura/window_tree_host_platform.cc b/chromium/ui/aura/window_tree_host_platform.cc index 9f25b25e22e..43294f6f232 100644 --- a/chromium/ui/aura/window_tree_host_platform.cc +++ b/chromium/ui/aura/window_tree_host_platform.cc @@ -6,6 +6,7 @@ #include <utility> +#include "base/macros.h" #include "base/run_loop.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" @@ -113,6 +114,14 @@ void WindowTreeHostPlatform::ReleaseCapture() { platform_window_->ReleaseCapture(); } +bool WindowTreeHostPlatform::CaptureSystemKeyEventsImpl( + base::Optional<base::flat_set<int>> native_key_codes) { + NOTIMPLEMENTED(); + return false; +} + +void WindowTreeHostPlatform::ReleaseSystemKeyEventCapture() {} + void WindowTreeHostPlatform::SetCursorNative(gfx::NativeCursor cursor) { if (cursor == current_cursor_) return; diff --git a/chromium/ui/aura/window_tree_host_platform.h b/chromium/ui/aura/window_tree_host_platform.h index 13ef6ca1e57..5935d1634b6 100644 --- a/chromium/ui/aura/window_tree_host_platform.h +++ b/chromium/ui/aura/window_tree_host_platform.h @@ -63,6 +63,9 @@ class AURA_EXPORT WindowTreeHostPlatform : public WindowTreeHost, float device_pixel_ratio) override; void OnAcceleratedWidgetDestroyed() override; void OnActivationChanged(bool active) override; + bool CaptureSystemKeyEventsImpl( + base::Optional<base::flat_set<int>> native_key_codes) override; + void ReleaseSystemKeyEventCapture() override; private: gfx::AcceleratedWidget widget_; diff --git a/chromium/ui/aura/window_unittest.cc b/chromium/ui/aura/window_unittest.cc index c9aec7a3001..375e2ddc552 100644 --- a/chromium/ui/aura/window_unittest.cc +++ b/chromium/ui/aura/window_unittest.cc @@ -32,6 +32,7 @@ #include "ui/aura/window_delegate.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_observer.h" +#include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host.h" #include "ui/base/class_property.h" #include "ui/base/hit_test.h" @@ -113,6 +114,7 @@ DEFINE_UI_CLASS_PROPERTY_TYPE(DeletionTestProperty*); namespace aura { namespace test { +namespace { class WindowTest : public AuraTestBaseWithType { public: @@ -140,8 +142,6 @@ class WindowTest : public AuraTestBaseWithType { DISALLOW_COPY_AND_ASSIGN(WindowTest); }; -namespace { - // Used for verifying destruction methods are invoked. class DestroyTrackingDelegateImpl : public TestWindowDelegate { public: @@ -316,8 +316,6 @@ void OffsetBounds(Window* window, int horizontal, int vertical) { window->SetBounds(bounds); } -} // namespace - TEST_P(WindowTest, GetChildById) { std::unique_ptr<Window> w1(CreateTestWindowWithId(1, root_window())); std::unique_ptr<Window> w11(CreateTestWindowWithId(11, w1.get())); @@ -424,18 +422,19 @@ TEST_P(WindowTest, ContainsMouse) { // Tests that the root window gets a valid LocalSurfaceId. TEST_P(WindowTest, RootWindowHasValidLocalSurfaceId) { // When mus is hosting viz, the LocalSurfaceId is sent from mus. - if (GetParam() == BackendType::MUS_HOSTING_VIZ) + if (GetParam() == BackendType::MASH) return; EXPECT_TRUE(root_window()->GetLocalSurfaceId().is_valid()); } TEST_P(WindowTest, WindowEmbeddingClientHasValidLocalSurfaceId) { // When mus is hosting viz, the LocalSurfaceId is sent from mus. - if (GetParam() == BackendType::MUS_HOSTING_VIZ) + if (GetParam() == BackendType::MASH) return; std::unique_ptr<Window> window(CreateTestWindow( SK_ColorWHITE, 1, gfx::Rect(10, 10, 300, 200), root_window())); - window->set_embed_frame_sink_id(viz::FrameSinkId(0, 1)); + test::WindowTestApi(window.get()).DisableFrameSinkRegistration(); + window->SetEmbedFrameSinkId(viz::FrameSinkId(0, 1)); EXPECT_TRUE(window->GetLocalSurfaceId().is_valid()); } @@ -1673,8 +1672,6 @@ TEST_P(WindowTest, Property) { EXPECT_EQ(nullptr, w->GetNativeWindowProperty(native_prop_key)); } -namespace { - class DeletionTestLayoutManager : public LayoutManager { public: explicit DeletionTestLayoutManager(DeletionTracker* tracker) @@ -1696,8 +1693,6 @@ class DeletionTestLayoutManager : public LayoutManager { DISALLOW_COPY_AND_ASSIGN(DeletionTestLayoutManager); }; -} // namespace - TEST_P(WindowTest, DeleteLayoutManagerBeforeOwnedProps) { DeletionTracker tracker; { @@ -2696,8 +2691,6 @@ TEST_P(WindowTest, OwnedByParentFalse) { EXPECT_EQ(NULL, w2->parent()); } -namespace { - // Used By DeleteWindowFromOnWindowDestroyed. Destroys a Window from // OnWindowDestroyed(). class OwningWindowDelegate : public TestWindowDelegate { @@ -2716,8 +2709,6 @@ class OwningWindowDelegate : public TestWindowDelegate { DISALLOW_COPY_AND_ASSIGN(OwningWindowDelegate); }; -} // namespace - // Creates a window with two child windows. When the first child window is // destroyed (WindowDelegate::OnWindowDestroyed) it deletes the second child. // This synthesizes BrowserView and the status bubble. Both are children of the @@ -2737,7 +2728,52 @@ TEST_P(WindowTest, DeleteWindowFromOnWindowDestroyed) { parent.reset(); } -namespace { +// WindowObserver implementation that deletes a window in +// OnWindowVisibilityChanged(). +class DeleteOnVisibilityChangedObserver : public WindowObserver { + public: + // |to_observe| is the Window this is added as an observer to. When + // OnWindowVisibilityChanged() is called |to_delete| is deleted. + explicit DeleteOnVisibilityChangedObserver(Window* to_observe, + Window* to_delete) + : to_observe_(to_observe), to_delete_(to_delete) { + to_observe_->AddObserver(this); + } + ~DeleteOnVisibilityChangedObserver() override { + // OnWindowVisibilityChanged() should have been called. + DCHECK(!to_delete_); + } + + // WindowObserver: + void OnWindowVisibilityChanged(Window* window, bool visible) override { + to_observe_->RemoveObserver(this); + delete to_delete_; + to_delete_ = nullptr; + } + + private: + Window* to_observe_; + Window* to_delete_; + + DISALLOW_COPY_AND_ASSIGN(DeleteOnVisibilityChangedObserver); +}; + +TEST_P(WindowTest, DeleteParentWindowFromOnWindowVisibiltyChanged) { + WindowTracker tracker; + Window* root = CreateTestWindowWithId(0, nullptr); + tracker.Add(root); + Window* child1 = CreateTestWindowWithId(0, root); + tracker.Add(child1); + tracker.Add(CreateTestWindowWithId(0, root)); + + // This deletes |root| (the parent) when OnWindowVisibilityChanged() is + // received by |child1|. + DeleteOnVisibilityChangedObserver deletion_observer(child1, root); + // The Hide() calls trigger deleting |root|, which should delete the whole + // tree. + root->Hide(); + EXPECT_TRUE(tracker.windows().empty()); +} // Used by DelegateNotifiedAsBoundsChange to verify OnBoundsChanged() is // invoked. @@ -2763,8 +2799,6 @@ class BoundsChangeDelegate : public TestWindowDelegate { DISALLOW_COPY_AND_ASSIGN(BoundsChangeDelegate); }; -} // namespace - // Verifies the delegate is notified when the actual bounds of the layer // change. TEST_P(WindowTest, DelegateNotifiedAsBoundsChange) { @@ -2843,8 +2877,6 @@ TEST_P(WindowTest, DelegateNotifiedAsBoundsChangeInHiddenLayer) { EXPECT_NE("0,0 100x100", window->layer()->bounds().ToString()); } -namespace { - // Used by AddChildNotifications to track notification counts. class AddChildNotificationsObserver : public WindowObserver { public: @@ -2871,8 +2903,6 @@ class AddChildNotificationsObserver : public WindowObserver { DISALLOW_COPY_AND_ASSIGN(AddChildNotificationsObserver); }; -} // namespace - // Assertions around when root window notifications are sent. TEST_P(WindowTest, AddChildNotifications) { AddChildNotificationsObserver observer; @@ -3094,8 +3124,6 @@ TEST_P(WindowTest, OnWindowHierarchyChange) { } } -namespace { - class TestLayerAnimationObserver : public ui::LayerAnimationObserver { public: TestLayerAnimationObserver() @@ -3130,8 +3158,6 @@ class TestLayerAnimationObserver : public ui::LayerAnimationObserver { DISALLOW_COPY_AND_ASSIGN(TestLayerAnimationObserver); }; -} // namespace - TEST_P(WindowTest, WindowDestroyCompletesAnimations) { ui::ScopedAnimationDurationScaleMode test_duration_mode( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); @@ -3240,13 +3266,14 @@ INSTANTIATE_TEST_CASE_P(/* no prefix */, WindowTest, ::testing::Values(BackendType::CLASSIC, BackendType::MUS, - BackendType::MUS_HOSTING_VIZ)); + BackendType::MASH)); INSTANTIATE_TEST_CASE_P(/* no prefix */, WindowObserverTest, ::testing::Values(BackendType::CLASSIC, BackendType::MUS, - BackendType::MUS_HOSTING_VIZ)); + BackendType::MASH)); +} // namespace } // namespace test } // namespace aura diff --git a/chromium/ui/base/BUILD.gn b/chromium/ui/base/BUILD.gn index 14011a657ff..b5904fe8e63 100644 --- a/chromium/ui/base/BUILD.gn +++ b/chromium/ui/base/BUILD.gn @@ -65,6 +65,8 @@ component("base") { output_name = "ui_base" sources = [ + "accelerators/media_keys_listener.cc", + "accelerators/media_keys_listener.h", "accelerators/menu_label_accelerator_util_linux.cc", "accelerators/menu_label_accelerator_util_linux.h", "accelerators/platform_accelerator.h", @@ -141,6 +143,8 @@ component("base") { "cocoa/remote_layer_api.mm", "cocoa/scoped_cg_context_smooth_fonts.h", "cocoa/scoped_cg_context_smooth_fonts.mm", + "cocoa/text_services_context_menu.cc", + "cocoa/text_services_context_menu.h", "cocoa/three_part_image.h", "cocoa/three_part_image.mm", "cocoa/tool_tip_base_view.h", @@ -213,7 +217,6 @@ component("base") { "l10n/time_format.h", "layout.cc", "layout.h", - "layout_mac.mm", "material_design/material_design_controller.cc", "material_design/material_design_controller.h", "models/button_menu_item_model.cc", @@ -291,6 +294,8 @@ component("base") { "win/accessibility_misc_utils.cc", "win/accessibility_misc_utils.h", "win/atl_module.h", + "win/direct_manipulation.cc", + "win/direct_manipulation.h", "win/foreground_helper.cc", "win/foreground_helper.h", "win/hidden_window.cc", @@ -369,6 +374,12 @@ component("base") { ] } + if (is_mac) { + sources += [ "accelerators/media_keys_listener_mac.mm" ] + } else { + sources += [ "accelerators/media_keys_listener_stub.cc" ] + } + if (is_win) { sources += [ "touch/touch_device_win.cc" ] } else if (is_android) { @@ -875,10 +886,6 @@ test("ui_base_unittests") { if (use_x11) { sources += [ "ime/composition_text_util_pango_unittest.cc" ] } - if (is_chromeos) { - # These were already removed in the non-chromeos case. - sources -= [ "ime/input_method_chromeos_unittest.cc" ] - } } # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. diff --git a/chromium/ui/base/accelerators/media_keys_listener.cc b/chromium/ui/base/accelerators/media_keys_listener.cc new file mode 100644 index 00000000000..4429e44f6af --- /dev/null +++ b/chromium/ui/base/accelerators/media_keys_listener.cc @@ -0,0 +1,13 @@ +// Copyright 2018 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/accelerators/media_keys_listener.h" + +namespace ui { + +MediaKeysListener::Delegate::~Delegate() = default; + +MediaKeysListener::~MediaKeysListener() = default; + +} // namespace ui diff --git a/chromium/ui/base/accelerators/media_keys_listener.h b/chromium/ui/base/accelerators/media_keys_listener.h new file mode 100644 index 00000000000..5ffeafc5511 --- /dev/null +++ b/chromium/ui/base/accelerators/media_keys_listener.h @@ -0,0 +1,60 @@ +// Copyright 2018 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_ACCELERATORS_MEDIA_KEYS_LISTENER_H_ +#define UI_BASE_ACCELERATORS_MEDIA_KEYS_LISTENER_H_ + +#include <memory> + +#include "base/callback.h" +#include "ui/base/ui_base_export.h" + +namespace ui { + +class Accelerator; + +// Create MediaKeyListener to receive accelerators on media keys. +class UI_BASE_EXPORT MediaKeysListener { + public: + enum class Scope { + kGlobal, // Listener works whenever application in focus or not. + kFocused, // Listener only works whan application has focus. + }; + + enum class MediaKeysHandleResult { + kIgnore, // Ignore the key and continue propagation to other system apps. + kSuppressPropagation, // Handled. Prevent propagation to other system + // apps. + }; + + // Media keys accelerators receiver. + class UI_BASE_EXPORT Delegate { + public: + virtual ~Delegate(); + + // Called on media key event. + // Return result - whether event is handled and propagation of event should + // be suppressed. + virtual MediaKeysHandleResult OnMediaKeysAccelerator( + const Accelerator& accelerator) = 0; + }; + + // Can return nullptr if media keys listening is not implemented. + // Currently implemented only on mac. + static std::unique_ptr<MediaKeysListener> Create(Delegate* delegate, + Scope scope); + + virtual ~MediaKeysListener(); + + // Start receiving media keys events. + virtual void StartWatchingMediaKeys() = 0; + // Stop receiving media keys events. + virtual void StopWatchingMediaKeys() = 0; + // Whether listener started receiving media keys events. + virtual bool IsWatchingMediaKeys() const = 0; +}; + +} // namespace ui + +#endif // UI_BASE_ACCELERATORS_MEDIA_KEYS_LISTENER_H_ diff --git a/chromium/ui/base/accelerators/media_keys_listener_mac.mm b/chromium/ui/base/accelerators/media_keys_listener_mac.mm new file mode 100644 index 00000000000..cd595b0c017 --- /dev/null +++ b/chromium/ui/base/accelerators/media_keys_listener_mac.mm @@ -0,0 +1,214 @@ +// Copyright 2018 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/accelerators/media_keys_listener.h" + +#include <ApplicationServices/ApplicationServices.h> +#include <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> +#include <CoreFoundation/CoreFoundation.h> +#include <IOKit/hidsystem/ev_keymap.h> + +#include "ui/base/accelerators/accelerator.h" + +namespace ui { + +namespace { + +// The media keys subtype. No official docs found, but widely known. +// http://lists.apple.com/archives/cocoa-dev/2007/Aug/msg00499.html +const int kSystemDefinedEventMediaKeysSubtype = 8; + +ui::KeyboardCode MediaKeyCodeToKeyboardCode(int key_code) { + switch (key_code) { + case NX_KEYTYPE_PLAY: + return ui::VKEY_MEDIA_PLAY_PAUSE; + case NX_KEYTYPE_PREVIOUS: + case NX_KEYTYPE_REWIND: + return ui::VKEY_MEDIA_PREV_TRACK; + case NX_KEYTYPE_NEXT: + case NX_KEYTYPE_FAST: + return ui::VKEY_MEDIA_NEXT_TRACK; + } + return ui::VKEY_UNKNOWN; +} + +class MediaKeysListenerImpl : public MediaKeysListener { + public: + MediaKeysListenerImpl(MediaKeysListener::Delegate* delegate, Scope scope); + + ~MediaKeysListenerImpl() override; + + // MediaKeysListener: + void StartWatchingMediaKeys() override; + void StopWatchingMediaKeys() override; + bool IsWatchingMediaKeys() const override; + + private: + // Callback on media key event. + MediaKeysHandleResult OnMediaKeyEvent(int media_key_code); + + // The callback for when an event tap happens. + static CGEventRef EventTapCallback(CGEventTapProxy proxy, + CGEventType type, + CGEventRef event, + void* refcon); + + MediaKeysListener::Delegate* delegate_; + const Scope scope_; + // Event tap for intercepting mac media keys. + CFMachPortRef event_tap_ = nullptr; + CFRunLoopSourceRef event_tap_source_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(MediaKeysListenerImpl); +}; + +MediaKeysListenerImpl::MediaKeysListenerImpl( + MediaKeysListener::Delegate* delegate, + Scope scope) + : delegate_(delegate), scope_(scope) { + CHECK_NE(delegate_, nullptr); +} + +MediaKeysListenerImpl::~MediaKeysListenerImpl() { + if (event_tap_) { + StopWatchingMediaKeys(); + } +} + +void MediaKeysListenerImpl::StartWatchingMediaKeys() { + // Make sure there's no existing event tap. + if (event_tap_) { + return; + } + DCHECK_EQ(event_tap_, nullptr); + DCHECK_EQ(event_tap_source_, nullptr); + + // Add an event tap to intercept the system defined media key events. + event_tap_ = CGEventTapCreate( + kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, + CGEventMaskBit(NX_SYSDEFINED), EventTapCallback, this); + if (event_tap_ == nullptr) { + LOG(ERROR) << "Error: failed to create event tap."; + return; + } + + event_tap_source_ = + CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, event_tap_, 0); + if (event_tap_source_ == nullptr) { + LOG(ERROR) << "Error: failed to create new run loop source."; + return; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), event_tap_source_, + kCFRunLoopCommonModes); +} + +void MediaKeysListenerImpl::StopWatchingMediaKeys() { + if (!event_tap_) { + return; + } + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), event_tap_source_, + kCFRunLoopCommonModes); + // Ensure both event tap and source are initialized. + DCHECK_NE(event_tap_, nullptr); + DCHECK_NE(event_tap_source_, nullptr); + + // Invalidate the event tap. + CFMachPortInvalidate(event_tap_); + CFRelease(event_tap_); + event_tap_ = nullptr; + + // Release the event tap source. + CFRelease(event_tap_source_); + event_tap_source_ = nullptr; +} + +bool MediaKeysListenerImpl::IsWatchingMediaKeys() const { + return event_tap_ != nullptr; +} + +MediaKeysListener::MediaKeysHandleResult MediaKeysListenerImpl::OnMediaKeyEvent( + int media_key_code) { + const ui::KeyboardCode key_code = MediaKeyCodeToKeyboardCode(media_key_code); + // Create an accelerator corresponding to the keyCode. + const ui::Accelerator accelerator(key_code, 0); + return delegate_->OnMediaKeysAccelerator(accelerator); +} + +// Processed events should propagate if they aren't handled by any listeners. +// For events that don't matter, this handler should return as quickly as +// possible. +// Returning event causes the event to propagate to other applications. +// Returning nullptr prevents the event from propagating. +// static +CGEventRef MediaKeysListenerImpl::EventTapCallback(CGEventTapProxy proxy, + CGEventType type, + CGEventRef event, + void* refcon) { + MediaKeysListenerImpl* shortcut_listener = + static_cast<MediaKeysListenerImpl*>(refcon); + + const bool is_active = [NSApp isActive]; + + if (shortcut_listener->scope_ == Scope::kFocused && !is_active) { + return event; + } + + // Handle the timeout case by re-enabling the tap. + if (type == kCGEventTapDisabledByTimeout) { + CGEventTapEnable(shortcut_listener->event_tap_, true); + return event; + } + + // Convert the CGEvent to an NSEvent for access to the data1 field. + NSEvent* ns_event = [NSEvent eventWithCGEvent:event]; + if (ns_event == nil) { + return event; + } + + // Ignore events that are not system defined media keys. + if (type != NX_SYSDEFINED || [ns_event type] != NSSystemDefined || + [ns_event subtype] != kSystemDefinedEventMediaKeysSubtype) { + return event; + } + + NSInteger data1 = [ns_event data1]; + // Ignore media keys that aren't previous, next and play/pause. + // Magical constants are from http://weblog.rogueamoeba.com/2007/09/29/ + int key_code = (data1 & 0xFFFF0000) >> 16; + if (key_code != NX_KEYTYPE_PLAY && key_code != NX_KEYTYPE_NEXT && + key_code != NX_KEYTYPE_PREVIOUS && key_code != NX_KEYTYPE_FAST && + key_code != NX_KEYTYPE_REWIND) { + return event; + } + + int key_flags = data1 & 0x0000FFFF; + bool is_key_pressed = ((key_flags & 0xFF00) >> 8) == 0xA; + + // If the key wasn't pressed (eg. was released), ignore this event. + if (!is_key_pressed) + return event; + + // Now we have a media key that we care about. Send it to the caller. + auto result = shortcut_listener->OnMediaKeyEvent(key_code); + + // Prevent event from proagating to other apps if handled by Chrome. + if (result == MediaKeysHandleResult::kSuppressPropagation) { + return nullptr; + } + + // By default, pass the event through. + return event; +} + +} // namespace + +std::unique_ptr<MediaKeysListener> MediaKeysListener::Create( + MediaKeysListener::Delegate* delegate, + MediaKeysListener::Scope scope) { + return std::make_unique<MediaKeysListenerImpl>(delegate, scope); +} + +} // namespace ui diff --git a/chromium/ui/base/accelerators/media_keys_listener_stub.cc b/chromium/ui/base/accelerators/media_keys_listener_stub.cc new file mode 100644 index 00000000000..67005291850 --- /dev/null +++ b/chromium/ui/base/accelerators/media_keys_listener_stub.cc @@ -0,0 +1,16 @@ +// Copyright 2018 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/accelerators/media_keys_listener.h" + +namespace ui { + +// TODO(ganenkokb): Need implementation for non-mac platforms. +std::unique_ptr<MediaKeysListener> MediaKeysListener::Create( + MediaKeysListener::Delegate* delegate, + MediaKeysListener::Scope scope) { + return nullptr; +} + +} // namespace ui diff --git a/chromium/ui/base/cocoa/text_services_context_menu.cc b/chromium/ui/base/cocoa/text_services_context_menu.cc new file mode 100644 index 00000000000..f7cb1dc3c24 --- /dev/null +++ b/chromium/ui/base/cocoa/text_services_context_menu.cc @@ -0,0 +1,152 @@ +// Copyright 2018 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/cocoa/text_services_context_menu.h" + +#include <utility> + +#include <ApplicationServices/ApplicationServices.h> +#include <CoreAudio/CoreAudio.h> + +#include "base/mac/mac_logging.h" +#include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/strings/grit/ui_strings.h" + +namespace { + +// The speech channel used for speaking. This is shared to check if a speech +// channel is currently speaking. +SpeechChannel g_speech_channel; + +// Returns the TextDirection associated associated with the given BiDi +// |command_id|. +base::i18n::TextDirection GetTextDirectionFromCommandId(int command_id) { + switch (command_id) { + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT: + return base::i18n::UNKNOWN_DIRECTION; + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR: + return base::i18n::LEFT_TO_RIGHT; + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL: + return base::i18n::RIGHT_TO_LEFT; + default: + NOTREACHED(); + return base::i18n::UNKNOWN_DIRECTION; + } +} + +} // namespace + +namespace ui { + +TextServicesContextMenu::TextServicesContextMenu(Delegate* delegate) + : speech_submenu_model_(this), + bidi_submenu_model_(this), + delegate_(delegate) { + DCHECK(delegate); + + speech_submenu_model_.AddItemWithStringId(IDS_SPEECH_START_SPEAKING_MAC, + IDS_SPEECH_START_SPEAKING_MAC); + speech_submenu_model_.AddItemWithStringId(IDS_SPEECH_STOP_SPEAKING_MAC, + IDS_SPEECH_STOP_SPEAKING_MAC); + + bidi_submenu_model_.AddCheckItemWithStringId( + IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT, + IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT); + bidi_submenu_model_.AddCheckItemWithStringId( + IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR, + IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR); + bidi_submenu_model_.AddCheckItemWithStringId( + IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL, + IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL); +} + +void TextServicesContextMenu::SpeakText(const base::string16& text) { + if (IsSpeaking()) + StopSpeaking(); + + if (!g_speech_channel) { + OSErr result = NewSpeechChannel(nullptr, &g_speech_channel); + OSSTATUS_DCHECK(result == noErr, result); + } + + SpeakCFString(g_speech_channel, base::SysUTF16ToCFStringRef(text), nullptr); +} + +void TextServicesContextMenu::StopSpeaking() { + DCHECK(g_speech_channel); + StopSpeechAt(g_speech_channel, kImmediate); + DisposeSpeechChannel(g_speech_channel); + g_speech_channel = nullptr; +} + +bool TextServicesContextMenu::IsSpeaking() { + return SpeechBusy(); +} + +void TextServicesContextMenu::AppendToContextMenu(SimpleMenuModel* model) { + model->AddSeparator(NORMAL_SEPARATOR); + model->AddSubMenuWithStringId(IDS_SPEECH_MAC, IDS_SPEECH_MAC, + &speech_submenu_model_); +} + +void TextServicesContextMenu::AppendEditableItems(SimpleMenuModel* model) { + model->AddSubMenuWithStringId(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU, + IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU, + &bidi_submenu_model_); +} + +bool TextServicesContextMenu::IsCommandIdChecked(int command_id) const { + switch (command_id) { + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT: + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR: + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL: + return delegate_->IsTextDirectionChecked( + GetTextDirectionFromCommandId(command_id)); + case IDS_SPEECH_START_SPEAKING_MAC: + case IDS_SPEECH_STOP_SPEAKING_MAC: + return false; + } + + NOTREACHED(); + return false; +} + +bool TextServicesContextMenu::IsCommandIdEnabled(int command_id) const { + switch (command_id) { + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT: + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR: + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL: + return delegate_->IsTextDirectionEnabled( + GetTextDirectionFromCommandId(command_id)); + case IDS_SPEECH_START_SPEAKING_MAC: + return true; + case IDS_SPEECH_STOP_SPEAKING_MAC: + return IsSpeaking(); + } + + NOTREACHED(); + return false; +} + +void TextServicesContextMenu::ExecuteCommand(int command_id, int event_flags) { + switch (command_id) { + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT: + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR: + case IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL: + delegate_->UpdateTextDirection(GetTextDirectionFromCommandId(command_id)); + break; + case IDS_SPEECH_START_SPEAKING_MAC: + SpeakText(delegate_->GetSelectedText()); + break; + case IDS_SPEECH_STOP_SPEAKING_MAC: + StopSpeaking(); + break; + default: + NOTREACHED(); + } +} + +} // namespace ui
\ No newline at end of file diff --git a/chromium/ui/base/cocoa/text_services_context_menu.h b/chromium/ui/base/cocoa/text_services_context_menu.h new file mode 100644 index 00000000000..2c163d7bee7 --- /dev/null +++ b/chromium/ui/base/cocoa/text_services_context_menu.h @@ -0,0 +1,74 @@ +// Copyright 2018 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_COCOA_TEXT_SERVICES_CONTEXT_MENU_H_ +#define UI_BASE_COCOA_TEXT_SERVICES_CONTEXT_MENU_H_ + +#include "base/i18n/rtl.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "ui/base/models/simple_menu_model.h" +#include "ui/base/ui_base_export.h" + +namespace ui { + +// This class is used to append and handle the Speech and BiDi submenu for the +// context menu. +// TODO (spqchan): Replace the Speech and BiDi logic in RenderViewContextMenu +// with TextServicesContextMenu. +class UI_BASE_EXPORT TextServicesContextMenu + : public SimpleMenuModel::Delegate { + public: + class UI_BASE_EXPORT Delegate { + public: + // Returns the selected text. + virtual base::string16 GetSelectedText() const = 0; + + // Returns true if |direction| should be enabled in the BiDi submenu. + virtual bool IsTextDirectionEnabled( + base::i18n::TextDirection direction) const = 0; + + // Returns true if |direction| should be checked in the BiDi submenu. + virtual bool IsTextDirectionChecked( + base::i18n::TextDirection direction) const = 0; + + // Updates the text direction to |direction|. + virtual void UpdateTextDirection(base::i18n::TextDirection direction) = 0; + }; + + explicit TextServicesContextMenu(Delegate* delegate); + + // Methods for speaking. + static void SpeakText(const base::string16& text); + static void StopSpeaking(); + static bool IsSpeaking(); + + // Appends text service items to |model|. A submenu is added for speech, + // which |this| serves as the delegate for. + void AppendToContextMenu(SimpleMenuModel* model); + + // Appends items to the context menu applicable to editable content. A + // submenu is added for bidirection, which |this| serves as a delegate for. + void AppendEditableItems(SimpleMenuModel* model); + + // SimpleMenuModel::Delegate: + bool IsCommandIdChecked(int command_id) const override; + bool IsCommandIdEnabled(int command_id) const override; + void ExecuteCommand(int command_id, int event_flags) override; + + private: + // Model for the "Speech" submenu. + ui::SimpleMenuModel speech_submenu_model_; + + // Model for the BiDi input submenu. + ui::SimpleMenuModel bidi_submenu_model_; + + Delegate* delegate_; // Weak. + + DISALLOW_COPY_AND_ASSIGN(TextServicesContextMenu); +}; + +} // namespace ui + +#endif // UI_BASE_COCOA_TEXT_SERVICES_CONTEXT_MENU_H_
\ No newline at end of file diff --git a/chromium/ui/base/ime/ime_bridge.cc b/chromium/ui/base/ime/ime_bridge.cc index 7b4e8e23638..e30642b3cb5 100644 --- a/chromium/ui/base/ime/ime_bridge.cc +++ b/chromium/ui/base/ime/ime_bridge.cc @@ -13,23 +13,25 @@ namespace ui { -static IMEBridge* g_ime_bridge = NULL; +static IMEBridge* g_ime_bridge = nullptr; // An implementation of IMEBridge. class IMEBridgeImpl : public IMEBridge { public: #if defined(OS_CHROMEOS) IMEBridgeImpl() - : input_context_handler_(NULL), - engine_handler_(NULL), + : input_context_handler_(nullptr), + engine_handler_(nullptr), + observer_(nullptr), current_input_context_(ui::TEXT_INPUT_TYPE_NONE, ui::TEXT_INPUT_MODE_DEFAULT, 0), - candidate_window_handler_(NULL) {} + candidate_window_handler_(nullptr) {} #else IMEBridgeImpl() - : input_context_handler_(NULL), - engine_handler_(NULL), + : input_context_handler_(nullptr), + engine_handler_(nullptr), + observer_(nullptr), current_input_context_(ui::TEXT_INPUT_TYPE_NONE, ui::TEXT_INPUT_MODE_DEFAULT, 0) {} @@ -70,6 +72,17 @@ class IMEBridgeImpl : public IMEBridge { return current_input_context_; } + // IMEBridge override. + void SetObserver(ui::IMEBridgeObserver* observer) override { + observer_ = observer; + } + + // IMEBridge override. + void MaybeSwitchEngine() override { + if (observer_) + observer_->OnRequestSwitchEngine(); + } + #if defined(OS_CHROMEOS) // IMEBridge override. void SetCandidateWindowHandler( @@ -87,6 +100,7 @@ class IMEBridgeImpl : public IMEBridge { private: IMEInputContextHandlerInterface* input_context_handler_; IMEEngineHandlerInterface* engine_handler_; + IMEBridgeObserver* observer_; IMEEngineHandlerInterface::InputContext current_input_context_; #if defined(OS_CHROMEOS) @@ -111,7 +125,7 @@ void IMEBridge::Initialize() { // static. void IMEBridge::Shutdown() { delete g_ime_bridge; - g_ime_bridge = NULL; + g_ime_bridge = nullptr; } // static. diff --git a/chromium/ui/base/ime/ime_bridge.h b/chromium/ui/base/ime/ime_bridge.h index 5db8bbaa19f..e18c03a27b2 100644 --- a/chromium/ui/base/ime/ime_bridge.h +++ b/chromium/ui/base/ime/ime_bridge.h @@ -7,6 +7,7 @@ #include "base/macros.h" #include "build/build_config.h" +#include "ui/base/ime/ime_bridge_observer.h" #include "ui/base/ime/ime_engine_handler_interface.h" #include "ui/base/ime/ime_input_context_handler_interface.h" #include "ui/base/ime/ui_base_ime_export.h" @@ -63,6 +64,12 @@ class UI_BASE_IME_EXPORT IMEBridge { virtual const IMEEngineHandlerInterface::InputContext& GetCurrentInputContext() const = 0; + // Sets the observer that observes the switching engine event. + virtual void SetObserver(ui::IMEBridgeObserver* observer) = 0; + + // Switches the engine handler upon top level window focus change. + virtual void MaybeSwitchEngine() = 0; + #if defined(OS_CHROMEOS) // Returns current CandidateWindowHandler. This function returns NULL if // current candidate window is not ready to use. diff --git a/chromium/ui/base/ime/ime_bridge_observer.h b/chromium/ui/base/ime/ime_bridge_observer.h new file mode 100644 index 00000000000..a21c5f85a41 --- /dev/null +++ b/chromium/ui/base/ime/ime_bridge_observer.h @@ -0,0 +1,23 @@ +// Copyright 2018 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_IME_BRIDGE_OBSERVER_H_ +#define UI_BASE_IME_IME_BRIDGE_OBSERVER_H_ + +#include "ui/base/ime/ui_base_ime_export.h" + +namespace ui { + +// A interface to . +class UI_BASE_IME_EXPORT IMEBridgeObserver { + public: + virtual ~IMEBridgeObserver() {} + + // Called when requesting to switch the engine handler from ui::InputMethod. + virtual void OnRequestSwitchEngine() = 0; +}; + +} // namespace ui + +#endif // UI_BASE_IME_IME_BRIDGE_OBSERVER_H_ diff --git a/chromium/ui/base/ime/ime_engine_handler_interface.h b/chromium/ui/base/ime/ime_engine_handler_interface.h index 242f1c781d7..3987085386a 100644 --- a/chromium/ui/base/ime/ime_engine_handler_interface.h +++ b/chromium/ui/base/ime/ime_engine_handler_interface.h @@ -71,10 +71,6 @@ class UI_BASE_IME_EXPORT IMEEngineHandlerInterface { // Called when the IME is reset. virtual void Reset() = 0; - // Called when the top-level-window is changed, which could switch the engine - // handler. - virtual void MaybeSwitchEngine() = 0; - // Called when the key event is received. // Actual implementation must call |callback| after key event handling. virtual void ProcessKeyEvent(const KeyEvent& key_event, diff --git a/chromium/ui/base/ime/input_method_base.cc b/chromium/ui/base/ime/input_method_base.cc index 18b5a47bdb4..7d4747b5c05 100644 --- a/chromium/ui/base/ime/input_method_base.cc +++ b/chromium/ui/base/ime/input_method_base.cc @@ -40,11 +40,10 @@ void InputMethodBase::SetDelegate(internal::InputMethodDelegate* delegate) { } void InputMethodBase::OnFocus() { - if (ui::IMEBridge::Get()) { - ui::IMEBridge::Get()->SetInputContextHandler(this); - ui::IMEEngineHandlerInterface* engine = GetEngine(); - if (engine) - engine->MaybeSwitchEngine(); + ui::IMEBridge* bridge = ui::IMEBridge::Get(); + if (bridge) { + bridge->SetInputContextHandler(this); + bridge->MaybeSwitchEngine(); } } diff --git a/chromium/ui/base/ime/input_method_chromeos.cc b/chromium/ui/base/ime/input_method_chromeos.cc index 64cd9cfb893..fba861cd4a9 100644 --- a/chromium/ui/base/ime/input_method_chromeos.cc +++ b/chromium/ui/base/ime/input_method_chromeos.cc @@ -75,6 +75,40 @@ ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEvent( // handled in event rewriter. keyboard->SetCapsLockEnabled(event->IsCapsLockOn()); } + + // For JP106 language input keys, makes sure they can be passed to the app + // so that the VDI web apps can be supported. See https://crbug.com/816341. + // VKEY_CONVERT: Henkan key + // VKEY_NONCONVERT: Muhenkan key + // VKEY_DBE_SBCSCHAR/VKEY_DBE_DBCSCHAR: ZenkakuHankaku key + chromeos::input_method::InputMethodManager::State* state = + manager->GetActiveIMEState().get(); + if (event->type() == ET_KEY_PRESSED && state) { + bool language_input_key = true; + switch (event->key_code()) { + case ui::VKEY_CONVERT: + state->ChangeInputMethodToJpIme(); + break; + case ui::VKEY_NONCONVERT: + state->ChangeInputMethodToJpKeyboard(); + break; + case ui::VKEY_DBE_SBCSCHAR: + case ui::VKEY_DBE_DBCSCHAR: + state->ToggleInputMethodForJpIme(); + break; + default: + language_input_key = false; + break; + } + if (language_input_key) { + // Dispatches the event to app/blink. + // TODO(shuchen): Eventually, the language input keys should be handed + // over to the IME extension to process. And IMF can handle if the IME + // extension didn't handle. + return DispatchKeyEventPostIME( + event, std::make_unique<AckCallback>(std::move(ack_callback))); + } + } } // If |context_| is not usable, then we can only dispatch the key event as is. diff --git a/chromium/ui/base/ime/input_method_chromeos_unittest.cc b/chromium/ui/base/ime/input_method_chromeos_unittest.cc index 0e64f214863..fc127d28125 100644 --- a/chromium/ui/base/ime/input_method_chromeos_unittest.cc +++ b/chromium/ui/base/ime/input_method_chromeos_unittest.cc @@ -16,6 +16,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h" #include "ui/base/ime/chromeos/mock_ime_engine_handler.h" +#include "ui/base/ime/chromeos/mock_input_method_manager.h" #include "ui/base/ime/composition_text.h" #include "ui/base/ime/dummy_text_input_client.h" #include "ui/base/ime/ime_bridge.h" @@ -200,6 +201,64 @@ class SetSurroundingTextVerifier { DISALLOW_COPY_AND_ASSIGN(SetSurroundingTextVerifier); }; +class TestInputMethodManager + : public chromeos::input_method::MockInputMethodManager { + class TestState : public MockInputMethodManager::State { + public: + TestState() { Reset(); } + + // InputMethodManager::State: + void ChangeInputMethodToJpKeyboard() override { + is_jp_kbd_ = true; + is_jp_ime_ = false; + } + void ChangeInputMethodToJpIme() override { + is_jp_kbd_ = false; + is_jp_ime_ = true; + } + void ToggleInputMethodForJpIme() override { + if (!is_jp_ime_) { + is_jp_kbd_ = false; + is_jp_ime_ = true; + } else { + is_jp_kbd_ = true; + is_jp_ime_ = false; + } + } + void Reset() { + is_jp_kbd_ = false; + is_jp_ime_ = false; + } + bool is_jp_kbd() const { return is_jp_kbd_; } + bool is_jp_ime() const { return is_jp_ime_; } + + protected: + ~TestState() override {} + + private: + bool is_jp_kbd_ = false; + bool is_jp_ime_ = false; + + DISALLOW_COPY_AND_ASSIGN(TestState); + }; + + private: + scoped_refptr<TestState> state_; + + public: + TestInputMethodManager() { + state_ = scoped_refptr<TestState>(new TestState()); + } + + TestState* state() { return state_.get(); } + + scoped_refptr<InputMethodManager::State> GetActiveIMEState() override { + return scoped_refptr<InputMethodManager::State>(state_.get()); + } + + DISALLOW_COPY_AND_ASSIGN(TestInputMethodManager); +}; + class InputMethodChromeOSTest : public internal::InputMethodDelegate, public testing::Test, public DummyTextInputClient { @@ -227,6 +286,11 @@ class InputMethodChromeOSTest : public internal::InputMethodDelegate, ime_.reset(new TestableInputMethodChromeOS(this)); ime_->SetFocusedTextInputClient(this); + + // InputMethodManager owns and delete it in InputMethodManager::Shutdown(). + input_method_manager_ = new TestInputMethodManager(); + chromeos::input_method::InputMethodManager::Initialize( + input_method_manager_); } void TearDown() override { @@ -238,6 +302,7 @@ class InputMethodChromeOSTest : public internal::InputMethodDelegate, mock_ime_engine_handler_.reset(); mock_ime_candidate_window_handler_.reset(); IMEBridge::Shutdown(); + chromeos::input_method::InputMethodManager::Shutdown(); ResetFlags(); } @@ -257,9 +322,11 @@ class InputMethodChromeOSTest : public internal::InputMethodDelegate, } void ConfirmCompositionText() override { confirmed_text_ = composition_text_; - composition_text_.Clear(); + composition_text_ = CompositionText(); + } + void ClearCompositionText() override { + composition_text_ = CompositionText(); } - void ClearCompositionText() override { composition_text_.Clear(); } void InsertText(const base::string16& text) override { inserted_text_ = text; } @@ -272,8 +339,7 @@ class InputMethodChromeOSTest : public internal::InputMethodDelegate, bool CanComposeInline() const override { return can_compose_inline_; } gfx::Rect GetCaretBounds() const override { return caret_bounds_; } bool HasCompositionText() const override { - CompositionText empty; - return composition_text_ != empty; + return composition_text_ != CompositionText(); } bool GetTextRange(gfx::Range* range) const override { *range = text_range_; @@ -300,8 +366,8 @@ class InputMethodChromeOSTest : public internal::InputMethodDelegate, dispatched_key_event_ = ui::KeyEvent(ui::ET_UNKNOWN, ui::VKEY_UNKNOWN, ui::EF_NONE); - composition_text_.Clear(); - confirmed_text_.Clear(); + composition_text_ = CompositionText(); + confirmed_text_ = CompositionText(); inserted_text_.clear(); inserted_char_ = 0; inserted_char_flags_ = 0; @@ -342,6 +408,8 @@ class InputMethodChromeOSTest : public internal::InputMethodDelegate, bool stop_propagation_post_ime_; + TestInputMethodManager* input_method_manager_; + DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOSTest); }; @@ -531,12 +599,13 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_NoAttribute) { // If there is no selection, |selection| represents cursor position. EXPECT_EQ(kCursorPos, composition_text.selection.start()); EXPECT_EQ(kCursorPos, composition_text.selection.end()); - // If there is no underline, |underlines| contains one underline and it is + // If there is no underline, |ime_text_spans| contains one underline and it is // whole text underline. - ASSERT_EQ(1UL, composition_text.underlines.size()); - EXPECT_EQ(0UL, composition_text.underlines[0].start_offset); - EXPECT_EQ(kSampleAsciiText.size(), composition_text.underlines[0].end_offset); - EXPECT_FALSE(composition_text.underlines[0].thick); + ASSERT_EQ(1UL, composition_text.ime_text_spans.size()); + EXPECT_EQ(0UL, composition_text.ime_text_spans[0].start_offset); + EXPECT_EQ(kSampleAsciiText.size(), + composition_text.ime_text_spans[0].end_offset); + EXPECT_FALSE(composition_text.ime_text_spans[0].thick); } TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) { @@ -545,9 +614,9 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) { // Set up chromeos composition text with one underline attribute. CompositionText composition_text; composition_text.text = kSampleText; - CompositionUnderline underline(1UL, 4UL, SK_ColorBLACK, false, - SK_ColorTRANSPARENT); - composition_text.underlines.push_back(underline); + ImeTextSpan underline(ImeTextSpan::Type::kComposition, 1UL, 4UL, + SK_ColorBLACK, false, SK_ColorTRANSPARENT); + composition_text.ime_text_spans.push_back(underline); CompositionText composition_text2; ime_->ExtractCompositionText(composition_text, kCursorPos, @@ -556,16 +625,16 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) { // If there is no selection, |selection| represents cursor position. EXPECT_EQ(kCursorPos, composition_text2.selection.start()); EXPECT_EQ(kCursorPos, composition_text2.selection.end()); - ASSERT_EQ(1UL, composition_text2.underlines.size()); + ASSERT_EQ(1UL, composition_text2.ime_text_spans.size()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_offset), - composition_text2.underlines[0].start_offset); + composition_text2.ime_text_spans[0].start_offset); EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_offset), - composition_text2.underlines[0].end_offset); + composition_text2.ime_text_spans[0].end_offset); // Single underline represents as black thin line. - EXPECT_EQ(SK_ColorBLACK, composition_text2.underlines[0].color); - EXPECT_FALSE(composition_text2.underlines[0].thick); + EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color); + EXPECT_FALSE(composition_text2.ime_text_spans[0].thick); EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), - composition_text2.underlines[0].background_color); + composition_text2.ime_text_spans[0].background_color); } TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) { @@ -574,9 +643,9 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) { // Set up chromeos composition text with one underline attribute. CompositionText composition_text; composition_text.text = kSampleText; - CompositionUnderline underline(1UL, 4UL, SK_ColorBLACK, true, - SK_ColorTRANSPARENT); - composition_text.underlines.push_back(underline); + ImeTextSpan underline(ImeTextSpan::Type::kComposition, 1UL, 4UL, + SK_ColorBLACK, true, SK_ColorTRANSPARENT); + composition_text.ime_text_spans.push_back(underline); CompositionText composition_text2; ime_->ExtractCompositionText(composition_text, kCursorPos, @@ -585,16 +654,16 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) { // If there is no selection, |selection| represents cursor position. EXPECT_EQ(kCursorPos, composition_text2.selection.start()); EXPECT_EQ(kCursorPos, composition_text2.selection.end()); - ASSERT_EQ(1UL, composition_text2.underlines.size()); + ASSERT_EQ(1UL, composition_text2.ime_text_spans.size()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_offset), - composition_text2.underlines[0].start_offset); + composition_text2.ime_text_spans[0].start_offset); EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_offset), - composition_text2.underlines[0].end_offset); + composition_text2.ime_text_spans[0].end_offset); // Double underline represents as black thick line. - EXPECT_EQ(SK_ColorBLACK, composition_text2.underlines[0].color); - EXPECT_TRUE(composition_text2.underlines[0].thick); + EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color); + EXPECT_TRUE(composition_text2.ime_text_spans[0].thick); EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), - composition_text2.underlines[0].background_color); + composition_text2.ime_text_spans[0].background_color); } TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) { @@ -603,9 +672,9 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) { // Set up chromeos composition text with one underline attribute. CompositionText composition_text; composition_text.text = kSampleText; - CompositionUnderline underline(1UL, 4UL, SK_ColorRED, false, - SK_ColorTRANSPARENT); - composition_text.underlines.push_back(underline); + ImeTextSpan underline(ImeTextSpan::Type::kComposition, 1UL, 4UL, SK_ColorRED, + false, SK_ColorTRANSPARENT); + composition_text.ime_text_spans.push_back(underline); CompositionText composition_text2; ime_->ExtractCompositionText(composition_text, kCursorPos, @@ -613,14 +682,14 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) { EXPECT_EQ(kSampleText, composition_text2.text); EXPECT_EQ(kCursorPos, composition_text2.selection.start()); EXPECT_EQ(kCursorPos, composition_text2.selection.end()); - ASSERT_EQ(1UL, composition_text2.underlines.size()); + ASSERT_EQ(1UL, composition_text2.ime_text_spans.size()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_offset), - composition_text2.underlines[0].start_offset); + composition_text2.ime_text_spans[0].start_offset); EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_offset), - composition_text2.underlines[0].end_offset); + composition_text2.ime_text_spans[0].end_offset); // Error underline represents as red thin line. - EXPECT_EQ(SK_ColorRED, composition_text2.underlines[0].color); - EXPECT_FALSE(composition_text2.underlines[0].thick); + EXPECT_EQ(SK_ColorRED, composition_text2.ime_text_spans[0].underline_color); + EXPECT_FALSE(composition_text2.ime_text_spans[0].thick); } TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_Selection) { @@ -638,15 +707,15 @@ TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_Selection) { EXPECT_EQ(kSampleText, composition_text2.text); EXPECT_EQ(kCursorPos, composition_text2.selection.start()); EXPECT_EQ(kCursorPos, composition_text2.selection.end()); - ASSERT_EQ(1UL, composition_text2.underlines.size()); + ASSERT_EQ(1UL, composition_text2.ime_text_spans.size()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.start()), - composition_text2.underlines[0].start_offset); + composition_text2.ime_text_spans[0].start_offset); EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.end()), - composition_text2.underlines[0].end_offset); - EXPECT_EQ(SK_ColorBLACK, composition_text2.underlines[0].color); - EXPECT_TRUE(composition_text2.underlines[0].thick); + composition_text2.ime_text_spans[0].end_offset); + EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color); + EXPECT_TRUE(composition_text2.ime_text_spans[0].thick); EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), - composition_text2.underlines[0].background_color); + composition_text2.ime_text_spans[0].background_color); } TEST_F(InputMethodChromeOSTest, @@ -669,15 +738,15 @@ TEST_F(InputMethodChromeOSTest, composition_text2.selection.start()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), composition_text2.selection.end()); - ASSERT_EQ(1UL, composition_text2.underlines.size()); + ASSERT_EQ(1UL, composition_text2.ime_text_spans.size()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.start()), - composition_text2.underlines[0].start_offset); + composition_text2.ime_text_spans[0].start_offset); EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.end()), - composition_text2.underlines[0].end_offset); - EXPECT_EQ(SK_ColorBLACK, composition_text2.underlines[0].color); - EXPECT_TRUE(composition_text2.underlines[0].thick); + composition_text2.ime_text_spans[0].end_offset); + EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color); + EXPECT_TRUE(composition_text2.ime_text_spans[0].thick); EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), - composition_text2.underlines[0].background_color); + composition_text2.ime_text_spans[0].background_color); } TEST_F(InputMethodChromeOSTest, @@ -700,15 +769,15 @@ TEST_F(InputMethodChromeOSTest, composition_text2.selection.start()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), composition_text2.selection.end()); - ASSERT_EQ(1UL, composition_text2.underlines.size()); + ASSERT_EQ(1UL, composition_text2.ime_text_spans.size()); EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.start()), - composition_text2.underlines[0].start_offset); + composition_text2.ime_text_spans[0].start_offset); EXPECT_EQ(GetOffsetInUTF16(kSampleText, composition_text.selection.end()), - composition_text2.underlines[0].end_offset); - EXPECT_EQ(SK_ColorBLACK, composition_text2.underlines[0].color); - EXPECT_TRUE(composition_text2.underlines[0].thick); + composition_text2.ime_text_spans[0].end_offset); + EXPECT_EQ(SK_ColorBLACK, composition_text2.ime_text_spans[0].underline_color); + EXPECT_TRUE(composition_text2.ime_text_spans[0].thick); EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), - composition_text2.underlines[0].background_color); + composition_text2.ime_text_spans[0].background_color); } TEST_F(InputMethodChromeOSTest, SurroundingText_NoSelectionTest) { @@ -973,4 +1042,26 @@ TEST_F(InputMethodChromeOSKeyEventTest, DeadKeyPressTest) { EXPECT_EQ(eventA.time_stamp(), key_event.time_stamp()); } +TEST_F(InputMethodChromeOSKeyEventTest, JP106KeyTest) { + ui::KeyEvent eventConvert(ET_KEY_PRESSED, VKEY_CONVERT, EF_NONE); + ime_->DispatchKeyEvent(&eventConvert); + EXPECT_FALSE(input_method_manager_->state()->is_jp_kbd()); + EXPECT_TRUE(input_method_manager_->state()->is_jp_ime()); + + ui::KeyEvent eventNonConvert(ET_KEY_PRESSED, VKEY_NONCONVERT, EF_NONE); + ime_->DispatchKeyEvent(&eventNonConvert); + EXPECT_TRUE(input_method_manager_->state()->is_jp_kbd()); + EXPECT_FALSE(input_method_manager_->state()->is_jp_ime()); + + ui::KeyEvent eventDbeSbc(ET_KEY_PRESSED, VKEY_DBE_SBCSCHAR, EF_NONE); + ime_->DispatchKeyEvent(&eventDbeSbc); + EXPECT_FALSE(input_method_manager_->state()->is_jp_kbd()); + EXPECT_TRUE(input_method_manager_->state()->is_jp_ime()); + + ui::KeyEvent eventDbeDbc(ET_KEY_PRESSED, VKEY_DBE_DBCSCHAR, EF_NONE); + ime_->DispatchKeyEvent(&eventDbeDbc); + EXPECT_TRUE(input_method_manager_->state()->is_jp_kbd()); + EXPECT_FALSE(input_method_manager_->state()->is_jp_ime()); +} + } // namespace ui diff --git a/chromium/ui/base/l10n/l10n_util_win_unittest.cc b/chromium/ui/base/l10n/l10n_util_win_unittest.cc index 29ab718535d..3dfa8533722 100644 --- a/chromium/ui/base/l10n/l10n_util_win_unittest.cc +++ b/chromium/ui/base/l10n/l10n_util_win_unittest.cc @@ -7,7 +7,7 @@ #include <windows.h> #include "base/command_line.h" -#include "base/win/win_util.h" +#include "base/win/win_client_metrics.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" #include "ui/display/display.h" diff --git a/chromium/ui/base/layout.cc b/chromium/ui/base/layout.cc index c19b1bdac36..29a0e0e6c77 100644 --- a/chromium/ui/base/layout.cc +++ b/chromium/ui/base/layout.cc @@ -10,12 +10,10 @@ #include <cmath> #include <limits> -#include "base/command_line.h" #include "base/logging.h" #include "base/macros.h" #include "build/build_config.h" #include "ui/base/touch/touch_device.h" -#include "ui/base/ui_base_switches.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/gfx/image/image_skia.h" @@ -104,7 +102,6 @@ ScopedSetSupportedScaleFactors::~ScopedSetSupportedScaleFactors() { } // namespace test -#if !defined(OS_MACOSX) float GetScaleFactorForNativeView(gfx::NativeView view) { // A number of unit tests do not setup the screen. if (!display::Screen::GetScreen()) @@ -114,6 +111,5 @@ float GetScaleFactorForNativeView(gfx::NativeView view) { DCHECK(display.is_valid()); return display.device_scale_factor(); } -#endif // !defined(OS_MACOSX) } // namespace ui diff --git a/chromium/ui/base/layout_mac.mm b/chromium/ui/base/layout_mac.mm deleted file mode 100644 index 574a662a688..00000000000 --- a/chromium/ui/base/layout_mac.mm +++ /dev/null @@ -1,37 +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/base/layout.h" - -#import <Cocoa/Cocoa.h> - -#include "base/mac/sdk_forward_declarations.h" -#include "ui/display/display.h" - -namespace { - -float GetScaleFactorScaleForNativeView(gfx::NativeView view) { - if (NSWindow* window = [view window]) { - return [window backingScaleFactor]; - } - - NSArray* screens = [NSScreen screens]; - if (![screens count]) - return 1.0f; - - NSScreen* screen = [screens objectAtIndex:0]; - return [screen backingScaleFactor]; -} - -} // namespace - -namespace ui { - -float GetScaleFactorForNativeView(gfx::NativeView view) { - if (display::Display::HasForceDeviceScaleFactor()) - return display::Display::GetForcedDeviceScaleFactor(); - return GetScaleFactorScaleForNativeView(view); -} - -} // namespace ui diff --git a/chromium/ui/base/material_design/material_design_controller.cc b/chromium/ui/base/material_design/material_design_controller.cc index e475ce84f56..e19300ed6e1 100644 --- a/chromium/ui/base/material_design/material_design_controller.cc +++ b/chromium/ui/base/material_design/material_design_controller.cc @@ -51,6 +51,8 @@ void MaterialDesignController::Initialize() { SetMode(MATERIAL_NORMAL); } else if (switch_value == switches::kTopChromeMDMaterialHybrid) { SetMode(MATERIAL_HYBRID); + } else if (switch_value == switches::kTopChromeMDMaterialTouchOptimized) { + SetMode(MATERIAL_TOUCH_OPTIMIZED); } else if (switch_value == switches::kTopChromeMDMaterialAuto) { #if defined(OS_WIN) // TODO(girard): add support for switching between modes when @@ -81,6 +83,11 @@ bool MaterialDesignController::IsSecondaryUiMaterial() { } // static +bool MaterialDesignController::IsTouchOptimizedUiEnabled() { + return GetMode() == MATERIAL_TOUCH_OPTIMIZED; +} + +// static MaterialDesignController::Mode MaterialDesignController::DefaultMode() { #if defined(OS_CHROMEOS) // If a scan of available devices has already completed, use material-hybrid diff --git a/chromium/ui/base/material_design/material_design_controller.h b/chromium/ui/base/material_design/material_design_controller.h index e498ef2ea1f..731b304ad51 100644 --- a/chromium/ui/base/material_design/material_design_controller.h +++ b/chromium/ui/base/material_design/material_design_controller.h @@ -23,7 +23,9 @@ class UI_BASE_EXPORT MaterialDesignController { // Basic material design. MATERIAL_NORMAL = 0, // Material design targeted at mouse/touch hybrid devices. - MATERIAL_HYBRID = 1 + MATERIAL_HYBRID = 1, + // Material design that is more optimized for touch devices. + MATERIAL_TOUCH_OPTIMIZED = 2 }; // Initializes |mode_|. Must be called before checking |mode_|. @@ -36,6 +38,9 @@ class UI_BASE_EXPORT MaterialDesignController { // should be extended to cover secondary UI. static bool IsSecondaryUiMaterial(); + // Returns true if the touch-optimized UI material design mode is enabled; + static bool IsTouchOptimizedUiEnabled(); + // Returns the per-platform default material design variant. static Mode DefaultMode(); diff --git a/chromium/ui/base/models/menu_model.cc b/chromium/ui/base/models/menu_model.cc index 1b5f6ab0bca..2bed40097fd 100644 --- a/chromium/ui/base/models/menu_model.cc +++ b/chromium/ui/base/models/menu_model.cc @@ -40,6 +40,10 @@ base::string16 MenuModel::GetMinorTextAt(int index) const { return base::string16(); } +const gfx::VectorIcon* MenuModel::GetMinorIconAt(int index) const { + return nullptr; +} + const gfx::FontList* MenuModel::GetLabelFontListAt(int index) const { return NULL; } diff --git a/chromium/ui/base/models/menu_model.h b/chromium/ui/base/models/menu_model.h index 0755f2752f1..605dc1b17e4 100644 --- a/chromium/ui/base/models/menu_model.h +++ b/chromium/ui/base/models/menu_model.h @@ -15,6 +15,7 @@ namespace gfx { class FontList; class Image; +struct VectorIcon; } namespace ui { @@ -65,6 +66,10 @@ class UI_BASE_EXPORT MenuModel { // is rendered to the right of the label and using the font GetLabelFontAt(). virtual base::string16 GetMinorTextAt(int index) const; + // Returns the minor icon of the item at the specified index. The minor icon + // is rendered to the left of the minor text. + virtual const gfx::VectorIcon* GetMinorIconAt(int index) const; + // Returns true if the menu item (label/sublabel/icon) at the specified // index can change over the course of the menu's lifetime. If this function // returns true, the label, sublabel and icon of the menu item will be diff --git a/chromium/ui/base/models/simple_menu_model.cc b/chromium/ui/base/models/simple_menu_model.cc index 377d1eee2db..081f550689f 100644 --- a/chromium/ui/base/models/simple_menu_model.cc +++ b/chromium/ui/base/models/simple_menu_model.cc @@ -12,25 +12,11 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image.h" namespace ui { const int kSeparatorId = -1; -struct SimpleMenuModel::Item { - int command_id; - base::string16 label; - base::string16 sublabel; - base::string16 minor_text; - gfx::Image icon; - ItemType type; - int group_id; - MenuModel* submenu; - ButtonMenuItemModel* button_model; - MenuSeparatorType separator_type; -}; - //////////////////////////////////////////////////////////////////////////////// // SimpleMenuModel::Delegate, public: @@ -83,17 +69,14 @@ bool SimpleMenuModel::Delegate::GetAcceleratorForCommandId( SimpleMenuModel::SimpleMenuModel(Delegate* delegate) : delegate_(delegate), - menu_model_delegate_(NULL), - method_factory_(this) { -} + menu_model_delegate_(nullptr), + method_factory_(this) {} SimpleMenuModel::~SimpleMenuModel() { } void SimpleMenuModel::AddItem(int command_id, const base::string16& label) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR }; - AppendItem(item); + AppendItem(Item(command_id, TYPE_COMMAND, label)); } void SimpleMenuModel::AddItemWithStringId(int command_id, int string_id) { @@ -102,9 +85,7 @@ void SimpleMenuModel::AddItemWithStringId(int command_id, int string_id) { void SimpleMenuModel::AddCheckItem(int command_id, const base::string16& label) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR }; - AppendItem(item); + AppendItem(Item(command_id, TYPE_CHECK, label)); } void SimpleMenuModel::AddCheckItemWithStringId(int command_id, int string_id) { @@ -114,10 +95,9 @@ void SimpleMenuModel::AddCheckItemWithStringId(int command_id, int string_id) { void SimpleMenuModel::AddRadioItem(int command_id, const base::string16& label, int group_id) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_RADIO, group_id, NULL, NULL, - NORMAL_SEPARATOR }; - AppendItem(item); + Item item(command_id, TYPE_RADIO, label); + item.group_id = group_id; + AppendItem(std::move(item)); } void SimpleMenuModel::AddRadioItemWithStringId(int command_id, int string_id, @@ -140,26 +120,24 @@ void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type) { if (separator_type == SPACING_SEPARATOR) NOTIMPLEMENTED(); #endif - Item item = { kSeparatorId, base::string16(), base::string16(), - base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL, - separator_type }; - AppendItem(item); + Item item(kSeparatorId, TYPE_SEPARATOR, base::string16()); + item.separator_type = separator_type; + AppendItem(std::move(item)); } void SimpleMenuModel::AddButtonItem(int command_id, ButtonMenuItemModel* model) { - Item item = { command_id, base::string16(), base::string16(), - base::string16(), gfx::Image(), TYPE_BUTTON_ITEM, -1, NULL, - model, NORMAL_SEPARATOR }; - AppendItem(item); + Item item(command_id, TYPE_BUTTON_ITEM, base::string16()); + item.button_model = model; + AppendItem(std::move(item)); } void SimpleMenuModel::AddSubMenu(int command_id, const base::string16& label, MenuModel* model) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_SUBMENU, -1, model, NULL, NORMAL_SEPARATOR }; - AppendItem(item); + Item item(command_id, TYPE_SUBMENU, label); + item.submenu = model; + AppendItem(std::move(item)); } void SimpleMenuModel::AddSubMenuWithStringId(int command_id, @@ -170,9 +148,7 @@ void SimpleMenuModel::AddSubMenuWithStringId(int command_id, void SimpleMenuModel::InsertItemAt(int index, int command_id, const base::string16& label) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_COMMAND, -1, NULL, NULL, NORMAL_SEPARATOR }; - InsertItemAtIndex(item, index); + InsertItemAtIndex(Item(command_id, TYPE_COMMAND, label), index); } void SimpleMenuModel::InsertItemWithStringIdAt( @@ -187,18 +163,15 @@ void SimpleMenuModel::InsertSeparatorAt(int index, NOTIMPLEMENTED(); } #endif - Item item = { kSeparatorId, base::string16(), base::string16(), - base::string16(), gfx::Image(), TYPE_SEPARATOR, -1, NULL, NULL, - separator_type }; - InsertItemAtIndex(item, index); + Item item(kSeparatorId, TYPE_SEPARATOR, base::string16()); + item.separator_type = separator_type; + InsertItemAtIndex(std::move(item), index); } void SimpleMenuModel::InsertCheckItemAt(int index, int command_id, const base::string16& label) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_CHECK, -1, NULL, NULL, NORMAL_SEPARATOR }; - InsertItemAtIndex(item, index); + InsertItemAtIndex(Item(command_id, TYPE_CHECK, label), index); } void SimpleMenuModel::InsertCheckItemWithStringIdAt( @@ -210,10 +183,9 @@ void SimpleMenuModel::InsertRadioItemAt(int index, int command_id, const base::string16& label, int group_id) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_RADIO, group_id, NULL, NULL, - NORMAL_SEPARATOR }; - InsertItemAtIndex(item, index); + Item item(command_id, TYPE_RADIO, label); + item.group_id = group_id; + InsertItemAtIndex(std::move(item), index); } void SimpleMenuModel::InsertRadioItemWithStringIdAt( @@ -226,10 +198,9 @@ void SimpleMenuModel::InsertSubMenuAt(int index, int command_id, const base::string16& label, MenuModel* model) { - Item item = { command_id, label, base::string16(), base::string16(), - gfx::Image(), TYPE_SUBMENU, -1, model, NULL, - NORMAL_SEPARATOR }; - InsertItemAtIndex(item, index); + Item item(command_id, TYPE_SUBMENU, label); + item.submenu = model; + InsertItemAtIndex(std::move(item), index); } void SimpleMenuModel::InsertSubMenuWithStringIdAt( @@ -258,6 +229,11 @@ void SimpleMenuModel::SetMinorText(int index, items_[ValidateItemIndex(index)].minor_text = minor_text; } +void SimpleMenuModel::SetMinorIcon(int index, + const gfx::VectorIcon& minor_icon) { + items_[ValidateItemIndex(index)].minor_icon = &minor_icon; +} + void SimpleMenuModel::Clear() { items_.clear(); MenuItemsChanged(); @@ -317,6 +293,10 @@ base::string16 SimpleMenuModel::GetMinorTextAt(int index) const { return items_[ValidateItemIndex(index)].minor_text; } +const gfx::VectorIcon* SimpleMenuModel::GetMinorIconAt(int index) const { + return items_[ValidateItemIndex(index)].minor_icon; +} + bool SimpleMenuModel::IsItemDynamicAt(int index) const { if (delegate_) return delegate_->IsItemForCommandIdDynamic(GetCommandIdAt(index)); @@ -433,21 +413,27 @@ void SimpleMenuModel::MenuItemsChanged() { //////////////////////////////////////////////////////////////////////////////// // SimpleMenuModel, Private: +SimpleMenuModel::Item::Item(Item&&) = default; +SimpleMenuModel::Item::Item(int command_id, ItemType type, base::string16 label) + : command_id(command_id), type(type), label(label) {} +SimpleMenuModel::Item& SimpleMenuModel::Item::operator=(Item&&) = default; +SimpleMenuModel::Item::~Item() = default; + int SimpleMenuModel::ValidateItemIndex(int index) const { CHECK_GE(index, 0); CHECK_LT(static_cast<size_t>(index), items_.size()); return index; } -void SimpleMenuModel::AppendItem(const Item& item) { +void SimpleMenuModel::AppendItem(Item item) { ValidateItem(item); - items_.push_back(item); + items_.push_back(std::move(item)); MenuItemsChanged(); } -void SimpleMenuModel::InsertItemAtIndex(const Item& item, int index) { +void SimpleMenuModel::InsertItemAtIndex(Item item, int index) { ValidateItem(item); - items_.insert(items_.begin() + index, item); + items_.insert(items_.begin() + index, std::move(item)); MenuItemsChanged(); } diff --git a/chromium/ui/base/models/simple_menu_model.h b/chromium/ui/base/models/simple_menu_model.h index 5f05e870d65..72bf5e0907e 100644 --- a/chromium/ui/base/models/simple_menu_model.h +++ b/chromium/ui/base/models/simple_menu_model.h @@ -13,10 +13,7 @@ #include "base/strings/string16.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/models/menu_model.h" - -namespace gfx { -class Image; -} +#include "ui/gfx/image/image.h" namespace ui { @@ -131,6 +128,9 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel { // Sets the minor text for the item at |index|. void SetMinorText(int index, const base::string16& minor_text); + // Sets the minor icon for the item at |index|. + void SetMinorIcon(int index, const gfx::VectorIcon& minor_icon); + // Clears all items. Note that it does not free MenuModel of submenu. void Clear(); @@ -147,6 +147,7 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel { base::string16 GetLabelAt(int index) const override; base::string16 GetSublabelAt(int index) const override; base::string16 GetMinorTextAt(int index) const override; + const gfx::VectorIcon* GetMinorIconAt(int index) const override; bool IsItemDynamicAt(int index) const override; bool GetAcceleratorAt(int index, ui::Accelerator* accelerator) const override; bool IsItemCheckedAt(int index) const override; @@ -179,7 +180,24 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel { virtual void MenuItemsChanged(); private: - struct Item; + struct Item { + Item(Item&&); + Item(int command_id, ItemType type, base::string16 label); + Item& operator=(Item&&); + ~Item(); + + int command_id = 0; + ItemType type = TYPE_COMMAND; + base::string16 label; + base::string16 sublabel; + base::string16 minor_text; + const gfx::VectorIcon* minor_icon = nullptr; + gfx::Image icon; + int group_id = -1; + MenuModel* submenu = nullptr; + ButtonMenuItemModel* button_model = nullptr; + MenuSeparatorType separator_type = NORMAL_SEPARATOR; + }; typedef std::vector<Item> ItemVector; @@ -190,8 +208,8 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel { int ValidateItemIndex(int index) const; // Functions for inserting items into |items_|. - void AppendItem(const Item& item); - void InsertItemAtIndex(const Item& item, int index); + void AppendItem(Item item); + void InsertItemAtIndex(Item item, int index); void ValidateItem(const Item& item); // Notify the delegate that the menu is closed. diff --git a/chromium/ui/base/mojo/DEPS b/chromium/ui/base/mojo/DEPS index 4c418e20ff5..e0c12f73402 100644 --- a/chromium/ui/base/mojo/DEPS +++ b/chromium/ui/base/mojo/DEPS @@ -1,4 +1,4 @@ include_rules = [ "+mojo/public/cpp/bindings", - "+third_party/WebKit/common/clipboard/clipboard.mojom-shared.h" + "+third_party/WebKit/public/mojom/clipboard/clipboard.mojom-shared.h" ] diff --git a/chromium/ui/base/mojo/clipboard.typemap b/chromium/ui/base/mojo/clipboard.typemap index 1063cb3671f..ebd328b5ad3 100644 --- a/chromium/ui/base/mojo/clipboard.typemap +++ b/chromium/ui/base/mojo/clipboard.typemap @@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -mojom = "//third_party/WebKit/common/clipboard/clipboard.mojom" +mojom = "//third_party/WebKit/public/mojom/clipboard/clipboard.mojom" public_headers = [ "//ui/base/clipboard/clipboard_types.h" ] traits_headers = [ "//ui/base/mojo/clipboard_struct_traits.h" ] deps = [ diff --git a/chromium/ui/base/mojo/clipboard_struct_traits.h b/chromium/ui/base/mojo/clipboard_struct_traits.h index 81c618e3911..280a1f2bc97 100644 --- a/chromium/ui/base/mojo/clipboard_struct_traits.h +++ b/chromium/ui/base/mojo/clipboard_struct_traits.h @@ -5,7 +5,7 @@ #ifndef UI_BASE_MOJO_CLIPBOARD_STRUCT_TRAITS_H_ #define UI_BASE_MOJO_CLIPBOARD_STRUCT_TRAITS_H_ -#include "third_party/WebKit/common/clipboard/clipboard.mojom-shared.h" +#include "third_party/WebKit/public/mojom/clipboard/clipboard.mojom-shared.h" #include "ui/base/clipboard/clipboard_types.h" namespace mojo { diff --git a/chromium/ui/base/resource/resource_bundle.cc b/chromium/ui/base/resource/resource_bundle.cc index 56101888f27..3bfd3cd883b 100644 --- a/chromium/ui/base/resource/resource_bundle.cc +++ b/chromium/ui/base/resource/resource_bundle.cc @@ -74,25 +74,6 @@ const char kPakFileExtension[] = ".pak"; ResourceBundle* g_shared_instance_ = NULL; -#if defined(OS_ANDROID) -// Returns the scale factor closest to |scale| from the full list of factors. -// Note that it does NOT rely on the list of supported scale factors. -// Finding the closest match is inefficient and shouldn't be done frequently. -ScaleFactor FindClosestScaleFactorUnsafe(float scale) { - float smallest_diff = std::numeric_limits<float>::max(); - ScaleFactor closest_match = SCALE_FACTOR_100P; - for (int i = SCALE_FACTOR_100P; i < NUM_SCALE_FACTORS; ++i) { - const ScaleFactor scale_factor = static_cast<ScaleFactor>(i); - float diff = std::abs(GetScaleForScaleFactor(scale_factor) - scale); - if (diff < smallest_diff) { - closest_match = scale_factor; - smallest_diff = diff; - } - } - return closest_match; -} -#endif // OS_ANDROID - base::FilePath GetResourcesPakFilePath(const std::string& pak_name) { base::FilePath path; if (PathService::Get(base::DIR_MODULE, &path)) @@ -761,22 +742,7 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) { DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; g_shared_instance_ = new ResourceBundle(delegate); static std::vector<ScaleFactor> supported_scale_factors; -#if !defined(OS_IOS) - // On platforms other than iOS, 100P is always a supported scale factor. - // For Windows we have a separate case in this function. - supported_scale_factors.push_back(SCALE_FACTOR_100P); -#endif -#if defined(OS_ANDROID) - float display_density; - if (display::Display::HasForceDeviceScaleFactor()) { - display_density = display::Display::GetForcedDeviceScaleFactor(); - } else { - display_density = GetPrimaryDisplayScale(); - } - const ScaleFactor closest = FindClosestScaleFactorUnsafe(display_density); - if (closest != SCALE_FACTOR_100P) - supported_scale_factors.push_back(closest); -#elif defined(OS_IOS) +#if defined(OS_IOS) display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); if (display.device_scale_factor() > 2.0) { DCHECK_EQ(3.0, display.device_scale_factor()); @@ -787,9 +753,14 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) { } else { supported_scale_factors.push_back(SCALE_FACTOR_100P); } -#elif defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_WIN) +#else + // On platforms other than iOS, 100P is always a supported scale factor. + // For Windows we have a separate case in this function. + supported_scale_factors.push_back(SCALE_FACTOR_100P); +#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_WIN) supported_scale_factors.push_back(SCALE_FACTOR_200P); #endif +#endif ui::SetSupportedScaleFactors(supported_scale_factors); } diff --git a/chromium/ui/base/resource/resource_bundle_android.cc b/chromium/ui/base/resource/resource_bundle_android.cc index 0923b6fd6a3..a91fdabe964 100644 --- a/chromium/ui/base/resource/resource_bundle_android.cc +++ b/chromium/ui/base/resource/resource_bundle_android.cc @@ -211,9 +211,4 @@ std::string GetPathForAndroidLocalePakWithinApk(const std::string& locale) { return base::android::ConvertJavaStringToUTF8(env, ret.obj()); } -float GetPrimaryDisplayScale() { - return Java_ResourceBundle_getPrimaryDisplayScale( - base::android::AttachCurrentThread()); -} - } // namespace ui diff --git a/chromium/ui/base/ui_base_features.cc b/chromium/ui/base/ui_base_features.cc index f6be5b193e0..3e1850d3f45 100644 --- a/chromium/ui/base/ui_base_features.cc +++ b/chromium/ui/base/ui_base_features.cc @@ -4,19 +4,69 @@ #include "ui/base/ui_base_features.h" +#include "ui/base/ui_base_switches_util.h" + +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#endif + namespace features { +// Enables the floating virtual keyboard behavior. +const base::Feature kEnableFloatingVirtualKeyboard = { + "enable-floating-virtual-keyboard", base::FEATURE_DISABLED_BY_DEFAULT}; + +// Applies the material design mode to elements throughout Chrome (not just top +// Chrome). +const base::Feature kSecondaryUiMd = {"SecondaryUiMd", +// Enabled by default on Windows, Mac and Desktop Linux. +// http://crbug.com/775847. +#if defined(OS_WIN) || defined(OS_MACOSX) || \ + (defined(OS_LINUX) && !defined(OS_CHROMEOS)) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; + +const base::Feature kTouchableAppContextMenu = { + "EnableTouchableAppContextMenu", base::FEATURE_DISABLED_BY_DEFAULT}; + +bool IsTouchableAppContextMenuEnabled() { + return base::FeatureList::IsEnabled(kTouchableAppContextMenu) || + switches::IsTouchableAppContextMenuEnabled(); +} + #if defined(OS_WIN) // Enables stylus appearing as touch when in contact with digitizer. const base::Feature kDirectManipulationStylus = { "DirectManipulationStylus", base::FEATURE_ENABLED_BY_DEFAULT}; + +// Enables using WM_POINTER instead of WM_TOUCH for touch events. +const base::Feature kPointerEventsForTouch = {"PointerEventsForTouch", + base::FEATURE_ENABLED_BY_DEFAULT}; + +bool IsUsingWMPointerForTouch() { + return base::win::GetVersion() >= base::win::VERSION_WIN8 && + base::FeatureList::IsEnabled(kPointerEventsForTouch); +} #endif // defined(OS_WIN) -// Applies the material design mode to elements throughout Chrome (not just top -// Chrome). -const base::Feature kSecondaryUiMd = {"SecondaryUiMd", - // Disabled for M65 on all platforms. - // http://crbug.com/805776. - base::FEATURE_DISABLED_BY_DEFAULT}; +// Used to have ash run in its own process. This implicitly turns on the +// WindowService. That is, if this is set IsMusEnabled() returns true. +const base::Feature kMash = {"Mash", base::FEATURE_DISABLED_BY_DEFAULT}; + +// Used to control the mus service (aka the UI service). This makes mus run in +// process. +const base::Feature kMus = {"Mus", base::FEATURE_DISABLED_BY_DEFAULT}; + +bool IsMusEnabled() { +#if defined(USE_AURA) + return base::FeatureList::IsEnabled(features::kMus) || + base::FeatureList::IsEnabled(features::kMash); +#else + return false; +#endif +} } // namespace features diff --git a/chromium/ui/base/ui_base_features.h b/chromium/ui/base/ui_base_features.h index 191fc9ef391..acff7278164 100644 --- a/chromium/ui/base/ui_base_features.h +++ b/chromium/ui/base/ui_base_features.h @@ -11,11 +11,32 @@ namespace features { +// Keep sorted! +UI_BASE_EXPORT extern const base::Feature kEnableFloatingVirtualKeyboard; +UI_BASE_EXPORT extern const base::Feature kSecondaryUiMd; +UI_BASE_EXPORT extern const base::Feature kTouchableAppContextMenu; + +UI_BASE_EXPORT bool IsTouchableAppContextMenuEnabled(); + #if defined(OS_WIN) UI_BASE_EXPORT extern const base::Feature kDirectManipulationStylus; +UI_BASE_EXPORT extern const base::Feature kPointerEventsForTouch; + +// Returns true if the system should use WM_POINTER events for touch events. +UI_BASE_EXPORT bool IsUsingWMPointerForTouch(); #endif // defined(OS_WIN) -UI_BASE_EXPORT extern const base::Feature kSecondaryUiMd; +// TODO(sky): rename this to something that better conveys what it means. +UI_BASE_EXPORT extern const base::Feature kMash; +// WARNING: generally you should only use this in tests to enable the feature. +// Outside of tests use IsMusEnabled() to detect if mus is enabled. +// TODO(sky): rename this to kWindowService. +UI_BASE_EXPORT extern const base::Feature kMus; + +// Returns true if mus (the Window Service) is enabled. +// NOTE: this returns true if either kMus or kMash is specified. +// TODO(sky): rename this to IsWindowServiceEnabled(). +UI_BASE_EXPORT bool IsMusEnabled(); } // namespace features diff --git a/chromium/ui/base/ui_base_switches.cc b/chromium/ui/base/ui_base_switches.cc index 9f52ad1807c..254140166bc 100644 --- a/chromium/ui/base/ui_base_switches.cc +++ b/chromium/ui/base/ui_base_switches.cc @@ -4,14 +4,6 @@ #include "ui/base/ui_base_switches.h" -namespace features { - -// Enables the floating virtual keyboard behavior. -const base::Feature kEnableFloatingVirtualKeyboard = { - "enable-floating-virtual-keyboard", base::FEATURE_DISABLED_BY_DEFAULT}; - -} // namespace features - namespace switches { #if defined(OS_MACOSX) && !defined(OS_IOS) @@ -45,6 +37,10 @@ const char kDisableTouchDragDrop[] = "disable-touch-drag-drop"; // Enables touch event based drag and drop. const char kEnableTouchDragDrop[] = "enable-touch-drag-drop"; +// Enables touchable app context menus and notification indicators. +const char kEnableTouchableAppContextMenu[] = + "enable-touchable-app-context-menus"; + // Forces high-contrast mode in native UI drawing, regardless of system // settings. Note that this has limited effect on Windows: only Aura colors will // be switched to high contrast, not other system colors. @@ -78,6 +74,10 @@ const char kTopChromeMDMaterialAuto[] = "material-auto"; // mouse/touch hybrid devices. const char kTopChromeMDMaterialHybrid[] = "material-hybrid"; +// Material design mode that is more optimized for touch devices for the +// |kTopChromeMD| switch. +const char kTopChromeMDMaterialTouchOptimized[] = "material-touch-optimized"; + // Classic, non-material, mode for the |kTopChromeMD| switch. const char kTopChromeMDNonMaterial[] = "non-material"; @@ -96,9 +96,6 @@ const char kUIDisablePartialSwap[] = "ui-disable-partial-swap"; // Red: Overdrawn four or more times. const char kShowOverdrawFeedback[] = "show-overdraw-feedback"; -// Use draw occlusion to skip draw quads when they are not shown on screen. -const char kEnableDrawOcclusion[] = "enable-draw-occlusion"; - // Use SkiaRenderer instead of GLRenderer for direct rendering. const char kUseSkiaRenderer[] = "use-skia-renderer"; @@ -120,14 +117,4 @@ const char kSlowDownCompositingScaleFactor[] = // Tint GL-composited color. const char kTintGlCompositedContent[] = "tint-gl-composited-content"; -#if defined(USE_AURA) -// Used to enable the mus service (aka the UI service). This makes mus run in -// process. It is also used to notify the clients that the UI service is being -// used. -const char kMus[] = "mus"; - -// If set mus is hosting Viz. Only applicable is kMus if specified. -const char kMusHostingViz[] = "mus-hosting-viz"; -#endif - } // namespace switches diff --git a/chromium/ui/base/ui_base_switches.h b/chromium/ui/base/ui_base_switches.h index 6269678a013..2ce580331e3 100644 --- a/chromium/ui/base/ui_base_switches.h +++ b/chromium/ui/base/ui_base_switches.h @@ -7,16 +7,8 @@ #ifndef UI_BASE_UI_BASE_SWITCHES_H_ #define UI_BASE_UI_BASE_SWITCHES_H_ -#include "base/feature_list.h" #include "build/build_config.h" #include "ui/base/ui_base_export.h" -#include "ui/base/ui_features.h" - -namespace features { - -UI_BASE_EXPORT extern const base::Feature kEnableFloatingVirtualKeyboard; - -} // namespace features namespace switches { @@ -31,8 +23,8 @@ UI_BASE_EXPORT extern const char kDisableCompositedAntialiasing[]; UI_BASE_EXPORT extern const char kDisableDwmComposition[]; UI_BASE_EXPORT extern const char kDisableTouchAdjustment[]; UI_BASE_EXPORT extern const char kDisableTouchDragDrop[]; -UI_BASE_EXPORT extern const char kEnableDrawOcclusion[]; UI_BASE_EXPORT extern const char kEnableTouchDragDrop[]; +UI_BASE_EXPORT extern const char kEnableTouchableAppContextMenu[]; UI_BASE_EXPORT extern const char kForceHighContrast[]; UI_BASE_EXPORT extern const char kLang[]; UI_BASE_EXPORT extern const char kMaterialDesignInkDropAnimationSpeed[]; @@ -45,6 +37,7 @@ UI_BASE_EXPORT extern const char kTopChromeMD[]; UI_BASE_EXPORT extern const char kTopChromeMDMaterial[]; UI_BASE_EXPORT extern const char kTopChromeMDMaterialAuto[]; UI_BASE_EXPORT extern const char kTopChromeMDMaterialHybrid[]; +UI_BASE_EXPORT extern const char kTopChromeMDMaterialTouchOptimized[]; UI_BASE_EXPORT extern const char kTopChromeMDNonMaterial[]; UI_BASE_EXPORT extern const char kUIDisablePartialSwap[]; UI_BASE_EXPORT extern const char kUseSkiaRenderer[]; @@ -53,11 +46,6 @@ UI_BASE_EXPORT extern const char kUseSkiaRenderer[]; UI_BASE_EXPORT extern const char kDisallowNonExactResourceReuse[]; UI_BASE_EXPORT extern const char kMangleLocalizedStrings[]; -#if defined(USE_AURA) -UI_BASE_EXPORT extern const char kMus[]; -UI_BASE_EXPORT extern const char kMusHostingViz[]; -#endif - } // namespace switches #endif // UI_BASE_UI_BASE_SWITCHES_H_ diff --git a/chromium/ui/base/ui_base_switches_util.cc b/chromium/ui/base/ui_base_switches_util.cc index 92019a32a89..ad8161db43d 100644 --- a/chromium/ui/base/ui_base_switches_util.cc +++ b/chromium/ui/base/ui_base_switches_util.cc @@ -13,21 +13,16 @@ namespace switches { bool IsTouchDragDropEnabled() { #if defined(OS_CHROMEOS) || defined(OS_ANDROID) return !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableTouchDragDrop); + kDisableTouchDragDrop); #else return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTouchDragDrop); + kEnableTouchDragDrop); #endif } -bool IsMusHostingViz() { -#if defined(USE_AURA) - auto* cmd = base::CommandLine::ForCurrentProcess(); - return cmd->HasSwitch(switches::kMus) && - cmd->HasSwitch(switches::kMusHostingViz); -#else - return false; -#endif +bool IsTouchableAppContextMenuEnabled() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + kEnableTouchableAppContextMenu); } } // namespace switches diff --git a/chromium/ui/base/ui_base_switches_util.h b/chromium/ui/base/ui_base_switches_util.h index 70ba67038e3..f84ed94f36a 100644 --- a/chromium/ui/base/ui_base_switches_util.h +++ b/chromium/ui/base/ui_base_switches_util.h @@ -12,9 +12,9 @@ namespace switches { UI_BASE_EXPORT bool IsLinkDisambiguationPopupEnabled(); UI_BASE_EXPORT bool IsTouchDragDropEnabled(); -// Returns whether mus is hosting viz. Mus is hosting viz only if -// --mus-hosting-viz is set. -UI_BASE_EXPORT bool IsMusHostingViz(); +// Returns whether the touchable app context menu switch has been set. Prefer +// features::IsTouchableAppContextMenuEnabled(). +UI_BASE_EXPORT bool IsTouchableAppContextMenuEnabled(); } // namespace switches diff --git a/chromium/ui/base/ui_features.gni b/chromium/ui/base/ui_features.gni index 708a8f86fd8..806ef9505ad 100644 --- a/chromium/ui/base/ui_features.gni +++ b/chromium/ui/base/ui_features.gni @@ -17,8 +17,8 @@ declare_args() { # Whether the message center should be included for displaying notifications. enable_message_center = is_win || is_mac || is_linux || is_chromeos - # Set to true to if mus (aka the UI service) is enabled. Use --mus (or --mash - # in chrome code) to start in mus/mash. + # Set to true to if mus (aka the UI service) is enabled. Use the features kMus + # (or kMash in chrome code) to start in mus/mash. enable_mus = is_chromeos # Optimize parts of Chrome's UI written with web technologies (HTML/CSS/JS) diff --git a/chromium/ui/gfx/win/direct_manipulation.cc b/chromium/ui/base/win/direct_manipulation.cc index 73084992d12..78f19277727 100644 --- a/chromium/ui/gfx/win/direct_manipulation.cc +++ b/chromium/ui/base/win/direct_manipulation.cc @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/gfx/win/direct_manipulation.h" +#include "ui/base/win/direct_manipulation.h" #include <objbase.h> #include "base/win/windows_version.h" -namespace gfx { +namespace ui { namespace win { // static @@ -17,7 +17,7 @@ DirectManipulationHelper::CreateInstance() { // TODO(dtapuska): Do not create a DirectManipulationHelper on any windows // versions as it only causes issues. High Precision Touchpad events seem to // always be sent to apps with recent Windows 10 versions. This class should - // eventually be removed. See crbug.com/647038. + // eventually be removed. See https://crbug.com/647038. return nullptr; } @@ -60,14 +60,14 @@ void DirectManipulationHelper::Initialize(HWND window) { // Enable the desired configuration for each viewport. // DIRECTMANIPULATION_CONFIGURATION configuration = - DIRECTMANIPULATION_CONFIGURATION_INTERACTION - | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X - | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y - | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA - | DIRECTMANIPULATION_CONFIGURATION_RAILS_X - | DIRECTMANIPULATION_CONFIGURATION_RAILS_Y - | DIRECTMANIPULATION_CONFIGURATION_SCALING - | DIRECTMANIPULATION_CONFIGURATION_SCALING_INERTIA; + DIRECTMANIPULATION_CONFIGURATION_INTERACTION | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA | + DIRECTMANIPULATION_CONFIGURATION_RAILS_X | + DIRECTMANIPULATION_CONFIGURATION_RAILS_Y | + DIRECTMANIPULATION_CONFIGURATION_SCALING | + DIRECTMANIPULATION_CONFIGURATION_SCALING_INERTIA; hr = view_port_outer_->ActivateConfiguration(configuration); CHECK(SUCCEEDED(hr)); @@ -103,9 +103,11 @@ void DirectManipulationHelper::Deactivate(HWND window) { manager_->Deactivate(window); } -void DirectManipulationHelper:: HandleMouseWheel(HWND window, UINT message, - WPARAM w_param, LPARAM l_param) { - MSG msg = { window, message, w_param, l_param}; +void DirectManipulationHelper::HandleMouseWheel(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param) { + MSG msg = {window, message, w_param, l_param}; HRESULT hr = view_port_outer_->SetContact(DIRECTMANIPULATION_MOUSEFOCUS); if (SUCCEEDED(hr)) { @@ -116,4 +118,4 @@ void DirectManipulationHelper:: HandleMouseWheel(HWND window, UINT message, } } // namespace win. -} // namespace gfx. +} // namespace ui. diff --git a/chromium/ui/gfx/win/direct_manipulation.h b/chromium/ui/base/win/direct_manipulation.h index 155b40b7d09..af7ad807f2e 100644 --- a/chromium/ui/gfx/win/direct_manipulation.h +++ b/chromium/ui/base/win/direct_manipulation.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_GFX_WIN_DIRECT_MANIPULATION_H_ -#define UI_GFX_WIN_DIRECT_MANIPULATION_H_ +#ifndef UI_WIN_DIRECT_MANIPULATION_H_ +#define UI_WIN_DIRECT_MANIPULATION_H_ #include <directmanipulation.h> #include <wrl/client.h> @@ -11,10 +11,10 @@ #include <memory> #include "base/macros.h" +#include "ui/base/ui_base_export.h" #include "ui/gfx/geometry/rect.h" -#include "ui/gfx/gfx_export.h" -namespace gfx { +namespace ui { namespace win { // Windows 10 provides a new API called Direct Manipulation which generates @@ -39,7 +39,7 @@ namespace win { // Direct Manipulation consumer. We don't rely on Direct manipulation // to do the smooth scrolling in the background thread as documented on // msdn. -class GFX_EXPORT DirectManipulationHelper { +class UI_BASE_EXPORT DirectManipulationHelper { public: // Creates an instance of this class if Direct Manipulation is enabled on // the platform. If not returns NULL. @@ -63,8 +63,10 @@ class GFX_EXPORT DirectManipulationHelper { // Passes the WM_MOUSEWHEEL messages to Direct Manipulation. This is for // logistics purposes. - void HandleMouseWheel(HWND window, UINT message, WPARAM w_param, - LPARAM l_param); + void HandleMouseWheel(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param); ~DirectManipulationHelper(); @@ -81,6 +83,6 @@ class GFX_EXPORT DirectManipulationHelper { }; } // namespace win -} // namespace gfx +} // namespace ui -#endif // UI_GFX_WIN_DIRECT_MANIPULATION_H_ +#endif // UI_WIN_DIRECT_MANIPULATION_H_ diff --git a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc new file mode 100644 index 00000000000..bbce7bda6eb --- /dev/null +++ b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc @@ -0,0 +1,379 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/win/osk_display_manager.h" + +#include <windows.h> +#include <shellapi.h> +#include <shlobj.h> +#include <shobjidl.h> // Must be before propkey. + +#include "base/bind.h" +#include "base/debug/leak_annotations.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/single_thread_task_runner.h" +#include "base/strings/string_util.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/win/registry.h" +#include "base/win/scoped_co_mem.h" +#include "base/win/win_util.h" +#include "base/win/windows_version.h" +#include "ui/base/win/hidden_window.h" +#include "ui/base/win/osk_display_observer.h" +#include "ui/display/win/dpi.h" +#include "ui/gfx/geometry/dip_util.h" + +namespace { + +constexpr int kCheckOSKDelayMs = 1000; +constexpr int kDismissKeyboardRetryTimeoutMs = 100; +constexpr int kDismissKeyboardMaxRetries = 5; + +constexpr wchar_t kOSKClassName[] = L"IPTip_Main_Window"; + +constexpr wchar_t kWindows8OSKRegPath[] = + L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}" + L"\\LocalServer32"; + +} // namespace + +namespace ui { + +// This class provides functionality to detect when the on screen keyboard +// is displayed and move the main window up if it is obscured by the keyboard. +class OnScreenKeyboardDetector { + public: + OnScreenKeyboardDetector(); + ~OnScreenKeyboardDetector(); + + // Schedules a delayed task which detects if the on screen keyboard was + // displayed. + void DetectKeyboard(HWND main_window); + + // Dismisses the on screen keyboard. If a call to display the keyboard was + // made, this function waits for the keyboard to become visible by retrying + // upto a maximum of kDismissKeyboardMaxRetries. + bool DismissKeyboard(); + + // Add/Remove keyboard observers. + // Please note that this class does not track the |observer| destruction. It + // is upto the classes which set up these observers to remove them when they + // are destroyed. + void AddObserver(OnScreenKeyboardObserver* observer); + void RemoveObserver(OnScreenKeyboardObserver* observer); + + // Returns true if the osk is visible. Sets osk bounding rect if non-null + static bool IsKeyboardVisible(gfx::Rect* osk_bounding_rect); + + private: + // Executes as a task and detects if the on screen keyboard is displayed. + // Once the keyboard is displayed it schedules the HideIfNecessary() task to + // detect when the keyboard is or should be hidden. + void CheckIfKeyboardVisible(); + + // Executes as a task and detects if the keyboard was hidden or should be + // hidden. + void HideIfNecessary(); + + // Notifies observers that the keyboard was displayed. + // A recurring task HideIfNecessary() is started to detect when the OSK + // disappears. + void HandleKeyboardVisible(); + + // Notifies observers that the keyboard was hidden. + // The observer list is cleared out after this notification. + void HandleKeyboardHidden(); + + // Removes all observers from the list. + void ClearObservers(); + + // The main window which displays the on screen keyboard. + HWND main_window_ = nullptr; + + // Tracks if the keyboard was displayed. + bool osk_visible_notification_received_ = false; + + // The keyboard dimensions in pixels. + gfx::Rect osk_rect_pixels_; + + // Set to true if a call to DetectKeyboard() was made. + bool keyboard_detect_requested_ = false; + + // Contains the number of attempts made to dismiss the keyboard. Please refer + // to the DismissKeyboard() function for more information. + int keyboard_dismiss_retry_count_ = 0; + + base::ObserverList<OnScreenKeyboardObserver, false> observers_; + + // Should be the last member in the class. Helps ensure that tasks spawned + // by this class instance are canceled when it is destroyed. + base::WeakPtrFactory<OnScreenKeyboardDetector> keyboard_detector_factory_; + + DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDetector); +}; + +// OnScreenKeyboardDetector member definitions. +OnScreenKeyboardDetector::OnScreenKeyboardDetector() + : keyboard_detector_factory_(this) {} + +OnScreenKeyboardDetector::~OnScreenKeyboardDetector() { + ClearObservers(); +} + +void OnScreenKeyboardDetector::DetectKeyboard(HWND main_window) { + main_window_ = main_window; + keyboard_detect_requested_ = true; + // The keyboard is displayed by TabTip.exe which is launched via a + // ShellExecute call in the + // OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard() function. We use + // a delayed task to check if the keyboard is visible because of the possible + // delay between the ShellExecute call and the keyboard becoming visible. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&OnScreenKeyboardDetector::CheckIfKeyboardVisible, + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); +} + +bool OnScreenKeyboardDetector::DismissKeyboard() { + // We dismiss the virtual keyboard by generating the ESC keystroke + // programmatically. + HWND osk = ::FindWindow(kOSKClassName, nullptr); + if (::IsWindow(osk) && ::IsWindowEnabled(osk)) { + keyboard_detect_requested_ = false; + keyboard_dismiss_retry_count_ = 0; + HandleKeyboardHidden(); + PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0); + return true; + } else if (keyboard_detect_requested_) { + if (keyboard_dismiss_retry_count_ < kDismissKeyboardMaxRetries) { + keyboard_dismiss_retry_count_++; + // Please refer to the comments in the DetectKeyboard() function for more + // information as to why we need a delayed task here. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(base::IgnoreResult( + &OnScreenKeyboardDetector::DismissKeyboard), + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kDismissKeyboardRetryTimeoutMs)); + } else { + keyboard_dismiss_retry_count_ = 0; + } + } + return false; +} + +void OnScreenKeyboardDetector::AddObserver(OnScreenKeyboardObserver* observer) { + observers_.AddObserver(observer); +} + +void OnScreenKeyboardDetector::RemoveObserver( + OnScreenKeyboardObserver* observer) { + observers_.RemoveObserver(observer); +} + +// static +bool OnScreenKeyboardDetector::IsKeyboardVisible(gfx::Rect* osk_bounding_rect) { + HWND osk = ::FindWindow(kOSKClassName, nullptr); + if (!::IsWindow(osk)) + return false; + if (osk_bounding_rect) { + RECT osk_rect = {}; + ::GetWindowRect(osk, &osk_rect); + *osk_bounding_rect = gfx::Rect(osk_rect); + } + return ::IsWindowVisible(osk) && ::IsWindowEnabled(osk); +} + +void OnScreenKeyboardDetector::CheckIfKeyboardVisible() { + if (IsKeyboardVisible(&osk_rect_pixels_)) { + if (!osk_visible_notification_received_) + HandleKeyboardVisible(); + } else { + DVLOG(1) << "OSK did not come up in 1 second. Something wrong."; + } +} + +void OnScreenKeyboardDetector::HideIfNecessary() { + HWND osk = ::FindWindow(kOSKClassName, nullptr); + if (!::IsWindow(osk)) + return; + + // Three cases here. + // 1. OSK was hidden because the user dismissed it. + // 2. We are no longer in the foreground. + // 3. The OSK is still visible. + // In the first case we just have to notify the observers that the OSK was + // hidden. + // In the second case we need to dismiss the OSK which internally will + // notify the observers about the OSK being hidden. + if (!::IsWindowEnabled(osk)) { + if (osk_visible_notification_received_) { + if (main_window_ == ::GetForegroundWindow()) { + DVLOG(1) << "OSK window hidden while we are in the foreground."; + HandleKeyboardHidden(); + } + } + } else if (main_window_ != ::GetForegroundWindow()) { + if (osk_visible_notification_received_) { + DVLOG(1) << "We are no longer in the foreground. Dismising OSK."; + DismissKeyboard(); + } + } else { + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary, + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); + } +} + +void OnScreenKeyboardDetector::HandleKeyboardVisible() { + DCHECK(!osk_visible_notification_received_); + osk_visible_notification_received_ = true; + + for (OnScreenKeyboardObserver& observer : observers_) + observer.OnKeyboardVisible(osk_rect_pixels_); + + // Now that the keyboard is visible, run the task to detect if it was hidden. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&OnScreenKeyboardDetector::HideIfNecessary, + keyboard_detector_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs)); +} + +void OnScreenKeyboardDetector::HandleKeyboardHidden() { + osk_visible_notification_received_ = false; + for (OnScreenKeyboardObserver& observer : observers_) + observer.OnKeyboardHidden(osk_rect_pixels_); + ClearObservers(); +} + +void OnScreenKeyboardDetector::ClearObservers() { + for (auto& observer : observers_) + RemoveObserver(&observer); +} + +// OnScreenKeyboardDisplayManager member definitions. +OnScreenKeyboardDisplayManager::OnScreenKeyboardDisplayManager() {} + +OnScreenKeyboardDisplayManager::~OnScreenKeyboardDisplayManager() {} + +OnScreenKeyboardDisplayManager* OnScreenKeyboardDisplayManager::GetInstance() { + static OnScreenKeyboardDisplayManager* instance = nullptr; + if (!instance) { + instance = new OnScreenKeyboardDisplayManager; + ANNOTATE_LEAKING_OBJECT_PTR(instance); + } + return instance; +} + +bool OnScreenKeyboardDisplayManager::DisplayVirtualKeyboard( + OnScreenKeyboardObserver* observer) { + if (base::win::GetVersion() < base::win::VERSION_WIN8) + return false; + + if (base::win::IsKeyboardPresentOnSlate(nullptr, ui::GetHiddenWindow())) + return false; + + if (osk_path_.empty() && !GetOSKPath(&osk_path_)) { + DLOG(WARNING) << "Failed to get on screen keyboard path from registry"; + return false; + } + + HINSTANCE ret = ::ShellExecuteW(nullptr, L"", osk_path_.c_str(), nullptr, + nullptr, SW_SHOW); + + bool success = reinterpret_cast<intptr_t>(ret) > 32; + if (success) { + // If multiple calls to DisplayVirtualKeyboard occur one after the other, + // the last observer would be the one to get notifications. + keyboard_detector_.reset(new OnScreenKeyboardDetector); + if (observer) + keyboard_detector_->AddObserver(observer); + keyboard_detector_->DetectKeyboard(::GetForegroundWindow()); + } + return success; +} + +bool OnScreenKeyboardDisplayManager::DismissVirtualKeyboard() { + if (base::win::GetVersion() < base::win::VERSION_WIN8) + return false; + + return keyboard_detector_ ? keyboard_detector_->DismissKeyboard() : false; +} + +void OnScreenKeyboardDisplayManager::RemoveObserver( + OnScreenKeyboardObserver* observer) { + if (keyboard_detector_) + keyboard_detector_->RemoveObserver(observer); +} + +bool OnScreenKeyboardDisplayManager::GetOSKPath(base::string16* osk_path) { + DCHECK(osk_path); + + // We need to launch TabTip.exe from the location specified under the + // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}} + // CLSID. + // TabTip.exe is typically found at + // c:\program files\common files\microsoft shared\ink on English Windows. + // We don't want to launch TabTip.exe from + // c:\program files (x86)\common files\microsoft shared\ink. This path is + // normally found on 64 bit Windows. + base::win::RegKey key(HKEY_LOCAL_MACHINE, kWindows8OSKRegPath, + KEY_READ | KEY_WOW64_64KEY); + DWORD osk_path_length = 1024; + if (key.ReadValue(nullptr, base::WriteInto(osk_path, osk_path_length), + &osk_path_length, nullptr) != ERROR_SUCCESS) { + return false; + } + + osk_path->resize(base::string16::traits_type::length(osk_path->c_str())); + + *osk_path = base::ToLowerASCII(*osk_path); + + size_t common_program_files_offset = osk_path->find(L"%commonprogramfiles%"); + // Typically the path to TabTip.exe read from the registry will start with + // %CommonProgramFiles% which needs to be replaced with the corrsponding + // expanded string. + // If the path does not begin with %CommonProgramFiles% we use it as is. + if (common_program_files_offset != base::string16::npos) { + // Preserve the beginning quote in the path. + osk_path->erase(common_program_files_offset, + wcslen(L"%commonprogramfiles%")); + // The path read from the registry contains the %CommonProgramFiles% + // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath + // function returns the common program files path with the X86 suffix for + // the FOLDERID_ProgramFilesCommon value. + // To get the correct path to TabTip.exe we first read the environment + // variable CommonProgramW6432 which points to the desired common + // files path. Failing that we fallback to the SHGetKnownFolderPath API. + + // We then replace the %CommonProgramFiles% value with the actual common + // files path found in the process. + base::string16 common_program_files_path; + DWORD buffer_size = + GetEnvironmentVariable(L"CommonProgramW6432", nullptr, 0); + if (buffer_size) { + GetEnvironmentVariable( + L"CommonProgramW6432", + base::WriteInto(&common_program_files_path, buffer_size), + buffer_size); + DCHECK(!common_program_files_path.empty()); + } else { + base::win::ScopedCoMem<wchar_t> common_program_files; + if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, nullptr, + &common_program_files))) { + return false; + } + common_program_files_path = common_program_files; + } + osk_path->insert(common_program_files_offset, common_program_files_path); + } + return !osk_path->empty(); +} + +bool OnScreenKeyboardDisplayManager::IsKeyboardVisible() const { + return OnScreenKeyboardDetector::IsKeyboardVisible(nullptr); +} + +} // namespace ui diff --git a/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h new file mode 100644 index 00000000000..b5392c4b686 --- /dev/null +++ b/chromium/ui/base/win/on_screen_keyboard_display_manager_tab_tip.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_ +#define UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_ + +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/strings/string16.h" +#include "ui/base/ui_base_export.h" +#include "ui/gfx/geometry/rect.h" + +namespace ui { + +class OnScreenKeyboardDetector; +class OnScreenKeyboardObserver; + +// This class provides functionality to display the on screen keyboard on +// Windows 8+. It optionally notifies observers that the OSK is displayed, +// hidden, etc. +class UI_BASE_EXPORT OnScreenKeyboardDisplayManager { + public: + static OnScreenKeyboardDisplayManager* GetInstance(); + + ~OnScreenKeyboardDisplayManager(); + + // Functions to display and dismiss the keyboard. + // The optional |observer| parameter allows callers to be notified when the + // keyboard is displayed, dismissed, etc. + bool DisplayVirtualKeyboard(OnScreenKeyboardObserver* observer); + // When the keyboard is dismissed, the registered observer if any is removed + // after notifying it. + bool DismissVirtualKeyboard(); + + // Removes a registered observer. + void RemoveObserver(OnScreenKeyboardObserver* observer); + + // Returns the path of the on screen keyboard exe (TabTip.exe) in the + // |osk_path| parameter. + // Returns true on success. + bool GetOSKPath(base::string16* osk_path); + + // Returns true if the virtual keyboard is currently visible. + bool IsKeyboardVisible() const; + + private: + OnScreenKeyboardDisplayManager(); + + std::unique_ptr<OnScreenKeyboardDetector> keyboard_detector_; + + // The location of TabTip.exe. + base::string16 osk_path_; + + DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManager); +}; + +} // namespace ui + +#endif // UI_BASE_WIN_OSK_DISPLAY_MANAGER_H_ diff --git a/chromium/ui/base/win/shell.cc b/chromium/ui/base/win/shell.cc index ebd6c65d481..b5afdead174 100644 --- a/chromium/ui/base/win/shell.cc +++ b/chromium/ui/base/win/shell.cc @@ -27,29 +27,21 @@ namespace win { namespace { -// Default ShellExecuteEx flags used with the "openas" verb. +// Default ShellExecuteEx flags used with "openas", "explore", and default +// verbs. // // SEE_MASK_NOASYNC is specified so that ShellExecuteEx can be invoked from a // thread whose message loop may not wait around long enough for the // asynchronous tasks initiated by ShellExecuteEx to complete. Using this flag // causes ShellExecuteEx() to block until these tasks complete. -const DWORD kDefaultOpenAsFlags = SEE_MASK_NOASYNC; - -// Default ShellExecuteEx flags used with the "explore", "open" or default verb. -// -// See kDefaultOpenFlags for description SEE_MASK_NOASYNC flag. -// SEE_MASK_FLAG_NO_UI is used to suppress any error message boxes that might be -// displayed if there is an error in opening the file. Failure in invoking the -// "open" actions result in invocation of the "saveas" verb, making the error -// dialog superfluous. -const DWORD kDefaultOpenFlags = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; +const DWORD kDefaultShellExecuteFlags = SEE_MASK_NOASYNC; // Invokes ShellExecuteExW() with the given parameters. -DWORD InvokeShellExecute(const base::string16 path, - const base::string16 working_directory, - const base::string16 args, - const base::string16 verb, - DWORD mask) { +bool InvokeShellExecute(const base::string16 path, + const base::string16 working_directory, + const base::string16 args, + const base::string16 verb, + DWORD mask) { base::AssertBlockingAllowed(); SHELLEXECUTEINFO sei = {sizeof(sei)}; sei.fMask = mask; @@ -59,7 +51,7 @@ DWORD InvokeShellExecute(const base::string16 path, sei.lpDirectory = (working_directory.empty() ? nullptr : working_directory.c_str()); sei.lpParameters = (args.empty() ? nullptr : args.c_str()); - return ::ShellExecuteExW(&sei) ? ERROR_SUCCESS : ::GetLastError(); + return ::ShellExecuteExW(&sei); } } // namespace @@ -68,32 +60,22 @@ bool OpenAnyViaShell(const base::string16& full_path, const base::string16& directory, const base::string16& args, DWORD mask) { - DWORD open_result = - InvokeShellExecute(full_path, directory, args, base::string16(), mask); - if (open_result == ERROR_SUCCESS) - return true; - // Show the Windows "Open With" dialog box to ask the user to pick an app to - // open the file with. Note that we are not forwarding |args| for the "openas" - // call since the target application is nolonger known at this point. - if (open_result == ERROR_NO_ASSOCIATION) - return InvokeShellExecute(full_path, directory, base::string16(), L"openas", - kDefaultOpenAsFlags) == ERROR_SUCCESS; - return false; + return InvokeShellExecute(full_path, directory, args, base::string16(), mask); } bool OpenFileViaShell(const base::FilePath& full_path) { - return OpenAnyViaShell(full_path.value(), full_path.DirName().value(), - base::string16(), kDefaultOpenFlags); + // Invoke the default verb on the file with no arguments. + return InvokeShellExecute(full_path.value(), full_path.DirName().value(), + base::string16(), base::string16(), + kDefaultShellExecuteFlags); } bool OpenFolderViaShell(const base::FilePath& full_path) { // The "explore" verb causes the folder at |full_path| to be displayed in a - // file browser. This will fail if |full_path| is not a directory. The - // resulting error does not cause UI due to the SEE_MASK_FLAG_NO_UI flag in - // kDefaultOpenFlags. + // file browser. This will fail if |full_path| is not a directory. return InvokeShellExecute(full_path.value(), full_path.value(), base::string16(), L"explore", - kDefaultOpenFlags) == ERROR_SUCCESS; + kDefaultShellExecuteFlags); } bool PreventWindowFromPinning(HWND hwnd) { diff --git a/chromium/ui/base/win/shell.h b/chromium/ui/base/win/shell.h index df784a6e13b..c47e5ce3f47 100644 --- a/chromium/ui/base/win/shell.h +++ b/chromium/ui/base/win/shell.h @@ -17,8 +17,8 @@ class FilePath; namespace ui { namespace win { -// Open the folder at |full_path| via the Windows shell. Does nothing if -// |full_path| is not a folder. +// Open the folder at |full_path| via the Windows shell. It is an error if +// |full_path| does not refer to a folder. // // Note: Must be called on a thread that allows blocking. UI_BASE_EXPORT bool OpenFolderViaShell(const base::FilePath& full_path); diff --git a/chromium/ui/chromeos/BUILD.gn b/chromium/ui/chromeos/BUILD.gn index 8ef1bca5769..c15c784e377 100644 --- a/chromium/ui/chromeos/BUILD.gn +++ b/chromium/ui/chromeos/BUILD.gn @@ -9,8 +9,6 @@ assert(is_chromeos) component("chromeos") { output_name = "ui_chromeos" sources = [ - "accelerometer/accelerometer_util.cc", - "accelerometer/accelerometer_util.h", "devicetype_utils.cc", "devicetype_utils.h", "ime/candidate_view.cc", @@ -26,10 +24,6 @@ component("chromeos") { "ime/input_method_menu_manager.h", "ime/mode_indicator_view.cc", "ime/mode_indicator_view.h", - "touch_accessibility_enabler.cc", - "touch_accessibility_enabler.h", - "touch_exploration_controller.cc", - "touch_exploration_controller.h", "user_activity_power_manager_notifier.cc", "user_activity_power_manager_notifier.h", ] @@ -70,8 +64,6 @@ test("ui_chromeos_unittests") { "ime/input_method_menu_item_unittest.cc", "ime/input_method_menu_manager_unittest.cc", "run_all_unittests.cc", - "touch_accessibility_enabler_unittest.cc", - "touch_exploration_controller_unittest.cc", ] deps = [ ":chromeos", diff --git a/chromium/ui/chromeos/search_box/BUILD.gn b/chromium/ui/chromeos/search_box/BUILD.gn new file mode 100644 index 00000000000..826cad941df --- /dev/null +++ b/chromium/ui/chromeos/search_box/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("search_box") { + sources = [ + "search_box_constants.h", + "search_box_view_base.cc", + "search_box_view_base.h", + "search_box_view_delegate.h", + ] + + defines = [ "SEARCH_BOX_IMPLEMENTATION" ] + + deps = [ + "//base", + "//skia", + "//ui/base", + "//ui/base/ime", + "//ui/events", + "//ui/strings", + "//ui/views", + ] +} diff --git a/chromium/ui/compositor/BUILD.gn b/chromium/ui/compositor/BUILD.gn index b8f0cacc39e..12788fef517 100644 --- a/chromium/ui/compositor/BUILD.gn +++ b/chromium/ui/compositor/BUILD.gn @@ -151,8 +151,8 @@ static_library("test_support") { "//components/viz/host", "//components/viz/service", "//components/viz/test:test_support", - "//gpu/command_buffer/client:gles2_c_lib", "//gpu/command_buffer/client:gles2_implementation", + "//gpu/command_buffer/client:raster", "//gpu/command_buffer/common", "//gpu/ipc:gl_in_process_context", "//gpu/skia_bindings", @@ -182,6 +182,7 @@ static_library("test_support") { test("compositor_unittests") { sources = [ "callback_layer_animation_observer_unittest.cc", + "canvas_painter_unittest.cc", "compositor_lock_unittest.cc", "compositor_unittest.cc", "layer_animation_element_unittest.cc", diff --git a/chromium/ui/compositor/canvas_painter.cc b/chromium/ui/compositor/canvas_painter.cc index 864d8b03e84..31c4cabdc1f 100644 --- a/chromium/ui/compositor/canvas_painter.cc +++ b/chromium/ui/compositor/canvas_painter.cc @@ -9,30 +9,34 @@ namespace ui { CanvasPainter::CanvasPainter(SkBitmap* output, - const gfx::Size& paint_size, - float raster_scale, + const gfx::Size& output_size, + float device_scale_factor, SkColor clear_color, bool is_pixel_canvas) : output_(output), - paint_size_(paint_size), - raster_scale_(raster_scale), + pixel_output_size_( + gfx::ScaleToCeiledSize(output_size, device_scale_factor)), + raster_scale_(is_pixel_canvas ? 1.f : device_scale_factor), clear_color_(clear_color), list_(new cc::DisplayItemList), context_(list_.get(), - raster_scale, - gfx::Rect(paint_size_), + device_scale_factor, + gfx::Rect(output_size), is_pixel_canvas) {} CanvasPainter::~CanvasPainter() { - gfx::Size pixel_size = gfx::ScaleToCeiledSize(paint_size_, raster_scale_); - SkImageInfo info = SkImageInfo::MakeN32( - pixel_size.width(), pixel_size.height(), kPremul_SkAlphaType); + SkImageInfo info = + SkImageInfo::MakeN32(pixel_output_size_.width(), + pixel_output_size_.height(), kPremul_SkAlphaType); if (!output_->tryAllocPixels(info)) return; SkCanvas canvas(*output_); canvas.clear(clear_color_); + // When pixel canvas is enabled, the recordings and canvas are already scaled + // to the correct raster size. This additional scaling is not required and + // hence |raster_scale_| should be equal to 1 during this operation. canvas.scale(raster_scale_, raster_scale_); list_->Finalize(); diff --git a/chromium/ui/compositor/canvas_painter.h b/chromium/ui/compositor/canvas_painter.h index da44d7bb166..51e196e2c71 100644 --- a/chromium/ui/compositor/canvas_painter.h +++ b/chromium/ui/compositor/canvas_painter.h @@ -27,8 +27,8 @@ namespace ui { class COMPOSITOR_EXPORT CanvasPainter { public: CanvasPainter(SkBitmap* output, - const gfx::Size& paint_size, - float raster_scale, + const gfx::Size& output_size, + float device_scale_factor, SkColor clear_color, bool is_pixel_canvas); ~CanvasPainter(); @@ -36,8 +36,10 @@ class COMPOSITOR_EXPORT CanvasPainter { const PaintContext& context() const { return context_; } private: + friend class CanvasPainterTest; + SkBitmap* const output_; - const gfx::Size paint_size_; + const gfx::Size pixel_output_size_; const float raster_scale_; const SkColor clear_color_; scoped_refptr<cc::DisplayItemList> list_; diff --git a/chromium/ui/compositor/canvas_painter_unittest.cc b/chromium/ui/compositor/canvas_painter_unittest.cc new file mode 100644 index 00000000000..bdbe4653529 --- /dev/null +++ b/chromium/ui/compositor/canvas_painter_unittest.cc @@ -0,0 +1,121 @@ +// Copyright 2018 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/compositor/canvas_painter.h" + +#include "base/macros.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/compositor/paint_recorder.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" + +namespace ui { +namespace { +void CheckPaintedShape(const SkBitmap& bitmap, + const gfx::Rect& shape_bounds, + const SkColor shape_color, + float device_scale_factor) { + // Whether pixel canvas is enabled or not, the pixel location of the shape + // should remain the same. + const gfx::Point expected_top_left_location = + gfx::ScaleToRoundedPoint(shape_bounds.origin(), device_scale_factor); + const gfx::Point expected_bottom_right_location = gfx::ScaleToRoundedPoint( + shape_bounds.bottom_right(), device_scale_factor); + + EXPECT_EQ(bitmap.getColor(expected_top_left_location.x(), + expected_top_left_location.y()), + shape_color); + EXPECT_EQ(bitmap.getColor(expected_bottom_right_location.x(), + expected_bottom_right_location.y()), + shape_color); +} +} // namespace + +class CanvasPainterTest : public ::testing::TestWithParam<float> { + public: + CanvasPainterTest() : device_scale_factor_(GetParam()) {} + + float device_scale_factor() const { return device_scale_factor_; } + + const gfx::Size& pixel_output_size(const CanvasPainter& painter) const { + return painter.pixel_output_size_; + } + + float raster_scale(const CanvasPainter& painter) const { + return painter.raster_scale_; + } + + // Paints a rect with bounds |shape_bounds| and color |shape_color| on + // |bitmap| with the help of CanvasPainter. The output size of the bitmap in + // DIP is |size|. + void Paint(SkBitmap* bitmap, + const gfx::Size& size, + float device_scale_factor, + bool is_pixel_canvas, + const gfx::Rect& shape_bounds, + SkColor shape_color) { + CanvasPainter painter(bitmap, size, device_scale_factor, + SK_ColorTRANSPARENT, is_pixel_canvas); + + // The paint recording size is scaled to match the raster size if pixel + // canvas is enabled. + const gfx::Size paint_recording_size = gfx::ScaleToCeiledSize( + size, is_pixel_canvas ? device_scale_factor : 1.f); + + PaintRecorder recorder(painter.context(), paint_recording_size, + device_scale_factor, device_scale_factor, nullptr); + recorder.canvas()->DrawRect(gfx::RectF(shape_bounds), shape_color); + } + + private: + float device_scale_factor_; + + DISALLOW_COPY_AND_ASSIGN(CanvasPainterTest); +}; + +TEST_P(CanvasPainterTest, Initialization) { + SkBitmap output; + const gfx::Size output_size(100, 100); + CanvasPainter painter(&output, output_size, device_scale_factor(), + SK_ColorTRANSPARENT, false /* is_pixel_canvas */); + EXPECT_EQ(pixel_output_size(painter), + gfx::ScaleToCeiledSize(output_size, device_scale_factor())); + EXPECT_EQ(raster_scale(painter), device_scale_factor()); +} + +TEST_P(CanvasPainterTest, InitializationPixelCanvasEnabled) { + SkBitmap output; + const gfx::Size output_size(100, 100); + CanvasPainter painter(&output, output_size, device_scale_factor(), + SK_ColorTRANSPARENT, true /* is_pixel_canvas */); + EXPECT_EQ(pixel_output_size(painter), + gfx::ScaleToCeiledSize(output_size, device_scale_factor())); + EXPECT_EQ(raster_scale(painter), 1.f); +} + +TEST_P(CanvasPainterTest, Paint) { + SkBitmap bitmap; + const SkColor shape_color = SK_ColorRED; + const gfx::Rect shape_bounds(100, 100, 100, 100); + + Paint(&bitmap, gfx::Size(1000, 1000), device_scale_factor(), + false /* is_pixel_canvas */, shape_bounds, shape_color); + CheckPaintedShape(bitmap, shape_bounds, shape_color, device_scale_factor()); +} + +TEST_P(CanvasPainterTest, PaintPixelCanvasEnabled) { + SkBitmap bitmap; + const SkColor shape_color = SK_ColorRED; + const gfx::Rect shape_bounds(100, 100, 100, 100); + + Paint(&bitmap, gfx::Size(1000, 1000), device_scale_factor(), + true /* is_pixel_canvas */, shape_bounds, shape_color); + CheckPaintedShape(bitmap, shape_bounds, shape_color, device_scale_factor()); +} + +INSTANTIATE_TEST_CASE_P(, + CanvasPainterTest, + ::testing::Values(1.f, 1.25f, 1.5f, 1.6f, 2.f, 2.25f)); +} // namespace ui diff --git a/chromium/ui/compositor/compositor.cc b/chromium/ui/compositor/compositor.cc index 7e68848c42f..c843ef6c644 100644 --- a/chromium/ui/compositor/compositor.cc +++ b/chromium/ui/compositor/compositor.cc @@ -35,7 +35,9 @@ #include "components/viz/common/resources/resource_format.h" #include "components/viz/common/resources/resource_settings.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" +#include "components/viz/common/switches.h" #include "components/viz/host/host_frame_sink_manager.h" +#include "components/viz/host/renderer_settings_creation.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/ui_base_switches.h" @@ -77,10 +79,8 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id, auto* host_frame_sink_manager = context_factory_private_->GetHostFrameSinkManager(); host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this); -#if DCHECK_IS_ON() host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_, "Compositor"); -#endif } root_web_layer_ = cc::Layer::Create(); @@ -164,7 +164,6 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id, if (command_line->HasSwitch(switches::kUIEnableRGBA4444Textures)) settings.preferred_tile_format = viz::RGBA_4444; - settings.resource_settings = context_factory_->GetResourceSettings(); #if defined(OS_MACOSX) // Using CoreAnimation to composite requires using GpuMemoryBuffers, which @@ -173,19 +172,21 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id, settings.use_zero_copy; #endif - settings.gpu_memory_policy.bytes_limit_when_visible = 512 * 1024 * 1024; - settings.gpu_memory_policy.priority_cutoff_when_visible = + settings.memory_policy.bytes_limit_when_visible = 512 * 1024 * 1024; + settings.memory_policy.priority_cutoff_when_visible = gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; settings.disallow_non_exact_resource_reuse = command_line->HasSwitch(switches::kDisallowNonExactResourceReuse); - if (command_line->HasSwitch( - cc::switches::kRunAllCompositorStagesBeforeDraw)) { + if (command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw)) { settings.wait_for_all_pipeline_stages_before_draw = true; settings.enable_latency_recovery = false; } + settings.always_request_presentation_time = + command_line->HasSwitch(cc::switches::kAlwaysRequestPresentationTime); + base::TimeTicks before_create = base::TimeTicks::Now(); animation_host_ = cc::AnimationHost::CreateMainInstance(); @@ -205,7 +206,6 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id, animation_host_->AddAnimationTimeline(animation_timeline_.get()); host_->SetRootLayer(root_web_layer_); - host_->SetFrameSinkId(frame_sink_id_); host_->SetVisible(true); if (command_line->HasSwitch(switches::kUISlowAnimations)) { @@ -349,17 +349,18 @@ void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel, const viz::LocalSurfaceId& local_surface_id) { DCHECK_GT(scale, 0); + bool device_scale_factor_changed = device_scale_factor_ != scale; + device_scale_factor_ = scale; + if (!size_in_pixel.IsEmpty()) { size_ = size_in_pixel; - host_->SetViewportSize(size_in_pixel, local_surface_id); + host_->SetViewportSizeAndScale(size_in_pixel, scale, local_surface_id); root_web_layer_->SetBounds(size_in_pixel); // TODO(fsamuel): Get rid of ContextFactoryPrivate. if (context_factory_private_) context_factory_private_->ResizeDisplay(this, size_in_pixel); } - if (device_scale_factor_ != scale) { - device_scale_factor_ = scale; - host_->SetDeviceScaleFactor(scale); + if (device_scale_factor_changed) { if (is_pixel_canvas()) host_->SetRecordingScaleFactor(scale); if (root_layer_) diff --git a/chromium/ui/compositor/compositor.h b/chromium/ui/compositor/compositor.h index eb56a103f8c..78b36146063 100644 --- a/chromium/ui/compositor/compositor.h +++ b/chromium/ui/compositor/compositor.h @@ -21,8 +21,8 @@ #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_single_thread_client.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" +#include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/local_surface_id.h" -#include "components/viz/common/surfaces/surface_sequence.h" #include "components/viz/host/host_frame_sink_client.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkMatrix44.h" @@ -66,7 +66,6 @@ class FrameSinkManagerImpl; class ContextProvider; class HostFrameSinkManager; class LocalSurfaceId; -class ResourceSettings; } namespace ui { @@ -178,9 +177,6 @@ class COMPOSITOR_EXPORT ContextFactory { // Gets the task graph runner. virtual cc::TaskGraphRunner* GetTaskGraphRunner() = 0; - // Gets the renderer settings. - virtual const viz::ResourceSettings& GetResourceSettings() const = 0; - virtual void AddObserver(ContextFactoryObserver* observer) = 0; virtual void RemoveObserver(ContextFactoryObserver* observer) = 0; diff --git a/chromium/ui/compositor/dip_util.cc b/chromium/ui/compositor/dip_util.cc index 0aad3970242..1dd91456930 100644 --- a/chromium/ui/compositor/dip_util.cc +++ b/chromium/ui/compositor/dip_util.cc @@ -93,6 +93,14 @@ void SnapLayerToPhysicalPixelBoundary(ui::Layer* snapped_layer, gfx::Vector2dF fudge = view_offset_snapped - view_offset; fudge.Scale(1.0 / scale_factor); + + // Apply any scale originating from transforms to the fudge. + gfx::Transform transform; + layer_to_snap->parent()->GetTargetTransformRelativeTo(snapped_layer, + &transform); + gfx::Vector2dF transform_scale = transform.Scale2d(); + fudge.Scale(1.0 / transform_scale.x(), 1.0 / transform_scale.y()); + layer_to_snap->SetSubpixelPositionOffset(fudge); #if DCHECK_IS_ON() gfx::PointF layer_offset; @@ -105,6 +113,7 @@ void SnapLayerToPhysicalPixelBoundary(ui::Layer* snapped_layer, } else { origin = layer_to_snap->position(); } + origin.Scale(transform_scale.x(), transform_scale.y()); CheckSnapped((layer_offset.x() + origin.x()) * scale_factor); CheckSnapped((layer_offset.y() + origin.y()) * scale_factor); #endif diff --git a/chromium/ui/compositor/layer.cc b/chromium/ui/compositor/layer.cc index c5f67114ab7..ffd6f93c307 100644 --- a/chromium/ui/compositor/layer.cc +++ b/chromium/ui/compositor/layer.cc @@ -187,10 +187,13 @@ std::unique_ptr<Layer> Layer::Clone() const { // cc::Layer state. if (surface_layer_) { if (surface_layer_->primary_surface_id().is_valid()) { - clone->SetShowPrimarySurface(surface_layer_->primary_surface_id(), - frame_size_in_dip_, - surface_layer_->background_color(), - surface_layer_->surface_reference_factory()); + clone->SetShowPrimarySurface( + surface_layer_->primary_surface_id(), frame_size_in_dip_, + surface_layer_->background_color(), + surface_layer_->deadline_in_frames() + ? cc::DeadlinePolicy::UseSpecifiedDeadline( + *surface_layer_->deadline_in_frames()) + : cc::DeadlinePolicy::UseDefaultDeadline()); } if (surface_layer_->fallback_surface_id().is_valid()) clone->SetFallbackSurfaceId(surface_layer_->fallback_surface_id()); @@ -746,29 +749,28 @@ bool Layer::TextureFlipped() const { return texture_layer_->flipped(); } -void Layer::SetShowPrimarySurface( - const viz::SurfaceId& surface_id, - const gfx::Size& frame_size_in_dip, - SkColor default_background_color, - scoped_refptr<viz::SurfaceReferenceFactory> ref_factory) { +void Layer::SetShowPrimarySurface(const viz::SurfaceId& surface_id, + const gfx::Size& frame_size_in_dip, + SkColor default_background_color, + const cc::DeadlinePolicy& deadline_policy) { DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR); if (!surface_layer_) { - scoped_refptr<cc::SurfaceLayer> new_layer = - cc::SurfaceLayer::Create(ref_factory); + scoped_refptr<cc::SurfaceLayer> new_layer = cc::SurfaceLayer::Create(); SwitchToLayer(new_layer); surface_layer_ = new_layer; } - surface_layer_->SetPrimarySurfaceId(surface_id, base::nullopt); + surface_layer_->SetPrimarySurfaceId(surface_id, deadline_policy); surface_layer_->SetBackgroundColor(default_background_color); frame_size_in_dip_ = frame_size_in_dip; RecomputeDrawsContentAndUVRect(); for (const auto& mirror : mirrors_) { - mirror->dest()->SetShowPrimarySurface( - surface_id, frame_size_in_dip, default_background_color, ref_factory); + mirror->dest()->SetShowPrimarySurface(surface_id, frame_size_in_dip, + default_background_color, + deadline_policy); } } diff --git a/chromium/ui/compositor/layer.h b/chromium/ui/compositor/layer.h index 736c4d53550..8200c6d43be 100644 --- a/chromium/ui/compositor/layer.h +++ b/chromium/ui/compositor/layer.h @@ -22,7 +22,6 @@ #include "cc/layers/surface_layer.h" #include "cc/layers/texture_layer_client.h" #include "components/viz/common/resources/transferable_resource.h" -#include "components/viz/common/surfaces/sequence_surface_reference_factory.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer_animation_delegate.h" @@ -303,12 +302,12 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate, void SetTextureFlipped(bool flipped); bool TextureFlipped() const; + // TODO(fsamuel): Update this comment. // Begins showing content from a surface with a particular ID. - void SetShowPrimarySurface( - const viz::SurfaceId& surface_id, - const gfx::Size& frame_size_in_dip, - SkColor default_background_color, - scoped_refptr<viz::SurfaceReferenceFactory> surface_ref); + void SetShowPrimarySurface(const viz::SurfaceId& surface_id, + const gfx::Size& frame_size_in_dip, + SkColor default_background_color, + const cc::DeadlinePolicy& deadline_policy); // In the event that the primary surface is not yet available in the // display compositor, the fallback surface will be used. diff --git a/chromium/ui/compositor/layer_animation_element.cc b/chromium/ui/compositor/layer_animation_element.cc index cb5ccccd20d..38bd26b8a60 100644 --- a/chromium/ui/compositor/layer_animation_element.cc +++ b/chromium/ui/compositor/layer_animation_element.cc @@ -10,8 +10,8 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/stringprintf.h" -#include "cc/animation/animation.h" #include "cc/animation/animation_id_provider.h" +#include "cc/animation/keyframe_model.h" #include "ui/compositor/float_animation_curve_adapter.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_delegate.h" @@ -300,7 +300,7 @@ class ThreadedLayerAnimationElement : public LayerAnimationElement { LayerThreadedAnimationDelegate* threaded = delegate->GetThreadedAnimationDelegate(); DCHECK(threaded); - threaded->RemoveThreadedAnimation(animation_id()); + threaded->RemoveThreadedAnimation(keyframe_model_id()); } OnEnd(delegate); @@ -312,7 +312,7 @@ class ThreadedLayerAnimationElement : public LayerAnimationElement { LayerThreadedAnimationDelegate* threaded = delegate->GetThreadedAnimationDelegate(); DCHECK(threaded); - threaded->RemoveThreadedAnimation(animation_id()); + threaded->RemoveThreadedAnimation(keyframe_model_id()); } } @@ -323,18 +323,18 @@ class ThreadedLayerAnimationElement : public LayerAnimationElement { return; } set_effective_start_time(base::TimeTicks()); - std::unique_ptr<cc::Animation> animation = CreateCCAnimation(); - animation->set_needs_synchronized_start_time(true); + std::unique_ptr<cc::KeyframeModel> keyframe_model = CreateCCKeyframeModel(); + keyframe_model->set_needs_synchronized_start_time(true); LayerThreadedAnimationDelegate* threaded = delegate->GetThreadedAnimationDelegate(); DCHECK(threaded); - threaded->AddThreadedAnimation(std::move(animation)); + threaded->AddThreadedAnimation(std::move(keyframe_model)); } virtual void OnEnd(LayerAnimationDelegate* delegate) = 0; - virtual std::unique_ptr<cc::Animation> CreateCCAnimation() = 0; + virtual std::unique_ptr<cc::KeyframeModel> CreateCCKeyframeModel() = 0; private: DISALLOW_COPY_AND_ASSIGN(ThreadedLayerAnimationElement); @@ -376,14 +376,14 @@ class ThreadedOpacityTransition : public ThreadedLayerAnimationElement { PropertyChangeReason::FROM_ANIMATION); } - std::unique_ptr<cc::Animation> CreateCCAnimation() override { + std::unique_ptr<cc::KeyframeModel> CreateCCKeyframeModel() override { std::unique_ptr<cc::AnimationCurve> animation_curve( new FloatAnimationCurveAdapter(tween_type(), start_, target_, duration())); - std::unique_ptr<cc::Animation> animation(cc::Animation::Create( - std::move(animation_curve), animation_id(), animation_group_id(), + std::unique_ptr<cc::KeyframeModel> keyframe_model(cc::KeyframeModel::Create( + std::move(animation_curve), keyframe_model_id(), animation_group_id(), cc::TargetProperty::OPACITY)); - return animation; + return keyframe_model; } void OnGetTarget(TargetValue* target) const override { @@ -446,14 +446,14 @@ class ThreadedTransformTransition : public ThreadedLayerAnimationElement { PropertyChangeReason::FROM_ANIMATION); } - std::unique_ptr<cc::Animation> CreateCCAnimation() override { + std::unique_ptr<cc::KeyframeModel> CreateCCKeyframeModel() override { std::unique_ptr<cc::AnimationCurve> animation_curve( new TransformAnimationCurveAdapter(tween_type(), start_, target_, duration())); - std::unique_ptr<cc::Animation> animation(cc::Animation::Create( - std::move(animation_curve), animation_id(), animation_group_id(), + std::unique_ptr<cc::KeyframeModel> keyframe_model(cc::KeyframeModel::Create( + std::move(animation_curve), keyframe_model_id(), animation_group_id(), cc::TargetProperty::TRANSFORM)); - return animation; + return keyframe_model; } void OnGetTarget(TargetValue* target) const override { @@ -499,7 +499,7 @@ LayerAnimationElement::LayerAnimationElement(AnimatableProperties properties, properties_(properties), duration_(GetEffectiveDuration(duration)), tween_type_(gfx::Tween::LINEAR), - animation_id_(cc::AnimationIdProvider::NextAnimationId()), + keyframe_model_id_(cc::AnimationIdProvider::NextKeyframeModelId()), animation_group_id_(0), last_progressed_fraction_(0.0), animation_metrics_reporter_(nullptr), @@ -512,7 +512,7 @@ LayerAnimationElement::LayerAnimationElement( properties_(element.properties_), duration_(element.duration_), tween_type_(element.tween_type_), - animation_id_(cc::AnimationIdProvider::NextAnimationId()), + keyframe_model_id_(cc::AnimationIdProvider::NextKeyframeModelId()), animation_group_id_(element.animation_group_id_), last_progressed_fraction_(element.last_progressed_fraction_), animation_metrics_reporter_(nullptr), @@ -566,7 +566,7 @@ bool LayerAnimationElement::Progress(base::TimeTicks now, bool LayerAnimationElement::IsFinished(base::TimeTicks time, base::TimeDelta* total_duration) { // If an effective start has been requested but the effective start time - // hasn't yet been set, the animation is not finished, regardless of the + // hasn't yet been set, the keyframe_model is not finished, regardless of the // value of |time|. if (!first_frame_ && (effective_start_time_ == base::TimeTicks())) return false; @@ -639,7 +639,7 @@ std::string LayerAnimationElement::ToString() const { return base::StringPrintf( "LayerAnimationElement{name=%s, id=%d, group=%d, " "last_progressed_fraction=%0.2f}", - DebugName().c_str(), animation_id_, animation_group_id_, + DebugName().c_str(), keyframe_model_id_, animation_group_id_, last_progressed_fraction_); } diff --git a/chromium/ui/compositor/layer_animation_element.h b/chromium/ui/compositor/layer_animation_element.h index 2ef8f4d8284..5088f879c62 100644 --- a/chromium/ui/compositor/layer_animation_element.h +++ b/chromium/ui/compositor/layer_animation_element.h @@ -13,7 +13,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" -#include "cc/animation/animation.h" +#include "cc/animation/keyframe_model.h" #include "cc/trees/target_property.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/compositor/compositor_export.h" @@ -196,10 +196,10 @@ class COMPOSITOR_EXPORT LayerAnimationElement { animation_metrics_reporter_ = reporter; } - // Each LayerAnimationElement has a unique animation_id. Elements belonging - // to sequences that are supposed to start together have the same + // Each LayerAnimationElement has a unique keyframe_model_id. Elements + // belonging to sequences that are supposed to start together have the same // animation_group_id. - int animation_id() const { return animation_id_; } + int keyframe_model_id() const { return keyframe_model_id_; } int animation_group_id() const { return animation_group_id_; } void set_animation_group_id(int id) { animation_group_id_ = id; } @@ -241,7 +241,7 @@ class COMPOSITOR_EXPORT LayerAnimationElement { const base::TimeDelta duration_; gfx::Tween::Type tween_type_; - const int animation_id_; + const int keyframe_model_id_; int animation_group_id_; double last_progressed_fraction_; diff --git a/chromium/ui/compositor/layer_animation_element_unittest.cc b/chromium/ui/compositor/layer_animation_element_unittest.cc index b055f1eb3ac..664daedb561 100644 --- a/chromium/ui/compositor/layer_animation_element_unittest.cc +++ b/chromium/ui/compositor/layer_animation_element_unittest.cc @@ -491,7 +491,7 @@ TEST(LayerAnimationElementTest, ToString) { base::StringPrintf("LayerAnimationElement{name=ThreadedOpacityTransition," " id=%d, group=42, " "last_progressed_fraction=0.00}", - element->animation_id()), + element->keyframe_model_id()), element->ToString()); } diff --git a/chromium/ui/compositor/layer_animation_sequence_unittest.cc b/chromium/ui/compositor/layer_animation_sequence_unittest.cc index 7b4ab3bbf90..ab6527d9739 100644 --- a/chromium/ui/compositor/layer_animation_sequence_unittest.cc +++ b/chromium/ui/compositor/layer_animation_sequence_unittest.cc @@ -285,7 +285,7 @@ TEST(LayerAnimationSequenceTest, ToString) { std::unique_ptr<LayerAnimationElement> brightness = LayerAnimationElement::CreateBrightnessElement(1.0f, delta); - int brightness_id = brightness->animation_id(); + int brightness_id = brightness->keyframe_model_id(); sequence.AddElement(std::move(brightness)); EXPECT_EQ( base::StringPrintf( @@ -298,7 +298,7 @@ TEST(LayerAnimationSequenceTest, ToString) { std::unique_ptr<LayerAnimationElement> opacity = LayerAnimationElement::CreateOpacityElement(1.0f, delta); - int opacity_id = opacity->animation_id(); + int opacity_id = opacity->keyframe_model_id(); sequence.AddElement(std::move(opacity)); sequence.set_is_cyclic(true); sequence.set_animation_group_id(1973); diff --git a/chromium/ui/compositor/layer_animator.cc b/chromium/ui/compositor/layer_animator.cc index 01b17ca798c..5809b9db569 100644 --- a/chromium/ui/compositor/layer_animator.cc +++ b/chromium/ui/compositor/layer_animator.cc @@ -12,9 +12,9 @@ #include "base/trace_event/trace_event.h" #include "cc/animation/animation_host.h" #include "cc/animation/animation_id_provider.h" -#include "cc/animation/animation_player.h" #include "cc/animation/animation_timeline.h" #include "cc/animation/element_animations.h" +#include "cc/animation/single_keyframe_effect_animation.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" @@ -55,8 +55,8 @@ LayerAnimator::LayerAnimator(base::TimeDelta transition_duration) disable_timer_for_test_(false), adding_animations_(false), animation_metrics_reporter_(nullptr) { - animation_player_ = - cc::AnimationPlayer::Create(cc::AnimationIdProvider::NextPlayerId()); + animation_ = cc::SingleKeyframeEffectAnimation::Create( + cc::AnimationIdProvider::NextAnimationId()); } LayerAnimator::~LayerAnimator() { @@ -66,7 +66,7 @@ LayerAnimator::~LayerAnimator() { } ClearAnimationsInternal(); delegate_ = NULL; - DCHECK(!animation_player_->animation_timeline()); + DCHECK(!animation_->animation_timeline()); } // static @@ -138,9 +138,9 @@ void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) { void LayerAnimator::SwitchToLayer(scoped_refptr<cc::Layer> new_layer) { if (delegate_) - DetachLayerFromAnimationPlayer(); + DetachLayerFromAnimation(); if (new_layer) - AttachLayerToAnimationPlayer(new_layer->id()); + AttachLayerToAnimation(new_layer->id()); } void LayerAnimator::AttachLayerAndTimeline(Compositor* compositor) { @@ -148,10 +148,10 @@ void LayerAnimator::AttachLayerAndTimeline(Compositor* compositor) { cc::AnimationTimeline* timeline = compositor->GetAnimationTimeline(); DCHECK(timeline); - timeline->AttachPlayer(animation_player_); + timeline->AttachAnimation(animation_); DCHECK(delegate_->GetCcLayer()); - AttachLayerToAnimationPlayer(delegate_->GetCcLayer()->id()); + AttachLayerToAnimation(delegate_->GetCcLayer()->id()); } void LayerAnimator::DetachLayerAndTimeline(Compositor* compositor) { @@ -160,39 +160,40 @@ void LayerAnimator::DetachLayerAndTimeline(Compositor* compositor) { cc::AnimationTimeline* timeline = compositor->GetAnimationTimeline(); DCHECK(timeline); - DetachLayerFromAnimationPlayer(); - timeline->DetachPlayer(animation_player_); + DetachLayerFromAnimation(); + timeline->DetachAnimation(animation_); } -void LayerAnimator::AttachLayerToAnimationPlayer(int layer_id) { +void LayerAnimator::AttachLayerToAnimation(int layer_id) { // For ui, layer and element ids are equivalent. cc::ElementId element_id(layer_id); - if (!animation_player_->element_id()) - animation_player_->AttachElement(element_id); + if (!animation_->element_id()) + animation_->AttachElement(element_id); else - DCHECK_EQ(animation_player_->element_id(), element_id); + DCHECK_EQ(animation_->element_id(), element_id); - animation_player_->set_animation_delegate(this); + animation_->set_animation_delegate(this); } -void LayerAnimator::DetachLayerFromAnimationPlayer() { - animation_player_->set_animation_delegate(nullptr); +void LayerAnimator::DetachLayerFromAnimation() { + animation_->set_animation_delegate(nullptr); - if (animation_player_->element_id()) - animation_player_->DetachElement(); + if (animation_->element_id()) + animation_->DetachElement(); } void LayerAnimator::AddThreadedAnimation( - std::unique_ptr<cc::Animation> animation) { - animation_player_->AddAnimation(std::move(animation)); + std::unique_ptr<cc::KeyframeModel> animation) { + animation_->AddKeyframeModel(std::move(animation)); } -void LayerAnimator::RemoveThreadedAnimation(int animation_id) { - animation_player_->RemoveAnimation(animation_id); +void LayerAnimator::RemoveThreadedAnimation(int keyframe_model_id) { + animation_->RemoveKeyframeModel(keyframe_model_id); } -cc::AnimationPlayer* LayerAnimator::GetAnimationPlayerForTesting() const { - return animation_player_.get(); +cc::SingleKeyframeEffectAnimation* LayerAnimator::GetAnimationForTesting() + const { + return animation_.get(); } void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) { diff --git a/chromium/ui/compositor/layer_animator.h b/chromium/ui/compositor/layer_animator.h index 9ad8f5b043d..9f19dce640e 100644 --- a/chromium/ui/compositor/layer_animator.h +++ b/chromium/ui/compositor/layer_animator.h @@ -24,9 +24,9 @@ namespace cc { class Animation; -class AnimationPlayer; class AnimationTimeline; class Layer; +class SingleKeyframeEffectAnimation; } namespace gfx { @@ -114,12 +114,12 @@ class COMPOSITOR_EXPORT LayerAnimator : public base::RefCounted<LayerAnimator>, // Unsubscribe from |cc_layer_| and subscribe to |new_layer|. void SwitchToLayer(scoped_refptr<cc::Layer> new_layer); - // Attach AnimationPlayer to Layer and AnimationTimeline + // Attach Animation to Layer and AnimationTimeline void AttachLayerAndTimeline(Compositor* compositor); - // Detach AnimationPlayer from Layer and AnimationTimeline + // Detach Animation from Layer and AnimationTimeline void DetachLayerAndTimeline(Compositor* compositor); - cc::AnimationPlayer* GetAnimationPlayerForTesting() const; + cc::SingleKeyframeEffectAnimation* GetAnimationForTesting() const; // Sets the animation preemption strategy. This determines the behaviour if // a property is set during an animation. The default is @@ -371,11 +371,12 @@ class COMPOSITOR_EXPORT LayerAnimator : public base::RefCounted<LayerAnimator>, std::unique_ptr<cc::AnimationCurve> curve) override {} // Implementation of LayerThreadedAnimationDelegate. - void AddThreadedAnimation(std::unique_ptr<cc::Animation> animation) override; - void RemoveThreadedAnimation(int animation_id) override; + void AddThreadedAnimation( + std::unique_ptr<cc::KeyframeModel> keyframe_model) override; + void RemoveThreadedAnimation(int keyframe_model_id) override; - void AttachLayerToAnimationPlayer(int layer_id); - void DetachLayerFromAnimationPlayer(); + void AttachLayerToAnimation(int layer_id); + void DetachLayerFromAnimation(); void set_animation_metrics_reporter(AnimationMetricsReporter* reporter) { animation_metrics_reporter_ = reporter; @@ -388,7 +389,7 @@ class COMPOSITOR_EXPORT LayerAnimator : public base::RefCounted<LayerAnimator>, LayerAnimationDelegate* delegate_; // Plays CC animations. - scoped_refptr<cc::AnimationPlayer> animation_player_; + scoped_refptr<cc::SingleKeyframeEffectAnimation> animation_; // The currently running animations. RunningAnimations running_animations_; diff --git a/chromium/ui/compositor/layer_owner_unittest.cc b/chromium/ui/compositor/layer_owner_unittest.cc index c848ee0d538..3a6b60b7083 100644 --- a/chromium/ui/compositor/layer_owner_unittest.cc +++ b/chromium/ui/compositor/layer_owner_unittest.cc @@ -9,7 +9,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/test/null_task_runner.h" -#include "cc/animation/animation_player.h" +#include "cc/animation/single_keyframe_effect_animation.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" @@ -176,7 +176,7 @@ TEST_F(LayerOwnerTestWithCompositor, RecreateNonRootLayerDuringAnimation) { } // Tests that if LayerOwner-derived class destroys layer, then -// LayerAnimator's player becomes detached from compositor timeline. +// LayerAnimator's animation becomes detached from compositor timeline. TEST_F(LayerOwnerTestWithCompositor, DetachTimelineOnAnimatorDeletion) { std::unique_ptr<Layer> root_layer(new Layer); compositor()->SetRootLayer(root_layer.get()); @@ -186,18 +186,18 @@ TEST_F(LayerOwnerTestWithCompositor, DetachTimelineOnAnimatorDeletion) { layer->SetOpacity(0.5f); root_layer->Add(layer); - scoped_refptr<cc::AnimationPlayer> player = - layer->GetAnimator()->GetAnimationPlayerForTesting(); - EXPECT_TRUE(player); - EXPECT_TRUE(player->animation_timeline()); + scoped_refptr<cc::SingleKeyframeEffectAnimation> animation = + layer->GetAnimator()->GetAnimationForTesting(); + EXPECT_TRUE(animation); + EXPECT_TRUE(animation->animation_timeline()); - // Destroying layer/animator must detach animator's player from timeline. + // Destroying layer/animator must detach animator's animation from timeline. owner.DestroyLayerForTesting(); - EXPECT_FALSE(player->animation_timeline()); + EXPECT_FALSE(animation->animation_timeline()); } // Tests that if we run threaded opacity animation on already added layer -// then LayerAnimator's player becomes attached to timeline. +// then LayerAnimator's animation becomes attached to timeline. TEST_F(LayerOwnerTestWithCompositor, AttachTimelineIfAnimatorCreatedAfterSetCompositor) { std::unique_ptr<Layer> root_layer(new Layer); @@ -209,10 +209,10 @@ TEST_F(LayerOwnerTestWithCompositor, layer->SetOpacity(0.5f); - scoped_refptr<cc::AnimationPlayer> player = - layer->GetAnimator()->GetAnimationPlayerForTesting(); - EXPECT_TRUE(player); - EXPECT_TRUE(player->animation_timeline()); + scoped_refptr<cc::SingleKeyframeEffectAnimation> animation = + layer->GetAnimator()->GetAnimationForTesting(); + EXPECT_TRUE(animation); + EXPECT_TRUE(animation->animation_timeline()); } } // namespace ui diff --git a/chromium/ui/compositor/layer_threaded_animation_delegate.h b/chromium/ui/compositor/layer_threaded_animation_delegate.h index 4fcf7f332ec..9b1251d1a17 100644 --- a/chromium/ui/compositor/layer_threaded_animation_delegate.h +++ b/chromium/ui/compositor/layer_threaded_animation_delegate.h @@ -7,17 +7,17 @@ #include <memory> -#include "cc/animation/animation.h" +#include "cc/animation/keyframe_model.h" #include "ui/compositor/compositor_export.h" namespace ui { -// Attach CC animations using this interface. +// Attach CC keyframe_models using this interface. class COMPOSITOR_EXPORT LayerThreadedAnimationDelegate { public: virtual void AddThreadedAnimation( - std::unique_ptr<cc::Animation> animation) = 0; - virtual void RemoveThreadedAnimation(int animation_id) = 0; + std::unique_ptr<cc::KeyframeModel> keyframe_model) = 0; + virtual void RemoveThreadedAnimation(int keyframe_model_id) = 0; protected: virtual ~LayerThreadedAnimationDelegate() {} diff --git a/chromium/ui/compositor/layer_unittest.cc b/chromium/ui/compositor/layer_unittest.cc index 1c8dd0fabde..a544b33d938 100644 --- a/chromium/ui/compositor/layer_unittest.cc +++ b/chromium/ui/compositor/layer_unittest.cc @@ -26,17 +26,14 @@ #include "build/build_config.h" #include "cc/animation/animation_events.h" #include "cc/animation/animation_host.h" -#include "cc/animation/animation_player.h" -#include "cc/animation/animation_ticker.h" +#include "cc/animation/keyframe_effect.h" +#include "cc/animation/single_keyframe_effect_animation.h" #include "cc/layers/layer.h" #include "cc/test/pixel_test_utils.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/frame_sinks/copy_output_result.h" #include "components/viz/common/resources/transferable_resource.h" -#include "components/viz/common/surfaces/sequence_surface_reference_factory.h" #include "components/viz/common/surfaces/surface_id.h" -#include "components/viz/common/surfaces/surface_reference_factory.h" -#include "components/viz/common/surfaces/surface_sequence.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2.h" @@ -1833,26 +1830,6 @@ TEST_F(LayerWithDelegateTest, SetBoundsWhenInvisible) { EXPECT_TRUE(delegate.painted()); } -namespace { - -class TestSurfaceReferenceFactory - : public viz::SequenceSurfaceReferenceFactory { - public: - TestSurfaceReferenceFactory() = default; - - private: - ~TestSurfaceReferenceFactory() override = default; - - // cc::SequenceSurfaceReferenceFactory implementation: - void SatisfySequence(const viz::SurfaceSequence& seq) const override {} - void RequireSequence(const viz::SurfaceId& id, - const viz::SurfaceSequence& seq) const override {} - - DISALLOW_COPY_AND_ASSIGN(TestSurfaceReferenceFactory); -}; - -} // namespace - TEST_F(LayerWithDelegateTest, ExternalContent) { std::unique_ptr<Layer> root( CreateNoTextureLayer(gfx::Rect(0, 0, 1000, 1000))); @@ -1865,6 +1842,7 @@ TEST_F(LayerWithDelegateTest, ExternalContent) { // The layer is already showing solid color content, so the cc layer won't // change. scoped_refptr<cc::Layer> before = child->cc_layer_for_testing(); + child->SetShowSolidColorContent(); EXPECT_TRUE(child->cc_layer_for_testing()); EXPECT_EQ(before.get(), child->cc_layer_for_testing()); @@ -1873,9 +1851,17 @@ TEST_F(LayerWithDelegateTest, ExternalContent) { before = child->cc_layer_for_testing(); child->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10), SK_ColorWHITE, - new TestSurfaceReferenceFactory()); - EXPECT_TRUE(child->cc_layer_for_testing()); - EXPECT_NE(before.get(), child->cc_layer_for_testing()); + cc::DeadlinePolicy::UseDefaultDeadline()); + scoped_refptr<cc::Layer> after = child->cc_layer_for_testing(); + const auto* surface = static_cast<cc::SurfaceLayer*>(after.get()); + EXPECT_TRUE(after.get()); + EXPECT_NE(before.get(), after.get()); + EXPECT_EQ(base::nullopt, surface->deadline_in_frames()); + + child->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10), + SK_ColorWHITE, + cc::DeadlinePolicy::UseSpecifiedDeadline(4u)); + EXPECT_EQ(4u, surface->deadline_in_frames()); // Changing to painted content should change the underlying cc layer. before = child->cc_layer_for_testing(); @@ -1886,14 +1872,12 @@ TEST_F(LayerWithDelegateTest, ExternalContent) { TEST_F(LayerWithDelegateTest, ExternalContentMirroring) { std::unique_ptr<Layer> layer(CreateLayer(LAYER_SOLID_COLOR)); - scoped_refptr<viz::SurfaceReferenceFactory> reference_factory( - new TestSurfaceReferenceFactory()); viz::SurfaceId surface_id( viz::FrameSinkId(0, 1), viz::LocalSurfaceId(2, base::UnguessableToken::Create())); layer->SetShowPrimarySurface(surface_id, gfx::Size(10, 10), SK_ColorWHITE, - reference_factory); + cc::DeadlinePolicy::UseDefaultDeadline()); const auto mirror = layer->Mirror(); auto* const cc_layer = mirror->cc_layer_for_testing(); @@ -1906,12 +1890,12 @@ TEST_F(LayerWithDelegateTest, ExternalContentMirroring) { viz::SurfaceId(viz::FrameSinkId(1, 2), viz::LocalSurfaceId(3, base::UnguessableToken::Create())); layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE, - reference_factory); + cc::DeadlinePolicy::UseDefaultDeadline()); // The mirror should continue to use the same cc_layer. EXPECT_EQ(cc_layer, mirror->cc_layer_for_testing()); layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE, - reference_factory); + cc::DeadlinePolicy::UseDefaultDeadline()); // Surface updates propagate to the mirror. EXPECT_EQ(surface_id, surface->primary_surface_id()); @@ -1933,7 +1917,7 @@ TEST_F(LayerWithDelegateTest, LayerFiltersSurvival) { scoped_refptr<cc::Layer> before = layer->cc_layer_for_testing(); layer->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10), SK_ColorWHITE, - new TestSurfaceReferenceFactory()); + cc::DeadlinePolicy::UseDefaultDeadline()); EXPECT_EQ(layer->layer_grayscale(), 0.5f); EXPECT_TRUE(layer->cc_layer_for_testing()); EXPECT_NE(before.get(), layer->cc_layer_for_testing()); @@ -1949,43 +1933,43 @@ TEST_F(LayerWithRealCompositorTest, AddRemoveThreadedAnimations) { l1->SetAnimator(LayerAnimator::CreateImplicitAnimator()); l2->SetAnimator(LayerAnimator::CreateImplicitAnimator()); - auto* player1 = l1->GetAnimator()->GetAnimationPlayerForTesting(); - auto* player2 = l2->GetAnimator()->GetAnimationPlayerForTesting(); + auto* animation1 = l1->GetAnimator()->GetAnimationForTesting(); + auto* animation2 = l2->GetAnimator()->GetAnimationForTesting(); - EXPECT_FALSE(player1->has_any_animation()); + EXPECT_FALSE(animation1->keyframe_effect()->has_any_keyframe_model()); // Trigger a threaded animation. l1->SetOpacity(0.5f); - EXPECT_TRUE(player1->has_any_animation()); + EXPECT_TRUE(animation1->keyframe_effect()->has_any_keyframe_model()); // Ensure we can remove a pending threaded animation. l1->GetAnimator()->StopAnimating(); - EXPECT_FALSE(player1->has_any_animation()); + EXPECT_FALSE(animation1->keyframe_effect()->has_any_keyframe_model()); // Trigger another threaded animation. l1->SetOpacity(0.2f); - EXPECT_TRUE(player1->has_any_animation()); + EXPECT_TRUE(animation1->keyframe_effect()->has_any_keyframe_model()); root->Add(l1.get()); GetCompositor()->SetRootLayer(root.get()); // Now l1 is part of a tree. - EXPECT_TRUE(player1->has_any_animation()); + EXPECT_TRUE(animation1->keyframe_effect()->has_any_keyframe_model()); l1->SetOpacity(0.1f); // IMMEDIATELY_SET_NEW_TARGET is a default preemption strategy for conflicting // animations. - EXPECT_FALSE(player1->has_any_animation()); + EXPECT_FALSE(animation1->keyframe_effect()->has_any_keyframe_model()); // Adding a layer to an existing tree. l2->SetOpacity(0.5f); - EXPECT_TRUE(player2->has_any_animation()); + EXPECT_TRUE(animation2->keyframe_effect()->has_any_keyframe_model()); l1->Add(l2.get()); - EXPECT_TRUE(player2->has_any_animation()); + EXPECT_TRUE(animation2->keyframe_effect()->has_any_keyframe_model()); } // Tests that in-progress threaded animations complete when a Layer's @@ -2222,7 +2206,7 @@ TEST_F(LayerWithDelegateTest, NonAnimatingAnimatorsAreRemovedFromCollection) { namespace { -std::string Vector2dFTo100thPercisionString(const gfx::Vector2dF& vector) { +std::string Vector2dFTo100thPrecisionString(const gfx::Vector2dF& vector) { return base::StringPrintf("%.2f %0.2f", vector.x(), vector.y()); } @@ -2245,21 +2229,68 @@ TEST_F(LayerWithRealCompositorTest, SnapLayerToPixels) { SnapLayerToPhysicalPixelBoundary(root.get(), c11.get()); // 0.5 at 1.25 scale : (1 - 0.25 + 0.25) / 1.25 = 0.4 EXPECT_EQ("0.40 0.40", - Vector2dFTo100thPercisionString(c11->subpixel_position_offset())); + Vector2dFTo100thPrecisionString(c11->subpixel_position_offset())); GetCompositor()->SetScaleAndSize(1.5f, gfx::Size(100, 100), viz::LocalSurfaceId()); SnapLayerToPhysicalPixelBoundary(root.get(), c11.get()); // c11 must already be aligned at 1.5 scale. EXPECT_EQ("0.00 0.00", - Vector2dFTo100thPercisionString(c11->subpixel_position_offset())); + Vector2dFTo100thPrecisionString(c11->subpixel_position_offset())); c11->SetBounds(gfx::Rect(2, 2, 10, 10)); SnapLayerToPhysicalPixelBoundary(root.get(), c11.get()); // c11 is now off the pixel. // 0.5 / 1.5 = 0.333... EXPECT_EQ("0.33 0.33", - Vector2dFTo100thPercisionString(c11->subpixel_position_offset())); + Vector2dFTo100thPrecisionString(c11->subpixel_position_offset())); +} + +TEST_F(LayerWithRealCompositorTest, SnapLayerToPixelsWithScaleTransform) { + std::unique_ptr<Layer> root(CreateLayer(LAYER_TEXTURED)); + std::unique_ptr<Layer> c1(CreateLayer(LAYER_TEXTURED)); + std::unique_ptr<Layer> c11(CreateLayer(LAYER_TEXTURED)); + std::unique_ptr<Layer> c111(CreateLayer(LAYER_TEXTURED)); + + GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(100, 100), + viz::LocalSurfaceId()); + GetCompositor()->SetRootLayer(root.get()); + root->Add(c1.get()); + c1->Add(c11.get()); + c11->Add(c111.get()); + + root->SetBounds(gfx::Rect(0, 0, 100, 100)); + c1->SetBounds(gfx::Rect(0, 0, 10, 10)); + c11->SetBounds(gfx::Rect(0, 0, 10, 10)); + c111->SetBounds(gfx::Rect(2, 2, 5, 5)); + + gfx::Transform transform; + transform.Scale(1.25f, 1.25f); + + c1->SetTransform(transform); + SnapLayerToPhysicalPixelBoundary(root.get(), c111.get()); + + // c111 ends up at 2.5, and is supposed to be snapped to 3.0. So subpixel + // offset is expected to be: + // 0.5 / 1.25 = 0.40 + EXPECT_EQ("0.40 0.40", + Vector2dFTo100thPrecisionString(c111->subpixel_position_offset())); + + c11->SetTransform(transform); + SnapLayerToPhysicalPixelBoundary(root.get(), c111.get()); + + // c111 ends up at 3.125, and is supposed to be snapped to 3.0. So subpixel + // offset is expected to be: + // -0.125 / (1.25 * 1.25) = -0.08 + EXPECT_EQ("-0.08 -0.08", + Vector2dFTo100thPrecisionString(c111->subpixel_position_offset())); + + // A transform on c111 should not affect the subpixel offset so expect it to + // be the same as before. + c111->SetTransform(transform); + SnapLayerToPhysicalPixelBoundary(root.get(), c111.get()); + EXPECT_EQ("-0.08 -0.08", + Vector2dFTo100thPrecisionString(c111->subpixel_position_offset())); } // Verify that LayerDelegate::OnLayerBoundsChanged() is called when the bounds diff --git a/chromium/ui/display/OWNERS b/chromium/ui/display/OWNERS index 69f028b378a..e60ce6577fc 100644 --- a/chromium/ui/display/OWNERS +++ b/chromium/ui/display/OWNERS @@ -1,3 +1,4 @@ derat@chromium.org marcheu@chromium.org oshima@chromium.org +afakhry@chromium.org diff --git a/chromium/ui/display/display.cc b/chromium/ui/display/display.cc index 487676642cb..9a10474c49a 100644 --- a/chromium/ui/display/display.cc +++ b/chromium/ui/display/display.cc @@ -300,4 +300,17 @@ bool Display::HasInternalDisplay() { return internal_display_id_ != kInvalidDisplayId; } +bool Display::operator==(const Display& rhs) const { + return id_ == rhs.id_ && bounds_ == rhs.bounds_ && + size_in_pixels_ == rhs.size_in_pixels_ && + work_area_ == rhs.work_area_ && + device_scale_factor_ == rhs.device_scale_factor_ && + rotation_ == rhs.rotation_ && touch_support_ == rhs.touch_support_ && + accelerometer_support_ == rhs.accelerometer_support_ && + maximum_cursor_size_ == rhs.maximum_cursor_size_ && + color_space_ == rhs.color_space_ && color_depth_ == rhs.color_depth_ && + depth_per_component_ == rhs.depth_per_component_ && + is_monochrome_ == rhs.is_monochrome_; +} + } // namespace display diff --git a/chromium/ui/display/display.h b/chromium/ui/display/display.h index ea598a6ea63..49f76438ef3 100644 --- a/chromium/ui/display/display.h +++ b/chromium/ui/display/display.h @@ -48,29 +48,28 @@ class DISPLAY_EXPORT Display final { // The display rotation can have multiple causes for change. A user can set a // preference. On devices with accelerometers, they can change the rotation. // RotationSource allows for the tracking of a Rotation per source of the - // change. ROTATION_SOURCE_ACTIVE is the current rotation of the display. - // Rotation changes not due to an accelerometer, nor the user, are to use this - // source directly. ROTATION_SOURCE_UNKNOWN is when no rotation source has - // been provided. - enum RotationSource { - ROTATION_SOURCE_ACCELEROMETER = 0, - ROTATION_SOURCE_ACTIVE, - ROTATION_SOURCE_USER, - ROTATION_SOURCE_UNKNOWN, + // change. ACTIVE is the current rotation of the display. Rotation changes not + // due to an accelerometer, nor the user, are to use this source directly. + // UNKNOWN is when no rotation source has been provided. + enum class RotationSource { + ACCELEROMETER = 0, + ACTIVE, + USER, + UNKNOWN, }; // Touch support for the display. - enum TouchSupport { - TOUCH_SUPPORT_UNKNOWN, - TOUCH_SUPPORT_AVAILABLE, - TOUCH_SUPPORT_UNAVAILABLE, + enum class TouchSupport { + UNKNOWN, + AVAILABLE, + UNAVAILABLE, }; // Accelerometer support for the display. - enum AccelerometerSupport { - ACCELEROMETER_SUPPORT_UNKNOWN, - ACCELEROMETER_SUPPORT_AVAILABLE, - ACCELEROMETER_SUPPORT_UNAVAILABLE, + enum class AccelerometerSupport { + UNKNOWN, + AVAILABLE, + UNAVAILABLE, }; // Creates a display with kInvalidDisplayId as default. @@ -143,8 +142,7 @@ class DISPLAY_EXPORT Display final { accelerometer_support_ = support; } - // Utility functions that just return the size of display and - // work area. + // Utility functions that just return the size of display and work area. const gfx::Size& size() const { return bounds_.size(); } const gfx::Size& work_area_size() const { return work_area_.size(); } @@ -226,6 +224,9 @@ class DISPLAY_EXPORT Display final { is_monochrome_ = is_monochrome; } + bool operator==(const Display& rhs) const; + bool operator!=(const Display& rhs) const { return !(*this == rhs); } + private: friend struct mojo::StructTraits<mojom::DisplayDataView, Display>; @@ -237,8 +238,8 @@ class DISPLAY_EXPORT Display final { gfx::Rect work_area_; float device_scale_factor_; Rotation rotation_ = ROTATE_0; - TouchSupport touch_support_ = TOUCH_SUPPORT_UNKNOWN; - AccelerometerSupport accelerometer_support_ = ACCELEROMETER_SUPPORT_UNKNOWN; + TouchSupport touch_support_ = TouchSupport::UNKNOWN; + AccelerometerSupport accelerometer_support_ = AccelerometerSupport::UNKNOWN; gfx::Size maximum_cursor_size_; // NOTE: this is not currently written to the mojom as it is not used in // aura. diff --git a/chromium/ui/display/display_switches.cc b/chromium/ui/display/display_switches.cc index c121928f527..d06ee064e1e 100644 --- a/chromium/ui/display/display_switches.cc +++ b/chromium/ui/display/display_switches.cc @@ -53,12 +53,8 @@ const char kScreenConfig[] = "screen-config"; const char kUseFirstDisplayAsInternal[] = "use-first-display-as-internal"; #if defined(OS_CHROMEOS) - // Enables unified desktop mode. const char kEnableUnifiedDesktop[] = "ash-enable-unified-desktop"; - -// Enables using the monitor's provided color space information when rendering. -const char kUseMonitorColorSpace[] = "use-monitor-color-space"; #endif } // namespace switches @@ -68,4 +64,11 @@ namespace features { const base::Feature kHighDynamicRange{"HighDynamicRange", base::FEATURE_ENABLED_BY_DEFAULT}; +#if defined(OS_CHROMEOS) +// Enables using the monitor's provided color space information when rendering. +// TODO(mcasas): remove this flag http://crbug.com/771345. +const base::Feature kUseMonitorColorSpace{"UseMonitorColorSpace", + base::FEATURE_DISABLED_BY_DEFAULT}; +#endif + } // namespace features diff --git a/chromium/ui/display/display_switches.h b/chromium/ui/display/display_switches.h index 7d7c5e44f76..da146eb5359 100644 --- a/chromium/ui/display/display_switches.h +++ b/chromium/ui/display/display_switches.h @@ -26,7 +26,6 @@ DISPLAY_EXPORT extern const char kUseFirstDisplayAsInternal[]; #if defined(OS_CHROMEOS) DISPLAY_EXPORT extern const char kEnableUnifiedDesktop[]; -DISPLAY_EXPORT extern const char kUseMonitorColorSpace[]; #endif } // namespace switches @@ -35,6 +34,10 @@ namespace features { DISPLAY_EXPORT extern const base::Feature kHighDynamicRange; +#if defined(OS_CHROMEOS) +DISPLAY_EXPORT extern const base::Feature kUseMonitorColorSpace; +#endif + } // namespace features #endif // UI_DISPLAY_DISPLAY_SWITCHES_H_ diff --git a/chromium/ui/display/mac/screen_mac.mm b/chromium/ui/display/mac/screen_mac.mm index 13800125153..4850c795480 100644 --- a/chromium/ui/display/mac/screen_mac.mm +++ b/chromium/ui/display/mac/screen_mac.mm @@ -170,8 +170,8 @@ class ScreenMac : public Screen { } bool IsWindowUnderCursor(gfx::NativeWindow window) override { - NOTIMPLEMENTED(); - return false; + return [NSWindow windowNumberAtPoint:[NSEvent mouseLocation] + belowWindowWithWindowNumber:0] == [window windowNumber]; } gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override { diff --git a/chromium/ui/display/manager/chromeos/display_configurator.cc b/chromium/ui/display/manager/chromeos/display_configurator.cc index b85425bc3f0..b077a4b25db 100644 --- a/chromium/ui/display/manager/chromeos/display_configurator.cc +++ b/chromium/ui/display/manager/chromeos/display_configurator.cc @@ -41,8 +41,6 @@ struct DisplayState { const DisplayMode* mirror_mode = nullptr; }; -void DoNothing(bool status) {} - } // namespace const int DisplayConfigurator::kSetDisplayPowerNoFlags = 0; @@ -595,7 +593,7 @@ void DisplayConfigurator::OnDisplayControlTaken(DisplayControlCallback callback, force_configure_ = true; // Restore the last power state used before releasing control. SetDisplayPower(requested_power_state_, kSetDisplayPowerNoFlags, - base::Bind(&DoNothing)); + base::DoNothing()); } std::move(callback).Run(success); @@ -695,7 +693,7 @@ void DisplayConfigurator::UnregisterContentProtectionClient( } } - set_protection_callbacks_.push(base::Bind(&DoNothing)); + set_protection_callbacks_.push(base::DoNothing()); ApplyContentProtectionTask* task = new ApplyContentProtectionTask( layout_manager_.get(), native_display_delegate_.get(), protections, base::Bind(&DisplayConfigurator::OnContentProtectionClientUnregistered, @@ -1010,7 +1008,7 @@ void DisplayConfigurator::ResumeDisplays() { // If requested_power_state_ is ALL_OFF due to idle suspend, powerd will turn // the display power on when it enables the backlight. SetDisplayPower(requested_power_state_, kSetDisplayPowerNoFlags, - base::Bind(&DoNothing)); + base::DoNothing()); } void DisplayConfigurator::ConfigureDisplays() { diff --git a/chromium/ui/display/manager/chromeos/touch_device_manager.cc b/chromium/ui/display/manager/chromeos/touch_device_manager.cc index 4289ec261c3..4ffd851a402 100644 --- a/chromium/ui/display/manager/chromeos/touch_device_manager.cc +++ b/chromium/ui/display/manager/chromeos/touch_device_manager.cc @@ -263,7 +263,7 @@ void TouchDeviceManager::AssociateTouchscreens( ManagedDisplayInfoList displays; for (ManagedDisplayInfo& display : *all_displays) { // Reset touch support from the display. - display.set_touch_support(Display::TOUCH_SUPPORT_UNAVAILABLE); + display.set_touch_support(Display::TouchSupport::UNAVAILABLE); displays.push_back(&display); } @@ -496,7 +496,7 @@ void TouchDeviceManager::AssociateAnyRemainingDevices( void TouchDeviceManager::Associate(ManagedDisplayInfo* display, const ui::TouchscreenDevice& device) { - display->set_touch_support(Display::TOUCH_SUPPORT_AVAILABLE); + display->set_touch_support(Display::TouchSupport::AVAILABLE); active_touch_associations_[TouchDeviceIdentifier::FromDevice(device)] = display->id(); } diff --git a/chromium/ui/display/manager/chromeos/update_display_configuration_task.cc b/chromium/ui/display/manager/chromeos/update_display_configuration_task.cc index 74a17bcb07c..70e19c34920 100644 --- a/chromium/ui/display/manager/chromeos/update_display_configuration_task.cc +++ b/chromium/ui/display/manager/chromeos/update_display_configuration_task.cc @@ -27,7 +27,6 @@ UpdateDisplayConfigurationTask::UpdateDisplayConfigurationTask( power_flags_(power_flags), force_configure_(force_configure), callback_(callback), - force_dpms_(false), requesting_displays_(false), weak_ptr_factory_(this) { delegate_->AddObserver(this); @@ -72,10 +71,6 @@ void UpdateDisplayConfigurationTask::OnDisplaysUpdated( << " flags=" << power_flags_ << " force_configure=" << force_configure_ << " display_count=" << cached_displays_.size(); - // If there has been any change in the requested power state and the displays - // aren't being turned off force a change in DPMS state. - force_dpms_ = ShouldForceDpms() && ShouldConfigure(); - if (ShouldConfigure()) { EnterState(base::Bind(&UpdateDisplayConfigurationTask::OnStateEntered, weak_ptr_factory_.GetWeakPtr())); diff --git a/chromium/ui/display/manager/chromeos/update_display_configuration_task.h b/chromium/ui/display/manager/chromeos/update_display_configuration_task.h index 1538fd0f2e3..13c0df36147 100644 --- a/chromium/ui/display/manager/chromeos/update_display_configuration_task.h +++ b/chromium/ui/display/manager/chromeos/update_display_configuration_task.h @@ -93,8 +93,6 @@ class DISPLAY_MANAGER_EXPORT UpdateDisplayConfigurationTask // Used to signal that the task has finished. ResponseCallback callback_; - bool force_dpms_; - bool requesting_displays_; // List of updated displays. diff --git a/chromium/ui/display/manager/display_manager.cc b/chromium/ui/display/manager/display_manager.cc index fc1d98157ac..e7fd443794b 100644 --- a/chromium/ui/display/manager/display_manager.cc +++ b/chromium/ui/display/manager/display_manager.cc @@ -648,9 +648,9 @@ void DisplayManager::RegisterDisplayProperty( rotation = Display::ROTATE_0; display_info_[display_id].SetRotation(rotation, - Display::ROTATION_SOURCE_USER); + Display::RotationSource::USER); display_info_[display_id].SetRotation(rotation, - Display::ROTATION_SOURCE_ACTIVE); + Display::RotationSource::ACTIVE); // Just in case the preference file was corrupted. // TODO(mukai): register |display_modes_| here as well, so the lookup for the // default mode in GetActiveModeForDisplayId() gets much simpler. @@ -850,9 +850,9 @@ void DisplayManager::OnNativeDisplaysChanged( // active again. Display::Rotation user_rotation = display_info_[Display::InternalDisplayId()].GetRotation( - Display::ROTATION_SOURCE_USER); + Display::RotationSource::USER); display_info_[Display::InternalDisplayId()].SetRotation( - user_rotation, Display::ROTATION_SOURCE_USER); + user_rotation, Display::RotationSource::USER); } } @@ -1433,7 +1433,7 @@ void DisplayManager::SetTouchCalibrationData( for (const auto& display : active_display_list_) { ManagedDisplayInfo info = GetDisplayInfo(display.id()); if (info.id() == display_id) { - info.set_touch_support(Display::TOUCH_SUPPORT_AVAILABLE); + info.set_touch_support(Display::TouchSupport::AVAILABLE); update_add_support = true; } else if (info.id() == previous_display_id) { // Since we are reassociating the touch device to another display, we need @@ -1442,7 +1442,7 @@ void DisplayManager::SetTouchCalibrationData( if (!touch_device_manager_ ->GetAssociatedTouchDevicesForDisplay(previous_display_id) .empty()) { - info.set_touch_support(Display::TOUCH_SUPPORT_UNAVAILABLE); + info.set_touch_support(Display::TouchSupport::UNAVAILABLE); update_remove_support = true; } } @@ -1452,14 +1452,14 @@ void DisplayManager::SetTouchCalibrationData( // Update the non active displays. if (!update_add_support) { display_info_[display_id].set_touch_support( - Display::TOUCH_SUPPORT_AVAILABLE); + Display::TouchSupport::AVAILABLE); } if (!update_remove_support && !touch_device_manager_ ->GetAssociatedTouchDevicesForDisplay(previous_display_id) .empty()) { display_info_[previous_display_id].set_touch_support( - Display::TOUCH_SUPPORT_UNAVAILABLE); + Display::TouchSupport::UNAVAILABLE); } // Update the active displays. if (update_add_support || update_remove_support) @@ -1983,8 +1983,8 @@ Display DisplayManager::CreateDisplayFromDisplayInfoById(int64_t id) { new_display.set_touch_support(display_info.touch_support()); new_display.set_maximum_cursor_size(display_info.maximum_cursor_size()); #if defined(OS_CHROMEOS) - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(::switches::kUseMonitorColorSpace)) + // TODO(mcasas): remove this check, http://crbug.com/771345. + if (base::FeatureList::IsEnabled(features::kUseMonitorColorSpace)) new_display.set_color_space(display_info.color_space()); #else new_display.set_color_space(display_info.color_space()); @@ -1992,10 +1992,10 @@ Display DisplayManager::CreateDisplayFromDisplayInfoById(int64_t id) { if (internal_display_has_accelerometer_ && Display::IsInternalDisplayId(id)) { new_display.set_accelerometer_support( - Display::ACCELEROMETER_SUPPORT_AVAILABLE); + Display::AccelerometerSupport::AVAILABLE); } else { new_display.set_accelerometer_support( - Display::ACCELEROMETER_SUPPORT_UNAVAILABLE); + Display::AccelerometerSupport::UNAVAILABLE); } return new_display; } diff --git a/chromium/ui/display/manager/display_manager.h b/chromium/ui/display/manager/display_manager.h index 58bfde04d50..2ff69b5e70c 100644 --- a/chromium/ui/display/manager/display_manager.h +++ b/chromium/ui/display/manager/display_manager.h @@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include <algorithm> #include <map> #include <memory> #include <string> @@ -16,6 +17,7 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -354,6 +356,17 @@ class DISPLAY_MANAGER_EXPORT DisplayManager mixed_mirror_mode_params_ = mixed_params; } + void dec_screen_capture_active_counter() { + DCHECK_GT(screen_capture_active_counter_, 0); + screen_capture_active_counter_--; + } + + void inc_screen_capture_active_counter() { ++screen_capture_active_counter_; } + + bool screen_capture_is_active() const { + return screen_capture_active_counter_ > 0; + } + // Remove mirroring source and destination displays, so that they will be // updated when UpdateDisplaysWith() is called. void ClearMirroringSourceAndDestination(); @@ -646,6 +659,10 @@ class DISPLAY_MANAGER_EXPORT DisplayManager bool internal_display_has_accelerometer_ = false; + // Set during screen capture to enable software compositing of mouse cursor, + // this is a counter to enable multiple active sessions at once. + int screen_capture_active_counter_ = 0; + base::Closure created_mirror_window_; base::ObserverList<DisplayObserver> observers_; diff --git a/chromium/ui/display/manager/managed_display_info.cc b/chromium/ui/display/manager/managed_display_info.cc index 7e025920fa2..c4906316e61 100644 --- a/chromium/ui/display/manager/managed_display_info.cc +++ b/chromium/ui/display/manager/managed_display_info.cc @@ -240,7 +240,7 @@ ManagedDisplayInfo ManagedDisplayInfo::CreateFromSpecWithID( ManagedDisplayInfo display_info( id, base::StringPrintf("Display-%d", static_cast<int>(id)), has_overscan); display_info.set_device_scale_factor(device_scale_factor); - display_info.SetRotation(rotation, Display::ROTATION_SOURCE_ACTIVE); + display_info.SetRotation(rotation, Display::RotationSource::ACTIVE); display_info.set_configured_ui_scale(ui_scale); display_info.SetBounds(bounds_in_native); display_info.SetManagedDisplayModes(display_modes); @@ -261,8 +261,8 @@ ManagedDisplayInfo ManagedDisplayInfo::CreateFromSpecWithID( ManagedDisplayInfo::ManagedDisplayInfo() : id_(kInvalidDisplayId), has_overscan_(false), - active_rotation_source_(Display::ROTATION_SOURCE_UNKNOWN), - touch_support_(Display::TOUCH_SUPPORT_UNKNOWN), + active_rotation_source_(Display::RotationSource::UNKNOWN), + touch_support_(Display::TouchSupport::UNKNOWN), device_scale_factor_(1.0f), device_dpi_(kDpi96), overscan_insets_in_dip_(0, 0, 0, 0), @@ -277,8 +277,8 @@ ManagedDisplayInfo::ManagedDisplayInfo(int64_t id, : id_(id), name_(name), has_overscan_(has_overscan), - active_rotation_source_(Display::ROTATION_SOURCE_UNKNOWN), - touch_support_(Display::TOUCH_SUPPORT_UNKNOWN), + active_rotation_source_(Display::RotationSource::UNKNOWN), + touch_support_(Display::TouchSupport::UNKNOWN), device_scale_factor_(1.0f), device_dpi_(kDpi96), overscan_insets_in_dip_(0, 0, 0, 0), @@ -295,12 +295,12 @@ ManagedDisplayInfo::~ManagedDisplayInfo() {} void ManagedDisplayInfo::SetRotation(Display::Rotation rotation, Display::RotationSource source) { rotations_[source] = rotation; - rotations_[Display::ROTATION_SOURCE_ACTIVE] = rotation; + rotations_[Display::RotationSource::ACTIVE] = rotation; active_rotation_source_ = source; } Display::Rotation ManagedDisplayInfo::GetActiveRotation() const { - return GetRotation(Display::ROTATION_SOURCE_ACTIVE); + return GetRotation(Display::RotationSource::ACTIVE); } Display::Rotation ManagedDisplayInfo::GetRotation( @@ -423,9 +423,9 @@ std::string ManagedDisplayInfo::ToString() const { size_in_pixel_.ToString().c_str(), device_scale_factor_, overscan_insets_in_dip_.ToString().c_str(), rotation_degree, configured_ui_scale_, - touch_support_ == Display::TOUCH_SUPPORT_AVAILABLE + touch_support_ == Display::TouchSupport::AVAILABLE ? "yes" - : touch_support_ == Display::TOUCH_SUPPORT_UNAVAILABLE ? "no" + : touch_support_ == Display::TouchSupport::UNAVAILABLE ? "no" : "unknown"); return result; diff --git a/chromium/ui/display/mojo/display_struct_traits.cc b/chromium/ui/display/mojo/display_struct_traits.cc index 4b61b0a0950..2603edefccc 100644 --- a/chromium/ui/display/mojo/display_struct_traits.cc +++ b/chromium/ui/display/mojo/display_struct_traits.cc @@ -48,11 +48,11 @@ display::mojom::TouchSupport EnumTraits<display::mojom::TouchSupport, display::Display::TouchSupport>:: ToMojom(display::Display::TouchSupport touch_support) { switch (touch_support) { - case display::Display::TOUCH_SUPPORT_UNKNOWN: + case display::Display::TouchSupport::UNKNOWN: return display::mojom::TouchSupport::UNKNOWN; - case display::Display::TOUCH_SUPPORT_AVAILABLE: + case display::Display::TouchSupport::AVAILABLE: return display::mojom::TouchSupport::AVAILABLE; - case display::Display::TOUCH_SUPPORT_UNAVAILABLE: + case display::Display::TouchSupport::UNAVAILABLE: return display::mojom::TouchSupport::UNAVAILABLE; } NOTREACHED(); @@ -64,13 +64,13 @@ bool EnumTraits<display::mojom::TouchSupport, display::Display::TouchSupport>:: display::Display::TouchSupport* out) { switch (touch_support) { case display::mojom::TouchSupport::UNKNOWN: - *out = display::Display::TOUCH_SUPPORT_UNKNOWN; + *out = display::Display::TouchSupport::UNKNOWN; return true; case display::mojom::TouchSupport::AVAILABLE: - *out = display::Display::TOUCH_SUPPORT_AVAILABLE; + *out = display::Display::TouchSupport::AVAILABLE; return true; case display::mojom::TouchSupport::UNAVAILABLE: - *out = display::Display::TOUCH_SUPPORT_UNAVAILABLE; + *out = display::Display::TouchSupport::UNAVAILABLE; return true; } NOTREACHED(); @@ -82,11 +82,11 @@ EnumTraits<display::mojom::AccelerometerSupport, display::Display::AccelerometerSupport>:: ToMojom(display::Display::AccelerometerSupport accelerometer_support) { switch (accelerometer_support) { - case display::Display::ACCELEROMETER_SUPPORT_UNKNOWN: + case display::Display::AccelerometerSupport::UNKNOWN: return display::mojom::AccelerometerSupport::UNKNOWN; - case display::Display::ACCELEROMETER_SUPPORT_AVAILABLE: + case display::Display::AccelerometerSupport::AVAILABLE: return display::mojom::AccelerometerSupport::AVAILABLE; - case display::Display::ACCELEROMETER_SUPPORT_UNAVAILABLE: + case display::Display::AccelerometerSupport::UNAVAILABLE: return display::mojom::AccelerometerSupport::UNAVAILABLE; } NOTREACHED(); @@ -99,13 +99,13 @@ bool EnumTraits<display::mojom::AccelerometerSupport, display::Display::AccelerometerSupport* out) { switch (accelerometer_support) { case display::mojom::AccelerometerSupport::UNKNOWN: - *out = display::Display::ACCELEROMETER_SUPPORT_UNKNOWN; + *out = display::Display::AccelerometerSupport::UNKNOWN; return true; case display::mojom::AccelerometerSupport::AVAILABLE: - *out = display::Display::ACCELEROMETER_SUPPORT_AVAILABLE; + *out = display::Display::AccelerometerSupport::AVAILABLE; return true; case display::mojom::AccelerometerSupport::UNAVAILABLE: - *out = display::Display::ACCELEROMETER_SUPPORT_UNAVAILABLE; + *out = display::Display::AccelerometerSupport::UNAVAILABLE; return true; } NOTREACHED(); diff --git a/chromium/ui/display/mojo/display_struct_traits_unittest.cc b/chromium/ui/display/mojo/display_struct_traits_unittest.cc index 3dd7d2e3822..1dd6cf72c8a 100644 --- a/chromium/ui/display/mojo/display_struct_traits_unittest.cc +++ b/chromium/ui/display/mojo/display_struct_traits_unittest.cc @@ -130,8 +130,8 @@ TEST(DisplayStructTraitsTest, SetAllDisplayValues) { input.set_work_area(work_area); input.set_device_scale_factor(2.0f); input.set_rotation(Display::ROTATE_270); - input.set_touch_support(Display::TOUCH_SUPPORT_AVAILABLE); - input.set_accelerometer_support(Display::ACCELEROMETER_SUPPORT_UNAVAILABLE); + input.set_touch_support(Display::TouchSupport::AVAILABLE); + input.set_accelerometer_support(Display::AccelerometerSupport::UNAVAILABLE); input.set_maximum_cursor_size(maximum_cursor_size); input.set_color_depth(input.color_depth() + 1); input.set_depth_per_component(input.depth_per_component() + 1); diff --git a/chromium/ui/display/win/color_profile_reader.cc b/chromium/ui/display/win/color_profile_reader.cc index c53c10e8cc1..7c8d48adeca 100644 --- a/chromium/ui/display/win/color_profile_reader.cc +++ b/chromium/ui/display/win/color_profile_reader.cc @@ -9,7 +9,6 @@ #include "base/files/file_util.h" #include "base/task_scheduler/post_task.h" -#include "base/threading/sequenced_worker_pool.h" #include "ui/display/win/display_info.h" #include "ui/gfx/icc_profile.h" @@ -60,9 +59,6 @@ void ColorProfileReader::UpdateIfNeeded() { if (device_to_path_map_ == new_device_to_path_map) return; - if (!base::SequencedWorkerPool::IsEnabled()) - return; - update_in_flight_ = true; base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND}, diff --git a/chromium/ui/events/BUILD.gn b/chromium/ui/events/BUILD.gn index d6363a7be90..96adf2efb72 100644 --- a/chromium/ui/events/BUILD.gn +++ b/chromium/ui/events/BUILD.gn @@ -99,6 +99,13 @@ component("events_base") { "Carbon.framework", ] } + + if (is_chromecast && !is_android) { + sources += [ + "chromecast/scroller.cc", + "chromecast/scroller.h", + ] + } } component("events") { @@ -130,6 +137,9 @@ component("events") { "events_stub.cc", "gestures/gesture_recognizer_impl_mac.cc", "gestures/gesture_types.h", + "keyboard_hook.h", + "keyboard_hook_base.cc", + "keyboard_hook_base.h", "keycodes/platform_key_map_win.cc", "keycodes/platform_key_map_win.h", "null_event_targeter.cc", @@ -139,8 +149,10 @@ component("events") { "system_input_injector.cc", "system_input_injector.h", "win/events_win.cc", + "win/keyboard_hook_win.cc", "win/system_event_state_lookup.cc", "win/system_event_state_lookup.h", + "x/keyboard_hook_posix.cc", ] defines = [ "EVENTS_IMPLEMENTATION" ] @@ -487,6 +499,10 @@ if (!is_ios) { if (is_win) { sources += [ "blink/web_input_event_builders_win_unittest.cc" ] } + + if (is_chromecast && !is_android) { + sources += [ "chromecast/scroller_unittest.cc" ] + } } } diff --git a/chromium/ui/events/android/gesture_event_android.cc b/chromium/ui/events/android/gesture_event_android.cc index d0f25354b3d..277efb57479 100644 --- a/chromium/ui/events/android/gesture_event_android.cc +++ b/chromium/ui/events/android/gesture_event_android.cc @@ -12,12 +12,24 @@ GestureEventAndroid::GestureEventAndroid(int type, const gfx::PointF& location, const gfx::PointF& screen_location, long time_ms, - float delta) + float scale, + float delta_x, + float delta_y, + float velocity_x, + float velocity_y, + bool target_viewport, + bool synthetic_scroll) : type_(type), location_(location), screen_location_(screen_location), time_ms_(time_ms), - delta_(delta) {} + scale_(scale), + delta_x_(delta_x), + delta_y_(delta_y), + velocity_x_(velocity_x), + velocity_y_(velocity_y), + target_viewport_(target_viewport), + synthetic_scroll_(synthetic_scroll) {} GestureEventAndroid::~GestureEventAndroid() {} @@ -26,7 +38,8 @@ std::unique_ptr<GestureEventAndroid> GestureEventAndroid::CreateFor( auto offset = new_location - location_; gfx::PointF new_screen_location = screen_location_ + offset; return std::unique_ptr<GestureEventAndroid>(new GestureEventAndroid( - type_, new_location, new_screen_location, time_ms_, delta_)); + type_, new_location, new_screen_location, time_ms_, scale_, delta_x_, + delta_y_, velocity_x_, velocity_y_, target_viewport_, synthetic_scroll_)); } } // namespace ui diff --git a/chromium/ui/events/android/gesture_event_android.h b/chromium/ui/events/android/gesture_event_android.h index d07f343ff2c..2824847a103 100644 --- a/chromium/ui/events/android/gesture_event_android.h +++ b/chromium/ui/events/android/gesture_event_android.h @@ -21,7 +21,13 @@ class EVENTS_EXPORT GestureEventAndroid { const gfx::PointF& location, const gfx::PointF& screen_location, long time_ms, - float delta); + float scale, + float delta_x, + float delta_y, + float velocity_x, + float velocity_y, + bool target_viewport, + bool synthetic_scroll); ~GestureEventAndroid(); @@ -29,7 +35,13 @@ class EVENTS_EXPORT GestureEventAndroid { const gfx::PointF& location() const { return location_; } const gfx::PointF& screen_location() const { return screen_location_; } long time() const { return time_ms_; } - float delta() const { return delta_; } + float scale() const { return scale_; } + float delta_x() const { return delta_x_; } + float delta_y() const { return delta_y_; } + float velocity_x() const { return velocity_x_; } + float velocity_y() const { return velocity_y_; } + bool target_viewport() const { return target_viewport_; } + bool synthetic_scroll() const { return synthetic_scroll_; } // Creates a new GestureEventAndroid instance different from |this| only by // its location. @@ -42,7 +54,13 @@ class EVENTS_EXPORT GestureEventAndroid { gfx::PointF screen_location_; long time_ms_; - float delta_; + float scale_; + float delta_x_; + float delta_y_; + float velocity_x_; + float velocity_y_; + bool target_viewport_; + bool synthetic_scroll_; DISALLOW_COPY_AND_ASSIGN(GestureEventAndroid); }; diff --git a/chromium/ui/events/android/motion_event_android.cc b/chromium/ui/events/android/motion_event_android.cc index 433ff446825..a6ad292d344 100644 --- a/chromium/ui/events/android/motion_event_android.cc +++ b/chromium/ui/events/android/motion_event_android.cc @@ -20,43 +20,91 @@ using base::android::ScopedJavaLocalRef; namespace ui { namespace { -#define EVENT_CASE(x) \ - case JNI_MotionEvent::x: \ - return MotionEventAndroid::x +#define ACTION_CASE(x) \ + case JNI_MotionEvent::ACTION_##x: \ + return MotionEventAndroid::Action::x + +#define ACTION_REVERSE_CASE(x) \ + case MotionEventAndroid::Action::x: \ + return JNI_MotionEvent::ACTION_##x + +#define TOOL_TYPE_CASE(x) \ + case JNI_MotionEvent::TOOL_TYPE_##x: \ + return MotionEventAndroid::ToolType::x + +#define TOOL_TYPE_REVERSE_CASE(x) \ + case MotionEventAndroid::ToolType::x: \ + return JNI_MotionEvent::TOOL_TYPE_##x MotionEventAndroid::Action FromAndroidAction(int android_action) { switch (android_action) { - EVENT_CASE(ACTION_DOWN); - EVENT_CASE(ACTION_UP); - EVENT_CASE(ACTION_MOVE); - EVENT_CASE(ACTION_CANCEL); - EVENT_CASE(ACTION_POINTER_DOWN); - EVENT_CASE(ACTION_POINTER_UP); - EVENT_CASE(ACTION_HOVER_ENTER); - EVENT_CASE(ACTION_HOVER_EXIT); - EVENT_CASE(ACTION_HOVER_MOVE); - EVENT_CASE(ACTION_BUTTON_PRESS); - EVENT_CASE(ACTION_BUTTON_RELEASE); + ACTION_CASE(DOWN); + ACTION_CASE(UP); + ACTION_CASE(MOVE); + ACTION_CASE(CANCEL); + ACTION_CASE(POINTER_DOWN); + ACTION_CASE(POINTER_UP); + ACTION_CASE(HOVER_ENTER); + ACTION_CASE(HOVER_EXIT); + ACTION_CASE(HOVER_MOVE); + ACTION_CASE(BUTTON_PRESS); + ACTION_CASE(BUTTON_RELEASE); default: NOTREACHED() << "Invalid Android MotionEvent action: " << android_action; }; - return MotionEventAndroid::ACTION_CANCEL; + return MotionEventAndroid::Action::CANCEL; +} + +int ToAndroidAction(MotionEventAndroid::Action action) { + switch (action) { + ACTION_REVERSE_CASE(DOWN); + ACTION_REVERSE_CASE(UP); + ACTION_REVERSE_CASE(MOVE); + ACTION_REVERSE_CASE(CANCEL); + ACTION_REVERSE_CASE(POINTER_DOWN); + ACTION_REVERSE_CASE(POINTER_UP); + ACTION_REVERSE_CASE(HOVER_ENTER); + ACTION_REVERSE_CASE(HOVER_EXIT); + ACTION_REVERSE_CASE(HOVER_MOVE); + ACTION_REVERSE_CASE(BUTTON_PRESS); + ACTION_REVERSE_CASE(BUTTON_RELEASE); + default: + NOTREACHED() << "Invalid MotionEvent action: " << action; + }; + return JNI_MotionEvent::ACTION_CANCEL; } MotionEventAndroid::ToolType FromAndroidToolType(int android_tool_type) { switch (android_tool_type) { - EVENT_CASE(TOOL_TYPE_UNKNOWN); - EVENT_CASE(TOOL_TYPE_FINGER); - EVENT_CASE(TOOL_TYPE_STYLUS); - EVENT_CASE(TOOL_TYPE_MOUSE); - EVENT_CASE(TOOL_TYPE_ERASER); + TOOL_TYPE_CASE(UNKNOWN); + TOOL_TYPE_CASE(FINGER); + TOOL_TYPE_CASE(STYLUS); + TOOL_TYPE_CASE(MOUSE); + TOOL_TYPE_CASE(ERASER); default: NOTREACHED() << "Invalid Android MotionEvent tool type: " << android_tool_type; }; - return MotionEventAndroid::TOOL_TYPE_UNKNOWN; + return MotionEventAndroid::ToolType::UNKNOWN; +} + +int ToAndroidToolType(MotionEventAndroid::ToolType tool_type) { + switch (tool_type) { + TOOL_TYPE_REVERSE_CASE(UNKNOWN); + TOOL_TYPE_REVERSE_CASE(FINGER); + TOOL_TYPE_REVERSE_CASE(STYLUS); + TOOL_TYPE_REVERSE_CASE(MOUSE); + TOOL_TYPE_REVERSE_CASE(ERASER); + default: + NOTREACHED() << "Invalid MotionEvent tool type: " << tool_type; + }; + return JNI_MotionEvent::TOOL_TYPE_UNKNOWN; } -#undef EVENT_CASE + +#undef ACTION_CASE +#undef ACTION_REVERSE_CASE +#undef TOOL_TYPE_CASE +#undef TOOL_TYPE_REVERSE_CASE int FromAndroidButtonState(int button_state) { int result = 0; @@ -131,11 +179,11 @@ float ToValidFloat(float x) { size_t ToValidHistorySize(jint history_size, ui::MotionEvent::Action action) { DCHECK_GE(history_size, 0); - // While the spec states that only ACTION_MOVE events should contain + // While the spec states that only Action::MOVE events should contain // historical entries, it's possible that an embedder could repurpose an - // ACTION_MOVE event into a different kind of event. In that case, the + // Action::MOVE event into a different kind of event. In that case, the // historical values are meaningless, and should not be exposed. - if (action != ui::MotionEvent::ACTION_MOVE) + if (action != ui::MotionEvent::Action::MOVE) return 0; return history_size; } @@ -179,7 +227,7 @@ MotionEventAndroid::CachedPointer::CachedPointer() orientation(0), tilt_x(0), tilt_y(0), - tool_type(TOOL_TYPE_UNKNOWN) {} + tool_type(ToolType::UNKNOWN) {} MotionEventAndroid::MotionEventAndroid(JNIEnv* env, jobject event, @@ -253,19 +301,12 @@ MotionEventAndroid::MotionEventAndroid(const MotionEventAndroid& e) } // static -int MotionEventAndroid::GetAndroidActionForTesting(int action) { - int android_action = JNI_MotionEvent::ACTION_CANCEL; - switch (action) { - case ui::MotionEvent::ACTION_DOWN: - android_action = JNI_MotionEvent::ACTION_DOWN; - break; - case ui::MotionEvent::ACTION_UP: - android_action = JNI_MotionEvent::ACTION_UP; - break; - default: - NOTIMPLEMENTED() << "Conversion not supported: " << action; - } - return android_action; +int MotionEventAndroid::GetAndroidAction(Action action) { + return ToAndroidAction(action); +} + +int MotionEventAndroid::GetAndroidToolType(ToolType tool_type) { + return ToAndroidToolType(tool_type); } std::unique_ptr<MotionEventAndroid> MotionEventAndroid::CreateFor( @@ -305,8 +346,8 @@ ScopedJavaLocalRef<jobject> MotionEventAndroid::GetJavaObject() const { } int MotionEventAndroid::GetActionIndex() const { - DCHECK(cached_action_ == MotionEvent::ACTION_POINTER_UP || - cached_action_ == MotionEvent::ACTION_POINTER_DOWN) + DCHECK(cached_action_ == MotionEvent::Action::POINTER_UP || + cached_action_ == MotionEvent::Action::POINTER_DOWN) << "Invalid action for GetActionIndex(): " << cached_action_; DCHECK_GE(cached_action_index_, 0); DCHECK_LT(cached_action_index_, static_cast<int>(cached_pointer_count_)); @@ -341,6 +382,22 @@ float MotionEventAndroid::GetY(size_t pointer_index) const { AttachCurrentThread(), event_, pointer_index)); } +float MotionEventAndroid::GetXPix(size_t pointer_index) const { + DCHECK_LT(pointer_index, cached_pointer_count_); + if (pointer_index < MAX_POINTERS_TO_CACHE) + return cached_pointers_[pointer_index].position.x() / pix_to_dip_; + return JNI_MotionEvent::Java_MotionEvent_getXF_I(AttachCurrentThread(), + event_, pointer_index); +} + +float MotionEventAndroid::GetYPix(size_t pointer_index) const { + DCHECK_LT(pointer_index, cached_pointer_count_); + if (pointer_index < MAX_POINTERS_TO_CACHE) + return cached_pointers_[pointer_index].position.y() / pix_to_dip_; + return JNI_MotionEvent::Java_MotionEvent_getYF_I(AttachCurrentThread(), + event_, pointer_index); +} + float MotionEventAndroid::GetRawX(size_t pointer_index) const { return GetX(pointer_index) + cached_raw_position_offset_.x(); } @@ -380,7 +437,7 @@ float MotionEventAndroid::GetPressure(size_t pointer_index) const { // accessed at most once per event instance). if (!event_.obj()) return 0.f; - if (cached_action_ == MotionEvent::ACTION_UP) + if (cached_action_ == MotionEvent::Action::UP) return 0.f; return JNI_MotionEvent::Java_MotionEvent_getPressureF_I( AttachCurrentThread(), event_, pointer_index); diff --git a/chromium/ui/events/android/motion_event_android.h b/chromium/ui/events/android/motion_event_android.h index e23d0e5c0af..53165164f52 100644 --- a/chromium/ui/events/android/motion_event_android.h +++ b/chromium/ui/events/android/motion_event_android.h @@ -27,7 +27,8 @@ class EVENTS_EXPORT MotionEventAndroid : public MotionEvent { public: // Returns the motion event action defined in Java layer for a given // MotionEvent::Action. - static int GetAndroidActionForTesting(int action); + static int GetAndroidAction(Action action); + static int GetAndroidToolType(ToolType tool_type); struct Pointer { Pointer(jint id, @@ -79,6 +80,9 @@ class EVENTS_EXPORT MotionEventAndroid : public MotionEvent { // Convenience method returning the pointer at index 0. gfx::PointF GetPoint() const { return gfx::PointF(GetX(0), GetY(0)); } + gfx::PointF GetPointPix() const { + return gfx::PointF(GetXPix(0), GetYPix(0)); + } // ui::MotionEvent methods. uint32_t GetUniqueEventId() const override; @@ -119,6 +123,9 @@ class EVENTS_EXPORT MotionEventAndroid : public MotionEvent { base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const; + float GetXPix(size_t pointer_index) const; + float GetYPix(size_t pointer_index) const; + private: struct CachedPointer; diff --git a/chromium/ui/events/android/motion_event_android_unittest.cc b/chromium/ui/events/android/motion_event_android_unittest.cc index 6ca7bb7e749..2a6b1671de9 100644 --- a/chromium/ui/events/android/motion_event_android_unittest.cc +++ b/chromium/ui/events/android/motion_event_android_unittest.cc @@ -72,7 +72,7 @@ TEST(MotionEventAndroidTest, Constructor) { action_index, kAndroidActionButton, kAndroidButtonPrimary, kAndroidAltKeyDown, raw_offset, -raw_offset, false, &p0, &p1); - EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::DOWN, event.GetAction()); EXPECT_EQ(event_time, event.GetEventTime()); EXPECT_EQ(p0.pos_x_pixels * kPixToDip, event.GetX(0)); EXPECT_EQ(p0.pos_y_pixels * kPixToDip, event.GetY(0)); @@ -96,8 +96,8 @@ TEST(MotionEventAndroidTest, Constructor) { float_error); EXPECT_EQ(p0.id, event.GetPointerId(0)); EXPECT_EQ(p1.id, event.GetPointerId(1)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(0)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(1)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(0)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(1)); EXPECT_EQ(MotionEvent::BUTTON_PRIMARY, event.GetButtonState()); EXPECT_EQ(ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON, event.GetFlags()); EXPECT_EQ(static_cast<size_t>(pointer_count), event.GetPointerCount()); @@ -136,7 +136,7 @@ TEST(MotionEventAndroidTest, Cancel) { 0, false, &p0, nullptr); std::unique_ptr<MotionEvent> cancel_event = event.Cancel(); - EXPECT_EQ(MotionEvent::ACTION_CANCEL, cancel_event->GetAction()); + EXPECT_EQ(MotionEvent::Action::CANCEL, cancel_event->GetAction()); EXPECT_EQ(event_time, cancel_event->GetEventTime()); EXPECT_EQ(p0.pos_x_pixels * kPixToDip, cancel_event->GetX(0)); EXPECT_EQ(p0.pos_y_pixels * kPixToDip, cancel_event->GetY(0)); @@ -193,7 +193,7 @@ TEST(MotionEventAndroidTest, ActionIndexForPointerDown) { pointer_count, history_size, action_index, 0, 0, 0, 0, 0, false, &p0, &p1); - EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::POINTER_DOWN, event.GetAction()); EXPECT_EQ(action_index, event.GetActionIndex()); } diff --git a/chromium/ui/events/base_event_utils.cc b/chromium/ui/events/base_event_utils.cc index 6eee6f1f671..20bbed9d18f 100644 --- a/chromium/ui/events/base_event_utils.cc +++ b/chromium/ui/events/base_event_utils.cc @@ -47,7 +47,7 @@ bool IsSystemKeyModifier(int flags) { (EF_ALTGR_DOWN & flags) == 0; } -base::LazyInstance<std::unique_ptr<base::TickClock>>::Leaky g_tick_clock = +base::LazyInstance<base::TickClock*>::Leaky g_tick_clock = LAZY_INSTANCE_INITIALIZER; base::TimeTicks EventTimeForNow() { @@ -55,8 +55,8 @@ base::TimeTicks EventTimeForNow() { : base::TimeTicks::Now(); } -void SetEventTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock) { - g_tick_clock.Get() = std::move(tick_clock); +void SetEventTickClockForTesting(base::TickClock* tick_clock) { + g_tick_clock.Get() = tick_clock; } double EventTimeStampToSeconds(base::TimeTicks time_stamp) { diff --git a/chromium/ui/events/base_event_utils.h b/chromium/ui/events/base_event_utils.h index 4e177803e27..d030fd15b8d 100644 --- a/chromium/ui/events/base_event_utils.h +++ b/chromium/ui/events/base_event_utils.h @@ -27,8 +27,10 @@ EVENTS_BASE_EXPORT bool IsSystemKeyModifier(int flags); // Create a timestamp based on the current time. EVENTS_BASE_EXPORT base::TimeTicks EventTimeForNow(); +// Overrides the clock used by EventTimeForNow for testing. +// This doesn't take the ownership of the clock. EVENTS_BASE_EXPORT void SetEventTickClockForTesting( - std::unique_ptr<base::TickClock> tick_clock); + base::TickClock* tick_clock); // Converts an event timestamp ticks to seconds (floating point representation). // WARNING: This should only be used when interfacing with platform code that diff --git a/chromium/ui/events/blink/blink_event_util.cc b/chromium/ui/events/blink/blink_event_util.cc index 6c253aa9c27..c8d058216b2 100644 --- a/chromium/ui/events/blink/blink_event_util.cc +++ b/chromium/ui/events/blink/blink_event_util.cc @@ -9,8 +9,8 @@ #include <algorithm> #include <bitset> #include <limits> +#include <memory> -#include "base/memory/ptr_util.h" #include "base/time/time.h" #include "build/build_config.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" @@ -44,24 +44,24 @@ const int kInvalidTouchIndex = -1; WebInputEvent::Type ToWebTouchEventType(MotionEvent::Action action) { switch (action) { - case MotionEvent::ACTION_DOWN: + case MotionEvent::Action::DOWN: return WebInputEvent::kTouchStart; - case MotionEvent::ACTION_MOVE: + case MotionEvent::Action::MOVE: return WebInputEvent::kTouchMove; - case MotionEvent::ACTION_UP: + case MotionEvent::Action::UP: return WebInputEvent::kTouchEnd; - case MotionEvent::ACTION_CANCEL: + case MotionEvent::Action::CANCEL: return WebInputEvent::kTouchCancel; - case MotionEvent::ACTION_POINTER_DOWN: + case MotionEvent::Action::POINTER_DOWN: return WebInputEvent::kTouchStart; - case MotionEvent::ACTION_POINTER_UP: + case MotionEvent::Action::POINTER_UP: return WebInputEvent::kTouchEnd; - case MotionEvent::ACTION_NONE: - case MotionEvent::ACTION_HOVER_ENTER: - case MotionEvent::ACTION_HOVER_EXIT: - case MotionEvent::ACTION_HOVER_MOVE: - case MotionEvent::ACTION_BUTTON_PRESS: - case MotionEvent::ACTION_BUTTON_RELEASE: + case MotionEvent::Action::NONE: + case MotionEvent::Action::HOVER_ENTER: + case MotionEvent::Action::HOVER_EXIT: + case MotionEvent::Action::HOVER_MOVE: + case MotionEvent::Action::BUTTON_PRESS: + case MotionEvent::Action::BUTTON_RELEASE: break; } NOTREACHED() << "Invalid MotionEvent::Action = " << action; @@ -69,50 +69,51 @@ WebInputEvent::Type ToWebTouchEventType(MotionEvent::Action action) { } // Note that the action index is meaningful only in the context of -// |ACTION_POINTER_UP| and |ACTION_POINTER_DOWN|; other actions map directly to -// WebTouchPoint::State. +// |Action::POINTER_UP| and |Action::POINTER_DOWN|; other actions map directly +// to WebTouchPoint::State. WebTouchPoint::State ToWebTouchPointState(const MotionEvent& event, size_t pointer_index) { switch (event.GetAction()) { - case MotionEvent::ACTION_DOWN: + case MotionEvent::Action::DOWN: return WebTouchPoint::kStatePressed; - case MotionEvent::ACTION_MOVE: + case MotionEvent::Action::MOVE: return WebTouchPoint::kStateMoved; - case MotionEvent::ACTION_UP: + case MotionEvent::Action::UP: return WebTouchPoint::kStateReleased; - case MotionEvent::ACTION_CANCEL: + case MotionEvent::Action::CANCEL: return WebTouchPoint::kStateCancelled; - case MotionEvent::ACTION_POINTER_DOWN: + case MotionEvent::Action::POINTER_DOWN: return static_cast<int>(pointer_index) == event.GetActionIndex() ? WebTouchPoint::kStatePressed : WebTouchPoint::kStateStationary; - case MotionEvent::ACTION_POINTER_UP: + case MotionEvent::Action::POINTER_UP: return static_cast<int>(pointer_index) == event.GetActionIndex() ? WebTouchPoint::kStateReleased : WebTouchPoint::kStateStationary; - case MotionEvent::ACTION_NONE: - case MotionEvent::ACTION_HOVER_ENTER: - case MotionEvent::ACTION_HOVER_EXIT: - case MotionEvent::ACTION_HOVER_MOVE: - case MotionEvent::ACTION_BUTTON_PRESS: - case MotionEvent::ACTION_BUTTON_RELEASE: + case MotionEvent::Action::NONE: + case MotionEvent::Action::HOVER_ENTER: + case MotionEvent::Action::HOVER_EXIT: + case MotionEvent::Action::HOVER_MOVE: + case MotionEvent::Action::BUTTON_PRESS: + case MotionEvent::Action::BUTTON_RELEASE: break; } NOTREACHED() << "Invalid MotionEvent::Action."; return WebTouchPoint::kStateUndefined; } -WebPointerProperties::PointerType ToWebPointerType(int tool_type) { - switch (static_cast<MotionEvent::ToolType>(tool_type)) { - case MotionEvent::TOOL_TYPE_UNKNOWN: +WebPointerProperties::PointerType ToWebPointerType( + MotionEvent::ToolType tool_type) { + switch (tool_type) { + case MotionEvent::ToolType::UNKNOWN: return WebPointerProperties::PointerType::kUnknown; - case MotionEvent::TOOL_TYPE_FINGER: + case MotionEvent::ToolType::FINGER: return WebPointerProperties::PointerType::kTouch; - case MotionEvent::TOOL_TYPE_STYLUS: + case MotionEvent::ToolType::STYLUS: return WebPointerProperties::PointerType::kPen; - case MotionEvent::TOOL_TYPE_MOUSE: + case MotionEvent::ToolType::MOUSE: return WebPointerProperties::PointerType::kMouse; - case MotionEvent::TOOL_TYPE_ERASER: + case MotionEvent::ToolType::ERASER: return WebPointerProperties::PointerType::kEraser; } NOTREACHED() << "Invalid MotionEvent::ToolType = " << tool_type; @@ -599,7 +600,8 @@ std::pair<WebGestureEvent, WebGestureEvent> CoalesceScrollAndPinch( blink::WebTouchEvent CreateWebTouchEventFromMotionEvent( const MotionEvent& event, - bool moved_beyond_slop_region) { + bool moved_beyond_slop_region, + bool hovering) { static_assert(static_cast<int>(MotionEvent::MAX_TOUCH_POINT_COUNT) == static_cast<int>(blink::WebTouchEvent::kTouchesLengthCap), "inconsistent maximum number of active touch points"); @@ -612,6 +614,7 @@ blink::WebTouchEvent CreateWebTouchEventFromMotionEvent( ? WebInputEvent::kEventNonBlocking : WebInputEvent::kBlocking; result.moved_beyond_slop_region = moved_beyond_slop_region; + result.hovering = hovering; // TODO(mustaq): MotionEvent flags seems unrelated, should use // metaState instead? @@ -938,23 +941,23 @@ std::unique_ptr<blink::WebInputEvent> TranslateAndScaleWebInputEvent( WebInputEvent::Type ToWebMouseEventType(MotionEvent::Action action) { switch (action) { - case MotionEvent::ACTION_DOWN: - case MotionEvent::ACTION_BUTTON_PRESS: + case MotionEvent::Action::DOWN: + case MotionEvent::Action::BUTTON_PRESS: return WebInputEvent::kMouseDown; - case MotionEvent::ACTION_MOVE: - case MotionEvent::ACTION_HOVER_MOVE: + case MotionEvent::Action::MOVE: + case MotionEvent::Action::HOVER_MOVE: return WebInputEvent::kMouseMove; - case MotionEvent::ACTION_HOVER_ENTER: + case MotionEvent::Action::HOVER_ENTER: return WebInputEvent::kMouseEnter; - case MotionEvent::ACTION_HOVER_EXIT: + case MotionEvent::Action::HOVER_EXIT: return WebInputEvent::kMouseLeave; - case MotionEvent::ACTION_UP: - case MotionEvent::ACTION_BUTTON_RELEASE: + case MotionEvent::Action::UP: + case MotionEvent::Action::BUTTON_RELEASE: return WebInputEvent::kMouseUp; - case MotionEvent::ACTION_NONE: - case MotionEvent::ACTION_CANCEL: - case MotionEvent::ACTION_POINTER_DOWN: - case MotionEvent::ACTION_POINTER_UP: + case MotionEvent::Action::NONE: + case MotionEvent::Action::CANCEL: + case MotionEvent::Action::POINTER_DOWN: + case MotionEvent::Action::POINTER_UP: break; } NOTREACHED() << "Invalid MotionEvent::Action = " << action; @@ -1049,11 +1052,11 @@ void SetWebPointerPropertiesFromMotionEventData( float tilt_x, float tilt_y, int android_buttons_changed, - int tool_type) { + MotionEvent::ToolType tool_type) { webPointerProperties.id = pointer_id; webPointerProperties.force = pressure; - if (tool_type == MotionEvent::TOOL_TYPE_STYLUS) { + if (tool_type == MotionEvent::ToolType::STYLUS) { // A stylus points to a direction specified by orientation and tilts to // the opposite direction. Coordinate system is left-handed. webPointerProperties.tilt_x = tilt_x; @@ -1173,11 +1176,20 @@ std::unique_ptr<WebGestureEvent> CreateWebGestureEventFromGestureEventAndroid( case GESTURE_EVENT_TYPE_PINCH_END: event_type = WebInputEvent::kGesturePinchEnd; break; + case GESTURE_EVENT_TYPE_SCROLL_START: + event_type = WebInputEvent::kGestureScrollBegin; + break; + case GESTURE_EVENT_TYPE_FLING_START: + event_type = WebInputEvent::kGestureFlingStart; + break; + case GESTURE_EVENT_TYPE_FLING_CANCEL: + event_type = WebInputEvent::kGestureFlingCancel; + break; default: NOTREACHED() << "Unknown gesture event type"; - return base::MakeUnique<WebGestureEvent>(); + return std::make_unique<WebGestureEvent>(); } - auto web_event = base::MakeUnique<WebGestureEvent>( + auto web_event = std::make_unique<WebGestureEvent>( event_type, WebInputEvent::kNoModifiers, event.time() / 1000.0); // NOTE: Source gesture events are synthetic ones that simulate // gesture from keyboard (zoom in/out) for now. Should populate Blink @@ -1187,8 +1199,24 @@ std::unique_ptr<WebGestureEvent> CreateWebGestureEventFromGestureEventAndroid( web_event->global_x = event.screen_location().x(); web_event->global_x = event.screen_location().y(); web_event->source_device = blink::kWebGestureDeviceTouchscreen; - if (event_type == WebInputEvent::kGesturePinchUpdate) - web_event->data.pinch_update.scale = event.delta(); + if (event.synthetic_scroll()) + web_event->source_device = blink::kWebGestureDeviceSyntheticAutoscroll; + if (event_type == WebInputEvent::kGesturePinchUpdate) { + web_event->data.pinch_update.scale = event.scale(); + } else if (event_type == WebInputEvent::kGestureScrollBegin) { + web_event->data.scroll_begin.delta_x_hint = event.delta_x(); + web_event->data.scroll_begin.delta_y_hint = event.delta_y(); + web_event->data.scroll_begin.target_viewport = event.target_viewport(); + } else if (event_type == WebInputEvent::kGestureFlingStart) { + web_event->data.fling_start.velocity_x = event.velocity_x(); + web_event->data.fling_start.velocity_y = event.velocity_y(); + web_event->data.fling_start.target_viewport = event.target_viewport(); + } else if (event_type == WebInputEvent::kGestureFlingCancel) { + web_event->data.fling_cancel.prevent_boosting = true; + if (event.synthetic_scroll()) + web_event->data.fling_cancel.target_viewport = true; + } + return web_event; } #endif diff --git a/chromium/ui/events/blink/blink_event_util.h b/chromium/ui/events/blink/blink_event_util.h index 53caa592cfc..24b85de5204 100644 --- a/chromium/ui/events/blink/blink_event_util.h +++ b/chromium/ui/events/blink/blink_event_util.h @@ -44,7 +44,8 @@ CoalesceScrollAndPinch(const blink::WebGestureEvent* second_last_event, blink::WebTouchEvent CreateWebTouchEventFromMotionEvent( const MotionEvent& event, - bool may_cause_scrolling); + bool may_cause_scrolling, + bool hovering); blink::WebGestureEvent CreateWebGestureEvent(const GestureEventDetails& details, base::TimeTicks timestamp, @@ -85,7 +86,7 @@ void SetWebPointerPropertiesFromMotionEventData( float tilt_x, float tilt_y, int android_buttons_changed, - int tool_type); + MotionEvent::ToolType tool_type); int WebEventModifiersToEventFlags(int modifiers); diff --git a/chromium/ui/events/blink/blink_event_util_unittest.cc b/chromium/ui/events/blink/blink_event_util_unittest.cc index d895b48caa8..b8cb09a9f16 100644 --- a/chromium/ui/events/blink/blink_event_util_unittest.cc +++ b/chromium/ui/events/blink/blink_event_util_unittest.cc @@ -30,9 +30,9 @@ TEST(BlinkEventUtilTest, NoScalingWith1DSF) { } TEST(BlinkEventUtilTest, NonPaginatedWebMouseWheelEvent) { - blink::WebMouseWheelEvent event(blink::WebInputEvent::kMouseWheel, - blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::kTimeStampForTesting); + blink::WebMouseWheelEvent event( + blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::GetStaticTimeStampForTests()); event.delta_x = 1.f; event.delta_y = 1.f; event.wheel_ticks_x = 1.f; @@ -50,9 +50,9 @@ TEST(BlinkEventUtilTest, NonPaginatedWebMouseWheelEvent) { } TEST(BlinkEventUtilTest, PaginatedWebMouseWheelEvent) { - blink::WebMouseWheelEvent event(blink::WebInputEvent::kMouseWheel, - blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::kTimeStampForTesting); + blink::WebMouseWheelEvent event( + blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::GetStaticTimeStampForTests()); event.delta_x = 1.f; event.delta_y = 1.f; event.wheel_ticks_x = 1.f; @@ -158,13 +158,13 @@ TEST(BlinkEventUtilTest, TouchEventCoalescing) { TEST(BlinkEventUtilTest, WebMouseWheelEventCoalescing) { blink::WebMouseWheelEvent coalesced_event( blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::kTimeStampForTesting); + blink::WebInputEvent::GetStaticTimeStampForTests()); coalesced_event.delta_x = 1; coalesced_event.delta_y = 1; blink::WebMouseWheelEvent event_to_be_coalesced( blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::kTimeStampForTesting); + blink::WebInputEvent::GetStaticTimeStampForTests()); event_to_be_coalesced.delta_x = 3; event_to_be_coalesced.delta_y = 4; @@ -201,14 +201,14 @@ TEST(BlinkEventUtilTest, WebGestureEventCoalescing) { blink::WebGestureEvent coalesced_event( blink::WebInputEvent::kGestureScrollUpdate, blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::kTimeStampForTesting); + blink::WebInputEvent::GetStaticTimeStampForTests()); coalesced_event.data.scroll_update.delta_x = 1; coalesced_event.data.scroll_update.delta_y = 1; blink::WebGestureEvent event_to_be_coalesced( blink::WebInputEvent::kGestureScrollUpdate, blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::kTimeStampForTesting); + blink::WebInputEvent::GetStaticTimeStampForTests()); event_to_be_coalesced.data.scroll_update.delta_x = 3; event_to_be_coalesced.data.scroll_update.delta_y = 4; diff --git a/chromium/ui/events/blink/input_handler_proxy.cc b/chromium/ui/events/blink/input_handler_proxy.cc index ba36cfb0d5d..6d77910839f 100644 --- a/chromium/ui/events/blink/input_handler_proxy.cc +++ b/chromium/ui/events/blink/input_handler_proxy.cc @@ -161,7 +161,7 @@ InputHandlerProxy::InputHandlerProxy( current_overscroll_params_(nullptr), has_ongoing_compositor_scroll_fling_pinch_(false), is_first_gesture_scroll_update_(false), - tick_clock_(std::make_unique<base::DefaultTickClock>()) { + tick_clock_(base::DefaultTickClock::GetInstance()) { DCHECK(client); input_handler_->BindToClient(this, touchpad_and_wheel_scroll_latching_enabled_); @@ -299,6 +299,7 @@ void InputHandlerProxy::DispatchSingleInputEvent( switch (event_with_callback->event().GetType()) { case blink::WebGestureEvent::kGestureScrollBegin: is_first_gesture_scroll_update_ = true; + FALLTHROUGH; case blink::WebGestureEvent::kGestureFlingStart: case blink::WebGestureEvent::kGesturePinchBegin: case blink::WebGestureEvent::kGestureScrollUpdate: @@ -736,6 +737,12 @@ InputHandlerProxy::HandleGestureScrollUpdate( DCHECK(expect_scroll_update_end_); #endif + gfx::Vector2dF scroll_delta(-gesture_event.data.scroll_update.delta_x, + -gesture_event.data.scroll_update.delta_y); + TRACE_EVENT_INSTANT2("input", "InputHandlerProxy::HandleGestureScrollUpdate", + TRACE_EVENT_SCOPE_THREAD, "dx", scroll_delta.x(), "dy", + scroll_delta.y()); + if (scroll_sequence_ignored_) return DROP_EVENT; @@ -744,8 +751,6 @@ InputHandlerProxy::HandleGestureScrollUpdate( cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event); gfx::Point scroll_point(gesture_event.x, gesture_event.y); - gfx::Vector2dF scroll_delta(-gesture_event.data.scroll_update.delta_x, - -gesture_event.data.scroll_update.delta_y); if (ShouldAnimate(gesture_event.data.scroll_update.delta_units != blink::WebGestureEvent::ScrollUnits::kPixels)) { @@ -760,7 +765,12 @@ InputHandlerProxy::HandleGestureScrollUpdate( return DID_HANDLE; case cc::InputHandler::SCROLL_IGNORED: return DROP_EVENT; - default: + case cc::InputHandler::SCROLL_ON_MAIN_THREAD: + case cc::InputHandler::SCROLL_UNKNOWN: + if (input_handler_->ScrollingShouldSwitchtoMainThread()) { + gesture_scroll_on_impl_thread_ = false; + client_->GenerateScrollBeginAndSendToMainThread(gesture_event); + } return DID_NOT_HANDLE; } } @@ -1325,9 +1335,8 @@ void InputHandlerProxy::HandleScrollElasticityOverscroll( scroll_result)); } -void InputHandlerProxy::SetTickClockForTesting( - std::unique_ptr<base::TickClock> tick_clock) { - tick_clock_ = std::move(tick_clock); +void InputHandlerProxy::SetTickClockForTesting(base::TickClock* tick_clock) { + tick_clock_ = tick_clock; } void InputHandlerProxy::UpdateCurrentFlingState( diff --git a/chromium/ui/events/blink/input_handler_proxy.h b/chromium/ui/events/blink/input_handler_proxy.h index bb67ec43501..feeea9d1c65 100644 --- a/chromium/ui/events/blink/input_handler_proxy.h +++ b/chromium/ui/events/blink/input_handler_proxy.h @@ -176,7 +176,10 @@ class InputHandlerProxy : public cc::InputHandlerClient, const blink::WebGestureEvent& gesture_event, const cc::InputHandlerScrollResult& scroll_result); - void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); + // Overrides the internal clock for testing. + // This doesn't take the ownership of the clock. |tick_clock| must outlive the + // InputHandlerProxy instance. + void SetTickClockForTesting(base::TickClock* tick_clock); // |is_touching_scrolling_layer| indicates if one of the points that has // been touched hits a currently scrolling layer. @@ -257,7 +260,7 @@ class InputHandlerProxy : public cc::InputHandlerClient, bool has_ongoing_compositor_scroll_fling_pinch_; bool is_first_gesture_scroll_update_; - std::unique_ptr<base::TickClock> tick_clock_; + base::TickClock* tick_clock_; std::unique_ptr<FlingBooster> fling_booster_; diff --git a/chromium/ui/events/blink/input_handler_proxy_client.h b/chromium/ui/events/blink/input_handler_proxy_client.h index 9f2fb2fa22f..3d992cd12fb 100644 --- a/chromium/ui/events/blink/input_handler_proxy_client.h +++ b/chromium/ui/events/blink/input_handler_proxy_client.h @@ -23,8 +23,7 @@ class InputHandlerProxyClient { // Dispatch a non blocking event to the main thread. This is used when a // gesture fling from a touchpad is processed and the target only has - // passive event listeners. If the target has blocking event listeners - // |TransferActiveWheelFlingAnimation| will be used instead. + // passive event listeners. virtual void DispatchNonBlockingEventToMainThread( WebScopedInputEvent event, const ui::LatencyInfo& latency_info) = 0; diff --git a/chromium/ui/events/blink/input_handler_proxy_unittest.cc b/chromium/ui/events/blink/input_handler_proxy_unittest.cc index beef5fc3d56..2f1830b4735 100644 --- a/chromium/ui/events/blink/input_handler_proxy_unittest.cc +++ b/chromium/ui/events/blink/input_handler_proxy_unittest.cc @@ -9,15 +9,11 @@ #include "base/bind.h" #include "base/containers/circular_deque.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted_memory.h" #include "base/message_loop/message_loop.h" -#include "base/run_loop.h" #include "base/test/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_tick_clock.h" #include "base/test/trace_event_analyzer.h" -#include "base/trace_event/trace_buffer.h" #include "cc/input/main_thread_scrolling_reason.h" #include "cc/trees/swap_promise_monitor.h" #include "testing/gmock/include/gmock/gmock.h" @@ -111,12 +107,8 @@ WebGestureEvent CreateFling(WebGestureDevice source_device, WebPoint point, WebPoint global_point, int modifiers) { - return CreateFling(base::TimeTicks(), - source_device, - velocity, - point, - global_point, - modifiers); + return CreateFling(base::TimeTicks(), source_device, velocity, point, + global_point, modifiers); } WebScopedInputEvent CreateGestureScrollFlingPinch( @@ -126,7 +118,7 @@ WebScopedInputEvent CreateGestureScrollFlingPinch( int x = 0, int y = 0) { WebGestureEvent gesture(type, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); gesture.source_device = source_device; if (type == WebInputEvent::kGestureScrollUpdate) { gesture.data.scroll_update.delta_y = delta_y_or_scale; @@ -142,15 +134,6 @@ WebScopedInputEvent CreateGestureScrollFlingPinch( return WebInputEventTraits::Clone(gesture); } -void OnTraceDataCollected(base::Closure quit_closure, - base::trace_event::TraceResultBuffer* buffer, - const scoped_refptr<base::RefCountedString>& json, - bool has_more_events) { - buffer->AddFragment(json->data()); - if (!has_more_events) - quit_closure.Run(); -} - class MockInputHandler : public cc::InputHandler { public: MockInputHandler() {} @@ -544,32 +527,6 @@ class InputHandlerProxyEventQueueTest : public testing::TestWithParam<bool> { std::make_unique<CompositorThreadEventQueue>(); } - void StartTracing() { - base::trace_event::TraceLog::GetInstance()->SetEnabled( - base::trace_event::TraceConfig("*"), - base::trace_event::TraceLog::RECORDING_MODE); - } - - void StopTracing() { - base::trace_event::TraceLog::GetInstance()->SetDisabled(); - } - - std::unique_ptr<trace_analyzer::TraceAnalyzer> CreateTraceAnalyzer() { - base::trace_event::TraceResultBuffer buffer; - base::trace_event::TraceResultBuffer::SimpleOutput trace_output; - buffer.SetOutputCallback(trace_output.GetCallback()); - base::RunLoop run_loop; - buffer.Start(); - base::trace_event::TraceLog::GetInstance()->Flush( - base::Bind(&OnTraceDataCollected, run_loop.QuitClosure(), - base::Unretained(&buffer))); - run_loop.Run(); - buffer.Finish(); - - return base::WrapUnique( - trace_analyzer::TraceAnalyzer::Create(trace_output.json_output)); - } - void HandleGestureEvent(WebInputEvent::Type type, float delta_y_or_scale = 0, int x = 0, @@ -606,9 +563,8 @@ class InputHandlerProxyEventQueueTest : public testing::TestWithParam<bool> { return input_handler_proxy_->compositor_event_queue_->queue_; } - void SetInputHandlerProxyTickClockForTesting( - std::unique_ptr<base::TickClock> tick_clock) { - input_handler_proxy_->SetTickClockForTesting(std::move(tick_clock)); + void SetInputHandlerProxyTickClockForTesting(base::TickClock* tick_clock) { + input_handler_proxy_->SetTickClockForTesting(tick_clock); } protected: @@ -632,7 +588,7 @@ TEST_P(InputHandlerProxyTest, MouseWheelNoListener) { WebMouseWheelEvent wheel(WebInputEvent::kMouseWheel, WebInputEvent::kControlKey, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); VERIFY_AND_RESET_MOCKS(); } @@ -645,7 +601,7 @@ TEST_P(InputHandlerProxyTest, MouseWheelPassiveListener) { WebMouseWheelEvent wheel(WebInputEvent::kMouseWheel, WebInputEvent::kControlKey, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); VERIFY_AND_RESET_MOCKS(); } @@ -658,7 +614,7 @@ TEST_P(InputHandlerProxyTest, MouseWheelBlockingListener) { WebMouseWheelEvent wheel(WebInputEvent::kMouseWheel, WebInputEvent::kControlKey, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); VERIFY_AND_RESET_MOCKS(); } @@ -672,7 +628,7 @@ TEST_P(InputHandlerProxyTest, MouseWheelBlockingAndPassiveListener) { WebMouseWheelEvent wheel(WebInputEvent::kMouseWheel, WebInputEvent::kControlKey, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel)); VERIFY_AND_RESET_MOCKS(); } @@ -1759,7 +1715,7 @@ TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) { // hit-testing for the third touch point. WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.touches_length = 3; touch.touch_start_or_first_touch_move = true; @@ -1801,7 +1757,7 @@ TEST_P(InputHandlerProxyTest, HitTestTouchEventNullTouchAction) { // hit-testing for the third touch point. WebTouchEvent touch(WebInputEvent::kTouchMove, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.touches_length = 3; touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0); @@ -1846,7 +1802,7 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestNegative) { .WillOnce(testing::Return()); WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.unique_touch_event_id = 1; touch.touches_length = 3; @@ -1892,7 +1848,7 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) { // hit-testing for the third touch point. WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.unique_touch_event_id = 1; touch.touches_length = 3; @@ -1934,7 +1890,7 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPassivePositive) { .WillOnce(testing::Return()); WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.unique_touch_event_id = 1; touch.touches_length = 3; @@ -1975,7 +1931,7 @@ TEST_P(InputHandlerProxyTest, TouchStartPassiveAndTouchEndBlocking) { .WillOnce(testing::Return()); WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.unique_touch_event_id = 1; touch.touches_length = 1; touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0); @@ -2010,7 +1966,7 @@ TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) { .WillOnce(testing::Return()); WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.touches_length = 1; touch.touch_start_or_first_touch_move = true; touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStatePressed, 0, 0); @@ -2050,7 +2006,7 @@ TEST_P(InputHandlerProxyTest, GestureFlingCancelledByKeyboardEvent) { // Keyboard events received during a scroll should have no effect. WebKeyboardEvent key_event(WebInputEvent::kKeyDown, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE, input_handler_->HandleInputEvent(key_event)); EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); @@ -2111,7 +2067,7 @@ TEST_P(InputHandlerProxyTest, GestureFlingCancelledByWheelEvent) { WebMouseWheelEvent wheel_event(WebInputEvent::kMouseWheel, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); input_handler_->HandleInputEvent(wheel_event); EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); VERIFY_AND_RESET_MOCKS(); @@ -2136,7 +2092,6 @@ TEST_P(InputHandlerProxyTest, GestureFlingCancelledByWheelEvent) { GetEventListenerProperties(cc::EventListenerClass::kMouseWheel)) .WillOnce(testing::Return(cc::EventListenerProperties::kBlocking)); - input_handler_->HandleInputEvent(wheel_event); EXPECT_FALSE(input_handler_->gesture_scroll_on_impl_thread_for_testing()); VERIFY_AND_RESET_MOCKS(); @@ -2638,7 +2593,7 @@ TEST_P(InputHandlerProxyTest, DidReceiveInputEvent_ForFlingTouchscreen) { EXPECT_CALL(mock_input_handler_, FlingScrollBegin()) .WillOnce(testing::Return(kImplThreadScrollState)); EXPECT_EQ(InputHandlerProxy::DID_HANDLE, - input_handler_->HandleInputEvent(gesture_)); + input_handler_->HandleInputEvent(gesture_)); VERIFY_AND_RESET_MOCKS(); EXPECT_SET_NEEDS_ANIMATE_INPUT(1); @@ -2751,7 +2706,7 @@ TEST_P(InputHandlerProxyTest, GestureScrollingThreadStatusHistogram) { WebTouchEvent touch_start(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch_start.touches_length = 1; touch_start.touch_start_or_first_touch_move = true; touch_start.touches[0] = @@ -2859,7 +2814,7 @@ TEST_P(InputHandlerProxyTest, WheelScrollingThreadStatusHistogram) { WebMouseWheelEvent wheel(WebInputEvent::kMouseWheel, WebInputEvent::kControlKey, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); WebGestureEvent gesture_scroll_begin; gesture_scroll_begin.SetType(WebInputEvent::kGestureScrollBegin); @@ -3068,11 +3023,9 @@ TEST_P(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScrollPinchScroll) { TEST_P(InputHandlerProxyEventQueueTest, VSyncAlignedQueueingTime) { base::HistogramTester histogram_tester; - std::unique_ptr<base::SimpleTestTickClock> tick_clock = - std::make_unique<base::SimpleTestTickClock>(); - base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get(); - tick_clock_ptr->SetNowTicks(base::TimeTicks::Now()); - SetInputHandlerProxyTickClockForTesting(std::move(tick_clock)); + base::SimpleTestTickClock tick_clock; + tick_clock.SetNowTicks(base::TimeTicks::Now()); + SetInputHandlerProxyTickClockForTesting(&tick_clock); // Handle scroll on compositor. cc::InputHandlerScrollResult scroll_result_did_scroll_; @@ -3088,17 +3041,17 @@ TEST_P(InputHandlerProxyEventQueueTest, VSyncAlignedQueueingTime) { EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)); HandleGestureEvent(WebInputEvent::kGestureScrollBegin); - tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(10)); + tick_clock.Advance(base::TimeDelta::FromMicroseconds(10)); HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20); - tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(40)); + tick_clock.Advance(base::TimeDelta::FromMicroseconds(40)); HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -40); - tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(20)); + tick_clock.Advance(base::TimeDelta::FromMicroseconds(20)); HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -10); - tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(10)); + tick_clock.Advance(base::TimeDelta::FromMicroseconds(10)); HandleGestureEvent(WebInputEvent::kGestureScrollEnd); // Dispatch all queued events. - tick_clock_ptr->Advance(base::TimeDelta::FromMicroseconds(70)); + tick_clock.Advance(base::TimeDelta::FromMicroseconds(70)); input_handler_proxy_->DeliverInputForBeginFrame(); EXPECT_EQ(0ul, event_queue().size()); EXPECT_EQ(5ul, event_disposition_recorder_.size()); @@ -3183,7 +3136,7 @@ TEST_P(InputHandlerProxyEventQueueTest, OriginalEventsTracing) { EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true)) .Times(::testing::AtLeast(1)); - StartTracing(); + trace_analyzer::Start("*"); // Simulate scroll. HandleGestureEvent(WebInputEvent::kGestureScrollBegin); HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20); @@ -3201,11 +3154,9 @@ TEST_P(InputHandlerProxyEventQueueTest, OriginalEventsTracing) { // Dispatch all events. input_handler_proxy_->DeliverInputForBeginFrame(); - StopTracing(); // Retrieve tracing data. - std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer = - CreateTraceAnalyzer(); + auto analyzer = trace_analyzer::Stop(); trace_analyzer::TraceEventVector begin_events; trace_analyzer::Query begin_query = trace_analyzer::Query::EventPhaseIs( TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN); diff --git a/chromium/ui/events/blink/web_input_event_traits.cc b/chromium/ui/events/blink/web_input_event_traits.cc index c4a1e920677..6fc2c8718dc 100644 --- a/chromium/ui/events/blink/web_input_event_traits.cc +++ b/chromium/ui/events/blink/web_input_event_traits.cc @@ -80,9 +80,10 @@ void ApppendTouchPointDetails(const WebTouchPoint& point, std::string* result) { void ApppendEventDetails(const WebTouchEvent& event, std::string* result) { StringAppendF(result, "{\n Touches: %u, DispatchType: %d, CausesScrolling: %d," - " uniqueTouchEventId: %u\n[\n", + " Hovering: %d, uniqueTouchEventId: %u\n[\n", event.touches_length, event.dispatch_type, - event.moved_beyond_slop_region, event.unique_touch_event_id); + event.moved_beyond_slop_region, event.hovering, + event.unique_touch_event_id); for (unsigned i = 0; i < event.touches_length; ++i) ApppendTouchPointDetails(event.touches[i], result); result->append(" ]\n}"); diff --git a/chromium/ui/events/blink/web_input_event_traits_unittest.cc b/chromium/ui/events/blink/web_input_event_traits_unittest.cc index d00bff5beb7..a904dc421d6 100644 --- a/chromium/ui/events/blink/web_input_event_traits_unittest.cc +++ b/chromium/ui/events/blink/web_input_event_traits_unittest.cc @@ -26,27 +26,27 @@ using WebInputEventTraitsTest = testing::Test; // Very basic smoke test to ensure stringification doesn't explode. TEST_F(WebInputEventTraitsTest, ToString) { WebKeyboardEvent key(WebInputEvent::kRawKeyDown, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_FALSE(WebInputEventTraits::ToString(key).empty()); WebMouseEvent mouse(WebInputEvent::kMouseMove, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_FALSE(WebInputEventTraits::ToString(mouse).empty()); WebMouseWheelEvent mouse_wheel(WebInputEvent::kMouseWheel, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); EXPECT_FALSE(WebInputEventTraits::ToString(mouse_wheel).empty()); WebGestureEvent gesture(WebInputEvent::kGesturePinchBegin, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); gesture.x = 1; gesture.y = 1; EXPECT_FALSE(WebInputEventTraits::ToString(gesture).empty()); WebTouchEvent touch(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers, - WebInputEvent::kTimeStampForTesting); + WebInputEvent::GetStaticTimeStampForTests()); touch.touches_length = 1; EXPECT_FALSE(WebInputEventTraits::ToString(touch).empty()); } diff --git a/chromium/ui/events/chromecast/scroller.cc b/chromium/ui/events/chromecast/scroller.cc new file mode 100644 index 00000000000..9c989a95f10 --- /dev/null +++ b/chromium/ui/events/chromecast/scroller.cc @@ -0,0 +1,477 @@ +// Copyright 2018 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/events/chromecast/scroller.h" + +#include <cmath> + +#include "base/lazy_instance.h" +#include "base/macros.h" + +namespace ui { +namespace { + +// Default scroll duration from android.widget.Scroller. +const int kDefaultDurationMs = 250; + +// Default friction constant in android.view.ViewConfiguration. +const float kDefaultFriction = 0.015f; + +// == std::log(0.78f) / std::log(0.9f) +const float kDecelerationRate = 2.3582018f; + +// Tension lines cross at (kInflexion, 1). +const float kInflexion = 0.35f; + +const float kEpsilon = 1e-5f; + +// Fling scroll is stopped when the scroll position is |kThresholdForFlingEnd| +// pixels or closer from the end. +const float kThresholdForFlingEnd = 0.1; + +bool ApproxEquals(float a, float b) { + return std::abs(a - b) < kEpsilon; +} + +struct ViscosityConstants { + ViscosityConstants() + : viscous_fluid_scale_(8.f), viscous_fluid_normalize_(1.f) { + viscous_fluid_normalize_ = 1.0f / ApplyViscosity(1.0f); + } + + float ApplyViscosity(float x) { + x *= viscous_fluid_scale_; + if (x < 1.0f) { + x -= (1.0f - std::exp(-x)); + } else { + float start = 0.36787944117f; // 1/e == exp(-1) + x = 1.0f - std::exp(1.0f - x); + x = start + x * (1.0f - start); + } + x *= viscous_fluid_normalize_; + return x; + } + + private: + // This controls the intensity of the viscous fluid effect. + float viscous_fluid_scale_; + float viscous_fluid_normalize_; + + DISALLOW_COPY_AND_ASSIGN(ViscosityConstants); +}; + +struct SplineConstants { + SplineConstants() { + const float kStartTension = 0.5f; + const float kEndTension = 1.0f; + const float kP1 = kStartTension * kInflexion; + const float kP2 = 1.0f - kEndTension * (1.0f - kInflexion); + + float x_min = 0.0f; + float y_min = 0.0f; + for (int i = 0; i < NUM_SAMPLES; i++) { + const float alpha = static_cast<float>(i) / NUM_SAMPLES; + + float x_max = 1.0f; + float x, tx, coef; + while (true) { + x = x_min + (x_max - x_min) / 2.0f; + coef = 3.0f * x * (1.0f - x); + tx = coef * ((1.0f - x) * kP1 + x * kP2) + x * x * x; + if (ApproxEquals(tx, alpha)) + break; + if (tx > alpha) + x_max = x; + else + x_min = x; + } + spline_position_[i] = coef * ((1.0f - x) * kStartTension + x) + x * x * x; + + float y_max = 1.0f; + float y, dy; + while (true) { + y = y_min + (y_max - y_min) / 2.0f; + coef = 3.0f * y * (1.0f - y); + dy = coef * ((1.0f - y) * kStartTension + y) + y * y * y; + if (ApproxEquals(dy, alpha)) + break; + if (dy > alpha) + y_max = y; + else + y_min = y; + } + spline_time_[i] = coef * ((1.0f - y) * kP1 + y * kP2) + y * y * y; + } + spline_position_[NUM_SAMPLES] = spline_time_[NUM_SAMPLES] = 1.0f; + } + + void CalculateCoefficients(float t, + float* distance_coef, + float* velocity_coef) { + *distance_coef = 1.f; + *velocity_coef = 0.f; + const int index = static_cast<int>(NUM_SAMPLES * t); + if (index < NUM_SAMPLES) { + const float t_inf = static_cast<float>(index) / NUM_SAMPLES; + const float t_sup = static_cast<float>(index + 1) / NUM_SAMPLES; + const float d_inf = spline_position_[index]; + const float d_sup = spline_position_[index + 1]; + *velocity_coef = (d_sup - d_inf) / (t_sup - t_inf); + *distance_coef = d_inf + (t - t_inf) * *velocity_coef; + } + } + + private: + enum { NUM_SAMPLES = 100 }; + + float spline_position_[NUM_SAMPLES + 1]; + float spline_time_[NUM_SAMPLES + 1]; + + DISALLOW_COPY_AND_ASSIGN(SplineConstants); +}; + +float ComputeDeceleration(float friction) { + const float kGravityEarth = 9.80665f; + return kGravityEarth // g (m/s^2) + * 39.37f // inch/meter + * 160.f // pixels/inch + * friction; +} + +template <typename T> +int Signum(T t) { + return (T(0) < t) - (t < T(0)); +} + +template <typename T> +T Clamped(T t, T a, T b) { + return t < a ? a : (t > b ? b : t); +} + +// Leaky to allow access from the impl thread. +base::LazyInstance<ViscosityConstants>::Leaky g_viscosity_constants = + LAZY_INSTANCE_INITIALIZER; + +base::LazyInstance<SplineConstants>::Leaky g_spline_constants = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +Scroller::Config::Config() + : fling_friction(kDefaultFriction), flywheel_enabled(false) { +} + +Scroller::Scroller(const Config& config) + : mode_(UNDEFINED), + start_x_(0), + start_y_(0), + final_x_(0), + final_y_(0), + min_x_(0), + max_x_(0), + min_y_(0), + max_y_(0), + curr_x_(0), + curr_y_(0), + duration_seconds_reciprocal_(1), + delta_x_(0), + delta_x_norm_(1), + delta_y_(0), + delta_y_norm_(1), + finished_(true), + flywheel_enabled_(config.flywheel_enabled), + velocity_(0), + curr_velocity_(0), + distance_(0), + fling_friction_(config.fling_friction), + deceleration_(ComputeDeceleration(fling_friction_)), + tuning_coeff_(ComputeDeceleration(0.84f)) { +} + +Scroller::~Scroller() { +} + +bool Scroller::ComputeScrollOffset(base::TimeTicks time, + gfx::Vector2dF* offset, + gfx::Vector2dF* velocity) { + DCHECK(offset); + DCHECK(velocity); + if (!ComputeScrollOffsetInternal(time)) { + *offset = gfx::Vector2dF(GetFinalX(), GetFinalY()); + *velocity = gfx::Vector2dF(); + return false; + } + + *offset = gfx::Vector2dF(GetCurrX(), GetCurrY()); + *velocity = gfx::Vector2dF(GetCurrVelocityX(), GetCurrVelocityY()); + return true; +} + +void Scroller::StartScroll(float start_x, + float start_y, + float dx, + float dy, + base::TimeTicks start_time) { + StartScroll(start_x, + start_y, + dx, + dy, + start_time, + base::TimeDelta::FromMilliseconds(kDefaultDurationMs)); +} + +void Scroller::StartScroll(float start_x, + float start_y, + float dx, + float dy, + base::TimeTicks start_time, + base::TimeDelta duration) { + DCHECK_GT(duration, base::TimeDelta()); + mode_ = SCROLL_MODE; + finished_ = false; + duration_ = duration; + duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF(); + start_time_ = start_time; + curr_x_ = start_x_ = start_x; + curr_y_ = start_y_ = start_y; + final_x_ = start_x + dx; + final_y_ = start_y + dy; + RecomputeDeltas(); + curr_time_ = start_time_; +} + +void Scroller::Fling(float start_x, + float start_y, + float velocity_x, + float velocity_y, + float min_x, + float max_x, + float min_y, + float max_y, + base::TimeTicks start_time) { + DCHECK(velocity_x || velocity_y); + + // Continue a scroll or fling in progress. + if (flywheel_enabled_ && !finished_) { + float old_velocity_x = GetCurrVelocityX(); + float old_velocity_y = GetCurrVelocityY(); + if (Signum(velocity_x) == Signum(old_velocity_x) && + Signum(velocity_y) == Signum(old_velocity_y)) { + velocity_x += old_velocity_x; + velocity_y += old_velocity_y; + } + } + + mode_ = FLING_MODE; + finished_ = false; + + float velocity = std::sqrt(velocity_x * velocity_x + velocity_y * velocity_y); + + velocity_ = velocity; + duration_ = GetSplineFlingDuration(velocity); + DCHECK_GT(duration_, base::TimeDelta()); + duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF(); + start_time_ = start_time; + curr_time_ = start_time_; + curr_x_ = start_x_ = start_x; + curr_y_ = start_y_ = start_y; + + float coeff_x = velocity == 0 ? 1.0f : velocity_x / velocity; + float coeff_y = velocity == 0 ? 1.0f : velocity_y / velocity; + + double total_distance = GetSplineFlingDistance(velocity); + distance_ = total_distance * Signum(velocity); + + min_x_ = min_x; + max_x_ = max_x; + min_y_ = min_y; + max_y_ = max_y; + + final_x_ = start_x + total_distance * coeff_x; + final_x_ = Clamped(final_x_, min_x_, max_x_); + + final_y_ = start_y + total_distance * coeff_y; + final_y_ = Clamped(final_y_, min_y_, max_y_); + + RecomputeDeltas(); +} + +void Scroller::ExtendDuration(base::TimeDelta extend) { + base::TimeDelta passed = GetTimePassed(); + duration_ = passed + extend; + duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF(); + finished_ = false; +} + +void Scroller::SetFinalX(float new_x) { + final_x_ = new_x; + finished_ = false; + RecomputeDeltas(); +} + +void Scroller::SetFinalY(float new_y) { + final_y_ = new_y; + finished_ = false; + RecomputeDeltas(); +} + +void Scroller::AbortAnimation() { + curr_x_ = final_x_; + curr_y_ = final_y_; + curr_velocity_ = 0; + curr_time_ = start_time_ + duration_; + finished_ = true; +} + +void Scroller::ForceFinished(bool finished) { + finished_ = finished; +} + +bool Scroller::IsFinished() const { + return finished_; +} + +base::TimeDelta Scroller::GetTimePassed() const { + return curr_time_ - start_time_; +} + +base::TimeDelta Scroller::GetDuration() const { + return duration_; +} + +float Scroller::GetCurrX() const { + return curr_x_; +} + +float Scroller::GetCurrY() const { + return curr_y_; +} + +float Scroller::GetCurrVelocity() const { + if (finished_) + return 0; + if (mode_ == FLING_MODE) + return curr_velocity_; + return velocity_ - deceleration_ * GetTimePassed().InSecondsF() * 0.5f; +} + +float Scroller::GetCurrVelocityX() const { + return delta_x_norm_ * GetCurrVelocity(); +} + +float Scroller::GetCurrVelocityY() const { + return delta_y_norm_ * GetCurrVelocity(); +} + +float Scroller::GetStartX() const { + return start_x_; +} + +float Scroller::GetStartY() const { + return start_y_; +} + +float Scroller::GetFinalX() const { + return final_x_; +} + +float Scroller::GetFinalY() const { + return final_y_; +} + +bool Scroller::IsScrollingInDirection(float xvel, float yvel) const { + return !finished_ && Signum(xvel) == Signum(delta_x_) && + Signum(yvel) == Signum(delta_y_); +} + +bool Scroller::ComputeScrollOffsetInternal(base::TimeTicks time) { + if (finished_) + return false; + + if (time <= start_time_) + return true; + + if (time == curr_time_) + return true; + + base::TimeDelta time_passed = time - start_time_; + if (time_passed >= duration_) { + AbortAnimation(); + return false; + } + + curr_time_ = time; + + const float u = time_passed.InSecondsF() * duration_seconds_reciprocal_; + switch (mode_) { + case UNDEFINED: + NOTREACHED() << "|StartScroll()| or |Fling()| must be called prior to " + "scroll offset computation."; + return false; + + case SCROLL_MODE: { + float x = g_viscosity_constants.Get().ApplyViscosity(u); + + curr_x_ = start_x_ + x * delta_x_; + curr_y_ = start_y_ + x * delta_y_; + } break; + + case FLING_MODE: { + float distance_coef = 1.f; + float velocity_coef = 0.f; + g_spline_constants.Get().CalculateCoefficients( + u, &distance_coef, &velocity_coef); + + curr_velocity_ = velocity_coef * distance_ * duration_seconds_reciprocal_; + + curr_x_ = start_x_ + distance_coef * delta_x_; + curr_x_ = Clamped(curr_x_, min_x_, max_x_); + + curr_y_ = start_y_ + distance_coef * delta_y_; + curr_y_ = Clamped(curr_y_, min_y_, max_y_); + + float diff_x = std::abs(curr_x_ - final_x_); + float diff_y = std::abs(curr_y_ - final_y_); + if (diff_x < kThresholdForFlingEnd && diff_y < kThresholdForFlingEnd) + AbortAnimation(); + } break; + } + + return !finished_; +} + +void Scroller::RecomputeDeltas() { + delta_x_ = final_x_ - start_x_; + delta_y_ = final_y_ - start_y_; + + const float hyp = std::sqrt(delta_x_ * delta_x_ + delta_y_ * delta_y_); + if (hyp > kEpsilon) { + delta_x_norm_ = delta_x_ / hyp; + delta_y_norm_ = delta_y_ / hyp; + } else { + delta_x_norm_ = delta_y_norm_ = 1; + } +} + +double Scroller::GetSplineDeceleration(float velocity) const { + return std::log(kInflexion * std::abs(velocity) / + (fling_friction_ * tuning_coeff_)); +} + +base::TimeDelta Scroller::GetSplineFlingDuration(float velocity) const { + const double l = GetSplineDeceleration(velocity); + const double decel_minus_one = kDecelerationRate - 1.0; + const double time_seconds = std::exp(l / decel_minus_one); + return base::TimeDelta::FromMicroseconds(time_seconds * + base::Time::kMicrosecondsPerSecond); +} + +double Scroller::GetSplineFlingDistance(float velocity) const { + const double l = GetSplineDeceleration(velocity); + const double decel_minus_one = kDecelerationRate - 1.0; + return fling_friction_ * tuning_coeff_ * + std::exp(kDecelerationRate / decel_minus_one * l); +} + +} // namespace ui diff --git a/chromium/ui/events/chromecast/scroller.h b/chromium/ui/events/chromecast/scroller.h new file mode 100644 index 00000000000..f4ef836775e --- /dev/null +++ b/chromium/ui/events/chromecast/scroller.h @@ -0,0 +1,151 @@ +// Copyright 2018 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_EVENTS_CHROMECAST_SCROLLER_H_ +#define UI_EVENTS_CHROMECAST_SCROLLER_H_ + +#include "base/time/time.h" +#include "ui/events/events_base_export.h" +#include "ui/events/gesture_curve.h" +#include "ui/gfx/geometry/vector2d_f.h" + +namespace ui { + +// Native port of android.widget.Scroller. +// * Change-Id: I4365946f890a76fcfa78ca9d69f2a8e0848095a9 +// * Please update the Change-Id as upstream Android changes are pulled. +class EVENTS_BASE_EXPORT Scroller : public GestureCurve { + public: + struct Config { + Config(); + + // Controls fling deceleration. Defaults to 0.015f. + float fling_friction; + + // Controls fling accumulation. Defaults to disabled. + bool flywheel_enabled; + }; + + explicit Scroller(const Config& config); + ~Scroller() override; + + // GestureCurve implementation. + bool ComputeScrollOffset(base::TimeTicks time, + gfx::Vector2dF* offset, + gfx::Vector2dF* velocity) override; + + // Start scrolling by providing a starting point and the distance to travel. + // The default value of 250 milliseconds will be used for the duration. + void StartScroll(float start_x, + float start_y, + float dx, + float dy, + base::TimeTicks start_time); + + // Start scrolling by providing a starting point, the distance to travel, + // and the duration of the scroll. + void StartScroll(float start_x, + float start_y, + float dx, + float dy, + base::TimeTicks start_time, + base::TimeDelta duration); + + // Start scrolling based on a fling gesture. The distance travelled will + // depend on the initial velocity of the fling. + void Fling(float start_x, + float start_y, + float velocity_x, + float velocity_y, + float min_x, + float max_x, + float min_y, + float max_y, + base::TimeTicks start_time); + + // Extend the scroll animation by |extend|. This allows a running animation + // to scroll further and longer when used with |SetFinalX()| or |SetFinalY()|. + void ExtendDuration(base::TimeDelta extend); + void SetFinalX(float new_x); + void SetFinalY(float new_y); + + // Stops the animation. Contrary to |ForceFinished()|, aborting the animation + // causes the scroller to move to the final x and y position. + void AbortAnimation(); + + // Terminate the scroll without affecting the current x and y positions. + void ForceFinished(bool finished); + + // Returns whether the scroller has finished scrolling. + bool IsFinished() const; + + // Returns the time elapsed since the beginning of the scrolling. + base::TimeDelta GetTimePassed() const; + + // Returns how long the scroll event will take. + base::TimeDelta GetDuration() const; + + float GetStartX() const; + float GetStartY() const; + float GetCurrX() const; + float GetCurrY() const; + float GetCurrVelocity() const; + float GetCurrVelocityX() const; + float GetCurrVelocityY() const; + float GetFinalX() const; + float GetFinalY() const; + + bool IsScrollingInDirection(float xvel, float yvel) const; + + private: + enum Mode { + UNDEFINED, + SCROLL_MODE, + FLING_MODE, + }; + + bool ComputeScrollOffsetInternal(base::TimeTicks time); + void RecomputeDeltas(); + + double GetSplineDeceleration(float velocity) const; + base::TimeDelta GetSplineFlingDuration(float velocity) const; + double GetSplineFlingDistance(float velocity) const; + + Mode mode_; + + float start_x_; + float start_y_; + float final_x_; + float final_y_; + + float min_x_; + float max_x_; + float min_y_; + float max_y_; + + float curr_x_; + float curr_y_; + base::TimeTicks start_time_; + base::TimeTicks curr_time_; + base::TimeDelta duration_; + double duration_seconds_reciprocal_; + float delta_x_; + float delta_x_norm_; + float delta_y_; + float delta_y_norm_; + bool finished_; + bool flywheel_enabled_; + + float velocity_; + float curr_velocity_; + float distance_; + + float fling_friction_; + float deceleration_; + float tuning_coeff_; +}; + +} // namespace ui + +#endif // UI_EVENTS_CHROMECAST_SCROLLER_H_ diff --git a/chromium/ui/events/chromecast/scroller_unittest.cc b/chromium/ui/events/chromecast/scroller_unittest.cc new file mode 100644 index 00000000000..1303f7f80c9 --- /dev/null +++ b/chromium/ui/events/chromecast/scroller_unittest.cc @@ -0,0 +1,178 @@ +// 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 <limits.h> + +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/chromecast/scroller.h" + +namespace ui { +namespace { + +const float kDefaultStartX = 7.f; +const float kDefaultStartY = 25.f; +const float kDefaultDeltaX = -20.f; +const float kDefaultDeltaY = 73.f; +const float kDefaultVelocityX = -350.f; +const float kDefaultVelocityY = 220.f; +const float kEpsilon = 1e-3f; + +Scroller::Config DefaultConfig() { + return Scroller::Config(); +} + +} // namespace + +class ScrollerTest : public testing::Test {}; + +TEST_F(ScrollerTest, Scroll) { + Scroller scroller(DefaultConfig()); + base::TimeTicks start_time = base::TimeTicks::Now(); + + // Start a scroll and verify initialized values. + scroller.StartScroll(kDefaultStartX, + kDefaultStartY, + kDefaultDeltaX, + kDefaultDeltaY, + start_time); + + EXPECT_EQ(kDefaultStartX, scroller.GetStartX()); + EXPECT_EQ(kDefaultStartY, scroller.GetStartY()); + EXPECT_EQ(kDefaultStartX, scroller.GetCurrX()); + EXPECT_EQ(kDefaultStartY, scroller.GetCurrY()); + EXPECT_EQ(kDefaultStartX + kDefaultDeltaX, scroller.GetFinalX()); + EXPECT_EQ(kDefaultStartY + kDefaultDeltaY, scroller.GetFinalY()); + EXPECT_FALSE(scroller.IsFinished()); + EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed()); + + // Advance halfway through the scroll. + const base::TimeDelta scroll_duration = scroller.GetDuration(); + gfx::Vector2dF offset, velocity; + EXPECT_TRUE(scroller.ComputeScrollOffset( + start_time + scroll_duration / 2, &offset, &velocity)); + + // Ensure we've moved in the direction of the delta, but have yet to reach + // the target. + EXPECT_GT(kDefaultStartX, offset.x()); + EXPECT_LT(kDefaultStartY, offset.y()); + EXPECT_LT(scroller.GetFinalX(), offset.x()); + EXPECT_GT(scroller.GetFinalY(), offset.y()); + EXPECT_FALSE(scroller.IsFinished()); + + // Ensure our velocity is non-zero and in the same direction as the delta. + EXPECT_GT(0.f, velocity.x() * kDefaultDeltaX); + EXPECT_GT(0.f, velocity.y() * kDefaultDeltaY); + EXPECT_TRUE(scroller.IsScrollingInDirection(kDefaultDeltaX, kDefaultDeltaY)); + + // Repeated offset computations at the same timestamp should yield identical + // results. + float curr_x = offset.x(); + float curr_y = offset.y(); + float curr_velocity_x = velocity.x(); + float curr_velocity_y = velocity.y(); + EXPECT_TRUE(scroller.ComputeScrollOffset( + start_time + scroll_duration / 2, &offset, &velocity)); + EXPECT_EQ(curr_x, offset.x()); + EXPECT_EQ(curr_y, offset.y()); + EXPECT_EQ(curr_velocity_x, velocity.x()); + EXPECT_EQ(curr_velocity_y, velocity.y()); + + // Advance to the end. + EXPECT_FALSE(scroller.ComputeScrollOffset( + start_time + scroll_duration, &offset, &velocity)); + EXPECT_EQ(scroller.GetFinalX(), offset.x()); + EXPECT_EQ(scroller.GetFinalY(), offset.y()); + EXPECT_TRUE(scroller.IsFinished()); + EXPECT_EQ(scroll_duration, scroller.GetTimePassed()); + EXPECT_NEAR(0.f, velocity.x(), kEpsilon); + EXPECT_NEAR(0.f, velocity.y(), kEpsilon); + + // Try to advance further; nothing should change. + EXPECT_FALSE(scroller.ComputeScrollOffset( + start_time + scroll_duration * 2, &offset, &velocity)); + EXPECT_EQ(scroller.GetFinalX(), offset.x()); + EXPECT_EQ(scroller.GetFinalY(), offset.y()); + EXPECT_TRUE(scroller.IsFinished()); + EXPECT_EQ(scroll_duration, scroller.GetTimePassed()); +} + +TEST_F(ScrollerTest, Fling) { + Scroller scroller(DefaultConfig()); + base::TimeTicks start_time = base::TimeTicks::Now(); + + // Start a fling and verify initialized values. + scroller.Fling(kDefaultStartX, + kDefaultStartY, + kDefaultVelocityX, + kDefaultVelocityY, + INT_MIN, + INT_MAX, + INT_MIN, + INT_MAX, + start_time); + + EXPECT_EQ(kDefaultStartX, scroller.GetStartX()); + EXPECT_EQ(kDefaultStartY, scroller.GetStartY()); + EXPECT_EQ(kDefaultStartX, scroller.GetCurrX()); + EXPECT_EQ(kDefaultStartY, scroller.GetCurrY()); + EXPECT_GT(kDefaultStartX, scroller.GetFinalX()); + EXPECT_LT(kDefaultStartY, scroller.GetFinalY()); + EXPECT_FALSE(scroller.IsFinished()); + EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed()); + + // Advance halfway through the fling. + const base::TimeDelta scroll_duration = scroller.GetDuration(); + gfx::Vector2dF offset, velocity; + scroller.ComputeScrollOffset( + start_time + scroll_duration / 2, &offset, &velocity); + + // Ensure we've moved in the direction of the velocity, but have yet to reach + // the target. + EXPECT_GT(kDefaultStartX, offset.x()); + EXPECT_LT(kDefaultStartY, offset.y()); + EXPECT_LT(scroller.GetFinalX(), offset.x()); + EXPECT_GT(scroller.GetFinalY(), offset.y()); + EXPECT_FALSE(scroller.IsFinished()); + + // Ensure our velocity is non-zero and in the same direction as the original + // velocity. + EXPECT_LT(0.f, velocity.x() * kDefaultVelocityX); + EXPECT_LT(0.f, velocity.y() * kDefaultVelocityY); + EXPECT_TRUE( + scroller.IsScrollingInDirection(kDefaultVelocityX, kDefaultVelocityY)); + + // Repeated offset computations at the same timestamp should yield identical + // results. + float curr_x = offset.x(); + float curr_y = offset.y(); + float curr_velocity_x = velocity.x(); + float curr_velocity_y = velocity.y(); + EXPECT_TRUE(scroller.ComputeScrollOffset( + start_time + scroll_duration / 2, &offset, &velocity)); + EXPECT_EQ(curr_x, offset.x()); + EXPECT_EQ(curr_y, offset.y()); + EXPECT_EQ(curr_velocity_x, velocity.x()); + EXPECT_EQ(curr_velocity_y, velocity.y()); + + // Advance to the end. + EXPECT_FALSE(scroller.ComputeScrollOffset( + start_time + scroll_duration, &offset, &velocity)); + EXPECT_EQ(scroller.GetFinalX(), offset.x()); + EXPECT_EQ(scroller.GetFinalY(), offset.y()); + EXPECT_TRUE(scroller.IsFinished()); + EXPECT_EQ(scroll_duration, scroller.GetTimePassed()); + EXPECT_NEAR(0.f, velocity.x(), kEpsilon); + EXPECT_NEAR(0.f, velocity.y(), kEpsilon); + + // Try to advance further; nothing should change. + EXPECT_FALSE(scroller.ComputeScrollOffset( + start_time + scroll_duration * 2, &offset, &velocity)); + EXPECT_EQ(scroller.GetFinalX(), offset.x()); + EXPECT_EQ(scroller.GetFinalY(), offset.y()); + EXPECT_TRUE(scroller.IsFinished()); + EXPECT_EQ(scroll_duration, scroller.GetTimePassed()); +} + +} // namespace ui diff --git a/chromium/ui/events/devices/x11/touch_factory_x11.cc b/chromium/ui/events/devices/x11/touch_factory_x11.cc index dc2dbfe79af..30992476602 100644 --- a/chromium/ui/events/devices/x11/touch_factory_x11.cc +++ b/chromium/ui/events/devices/x11/touch_factory_x11.cc @@ -179,8 +179,12 @@ bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { (virtual_core_keyboard_device_ == xiev->deviceid); } - if (event->evtype != XI_ButtonPress && - event->evtype != XI_ButtonRelease && + // Don't automatically accept XI_Enter or XI_Leave. They should be checked + // against the pointer_device_lookup_ to prevent handling for slave devices. + // This happens for unknown reasons when using xtest. + // https://crbug.com/683434. + if (event->evtype != XI_ButtonPress && event->evtype != XI_ButtonRelease && + event->evtype != XI_Enter && event->evtype != XI_Leave && event->evtype != XI_Motion) { return true; } diff --git a/chromium/ui/events/event.cc b/chromium/ui/events/event.cc index 3b38945471f..68daf98868e 100644 --- a/chromium/ui/events/event.cc +++ b/chromium/ui/events/event.cc @@ -828,6 +828,7 @@ TouchEvent::TouchEvent(const base::NativeEvent& native_event) unique_event_id_(ui::GetNextTouchEventId()), may_cause_scrolling_(false), should_remove_native_touch_id_mapping_(false), + hovering_(false), pointer_details_(GetTouchPointerDetailsFromNative(native_event)) { latency()->AddLatencyNumberWithTimestamp( INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, time_stamp(), 1); @@ -842,6 +843,7 @@ TouchEvent::TouchEvent(const PointerEvent& pointer_event) unique_event_id_(ui::GetNextTouchEventId()), may_cause_scrolling_(false), should_remove_native_touch_id_mapping_(false), + hovering_(false), pointer_details_(pointer_event.pointer_details()) { DCHECK(pointer_event.IsTouchPointerEvent() || pointer_event.IsPenPointerEvent()); @@ -881,6 +883,7 @@ TouchEvent::TouchEvent(EventType type, unique_event_id_(ui::GetNextTouchEventId()), may_cause_scrolling_(false), should_remove_native_touch_id_mapping_(false), + hovering_(false), pointer_details_(pointer_details) { latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); pointer_details_.twist = angle; @@ -891,6 +894,7 @@ TouchEvent::TouchEvent(const TouchEvent& copy) unique_event_id_(copy.unique_event_id_), may_cause_scrolling_(copy.may_cause_scrolling_), should_remove_native_touch_id_mapping_(false), + hovering_(copy.hovering_), pointer_details_(copy.pointer_details_) { // Copied events should not remove touch id mapping, as this either causes the // mapping to be lost before the initial event has finished dispatching, or @@ -1178,6 +1182,7 @@ KeyEvent::KeyEvent(const base::NativeEvent& native_event, int event_flags) // Only Windows has native character events. if (is_char_) { key_ = DomKey::FromCharacter(native_event.wParam); + set_flags(PlatformKeyMap::ReplaceControlAndAltWithAltGraph(flags())); } else { int adjusted_flags = flags(); key_ = PlatformKeyMap::DomKeyFromKeyboardCode(key_code(), &adjusted_flags); diff --git a/chromium/ui/events/event.h b/chromium/ui/events/event.h index b1baf5a5502..01fbde3ce9a 100644 --- a/chromium/ui/events/event.h +++ b/chromium/ui/events/event.h @@ -716,6 +716,9 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent { void set_may_cause_scrolling(bool causes) { may_cause_scrolling_ = causes; } bool may_cause_scrolling() const { return may_cause_scrolling_; } + void set_hovering(bool hovering) { hovering_ = hovering; } + bool hovering() const { return hovering_; } + void set_should_remove_native_touch_id_mapping( bool should_remove_native_touch_id_mapping) { should_remove_native_touch_id_mapping_ = @@ -753,6 +756,10 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent { // created a mapping between the native id and the touch_id_. bool should_remove_native_touch_id_mapping_; + // True for devices like some pens when they support hovering over + // digitizer and they send events while hovering. + bool hovering_; + // Structure for holding pointer details for implementing PointerEvents API. PointerDetails pointer_details_; }; diff --git a/chromium/ui/events/event_constants.h b/chromium/ui/events/event_constants.h index 79ca132182b..9340ec0b28f 100644 --- a/chromium/ui/events/event_constants.h +++ b/chromium/ui/events/event_constants.h @@ -103,7 +103,7 @@ enum EventFlags { EF_ALTGR_DOWN = 1 << 5, EF_MOD3_DOWN = 1 << 6, - // Other keyboard state. + // Other keyboard states. EF_NUM_LOCK_ON = 1 << 7, EF_CAPS_LOCK_ON = 1 << 8, EF_SCROLL_LOCK_ON = 1 << 9, @@ -116,7 +116,7 @@ enum EventFlags { EF_FORWARD_MOUSE_BUTTON = 1 << 14, }; -// Flags specific to key events +// Flags specific to key events. enum KeyEventFlags { EF_IME_FABRICATED_KEY = 1 << 15, // Key event fabricated by the underlying // IME without a user action. @@ -127,7 +127,7 @@ enum KeyEventFlags { EF_IS_EXTENDED_KEY = 1 << 18, // Windows extended key (see WM_KEYDOWN doc) }; -// Flags specific to mouse events +// Flags specific to mouse events. enum MouseEventFlags { EF_IS_DOUBLE_CLICK = 1 << 15, EF_IS_TRIPLE_CLICK = 1 << 16, diff --git a/chromium/ui/events/event_unittest.cc b/chromium/ui/events/event_unittest.cc index be300ce3ddd..3702b5b1daa 100644 --- a/chromium/ui/events/event_unittest.cc +++ b/chromium/ui/events/event_unittest.cc @@ -11,12 +11,15 @@ #include "base/macros.h" #include "base/test/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" +#include "ui/events/keycodes/keyboard_code_conversion.h" #include "ui/events/test/events_test_utils.h" +#include "ui/events/test/keyboard_layout.h" #include "ui/events/test/test_event_target.h" #include "ui/gfx/transform.h" @@ -1123,4 +1126,122 @@ TEST(EventTest, UpdateForRootTransformation) { } } +#if defined(OS_WIN) +namespace { + +const struct AltGraphEventTestCase { + KeyboardCode key_code; + KeyboardLayout layout; + std::vector<KeyboardCode> modifier_key_codes; + int expected_flags; +} kAltGraphEventTestCases[] = { + // US English -> AltRight never behaves as AltGraph. + {VKEY_C, + KEYBOARD_LAYOUT_ENGLISH_US, + {VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL}, + EF_ALT_DOWN | EF_CONTROL_DOWN}, + {VKEY_E, + KEYBOARD_LAYOUT_ENGLISH_US, + {VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL}, + EF_ALT_DOWN | EF_CONTROL_DOWN}, + + // French -> Always expect AltGraph if VKEY_RMENU is pressed. + {VKEY_C, + KEYBOARD_LAYOUT_FRENCH, + {VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL}, + EF_ALTGR_DOWN}, + {VKEY_E, + KEYBOARD_LAYOUT_FRENCH, + {VKEY_RMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL}, + EF_ALTGR_DOWN}, + + // French -> Expect Control+Alt is AltGraph on AltGraph-shifted keys. + {VKEY_C, + KEYBOARD_LAYOUT_FRENCH, + {VKEY_LMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL}, + EF_ALT_DOWN | EF_CONTROL_DOWN}, + {VKEY_E, + KEYBOARD_LAYOUT_FRENCH, + {VKEY_LMENU, VKEY_LCONTROL, VKEY_MENU, VKEY_CONTROL}, + EF_ALTGR_DOWN}, +}; + +class AltGraphEventTest : public testing::TestWithParam< + std::tr1::tuple<UINT, AltGraphEventTestCase>> { + public: + AltGraphEventTest() + : msg_({nullptr, message_type(), + static_cast<WPARAM>(test_case().key_code)}) { + // Save the current keyboard layout and state, to restore later. + CHECK(GetKeyboardState(original_keyboard_state_)); + original_keyboard_layout_ = GetKeyboardLayout(0); + + // Configure specified layout, and update keyboard state for specified + // modifier keys. + CHECK(ActivateKeyboardLayout(GetPlatformKeyboardLayout(test_case().layout), + 0)); + BYTE test_keyboard_state[256] = {}; + for (const auto& key_code : test_case().modifier_key_codes) + test_keyboard_state[key_code] = 0x80; + CHECK(SetKeyboardState(test_keyboard_state)); + } + + ~AltGraphEventTest() { + // Restore the original keyboard layout & key states. + CHECK(ActivateKeyboardLayout(original_keyboard_layout_, 0)); + CHECK(SetKeyboardState(original_keyboard_state_)); + } + + protected: + UINT message_type() const { return std::tr1::get<0>(GetParam()); } + const AltGraphEventTestCase& test_case() const { + return std::tr1::get<1>(GetParam()); + } + + const MSG msg_; + base::test::ScopedFeatureList feature_list_; + BYTE original_keyboard_state_[256] = {}; + HKL original_keyboard_layout_ = nullptr; +}; + +} // namespace + +TEST_P(AltGraphEventTest, OldKeyEventAltGraphModifier) { + feature_list_.InitFromCommandLine("", "FixAltGraph"); + + // Old behaviour always sets AltGraph modifier whenever both Control and Alt + // are pressed. + KeyEvent event(msg_); + EXPECT_EQ(event.flags() & (EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN), + EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN); +} + +TEST_P(AltGraphEventTest, KeyEventAltGraphModifer) { + feature_list_.InitFromCommandLine("FixAltGraph", ""); + + KeyEvent event(msg_); + if (message_type() == WM_CHAR) { + // By definition, if we receive a WM_CHAR message when Control and Alt are + // pressed, it indicates AltGraph. + EXPECT_EQ(event.flags() & (EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN), + EF_ALTGR_DOWN); + } else { + EXPECT_EQ(event.flags() & (EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN), + test_case().expected_flags); + } +} + +INSTANTIATE_TEST_CASE_P( + WM_KEY, + AltGraphEventTest, + ::testing::Combine(::testing::Values(WM_KEYDOWN, WM_KEYUP), + ::testing::ValuesIn(kAltGraphEventTestCases))); +INSTANTIATE_TEST_CASE_P( + WM_CHAR, + AltGraphEventTest, + ::testing::Combine(::testing::Values(WM_CHAR), + ::testing::ValuesIn(kAltGraphEventTestCases))); + +#endif // defined(OS_WIN) + } // namespace ui diff --git a/chromium/ui/events/event_utils.cc b/chromium/ui/events/event_utils.cc index 796518f1c5e..aa9b26e309d 100644 --- a/chromium/ui/events/event_utils.cc +++ b/chromium/ui/events/event_utils.cc @@ -86,21 +86,21 @@ void ValidateEventTimeClock(base::TimeTicks* timestamp) { bool ShouldDefaultToNaturalScroll() { return GetInternalDisplayTouchSupport() == - display::Display::TOUCH_SUPPORT_AVAILABLE; + display::Display::TouchSupport::AVAILABLE; } display::Display::TouchSupport GetInternalDisplayTouchSupport() { display::Screen* screen = display::Screen::GetScreen(); // No screen in some unit tests. if (!screen) - return display::Display::TOUCH_SUPPORT_UNKNOWN; + return display::Display::TouchSupport::UNKNOWN; const std::vector<display::Display>& displays = screen->GetAllDisplays(); for (std::vector<display::Display>::const_iterator it = displays.begin(); it != displays.end(); ++it) { if (it->IsInternal()) return it->touch_support(); } - return display::Display::TOUCH_SUPPORT_UNAVAILABLE; + return display::Display::TouchSupport::UNAVAILABLE; } void ComputeEventLatencyOS(const base::NativeEvent& native_event) { @@ -135,4 +135,19 @@ void ComputeEventLatencyOS(const base::NativeEvent& native_event) { } } +void ConvertEventLocationToTargetWindowLocation( + const gfx::Point& target_window_origin, + const gfx::Point& current_window_origin, + ui::LocatedEvent* located_event) { + if (current_window_origin == target_window_origin) + return; + + DCHECK(located_event); + gfx::Vector2d offset = current_window_origin - target_window_origin; + gfx::PointF location_in_pixel_in_host = + located_event->location_f() + gfx::Vector2dF(offset); + located_event->set_location_f(location_in_pixel_in_host); + located_event->set_root_location_f(location_in_pixel_in_host); +} + } // namespace ui diff --git a/chromium/ui/events/event_utils.h b/chromium/ui/events/event_utils.h index f15a2dba849..5e1d931efea 100644 --- a/chromium/ui/events/event_utils.h +++ b/chromium/ui/events/event_utils.h @@ -177,6 +177,14 @@ EVENTS_EXPORT void UpdateX11EventForChangedButtonFlags(MouseEvent* event); // Registers a custom event type. EVENTS_EXPORT int RegisterCustomEventType(); +// Updates the location of |located_event| from |current_window_origin| to be in +// |target_window_origin|'s coordinate system so that it can be dispatched to a +// window based on |target_window_origin|. +EVENTS_EXPORT void ConvertEventLocationToTargetWindowLocation( + const gfx::Point& target_window_origin, + const gfx::Point& current_window_origin, + ui::LocatedEvent* located_event); + } // namespace ui #endif // UI_EVENTS_EVENT_UTILS_H_ diff --git a/chromium/ui/events/gesture_detection/filtered_gesture_provider.cc b/chromium/ui/events/gesture_detection/filtered_gesture_provider.cc index 10b93b25730..8038aa73902 100644 --- a/chromium/ui/events/gesture_detection/filtered_gesture_provider.cc +++ b/chromium/ui/events/gesture_detection/filtered_gesture_provider.cc @@ -31,7 +31,7 @@ FilteredGestureProvider::OnTouchEvent(const MotionEvent& event) { pending_gesture_packet_ = GestureEventDataPacket::FromTouch(event); - if (event.GetAction() == MotionEvent::ACTION_DOWN) + if (event.GetAction() == MotionEvent::Action::DOWN) any_touch_moved_beyond_slop_region_ = false; if (!gesture_provider_.OnTouchEvent(event)) diff --git a/chromium/ui/events/gesture_detection/gesture_detector.cc b/chromium/ui/events/gesture_detection/gesture_detector.cc index adb22f572c1..baa63d31d2e 100644 --- a/chromium/ui/events/gesture_detection/gesture_detector.cc +++ b/chromium/ui/events/gesture_detection/gesture_detector.cc @@ -150,7 +150,7 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { velocity_tracker_.AddMovement(ev); - const bool pointer_up = action == MotionEvent::ACTION_POINTER_UP; + const bool pointer_up = action == MotionEvent::Action::POINTER_UP; const int skip_index = pointer_up ? ev.GetActionIndex() : -1; // Determine focal point. @@ -169,16 +169,16 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { bool handled = false; switch (action) { - case MotionEvent::ACTION_NONE: - case MotionEvent::ACTION_HOVER_ENTER: - case MotionEvent::ACTION_HOVER_EXIT: - case MotionEvent::ACTION_HOVER_MOVE: - case MotionEvent::ACTION_BUTTON_PRESS: - case MotionEvent::ACTION_BUTTON_RELEASE: + case MotionEvent::Action::NONE: + case MotionEvent::Action::HOVER_ENTER: + case MotionEvent::Action::HOVER_EXIT: + case MotionEvent::Action::HOVER_MOVE: + case MotionEvent::Action::BUTTON_PRESS: + case MotionEvent::Action::BUTTON_RELEASE: NOTREACHED(); return handled; - case MotionEvent::ACTION_POINTER_DOWN: { + case MotionEvent::Action::POINTER_DOWN: { down_focus_x_ = last_focus_x_ = focus_x; down_focus_y_ = last_focus_y_ = focus_y; // Cancel long press and taps. @@ -204,7 +204,7 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { two_finger_tap_allowed_for_gesture_ = false; } break; - case MotionEvent::ACTION_POINTER_UP: { + case MotionEvent::Action::POINTER_UP: { down_focus_x_ = last_focus_x_ = focus_x; down_focus_y_ = last_focus_y_ = focus_y; @@ -246,7 +246,7 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { two_finger_tap_allowed_for_gesture_ = false; } break; - case MotionEvent::ACTION_DOWN: { + case MotionEvent::Action::DOWN: { bool is_repeated_tap = current_down_event_ && previous_up_event_ && IsRepeatedTap(*current_down_event_, *previous_up_event_, ev); @@ -292,35 +292,15 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { handled |= listener_->OnDown(ev); } break; - case MotionEvent::ACTION_MOVE: - { - const float scroll_x = last_focus_x_ - focus_x; - const float scroll_y = last_focus_y_ - focus_y; - if (is_double_tapping_) { - // Give the move events of the double-tap. - DCHECK(double_tap_listener_); - handled |= double_tap_listener_->OnDoubleTapEvent(ev); - } else if (all_pointers_within_slop_regions_) { - if (!IsWithinTouchSlop(ev)) { - handled = listener_->OnScroll( - *current_down_event_, ev, - (maximum_pointer_count_ > 1 && secondary_pointer_down_event_) - ? *secondary_pointer_down_event_ - : ev, - scroll_x, scroll_y); - last_focus_x_ = focus_x; - last_focus_y_ = focus_y; - all_pointers_within_slop_regions_ = false; - timeout_handler_->Stop(); - } - - const float delta_x = focus_x - down_focus_x_; - const float delta_y = focus_y - down_focus_y_; - const float distance_square = delta_x * delta_x + delta_y * delta_y; - if (distance_square > double_tap_touch_slop_square_) - always_in_bigger_tap_region_ = false; - } else if (std::abs(scroll_x) > kScrollEpsilon || - std::abs(scroll_y) > kScrollEpsilon) { + case MotionEvent::Action::MOVE: { + const float scroll_x = last_focus_x_ - focus_x; + const float scroll_y = last_focus_y_ - focus_y; + if (is_double_tapping_) { + // Give the move events of the double-tap. + DCHECK(double_tap_listener_); + handled |= double_tap_listener_->OnDoubleTapEvent(ev); + } else if (all_pointers_within_slop_regions_) { + if (!IsWithinTouchSlop(ev)) { handled = listener_->OnScroll( *current_down_event_, ev, (maximum_pointer_count_ > 1 && secondary_pointer_down_event_) @@ -329,22 +309,40 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { scroll_x, scroll_y); last_focus_x_ = focus_x; last_focus_y_ = focus_y; + all_pointers_within_slop_regions_ = false; + timeout_handler_->Stop(); } - if (!two_finger_tap_allowed_for_gesture_) - break; + const float delta_x = focus_x - down_focus_x_; + const float delta_y = focus_y - down_focus_y_; + const float distance_square = delta_x * delta_x + delta_y * delta_y; + if (distance_square > double_tap_touch_slop_square_) + always_in_bigger_tap_region_ = false; + } else if (std::abs(scroll_x) > kScrollEpsilon || + std::abs(scroll_y) > kScrollEpsilon) { + handled = listener_->OnScroll( + *current_down_event_, ev, + (maximum_pointer_count_ > 1 && secondary_pointer_down_event_) + ? *secondary_pointer_down_event_ + : ev, + scroll_x, scroll_y); + last_focus_x_ = focus_x; + last_focus_y_ = focus_y; + } - // Two-finger tap should be prevented if either pointer exceeds its - // (independent) slop region. - // If the event has had more than two pointers down at any time, - // two finger tap should be prevented. - if (maximum_pointer_count_ > 2 || !IsWithinTouchSlop(ev)) { - two_finger_tap_allowed_for_gesture_ = false; - } + if (!two_finger_tap_allowed_for_gesture_) + break; + + // Two-finger tap should be prevented if either pointer exceeds its + // (independent) slop region. + // If the event has had more than two pointers down at any time, + // two finger tap should be prevented. + if (maximum_pointer_count_ > 2 || !IsWithinTouchSlop(ev)) { + two_finger_tap_allowed_for_gesture_ = false; } - break; + } break; - case MotionEvent::ACTION_UP: + case MotionEvent::Action::UP: still_down_ = false; { if (is_double_tapping_) { @@ -375,8 +373,8 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { if ((std::abs(velocity_y) > min_fling_velocity_) || (std::abs(velocity_x) > min_fling_velocity_)) { - handled = listener_->OnFling( - *current_down_event_, ev, velocity_x, velocity_y); + handled = listener_->OnFling(*current_down_event_, ev, velocity_x, + velocity_y); } handled |= HandleSwipeIfNeeded(ev, velocity_x, velocity_y); @@ -393,7 +391,7 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { maximum_pointer_count_ = 0; break; - case MotionEvent::ACTION_CANCEL: + case MotionEvent::Action::CANCEL: Cancel(); break; } diff --git a/chromium/ui/events/gesture_detection/gesture_event_data.cc b/chromium/ui/events/gesture_detection/gesture_event_data.cc index 74a11be246a..e72d2104814 100644 --- a/chromium/ui/events/gesture_detection/gesture_event_data.cc +++ b/chromium/ui/events/gesture_detection/gesture_event_data.cc @@ -12,15 +12,15 @@ namespace { EventPointerType ToEventPointerType(MotionEvent::ToolType tool_type) { switch (tool_type) { - case MotionEvent::TOOL_TYPE_UNKNOWN: + case MotionEvent::ToolType::UNKNOWN: return EventPointerType::POINTER_TYPE_UNKNOWN; - case MotionEvent::TOOL_TYPE_FINGER: + case MotionEvent::ToolType::FINGER: return EventPointerType::POINTER_TYPE_TOUCH; - case MotionEvent::TOOL_TYPE_STYLUS: + case MotionEvent::ToolType::STYLUS: return EventPointerType::POINTER_TYPE_PEN; - case MotionEvent::TOOL_TYPE_MOUSE: + case MotionEvent::ToolType::MOUSE: return EventPointerType::POINTER_TYPE_MOUSE; - case MotionEvent::TOOL_TYPE_ERASER: + case MotionEvent::ToolType::ERASER: return EventPointerType::POINTER_TYPE_ERASER; default: NOTREACHED() << "Invalid ToolType = " << tool_type; @@ -80,13 +80,12 @@ GestureEventData::GestureEventData(const GestureEventData& other) = default; GestureEventData::GestureEventData() : motion_event_id(0), - primary_tool_type(MotionEvent::TOOL_TYPE_UNKNOWN), + primary_tool_type(MotionEvent::ToolType::UNKNOWN), x(0), y(0), raw_x(0), raw_y(0), flags(EF_NONE), - unique_touch_event_id(0U) { -} + unique_touch_event_id(0U) {} } // namespace ui diff --git a/chromium/ui/events/gesture_detection/gesture_event_data_packet.cc b/chromium/ui/events/gesture_detection/gesture_event_data_packet.cc index 5edd34a610b..d5b17225bd4 100644 --- a/chromium/ui/events/gesture_detection/gesture_event_data_packet.cc +++ b/chromium/ui/events/gesture_detection/gesture_event_data_packet.cc @@ -13,24 +13,24 @@ namespace { GestureEventDataPacket::GestureSource ToGestureSource( const ui::MotionEvent& event) { switch (event.GetAction()) { - case ui::MotionEvent::ACTION_DOWN: + case ui::MotionEvent::Action::DOWN: return GestureEventDataPacket::TOUCH_SEQUENCE_START; - case ui::MotionEvent::ACTION_UP: + case ui::MotionEvent::Action::UP: return GestureEventDataPacket::TOUCH_SEQUENCE_END; - case ui::MotionEvent::ACTION_MOVE: + case ui::MotionEvent::Action::MOVE: return GestureEventDataPacket::TOUCH_MOVE; - case ui::MotionEvent::ACTION_CANCEL: + case ui::MotionEvent::Action::CANCEL: return GestureEventDataPacket::TOUCH_SEQUENCE_CANCEL; - case ui::MotionEvent::ACTION_POINTER_DOWN: + case ui::MotionEvent::Action::POINTER_DOWN: return GestureEventDataPacket::TOUCH_START; - case ui::MotionEvent::ACTION_POINTER_UP: + case ui::MotionEvent::Action::POINTER_UP: return GestureEventDataPacket::TOUCH_END; - case ui::MotionEvent::ACTION_NONE: - case ui::MotionEvent::ACTION_HOVER_ENTER: - case ui::MotionEvent::ACTION_HOVER_EXIT: - case ui::MotionEvent::ACTION_HOVER_MOVE: - case ui::MotionEvent::ACTION_BUTTON_PRESS: - case ui::MotionEvent::ACTION_BUTTON_RELEASE: + case ui::MotionEvent::Action::NONE: + case ui::MotionEvent::Action::HOVER_ENTER: + case ui::MotionEvent::Action::HOVER_EXIT: + case ui::MotionEvent::Action::HOVER_MOVE: + case ui::MotionEvent::Action::BUTTON_PRESS: + case ui::MotionEvent::Action::BUTTON_RELEASE: NOTREACHED(); return GestureEventDataPacket::INVALID; }; diff --git a/chromium/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc b/chromium/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc index 1b7ec0e279c..ed46774ee35 100644 --- a/chromium/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc +++ b/chromium/ui/events/gesture_detection/gesture_event_data_packet_unittest.cc @@ -18,18 +18,11 @@ const float kTouchY = 14.2f; const uint32_t uniqueTouchEventId = 1234U; GestureEventData CreateGesture(EventType type) { - return GestureEventData(GestureEventDetails(type), - 0, - MotionEvent::TOOL_TYPE_FINGER, - base::TimeTicks(), - kTouchX, - kTouchY, - kTouchX + 5.f, - kTouchY + 10.f, - 1, + return GestureEventData(GestureEventDetails(type), 0, + MotionEvent::ToolType::FINGER, base::TimeTicks(), + kTouchX, kTouchY, kTouchX + 5.f, kTouchY + 10.f, 1, gfx::RectF(kTouchX - 1.f, kTouchY - 1.f, 2.f, 2.f), - EF_NONE, - uniqueTouchEventId); + EF_NONE, uniqueTouchEventId); } } // namespace @@ -75,7 +68,7 @@ TEST_F(GestureEventDataPacketTest, Basic) { EXPECT_EQ(GestureEventDataPacket::UNDEFINED, packet.gesture_source()); packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_DOWN, touch_time, kTouchX, kTouchY)); + MockMotionEvent(MotionEvent::Action::DOWN, touch_time, kTouchX, kTouchY)); EXPECT_TRUE(touch_time == packet.timestamp()); EXPECT_EQ(0U, packet.gesture_count()); EXPECT_EQ(gfx::PointF(kTouchX, kTouchY), packet.touch_location()); @@ -94,7 +87,7 @@ TEST_F(GestureEventDataPacketTest, Basic) { TEST_F(GestureEventDataPacketTest, Copy) { GestureEventDataPacket packet0 = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_UP)); + MockMotionEvent(MotionEvent::Action::UP)); packet0.Push(CreateGesture(ET_GESTURE_TAP_DOWN)); packet0.Push(CreateGesture(ET_GESTURE_SCROLL_BEGIN)); @@ -107,30 +100,30 @@ TEST_F(GestureEventDataPacketTest, Copy) { TEST_F(GestureEventDataPacketTest, GestureSource) { GestureEventDataPacket packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_DOWN)); + MockMotionEvent(MotionEvent::Action::DOWN)); EXPECT_EQ(GestureEventDataPacket::TOUCH_SEQUENCE_START, packet.gesture_source()); packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_UP)); + MockMotionEvent(MotionEvent::Action::UP)); EXPECT_EQ(GestureEventDataPacket::TOUCH_SEQUENCE_END, packet.gesture_source()); packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_CANCEL)); + MockMotionEvent(MotionEvent::Action::CANCEL)); EXPECT_EQ(GestureEventDataPacket::TOUCH_SEQUENCE_CANCEL, packet.gesture_source()); packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_MOVE)); + MockMotionEvent(MotionEvent::Action::MOVE)); EXPECT_EQ(GestureEventDataPacket::TOUCH_MOVE, packet.gesture_source()); packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_POINTER_DOWN)); + MockMotionEvent(MotionEvent::Action::POINTER_DOWN)); EXPECT_EQ(GestureEventDataPacket::TOUCH_START, packet.gesture_source()); packet = GestureEventDataPacket::FromTouch( - MockMotionEvent(MotionEvent::ACTION_POINTER_UP)); + MockMotionEvent(MotionEvent::Action::POINTER_UP)); EXPECT_EQ(GestureEventDataPacket::TOUCH_END, packet.gesture_source()); GestureEventData gesture = CreateGesture(ET_GESTURE_TAP); diff --git a/chromium/ui/events/gesture_detection/gesture_provider.cc b/chromium/ui/events/gesture_detection/gesture_provider.cc index c933f99d16b..d05af6677f4 100644 --- a/chromium/ui/events/gesture_detection/gesture_provider.cc +++ b/chromium/ui/events/gesture_detection/gesture_provider.cc @@ -28,30 +28,30 @@ const float kDoubleTapDragZoomSpeed = 0.005f; const char* GetMotionEventActionName(MotionEvent::Action action) { switch (action) { - case MotionEvent::ACTION_NONE: - return "ACTION_NONE"; - case MotionEvent::ACTION_POINTER_DOWN: - return "ACTION_POINTER_DOWN"; - case MotionEvent::ACTION_POINTER_UP: - return "ACTION_POINTER_UP"; - case MotionEvent::ACTION_DOWN: - return "ACTION_DOWN"; - case MotionEvent::ACTION_UP: - return "ACTION_UP"; - case MotionEvent::ACTION_CANCEL: - return "ACTION_CANCEL"; - case MotionEvent::ACTION_MOVE: - return "ACTION_MOVE"; - case MotionEvent::ACTION_HOVER_ENTER: - return "ACTION_HOVER_ENTER"; - case MotionEvent::ACTION_HOVER_EXIT: - return "ACTION_HOVER_EXIT"; - case MotionEvent::ACTION_HOVER_MOVE: - return "ACTION_HOVER_MOVE"; - case MotionEvent::ACTION_BUTTON_PRESS: - return "ACTION_BUTTON_PRESS"; - case MotionEvent::ACTION_BUTTON_RELEASE: - return "ACTION_BUTTON_RELEASE"; + case MotionEvent::Action::NONE: + return "Action::NONE"; + case MotionEvent::Action::POINTER_DOWN: + return "Action::POINTER_DOWN"; + case MotionEvent::Action::POINTER_UP: + return "Action::POINTER_UP"; + case MotionEvent::Action::DOWN: + return "Action::DOWN"; + case MotionEvent::Action::UP: + return "Action::UP"; + case MotionEvent::Action::CANCEL: + return "Action::CANCEL"; + case MotionEvent::Action::MOVE: + return "Action::MOVE"; + case MotionEvent::Action::HOVER_ENTER: + return "Action::HOVER_ENTER"; + case MotionEvent::Action::HOVER_EXIT: + return "Action::HOVER_EXIT"; + case MotionEvent::Action::HOVER_MOVE: + return "Action::HOVER_MOVE"; + case MotionEvent::Action::BUTTON_PRESS: + return "Action::BUTTON_PRESS"; + case MotionEvent::Action::BUTTON_RELEASE: + return "Action::BUTTON_RELEASE"; } return ""; } @@ -118,7 +118,7 @@ class GestureProvider::GestureListenerImpl : public ScaleGestureListener, SetIgnoreSingleTap(true); const MotionEvent::Action action = event.GetAction(); - if (action == MotionEvent::ACTION_DOWN) { + if (action == MotionEvent::Action::DOWN) { current_down_time_ = event.GetEventTime(); current_longpress_time_ = base::TimeTicks(); ignore_single_tap_ = false; @@ -132,14 +132,14 @@ class GestureProvider::GestureListenerImpl : public ScaleGestureListener, gesture_detector_.OnTouchEvent(event); scale_gesture_detector_.OnTouchEvent(event); - if (action == MotionEvent::ACTION_UP || - action == MotionEvent::ACTION_CANCEL) { + if (action == MotionEvent::Action::UP || + action == MotionEvent::Action::CANCEL) { // Note: This call will have no effect if a fling was just generated, as // |Fling()| will have already signalled an end to touch-scrolling. if (scroll_event_sent_) Send(CreateGesture(ET_GESTURE_SCROLL_END, event)); current_down_time_ = base::TimeTicks(); - } else if (action == MotionEvent::ACTION_MOVE) { + } else if (action == MotionEvent::Action::MOVE) { if (!show_press_event_sent_ && !scroll_event_sent_) { max_diameter_before_show_press_ = std::max(max_diameter_before_show_press_, event.GetTouchMajor()); @@ -157,8 +157,8 @@ class GestureProvider::GestureListenerImpl : public ScaleGestureListener, gesture.type() == ET_GESTURE_BEGIN || gesture.type() == ET_GESTURE_END); - if (gesture.primary_tool_type == MotionEvent::TOOL_TYPE_UNKNOWN || - gesture.primary_tool_type == MotionEvent::TOOL_TYPE_FINGER) { + if (gesture.primary_tool_type == MotionEvent::ToolType::UNKNOWN || + gesture.primary_tool_type == MotionEvent::ToolType::FINGER) { gesture.details.set_bounding_box( ClampBoundingBox(gesture.details.bounding_box_f(), config_.min_gesture_bounds_length, @@ -203,6 +203,7 @@ class GestureProvider::GestureListenerImpl : public ScaleGestureListener, // which case the press should simply be dropped. if (pinch_event_sent_ || scroll_event_sent_) return; + break; default: break; }; @@ -457,7 +458,7 @@ class GestureProvider::GestureListenerImpl : public ScaleGestureListener, } } - if (e.GetAction() == MotionEvent::ACTION_UP && + if (e.GetAction() == MotionEvent::Action::UP && !current_longpress_time_.is_null() && !IsScaleGestureDetectionInProgress()) { GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP); @@ -480,11 +481,11 @@ class GestureProvider::GestureListenerImpl : public ScaleGestureListener, bool OnDoubleTapEvent(const MotionEvent& e) override { switch (e.GetAction()) { - case MotionEvent::ACTION_DOWN: + case MotionEvent::Action::DOWN: gesture_detector_.set_longpress_enabled(false); break; - case MotionEvent::ACTION_UP: + case MotionEvent::Action::UP: if (!IsPinchInProgress() && !IsScrollInProgress()) { Send(CreateTapGesture(ET_GESTURE_DOUBLE_TAP, e, 1)); return true; @@ -803,9 +804,8 @@ bool GestureProvider::OnTouchEvent(const MotionEvent& event) { } void GestureProvider::ResetDetection() { - MotionEventGeneric generic_cancel_event(MotionEvent::ACTION_CANCEL, - base::TimeTicks::Now(), - PointerProperties()); + MotionEventGeneric generic_cancel_event( + MotionEvent::Action::CANCEL, base::TimeTicks::Now(), PointerProperties()); OnTouchEvent(generic_cancel_event); } @@ -843,19 +843,20 @@ bool GestureProvider::CanHandle(const MotionEvent& event) const { // Aura requires one cancel event per touch point, whereas Android requires // one cancel event per touch sequence. Thus we need to allow extra cancel // events. - return current_down_event_ || event.GetAction() == MotionEvent::ACTION_DOWN || - event.GetAction() == MotionEvent::ACTION_CANCEL; + return current_down_event_ || + event.GetAction() == MotionEvent::Action::DOWN || + event.GetAction() == MotionEvent::Action::CANCEL; } void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { switch (event.GetAction()) { - case MotionEvent::ACTION_DOWN: + case MotionEvent::Action::DOWN: current_down_event_ = event.Clone(); if (gesture_begin_end_types_enabled_) gesture_listener_->Send( gesture_listener_->CreateGesture(ET_GESTURE_BEGIN, event)); break; - case MotionEvent::ACTION_POINTER_DOWN: + case MotionEvent::Action::POINTER_DOWN: if (gesture_begin_end_types_enabled_) { const int action_index = event.GetActionIndex(); gesture_listener_->Send(gesture_listener_->CreateGesture( @@ -872,17 +873,17 @@ void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { event.GetFlags())); } break; - case MotionEvent::ACTION_POINTER_UP: - case MotionEvent::ACTION_UP: - case MotionEvent::ACTION_CANCEL: - case MotionEvent::ACTION_MOVE: + case MotionEvent::Action::POINTER_UP: + case MotionEvent::Action::UP: + case MotionEvent::Action::CANCEL: + case MotionEvent::Action::MOVE: break; - case MotionEvent::ACTION_NONE: - case MotionEvent::ACTION_HOVER_ENTER: - case MotionEvent::ACTION_HOVER_EXIT: - case MotionEvent::ACTION_HOVER_MOVE: - case MotionEvent::ACTION_BUTTON_PRESS: - case MotionEvent::ACTION_BUTTON_RELEASE: + case MotionEvent::Action::NONE: + case MotionEvent::Action::HOVER_ENTER: + case MotionEvent::Action::HOVER_EXIT: + case MotionEvent::Action::HOVER_MOVE: + case MotionEvent::Action::BUTTON_PRESS: + case MotionEvent::Action::BUTTON_RELEASE: NOTREACHED(); break; } @@ -890,8 +891,8 @@ void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { switch (event.GetAction()) { - case MotionEvent::ACTION_UP: - case MotionEvent::ACTION_CANCEL: { + case MotionEvent::Action::UP: + case MotionEvent::Action::CANCEL: { if (gesture_begin_end_types_enabled_) gesture_listener_->Send( gesture_listener_->CreateGesture(ET_GESTURE_END, event)); @@ -901,21 +902,21 @@ void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { UpdateDoubleTapDetectionSupport(); break; } - case MotionEvent::ACTION_POINTER_UP: + case MotionEvent::Action::POINTER_UP: if (gesture_begin_end_types_enabled_) gesture_listener_->Send( gesture_listener_->CreateGesture(ET_GESTURE_END, event)); break; - case MotionEvent::ACTION_DOWN: - case MotionEvent::ACTION_POINTER_DOWN: - case MotionEvent::ACTION_MOVE: + case MotionEvent::Action::DOWN: + case MotionEvent::Action::POINTER_DOWN: + case MotionEvent::Action::MOVE: break; - case MotionEvent::ACTION_NONE: - case MotionEvent::ACTION_HOVER_ENTER: - case MotionEvent::ACTION_HOVER_EXIT: - case MotionEvent::ACTION_HOVER_MOVE: - case MotionEvent::ACTION_BUTTON_PRESS: - case MotionEvent::ACTION_BUTTON_RELEASE: + case MotionEvent::Action::NONE: + case MotionEvent::Action::HOVER_ENTER: + case MotionEvent::Action::HOVER_EXIT: + case MotionEvent::Action::HOVER_MOVE: + case MotionEvent::Action::BUTTON_PRESS: + case MotionEvent::Action::BUTTON_RELEASE: NOTREACHED(); break; } diff --git a/chromium/ui/events/gesture_detection/gesture_provider_unittest.cc b/chromium/ui/events/gesture_detection/gesture_provider_unittest.cc index 39eae93a98f..354c0ae88f6 100644 --- a/chromium/ui/events/gesture_detection/gesture_provider_unittest.cc +++ b/chromium/ui/events/gesture_detection/gesture_provider_unittest.cc @@ -305,18 +305,17 @@ class GestureProviderTest : public testing::Test, public GestureProviderClient { int motion_event_flags = EF_SHIFT_DOWN | EF_CAPS_LOCK_ON; MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); - event = ObtainMotionEvent(event_time + kOneSecond, - MotionEvent::ACTION_MOVE, - scroll_to_x, - scroll_to_y); - event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); + event = + ObtainMotionEvent(event_time + kOneSecond, MotionEvent::Action::MOVE, + scroll_to_x, scroll_to_y); + event.SetToolType(0, MotionEvent::ToolType::FINGER); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); @@ -337,11 +336,11 @@ class GestureProviderTest : public testing::Test, public GestureProviderClient { EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type()); EXPECT_EQ(motion_event_id, GetReceivedGesture(1).motion_event_id); EXPECT_EQ(event_time + kOneSecond, GetReceivedGesture(1).time) - << "ScrollBegin should have the time of the ACTION_MOVE"; + << "ScrollBegin should have the time of the Action::MOVE"; event = ObtainMotionEvent( event_time + kOneSecond, end_action_type, scroll_to_x, scroll_to_y); - event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); + event.SetToolType(0, MotionEvent::ToolType::FINGER); event.SetPrimaryPointerId(motion_event_id); gesture_provider_->OnTouchEvent(event); @@ -399,11 +398,11 @@ class GestureProviderTest : public testing::Test, public GestureProviderClient { std::vector<gfx::PointF> event_positions(pointer_count); event_positions.assign(positions.begin(), positions.begin() + pointer_count); - MockMotionEvent event = - ObtainMotionEvent(event_time, - pointer_count > 1 ? MotionEvent::ACTION_POINTER_DOWN - : MotionEvent::ACTION_DOWN, - event_positions); + MockMotionEvent event = ObtainMotionEvent( + event_time, + pointer_count > 1 ? MotionEvent::Action::POINTER_DOWN + : MotionEvent::Action::DOWN, + event_positions); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); } @@ -411,20 +410,17 @@ class GestureProviderTest : public testing::Test, public GestureProviderClient { positions[i] += gfx::ScaleVector2d(velocities[i], dt); MockMotionEvent event = ObtainMotionEvent(event_time + kDeltaTimeForFlingSequences, - MotionEvent::ACTION_MOVE, - positions); + MotionEvent::Action::MOVE, positions); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); for (size_t i = 0; i < positions.size(); ++i) positions[i] += gfx::ScaleVector2d(velocities[i], dt); event = ObtainMotionEvent(event_time + 2 * kDeltaTimeForFlingSequences, - MotionEvent::ACTION_MOVE, - positions); + MotionEvent::Action::MOVE, positions); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + 2 * kDeltaTimeForFlingSequences, - MotionEvent::ACTION_POINTER_UP, - positions); + MotionEvent::Action::POINTER_UP, positions); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); } @@ -449,8 +445,8 @@ TEST_F(GestureProviderTest, GestureTap) { gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); - event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); + event.SetToolType(0, MotionEvent::ToolType::FINGER); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); @@ -463,9 +459,9 @@ TEST_F(GestureProviderTest, GestureTap) { EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP); - event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); + event = + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::UP); + event.SetToolType(0, MotionEvent::ToolType::FINGER); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); @@ -492,7 +488,7 @@ TEST_F(GestureProviderTest, GestureTapWithDelay) { gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); @@ -504,8 +500,8 @@ TEST_F(GestureProviderTest, GestureTapWithDelay) { EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP); + event = + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::UP); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); @@ -535,7 +531,7 @@ TEST_F(GestureProviderTest, GestureFlingAndCancelLongPress) { int motion_event_flags = EF_ALT_DOWN; MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); @@ -545,18 +541,15 @@ TEST_F(GestureProviderTest, GestureFlingAndCancelLongPress) { EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); - event = ObtainMotionEvent(event_time + delta_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX * 10, - kFakeCoordY * 10); + event = ObtainMotionEvent(event_time + delta_time, MotionEvent::Action::MOVE, + kFakeCoordX * 10, kFakeCoordY * 10); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time + delta_time * 2, - MotionEvent::ACTION_UP, - kFakeCoordX * 10, - kFakeCoordY * 10); + event = + ObtainMotionEvent(event_time + delta_time * 2, MotionEvent::Action::UP, + kFakeCoordX * 10, kFakeCoordY * 10); event.SetPrimaryPointerId(motion_event_id); event.set_flags(motion_event_flags); @@ -576,7 +569,7 @@ TEST_F(GestureProviderTest, GestureFlingAndCancelLongPress) { // - ET_GESTURE_SCROLL_UPDATE // - ET_GESTURE_SCROLL_END TEST_F(GestureProviderTest, ScrollEventActionUpSequence) { - CheckScrollEventSequenceForEndActionType(MotionEvent::ACTION_UP); + CheckScrollEventSequenceForEndActionType(MotionEvent::Action::UP); } // Verify that for a cancelled scroll the following events are sent: @@ -584,7 +577,7 @@ TEST_F(GestureProviderTest, ScrollEventActionUpSequence) { // - ET_GESTURE_SCROLL_UPDATE // - ET_GESTURE_SCROLL_END TEST_F(GestureProviderTest, ScrollEventActionCancelSequence) { - CheckScrollEventSequenceForEndActionType(MotionEvent::ACTION_CANCEL); + CheckScrollEventSequenceForEndActionType(MotionEvent::Action::CANCEL); } // Verify that for a normal fling (fling after scroll) the following events are @@ -597,15 +590,13 @@ TEST_F(GestureProviderTest, FlingEventSequence) { int motion_event_id = 6; MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time + delta_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX * 5, - kFakeCoordY * 5); + event = ObtainMotionEvent(event_time + delta_time, MotionEvent::Action::MOVE, + kFakeCoordX * 5, kFakeCoordY * 5); event.SetPrimaryPointerId(motion_event_id); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -624,10 +615,9 @@ TEST_F(GestureProviderTest, FlingEventSequence) { EXPECT_TRUE(hint_x > 0 && hint_y > 0 && hint_x > hint_y) << "ScrollBegin hint should be in positive X axis"; - event = ObtainMotionEvent(event_time + delta_time * 2, - MotionEvent::ACTION_UP, - kFakeCoordX * 10, - kFakeCoordY * 10); + event = + ObtainMotionEvent(event_time + delta_time * 2, MotionEvent::Action::UP, + kFakeCoordX * 10, kFakeCoordY * 10); event.SetPrimaryPointerId(motion_event_id); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -637,14 +627,14 @@ TEST_F(GestureProviderTest, FlingEventSequence) { EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_END)); EXPECT_EQ(event_time + delta_time * 2, GetMostRecentGestureEvent().time) - << "FlingStart should have the time of the ACTION_UP"; + << "FlingStart should have the time of the Action::UP"; } TEST_F(GestureProviderTest, GestureCancelledOnCancelEvent) { const base::TimeTicks event_time = TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -658,9 +648,9 @@ TEST_F(GestureProviderTest, GestureCancelledOnCancelEvent) { EXPECT_TRUE(CancelActiveTouchSequence()); EXPECT_FALSE(HasDownEvent()); - // A final ACTION_UP should have no effect. + // A final Action::UP should have no effect. event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_UP); + MotionEvent::Action::UP); EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); } @@ -668,7 +658,7 @@ TEST_F(GestureProviderTest, GestureCancelledOnDetectionReset) { const base::TimeTicks event_time = TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -680,9 +670,9 @@ TEST_F(GestureProviderTest, GestureCancelledOnDetectionReset) { ResetGestureDetection(); EXPECT_FALSE(HasDownEvent()); - // A final ACTION_UP should have no effect. + // A final Action::UP should have no effect. event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_UP); + MotionEvent::Action::UP); EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); } @@ -690,23 +680,20 @@ TEST_F(GestureProviderTest, NoTapAfterScrollBegins) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); - event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX + 50, - kFakeCoordY + 50); + event = + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::MOVE, + kFakeCoordX + 50, kFakeCoordY + 50); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); - event = ObtainMotionEvent(event_time + kOneSecond, - MotionEvent::ACTION_UP, - kFakeCoordX + 50, - kFakeCoordY + 50); + event = ObtainMotionEvent(event_time + kOneSecond, MotionEvent::Action::UP, + kFakeCoordX + 50, kFakeCoordY + 50); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); @@ -716,24 +703,20 @@ TEST_F(GestureProviderTest, DoubleTap) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_DOWN, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -741,18 +724,16 @@ TEST_F(GestureProviderTest, DoubleTap) { // Moving a very small amount of distance should not trigger the double tap // drag zoom mode. - event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX, - kFakeCoordY + 1); + event = + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::MOVE, + kFakeCoordX, kFakeCoordY + 1); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); - event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY + 1); + event = + ObtainMotionEvent(event_time + kOneMicrosecond * 2, + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY + 1); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); const GestureEventData& double_tap = GetMostRecentGestureEvent(); @@ -768,26 +749,23 @@ TEST_F(GestureProviderTest, DoubleTapDragZoomBasic) { const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay(); MockMotionEvent event = - ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(down_time_1, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); - event = ObtainMotionEvent( - down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event = ObtainMotionEvent(down_time_2, MotionEvent::Action::DOWN, kFakeCoordX, + kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 100); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); @@ -798,8 +776,7 @@ TEST_F(GestureProviderTest, DoubleTapDragZoomBasic) { GetMostRecentGestureEvent().details.bounding_box_f()); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); @@ -808,8 +785,7 @@ TEST_F(GestureProviderTest, DoubleTapDragZoomBasic) { GetMostRecentGestureEvent().details.bounding_box_f()); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 100); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); @@ -818,8 +794,7 @@ TEST_F(GestureProviderTest, DoubleTapDragZoomBasic) { GetMostRecentGestureEvent().details.bounding_box_f()); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 4, - MotionEvent::ACTION_UP, - kFakeCoordX, + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY - 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END)); @@ -839,20 +814,18 @@ TEST_F(GestureProviderTest, ScrollUpdateValues) { const base::TimeTicks event_time = TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Move twice so that we get two ET_GESTURE_SCROLL_UPDATE events and can // compare the relative and absolute coordinates. - event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX - delta_x / 2, - kFakeCoordY - delta_y / 2); + event = + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::MOVE, + kFakeCoordX - delta_x / 2, kFakeCoordY - delta_y / 2); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX - delta_x, + MotionEvent::Action::MOVE, kFakeCoordX - delta_x, kFakeCoordY - delta_y); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -882,26 +855,22 @@ TEST_F(GestureProviderTest, FractionalScroll) { const base::TimeTicks event_time = TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Skip past the touch slop and move back. - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 100); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE); + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Now move up slowly, mostly vertically but with a (fractional) bit of // horizontal motion. for (int i = 1; i <= 10; i++) { - event = ObtainMotionEvent(event_time + kOneMicrosecond * i, - MotionEvent::ACTION_MOVE, - kFakeCoordX + delta_x * i, - kFakeCoordY + delta_y * i); + event = ObtainMotionEvent( + event_time + kOneMicrosecond * i, MotionEvent::Action::MOVE, + kFakeCoordX + delta_x * i, kFakeCoordY + delta_y * i); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); ASSERT_LT(0U, GetReceivedGestureCount()); @@ -937,21 +906,19 @@ TEST_F(GestureProviderTest, ScrollBeginValues) { const base::TimeTicks event_time = TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Move twice such that the first event isn't sufficient to start // scrolling on it's own. - event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX + 2, - kFakeCoordY + 1); + event = + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::MOVE, + kFakeCoordX + 2, kFakeCoordY + 1); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(gesture_provider_->IsScrollInProgress()); event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX + delta_x, + MotionEvent::Action::MOVE, kFakeCoordX + delta_x, kFakeCoordY + delta_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(gesture_provider_->IsScrollInProgress()); @@ -973,20 +940,20 @@ TEST_F(GestureProviderTest, SlopRegionCheckOnOneFingerScroll) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 0, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Move within slop region. - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, 0, scaled_touch_slop / 2); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Exceed slop region. - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, 0, 2 * scaled_touch_slop); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP, 0, 2 * scaled_touch_slop); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -1004,41 +971,41 @@ TEST_F(GestureProviderTest, SlopRegionCheckOnTwoFingerScroll) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 0, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, 0, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 0, 0, kMaxTwoFingerTapSeparation / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Move within slop region: two-finger tap happens. - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, 0, scaled_touch_slop / 2, kMaxTwoFingerTapSeparation / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_UP, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_UP, 0, scaled_touch_slop / 2, kMaxTwoFingerTapSeparation / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Exceed slop region: scroll. - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 0, scaled_touch_slop / 2, kMaxTwoFingerTapSeparation / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_MOVE, 0, scaled_touch_slop / 2, + event_time, MotionEvent::Action::MOVE, 0, scaled_touch_slop / 2, kMaxTwoFingerTapSeparation / 2, 2 * scaled_touch_slop); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_UP, 0, scaled_touch_slop / 2, + event_time, MotionEvent::Action::POINTER_UP, 0, scaled_touch_slop / 2, kMaxTwoFingerTapSeparation / 2, 2 * scaled_touch_slop); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP, 0, scaled_touch_slop / 2); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -1059,13 +1026,13 @@ TEST_F(GestureProviderTest, SlopRegionCheckOnMissingSecondaryPointerDownEvent) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 0, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - // Don't send ACTION_POINTER_DOWN event to the gesture_provider. - // This is for simulating the cases that the ACTION_POINTER_DOWN event is + // Don't send Action::POINTER_DOWN event to the gesture_provider. + // This is for simulating the cases that the Action::POINTER_DOWN event is // missing from the event sequence. - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, 0, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 0, 0, kMaxTwoFingerTapSeparation / 2, 0); event.MovePoint(1, 0, 3 * scaled_touch_slop); @@ -1091,21 +1058,21 @@ TEST_F(GestureProviderTest, NoSlopRegionCheckOnThreeFingerScroll) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 0, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, 0, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 0, 0, kMaxTwoFingerTapSeparation / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, 0, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 0, 0, kMaxTwoFingerTapSeparation / 2, 0, 2 * kMaxTwoFingerTapSeparation, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Move within slop region, three-finger scroll always happens. event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_MOVE, 0, scaled_touch_slop / 2, + event_time, MotionEvent::Action::MOVE, 0, scaled_touch_slop / 2, kMaxTwoFingerTapSeparation / 2, 0, 2 * kMaxTwoFingerTapSeparation, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -1122,10 +1089,10 @@ TEST_F(GestureProviderTest, ScrollStartWithSecondaryPointer) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 0, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, 0, 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 0, 0, kMaxTwoFingerTapSeparation / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -1152,21 +1119,21 @@ TEST_F(GestureProviderTest, NoFlingBeforeExeedingSlopRegion) { base::TimeTicks event_time = base::TimeTicks::Now(); base::TimeDelta delta_time = kDeltaTimeForFlingSequences; MockMotionEvent event = ObtainMotionEvent(event_time + delta_time, - MotionEvent::ACTION_DOWN, 0, 0); + MotionEvent::Action::DOWN, 0, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + 2 * delta_time, - MotionEvent::ACTION_POINTER_DOWN, 0, 0, 10, 0); + MotionEvent::Action::POINTER_DOWN, 0, 0, 10, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); // Fast pointer movements within touch slop region. event = ObtainMotionEvent(event_time + 3 * delta_time, - MotionEvent::ACTION_MOVE, 1, 0, 11, 0); + MotionEvent::Action::MOVE, 1, 0, 11, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + 4 * delta_time, - MotionEvent::ACTION_MOVE, 2, 0, 12, 0); + MotionEvent::Action::MOVE, 2, 0, 12, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + 5 * delta_time, - MotionEvent::ACTION_MOVE, 3, 0, 13, 0); + MotionEvent::Action::MOVE, 3, 0, 13, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event.ReleasePointAtIndex(0); @@ -1184,16 +1151,14 @@ TEST_F(GestureProviderTest, LongPressAndTapCancelledWhenScrollBegins) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX * 5, - kFakeCoordY * 5); + event = + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::MOVE, + kFakeCoordX * 5, kFakeCoordY * 5); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX * 10, + MotionEvent::Action::MOVE, kFakeCoordX * 10, kFakeCoordY * 10); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -1211,7 +1176,7 @@ TEST_F(GestureProviderTest, GestureLongTap) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); const base::TimeDelta long_press_timeout = @@ -1223,7 +1188,7 @@ TEST_F(GestureProviderTest, GestureLongTap) { EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent(event_time + kOneSecond, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time + kOneSecond, MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_LONG_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); @@ -1235,7 +1200,7 @@ TEST_F(GestureProviderTest, GestureLongPressDoesNotPreventScrolling) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); const base::TimeDelta long_press_timeout = @@ -1245,8 +1210,7 @@ TEST_F(GestureProviderTest, GestureLongPressDoesNotPreventScrolling) { EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event = ObtainMotionEvent(event_time + long_press_timeout, - MotionEvent::ACTION_MOVE, - kFakeCoordX + 100, + MotionEvent::Action::MOVE, kFakeCoordX + 100, kFakeCoordY + 100); gesture_provider_->OnTouchEvent(event); @@ -1255,7 +1219,7 @@ TEST_F(GestureProviderTest, GestureLongPressDoesNotPreventScrolling) { EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); event = ObtainMotionEvent(event_time + long_press_timeout, - MotionEvent::ACTION_UP); + MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); } @@ -1265,21 +1229,17 @@ TEST_F(GestureProviderTest, NoGestureLongPressDuringDoubleTap) { int motion_event_id = 6; MockMotionEvent event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_DOWN, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -1292,8 +1252,7 @@ TEST_F(GestureProviderTest, NoGestureLongPressDuringDoubleTap) { EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_PRESS)); event = ObtainMotionEvent(event_time + long_press_timeout, - MotionEvent::ACTION_MOVE, - kFakeCoordX + 20, + MotionEvent::Action::MOVE, kFakeCoordX + 20, kFakeCoordY + 20); event.SetPrimaryPointerId(motion_event_id); @@ -1304,10 +1263,9 @@ TEST_F(GestureProviderTest, NoGestureLongPressDuringDoubleTap) { EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); EXPECT_TRUE(gesture_provider_->IsDoubleTapInProgress()); - event = ObtainMotionEvent(event_time + long_press_timeout + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY + 1); + event = + ObtainMotionEvent(event_time + long_press_timeout + kOneMicrosecond, + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY + 1); event.SetPrimaryPointerId(motion_event_id); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); @@ -1325,12 +1283,11 @@ TEST_F(GestureProviderTest, TouchSlopRemovedFromScroll) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + touch_slop + scroll_delta); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -1351,42 +1308,36 @@ TEST_F(GestureProviderTest, NoScrollWithinTouchSlop) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX + touch_slop_pixels / scale_factor, - kFakeCoordY); + event = ObtainMotionEvent( + event_time + kOneMicrosecond * 2, MotionEvent::Action::MOVE, + kFakeCoordX + touch_slop_pixels / scale_factor, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + touch_slop_pixels / scale_factor); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); - event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX - touch_slop_pixels / scale_factor, - kFakeCoordY); + event = ObtainMotionEvent( + event_time + kOneMicrosecond * 2, MotionEvent::Action::MOVE, + kFakeCoordX - touch_slop_pixels / scale_factor, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY - touch_slop_pixels / scale_factor); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); - event = - ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, - kFakeCoordY + (touch_slop_pixels + 1.f) / scale_factor); + event = ObtainMotionEvent( + event_time + kOneMicrosecond * 2, MotionEvent::Action::MOVE, kFakeCoordX, + kFakeCoordY + (touch_slop_pixels + 1.f) / scale_factor); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); } @@ -1395,16 +1346,14 @@ TEST_F(GestureProviderTest, NoDoubleTapWhenTooRapid) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); @@ -1412,18 +1361,14 @@ TEST_F(GestureProviderTest, NoDoubleTapWhenTooRapid) { // If the second tap follows the first in too short a time span, no double-tap // will occur. event_time += (GetDoubleTapMinTime() / 2); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_DOWN, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); } @@ -1434,29 +1379,23 @@ TEST_F(GestureProviderTest, NoDoubleTapWhenExplicitlyDisabled) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_DOWN, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); @@ -1464,15 +1403,13 @@ TEST_F(GestureProviderTest, NoDoubleTapWhenExplicitlyDisabled) { gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); event_time = base::TimeTicks::Now(); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, + kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(5U, GetReceivedGestureCount()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); @@ -1483,32 +1420,24 @@ TEST_F(GestureProviderTest, NoDoubleTapWhenExplicitlyDisabled) { gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_DOWN, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_DOWN, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_DOUBLE_TAP, GetMostRecentGestureEventType()); } @@ -1518,15 +1447,13 @@ TEST_F(GestureProviderTest, NoDelayedTapWhenDoubleTapSupportToggled) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1U, GetReceivedGestureCount()); event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); EXPECT_EQ(2U, GetReceivedGestureCount()); @@ -1550,22 +1477,19 @@ TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPlatform) { gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); MockMotionEvent event = - ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(down_time_1, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); - event = ObtainMotionEvent( - down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event = ObtainMotionEvent(down_time_2, MotionEvent::Action::DOWN, kFakeCoordX, + kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 100); // The move should become a scroll, as doubletap drag zoom is disabled. @@ -1574,8 +1498,7 @@ TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPlatform) { EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); @@ -1585,8 +1508,7 @@ TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPlatform) { EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, - MotionEvent::ACTION_UP, - kFakeCoordX, + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END)); @@ -1602,22 +1524,19 @@ TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPage) { gesture_provider_->SetDoubleTapSupportForPageEnabled(false); MockMotionEvent event = - ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(down_time_1, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); - event = ObtainMotionEvent( - down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event = ObtainMotionEvent(down_time_2, MotionEvent::Action::DOWN, kFakeCoordX, + kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 100); // The move should become a scroll, as double tap drag zoom is disabled. @@ -1626,8 +1545,7 @@ TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPage) { EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); @@ -1635,8 +1553,7 @@ TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPage) { EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, - MotionEvent::ACTION_UP, - kFakeCoordX, + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END)); @@ -1653,19 +1570,16 @@ TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) { // Start a double-tap drag gesture. MockMotionEvent event = - ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(down_time_1, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); - event = ObtainMotionEvent( - down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event = ObtainMotionEvent(down_time_2, MotionEvent::Action::DOWN, kFakeCoordX, + kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 100); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); @@ -1680,16 +1594,14 @@ TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) { // Double tap zoom updates should continue. event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale()); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, - MotionEvent::ACTION_UP, - kFakeCoordX, + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END)); @@ -1703,19 +1615,16 @@ TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) { down_time_2 += kOneMicrosecond * 40; // Start a double-tap drag gesture. - event = ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(down_time_1, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, - MotionEvent::ACTION_UP, - kFakeCoordX, - kFakeCoordY); + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY); gesture_provider_->OnTouchEvent(event); - event = ObtainMotionEvent( - down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event = ObtainMotionEvent(down_time_2, MotionEvent::Action::DOWN, kFakeCoordX, + kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 100); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); @@ -1724,15 +1633,13 @@ TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) { // Double tap zoom updates should not be sent. // Instead, the second tap drag becomes a scroll gesture sequence. event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, - MotionEvent::ACTION_UP, - kFakeCoordX, + MotionEvent::Action::UP, kFakeCoordX, kFakeCoordY + 200); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END)); @@ -1754,7 +1661,7 @@ TEST_F(GestureProviderTest, PinchZoom) { int secondary_coord_y = kFakeCoordY + 20 * touch_slop; MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -1770,11 +1677,8 @@ TEST_F(GestureProviderTest, PinchZoom) { // Toggling double-tap support should not take effect until the next sequence. gesture_provider_->SetDoubleTapSupportForPageEnabled(true); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_DOWN, - kFakeCoordX, - kFakeCoordY, - secondary_coord_x, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, + kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -1787,12 +1691,8 @@ TEST_F(GestureProviderTest, PinchZoom) { secondary_coord_x += 5 * touch_slop; secondary_coord_y += 5 * touch_slop; - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX, - kFakeCoordY, - secondary_coord_x, - secondary_coord_y); + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, + kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -1821,12 +1721,8 @@ TEST_F(GestureProviderTest, PinchZoom) { secondary_coord_x += 2 * touch_slop; secondary_coord_y += 2 * touch_slop; - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX, - kFakeCoordY, - secondary_coord_x, - secondary_coord_y); + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, + kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); // Toggling double-tap support should not take effect until the next sequence. @@ -1844,11 +1740,8 @@ TEST_F(GestureProviderTest, PinchZoom) { secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_UP, - kFakeCoordX, - kFakeCoordY, - secondary_coord_x, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_UP, + kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); @@ -1863,7 +1756,7 @@ TEST_F(GestureProviderTest, PinchZoom) { secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); @@ -1883,49 +1776,45 @@ TEST_F(GestureProviderTest, NoPinchZoomWithFatFinger) { gesture_provider_->SetMultiTouchZoomSupportEnabled(true); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1U, GetReceivedGestureCount()); - event = ObtainMotionEvent(event_time + kOneSecond, - MotionEvent::ACTION_MOVE); + event = ObtainMotionEvent(event_time + kOneSecond, MotionEvent::Action::MOVE); event.SetTouchMajor(0.1f); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(1U, GetReceivedGestureCount()); - event = ObtainMotionEvent(event_time + kOneSecond * 2, - MotionEvent::ACTION_MOVE, - kFakeCoordX + 1.f, - kFakeCoordY); + event = + ObtainMotionEvent(event_time + kOneSecond * 2, MotionEvent::Action::MOVE, + kFakeCoordX + 1.f, kFakeCoordY); event.SetTouchMajor(1.f); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(1U, GetReceivedGestureCount()); - event = ObtainMotionEvent(event_time + kOneSecond * 3, - MotionEvent::ACTION_MOVE); + event = + ObtainMotionEvent(event_time + kOneSecond * 3, MotionEvent::Action::MOVE); event.SetTouchMajor(kFatFingerSize * 3.5f); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(1U, GetReceivedGestureCount()); - event = ObtainMotionEvent(event_time + kOneSecond * 4, - MotionEvent::ACTION_MOVE); + event = + ObtainMotionEvent(event_time + kOneSecond * 4, MotionEvent::Action::MOVE); event.SetTouchMajor(kFatFingerSize * 5.f); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(1U, GetReceivedGestureCount()); - event = ObtainMotionEvent(event_time + kOneSecond * 4, - MotionEvent::ACTION_MOVE, - kFakeCoordX + 50.f, - kFakeCoordY - 25.f); + event = + ObtainMotionEvent(event_time + kOneSecond * 4, MotionEvent::Action::MOVE, + kFakeCoordX + 50.f, kFakeCoordY - 25.f); event.SetTouchMajor(kFatFingerSize * 10.f); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); - event = ObtainMotionEvent(event_time + kOneSecond * 4, - MotionEvent::ACTION_MOVE, - kFakeCoordX + 100.f, - kFakeCoordY - 50.f); + event = + ObtainMotionEvent(event_time + kOneSecond * 4, MotionEvent::Action::MOVE, + kFakeCoordX + 100.f, kFakeCoordY - 50.f); event.SetTouchMajor(kFatFingerSize * 5.f); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); @@ -2065,7 +1954,7 @@ TEST_F(GestureProviderTest, GesturesCancelledAfterLongPressCausesLostFocus) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); const base::TimeDelta long_press_timeout = @@ -2078,7 +1967,7 @@ TEST_F(GestureProviderTest, GesturesCancelledAfterLongPressCausesLostFocus) { EXPECT_FALSE(HasDownEvent()); event = ObtainMotionEvent(event_time + long_press_timeout, - MotionEvent::ACTION_UP); + MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); } @@ -2093,7 +1982,7 @@ TEST_F(GestureProviderTest, CancelActiveTouchSequence) { EXPECT_EQ(0U, GetReceivedGestureCount()); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -2103,17 +1992,17 @@ TEST_F(GestureProviderTest, CancelActiveTouchSequence) { ASSERT_TRUE(CancelActiveTouchSequence()); EXPECT_FALSE(HasDownEvent()); - // Subsequent MotionEvent's are dropped until ACTION_DOWN. + // Subsequent MotionEvent's are dropped until Action::DOWN. event = ObtainMotionEvent(event_time + kOneMicrosecond, - MotionEvent::ACTION_MOVE); + MotionEvent::Action::MOVE); EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, - MotionEvent::ACTION_UP); + MotionEvent::Action::UP); EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent(event_time + kOneMicrosecond * 3, - MotionEvent::ACTION_DOWN); + MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); @@ -2126,25 +2015,24 @@ TEST_F(GestureProviderTest, DoubleTapDragZoomCancelledOnSecondaryPointerDown) { gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); MockMotionEvent event = - ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(down_time_1, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event = - ObtainMotionEvent(down_time_1 + kOneMicrosecond, MotionEvent::ACTION_UP); + ObtainMotionEvent(down_time_1 + kOneMicrosecond, MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); - event = ObtainMotionEvent(down_time_2, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(down_time_2, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY - 30); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); @@ -2152,28 +2040,21 @@ TEST_F(GestureProviderTest, DoubleTapDragZoomCancelledOnSecondaryPointerDown) { EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); - event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, - MotionEvent::ACTION_POINTER_DOWN, - kFakeCoordX, - kFakeCoordY - 30, - kFakeCoordX + 50, - kFakeCoordY + 50); + event = ObtainMotionEvent( + down_time_2 + kOneMicrosecond * 2, MotionEvent::Action::POINTER_DOWN, + kFakeCoordX, kFakeCoordY - 30, kFakeCoordX + 50, kFakeCoordY + 50); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_PINCH_END, GetMostRecentGestureEventType()); EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); const size_t gesture_count = GetReceivedGestureCount(); - event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, - MotionEvent::ACTION_POINTER_UP, - kFakeCoordX, - kFakeCoordY - 30, - kFakeCoordX + 50, - kFakeCoordY + 50); + event = ObtainMotionEvent( + down_time_2 + kOneMicrosecond * 3, MotionEvent::Action::POINTER_UP, + kFakeCoordX, kFakeCoordY - 30, kFakeCoordX + 50, kFakeCoordY + 50); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(gesture_count, GetReceivedGestureCount()); - event = ObtainMotionEvent(down_time_2 + kOneSecond, - MotionEvent::ACTION_UP); + event = ObtainMotionEvent(down_time_2 + kOneSecond, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(gesture_count + 1, GetReceivedGestureCount()); EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); @@ -2189,7 +2070,7 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { EXPECT_EQ(0U, GetReceivedGestureCount()); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 1, 1); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 1, 1); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(0).type()); @@ -2204,8 +2085,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { kMockTouchRadius * 2, kMockTouchRadius * 2), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 1, 1, + 2, 2); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); @@ -2216,8 +2097,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { EXPECT_EQ(2 + raw_offset_x, GetMostRecentGestureEvent().raw_x); EXPECT_EQ(2 + raw_offset_y, GetMostRecentGestureEvent().raw_y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2, 3, 3); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 1, 1, + 2, 2, 3, 3); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); @@ -2228,8 +2109,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { EXPECT_EQ(3 + raw_offset_x, GetMostRecentGestureEvent().raw_x); EXPECT_EQ(3 + raw_offset_y, GetMostRecentGestureEvent().raw_y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_UP, 1, 1, 2, 2, 3, 3); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_UP, 1, 1, + 2, 2, 3, 3); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); @@ -2240,8 +2121,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { EXPECT_EQ(1 + raw_offset_x, GetMostRecentGestureEvent().raw_x); EXPECT_EQ(1 + raw_offset_y, GetMostRecentGestureEvent().raw_y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_DOWN, 2, 2, 3, 3, 4, 4); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 2, 2, + 3, 3, 4, 4); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); @@ -2252,8 +2133,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { EXPECT_EQ(4 + raw_offset_x, GetMostRecentGestureEvent().raw_x); EXPECT_EQ(4 + raw_offset_y, GetMostRecentGestureEvent().raw_y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_UP, 2, 2, 3, 3, 4, 4); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_UP, 2, 2, + 3, 3, 4, 4); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); @@ -2264,8 +2145,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { EXPECT_EQ(2 + raw_offset_x, GetMostRecentGestureEvent().raw_x); EXPECT_EQ(2 + raw_offset_y, GetMostRecentGestureEvent().raw_y); - event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_UP, 3, 3, 4, 4); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_UP, 3, 3, + 4, 4); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); @@ -2276,8 +2157,7 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { EXPECT_EQ(3 + raw_offset_x, GetMostRecentGestureEvent().raw_x); EXPECT_EQ(3 + raw_offset_y, GetMostRecentGestureEvent().raw_y); - - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP, 4, 4); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP, 4, 4); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); @@ -2290,14 +2170,14 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { } // Verify that gesture begin and gesture end events are dispatched correctly -// when an ACTION_CANCEL is received. +// when an Action::CANCEL is received. TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { EnableBeginEndTypes(); base::TimeTicks event_time = base::TimeTicks::Now(); EXPECT_EQ(0U, GetReceivedGestureCount()); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 1, 1); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 1, 1); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(0).type()); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -2309,8 +2189,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { EXPECT_EQ(1, GetMostRecentGestureEvent().x); EXPECT_EQ(1, GetMostRecentGestureEvent().y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 1, 1, + 2, 2); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); EXPECT_EQ(3U, GetReceivedGestureCount()); @@ -2318,8 +2198,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { EXPECT_EQ(2, GetMostRecentGestureEvent().x); EXPECT_EQ(2, GetMostRecentGestureEvent().y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2, 3, 3); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 1, 1, + 2, 2, 3, 3); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); EXPECT_EQ(4U, GetReceivedGestureCount()); @@ -2327,8 +2207,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { EXPECT_EQ(3, GetMostRecentGestureEvent().x); EXPECT_EQ(3, GetMostRecentGestureEvent().y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_CANCEL, 1, 1, 2, 2, 3, 3); + event = ObtainMotionEvent(event_time, MotionEvent::Action::CANCEL, 1, 1, 2, 2, + 3, 3); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(5U, GetReceivedGestureCount()); EXPECT_EQ(3, GetReceivedGesture(4).details.touch_points()); @@ -2336,8 +2216,8 @@ TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { EXPECT_EQ(1, GetMostRecentGestureEvent().x); EXPECT_EQ(1, GetMostRecentGestureEvent().y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_CANCEL, 1, 1, 3, 3); + event = + ObtainMotionEvent(event_time, MotionEvent::Action::CANCEL, 1, 1, 3, 3); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(6U, GetReceivedGestureCount()); EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); @@ -2345,8 +2225,7 @@ TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { EXPECT_EQ(1, GetMostRecentGestureEvent().x); EXPECT_EQ(1, GetMostRecentGestureEvent().y); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_CANCEL, 3, 3); + event = ObtainMotionEvent(event_time, MotionEvent::Action::CANCEL, 3, 3); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEvent().type()); @@ -2356,7 +2235,7 @@ TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { // Test a simple two finger tap TEST_F(GestureProviderTest, TwoFingerTap) { - // The time between ACTION_POINTER_DOWN and ACTION_POINTER_UP must be <= the + // The time between Action::POINTER_DOWN and Action::POINTER_UP must be <= the // two finger tap delay. EnableTwoFingerTap(kMaxTwoFingerTapSeparation, base::TimeDelta()); const float scaled_touch_slop = GetTouchSlop(); @@ -2364,37 +2243,23 @@ TEST_F(GestureProviderTest, TwoFingerTap) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 0, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - 0, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, 0, scaled_touch_slop / 2); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_DOWN, - 0, - 0, - kMaxTwoFingerTapSeparation / 2, - 0); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 0, 0, + kMaxTwoFingerTapSeparation / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = - ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - 0, - -scaled_touch_slop / 2, - kMaxTwoFingerTapSeparation / 2 + scaled_touch_slop / 2, - 0); + event = ObtainMotionEvent( + event_time, MotionEvent::Action::MOVE, 0, -scaled_touch_slop / 2, + kMaxTwoFingerTapSeparation / 2 + scaled_touch_slop / 2, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_UP, - 0, - 0, - kMaxTwoFingerTapSeparation, - 0); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_UP, 0, 0, + kMaxTwoFingerTapSeparation, 0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); @@ -2413,28 +2278,20 @@ TEST_F(GestureProviderTest, TwoFingerTapCancelledByFingerMovement) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_DOWN, - kFakeCoordX, - kFakeCoordY, - kFakeCoordX, - kFakeCoordY); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, + kFakeCoordX, kFakeCoordY, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_MOVE, kFakeCoordX, kFakeCoordY, + event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, kFakeCoordX + 2 * scaled_touch_slop + 2, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_UP, - kFakeCoordX, - kFakeCoordY, - kFakeCoordX, - kFakeCoordY); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_UP, + kFakeCoordX, kFakeCoordY, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); @@ -2458,28 +2315,21 @@ TEST_F(GestureProviderTest, TwoFingerTapCancelledByDelay) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_DOWN, - kFakeCoordX, - kFakeCoordY, - kFakeCoordX + kMaxTwoFingerTapSeparation / 2, - kFakeCoordY); + event = ObtainMotionEvent( + event_time, MotionEvent::Action::POINTER_DOWN, kFakeCoordX, kFakeCoordY, + kFakeCoordX + kMaxTwoFingerTapSeparation / 2, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time + kOneSecond + kOneMicrosecond, - MotionEvent::ACTION_POINTER_UP, - kFakeCoordX, - kFakeCoordY, - kFakeCoordX + kMaxTwoFingerTapSeparation / 2, - kFakeCoordY); + event = ObtainMotionEvent( + event_time + kOneSecond + kOneMicrosecond, + MotionEvent::Action::POINTER_UP, kFakeCoordX, kFakeCoordY, + kFakeCoordX + kMaxTwoFingerTapSeparation / 2, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); @@ -2493,23 +2343,17 @@ TEST_F(GestureProviderTest, TwoFingerTapCancelledByDistanceBetweenPointers) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); + event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_DOWN, - kFakeCoordX, - kFakeCoordY, - kFakeCoordX + kMaxTwoFingerTapSeparation, - kFakeCoordY); + event = ObtainMotionEvent( + event_time, MotionEvent::Action::POINTER_DOWN, kFakeCoordX, kFakeCoordY, + kFakeCoordX + kMaxTwoFingerTapSeparation, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_UP, - kFakeCoordX, - kFakeCoordY, - kFakeCoordX + kMaxTwoFingerTapSeparation, - kFakeCoordY); + event = ObtainMotionEvent( + event_time, MotionEvent::Action::POINTER_UP, kFakeCoordX, kFakeCoordY, + kFakeCoordX + kMaxTwoFingerTapSeparation, kFakeCoordY); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); @@ -2535,7 +2379,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopCausesUpdate) { // First Finger Down MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -2544,7 +2388,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopCausesUpdate) { EXPECT_EQ(kFakeCoordY, GetMostRecentGestureEvent().y); // Second Finger Down - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); @@ -2557,7 +2401,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopCausesUpdate) { // Move second finger by exactly the touch slop. This shouldn't yet generate // a Pinch Begin. secondary_coord_y += touch_slop * 2; - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -2569,7 +2413,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopCausesUpdate) { // Move second finger that should *just* cross the slop threshold. secondary_coord_y += 1; - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -2600,7 +2444,7 @@ TEST_F(GestureProviderTest, PinchBelowMinSpanCausesUpdate) { // First Finger Down MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -2609,7 +2453,7 @@ TEST_F(GestureProviderTest, PinchBelowMinSpanCausesUpdate) { EXPECT_EQ(kFakeCoordY, GetMostRecentGestureEvent().y); // Second Finger Down - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); @@ -2621,7 +2465,7 @@ TEST_F(GestureProviderTest, PinchBelowMinSpanCausesUpdate) { // Move second finger enough to exceed the touch slop and start zooming. secondary_coord_y -= (touch_slop * 2 + 1); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -2635,7 +2479,7 @@ TEST_F(GestureProviderTest, PinchBelowMinSpanCausesUpdate) { // Move second finger so that the span becomes smaller than the min scaling // span. The pinch should end but we should receive an update before it does. secondary_coord_y -= touch_slop * 2; - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -2670,7 +2514,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopWithinMinScale) { // First Finger Down MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -2679,7 +2523,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopWithinMinScale) { EXPECT_EQ(kFakeCoordY, GetMostRecentGestureEvent().y); // Second Finger Down - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_DOWN, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); @@ -2692,7 +2536,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopWithinMinScale) { // Move second finger to exceed the touch slop. This shouldn't yet generate // a Pinch Begin since we're still within the minimum scaling span. secondary_coord_y += touch_slop * 2 + 1; - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -2704,7 +2548,7 @@ TEST_F(GestureProviderTest, PinchExceedingSlopWithinMinScale) { // Move second finger that should *just* cross the min scaling span threshold. secondary_coord_y = kFakeCoordY + min_scaling_span + 1; - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_MOVE, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); event.SetPrimaryPointerId(motion_event_id); event.SetRawOffset(raw_offset_x, raw_offset_y); @@ -2738,17 +2582,14 @@ TEST_F(GestureProviderTest, PinchZoomWithThreshold) { // First finger down. MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); // Second finger down. - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_POINTER_DOWN, - kFakeCoordX, - kFakeCoordY, - secondary_coord_x, + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, + kFakeCoordX, kFakeCoordY, secondary_coord_x, secondary_coord_y); gesture_provider_->OnTouchEvent(event); @@ -2758,12 +2599,8 @@ TEST_F(GestureProviderTest, PinchZoomWithThreshold) { // Move second finger. secondary_coord_x += 5 * touch_slop; secondary_coord_y += 5 * touch_slop; - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX, - kFakeCoordY, - secondary_coord_x, - secondary_coord_y); + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, + kFakeCoordY, secondary_coord_x, secondary_coord_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); @@ -2774,12 +2611,9 @@ TEST_F(GestureProviderTest, PinchZoomWithThreshold) { // Small move, shouldn't trigger pinch. gestures_.clear(); - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX, - kFakeCoordY, - secondary_coord_x + kMinPinchUpdateDistance, - secondary_coord_y); + event = ObtainMotionEvent( + event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, + secondary_coord_x + kMinPinchUpdateDistance, secondary_coord_y); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); @@ -2789,9 +2623,7 @@ TEST_F(GestureProviderTest, PinchZoomWithThreshold) { // need to overshoot kMinPinchUpdateDistance by a fair bit, as the span // calculation factors in touch radius. const float kOvershootMinPinchUpdateDistance = 3; - event = ObtainMotionEvent(event_time, - MotionEvent::ACTION_MOVE, - kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, kFakeCoordX, kFakeCoordY, secondary_coord_x + kMinPinchUpdateDistance + kOvershootMinPinchUpdateDistance, @@ -2810,7 +2642,7 @@ TEST_F(GestureProviderTest, MinGestureBoundsLength) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -2820,7 +2652,7 @@ TEST_F(GestureProviderTest, MinGestureBoundsLength) { GetMostRecentGestureEvent().details.bounding_box_f().height()); event = - ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(kMinGestureBoundsLength, @@ -2836,7 +2668,7 @@ TEST_F(GestureProviderTest, MaxGestureBoundsLength) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); @@ -2846,7 +2678,7 @@ TEST_F(GestureProviderTest, MaxGestureBoundsLength) { GetMostRecentGestureEvent().details.bounding_box_f().height()); event = - ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(kMaxGestureBoundsLength, @@ -2858,19 +2690,19 @@ TEST_F(GestureProviderTest, MaxGestureBoundsLength) { TEST_F(GestureProviderTest, ZeroRadiusBoundingBox) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 10, 20); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 10, 20); event.SetTouchMajor(0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(gfx::RectF(10, 20, 0, 0), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_POINTER_DOWN, 10, 20, 110, 120); + event = ObtainMotionEvent(event_time, MotionEvent::Action::POINTER_DOWN, 10, + 20, 110, 120); event.SetTouchMajor(0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent( - event_time, MotionEvent::ACTION_MOVE, 10, 20, 110, 150); + event = ObtainMotionEvent(event_time, MotionEvent::Action::MOVE, 10, 20, 110, + 150); event.SetTouchMajor(0); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -2889,33 +2721,33 @@ TEST_F(GestureProviderTest, NoMinOrMaxGestureBoundsLengthWithStylusOrMouse) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetTouchMajor(0); - event.SetToolType(0, MotionEvent::TOOL_TYPE_MOUSE); + event.SetToolType(0, MotionEvent::ToolType::MOUSE); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); - EXPECT_EQ(MotionEvent::TOOL_TYPE_MOUSE, + EXPECT_EQ(MotionEvent::ToolType::MOUSE, GetMostRecentGestureEvent().primary_tool_type); EXPECT_EQ(0.f, GetMostRecentGestureEvent().details.bounding_box_f().width()); EXPECT_EQ(0.f, GetMostRecentGestureEvent().details.bounding_box_f().height()); event = - ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::UP); event.SetTouchMajor(1); - event.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS); + event.SetToolType(0, MotionEvent::ToolType::STYLUS); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); - EXPECT_EQ(MotionEvent::TOOL_TYPE_STYLUS, + EXPECT_EQ(MotionEvent::ToolType::STYLUS, GetMostRecentGestureEvent().primary_tool_type); EXPECT_EQ(0, GetMostRecentGestureEvent().details.bounding_box_f().width()); EXPECT_EQ(0, GetMostRecentGestureEvent().details.bounding_box_f().height()); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); event.SetTouchMajor(2.f * kMaxGestureBoundsLength); - event.SetToolType(0, MotionEvent::TOOL_TYPE_MOUSE); + event.SetToolType(0, MotionEvent::ToolType::MOUSE); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_MOUSE, + EXPECT_EQ(MotionEvent::ToolType::MOUSE, GetMostRecentGestureEvent().primary_tool_type); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); EXPECT_EQ(2.f * kMaxGestureBoundsLength, @@ -2924,12 +2756,12 @@ TEST_F(GestureProviderTest, NoMinOrMaxGestureBoundsLengthWithStylusOrMouse) { GetMostRecentGestureEvent().details.bounding_box_f().height()); event = - ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::UP); event.SetTouchMajor(2.f * kMaxGestureBoundsLength); - event.SetToolType(0, MotionEvent::TOOL_TYPE_ERASER); + event.SetToolType(0, MotionEvent::ToolType::ERASER); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); - EXPECT_EQ(MotionEvent::TOOL_TYPE_ERASER, + EXPECT_EQ(MotionEvent::ToolType::ERASER, GetMostRecentGestureEvent().primary_tool_type); EXPECT_EQ(2.f * kMaxGestureBoundsLength, GetMostRecentGestureEvent().details.bounding_box_f().width()); @@ -2946,7 +2778,7 @@ TEST_F(GestureProviderTest, BoundingBoxForShowPressAndTapGesture) { SetShowPressAndLongPressTimeout(showpress_timeout, longpress_timeout); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 10, 10); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, 10, 10); event.SetTouchMajor(10); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); @@ -2955,12 +2787,12 @@ TEST_F(GestureProviderTest, BoundingBoxForShowPressAndTapGesture) { EXPECT_EQ(gfx::RectF(5, 5, 10, 10), GetMostRecentGestureEvent().details.bounding_box_f()); - event = ObtainMotionEvent( - event_time + kOneMicrosecond, MotionEvent::ACTION_MOVE, 11, 9); + event = ObtainMotionEvent(event_time + kOneMicrosecond, + MotionEvent::Action::MOVE, 11, 9); event.SetTouchMajor(20); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent( - event_time + kOneMicrosecond, MotionEvent::ACTION_MOVE, 8, 11); + event = ObtainMotionEvent(event_time + kOneMicrosecond, + MotionEvent::Action::MOVE, 8, 11); event.SetTouchMajor(10); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); RunTasksAndWait(showpress_timeout + kOneMicrosecond); @@ -2969,7 +2801,7 @@ TEST_F(GestureProviderTest, BoundingBoxForShowPressAndTapGesture) { GetMostRecentGestureEvent().details.bounding_box_f()); event = - ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); + ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::Action::UP); event.SetTouchMajor(30); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); @@ -2988,9 +2820,9 @@ TEST_F(GestureProviderTest, SingleTapRepeat) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); @@ -2998,9 +2830,9 @@ TEST_F(GestureProviderTest, SingleTapRepeat) { // A second tap after the double-tap timeout window will not increment // the tap count. event_time += GetDoubleTapTimeout() + kOneMicrosecond; - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); @@ -3008,9 +2840,9 @@ TEST_F(GestureProviderTest, SingleTapRepeat) { // A secondary tap within the tap repeat period should increment // the tap count. event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(2, GetMostRecentGestureEvent().details.tap_count()); @@ -3018,19 +2850,19 @@ TEST_F(GestureProviderTest, SingleTapRepeat) { // A secondary tap within the tap repeat location threshold should increment // the tap count. event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY + GetTouchSlop() / 2); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(3, GetMostRecentGestureEvent().details.tap_count()); // The tap count should reset after hitting the repeat length. event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); @@ -3038,18 +2870,18 @@ TEST_F(GestureProviderTest, SingleTapRepeat) { // If double-tap is enabled, the tap repeat count should always be 1. gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); RunTasksAndWait(GetDoubleTapTimeout()); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); RunTasksAndWait(GetDoubleTapTimeout()); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); @@ -3064,9 +2896,9 @@ TEST_F(GestureProviderTest, SingleTapRepeatLengthOfOne) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = - ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); gesture_provider_->OnTouchEvent(event); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); @@ -3074,18 +2906,18 @@ TEST_F(GestureProviderTest, SingleTapRepeatLengthOfOne) { // Repeated taps should still produce a tap count of 1 if the // tap repeat length is 1. event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); event_time += GetValidDoubleTapDelay(); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, + event = ObtainMotionEvent(event_time, MotionEvent::Action::DOWN, kFakeCoordX, kFakeCoordY + GetTouchSlop() / 2); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); + event = ObtainMotionEvent(event_time, MotionEvent::Action::UP); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); diff --git a/chromium/ui/events/gesture_detection/gesture_touch_uma_histogram.cc b/chromium/ui/events/gesture_detection/gesture_touch_uma_histogram.cc index db52a8ae49b..7afcbf49bd3 100644 --- a/chromium/ui/events/gesture_detection/gesture_touch_uma_histogram.cc +++ b/chromium/ui/events/gesture_detection/gesture_touch_uma_histogram.cc @@ -22,19 +22,19 @@ void GestureTouchUMAHistogram::RecordGestureEvent( } void GestureTouchUMAHistogram::RecordTouchEvent(const MotionEvent& event) { - if (event.GetAction() == MotionEvent::ACTION_DOWN) { + if (event.GetAction() == MotionEvent::Action::DOWN) { start_time_ = event.GetEventTime(); start_touch_position_ = gfx::Point(event.GetX(), event.GetY()); is_single_finger_ = true; max_distance_from_start_squared_ = 0; - } else if (event.GetAction() == MotionEvent::ACTION_MOVE && + } else if (event.GetAction() == MotionEvent::Action::MOVE && is_single_finger_) { float cur_dist = (start_touch_position_ - gfx::Point(event.GetX(), event.GetY())).LengthSquared(); if (cur_dist > max_distance_from_start_squared_) max_distance_from_start_squared_ = cur_dist; } else { - if (event.GetAction() == MotionEvent::ACTION_UP && is_single_finger_) { + if (event.GetAction() == MotionEvent::Action::UP && is_single_finger_) { UMA_HISTOGRAM_CUSTOM_COUNTS( "Event.TouchMaxDistance", static_cast<int>(sqrt(max_distance_from_start_squared_)), diff --git a/chromium/ui/events/gesture_detection/motion_event.cc b/chromium/ui/events/gesture_detection/motion_event.cc index 07ee9e125f2..a5c083b0782 100644 --- a/chromium/ui/events/gesture_detection/motion_event.cc +++ b/chromium/ui/events/gesture_detection/motion_event.cc @@ -59,4 +59,13 @@ std::unique_ptr<MotionEvent> MotionEvent::Cancel() const { return MotionEventGeneric::CancelEvent(*this); } +std::ostream& operator<<(std::ostream& stream, + const MotionEvent::Action action) { + return stream << static_cast<int>(action); +} +std::ostream& operator<<(std::ostream& stream, + const MotionEvent::ToolType tool_type) { + return stream << static_cast<int>(tool_type); +} + } // namespace ui diff --git a/chromium/ui/events/gesture_detection/motion_event.h b/chromium/ui/events/gesture_detection/motion_event.h index 05a3c55ee0f..383b23aa6eb 100644 --- a/chromium/ui/events/gesture_detection/motion_event.h +++ b/chromium/ui/events/gesture_detection/motion_event.h @@ -19,30 +19,23 @@ namespace ui { // subset of Android's MotionEvent API used in gesture detection. class GESTURE_DETECTION_EXPORT MotionEvent { public: - enum Action { - ACTION_NONE, - ACTION_DOWN, - ACTION_UP, - ACTION_MOVE, - ACTION_CANCEL, - ACTION_POINTER_DOWN, - ACTION_POINTER_UP, - ACTION_HOVER_ENTER, - ACTION_HOVER_EXIT, - ACTION_HOVER_MOVE, - ACTION_BUTTON_PRESS, - ACTION_BUTTON_RELEASE, - ACTION_LAST = ACTION_BUTTON_RELEASE + enum class Action { + NONE, + DOWN, + UP, + MOVE, + CANCEL, + POINTER_DOWN, + POINTER_UP, + HOVER_ENTER, + HOVER_EXIT, + HOVER_MOVE, + BUTTON_PRESS, + BUTTON_RELEASE, + LAST = BUTTON_RELEASE }; - enum ToolType { - TOOL_TYPE_UNKNOWN, - TOOL_TYPE_FINGER, - TOOL_TYPE_STYLUS, - TOOL_TYPE_MOUSE, - TOOL_TYPE_ERASER, - TOOL_TYPE_LAST = TOOL_TYPE_ERASER - }; + enum class ToolType { UNKNOWN, FINGER, STYLUS, MOUSE, ERASER, LAST = ERASER }; enum ButtonType { BUTTON_PRIMARY = 1 << 0, @@ -63,8 +56,8 @@ class GESTURE_DETECTION_EXPORT MotionEvent { // An unique identifier this motion event. virtual uint32_t GetUniqueEventId() const = 0; virtual Action GetAction() const = 0; - // Only valid if |GetAction()| returns ACTION_POINTER_UP or - // ACTION_POINTER_DOWN. + // Only valid if |GetAction()| returns Action::POINTER_UP or + // Action::POINTER_DOWN. virtual int GetActionIndex() const = 0; virtual size_t GetPointerCount() const = 0; virtual int GetPointerId(size_t pointer_index) const = 0; @@ -139,6 +132,13 @@ class GESTURE_DETECTION_EXPORT MotionEvent { std::unique_ptr<MotionEvent> Cancel() const; }; +GESTURE_DETECTION_EXPORT std::ostream& operator<<( + std::ostream& stream, + const MotionEvent::Action action); +GESTURE_DETECTION_EXPORT std::ostream& operator<<( + std::ostream& stream, + const MotionEvent::ToolType tool_type); + } // namespace ui #endif // UI_EVENTS_GESTURE_DETECTION_MOTION_EVENT_H_ diff --git a/chromium/ui/events/gesture_detection/motion_event_buffer.cc b/chromium/ui/events/gesture_detection/motion_event_buffer.cc index b2ce72f9ffc..596ca39403d 100644 --- a/chromium/ui/events/gesture_detection/motion_event_buffer.cc +++ b/chromium/ui/events/gesture_detection/motion_event_buffer.cc @@ -36,8 +36,8 @@ float Lerp(float a, float b, float alpha) { } bool CanAddSample(const MotionEvent& event0, const MotionEvent& event1) { - DCHECK_EQ(event0.GetAction(), MotionEvent::ACTION_MOVE); - if (event1.GetAction() != MotionEvent::ACTION_MOVE) + DCHECK_EQ(event0.GetAction(), MotionEvent::Action::MOVE); + if (event1.GetAction() != MotionEvent::Action::MOVE) return false; const size_t pointer_count = event0.GetPointerCount(); @@ -57,8 +57,8 @@ bool CanAddSample(const MotionEvent& event0, const MotionEvent& event1) { } bool ShouldResampleTool(MotionEvent::ToolType tool) { - return tool == MotionEvent::TOOL_TYPE_UNKNOWN || - tool == MotionEvent::TOOL_TYPE_FINGER; + return tool == MotionEvent::ToolType::UNKNOWN || + tool == MotionEvent::ToolType::FINGER; } // Splits a chunk of events from the front of the provided |batch| and returns @@ -109,7 +109,7 @@ std::unique_ptr<MotionEventGeneric> ResampleMotionEvent( const MotionEvent& event0, const MotionEvent& event1, base::TimeTicks resample_time) { - DCHECK_EQ(MotionEvent::ACTION_MOVE, event0.GetAction()); + DCHECK_EQ(MotionEvent::Action::MOVE, event0.GetAction()); DCHECK_EQ(event0.GetPointerCount(), event1.GetPointerCount()); const base::TimeTicks time0 = event0.GetEventTime(); @@ -130,8 +130,8 @@ std::unique_ptr<MotionEventGeneric> ResampleMotionEvent( event0, event1, event0_i, static_cast<size_t>(event1_i), alpha); if (event0_i == 0) { - event.reset(new MotionEventGeneric( - MotionEvent::ACTION_MOVE, resample_time, pointer)); + event.reset(new MotionEventGeneric(MotionEvent::Action::MOVE, + resample_time, pointer)); } else { event->PushPointer(pointer); } @@ -233,7 +233,7 @@ MotionEventBuffer::~MotionEventBuffer() { void MotionEventBuffer::OnMotionEvent(const MotionEvent& event) { DCHECK_EQ(0U, event.GetHistorySize()); - if (event.GetAction() != MotionEvent::ACTION_MOVE) { + if (event.GetAction() != MotionEvent::Action::MOVE) { last_extrapolated_event_time_ = base::TimeTicks(); if (!buffered_events_.empty()) FlushWithoutResampling(std::move(buffered_events_)); diff --git a/chromium/ui/events/gesture_detection/motion_event_buffer_unittest.cc b/chromium/ui/events/gesture_detection/motion_event_buffer_unittest.cc index b8090b2a82c..a6f78436309 100644 --- a/chromium/ui/events/gesture_detection/motion_event_buffer_unittest.cc +++ b/chromium/ui/events/gesture_detection/motion_event_buffer_unittest.cc @@ -83,8 +83,8 @@ class MotionEventBufferTest : public testing::Test, const MotionEvent& b, bool ignore_history) { EXPECT_EQ(a.GetAction(), b.GetAction()); - if (a.GetAction() == MotionEvent::ACTION_POINTER_DOWN || - a.GetAction() == MotionEvent::ACTION_POINTER_UP) { + if (a.GetAction() == MotionEvent::Action::POINTER_DOWN || + a.GetAction() == MotionEvent::Action::POINTER_UP) { EXPECT_EQ(a.GetActionIndex(), b.GetActionIndex()); } EXPECT_EQ(a.GetButtonState(), b.GetButtonState()); @@ -185,8 +185,8 @@ class MotionEventBufferTest : public testing::Test, base::TimeDelta last_dt; while (event_time < max_event_time) { position += gfx::ScaleVector2d(velocity, event_time_delta.InSecondsF()); - MockMotionEvent move( - MotionEvent::ACTION_MOVE, event_time, position.x(), position.y()); + MockMotionEvent move(MotionEvent::Action::MOVE, event_time, position.x(), + position.y()); buffer.OnMotionEvent(move); event_time += event_time_delta; @@ -258,7 +258,7 @@ TEST_F(MotionEventBufferTest, BufferWithOneMoveNotResampled) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move(MotionEvent::ACTION_MOVE, event_time, 4.f, 4.f); + MockMotionEvent move(MotionEvent::Action::MOVE, event_time, 4.f, 4.f); buffer.OnMotionEvent(move); EXPECT_TRUE(GetAndResetNeedsFlush()); EXPECT_FALSE(GetLastEvent()); @@ -274,7 +274,7 @@ TEST_F(MotionEventBufferTest, BufferFlushedOnNonActionMove) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 1.f, 1.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 1.f, 1.f); buffer.OnMotionEvent(move0); EXPECT_TRUE(GetAndResetNeedsFlush()); EXPECT_FALSE(GetLastEvent()); @@ -282,19 +282,19 @@ TEST_F(MotionEventBufferTest, BufferFlushedOnNonActionMove) { event_time += base::TimeDelta::FromMilliseconds(5); // The second move should remain buffered. - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 2.f, 2.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 2.f, 2.f); buffer.OnMotionEvent(move1); EXPECT_FALSE(GetAndResetNeedsFlush()); EXPECT_FALSE(GetLastEvent()); // The third move should remain buffered. - MockMotionEvent move2(MotionEvent::ACTION_MOVE, event_time, 3.f, 3.f); + MockMotionEvent move2(MotionEvent::Action::MOVE, event_time, 3.f, 3.f); buffer.OnMotionEvent(move2); EXPECT_FALSE(GetAndResetNeedsFlush()); EXPECT_FALSE(GetLastEvent()); // The up should flush the buffer. - MockMotionEvent up(MotionEvent::ACTION_UP, event_time, 4.f, 4.f); + MockMotionEvent up(MotionEvent::Action::UP, event_time, 4.f, 4.f); buffer.OnMotionEvent(up); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -314,7 +314,7 @@ TEST_F(MotionEventBufferTest, BufferFlushedOnIncompatibleActionMove) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 1.f, 1.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 1.f, 1.f); buffer.OnMotionEvent(move0); EXPECT_TRUE(GetAndResetNeedsFlush()); EXPECT_FALSE(GetLastEvent()); @@ -322,8 +322,8 @@ TEST_F(MotionEventBufferTest, BufferFlushedOnIncompatibleActionMove) { event_time += base::TimeDelta::FromMilliseconds(5); // The second move has a different pointer count, flushing the first. - MockMotionEvent move1( - MotionEvent::ACTION_MOVE, event_time, 2.f, 2.f, 3.f, 3.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 2.f, 2.f, 3.f, + 3.f); buffer.OnMotionEvent(move1); EXPECT_FALSE(GetAndResetNeedsFlush()); ASSERT_TRUE(GetLastEvent()); @@ -333,7 +333,7 @@ TEST_F(MotionEventBufferTest, BufferFlushedOnIncompatibleActionMove) { // The third move has differing tool types, flushing the second. MockMotionEvent move2(move1); - move2.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS); + move2.SetToolType(0, MotionEvent::ToolType::STYLUS); buffer.OnMotionEvent(move2); EXPECT_FALSE(GetAndResetNeedsFlush()); EXPECT_EVENT_EQ(move1, *GetLastEvent()); @@ -355,13 +355,13 @@ TEST_F(MotionEventBufferTest, BufferFlushedOnIncompatibleActionMove) { pointer0.id = 1; PointerProperties pointer1(10.f, 10.f, 2.f); pointer1.id = 2; - MotionEventGeneric move3(MotionEvent::ACTION_MOVE, event_time, pointer0); + MotionEventGeneric move3(MotionEvent::Action::MOVE, event_time, pointer0); move3.PushPointer(pointer1); buffer.OnMotionEvent(move3); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); - MotionEventGeneric move4(MotionEvent::ACTION_MOVE, event_time, pointer0); + MotionEventGeneric move4(MotionEvent::Action::MOVE, event_time, pointer0); pointer1.id = 7; move4.PushPointer(pointer1); buffer.OnMotionEvent(move2); @@ -374,7 +374,7 @@ TEST_F(MotionEventBufferTest, OnlyActionMoveBuffered) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent down(MotionEvent::ACTION_DOWN, event_time, 1.f, 1.f); + MockMotionEvent down(MotionEvent::Action::DOWN, event_time, 1.f, 1.f); buffer.OnMotionEvent(down); EXPECT_FALSE(GetAndResetNeedsFlush()); ASSERT_TRUE(GetLastEvent()); @@ -382,7 +382,7 @@ TEST_F(MotionEventBufferTest, OnlyActionMoveBuffered) { GetAndResetForwardedEvents(); - MockMotionEvent up(MotionEvent::ACTION_UP, event_time, 2.f, 2.f); + MockMotionEvent up(MotionEvent::Action::UP, event_time, 2.f, 2.f); buffer.OnMotionEvent(up); EXPECT_FALSE(GetAndResetNeedsFlush()); ASSERT_TRUE(GetLastEvent()); @@ -390,7 +390,7 @@ TEST_F(MotionEventBufferTest, OnlyActionMoveBuffered) { GetAndResetForwardedEvents(); - MockMotionEvent cancel(MotionEvent::ACTION_CANCEL, event_time, 3.f, 3.f); + MockMotionEvent cancel(MotionEvent::Action::CANCEL, event_time, 3.f, 3.f); buffer.OnMotionEvent(cancel); EXPECT_FALSE(GetAndResetNeedsFlush()); ASSERT_TRUE(GetLastEvent()); @@ -398,7 +398,7 @@ TEST_F(MotionEventBufferTest, OnlyActionMoveBuffered) { GetAndResetForwardedEvents(); - MockMotionEvent move(MotionEvent::ACTION_MOVE, event_time, 4.f, 4.f); + MockMotionEvent move(MotionEvent::Action::MOVE, event_time, 4.f, 4.f); buffer.OnMotionEvent(move); EXPECT_TRUE(GetAndResetNeedsFlush()); EXPECT_FALSE(GetLastEvent()); @@ -419,7 +419,7 @@ TEST_F(MotionEventBufferTest, OutOfOrderPointersBuffered) { PointerProperties p1(2.f, 1.f, 0.5f); p1.id = 2; - MotionEventGeneric move0(MotionEvent::ACTION_MOVE, event_time, p0); + MotionEventGeneric move0(MotionEvent::Action::MOVE, event_time, p0); move0.PushPointer(p1); buffer.OnMotionEvent(move0); EXPECT_TRUE(GetAndResetNeedsFlush()); @@ -429,7 +429,7 @@ TEST_F(MotionEventBufferTest, OutOfOrderPointersBuffered) { // The second move should remain buffered even if the logical pointers are // in a different order. - MotionEventGeneric move1(MotionEvent::ACTION_MOVE, event_time, p1); + MotionEventGeneric move1(MotionEvent::Action::MOVE, event_time, p1); move1.PushPointer(p0); buffer.OnMotionEvent(move1); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -452,14 +452,14 @@ TEST_F(MotionEventBufferTest, FlushedEventsNeverLaterThanFlushTime) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 1.f, 1.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 1.f, 1.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += LargeDelta(); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 2.f, 2.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 2.f, 2.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -509,13 +509,13 @@ TEST_F(MotionEventBufferTest, NoResamplingWhenDisabled) { MotionEventBuffer buffer(this, resampling_enabled); // Queue two events. - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 5.f, 10.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 5.f, 10.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); event_time += base::TimeDelta::FromMilliseconds(5); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 15.f, 30.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 15.f, 30.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -543,14 +543,14 @@ TEST_F(MotionEventBufferTest, NoResamplingWhenDisabled) { GetAndResetForwardedEvents(); // Now queue two more events. - move0 = MockMotionEvent(MotionEvent::ACTION_MOVE, event_time, 5.f, 10.f); + move0 = MockMotionEvent(MotionEvent::Action::MOVE, event_time, 5.f, 10.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += base::TimeDelta::FromMilliseconds(5); - move1 = MockMotionEvent(MotionEvent::ACTION_MOVE, event_time, 10.f, 20.f); + move1 = MockMotionEvent(MotionEvent::Action::MOVE, event_time, 10.f, 20.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -575,14 +575,14 @@ TEST_F(MotionEventBufferTest, NoResamplingWithOutOfOrderActionMove) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 5.f, 10.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 5.f, 10.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += base::TimeDelta::FromMilliseconds(10); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 10.f, 20.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 10.f, 20.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -609,14 +609,14 @@ TEST_F(MotionEventBufferTest, NoResamplingWithOutOfOrderActionMove) { // Try enqueuing an event *after* the second event but *before* the // extrapolated event. It should be dropped. event_time = move1.GetEventTime() + base::TimeDelta::FromMilliseconds(1); - MockMotionEvent move2(MotionEvent::ACTION_MOVE, event_time, 15.f, 25.f); + MockMotionEvent move2(MotionEvent::Action::MOVE, event_time, 15.f, 25.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); // Finally queue an event *after* the extrapolated event. event_time = expected_time + base::TimeDelta::FromMilliseconds(1); - MockMotionEvent move3(MotionEvent::ACTION_MOVE, event_time, 15.f, 25.f); + MockMotionEvent move3(MotionEvent::Action::MOVE, event_time, 15.f, 25.f); buffer.OnMotionEvent(move3); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); @@ -637,14 +637,14 @@ TEST_F(MotionEventBufferTest, NoResamplingWithSmallTimeDeltaBetweenMoves) { MotionEventBuffer buffer(this, true); // The first move should be buffered. - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 1.f, 1.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 1.f, 1.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += SmallDelta(); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 2.f, 2.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 2.f, 2.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -668,14 +668,14 @@ TEST_F(MotionEventBufferTest, NoResamplingWithMismatchBetweenMoves) { MotionEventBuffer buffer(this, true); // The first move should be buffered. - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 1.f, 1.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 1.f, 1.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += SmallDelta(); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 2.f, 2.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 2.f, 2.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -698,14 +698,14 @@ TEST_F(MotionEventBufferTest, Interpolation) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 5.f, 10.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 5.f, 10.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += base::TimeDelta::FromMilliseconds(5); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 15.f, 30.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 15.f, 30.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -723,8 +723,7 @@ TEST_F(MotionEventBufferTest, Interpolation) { float alpha = (interpolated_time - move0.GetEventTime()).InMillisecondsF() / (move1.GetEventTime() - move0.GetEventTime()).InMillisecondsF(); MockMotionEvent interpolated_event( - MotionEvent::ACTION_MOVE, - interpolated_time, + MotionEvent::Action::MOVE, interpolated_time, move0.GetX(0) + (move1.GetX(0) - move0.GetX(0)) * alpha, move0.GetY(0) + (move1.GetY(0) - move0.GetY(0)) * alpha); std::vector<std::unique_ptr<MotionEvent>> events = @@ -745,14 +744,14 @@ TEST_F(MotionEventBufferTest, Extrapolation) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 5.f, 10.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 5.f, 10.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += base::TimeDelta::FromMilliseconds(5); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 10.f, 20.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 10.f, 20.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -776,8 +775,7 @@ TEST_F(MotionEventBufferTest, Extrapolation) { (expected_time - move0.GetEventTime()).InMillisecondsF() / (move1.GetEventTime() - move0.GetEventTime()).InMillisecondsF(); MockMotionEvent extrapolated_event( - MotionEvent::ACTION_MOVE, - expected_time, + MotionEvent::Action::MOVE, expected_time, move0.GetX(0) + (move1.GetX(0) - move0.GetX(0)) * expected_alpha, move0.GetY(0) + (move1.GetY(0) - move0.GetY(0)) * expected_alpha); std::vector<std::unique_ptr<MotionEvent>> events = @@ -793,14 +791,14 @@ TEST_F(MotionEventBufferTest, ExtrapolationHorizonLimited) { base::TimeTicks event_time = base::TimeTicks::Now(); MotionEventBuffer buffer(this, true); - MockMotionEvent move0(MotionEvent::ACTION_MOVE, event_time, 5.f, 10.f); + MockMotionEvent move0(MotionEvent::Action::MOVE, event_time, 5.f, 10.f); buffer.OnMotionEvent(move0); ASSERT_FALSE(GetLastEvent()); EXPECT_TRUE(GetAndResetNeedsFlush()); // The second move should remain buffered. event_time += base::TimeDelta::FromMilliseconds(24); - MockMotionEvent move1(MotionEvent::ACTION_MOVE, event_time, 10.f, 20.f); + MockMotionEvent move1(MotionEvent::Action::MOVE, event_time, 10.f, 20.f); buffer.OnMotionEvent(move1); ASSERT_FALSE(GetLastEvent()); EXPECT_FALSE(GetAndResetNeedsFlush()); @@ -822,8 +820,7 @@ TEST_F(MotionEventBufferTest, ExtrapolationHorizonLimited) { (expected_time - move0.GetEventTime()).InMillisecondsF() / (move1.GetEventTime() - move0.GetEventTime()).InMillisecondsF(); MockMotionEvent extrapolated_event( - MotionEvent::ACTION_MOVE, - expected_time, + MotionEvent::Action::MOVE, expected_time, move0.GetX(0) + (move1.GetX(0) - move0.GetX(0)) * expected_alpha, move0.GetY(0) + (move1.GetY(0) - move0.GetY(0)) * expected_alpha); std::vector<std::unique_ptr<MotionEvent>> events = diff --git a/chromium/ui/events/gesture_detection/motion_event_generic.cc b/chromium/ui/events/gesture_detection/motion_event_generic.cc index 07afcd6c9b9..293ea0b689a 100644 --- a/chromium/ui/events/gesture_detection/motion_event_generic.cc +++ b/chromium/ui/events/gesture_detection/motion_event_generic.cc @@ -20,7 +20,7 @@ PointerProperties::PointerProperties() PointerProperties::PointerProperties(float x, float y, float touch_major) : id(0), - tool_type(MotionEvent::TOOL_TYPE_UNKNOWN), + tool_type(MotionEvent::ToolType::UNKNOWN), x(x), y(y), raw_x(x), @@ -119,7 +119,7 @@ MotionEvent::Action MotionEventGeneric::GetAction() const { } int MotionEventGeneric::GetActionIndex() const { - DCHECK(action_ == ACTION_POINTER_DOWN || action_ == ACTION_POINTER_UP); + DCHECK(action_ == Action::POINTER_DOWN || action_ == Action::POINTER_UP); DCHECK_GE(action_index_, 0); DCHECK_LT(action_index_, static_cast<int>(pointers_->size())); return action_index_; @@ -244,7 +244,7 @@ std::unique_ptr<MotionEventGeneric> MotionEventGeneric::CancelEvent( bool with_history = false; std::unique_ptr<MotionEventGeneric> cancel_event( new MotionEventGeneric(event, with_history)); - cancel_event->set_action(ACTION_CANCEL); + cancel_event->set_action(Action::CANCEL); cancel_event->set_unique_event_id(ui::GetNextTouchEventId()); return cancel_event; } @@ -263,7 +263,7 @@ void MotionEventGeneric::RemovePointerAt(size_t index) { void MotionEventGeneric::PushHistoricalEvent( std::unique_ptr<MotionEvent> event) { DCHECK(event); - DCHECK_EQ(event->GetAction(), ACTION_MOVE); + DCHECK_EQ(event->GetAction(), Action::MOVE); DCHECK_EQ(event->GetPointerCount(), GetPointerCount()); DCHECK_EQ(event->GetAction(), GetAction()); DCHECK_LE(event->GetEventTime(), GetEventTime()); @@ -271,11 +271,10 @@ void MotionEventGeneric::PushHistoricalEvent( } MotionEventGeneric::MotionEventGeneric() - : action_(ACTION_NONE), + : action_(Action::NONE), unique_event_id_(ui::GetNextTouchEventId()), action_index_(-1), - button_state_(0) { -} + button_state_(0) {} MotionEventGeneric::MotionEventGeneric(const MotionEvent& event, bool with_history) @@ -283,7 +282,7 @@ MotionEventGeneric::MotionEventGeneric(const MotionEvent& event, event_time_(event.GetEventTime()), unique_event_id_(event.GetUniqueEventId()), action_index_( - (action_ == ACTION_POINTER_UP || action_ == ACTION_POINTER_DOWN) + (action_ == Action::POINTER_UP || action_ == Action::POINTER_DOWN) ? event.GetActionIndex() : 0), button_state_(event.GetButtonState()), @@ -299,7 +298,7 @@ MotionEventGeneric::MotionEventGeneric(const MotionEvent& event, for (size_t h = 0; h < history_size; ++h) { std::unique_ptr<MotionEventGeneric> historical_event( new MotionEventGeneric()); - historical_event->set_action(ACTION_MOVE); + historical_event->set_action(Action::MOVE); historical_event->set_event_time(event.GetHistoricalEventTime(h)); for (size_t i = 0; i < pointer_count; ++i) { historical_event->PushPointer( diff --git a/chromium/ui/events/gesture_detection/motion_event_generic_unittest.cc b/chromium/ui/events/gesture_detection/motion_event_generic_unittest.cc index 0f5b2c5ee8e..c1eb7768249 100644 --- a/chromium/ui/events/gesture_detection/motion_event_generic_unittest.cc +++ b/chromium/ui/events/gesture_detection/motion_event_generic_unittest.cc @@ -15,8 +15,8 @@ namespace ui { TEST(MotionEventGenericTest, Basic) { base::TimeTicks event_time = base::TimeTicks::Now(); - MotionEventGeneric event( - MotionEvent::ACTION_DOWN, event_time, PointerProperties()); + MotionEventGeneric event(MotionEvent::Action::DOWN, event_time, + PointerProperties()); EXPECT_EQ(1U, event.GetPointerCount()); EXPECT_EQ(0U, event.GetHistorySize()); EXPECT_EQ(event_time, event.GetEventTime()); @@ -38,8 +38,8 @@ TEST(MotionEventGenericTest, Basic) { event.pointer(0).id = 3; EXPECT_EQ(3, event.GetPointerId(0)); - event.set_action(MotionEvent::ACTION_POINTER_DOWN); - EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction()); + event.set_action(MotionEvent::Action::POINTER_DOWN); + EXPECT_EQ(MotionEvent::Action::POINTER_DOWN, event.GetAction()); event_time += base::TimeDelta::FromMilliseconds(5); event.set_event_time(event_time); @@ -54,16 +54,15 @@ TEST(MotionEventGenericTest, Basic) { event.set_action_index(1); EXPECT_EQ(1, event.GetActionIndex()); - event.set_action(MotionEvent::ACTION_MOVE); - EXPECT_EQ(MotionEvent::ACTION_MOVE, event.GetAction()); + event.set_action(MotionEvent::Action::MOVE); + EXPECT_EQ(MotionEvent::Action::MOVE, event.GetAction()); PointerProperties historical_pointer0(1.2f, 2.4f, 1.f); PointerProperties historical_pointer1(2.4f, 4.8f, 2.f); PointerProperties historical_pointer2(4.8f, 9.6f, 3.f); MotionEventGeneric historical_event( - MotionEvent::ACTION_MOVE, - event_time - base::TimeDelta::FromMilliseconds(5), - historical_pointer0); + MotionEvent::Action::MOVE, + event_time - base::TimeDelta::FromMilliseconds(5), historical_pointer0); historical_event.PushPointer(historical_pointer1); historical_event.PushPointer(historical_pointer2); @@ -83,8 +82,7 @@ TEST(MotionEventGenericTest, Basic) { } TEST(MotionEventGenericTest, Clone) { - MotionEventGeneric event(MotionEvent::ACTION_DOWN, - base::TimeTicks::Now(), + MotionEventGeneric event(MotionEvent::Action::DOWN, base::TimeTicks::Now(), PointerProperties(8.3f, 4.7f, 2.f)); event.set_button_state(MotionEvent::BUTTON_PRIMARY); @@ -100,11 +98,11 @@ TEST(MotionEventGenericTest, CloneWithHistory) { event_time - base::TimeDelta::FromMilliseconds(5); PointerProperties pointer(8.3f, 4.7f, 10.1f); - MotionEventGeneric event(MotionEvent::ACTION_MOVE, event_time, pointer); + MotionEventGeneric event(MotionEvent::Action::MOVE, event_time, pointer); PointerProperties historical_pointer(3.4f, -4.3f, 11.5); std::unique_ptr<MotionEvent> historical_event(new MotionEventGeneric( - MotionEvent::ACTION_MOVE, historical_event_time, historical_pointer)); + MotionEvent::Action::MOVE, historical_event_time, historical_pointer)); event.PushHistoricalEvent(std::move(historical_event)); EXPECT_EQ(1U, event.GetHistorySize()); @@ -116,13 +114,12 @@ TEST(MotionEventGenericTest, CloneWithHistory) { } TEST(MotionEventGenericTest, Cancel) { - MotionEventGeneric event(MotionEvent::ACTION_UP, - base::TimeTicks::Now(), + MotionEventGeneric event(MotionEvent::Action::UP, base::TimeTicks::Now(), PointerProperties(8.7f, 4.3f, 1.f)); event.set_button_state(MotionEvent::BUTTON_SECONDARY); std::unique_ptr<MotionEvent> cancel = event.Cancel(); - event.set_action(MotionEvent::ACTION_CANCEL); + event.set_action(MotionEvent::Action::CANCEL); ASSERT_TRUE(cancel); EXPECT_NE(event.GetUniqueEventId(), cancel->GetUniqueEventId()); EXPECT_EQ(test::ToString(event), test::ToString(*cancel)); @@ -132,7 +129,7 @@ TEST(MotionEventGenericTest, FindPointerIndexOfId) { base::TimeTicks event_time = base::TimeTicks::Now(); PointerProperties pointer; pointer.id = 0; - MotionEventGeneric event0(MotionEvent::ACTION_DOWN, event_time, pointer); + MotionEventGeneric event0(MotionEvent::Action::DOWN, event_time, pointer); EXPECT_EQ(0, event0.FindPointerIndexOfId(0)); EXPECT_EQ(-1, event0.FindPointerIndexOfId(1)); EXPECT_EQ(-1, event0.FindPointerIndexOfId(-1)); @@ -159,7 +156,7 @@ TEST(MotionEventGenericTest, RemovePointerAt) { base::TimeTicks event_time = base::TimeTicks::Now(); PointerProperties pointer; pointer.id = 0; - MotionEventGeneric event(MotionEvent::ACTION_DOWN, event_time, pointer); + MotionEventGeneric event(MotionEvent::Action::DOWN, event_time, pointer); pointer.id = 7; EXPECT_EQ(1u, event.PushPointer(pointer)); @@ -245,19 +242,19 @@ TEST(MotionEventGenericTest, ToString) { pointer0.touch_major = 35; pointer0.orientation = -1; - MotionEventGeneric event(MotionEvent::ACTION_MOVE, event_time, pointer0); + MotionEventGeneric event(MotionEvent::Action::MOVE, event_time, pointer0); event.PushPointer(pointer1); pointer0.x += 50; pointer1.x -= 50; std::unique_ptr<MotionEventGeneric> historical_event0(new MotionEventGeneric( - MotionEvent::ACTION_MOVE, historical_event_time0, pointer0)); + MotionEvent::Action::MOVE, historical_event_time0, pointer0)); historical_event0->PushPointer(pointer1); pointer0.x += 100; pointer1.x -= 100; std::unique_ptr<MotionEventGeneric> historical_event1(new MotionEventGeneric( - MotionEvent::ACTION_MOVE, historical_event_time1, pointer0)); + MotionEvent::Action::MOVE, historical_event_time1, pointer0)); historical_event1->PushPointer(pointer1); event.PushHistoricalEvent(std::move(historical_event0)); diff --git a/chromium/ui/events/gesture_detection/scale_gesture_detector.cc b/chromium/ui/events/gesture_detection/scale_gesture_detector.cc index 73beab48ec6..eace042b698 100644 --- a/chromium/ui/events/gesture_detection/scale_gesture_detector.cc +++ b/chromium/ui/events/gesture_detection/scale_gesture_detector.cc @@ -71,7 +71,7 @@ ScaleGestureDetector::~ScaleGestureDetector() {} bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) { curr_time_ = event.GetEventTime(); - const int action = event.GetAction(); + const MotionEvent::Action action = event.GetAction(); const int count = static_cast<int>(event.GetPointerCount()); const bool is_stylus_button_down = @@ -82,11 +82,11 @@ bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) { !is_stylus_button_down; const bool stream_complete = - action == MotionEvent::ACTION_UP || - action == MotionEvent::ACTION_CANCEL || anchored_scale_cancelled || - (action == MotionEvent::ACTION_POINTER_DOWN && InAnchoredScaleMode()); + action == MotionEvent::Action::UP || + action == MotionEvent::Action::CANCEL || anchored_scale_cancelled || + (action == MotionEvent::Action::POINTER_DOWN && InAnchoredScaleMode()); - if (action == MotionEvent::ACTION_DOWN || stream_complete) { + if (action == MotionEvent::Action::DOWN || stream_complete) { // Reset any scale in progress with the listener. // If it's an ACTION_DOWN we're beginning a new event stream. // This means the app probably didn't give us all the events. Shame on it. @@ -110,12 +110,12 @@ bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) { initial_span_ = 0; } - const bool config_changed = action == MotionEvent::ACTION_DOWN || - action == MotionEvent::ACTION_POINTER_UP || - action == MotionEvent::ACTION_POINTER_DOWN || + const bool config_changed = action == MotionEvent::Action::DOWN || + action == MotionEvent::Action::POINTER_UP || + action == MotionEvent::Action::POINTER_DOWN || anchored_scale_cancelled; - const bool pointer_up = action == MotionEvent::ACTION_POINTER_UP; + const bool pointer_up = action == MotionEvent::Action::POINTER_UP; const int skip_index = pointer_up ? event.GetActionIndex() : -1; // Determine focal point. @@ -210,7 +210,7 @@ bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) { } // Handle motion; focal point and span/scale factor are changing. - if (action == MotionEvent::ACTION_MOVE) { + if (action == MotionEvent::Action::MOVE) { curr_span_x_ = span_x; curr_span_y_ = span_y; curr_span_ = span; diff --git a/chromium/ui/events/gesture_detection/scale_gesture_detector.h b/chromium/ui/events/gesture_detection/scale_gesture_detector.h index 38038bd2538..9a407854205 100644 --- a/chromium/ui/events/gesture_detection/scale_gesture_detector.h +++ b/chromium/ui/events/gesture_detection/scale_gesture_detector.h @@ -50,8 +50,8 @@ class GESTURE_DETECTION_EXPORT ScaleGestureDetector { // // Note: Applications should pass a complete and consistent event stream to // this method. A complete and consistent event stream involves all - // MotionEvents from the initial ACTION_DOWN to the final ACTION_UP or - // ACTION_CANCEL. + // MotionEvents from the initial Action::DOWN to the final Action::UP or + // Action::CANCEL. // // Returns true if the event was processed and the detector wants to receive // the rest of the MotionEvents in this event stream. diff --git a/chromium/ui/events/gesture_detection/snap_scroll_controller.cc b/chromium/ui/events/gesture_detection/snap_scroll_controller.cc index b50971d3e8f..a393c2e349d 100644 --- a/chromium/ui/events/gesture_detection/snap_scroll_controller.cc +++ b/chromium/ui/events/gesture_detection/snap_scroll_controller.cc @@ -51,12 +51,12 @@ void SnapScrollController::SetSnapScrollMode( const MotionEvent& event, bool is_scale_gesture_detection_in_progress) { switch (event.GetAction()) { - case MotionEvent::ACTION_DOWN: + case MotionEvent::Action::DOWN: mode_ = SNAP_PENDING; down_position_.set_x(event.GetX()); down_position_.set_y(event.GetY()); break; - case MotionEvent::ACTION_MOVE: { + case MotionEvent::Action::MOVE: { if (is_scale_gesture_detection_in_progress) break; @@ -80,8 +80,8 @@ void SnapScrollController::SetSnapScrollMode( if (mode_ == SNAP_PENDING && dx > kMaxSnapBound && dy > kMaxSnapBound) mode_ = SNAP_NONE; } break; - case MotionEvent::ACTION_UP: - case MotionEvent::ACTION_CANCEL: + case MotionEvent::Action::UP: + case MotionEvent::Action::CANCEL: down_position_ = gfx::PointF(); accumulated_distance_ = gfx::Vector2dF(); break; diff --git a/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc index a23bc35a4e8..4490825b526 100644 --- a/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc +++ b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter.cc @@ -139,7 +139,7 @@ TouchDispositionGestureFilter::TouchDispositionGestureFilter( TouchDispositionGestureFilterClient* client) : client_(client), ending_event_motion_event_id_(0), - ending_event_primary_tool_type_(MotionEvent::TOOL_TYPE_UNKNOWN), + ending_event_primary_tool_type_(MotionEvent::ToolType::UNKNOWN), needs_tap_ending_event_(false), needs_show_press_event_(false), needs_fling_ending_event_(false), diff --git a/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc index 613cc75d0fd..c2c26616d0f 100644 --- a/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc +++ b/chromium/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc @@ -275,7 +275,7 @@ class TouchDispositionGestureFilterTest GestureEventDetails details(type); details.set_device_type(GestureDeviceType::DEVICE_TOUCHSCREEN); return GestureEventData( - details, 0, MotionEvent::TOOL_TYPE_FINGER, base::TimeTicks(), x, y, 0, + details, 0, MotionEvent::ToolType::FINGER, base::TimeTicks(), x, y, 0, 0, 1, gfx::RectF(x - diameter / 2, y - diameter / 2, diameter, diameter), kDefaultEventFlags, 0U); diff --git a/chromium/ui/events/gesture_detection/velocity_tracker.cc b/chromium/ui/events/gesture_detection/velocity_tracker.cc index 4094525c2b6..b0f984026e4 100644 --- a/chromium/ui/events/gesture_detection/velocity_tracker.cc +++ b/chromium/ui/events/gesture_detection/velocity_tracker.cc @@ -36,16 +36,16 @@ namespace { static_assert(MotionEvent::MAX_POINTER_ID < 32, "max pointer id too large"); -// Threshold between ACTION_MOVE events for determining that a pointer has -// stopped moving. Some input devices do not send ACTION_MOVE events in the case -// where a pointer has stopped. We need to detect this case so that we can +// Threshold between Action::MOVE events for determining that a pointer has +// stopped moving. Some input devices do not send Action::MOVE events in the +// case where a pointer has stopped. We need to detect this case so that we can // accurately predict the velocity after the pointer starts moving again. const int kAssumePointerMoveStoppedTimeMs = 40; -// Threshold between ACTION_MOVE and ACTION_{UP|POINTER_UP} events for +// Threshold between Action::MOVE and Action::{UP|POINTER_UP} events for // determining that a pointer has stopped moving. This is a larger threshold // than |kAssumePointerMoveStoppedTimeMs|, as some devices may delay synthesis -// of ACTION_{UP|POINTER_UP} to reduce risk of noisy release. +// of Action::{UP|POINTER_UP} to reduce risk of noisy release. const int kAssumePointerUpStoppedTimeMs = 80; struct Position { @@ -297,15 +297,13 @@ void VelocityTracker::AddMovement(const TimeTicks& event_time, } void VelocityTracker::AddMovement(const MotionEvent& event) { - int32_t actionMasked = event.GetAction(); - - switch (actionMasked) { - case MotionEvent::ACTION_DOWN: + switch (event.GetAction()) { + case MotionEvent::Action::DOWN: // case MotionEvent::HOVER_ENTER: // Clear all pointers on down before adding the new movement. Clear(); break; - case MotionEvent::ACTION_POINTER_DOWN: { + case MotionEvent::Action::POINTER_DOWN: { // Start a new movement trace for a pointer that just went down. // We do this on down instead of on up because the client may want to // query the final velocity for a pointer that just went up. @@ -314,20 +312,20 @@ void VelocityTracker::AddMovement(const MotionEvent& event) { ClearPointers(downIdBits); break; } - case MotionEvent::ACTION_MOVE: - // case MotionEvent::ACTION_HOVER_MOVE: + case MotionEvent::Action::MOVE: + // case MotionEvent::Action::HOVER_MOVE: break; - case MotionEvent::ACTION_UP: - case MotionEvent::ACTION_POINTER_UP: - // Note that ACTION_UP and ACTION_POINTER_UP always report the last known - // position of the pointers that went up. ACTION_POINTER_UP does include - // the new position of pointers that remained down but we will also - // receive an ACTION_MOVE with this information if any of them actually - // moved. Since we don't know how many pointers will be going up at once - // it makes sense to just wait for the following ACTION_MOVE before adding - // the movement. However, if the up event itself is delayed because of - // (difficult albeit possible) prolonged stationary screen contact, assume - // that motion has stopped. + case MotionEvent::Action::UP: + case MotionEvent::Action::POINTER_UP: + // Note that Action::UP and Action::POINTER_UP always report the last + // known position of the pointers that went up. Action::POINTER_UP does + // include the new position of pointers that remained down but we will + // also receive an Action::MOVE with this information if any of them + // actually moved. Since we don't know how many pointers will be going up + // at once it makes sense to just wait for the following Action::MOVE + // before adding the movement. However, if the up event itself is delayed + // because of (difficult albeit possible) prolonged stationary screen + // contact, assume that motion has stopped. if ((event.GetEventTime() - last_event_time_) >= base::TimeDelta::FromMilliseconds(kAssumePointerUpStoppedTimeMs)) strategy_->Clear(); diff --git a/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc b/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc index a8e2880d3e4..e828d351afa 100644 --- a/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc +++ b/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc @@ -68,9 +68,9 @@ class VelocityTrackerTest : public testing::Test { if (!samples) return; const base::TimeDelta dt = t / samples; - state->AddMovement(Sample(MotionEvent::ACTION_DOWN, p0, t0, v, dt * 0)); + state->AddMovement(Sample(MotionEvent::Action::DOWN, p0, t0, v, dt * 0)); ApplyMovement(state, p0, v, t0, t, samples); - state->AddMovement(Sample(MotionEvent::ACTION_UP, p0, t0, v, t)); + state->AddMovement(Sample(MotionEvent::Action::UP, p0, t0, v, t)); } static void ApplyMovement(VelocityTrackerState* state, @@ -84,7 +84,7 @@ class VelocityTrackerTest : public testing::Test { return; const base::TimeDelta dt = t / samples; for (size_t i = 0; i < samples; ++i) - state->AddMovement(Sample(MotionEvent::ACTION_MOVE, p0, t0, v, dt * i)); + state->AddMovement(Sample(MotionEvent::Action::MOVE, p0, t0, v, dt * i)); } }; @@ -159,7 +159,7 @@ TEST_F(VelocityTrackerTest, VaryingVelocity) { base::TimeTicks t0 = base::TimeTicks::Now(); base::TimeDelta dt = kTenMillis * 10; state.AddMovement( - Sample(MotionEvent::ACTION_DOWN, p0, t0, vFast, base::TimeDelta())); + Sample(MotionEvent::Action::DOWN, p0, t0, vFast, base::TimeDelta())); // Apply some fast movement and compute the velocity. gfx::PointF pCurr = p0; @@ -202,7 +202,7 @@ TEST_F(VelocityTrackerTest, DelayedActionUp) { VelocityTrackerState state(VelocityTracker::Strategy::LSQ2); state.AddMovement( - Sample(MotionEvent::ACTION_DOWN, p0, t0, v, base::TimeDelta())); + Sample(MotionEvent::Action::DOWN, p0, t0, v, base::TimeDelta())); // Apply the movement and verify a (non-zero) velocity. ApplyMovement(&state, p0, v, t0, dt, samples); @@ -210,11 +210,11 @@ TEST_F(VelocityTrackerTest, DelayedActionUp) { EXPECT_NEAR(-1000, state.GetXVelocity(0), kEpsilson); EXPECT_NEAR(1000, state.GetYVelocity(0), kEpsilson); - // Apply the delayed ACTION_UP. + // Apply the delayed Action::UP. const gfx::PointF p1 = p0 + ScaleVector2d(v, dt.InSecondsF()); const base::TimeTicks t1 = t0 + dt + kTenMillis * 10; - state.AddMovement(Sample( - MotionEvent::ACTION_UP, p1, t1, v, base::TimeDelta())); + state.AddMovement( + Sample(MotionEvent::Action::UP, p1, t1, v, base::TimeDelta())); // The tracked velocity should have been reset. state.ComputeCurrentVelocity(1000, 1000); @@ -234,14 +234,14 @@ TEST_F(VelocityTrackerTest, NoDirectionReversal) { gfx::PointF p(0, 0); - MockMotionEvent m1(MotionEvent::ACTION_DOWN, t0, p.x(), p.y()); + MockMotionEvent m1(MotionEvent::Action::DOWN, t0, p.x(), p.y()); state_unrestricted.AddMovement(m1); state_restricted.AddMovement(m1); for (size_t i = 0; i < samples; ++i) { if (i < 50) p.set_y(p.y() + 10); - MockMotionEvent mi(MotionEvent::ACTION_MOVE, t0 + dt * i, p.x(), p.y()); + MockMotionEvent mi(MotionEvent::Action::MOVE, t0 + dt * i, p.x(), p.y()); state_unrestricted.AddMovement(mi); state_restricted.AddMovement(mi); } diff --git a/chromium/ui/events/gesture_event_details.cc b/chromium/ui/events/gesture_event_details.cc index 8f422cbfc6f..2de5edbbbc6 100644 --- a/chromium/ui/events/gesture_event_details.cc +++ b/chromium/ui/events/gesture_event_details.cc @@ -79,6 +79,7 @@ GestureEventDetails::GestureEventDetails(ui::EventType type, // allowed as an exception. if (other.type() == ui::ET_GESTURE_PINCH_BEGIN) break; + FALLTHROUGH; case ui::ET_GESTURE_SCROLL_UPDATE: case ui::ET_SCROLL_FLING_START: case ui::ET_GESTURE_SWIPE: diff --git a/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc b/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc index 65f680e7f83..b2aec0cbeb1 100644 --- a/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc +++ b/chromium/ui/events/gestures/blink/web_gesture_curve_impl.cc @@ -24,6 +24,10 @@ #include "ui/events/android/scroller.h" #endif +#if !defined(OS_ANDROID) && defined(CHROMECAST_BUILD) +#include "ui/events/chromecast/scroller.h" +#endif + using blink::WebGestureCurve; namespace ui { @@ -37,7 +41,7 @@ std::unique_ptr<GestureCurve> CreateDefaultPlatformCurve( base::TimeTicks()); } -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(CHROMECAST_BUILD) auto scroller = std::make_unique<Scroller>(Scroller::Config()); scroller->Fling(0, 0, diff --git a/chromium/ui/events/gestures/motion_event_aura.cc b/chromium/ui/events/gestures/motion_event_aura.cc index 50032936b65..12acaec437a 100644 --- a/chromium/ui/events/gestures/motion_event_aura.cc +++ b/chromium/ui/events/gestures/motion_event_aura.cc @@ -14,18 +14,18 @@ MotionEvent::ToolType EventPointerTypeToMotionEventToolType( EventPointerType type) { switch (type) { case EventPointerType::POINTER_TYPE_UNKNOWN: - return MotionEvent::TOOL_TYPE_UNKNOWN; + return MotionEvent::ToolType::UNKNOWN; case EventPointerType::POINTER_TYPE_MOUSE: - return MotionEvent::TOOL_TYPE_MOUSE; + return MotionEvent::ToolType::MOUSE; case EventPointerType::POINTER_TYPE_PEN: - return MotionEvent::TOOL_TYPE_STYLUS; + return MotionEvent::ToolType::STYLUS; case EventPointerType::POINTER_TYPE_TOUCH: - return MotionEvent::TOOL_TYPE_FINGER; + return MotionEvent::ToolType::FINGER; case EventPointerType::POINTER_TYPE_ERASER: - return MotionEvent::TOOL_TYPE_ERASER; + return MotionEvent::ToolType::ERASER; } - return MotionEvent::TOOL_TYPE_UNKNOWN; + return MotionEvent::ToolType::UNKNOWN; } PointerProperties GetPointerPropertiesFromTouchEvent(const TouchEvent& touch) { @@ -96,6 +96,7 @@ bool MotionEventAura::OnTouch(const TouchEvent& touch) { case ET_TOUCH_PRESSED: if (!AddTouch(touch)) return false; + FALLTHROUGH; case ET_TOUCH_RELEASED: case ET_TOUCH_CANCELLED: // Removing these touch points needs to be postponed until after the @@ -127,7 +128,7 @@ void MotionEventAura::CleanupRemovedTouchPoints(const TouchEvent& event) { DCHECK(GetPointerCount()); int index_to_delete = GetIndexFromId(event.pointer_details().id); set_action_index(-1); - set_action(MotionEvent::ACTION_NONE); + set_action(MotionEvent::Action::NONE); pointer(index_to_delete) = pointer(GetPointerCount() - 1); PopPointer(); } @@ -155,25 +156,25 @@ void MotionEventAura::UpdateCachedAction(const TouchEvent& touch) { switch (touch.type()) { case ET_TOUCH_PRESSED: if (GetPointerCount() == 1) { - set_action(ACTION_DOWN); + set_action(Action::DOWN); } else { - set_action(ACTION_POINTER_DOWN); + set_action(Action::POINTER_DOWN); set_action_index(GetIndexFromId(touch.pointer_details().id)); } break; case ET_TOUCH_RELEASED: if (GetPointerCount() == 1) { - set_action(ACTION_UP); + set_action(Action::UP); } else { - set_action(ACTION_POINTER_UP); + set_action(Action::POINTER_UP); set_action_index(GetIndexFromId(touch.pointer_details().id)); } break; case ET_TOUCH_CANCELLED: - set_action(ACTION_CANCEL); + set_action(Action::CANCEL); break; case ET_TOUCH_MOVED: - set_action(ACTION_MOVE); + set_action(Action::MOVE); break; default: NOTREACHED(); diff --git a/chromium/ui/events/gestures/motion_event_aura_unittest.cc b/chromium/ui/events/gestures/motion_event_aura_unittest.cc index 534013d9cfa..276876f2059 100644 --- a/chromium/ui/events/gestures/motion_event_aura_unittest.cc +++ b/chromium/ui/events/gestures/motion_event_aura_unittest.cc @@ -257,7 +257,7 @@ TEST(MotionEventAuraTest, TapParams) { EXPECT_FLOAT_EQ(radius_y, event.GetTouchMinor(0) / 2); EXPECT_FLOAT_EQ(rotation_angle, gfx::RadToDeg(event.GetOrientation(0)) + 90); EXPECT_FLOAT_EQ(pressure, event.GetPressure(0)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(0)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(0)); // Test case: radius_x < radius_y, rotation_angle < 90 radius_x = 67.89f; @@ -273,7 +273,7 @@ TEST(MotionEventAuraTest, TapParams) { EXPECT_FLOAT_EQ(radius_x, event.GetTouchMinor(1) / 2); EXPECT_FLOAT_EQ(rotation_angle, gfx::RadToDeg(event.GetOrientation(1))); EXPECT_FLOAT_EQ(pressure, event.GetPressure(1)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(1)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(1)); // Test cloning of tap params // TODO(mustaq): Make a separate clone test, crbug.com/450655 @@ -285,7 +285,7 @@ TEST(MotionEventAuraTest, TapParams) { EXPECT_FLOAT_EQ(radius_x, clone->GetTouchMinor(1) / 2); EXPECT_FLOAT_EQ(rotation_angle, gfx::RadToDeg(clone->GetOrientation(1))); EXPECT_FLOAT_EQ(pressure, clone->GetPressure(1)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, clone->GetToolType(1)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, clone->GetToolType(1)); // TODO(mustaq): The move test seems out-of-scope here, crbug.com/450655 radius_x = 76.98f; @@ -302,7 +302,7 @@ TEST(MotionEventAuraTest, TapParams) { EXPECT_FLOAT_EQ(radius_x, event.GetTouchMinor(1) / 2); EXPECT_FLOAT_EQ(rotation_angle, gfx::RadToDeg(event.GetOrientation(1))); EXPECT_FLOAT_EQ(pressure, event.GetPressure(1)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(1)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(1)); // Test case: radius_x > radius_y, rotation_angle > 90 radius_x = 123.45f; @@ -318,7 +318,7 @@ TEST(MotionEventAuraTest, TapParams) { EXPECT_FLOAT_EQ(radius_y, event.GetTouchMinor(2) / 2); EXPECT_FLOAT_EQ(rotation_angle, gfx::RadToDeg(event.GetOrientation(2)) + 90); EXPECT_FLOAT_EQ(pressure, event.GetPressure(2)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(2)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(2)); // Test case: radius_x < radius_y, rotation_angle > 90 radius_x = 67.89f; @@ -334,7 +334,7 @@ TEST(MotionEventAuraTest, TapParams) { EXPECT_FLOAT_EQ(radius_x, event.GetTouchMinor(3) / 2); EXPECT_FLOAT_EQ(rotation_angle, gfx::RadToDeg(event.GetOrientation(3)) + 180); EXPECT_FLOAT_EQ(pressure, event.GetPressure(3)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(3)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(3)); } TEST(MotionEventAuraTest, Timestamps) { @@ -371,36 +371,36 @@ TEST(MotionEventAuraTest, CachedAction) { TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, ids[0]); EXPECT_TRUE(event.OnTouch(press0)); - EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::DOWN, event.GetAction()); EXPECT_EQ(1U, event.GetPointerCount()); TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, ids[1]); EXPECT_TRUE(event.OnTouch(press1)); - EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::POINTER_DOWN, event.GetAction()); EXPECT_EQ(1, event.GetActionIndex()); EXPECT_EQ(2U, event.GetPointerCount()); // Test cloning of CachedAction information. std::unique_ptr<MotionEvent> clone = event.Clone(); - EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, clone->GetAction()); + EXPECT_EQ(MotionEvent::Action::POINTER_DOWN, clone->GetAction()); EXPECT_EQ(1, clone->GetActionIndex()); TouchEvent move0 = TouchWithType(ET_TOUCH_MOVED, ids[0]); move0.set_location(gfx::Point(10, 12)); EXPECT_TRUE(event.OnTouch(move0)); - EXPECT_EQ(MotionEvent::ACTION_MOVE, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::MOVE, event.GetAction()); EXPECT_EQ(2U, event.GetPointerCount()); TouchEvent release0 = TouchWithType(ET_TOUCH_RELEASED, ids[0]); EXPECT_TRUE(event.OnTouch(release0)); - EXPECT_EQ(MotionEvent::ACTION_POINTER_UP, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::POINTER_UP, event.GetAction()); EXPECT_EQ(2U, event.GetPointerCount()); event.CleanupRemovedTouchPoints(release0); EXPECT_EQ(1U, event.GetPointerCount()); TouchEvent release1 = TouchWithType(ET_TOUCH_RELEASED, ids[1]); EXPECT_TRUE(event.OnTouch(release1)); - EXPECT_EQ(MotionEvent::ACTION_UP, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::UP, event.GetAction()); EXPECT_EQ(1U, event.GetPointerCount()); event.CleanupRemovedTouchPoints(release1); EXPECT_EQ(0U, event.GetPointerCount()); @@ -412,17 +412,17 @@ TEST(MotionEventAuraTest, Cancel) { TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, ids[0]); EXPECT_TRUE(event.OnTouch(press0)); - EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::DOWN, event.GetAction()); EXPECT_EQ(1U, event.GetPointerCount()); TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, ids[1]); EXPECT_TRUE(event.OnTouch(press1)); - EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::POINTER_DOWN, event.GetAction()); EXPECT_EQ(1, event.GetActionIndex()); EXPECT_EQ(2U, event.GetPointerCount()); std::unique_ptr<MotionEvent> cancel = event.Cancel(); - EXPECT_EQ(MotionEvent::ACTION_CANCEL, cancel->GetAction()); + EXPECT_EQ(MotionEvent::Action::CANCEL, cancel->GetAction()); EXPECT_EQ(2U, cancel->GetPointerCount()); } @@ -431,7 +431,7 @@ TEST(MotionEventAuraTest, ToolType) { TouchEvent touch_event = TouchWithType(ET_TOUCH_PRESSED, 7); EXPECT_TRUE(event.OnTouch(touch_event)); ASSERT_EQ(1U, event.GetPointerCount()); - EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(0)); + EXPECT_EQ(MotionEvent::ToolType::FINGER, event.GetToolType(0)); touch_event = TouchWithType(ET_TOUCH_RELEASED, 7); PointerDetails pointer_details(EventPointerType::POINTER_TYPE_PEN, @@ -441,7 +441,7 @@ TEST(MotionEventAuraTest, ToolType) { /* force */ 1.0f); touch_event.SetPointerDetailsForTest(pointer_details); EXPECT_TRUE(event.OnTouch(touch_event)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_STYLUS, event.GetToolType(0)); + EXPECT_EQ(MotionEvent::ToolType::STYLUS, event.GetToolType(0)); } TEST(MotionEventAuraTest, Flags) { @@ -501,13 +501,13 @@ TEST(MotionEventAuraTest, UniqueEventID) { TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, 3); EXPECT_TRUE(event.OnTouch(press0)); - EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::DOWN, event.GetAction()); ASSERT_EQ(1U, event.GetPointerCount()); EXPECT_EQ(event.GetUniqueEventId(), press0.unique_event_id()); TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, 6); EXPECT_TRUE(event.OnTouch(press1)); - EXPECT_EQ(MotionEvent::ACTION_POINTER_DOWN, event.GetAction()); + EXPECT_EQ(MotionEvent::Action::POINTER_DOWN, event.GetAction()); EXPECT_EQ(2U, event.GetPointerCount()); EXPECT_EQ(event.GetUniqueEventId(), press1.unique_event_id()); } @@ -543,7 +543,7 @@ TEST(MotionEventAuraTest, PenRadiusDefault) { ET_TOUCH_PRESSED, gfx::Point(0, 0), base::TimeTicks(), ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 7)); EXPECT_TRUE(event.OnTouch(touch_event)); - EXPECT_EQ(MotionEvent::TOOL_TYPE_STYLUS, event.GetToolType(0)); + EXPECT_EQ(MotionEvent::ToolType::STYLUS, event.GetToolType(0)); EXPECT_EQ(1u, event.GetTouchMajor(0)); EXPECT_EQ(1u, event.GetTouchMinor(0)); } diff --git a/chromium/ui/events/keyboard_hook.h b/chromium/ui/events/keyboard_hook.h new file mode 100644 index 00000000000..32f05492772 --- /dev/null +++ b/chromium/ui/events/keyboard_hook.h @@ -0,0 +1,40 @@ +// Copyright 2018 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_EVENTS_KEYBOARD_HOOK_H_ +#define UI_EVENTS_KEYBOARD_HOOK_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/containers/flat_set.h" +#include "base/optional.h" +#include "ui/events/events_export.h" + +namespace ui { + +class KeyEvent; + +// Intercepts keyboard events typically handled by the OS or browser. +// Destroying the instance will unregister and clean up the keyboard hook. +class EVENTS_EXPORT KeyboardHook { + public: + using KeyEventCallback = base::RepeatingCallback<void(KeyEvent* event)>; + + virtual ~KeyboardHook() = default; + + // Creates a platform specific implementation. + // |native_key_codes| is the set of key codes which will be intercepted, if + // it is empty, this class will attempt to intercept all keys. + // |callback| is called for each key which is intercepted. + // Returns a valid instance if the hook was created and successfully + // registered otherwise nullptr. + static std::unique_ptr<KeyboardHook> Create( + base::Optional<base::flat_set<int>> native_key_codes, + KeyEventCallback callback); +}; + +} // namespace ui + +#endif // UI_EVENTS_KEYBOARD_HOOK_H_ diff --git a/chromium/ui/events/keyboard_hook_base.cc b/chromium/ui/events/keyboard_hook_base.cc new file mode 100644 index 00000000000..d9a7938ff30 --- /dev/null +++ b/chromium/ui/events/keyboard_hook_base.cc @@ -0,0 +1,34 @@ +// Copyright 2018 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/events/keyboard_hook_base.h" + +#include <utility> + +#include "base/macros.h" +#include "base/stl_util.h" +#include "ui/events/event.h" + +namespace ui { + +KeyboardHookBase::KeyboardHookBase( + base::Optional<base::flat_set<int>> native_key_codes, + KeyEventCallback callback) + : key_event_callback_(std::move(callback)), + key_codes_(std::move(native_key_codes)) { + DCHECK(key_event_callback_); +} + +KeyboardHookBase::~KeyboardHookBase() = default; + +bool KeyboardHookBase::ShouldCaptureKeyEvent(int key_code) const { + return !key_codes_ || base::ContainsKey(key_codes_.value(), key_code); +} + +void KeyboardHookBase::ForwardCapturedKeyEvent( + std::unique_ptr<KeyEvent> event) { + key_event_callback_.Run(event.get()); +} + +} // namespace ui diff --git a/chromium/ui/events/keyboard_hook_base.h b/chromium/ui/events/keyboard_hook_base.h new file mode 100644 index 00000000000..428c24fa077 --- /dev/null +++ b/chromium/ui/events/keyboard_hook_base.h @@ -0,0 +1,42 @@ +// Copyright 2018 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_EVENTS_KEYBOARD_HOOK_BASE_H_ +#define UI_EVENTS_KEYBOARD_HOOK_BASE_H_ + +#include <memory> + +#include "base/macros.h" +#include "ui/events/keyboard_hook.h" + +namespace ui { + +class KeyEvent; + +class KeyboardHookBase : public KeyboardHook { + public: + KeyboardHookBase(base::Optional<base::flat_set<int>> native_key_codes, + KeyEventCallback callback); + ~KeyboardHookBase() override; + + protected: + // Indicates whether |key_code| should be intercepted by the keyboard hook. + bool ShouldCaptureKeyEvent(int key_code) const; + + // Forwards the key event using |key_event_callback_|. + void ForwardCapturedKeyEvent(std::unique_ptr<KeyEvent> event); + + private: + // Used to forward key events. + KeyEventCallback key_event_callback_; + + // The set of keys which should be intercepted by the keyboard hook. + base::Optional<base::flat_set<int>> key_codes_; + + DISALLOW_COPY_AND_ASSIGN(KeyboardHookBase); +}; + +} // namespace ui + +#endif // UI_EVENTS_KEYBOARD_HOOK_BASE_H_ diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_android.cc b/chromium/ui/events/keycodes/keyboard_code_conversion_android.cc index 5baef1990a9..f65db2b5e08 100644 --- a/chromium/ui/events/keycodes/keyboard_code_conversion_android.cc +++ b/chromium/ui/events/keycodes/keyboard_code_conversion_android.cc @@ -284,7 +284,7 @@ DomKey GetDomKeyFromAndroidKeycode(int keycode) { case AKEYCODE_KATAKANA_HIRAGANA: return DomKey::HIRAGANA_KATAKANA; case AKEYCODE_KANA: - return DomKey::KANA_MODE; + return DomKey::KANJI_MODE; case AKEYCODE_BRIGHTNESS_DOWN: return DomKey::BRIGHTNESS_DOWN; case AKEYCODE_BRIGHTNESS_UP: @@ -379,6 +379,8 @@ DomKey GetDomKeyFromAndroidKeycode(int keycode) { return DomKey::COPY; case AKEYCODE_PASTE: return DomKey::PASTE; + case AKEYCODE_DVR: + return DomKey::DVR; // The following codes should already be handled as printable // character mapping. @@ -479,7 +481,6 @@ DomKey GetDomKeyFromAndroidKeycode(int keycode) { // case AKEYCODE_BUTTON_SELECT: // case AKEYCODE_BUTTON_MODE: // case AKEYCODE_WINDOW: - // case AKEYCODE_DVR: // case AKEYCODE_BUTTON_1: // case AKEYCODE_BUTTON_2: // case AKEYCODE_BUTTON_3: diff --git a/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc b/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc index 836f7829fff..4b95e75a497 100644 --- a/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc +++ b/chromium/ui/events/keycodes/keyboard_code_conversion_xkb.cc @@ -110,8 +110,10 @@ DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym) { return DomKey::END; case XKB_KEY_Select: return DomKey::SELECT; + // Treat Print/PrintScreen as PrintScreen https://crbug.com/683097. case XKB_KEY_Print: - return DomKey::PRINT; + case XKB_KEY_3270_PrintScreen: + return DomKey::PRINT_SCREEN; case XKB_KEY_Execute: return DomKey::EXECUTE; case XKB_KEY_Insert: @@ -357,8 +359,6 @@ DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym) { return DomKey::EX_SEL; case XKB_KEY_3270_CursorSelect: return DomKey::CR_SEL; - case XKB_KEY_3270_PrintScreen: - return DomKey::PRINT_SCREEN; case XKB_KEY_ISO_Level3_Shift: return DomKey::ALT_GRAPH; case XKB_KEY_ISO_Level3_Latch: diff --git a/chromium/ui/events/keycodes/platform_key_map_win.cc b/chromium/ui/events/keycodes/platform_key_map_win.cc index bd1dfcc7549..d7ecacc8553 100644 --- a/chromium/ui/events/keycodes/platform_key_map_win.cc +++ b/chromium/ui/events/keycodes/platform_key_map_win.cc @@ -65,10 +65,6 @@ bool HasControlAndAlt(int flags) { return (flags & kControlAndAltFlags) == kControlAndAltFlags; } -int SetControlAndAltToAltGraph(int flags) { - return (flags & ~kControlAndAltFlags) | EF_ALTGR_DOWN; -} - int ReplaceAltGraphWithControlAndAlt(int flags) { return (flags & EF_ALTGR_DOWN) ? ((flags & ~EF_ALTGR_DOWN) | kControlAndAltFlags) @@ -322,12 +318,10 @@ DomKey PlatformKeyMap::DomKeyFromKeyboardCodeImpl(KeyboardCode key_code, if (it != printable_keycode_to_key_.end()) { key = it->second; if (key != DomKey::NONE) { - // TODO(25503): Map Ctrl+Alt to AltGraph if new behaviour is enabled. - if (HasControlAndAlt(try_flags) && - base::FeatureList::IsEnabled(kFixAltGraphModifier)) { - // Printable character generated via Control+Alt means AltGraph. - *flags = SetControlAndAltToAltGraph(*flags); - } + // If we find a character with |try_flags| including Control and Alt + // then this is an AltGraph-shifted event. + if (HasControlAndAlt(try_flags)) + *flags = ReplaceControlAndAltWithAltGraph(*flags); return key; } } @@ -362,6 +356,15 @@ DomKey PlatformKeyMap::DomKeyFromKeyboardCode(KeyboardCode key_code, } // static +int PlatformKeyMap::ReplaceControlAndAltWithAltGraph(int flags) { + if (!HasControlAndAlt(flags)) + return flags; + if (!IsFixAltGraphEnabled()) + return flags; + return (flags & ~kControlAndAltFlags) | EF_ALTGR_DOWN; +} + +// static bool PlatformKeyMap::UsesAltGraph() { base::ThreadLocalStorage::Slot* platform_key_map_tls = g_platform_key_map_tls_lazy.Pointer(); diff --git a/chromium/ui/events/keycodes/platform_key_map_win.h b/chromium/ui/events/keycodes/platform_key_map_win.h index 7b9871fef6c..53e13ba090f 100644 --- a/chromium/ui/events/keycodes/platform_key_map_win.h +++ b/chromium/ui/events/keycodes/platform_key_map_win.h @@ -11,6 +11,7 @@ #include "base/event_types.h" #include "base/hash.h" +#include "ui/events/event.h" #include "ui/events/events_export.h" #include "ui/events/keycodes/dom/dom_key.h" #include "ui/events/keycodes/keyboard_codes_win.h" @@ -25,15 +26,20 @@ class EVENTS_EXPORT PlatformKeyMap { ~PlatformKeyMap(); // Returns the DOM KeyboardEvent key from |KeyboardCode|+|EventFlags| and - // the keyboard layout of current thread. + // the keyboard layout of current thread. If this is an AltGraph modified + // key then |flags| will have Control+Alt removed, and AltGraph set. // Updates a per-thread key map cache whenever the layout changes. - // If |flags| includes both Control and Alt modifiers, they will be replaced - // by AltGraph if the key generates a printable character with them. static DomKey DomKeyFromKeyboardCode(KeyboardCode key_code, int* flags); // Returns true if the currently-active keymap uses AltGraph shift. static bool UsesAltGraph(); + // If the supplied event has both Control and Alt modifiers set, then they + // are replaced by AltGraph. This should only ever be applied to the flags + // for printable-character events. + // TODO(crbug.com/25503): Has no effect if FixAltGraph is not enabled. + static int ReplaceControlAndAltWithAltGraph(int flags); + // TODO(crbug.com/25503): Returns true if we disambiguate AltGraph. static bool IsFixAltGraphEnabled(); diff --git a/chromium/ui/events/keycodes/platform_key_map_win_unittest.cc b/chromium/ui/events/keycodes/platform_key_map_win_unittest.cc index 814d5a35ddb..7424bfe8f86 100644 --- a/chromium/ui/events/keycodes/platform_key_map_win_unittest.cc +++ b/chromium/ui/events/keycodes/platform_key_map_win_unittest.cc @@ -6,6 +6,7 @@ #include "base/macros.h" #include "base/strings/string16.h" +#include "base/test/scoped_feature_list.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/dom/dom_code.h" @@ -29,6 +30,11 @@ struct TestKey { const char* altgr_capslock; }; +struct DomKeyAndFlags { + DomKey key; + int flags; +}; + } // anonymous namespace class PlatformKeyMapTest : public testing::Test { @@ -87,6 +93,16 @@ class PlatformKeyMapTest : public testing::Test { return keymap.DomKeyFromKeyboardCodeImpl(key_code, &flags); } + // Returns the DomKey and |flags| in a struct, for use in tests verifying + // that the API correctly modifies the |flags| in/out parameter. + DomKeyAndFlags DomKeyAndFlagsFromKeyboardCode(const PlatformKeyMap& keymap, + KeyboardCode key_code, + int flags) { + DomKeyAndFlags result = {DomKey(), flags}; + result.key = keymap.DomKeyFromKeyboardCodeImpl(key_code, &result.flags); + return result; + } + private: DISALLOW_COPY_AND_ASSIGN(PlatformKeyMapTest); }; @@ -326,7 +342,7 @@ TEST_F(PlatformKeyMapTest, JapaneseSpecificKeys) { } } -TEST_F(PlatformKeyMapTest, AltGraph) { +TEST_F(PlatformKeyMapTest, AltGraphDomKey) { PlatformKeyMap us_keymap( GetPlatformKeyboardLayout(KEYBOARD_LAYOUT_ENGLISH_US)); EXPECT_EQ(DomKey::ALT, @@ -343,4 +359,75 @@ TEST_F(PlatformKeyMapTest, AltGraph) { EF_ALTGR_DOWN | EF_IS_EXTENDED_KEY)); } +namespace { + +const struct AltGraphModifierTestCase { + // Test-case Virtual Keycode and modifier flags. + KeyboardCode key_code; + int flags; + + // Whether or not this case generates an AltGraph-shifted key under FR-fr + // layout. + bool expect_alt_graph; +} kAltGraphModifierTestCases[] = { + {VKEY_C, EF_NONE, false}, + {VKEY_C, EF_ALTGR_DOWN, false}, + {VKEY_C, EF_CONTROL_DOWN | EF_ALT_DOWN, false}, + {VKEY_C, EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN, false}, + {VKEY_E, EF_NONE, false}, + {VKEY_E, EF_ALTGR_DOWN, true}, + {VKEY_E, EF_CONTROL_DOWN | EF_ALT_DOWN, true}, + {VKEY_E, EF_CONTROL_DOWN | EF_ALT_DOWN | EF_ALTGR_DOWN, true}, +}; + +class AltGraphModifierTest + : public PlatformKeyMapTest, + public testing::WithParamInterface<KeyboardLayout> { + public: + AltGraphModifierTest() : keymap_(GetPlatformKeyboardLayout(GetParam())) {} + + protected: + base::test::ScopedFeatureList feature_list_; + PlatformKeyMap keymap_; +}; + +TEST_P(AltGraphModifierTest, OldAltGraphModifierBehaviour) { + feature_list_.InitFromCommandLine("", "FixAltGraph"); + + // Regardless of the keyboard layout, modifier flags should be unchanged. + for (const auto& test_case : kAltGraphModifierTestCases) { + DomKeyAndFlags result = DomKeyAndFlagsFromKeyboardCode( + keymap_, test_case.key_code, test_case.flags); + EXPECT_EQ(test_case.flags, result.flags) + << " for key_code=" << test_case.key_code; + } +} + +TEST_P(AltGraphModifierTest, AltGraphModifierBehaviour) { + feature_list_.InitFromCommandLine("FixAltGraph", ""); + + // If the key generates a character under AltGraph then |result| should + // report AltGraph, but not Control or Alt. + for (const auto& test_case : kAltGraphModifierTestCases) { + DomKeyAndFlags result = DomKeyAndFlagsFromKeyboardCode( + keymap_, test_case.key_code, test_case.flags); + if (GetParam() == KEYBOARD_LAYOUT_FRENCH && test_case.expect_alt_graph) { + EXPECT_EQ(EF_ALTGR_DOWN, result.flags) + << " for key_code=" << test_case.key_code + << " flags=" << test_case.flags; + } else { + EXPECT_EQ(test_case.flags, result.flags) + << " for key_code=" << test_case.key_code + << " flags=" << test_case.flags; + } + } +} + +INSTANTIATE_TEST_CASE_P(VerifyAltGraph, + AltGraphModifierTest, + ::testing::Values(KEYBOARD_LAYOUT_ENGLISH_US, + KEYBOARD_LAYOUT_FRENCH)); + +} // namespace + } // namespace ui diff --git a/chromium/ui/events/ozone/BUILD.gn b/chromium/ui/events/ozone/BUILD.gn index 613d448ce7e..f9a33289569 100644 --- a/chromium/ui/events/ozone/BUILD.gn +++ b/chromium/ui/events/ozone/BUILD.gn @@ -33,6 +33,8 @@ if (use_ozone) { "device/udev/device_manager_udev.cc", "device/udev/device_manager_udev.h", "events_ozone_export.h", + "keyboard/event_auto_repeat_handler.cc", + "keyboard/event_auto_repeat_handler.h", ] deps = [ diff --git a/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc b/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc index 5242dc7f55c..4cc71e34d38 100644 --- a/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc +++ b/chromium/ui/events/ozone/evdev/input_device_factory_evdev.cc @@ -10,6 +10,7 @@ #include <utility> +#include "base/bind.h" #include "base/files/scoped_file.h" #include "base/memory/ptr_util.h" #include "base/threading/thread_task_runner_handle.h" @@ -509,6 +510,16 @@ void InputDeviceFactoryEvdev::EnablePalmSuppression(bool enabled) { return; palm_suppression_enabled_ = enabled; + // This function can be called while disabling pen devices, so don't disable + // inline here. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&InputDeviceFactoryEvdev::EnableDevices, + weak_ptr_factory_.GetWeakPtr())); +} + +void InputDeviceFactoryEvdev::EnableDevices() { + // TODO(spang): Fix the UI to not dismiss menus when we use + // ApplyInputDeviceSettings() instead of this function. for (const auto& it : converters_) it.second->SetEnabled(IsDeviceEnabled(it.second.get())); } diff --git a/chromium/ui/events/ozone/evdev/input_device_factory_evdev.h b/chromium/ui/events/ozone/evdev/input_device_factory_evdev.h index 3c20987b281..567fbc35b28 100644 --- a/chromium/ui/events/ozone/evdev/input_device_factory_evdev.h +++ b/chromium/ui/events/ozone/evdev/input_device_factory_evdev.h @@ -63,8 +63,6 @@ class EVENTS_OZONE_EVDEV_EXPORT InputDeviceFactoryEvdev { base::WeakPtr<InputDeviceFactoryEvdev> GetWeakPtr(); - void EnablePalmSuppression(bool enabled); - private: // Open device at path & starting processing events. void AttachInputDevice(std::unique_ptr<EventConverterEvdev> converter); @@ -94,6 +92,8 @@ class EVENTS_OZONE_EVDEV_EXPORT InputDeviceFactoryEvdev { void SetBoolPropertyForOneType(const EventDeviceType type, const std::string& name, bool value); + void EnablePalmSuppression(bool enabled); + void EnableDevices(); // Task runner for our thread. scoped_refptr<base::TaskRunner> task_runner_; diff --git a/chromium/ui/events/ozone/evdev/input_injector_evdev.cc b/chromium/ui/events/ozone/evdev/input_injector_evdev.cc index b69dc04508b..f6976d717db 100644 --- a/chromium/ui/events/ozone/evdev/input_injector_evdev.cc +++ b/chromium/ui/events/ozone/evdev/input_injector_evdev.cc @@ -42,6 +42,7 @@ void InputInjectorEvdev::InjectMouseButton(EventFlags button, bool down) { break; case EF_MIDDLE_MOUSE_BUTTON: code = BTN_MIDDLE; + break; default: LOG(WARNING) << "Invalid flag: " << button << " for the button parameter"; return; diff --git a/chromium/ui/events/ozone/evdev/input_injector_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/input_injector_evdev_unittest.cc index 6c8b86ca0b6..737bce2125e 100644 --- a/chromium/ui/events/ozone/evdev/input_injector_evdev_unittest.cc +++ b/chromium/ui/events/ozone/evdev/input_injector_evdev_unittest.cc @@ -174,6 +174,12 @@ TEST_F(InputInjectorEvdevTest, RightClick) { run_loop_.RunUntilIdle(); } +TEST_F(InputInjectorEvdevTest, MiddleClick) { + ExpectClick(12, 13, EF_MIDDLE_MOUSE_BUTTON, 1); + SimulateMouseClick(12, 13, EF_MIDDLE_MOUSE_BUTTON, 1); + run_loop_.RunUntilIdle(); +} + TEST_F(InputInjectorEvdevTest, DoubleClick) { ExpectClick(12, 13, EF_LEFT_MOUSE_BUTTON, 2); SimulateMouseClick(12, 13, EF_LEFT_MOUSE_BUTTON, 2); diff --git a/chromium/ui/events/ozone/evdev/keyboard_evdev.cc b/chromium/ui/events/ozone/evdev/keyboard_evdev.cc index 23b738d9b63..a0f5420b0ed 100644 --- a/chromium/ui/events/ozone/evdev/keyboard_evdev.cc +++ b/chromium/ui/events/ozone/evdev/keyboard_evdev.cc @@ -19,23 +19,14 @@ namespace ui { -namespace { - -const int kRepeatDelayMs = 500; -const int kRepeatIntervalMs = 50; - -} // namespace - KeyboardEvdev::KeyboardEvdev(EventModifiers* modifiers, KeyboardLayoutEngine* keyboard_layout_engine, const EventDispatchCallback& callback) : callback_(callback), modifiers_(modifiers), keyboard_layout_engine_(keyboard_layout_engine), - weak_ptr_factory_(this) { - repeat_delay_ = base::TimeDelta::FromMilliseconds(kRepeatDelayMs); - repeat_interval_ = base::TimeDelta::FromMilliseconds(kRepeatIntervalMs); -} + auto_repeat_handler_(this), + weak_ptr_factory_(this) {} KeyboardEvdev::~KeyboardEvdev() { } @@ -54,7 +45,8 @@ void KeyboardEvdev::OnKeyChange(unsigned int key, return; // Key already released. key_state_.set(key, down); - UpdateKeyRepeat(key, down, suppress_auto_repeat, device_id); + auto_repeat_handler_.UpdateKeyRepeat(key, down, suppress_auto_repeat, + device_id); DispatchKey(key, down, is_repeat, timestamp, device_id); } @@ -67,23 +59,21 @@ bool KeyboardEvdev::IsCapsLockEnabled() { } bool KeyboardEvdev::IsAutoRepeatEnabled() { - return auto_repeat_enabled_; + return auto_repeat_handler_.IsAutoRepeatEnabled(); } void KeyboardEvdev::SetAutoRepeatEnabled(bool enabled) { - auto_repeat_enabled_ = enabled; + auto_repeat_handler_.SetAutoRepeatEnabled(enabled); } void KeyboardEvdev::SetAutoRepeatRate(const base::TimeDelta& delay, const base::TimeDelta& interval) { - repeat_delay_ = delay; - repeat_interval_ = interval; + auto_repeat_handler_.SetAutoRepeatRate(delay, interval); } void KeyboardEvdev::GetAutoRepeatRate(base::TimeDelta* delay, base::TimeDelta* interval) { - *delay = repeat_delay_; - *interval = repeat_interval_; + auto_repeat_handler_.GetAutoRepeatRate(delay, interval); } bool KeyboardEvdev::SetCurrentLayoutByName(const std::string& layout_name) { @@ -92,6 +82,13 @@ bool KeyboardEvdev::SetCurrentLayoutByName(const std::string& layout_name) { return result; } +void KeyboardEvdev::FlushInput(base::OnceClosure closure) { + // Post a task behind any pending key releases in the message loop + // FIFO. This ensures there's no spurious repeats during periods of UI + // thread jank. + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(closure)); +} + void KeyboardEvdev::UpdateModifier(int modifier_flag, bool down) { if (modifier_flag == EF_NONE) return; @@ -135,62 +132,6 @@ void KeyboardEvdev::RefreshModifiers() { } } -void KeyboardEvdev::UpdateKeyRepeat(unsigned int key, - bool down, - bool suppress_auto_repeat, - int device_id) { - if (!auto_repeat_enabled_ || suppress_auto_repeat) - StopKeyRepeat(); - else if (key != repeat_key_ && down) - StartKeyRepeat(key, device_id); - else if (key == repeat_key_ && !down) - StopKeyRepeat(); -} - -void KeyboardEvdev::StartKeyRepeat(unsigned int key, int device_id) { - repeat_key_ = key; - repeat_device_id_ = device_id; - repeat_sequence_++; - - ScheduleKeyRepeat(repeat_delay_); -} - -void KeyboardEvdev::StopKeyRepeat() { - repeat_key_ = KEY_RESERVED; - repeat_sequence_++; -} - -void KeyboardEvdev::ScheduleKeyRepeat(const base::TimeDelta& delay) { - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(&KeyboardEvdev::OnRepeatTimeout, - weak_ptr_factory_.GetWeakPtr(), repeat_sequence_), - delay); -} - -void KeyboardEvdev::OnRepeatTimeout(unsigned int sequence) { - if (repeat_sequence_ != sequence) - return; - - // Post a task behind any pending key releases in the message loop - // FIFO. This ensures there's no spurious repeats during periods of UI - // thread jank. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(&KeyboardEvdev::OnRepeatCommit, - weak_ptr_factory_.GetWeakPtr(), repeat_sequence_)); -} - -void KeyboardEvdev::OnRepeatCommit(unsigned int sequence) { - if (repeat_sequence_ != sequence) - return; - - DispatchKey(repeat_key_, true /* down */, true /* repeat */, - EventTimeForNow(), repeat_device_id_); - - ScheduleKeyRepeat(repeat_interval_); -} - void KeyboardEvdev::DispatchKey(unsigned int key, bool down, bool repeat, diff --git a/chromium/ui/events/ozone/evdev/keyboard_evdev.h b/chromium/ui/events/ozone/evdev/keyboard_evdev.h index 4a6f59bf11d..eba0dc0fe07 100644 --- a/chromium/ui/events/ozone/evdev/keyboard_evdev.h +++ b/chromium/ui/events/ozone/evdev/keyboard_evdev.h @@ -15,6 +15,7 @@ #include "ui/events/ozone/evdev/event_device_util.h" #include "ui/events/ozone/evdev/event_dispatch_callback.h" #include "ui/events/ozone/evdev/events_ozone_evdev_export.h" +#include "ui/events/ozone/keyboard/event_auto_repeat_handler.h" #include "ui/events/ozone/layout/keyboard_layout_engine.h" namespace ui { @@ -28,7 +29,8 @@ enum class DomCode; // one logical keyboard, applying modifiers & implementing key repeat. // // It also currently also applies the layout. -class EVENTS_OZONE_EVDEV_EXPORT KeyboardEvdev { +class EVENTS_OZONE_EVDEV_EXPORT KeyboardEvdev + : public EventAutoRepeatHandler::Delegate { public: KeyboardEvdev(EventModifiers* modifiers, KeyboardLayoutEngine* keyboard_layout_engine, @@ -65,20 +67,14 @@ class EVENTS_OZONE_EVDEV_EXPORT KeyboardEvdev { void UpdateModifier(int modifier_flag, bool down); void RefreshModifiers(); void UpdateCapsLockLed(); - void UpdateKeyRepeat(unsigned int key, - bool down, - bool suppress_auto_repeat, - int device_id); - void StartKeyRepeat(unsigned int key, int device_id); - void StopKeyRepeat(); - void ScheduleKeyRepeat(const base::TimeDelta& delay); - void OnRepeatTimeout(unsigned int sequence); - void OnRepeatCommit(unsigned int sequence); + + // EventAutoRepeatHandler::Delegate + void FlushInput(base::OnceClosure closure) override; void DispatchKey(unsigned int key, bool down, bool repeat, base::TimeTicks timestamp, - int device_id); + int device_id) override; // Aggregated key state. There is only one bit of state per key; we do not // attempt to count presses of the same key on multiple keyboards. @@ -98,13 +94,8 @@ class EVENTS_OZONE_EVDEV_EXPORT KeyboardEvdev { // Shared layout engine. KeyboardLayoutEngine* keyboard_layout_engine_; - // Key repeat state. - bool auto_repeat_enabled_ = true; - unsigned int repeat_key_ = KEY_RESERVED; - unsigned int repeat_sequence_ = 0; - int repeat_device_id_ = 0; - base::TimeDelta repeat_delay_; - base::TimeDelta repeat_interval_; + // Key repeat handler. + EventAutoRepeatHandler auto_repeat_handler_; base::WeakPtrFactory<KeyboardEvdev> weak_ptr_factory_; diff --git a/chromium/ui/events/ozone/evdev/touch_evdev_types.h b/chromium/ui/events/ozone/evdev/touch_evdev_types.h index 22d2345148b..cf0c58e83e2 100644 --- a/chromium/ui/events/ozone/evdev/touch_evdev_types.h +++ b/chromium/ui/events/ozone/evdev/touch_evdev_types.h @@ -58,12 +58,7 @@ struct EVENTS_OZONE_EVDEV_EXPORT InProgressTouchEvdev { float tilt_y = 0; ui::EventPointerType reported_tool_type = ui::EventPointerType::POINTER_TYPE_TOUCH; - - struct ButtonState { - bool down = false; - bool changed = false; - }; - ButtonState btn_stylus; + bool stylus_button = false; }; } // namespace ui diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc index 33455714618..7141819c6d4 100644 --- a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc +++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.cc @@ -228,6 +228,7 @@ void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) { MT_TOOL_FINGER); events_[i].tool_type = tool_type; events_[i].major = touch_major; + events_[i].stylus_button = false; if (events_[i].cancelled) cancelled_state = true; } @@ -264,8 +265,6 @@ void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) { } void TouchEventConverterEvdev::Reinitialize() { - ReleaseButtons(); - EventDeviceInfo info; if (!info.Initialize(fd_, path_)) { LOG(ERROR) << "Failed to synchronize state for touch device: " @@ -297,7 +296,6 @@ void TouchEventConverterEvdev::OnEnabled() { void TouchEventConverterEvdev::OnDisabled() { ReleaseTouches(); - ReleaseButtons(); if (enable_palm_suppression_callback_) { enable_palm_suppression_callback_.Run(false); } @@ -391,8 +389,7 @@ void TouchEventConverterEvdev::EmulateMultitouchEvent( void TouchEventConverterEvdev::ProcessKey(const input_event& input) { switch (input.code) { case BTN_STYLUS: - events_[current_slot_].btn_stylus.down = input.value; - events_[current_slot_].btn_stylus.changed = true; + events_[current_slot_].stylus_button = input.value; events_[current_slot_].altered = true; break; case BTN_TOOL_PEN: @@ -520,7 +517,7 @@ void TouchEventConverterEvdev::ReportTouchEvent( ui::PointerDetails details(event.reported_tool_type, /* pointer_id*/ 0, event.radius_x, event.radius_y, event.pressure, /* twist */ 0, event.tilt_x, event.tilt_y); - int flags = event.btn_stylus.down ? ui::EventFlags::EF_LEFT_MOUSE_BUTTON : 0; + int flags = event.stylus_button ? ui::EventFlags::EF_LEFT_MOUSE_BUTTON : 0; dispatcher_->DispatchTouchEvent(TouchEventParams( input_device_.id, event.slot, event_type, gfx::PointF(event.x, event.y), details, timestamp, flags)); @@ -587,7 +584,6 @@ void TouchEventConverterEvdev::ReportEvents(base::TimeTicks timestamp) { event->was_touching = event->touching; event->was_delayed = event->delayed; event->altered = false; - event->btn_stylus.changed = false; } } @@ -609,6 +605,7 @@ void TouchEventConverterEvdev::UpdateTrackingId(int slot, int tracking_id) { void TouchEventConverterEvdev::ReleaseTouches() { for (size_t slot = 0; slot < events_.size(); slot++) { + events_[slot].stylus_button = false; events_[slot].cancelled = true; events_[slot].altered = true; } @@ -616,19 +613,6 @@ void TouchEventConverterEvdev::ReleaseTouches() { ReportEvents(EventTimeForNow()); } -void TouchEventConverterEvdev::ReleaseButtons() { - for (size_t slot = 0; slot < events_.size(); slot++) { - InProgressTouchEvdev* event = &events_[slot]; - - if (event->btn_stylus.down) { - event->btn_stylus.down = false; - event->btn_stylus.changed = true; - } - } - - ReportEvents(EventTimeForNow()); -} - float TouchEventConverterEvdev::ScalePressure(int32_t value) { float pressure = value - pressure_min_; if (pressure_max_ - pressure_min_) diff --git a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h index 905902448fa..7e5c6c0756e 100644 --- a/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h +++ b/chromium/ui/events/ozone/evdev/touch_event_converter_evdev.h @@ -90,7 +90,6 @@ class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev void UpdateTrackingId(int slot, int tracking_id); void ReleaseTouches(); - void ReleaseButtons(); void CancelAllTouches(); bool IsPalm(const InProgressTouchEvdev& touch); // Normalize pressure value to [0, 1]. diff --git a/chromium/ui/events/ozone/keyboard/event_auto_repeat_handler.cc b/chromium/ui/events/ozone/keyboard/event_auto_repeat_handler.cc new file mode 100644 index 00000000000..3eea5cf5efa --- /dev/null +++ b/chromium/ui/events/ozone/keyboard/event_auto_repeat_handler.cc @@ -0,0 +1,103 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/ozone/keyboard/event_auto_repeat_handler.h" + +#include "base/threading/thread_task_runner_handle.h" +#include "ui/events/base_event_utils.h" + +namespace ui { + +namespace { + +constexpr int kRepeatDelayMs = 500; +constexpr int kRepeatIntervalMs = 50; + +} // namespace + +EventAutoRepeatHandler::EventAutoRepeatHandler(Delegate* delegate) + : repeat_delay_(base::TimeDelta::FromMilliseconds(kRepeatDelayMs)), + repeat_interval_(base::TimeDelta::FromMilliseconds(kRepeatIntervalMs)), + delegate_(delegate), + weak_ptr_factory_(this) { + DCHECK(delegate_); +} + +EventAutoRepeatHandler::~EventAutoRepeatHandler() {} + +bool EventAutoRepeatHandler::IsAutoRepeatEnabled() { + return auto_repeat_enabled_; +} + +void EventAutoRepeatHandler::SetAutoRepeatEnabled(bool enabled) { + auto_repeat_enabled_ = enabled; +} + +void EventAutoRepeatHandler::SetAutoRepeatRate( + const base::TimeDelta& delay, + const base::TimeDelta& interval) { + repeat_delay_ = delay; + repeat_interval_ = interval; +} + +void EventAutoRepeatHandler::GetAutoRepeatRate(base::TimeDelta* delay, + base::TimeDelta* interval) { + *delay = repeat_delay_; + *interval = repeat_interval_; +} + +void EventAutoRepeatHandler::UpdateKeyRepeat(unsigned int key, + bool down, + bool suppress_auto_repeat, + int device_id) { + if (!auto_repeat_enabled_ || suppress_auto_repeat) + StopKeyRepeat(); + else if (key != repeat_key_ && down) + StartKeyRepeat(key, device_id); + else if (key == repeat_key_ && !down) + StopKeyRepeat(); +} + +void EventAutoRepeatHandler::StartKeyRepeat(unsigned int key, int device_id) { + repeat_key_ = key; + repeat_device_id_ = device_id; + repeat_sequence_++; + + ScheduleKeyRepeat(repeat_delay_); +} + +void EventAutoRepeatHandler::StopKeyRepeat() { + repeat_key_ = KEY_RESERVED; + repeat_sequence_++; +} + +void EventAutoRepeatHandler::ScheduleKeyRepeat(const base::TimeDelta& delay) { + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&EventAutoRepeatHandler::OnRepeatTimeout, + weak_ptr_factory_.GetWeakPtr(), repeat_sequence_), + delay); +} + +void EventAutoRepeatHandler::OnRepeatTimeout(unsigned int sequence) { + if (repeat_sequence_ != sequence) + return; + + base::OnceClosure commit = + base::BindOnce(&EventAutoRepeatHandler::OnRepeatCommit, + weak_ptr_factory_.GetWeakPtr(), repeat_sequence_); + delegate_->FlushInput(std::move(commit)); +} + +void EventAutoRepeatHandler::OnRepeatCommit(unsigned int sequence) { + if (repeat_sequence_ != sequence) + return; + + delegate_->DispatchKey(repeat_key_, true /* down */, true /* repeat */, + EventTimeForNow(), repeat_device_id_); + + ScheduleKeyRepeat(repeat_interval_); +} + +} // namespace ui diff --git a/chromium/ui/events/ozone/keyboard/event_auto_repeat_handler.h b/chromium/ui/events/ozone/keyboard/event_auto_repeat_handler.h new file mode 100644 index 00000000000..f95430b3730 --- /dev/null +++ b/chromium/ui/events/ozone/keyboard/event_auto_repeat_handler.h @@ -0,0 +1,71 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_OZONE_KEYBOARD_EVENT_AUTO_REPEAT_HANDLER_H +#define UI_EVENTS_OZONE_KEYBOARD_EVENT_AUTO_REPEAT_HANDLER_H + +#include <linux/input.h> + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "ui/events/ozone/events_ozone_export.h" + +namespace ui { + +class EVENTS_OZONE_EXPORT EventAutoRepeatHandler { + public: + class Delegate { + public: + // Gives the client a chance to flush the input queue + // cancelling possible spurios auto repeat keys. + // Useful under janky situations. + virtual void FlushInput(base::OnceClosure closure) = 0; + virtual void DispatchKey(unsigned int key, + bool down, + bool repeat, + base::TimeTicks timestamp, + int device_id) = 0; + }; + + explicit EventAutoRepeatHandler(Delegate* delegate); + ~EventAutoRepeatHandler(); + + void UpdateKeyRepeat(unsigned int key, + bool down, + bool suppress_auto_repeat, + int device_id); + void StopKeyRepeat(); + + // Configuration for key repeat. + bool IsAutoRepeatEnabled(); + void SetAutoRepeatEnabled(bool enabled); + void SetAutoRepeatRate(const base::TimeDelta& delay, + const base::TimeDelta& interval); + void GetAutoRepeatRate(base::TimeDelta* delay, base::TimeDelta* interval); + + private: + void StartKeyRepeat(unsigned int key, int device_id); + void ScheduleKeyRepeat(const base::TimeDelta& delay); + void OnRepeatTimeout(unsigned int sequence); + void OnRepeatCommit(unsigned int sequence); + + // Key repeat state. + bool auto_repeat_enabled_ = true; + unsigned int repeat_key_ = KEY_RESERVED; + unsigned int repeat_sequence_ = 0; + int repeat_device_id_ = 0; + base::TimeDelta repeat_delay_; + base::TimeDelta repeat_interval_; + + Delegate* delegate_ = nullptr; + + base::WeakPtrFactory<EventAutoRepeatHandler> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(EventAutoRepeatHandler); +}; + +} // namespace ui + +#endif // UI_EVENTS_OZONE_KEYBOARD_EVENT_AUTO_REPEAT_HANDLER_H diff --git a/chromium/ui/events/win/keyboard_hook_win.cc b/chromium/ui/events/win/keyboard_hook_win.cc new file mode 100644 index 00000000000..8f92cd5ec72 --- /dev/null +++ b/chromium/ui/events/win/keyboard_hook_win.cc @@ -0,0 +1,131 @@ +// Copyright 2018 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/events/keyboard_hook_base.h" + +#include <utility> + +#include <windows.h> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/optional.h" +#include "base/threading/thread_checker.h" +#include "ui/events/event.h" + +namespace ui { + +namespace { + +// These keys interfere with the return value of ::GetKeyState() as observing +// them directly in LowLevelKeyboardProc will cause their key combinations to be +// ignored. As an example, the KeyF event in an Alt + F combination will result +// in a missing alt-down flag. Since a regular application can successfully +// receive these keys without using LowLevelKeyboardProc, they can be ignored. +bool IsOSReservedKey(DWORD vk) { + return vk == VK_SHIFT || vk == VK_LSHIFT || vk == VK_RSHIFT || + vk == VK_CONTROL || vk == VK_LCONTROL || vk == VK_RCONTROL || + vk == VK_MENU || vk == VK_LMENU || vk == VK_RMENU || vk == VK_LWIN || + vk == VK_RWIN || vk == VK_CAPITAL || vk == VK_NUMLOCK || + vk == VK_SCROLL; +} + +class KeyboardHookWin : public KeyboardHookBase { + public: + KeyboardHookWin(base::Optional<base::flat_set<int>> native_key_codes, + KeyEventCallback callback); + ~KeyboardHookWin() override; + + bool Register(); + + private: + static LRESULT CALLBACK ProcessKeyEvent(int code, + WPARAM w_param, + LPARAM l_param); + static KeyboardHookWin* instance_; + + THREAD_CHECKER(thread_checker_); + + HHOOK hook_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(KeyboardHookWin); +}; + +// static +KeyboardHookWin* KeyboardHookWin::instance_ = nullptr; + +KeyboardHookWin::KeyboardHookWin(base::Optional<base::flat_set<int>> key_codes, + KeyEventCallback callback) + : KeyboardHookBase(std::move(key_codes), std::move(callback)) {} + +KeyboardHookWin::~KeyboardHookWin() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + DCHECK_EQ(instance_, this); + instance_ = nullptr; + + if (!UnhookWindowsHookEx(hook_)) + DPLOG(ERROR) << "UnhookWindowsHookEx failed"; +} + +bool KeyboardHookWin::Register() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // Only one instance of this class can be registered at a time. + DCHECK(!instance_); + instance_ = this; + + // Per MSDN this Hook procedure will be called in the context of the thread + // which installed it. + hook_ = SetWindowsHookEx( + WH_KEYBOARD_LL, + reinterpret_cast<HOOKPROC>(&KeyboardHookWin::ProcessKeyEvent), + /*hMod=*/nullptr, + /*dwThreadId=*/0); + DPLOG_IF(ERROR, !hook_) << "SetWindowsHookEx failed"; + + return hook_ != nullptr; +} + +// static +LRESULT CALLBACK KeyboardHookWin::ProcessKeyEvent(int code, + WPARAM w_param, + LPARAM l_param) { + // If there is an error unhooking, this method could be called with a null + // |instance_|. Ensure we have a valid instance and that |code| is correct + // before proceeding. + if (!instance_ || code != HC_ACTION) + return CallNextHookEx(nullptr, code, w_param, l_param); + + DCHECK_CALLED_ON_VALID_THREAD(instance_->thread_checker_); + + KBDLLHOOKSTRUCT* ll_hooks = reinterpret_cast<KBDLLHOOKSTRUCT*>(l_param); + if (!IsOSReservedKey(ll_hooks->vkCode) && + instance_->ShouldCaptureKeyEvent(ll_hooks->vkCode)) { + MSG msg = {nullptr, w_param, ll_hooks->vkCode, + (ll_hooks->scanCode << 16) | (ll_hooks->flags & 0xFFFF), + ll_hooks->time}; + instance_->ForwardCapturedKeyEvent(std::make_unique<KeyEvent>(msg)); + return 1; + } + return CallNextHookEx(nullptr, code, w_param, l_param); +} + +} // namespace + +// static +std::unique_ptr<KeyboardHook> KeyboardHook::Create( + base::Optional<base::flat_set<int>> key_codes, + KeyEventCallback callback) { + std::unique_ptr<KeyboardHookWin> keyboard_hook = + std::make_unique<KeyboardHookWin>(std::move(key_codes), + std::move(callback)); + + if (!keyboard_hook->Register()) + return nullptr; + + return keyboard_hook; +} + +} // namespace ui diff --git a/chromium/ui/events/x/events_x_unittest.cc b/chromium/ui/events/x/events_x_unittest.cc index fa0291e44b1..0022b7f180f 100644 --- a/chromium/ui/events/x/events_x_unittest.cc +++ b/chromium/ui/events/x/events_x_unittest.cc @@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/devices/x11/device_data_manager_x11.h" @@ -548,30 +549,22 @@ base::TimeTicks TimeTicksFromMillis(int64_t millis) { return base::TimeTicks() + base::TimeDelta::FromMilliseconds(millis); } -class MockTickClock : public base::TickClock { - public: - explicit MockTickClock(int64_t milliseconds) - : ticks_(TimeTicksFromMillis(milliseconds)) {} - base::TimeTicks NowTicks() override { return ticks_; } - - private: - base::TimeTicks ticks_; -}; - } // namespace TEST_F(EventsXTest, TimestampRolloverAndAdjustWhenDecreasing) { XEvent event; InitButtonEvent(&event, true, gfx::Point(5, 10), 1, 0); - ResetTimestampRolloverCountersForTesting( - std::make_unique<MockTickClock>(0x100000001)); + base::SimpleTestTickClock clock; + clock.SetNowTicks(TimeTicksFromMillis(0x100000001)); + SetEventTickClockForTesting(&clock); + ResetTimestampRolloverCountersForTesting(); event.xbutton.time = 0xFFFFFFFF; EXPECT_EQ(TimeTicksFromMillis(0xFFFFFFFF), ui::EventTimeFromNative(&event)); - ResetTimestampRolloverCountersForTesting( - std::make_unique<MockTickClock>(0x100000007)); + clock.SetNowTicks(TimeTicksFromMillis(0x100000007)); + ResetTimestampRolloverCountersForTesting(); event.xbutton.time = 3; EXPECT_EQ(TimeTicksFromMillis(0x100000000 + 3), @@ -582,15 +575,18 @@ TEST_F(EventsXTest, NoTimestampRolloverWhenMonotonicIncreasing) { XEvent event; InitButtonEvent(&event, true, gfx::Point(5, 10), 1, 0); - ResetTimestampRolloverCountersForTesting(std::make_unique<MockTickClock>(10)); + base::SimpleTestTickClock clock; + clock.SetNowTicks(TimeTicksFromMillis(10)); + SetEventTickClockForTesting(&clock); + ResetTimestampRolloverCountersForTesting(); event.xbutton.time = 6; EXPECT_EQ(TimeTicksFromMillis(6), ui::EventTimeFromNative(&event)); event.xbutton.time = 7; EXPECT_EQ(TimeTicksFromMillis(7), ui::EventTimeFromNative(&event)); - ResetTimestampRolloverCountersForTesting( - std::make_unique<MockTickClock>(0x100000005)); + clock.SetNowTicks(TimeTicksFromMillis(0x100000005)); + ResetTimestampRolloverCountersForTesting(); event.xbutton.time = 0xFFFFFFFF; EXPECT_EQ(TimeTicksFromMillis(0xFFFFFFFF), ui::EventTimeFromNative(&event)); diff --git a/chromium/ui/events/x/events_x_utils.cc b/chromium/ui/events/x/events_x_utils.cc index 4106f41d517..6ad9ba9e9aa 100644 --- a/chromium/ui/events/x/events_x_utils.cc +++ b/chromium/ui/events/x/events_x_utils.cc @@ -635,6 +635,7 @@ int GetChangedMouseButtonFlagsFromXEvent(const XEvent& xev) { default: break; } + break; } default: break; @@ -818,11 +819,9 @@ bool IsAltPressed() { return XModifierStateWatcher::GetInstance()->state() & Mod1Mask; } -void ResetTimestampRolloverCountersForTesting( - std::unique_ptr<base::TickClock> tick_clock) { +void ResetTimestampRolloverCountersForTesting() { g_last_seen_timestamp_ms = 0; g_rollover_ms = 0; - SetEventTickClockForTesting(std::move(tick_clock)); } } // namespace ui diff --git a/chromium/ui/events/x/events_x_utils.h b/chromium/ui/events/x/events_x_utils.h index 4d5e754441a..64814e87715 100644 --- a/chromium/ui/events/x/events_x_utils.h +++ b/chromium/ui/events/x/events_x_utils.h @@ -89,8 +89,7 @@ EVENTS_X_EXPORT bool GetFlingDataFromXEvent(const XEvent& xev, // Uses the XModifierStateWatcher to determine if alt is pressed or not. EVENTS_X_EXPORT bool IsAltPressed(); -EVENTS_X_EXPORT void ResetTimestampRolloverCountersForTesting( - std::unique_ptr<base::TickClock> tick_clock = nullptr); +EVENTS_X_EXPORT void ResetTimestampRolloverCountersForTesting(); } // namespace ui diff --git a/chromium/ui/events/x/keyboard_hook_posix.cc b/chromium/ui/events/x/keyboard_hook_posix.cc new file mode 100644 index 00000000000..17c59bdcd2f --- /dev/null +++ b/chromium/ui/events/x/keyboard_hook_posix.cc @@ -0,0 +1,43 @@ +// Copyright 2018 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/events/keyboard_hook_base.h" + +#include "base/callback.h" +#include "base/macros.h" +#include "base/optional.h" +#include "ui/events/event.h" + +namespace ui { + +namespace { + +// A default implementation for POSIX platforms. +class KeyboardHookPosix : public KeyboardHookBase { + public: + KeyboardHookPosix(base::Optional<base::flat_set<int>> native_key_codes, + KeyEventCallback callback); + ~KeyboardHookPosix() override; + + private: + DISALLOW_COPY_AND_ASSIGN(KeyboardHookPosix); +}; + +KeyboardHookPosix::KeyboardHookPosix( + base::Optional<base::flat_set<int>> key_codes, + KeyEventCallback callback) + : KeyboardHookBase(std::move(key_codes), std::move(callback)) {} + +KeyboardHookPosix::~KeyboardHookPosix() = default; + +} // namespace + +// static +std::unique_ptr<KeyboardHook> KeyboardHook::Create( + base::Optional<base::flat_set<int>> native_key_codes, + KeyboardHook::KeyEventCallback callback) { + return nullptr; +} + +} // namespace ui diff --git a/chromium/ui/gfx/BUILD.gn b/chromium/ui/gfx/BUILD.gn index 580b686cf4b..9c38caf3ba8 100644 --- a/chromium/ui/gfx/BUILD.gn +++ b/chromium/ui/gfx/BUILD.gn @@ -172,8 +172,6 @@ jumbo_component("gfx") { "utf16_indexing.h", "vsync_provider.cc", "vsync_provider.h", - "win/direct_manipulation.cc", - "win/direct_manipulation.h", "win/direct_write.cc", "win/direct_write.h", "win/hwnd_util.cc", @@ -624,6 +622,12 @@ static_library("test_support") { "//ui/gfx/geometry", ] + if (!is_ios) { + sources += [ "render_text_test_api.h" ] + + deps += [ "//third_party:freetype_harfbuzz" ] + } + if (is_linux) { deps += [ "//third_party/fontconfig" ] } diff --git a/chromium/ui/gfx/animation/slide_animation.h b/chromium/ui/gfx/animation/slide_animation.h index 221c8ffaba7..4105970d196 100644 --- a/chromium/ui/gfx/animation/slide_animation.h +++ b/chromium/ui/gfx/animation/slide_animation.h @@ -55,9 +55,11 @@ class ANIMATION_EXPORT SlideAnimation : public LinearAnimation { virtual void Reset(double value); // Begin a showing animation or reverse a hiding animation in progress. + // Animates |GetCurrentValue()| towards 1. virtual void Show(); // Begin a hiding animation or reverse a showing animation in progress. + // Animates |GetCurrentValue()| towards 0. virtual void Hide(); // Sets the time a slide will take. Note that this isn't actually diff --git a/chromium/ui/gfx/buffer_format_util.cc b/chromium/ui/gfx/buffer_format_util.cc index 9c4837029ef..f72941f5258 100644 --- a/chromium/ui/gfx/buffer_format_util.cc +++ b/chromium/ui/gfx/buffer_format_util.cc @@ -11,17 +11,26 @@ namespace gfx { namespace { -const BufferFormat kBufferFormats[] = { - BufferFormat::ATC, BufferFormat::ATCIA, - BufferFormat::DXT1, BufferFormat::DXT5, - BufferFormat::ETC1, BufferFormat::R_8, - BufferFormat::R_16, BufferFormat::RG_88, - BufferFormat::BGR_565, BufferFormat::RGBA_4444, - BufferFormat::RGBX_8888, BufferFormat::RGBA_8888, - BufferFormat::BGRX_8888, BufferFormat::BGRX_1010102, - BufferFormat::BGRA_8888, BufferFormat::RGBA_F16, - BufferFormat::UYVY_422, BufferFormat::YUV_420_BIPLANAR, - BufferFormat::YVU_420}; +const BufferFormat kBufferFormats[] = {BufferFormat::ATC, + BufferFormat::ATCIA, + BufferFormat::DXT1, + BufferFormat::DXT5, + BufferFormat::ETC1, + BufferFormat::R_8, + BufferFormat::R_16, + BufferFormat::RG_88, + BufferFormat::BGR_565, + BufferFormat::RGBA_4444, + BufferFormat::RGBX_8888, + BufferFormat::RGBA_8888, + BufferFormat::BGRX_8888, + BufferFormat::BGRX_1010102, + BufferFormat::RGBX_1010102, + BufferFormat::BGRA_8888, + BufferFormat::RGBA_F16, + BufferFormat::UYVY_422, + BufferFormat::YUV_420_BIPLANAR, + BufferFormat::YVU_420}; static_assert(arraysize(kBufferFormats) == (static_cast<int>(BufferFormat::LAST) + 1), @@ -63,6 +72,7 @@ bool RowSizeForBufferFormatChecked( return true; case BufferFormat::BGRX_8888: case BufferFormat::BGRX_1010102: + case BufferFormat::RGBX_1010102: case BufferFormat::RGBX_8888: case BufferFormat::RGBA_8888: case BufferFormat::BGRA_8888: @@ -113,6 +123,7 @@ size_t NumberOfPlanesForBufferFormat(BufferFormat format) { case BufferFormat::RGBA_8888: case BufferFormat::BGRX_8888: case BufferFormat::BGRX_1010102: + case BufferFormat::RGBX_1010102: case BufferFormat::BGRA_8888: case BufferFormat::RGBA_F16: case BufferFormat::UYVY_422: @@ -142,6 +153,7 @@ size_t SubsamplingFactorForBufferFormat(BufferFormat format, size_t plane) { case BufferFormat::RGBA_8888: case BufferFormat::BGRX_8888: case BufferFormat::BGRX_1010102: + case BufferFormat::RGBX_1010102: case BufferFormat::BGRA_8888: case BufferFormat::RGBA_F16: case BufferFormat::UYVY_422: @@ -216,6 +228,7 @@ size_t BufferOffsetForBufferFormat(const Size& size, case BufferFormat::RGBA_8888: case BufferFormat::BGRX_8888: case BufferFormat::BGRX_1010102: + case BufferFormat::RGBX_1010102: case BufferFormat::BGRA_8888: case BufferFormat::RGBA_F16: case BufferFormat::UYVY_422: @@ -267,6 +280,8 @@ const char* BufferFormatToString(BufferFormat format) { return "BGRX_8888"; case BufferFormat::BGRX_1010102: return "BGRX_1010102"; + case BufferFormat::RGBX_1010102: + return "RGBX_1010102"; case BufferFormat::BGRA_8888: return "BGRA_8888"; case BufferFormat::RGBA_F16: diff --git a/chromium/ui/gfx/buffer_types.h b/chromium/ui/gfx/buffer_types.h index 53f4518d498..cd16f2ee83f 100644 --- a/chromium/ui/gfx/buffer_types.h +++ b/chromium/ui/gfx/buffer_types.h @@ -26,6 +26,7 @@ enum class BufferFormat { RGBA_8888, BGRX_8888, BGRX_1010102, + RGBX_1010102, BGRA_8888, RGBA_F16, YVU_420, diff --git a/chromium/ui/gfx/canvas_unittest.cc b/chromium/ui/gfx/canvas_unittest.cc index 837518a1aab..25bc3148741 100644 --- a/chromium/ui/gfx/canvas_unittest.cc +++ b/chromium/ui/gfx/canvas_unittest.cc @@ -72,12 +72,11 @@ TEST_F(CanvasTest, ClipRectWithScaling) { } // Line height is only supported on Skia. -#if defined(OS_MACOSX) || defined(OS_ANDROID) +#if defined(OS_ANDROID) #define MAYBE_StringSizeWithLineHeight DISABLED_StringSizeWithLineHeight #else #define MAYBE_StringSizeWithLineHeight StringSizeWithLineHeight #endif - TEST_F(CanvasTest, MAYBE_StringSizeWithLineHeight) { gfx::Size one_line_size = SizeStringInt("Q", 0, 0); gfx::Size four_line_size = SizeStringInt("Q\nQ\nQ\nQ", 1000000, 1000); diff --git a/chromium/ui/gfx/canvas_unittest_mac.mm b/chromium/ui/gfx/canvas_unittest_mac.mm index 99b25708464..78d0487ceba 100644 --- a/chromium/ui/gfx/canvas_unittest_mac.mm +++ b/chromium/ui/gfx/canvas_unittest_mac.mm @@ -49,8 +49,8 @@ class CanvasTestMac : public testing::Test { float canvas_width = kReallyLargeNumber; float canvas_height = kReallyLargeNumber; - Canvas::SizeStringFloat( - text16, font_list, &canvas_width, &canvas_height, 0, 0); + Canvas::SizeStringFloat(text16, font_list, &canvas_width, &canvas_height, 0, + 0, Typesetter::NATIVE); EXPECT_NE(kReallyLargeNumber, mac_width) << "no width for " << text; EXPECT_NE(kReallyLargeNumber, mac_height) << "no height for " << text; @@ -64,10 +64,9 @@ class CanvasTestMac : public testing::Test { Font font_; }; - // Tests that Canvas' SizeStringFloat yields result consistent with a native - // implementation. -// Disabled for the typesetter migration. http://crbug.com/803354. -TEST_F(CanvasTestMac, DISABLED_StringSizeIdenticalForSkia) { +// Tests that Canvas' SizeStringFloat yields result consistent with a native +// implementation when using Typesetter::NATIVE. +TEST_F(CanvasTestMac, StringSizeIdenticalForSkia) { CompareSizes(""); CompareSizes("Foo"); CompareSizes("Longword"); @@ -80,8 +79,8 @@ TEST_F(CanvasTestMac, FractionalWidth) { float height = kReallyLargeNumber; FontList font_list; - Canvas::SizeStringFloat( - base::UTF8ToUTF16("Test"), font_list, &width, &height, 0, 0); + Canvas::SizeStringFloat(base::UTF8ToUTF16("Test"), font_list, &width, &height, + 0, 0, Typesetter::NATIVE); EXPECT_GT(width, static_cast<int>(width)); } diff --git a/chromium/ui/gfx/color_palette.h b/chromium/ui/gfx/color_palette.h index 767f2d2c18b..3c77e6a68c9 100644 --- a/chromium/ui/gfx/color_palette.h +++ b/chromium/ui/gfx/color_palette.h @@ -13,24 +13,35 @@ namespace gfx { // as a visual flag for misbehaving code. constexpr SkColor kPlaceholderColor = SK_ColorRED; -const SkColor kChromeIconGrey = SkColorSetRGB(0x5A, 0x5A, 0x5A); +constexpr SkColor kChromeIconGrey = SkColorSetRGB(0x5A, 0x5A, 0x5A); // The number refers to the shade of darkness. Each color in the MD // palette ranges from 100-900. -const SkColor kGoogleBlue300 = SkColorSetRGB(0x7B, 0xAA, 0xF7); -const SkColor kGoogleBlue500 = SkColorSetRGB(0x42, 0x85, 0xF4); -const SkColor kGoogleBlue700 = SkColorSetRGB(0x33, 0x67, 0xD6); -const SkColor kGoogleBlue900 = SkColorSetRGB(0x1C, 0x3A, 0xA9); -const SkColor kGoogleRed300 = SkColorSetRGB(0xE6, 0x7C, 0x73); -const SkColor kGoogleRed700 = SkColorSetRGB(0xC5, 0x39, 0x29); -const SkColor kGoogleGreen300 = SkColorSetRGB(0x57, 0xBB, 0x8A); -const SkColor kGoogleGreen700 = SkColorSetRGB(0x0B, 0x80, 0x43); -const SkColor kGoogleYellow300 = SkColorSetRGB(0xF7, 0xCB, 0x4D); -const SkColor kGoogleYellow700 = SkColorSetRGB(0xF0, 0x93, 0x00); +constexpr SkColor kGoogleBlue300 = SkColorSetRGB(0x8A, 0xB4, 0xF8); +constexpr SkColor kGoogleBlue500 = SkColorSetRGB(0x42, 0x85, 0xF4); +constexpr SkColor kGoogleBlue600 = SkColorSetRGB(0x1A, 0x73, 0xE8); +constexpr SkColor kGoogleBlue700 = SkColorSetRGB(0x19, 0x67, 0xD2); +constexpr SkColor kGoogleBlue900 = SkColorSetRGB(0x17, 0x4E, 0xA6); +constexpr SkColor kGoogleRed300 = SkColorSetRGB(0xF2, 0x8B, 0xB2); +constexpr SkColor kGoogleRed600 = SkColorSetRGB(0xD9, 0x30, 0x25); +constexpr SkColor kGoogleRed700 = SkColorSetRGB(0xC5, 0x22, 0x1F); +constexpr SkColor kGoogleRed800 = SkColorSetRGB(0xB3, 0x14, 0x12); +constexpr SkColor kGoogleRedDark600 = SkColorSetRGB(0xD3, 0x3B, 0x30); +constexpr SkColor kGoogleRedDark800 = SkColorSetRGB(0xB4, 0x1B, 0x1A); +constexpr SkColor kGoogleGreen300 = SkColorSetRGB(0x81, 0xC9, 0x95); +constexpr SkColor kGoogleGreen700 = SkColorSetRGB(0x18, 0x80, 0x38); +constexpr SkColor kGoogleYellow300 = SkColorSetRGB(0xFD, 0xD6, 0x63); +constexpr SkColor kGoogleYellow700 = SkColorSetRGB(0xF2, 0x99, 0x00); +constexpr SkColor kGoogleYellow900 = SkColorSetRGB(0xE3, 0x74, 0x00); +constexpr SkColor kGoogleGrey100 = SkColorSetRGB(0xF1, 0xF3, 0xF4); +constexpr SkColor kGoogleGrey400 = SkColorSetRGB(0xBD, 0xC1, 0xC6); +constexpr SkColor kGoogleGrey700 = SkColorSetRGB(0x5F, 0x63, 0x68); +constexpr SkColor kGoogleGrey800 = SkColorSetRGB(0x3C, 0x40, 0x43); +constexpr SkColor kGoogleGrey900 = SkColorSetRGB(0x20, 0x21, 0x24); // An alpha value for designating a control's disabled state. In specs this is // sometimes listed as 0.38a. -const SkAlpha kDisabledControlAlpha = 0x61; +constexpr SkAlpha kDisabledControlAlpha = 0x61; } // namespace gfx diff --git a/chromium/ui/gfx/color_space.cc b/chromium/ui/gfx/color_space.cc index 1c79c47e5c9..77458c930c6 100644 --- a/chromium/ui/gfx/color_space.cc +++ b/chromium/ui/gfx/color_space.cc @@ -8,6 +8,7 @@ #include <map> #include <sstream> +#include "base/atomic_sequence_num.h" #include "base/containers/mru_cache.h" #include "base/lazy_instance.h" #include "base/synchronization/lock.h" @@ -21,6 +22,8 @@ namespace gfx { namespace { +base::AtomicSequenceNumber g_color_space_id; + // See comments in ToSkColorSpace about this cache. This cache may only be // accessed while holding g_sk_color_space_cache_lock. static const size_t kMaxCachedSkColorSpaces = 16; @@ -183,6 +186,11 @@ ColorSpace ColorSpace::CreateREC709() { RangeID::LIMITED); } +// static +int ColorSpace::GetNextId() { + return g_color_space_id.GetNext(); +} + bool ColorSpace::operator==(const ColorSpace& other) const { if (primaries_ != other.primaries_ || transfer_ != other.transfer_ || matrix_ != other.matrix_ || range_ != other.range_ || diff --git a/chromium/ui/gfx/color_space.h b/chromium/ui/gfx/color_space.h index 8e6cff172b1..561cbc74e2a 100644 --- a/chromium/ui/gfx/color_space.h +++ b/chromium/ui/gfx/color_space.h @@ -152,6 +152,9 @@ class COLOR_SPACE_EXPORT ColorSpace { static ColorSpace CreateREC601(); static ColorSpace CreateREC709(); + // Generates a process global unique ID that can be used to key a color space. + static int GetNextId(); + bool operator==(const ColorSpace& other) const; bool operator!=(const ColorSpace& other) const; bool operator<(const ColorSpace& other) const; diff --git a/chromium/ui/gfx/color_transform.cc b/chromium/ui/gfx/color_transform.cc index 548a9636678..cf3aa80546e 100644 --- a/chromium/ui/gfx/color_transform.cc +++ b/chromium/ui/gfx/color_transform.cc @@ -621,9 +621,14 @@ class ColorTransformToLinear : public ColorTransformPerChannelTransferFn { " float c1 = 3424.0 / 4096.0;\n" " float c2 = (2413.0 / 4096.0) * 32.0;\n" " float c3 = (2392.0 / 4096.0) * 32.0;\n" - " v = pow(max(pow(v, 1.0 / m2) - c1, 0.0) /\n" - " (c2 - c3 * pow(v, 1.0 / m2)), 1.0 / m1);\n" - " v *= 10000.0 / 80.0;\n" + " #ifdef GL_FRAGMENT_PRECISION_HIGH\n" + " highp float v2 = v;\n" + " #else\n" + " float v2 = v;\n" + " #endif\n" + " v2 = pow(max(pow(v2, 1.0 / m2) - c1, 0.0) /\n" + " (c2 - c3 * pow(v2, 1.0 / m2)), 1.0 / m1);\n" + " v = v2 * 10000.0 / 80.0;\n" " return v;\n"; return; case ColorSpace::TransferID::SMPTEST2084_NON_HDR: diff --git a/chromium/ui/gfx/font_list_unittest.cc b/chromium/ui/gfx/font_list_unittest.cc index 0d8bda77938..e2bcf215ecd 100644 --- a/chromium/ui/gfx/font_list_unittest.cc +++ b/chromium/ui/gfx/font_list_unittest.cc @@ -299,9 +299,9 @@ TEST(FontListTest, MAYBE_Fonts_DeriveWithSizeDelta) { #endif TEST(FontListTest, MAYBE_Fonts_GetHeight_GetBaseline) { // If a font list has only one font, the height and baseline must be the same. - Font font1("Arial", 16); - ASSERT_EQ("arial", base::ToLowerASCII(font1.GetActualFontNameForTesting())); - FontList font_list1("Arial, 16px"); + Font font1("Verdana", 16); + ASSERT_EQ("verdana", base::ToLowerASCII(font1.GetActualFontNameForTesting())); + FontList font_list1("Verdana, 16px"); EXPECT_EQ(font1.GetHeight(), font_list1.GetHeight()); EXPECT_EQ(font1.GetBaseline(), font_list1.GetBaseline()); diff --git a/chromium/ui/gfx/font_names_testing.cc b/chromium/ui/gfx/font_names_testing.cc index 941852a330a..09ec558cd7b 100644 --- a/chromium/ui/gfx/font_names_testing.cc +++ b/chromium/ui/gfx/font_names_testing.cc @@ -15,7 +15,7 @@ const char kSymbolFontName[] = "Symbol"; #endif #if defined(OS_LINUX) -const char kCJKFontName[] = "Kochi Mincho"; +const char kCJKFontName[] = "IPAMincho"; #elif defined(OS_MACOSX) const char kCJKFontName[] = "Heiti SC"; #else diff --git a/chromium/ui/gfx/geometry/mojo/BUILD.gn b/chromium/ui/gfx/geometry/mojo/BUILD.gn index f6cda9d3beb..2d0e1efbcfd 100644 --- a/chromium/ui/gfx/geometry/mojo/BUILD.gn +++ b/chromium/ui/gfx/geometry/mojo/BUILD.gn @@ -10,6 +10,8 @@ mojom("mojo") { sources = [ "geometry.mojom", ] + + check_includes_blink = false } mojom("test_interfaces") { diff --git a/chromium/ui/gfx/geometry/vector2d.h b/chromium/ui/gfx/geometry/vector2d.h index 4b45667adf5..d9964532f51 100644 --- a/chromium/ui/gfx/geometry/vector2d.h +++ b/chromium/ui/gfx/geometry/vector2d.h @@ -39,6 +39,9 @@ class GFX_EXPORT Vector2d { // Subtract the components of the |other| vector from the current vector. void Subtract(const Vector2d& other); + constexpr bool operator==(const Vector2d& other) const { + return x_ == other.x_ && y_ == other.y_; + } void operator+=(const Vector2d& other) { Add(other); } void operator-=(const Vector2d& other) { Subtract(other); } @@ -70,11 +73,7 @@ class GFX_EXPORT Vector2d { int y_; }; -inline bool operator==(const Vector2d& lhs, const Vector2d& rhs) { - return lhs.x() == rhs.x() && lhs.y() == rhs.y(); -} - -inline Vector2d operator-(const Vector2d& v) { +inline constexpr Vector2d operator-(const Vector2d& v) { return Vector2d(-v.x(), -v.y()); } diff --git a/chromium/ui/gfx/geometry/vector2d_f.h b/chromium/ui/gfx/geometry/vector2d_f.h index 92f7f877531..7e40ea881fc 100644 --- a/chromium/ui/gfx/geometry/vector2d_f.h +++ b/chromium/ui/gfx/geometry/vector2d_f.h @@ -67,15 +67,15 @@ class GFX_EXPORT Vector2dF { float y_; }; -inline bool operator==(const Vector2dF& lhs, const Vector2dF& rhs) { +inline constexpr bool operator==(const Vector2dF& lhs, const Vector2dF& rhs) { return lhs.x() == rhs.x() && lhs.y() == rhs.y(); } -inline bool operator!=(const Vector2dF& lhs, const Vector2dF& rhs) { +inline constexpr bool operator!=(const Vector2dF& lhs, const Vector2dF& rhs) { return !(lhs == rhs); } -inline Vector2dF operator-(const Vector2dF& v) { +inline constexpr Vector2dF operator-(const Vector2dF& v) { return Vector2dF(-v.x(), -v.y()); } diff --git a/chromium/ui/gfx/ipc/color/BUILD.gn b/chromium/ui/gfx/ipc/color/BUILD.gn index a2e66760411..496398dd77a 100644 --- a/chromium/ui/gfx/ipc/color/BUILD.gn +++ b/chromium/ui/gfx/ipc/color/BUILD.gn @@ -19,6 +19,6 @@ jumbo_component("color") { public_deps = [ "//base", "//ipc", - "//ui/gfx:gfx", + "//ui/gfx:color_space", ] } diff --git a/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.cc b/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.cc index ead0d23554b..dc58b2a48e1 100644 --- a/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.cc +++ b/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.cc @@ -7,57 +7,64 @@ #include <string> #include "base/pickle.h" +#include "ipc/ipc_message_utils.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h" #include "ui/gfx/transform.h" -namespace { - -struct SkBitmap_Data { - // The color type for the bitmap (bits per pixel, etc). - SkColorType color_type; +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#undef UI_GFX_IPC_SKIA_GFX_SKIA_PARAM_TRAITS_MACROS_H_ +#include "ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h" +} // namespace IPC - // The alpha type for the bitmap (opaque, premul, unpremul). - SkAlphaType alpha_type; +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#undef UI_GFX_IPC_SKIA_GFX_SKIA_PARAM_TRAITS_MACROS_H_ +#include "ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h" +} // namespace IPC - // The width of the bitmap in pixels. - uint32_t width; +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#undef UI_GFX_IPC_SKIA_GFX_SKIA_PARAM_TRAITS_MACROS_H_ +#include "ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h" +} // namespace IPC - // The height of the bitmap in pixels. - uint32_t height; +namespace IPC { - void InitSkBitmapDataForTransfer(const SkBitmap& bitmap) { - const SkImageInfo& info = bitmap.info(); - color_type = info.colorType(); - alpha_type = info.alphaType(); - width = info.width(); - height = info.height(); - } +void ParamTraits<SkImageInfo>::Write(base::Pickle* m, const SkImageInfo& p) { + WriteParam(m, p.colorType()); + WriteParam(m, p.alphaType()); + WriteParam(m, p.width()); + WriteParam(m, p.height()); +} - // Returns whether |bitmap| successfully initialized. - bool InitSkBitmapFromData(SkBitmap* bitmap, - const char* pixels, - size_t pixels_size) const { - if (!bitmap->tryAllocPixels( - SkImageInfo::Make(width, height, color_type, alpha_type))) - return false; - if (pixels_size != bitmap->computeByteSize()) - return false; - memcpy(bitmap->getPixels(), pixels, pixels_size); - return true; +bool ParamTraits<SkImageInfo>::Read(const base::Pickle* m, + base::PickleIterator* iter, + SkImageInfo* r) { + SkColorType color_type; + SkAlphaType alpha_type; + uint32_t width; + uint32_t height; + if (!ReadParam(m, iter, &color_type) || !ReadParam(m, iter, &alpha_type) || + !ReadParam(m, iter, &width) || !ReadParam(m, iter, &height)) { + return false; } -}; -} // namespace + *r = SkImageInfo::Make(width, height, color_type, alpha_type); + return true; +} -namespace IPC { +void ParamTraits<SkImageInfo>::Log(const SkImageInfo& p, std::string* l) { + l->append("<SkImageInfo>"); +} void ParamTraits<SkBitmap>::Write(base::Pickle* m, const SkBitmap& p) { - size_t fixed_size = sizeof(SkBitmap_Data); - SkBitmap_Data bmp_data; - bmp_data.InitSkBitmapDataForTransfer(p); - m->WriteData(reinterpret_cast<const char*>(&bmp_data), - static_cast<int>(fixed_size)); + WriteParam(m, p.info()); size_t pixel_size = p.computeByteSize(); m->WriteData(reinterpret_cast<const char*>(p.getPixels()), static_cast<int>(pixel_size)); @@ -66,28 +73,28 @@ void ParamTraits<SkBitmap>::Write(base::Pickle* m, const SkBitmap& p) { bool ParamTraits<SkBitmap>::Read(const base::Pickle* m, base::PickleIterator* iter, SkBitmap* r) { - const char* fixed_data; - int fixed_data_size = 0; - if (!iter->ReadData(&fixed_data, &fixed_data_size) || - (fixed_data_size <= 0)) { + SkImageInfo image_info; + if (!ReadParam(m, iter, &image_info)) return false; - } - if (fixed_data_size != sizeof(SkBitmap_Data)) - return false; // Message is malformed. - const char* variable_data; - int variable_data_size = 0; - if (!iter->ReadData(&variable_data, &variable_data_size) || - (variable_data_size < 0)) { + const char* bitmap_data; + int bitmap_data_size = 0; + if (!iter->ReadData(&bitmap_data, &bitmap_data_size)) return false; - } - const SkBitmap_Data* bmp_data = - reinterpret_cast<const SkBitmap_Data*>(fixed_data); - return bmp_data->InitSkBitmapFromData(r, variable_data, variable_data_size); + // ReadData() only returns true if bitmap_data_size >= 0. + + if (!r->tryAllocPixels(image_info)) + return false; + + if (static_cast<size_t>(bitmap_data_size) != r->computeByteSize()) + return false; + memcpy(r->getPixels(), bitmap_data, bitmap_data_size); + return true; } void ParamTraits<SkBitmap>::Log(const SkBitmap& p, std::string* l) { l->append("<SkBitmap>"); + LogParam(p.info(), l); } void ParamTraits<gfx::Transform>::Write(base::Pickle* m, const param_type& p) { diff --git a/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.h b/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.h index d3acc930865..3b0d4a82cd3 100644 --- a/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.h +++ b/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits.h @@ -12,6 +12,7 @@ #include "ui/gfx/ipc/skia/gfx_skia_ipc_export.h" class SkBitmap; +struct SkImageInfo; namespace base { class Pickle; @@ -25,6 +26,16 @@ class Transform; namespace IPC { template <> +struct GFX_SKIA_IPC_EXPORT ParamTraits<SkImageInfo> { + using param_type = SkImageInfo; + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template <> struct GFX_SKIA_IPC_EXPORT ParamTraits<SkBitmap> { using param_type = SkBitmap; static void Write(base::Pickle* m, const param_type& p); diff --git a/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h b/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h new file mode 100644 index 00000000000..e48af3f0aab --- /dev/null +++ b/chromium/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h @@ -0,0 +1,16 @@ +// Copyright 2018 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_GFX_IPC_SKIA_GFX_SKIA_PARAM_TRAITS_MACROS_H_ +#define UI_GFX_IPC_SKIA_GFX_SKIA_PARAM_TRAITS_MACROS_H_ + +#include <stdint.h> + +#include "ipc/ipc_message_macros.h" +#include "third_party/skia/include/core/SkImageInfo.h" + +IPC_ENUM_TRAITS_VALIDATE(SkColorType, kLastEnum_SkColorType); +IPC_ENUM_TRAITS_VALIDATE(SkAlphaType, kLastEnum_SkAlphaType); + +#endif // UI_GFX_IPC_SKIA_GFX_SKIA_PARAM_TRAITS_MACROS_H_ diff --git a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc index b86d8efeb86..a9fd8622ef5 100644 --- a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc +++ b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc @@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/trace_event/trace_event.h" +#include "build/build_config.h" #include "ui/gfx/native_pixmap_handle.h" #if defined(OS_CHROMEOS) @@ -64,10 +65,19 @@ class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory { return format == gfx::BufferFormat::BGRX_8888 || format == gfx::BufferFormat::RGBX_8888; case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE: - return format == gfx::BufferFormat::BGRX_8888 || - format == gfx::BufferFormat::BGRA_8888 || - format == gfx::BufferFormat::RGBX_8888 || - format == gfx::BufferFormat::RGBA_8888; + return +#if defined(ARCH_CPU_X86_FAMILY) + // Currently only Intel driver (i.e. minigbm and Mesa) supports R_8 + // RG_88 and NV12. https://crbug.com/356871 + format == gfx::BufferFormat::R_8 || + format == gfx::BufferFormat::RG_88 || + format == gfx::BufferFormat::YUV_420_BIPLANAR || +#endif + + format == gfx::BufferFormat::BGRX_8888 || + format == gfx::BufferFormat::BGRA_8888 || + format == gfx::BufferFormat::RGBX_8888 || + format == gfx::BufferFormat::RGBA_8888; case gfx::BufferUsage::SCANOUT_VDA_WRITE: return false; case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: diff --git a/chromium/ui/gfx/mac/io_surface.cc b/chromium/ui/gfx/mac/io_surface.cc index 4fe0ddd3f87..bf6111f0387 100644 --- a/chromium/ui/gfx/mac/io_surface.cc +++ b/chromium/ui/gfx/mac/io_surface.cc @@ -60,6 +60,7 @@ int32_t BytesPerElement(gfx::BufferFormat format, int plane) { case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_4444: case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::YVU_420: NOTREACHED(); return 0; @@ -74,7 +75,7 @@ int32_t PixelFormat(gfx::BufferFormat format) { case gfx::BufferFormat::R_8: return 'L008'; case gfx::BufferFormat::BGRX_1010102: - return 'R10k'; + return 'l10r'; // little-endian ARGB2101010 full-range ARGB case gfx::BufferFormat::BGRA_8888: case gfx::BufferFormat::BGRX_8888: case gfx::BufferFormat::RGBA_8888: @@ -95,6 +96,9 @@ int32_t PixelFormat(gfx::BufferFormat format) { case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_4444: case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::RGBX_1010102: + // Technically RGBX_1010102 should be accepted as 'R10k', but then it won't + // be supported by CGLTexImageIOSurface2D(), so it's best to reject it here. case gfx::BufferFormat::YVU_420: NOTREACHED(); return 0; @@ -209,7 +213,7 @@ IOSurfaceRef CreateIOSurface(const gfx::Size& size, } void IOSurfaceSetColorSpace(IOSurfaceRef io_surface, - const gfx::ColorSpace& color_space) { + const ColorSpace& color_space) { // Retrieve the ICC profile data that created this profile, if it exists. ICCProfile icc_profile = ICCProfile::FromCacheMac(color_space); @@ -218,9 +222,25 @@ void IOSurfaceSetColorSpace(IOSurfaceRef io_surface, icc_profile = ICCProfile::FromParametricColorSpace(color_space.GetAsFullRangeRGB()); } - - // If that fails, we can't use this color space. if (!icc_profile.IsValid()) { + if (__builtin_available(macos 10.12, *)) { + static const ColorSpace kBt2020(ColorSpace::PrimaryID::BT2020, + ColorSpace::TransferID::SMPTEST2084, + ColorSpace::MatrixID::BT2020_NCL, + ColorSpace::RangeID::LIMITED); + if (color_space == kBt2020) { + base::ScopedCFTypeRef<CGColorSpaceRef> cg_color_space( + CGColorSpaceCreateWithName(kCGColorSpaceITUR_2020)); + DCHECK(cg_color_space); + + base::ScopedCFTypeRef<CFDataRef> cf_data_icc_profile( + CGColorSpaceCopyICCData(cg_color_space)); + DCHECK(cf_data_icc_profile); + IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"), + cf_data_icc_profile); + return; + } + } DLOG(ERROR) << "Failed to set color space for IOSurface: no ICC profile: " << color_space.ToString(); return; diff --git a/chromium/ui/gfx/mojo/buffer_types.mojom b/chromium/ui/gfx/mojo/buffer_types.mojom index b197b50cdbd..0708aeb0cd3 100644 --- a/chromium/ui/gfx/mojo/buffer_types.mojom +++ b/chromium/ui/gfx/mojo/buffer_types.mojom @@ -20,6 +20,7 @@ enum BufferFormat { RGBA_8888, BGRX_8888, BGRX_1010102, + RGBX_1010102, BGRA_8888, RGBA_F16, YVU_420, diff --git a/chromium/ui/gfx/mojo/buffer_types_struct_traits.h b/chromium/ui/gfx/mojo/buffer_types_struct_traits.h index eb83ec07149..51957398716 100644 --- a/chromium/ui/gfx/mojo/buffer_types_struct_traits.h +++ b/chromium/ui/gfx/mojo/buffer_types_struct_traits.h @@ -42,6 +42,8 @@ struct EnumTraits<gfx::mojom::BufferFormat, gfx::BufferFormat> { return gfx::mojom::BufferFormat::BGRX_8888; case gfx::BufferFormat::BGRX_1010102: return gfx::mojom::BufferFormat::BGRX_1010102; + case gfx::BufferFormat::RGBX_1010102: + return gfx::mojom::BufferFormat::RGBX_1010102; case gfx::BufferFormat::BGRA_8888: return gfx::mojom::BufferFormat::BGRA_8888; case gfx::BufferFormat::RGBA_F16: @@ -96,6 +98,9 @@ struct EnumTraits<gfx::mojom::BufferFormat, gfx::BufferFormat> { case gfx::mojom::BufferFormat::BGRX_1010102: *out = gfx::BufferFormat::BGRX_1010102; return true; + case gfx::mojom::BufferFormat::RGBX_1010102: + *out = gfx::BufferFormat::RGBX_1010102; + return true; case gfx::mojom::BufferFormat::RGBA_8888: *out = gfx::BufferFormat::RGBA_8888; return true; diff --git a/chromium/ui/gfx/mojo/ca_layer_params.mojom b/chromium/ui/gfx/mojo/ca_layer_params.mojom index bdb8ef65b2a..7bf73564354 100644 --- a/chromium/ui/gfx/mojo/ca_layer_params.mojom +++ b/chromium/ui/gfx/mojo/ca_layer_params.mojom @@ -6,13 +6,17 @@ module gfx.mojom; import "ui/gfx/geometry/mojo/geometry.mojom"; +union CALayerContent { + uint32 ca_context_id; + handle io_surface_mach_port; +}; + // gfx::CALayerParams struct CALayerParams { // TODO(676224): Use preprocessor to restrict platform-specific members to // desired platform. bool is_empty; - uint32 ca_context_id; - handle? io_surface_mach_port; + CALayerContent content; gfx.mojom.Size pixel_size; float scale_factor; }; diff --git a/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.cc b/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.cc index a2cb2a99b30..dd553996b5c 100644 --- a/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.cc +++ b/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.cc @@ -10,33 +10,48 @@ namespace mojo { -mojo::ScopedHandle -StructTraits<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams>:: - io_surface_mach_port(const gfx::CALayerParams& ca_layer_params) { +gfx::mojom::CALayerContentPtr +StructTraits<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams>::content( + const gfx::CALayerParams& ca_layer_params) { #if defined(OS_MACOSX) && !defined(OS_IOS) - return mojo::WrapMachPort(ca_layer_params.io_surface_mach_port.get()); -#else - return mojo::ScopedHandle(); + if (ca_layer_params.io_surface_mach_port) { + DCHECK(!ca_layer_params.ca_context_id); + return gfx::mojom::CALayerContent::NewIoSurfaceMachPort( + mojo::WrapMachPort(ca_layer_params.io_surface_mach_port.get())); + } #endif + return gfx::mojom::CALayerContent::NewCaContextId( + ca_layer_params.ca_context_id); } bool StructTraits<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams>::Read( gfx::mojom::CALayerParamsDataView data, gfx::CALayerParams* out) { out->is_empty = data.is_empty(); - out->ca_context_id = data.ca_context_id(); + gfx::mojom::CALayerContentDataView content_data; + data.GetContentDataView(&content_data); + switch (content_data.tag()) { + case gfx::mojom::CALayerContentDataView::Tag::CA_CONTEXT_ID: + out->ca_context_id = content_data.ca_context_id(); + break; + case gfx::mojom::CALayerContentDataView::Tag::IO_SURFACE_MACH_PORT: #if defined(OS_MACOSX) && !defined(OS_IOS) - mach_port_t io_surface_mach_port; - MojoResult unwrap_result = - mojo::UnwrapMachPort(data.TakeIoSurfaceMachPort(), &io_surface_mach_port); - if (unwrap_result != MOJO_RESULT_OK) - return false; - out->io_surface_mach_port.reset(io_surface_mach_port); + mach_port_t io_surface_mach_port; + MojoResult unwrap_result = mojo::UnwrapMachPort( + content_data.TakeIoSurfaceMachPort(), &io_surface_mach_port); + if (unwrap_result != MOJO_RESULT_OK) + return false; + out->io_surface_mach_port.reset(io_surface_mach_port); +#else + return false; #endif + break; + } if (!data.ReadPixelSize(&out->pixel_size)) return false; + out->scale_factor = data.scale_factor(); return true; } diff --git a/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.h b/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.h index 59a947cbfbe..94127a0d5b5 100644 --- a/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.h +++ b/chromium/ui/gfx/mojo/ca_layer_params_struct_traits.h @@ -16,13 +16,6 @@ struct StructTraits<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams> { return ca_layer_params.is_empty; } - static uint32_t ca_context_id(const gfx::CALayerParams& ca_layer_params) { - return ca_layer_params.ca_context_id; - } - - static mojo::ScopedHandle io_surface_mach_port( - const gfx::CALayerParams& ca_layer_params); - static gfx::Size pixel_size(const gfx::CALayerParams& ca_layer_params) { return ca_layer_params.pixel_size; } @@ -31,6 +24,9 @@ struct StructTraits<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams> { return ca_layer_params.scale_factor; } + static gfx::mojom::CALayerContentPtr content( + const gfx::CALayerParams& ca_layer_params); + static bool Read(gfx::mojom::CALayerParamsDataView data, gfx::CALayerParams* out); }; diff --git a/chromium/ui/gfx/paint_vector_icon.cc b/chromium/ui/gfx/paint_vector_icon.cc index 7761ec11b10..b9832d0f231 100644 --- a/chromium/ui/gfx/paint_vector_icon.cc +++ b/chromium/ui/gfx/paint_vector_icon.cc @@ -562,6 +562,14 @@ void PaintVectorIcon(Canvas* canvas, SkColor color, const base::TimeDelta& elapsed_time) { DCHECK(!icon.is_empty()); + if (icon.path) { + DCHECK(icon.path_size > 0); + DCHECK_EQ(END, icon.path[icon.path_size - 1].command) << icon.name; + } + if (icon.path_1x) { + DCHECK(icon.path_1x_size > 0); + DCHECK_EQ(END, icon.path_1x[icon.path_1x_size - 1].command) << icon.name; + } const PathElement* path = (canvas->image_scale() == 1.f && icon.path_1x) ? icon.path_1x : icon.path; PaintPath(canvas, path, dip_size, color, elapsed_time); diff --git a/chromium/ui/gfx/paint_vector_icon_unittest.cc b/chromium/ui/gfx/paint_vector_icon_unittest.cc index bc4a4327b47..6570dc52d8b 100644 --- a/chromium/ui/gfx/paint_vector_icon_unittest.cc +++ b/chromium/ui/gfx/paint_vector_icon_unittest.cc @@ -51,7 +51,7 @@ TEST(VectorIconTest, RelativeMoveToAfterClose) { R_LINE_TO, 50, 51, END, }; - const VectorIcon icon = {elements, nullptr}; + const VectorIcon icon = {elements, arraysize(elements)}; PaintVectorIcon(&canvas, icon, 100, SK_ColorMAGENTA); sk_sp<cc::PaintRecord> record = recorder.finishRecordingAsPicture(); @@ -88,7 +88,7 @@ TEST(VectorIconTest, FlipsInRtl) { CLOSE, END, }; - const VectorIcon icon = {elements, nullptr}; + const VectorIcon icon = {elements, arraysize(elements)}; PaintVectorIcon(&canvas, icon, canvas_size, color); // Count the number of pixels in the canvas. diff --git a/chromium/ui/gfx/platform_font_win.cc b/chromium/ui/gfx/platform_font_win.cc index 759caf4ccc2..187ffbdaa03 100644 --- a/chromium/ui/gfx/platform_font_win.cc +++ b/chromium/ui/gfx/platform_font_win.cc @@ -24,7 +24,7 @@ #include "base/win/scoped_gdi_object.h" #include "base/win/scoped_hdc.h" #include "base/win/scoped_select_object.h" -#include "base/win/win_util.h" +#include "base/win/win_client_metrics.h" #include "third_party/skia/include/core/SkFontLCDConfig.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkTypeface.h" diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc index b5f58764ecb..3d706df56ee 100644 --- a/chromium/ui/gfx/render_text.cc +++ b/chromium/ui/gfx/render_text.cc @@ -250,12 +250,16 @@ void SkiaTextRenderer::DrawPosText(const SkPoint* pos, 0, 0, flags_); } -void SkiaTextRenderer::DrawUnderline(int x, int y, int width) { +void SkiaTextRenderer::DrawUnderline(int x, + int y, + int width, + SkScalar thickness_factor) { SkScalar x_scalar = SkIntToScalar(x); const SkScalar text_size = flags_.getTextSize(); SkRect r = SkRect::MakeLTRB( x_scalar, y + text_size * kUnderlineOffset, x_scalar + width, - y + (text_size * (kUnderlineOffset + kLineThicknessFactor))); + y + (text_size * + (kUnderlineOffset + (thickness_factor * kLineThicknessFactor)))); canvas_skia_->drawRect(r, flags_); } @@ -431,6 +435,7 @@ void RenderText::SetFontList(const FontList& font_list) { weights_.SetValue(font_list.GetFontWeight()); styles_[ITALIC].SetValue((font_style & Font::ITALIC) != 0); styles_[UNDERLINE].SetValue((font_style & Font::UNDERLINE) != 0); + styles_[HEAVY_UNDERLINE].SetValue(false); baseline_ = kInvalidBaseline; cached_bounds_and_offset_valid_ = false; OnLayoutTextAttributeChanged(false); @@ -913,11 +918,6 @@ SelectionModel RenderText::GetSelectionModelForSelectionStart() const { sel.is_reversed() ? CURSOR_BACKWARD : CURSOR_FORWARD); } -std::vector<Rect> RenderText::GetSubstringBoundsForTesting( - const gfx::Range& range) { - return GetSubstringBounds(range); -} - const Vector2d& RenderText::GetUpdatedDisplayOffset() { UpdateCachedBoundsAndOffset(); return display_offset_; @@ -1177,11 +1177,11 @@ void RenderText::ApplyCompositionAndSelectionStyles() { // Save the underline and color breaks to undo the temporary styles later. DCHECK(!composition_and_selection_styles_applied_); saved_colors_ = colors_; - saved_underlines_ = styles_[UNDERLINE]; + saved_underlines_ = styles_[HEAVY_UNDERLINE]; // Apply an underline to the composition range in |underlines|. if (composition_range_.IsValid() && !composition_range_.is_empty()) - styles_[UNDERLINE].ApplyValue(true, composition_range_); + styles_[HEAVY_UNDERLINE].ApplyValue(true, composition_range_); // Apply the selected text color to the [un-reversed] selection range. if (!selection().is_empty() && focused()) { @@ -1195,7 +1195,7 @@ void RenderText::UndoCompositionAndSelectionStyles() { // Restore the underline and color breaks to undo the temporary styles. DCHECK(composition_and_selection_styles_applied_); colors_ = saved_colors_; - styles_[UNDERLINE] = saved_underlines_; + styles_[HEAVY_UNDERLINE] = saved_underlines_; composition_and_selection_styles_applied_ = false; } @@ -1728,4 +1728,18 @@ Range RenderText::ExpandRangeToWordBoundary(const Range& range) const { : Range(range_min, range_max); } +internal::TextRunList* RenderText::GetRunList() { + NOTREACHED(); + return nullptr; +} + +const internal::TextRunList* RenderText::GetRunList() const { + NOTREACHED(); + return nullptr; +} + +void RenderText::SetGlyphWidthForTest(float test_width) { + NOTREACHED(); +} + } // namespace gfx diff --git a/chromium/ui/gfx/render_text.h b/chromium/ui/gfx/render_text.h index 0b8b82a2bc8..47fa4c605ce 100644 --- a/chromium/ui/gfx/render_text.h +++ b/chromium/ui/gfx/render_text.h @@ -50,6 +50,8 @@ class Font; namespace internal { +class TextRunList; + // Internal helper class used by derived classes to draw text through Skia. class GFX_EXPORT SkiaTextRenderer { public: @@ -68,7 +70,7 @@ class GFX_EXPORT SkiaTextRenderer { virtual void DrawPosText(const SkPoint* pos, const uint16_t* glyphs, size_t glyph_count); - void DrawUnderline(int x, int y, int width); + void DrawUnderline(int x, int y, int width, SkScalar thickness_factor = 1.0); void DrawStrike(int x, int y, int width, SkScalar thickness_factor); private: @@ -478,8 +480,13 @@ class GFX_EXPORT RenderText { // chosen. virtual std::vector<FontSpan> GetFontSpansForTesting() = 0; - // Helper function to be used in tests for retrieving the substring bounds. - std::vector<Rect> GetSubstringBoundsForTesting(const gfx::Range& range); + // Get the visual bounds containing the logical substring within the |range|. + // If |range| is empty, the result is empty. These bounds could be visually + // discontinuous if the substring is split by a LTR/RTL level change. + // These bounds are in local coordinates, but may be outside the visible + // region if the text is longer than the textfield. Subsequent text, cursor, + // or bounds changes may invalidate returned values. + virtual std::vector<Rect> GetSubstringBounds(const Range& range) = 0; // Gets the horizontal span (relative to the left of the text, not the view) // of the sequence of glyphs in |text_range|, over which the cursor will @@ -585,14 +592,6 @@ class GFX_EXPORT RenderText { // Sets the selection model, |model| is assumed to be valid. void SetSelectionModel(const SelectionModel& model); - // Get the visual bounds containing the logical substring within the |range|. - // If |range| is empty, the result is empty. These bounds could be visually - // discontinuous if the substring is split by a LTR/RTL level change. - // These bounds are in local coordinates, but may be outside the visible - // region if the text is longer than the textfield. Subsequent text, cursor, - // or bounds changes may invalidate returned values. - virtual std::vector<Rect> GetSubstringBounds(const Range& range) = 0; - // Convert between indices into |text_| and indices into // GetDisplayText(), which differ when the text is obscured, // truncated or elided. Regardless of whether or not the text is @@ -704,11 +703,20 @@ class GFX_EXPORT RenderText { // range. Maintains directionality of |range|. Range ExpandRangeToWordBoundary(const Range& range) const; + // Returns an implementation-specific run list, if implemented. + virtual internal::TextRunList* GetRunList(); + virtual const internal::TextRunList* GetRunList() const; + // Returns the decorated text corresponding to |range|. Returns false if the // text cannot be retrieved, e.g. if the text is obscured. virtual bool GetDecoratedTextForRange(const Range& range, DecoratedText* decorated_text) = 0; + // Specify the width of a glyph for test. The width of glyphs is very + // platform-dependent and environment-dependent. Otherwise multiline text + // will become really flaky. + virtual void SetGlyphWidthForTest(float test_width); + // Logical UTF-16 string data to be drawn. base::string16 text_; diff --git a/chromium/ui/gfx/render_text_harfbuzz.cc b/chromium/ui/gfx/render_text_harfbuzz.cc index 79a7a863cd1..9178adbe330 100644 --- a/chromium/ui/gfx/render_text_harfbuzz.cc +++ b/chromium/ui/gfx/render_text_harfbuzz.cc @@ -674,7 +674,8 @@ TextRunHarfBuzz::TextRunHarfBuzz(const Font& template_font) italic(false), weight(Font::Weight::NORMAL), strike(false), - underline(false) {} + underline(false), + heavy_underline(false) {} TextRunHarfBuzz::~TextRunHarfBuzz() {} @@ -1130,61 +1131,27 @@ SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel( if (!success) return selection; - // Match OS specific word break behavior. -#if defined(OS_WIN) - size_t pos; - if (direction == CURSOR_RIGHT) { - pos = std::min(selection.caret_pos() + 1, text().length()); - while (iter.Advance()) { - pos = iter.pos(); - if (iter.IsWord() && pos > selection.caret_pos()) { - // In Windows, word move advances past any characters separating the - // end of the current word from the next word. - while (iter.Advance() && !iter.IsWord()) - pos = iter.pos(); - break; - } - } - } else { // direction == CURSOR_LEFT - // Notes: We always iterate words from the beginning. - // This is probably fast enough for our usage, but we may - // want to modify WordIterator so that it can start from the - // middle of string and advance backwards. - pos = std::max<int>(selection.caret_pos() - 1, 0); - while (iter.Advance()) { - if (iter.IsWord()) { - size_t begin = iter.pos() - iter.GetString().length(); - if (begin == selection.caret_pos()) { - // The cursor is at the beginning of a word. - // Move to previous word. - break; - } else if (iter.pos() >= selection.caret_pos()) { - // The cursor is in the middle or at the end of a word. - // Move to the top of current word. - pos = begin; - break; - } - pos = iter.pos() - iter.GetString().length(); - } - } - } - return SelectionModel(pos, CURSOR_FORWARD); -#else internal::TextRunList* run_list = GetRunList(); - SelectionModel cur(selection); + SelectionModel current(selection); for (;;) { - cur = AdjacentCharSelectionModel(cur, direction); - size_t run = GetRunContainingCaret(cur); + current = AdjacentCharSelectionModel(current, direction); + size_t run = GetRunContainingCaret(current); if (run == run_list->size()) break; + size_t cursor = current.caret_pos(); +#if defined(OS_WIN) + // Windows generally advances to the start of a word in either direction. + // TODO: Break on the end of a word when the neighboring text is puctuation. + if (iter.IsStartOfWord(cursor)) + break; +#else const bool is_forward = run_list->runs()[run]->is_rtl == (direction == CURSOR_LEFT); - size_t cursor = cur.caret_pos(); if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) break; +#endif // defined(OS_WIN) } - return cur; -#endif + return current; } std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) { @@ -1367,7 +1334,9 @@ void RenderTextHarfBuzz::DrawVisualText(internal::SkiaTextRenderer* renderer) { ? (SkFloatToScalar(segment.width()) + preceding_segment_widths + SkIntToScalar(origin.x())) : positions[colored_glyphs.end() - glyphs_range.start()].x()); - if (run.underline) + if (run.heavy_underline) + renderer->DrawUnderline(start_x, origin.y(), end_x - start_x, 2.0); + else if (run.underline) renderer->DrawUnderline(start_x, origin.y(), end_x - start_x); if (run.strike) renderer->DrawStrike(start_x, origin.y(), end_x - start_x, @@ -1456,6 +1425,7 @@ void RenderTextHarfBuzz::ItemizeTextToRuns( run->baseline_type = style.baseline(); run->strike = style.style(STRIKE); run->underline = style.style(UNDERLINE); + run->heavy_underline = style.style(HEAVY_UNDERLINE); run->weight = style.weight(); int32_t script_item_break = 0; bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level); @@ -1739,6 +1709,8 @@ void RenderTextHarfBuzz::EnsureLayoutRunList() { } } +// Returns the current run list, |display_run_list_| if the text is elided, or +// |layout_run_list_| otherwise. internal::TextRunList* RenderTextHarfBuzz::GetRunList() { DCHECK(!update_layout_run_list_); DCHECK(!update_display_run_list_); @@ -1771,7 +1743,7 @@ bool RenderTextHarfBuzz::GetDecoratedTextForRange( int style = Font::NORMAL; if (run.italic) style |= Font::ITALIC; - if (run.underline) + if (run.underline || run.heavy_underline) style |= Font::UNDERLINE; // Get range relative to the decorated text. @@ -1787,4 +1759,8 @@ bool RenderTextHarfBuzz::GetDecoratedTextForRange( return true; } +void RenderTextHarfBuzz::SetGlyphWidthForTest(float test_width) { + glyph_width_for_test_ = test_width; +} + } // namespace gfx diff --git a/chromium/ui/gfx/render_text_harfbuzz.h b/chromium/ui/gfx/render_text_harfbuzz.h index b883e84fddf..983b225548d 100644 --- a/chromium/ui/gfx/render_text_harfbuzz.h +++ b/chromium/ui/gfx/render_text_harfbuzz.h @@ -91,6 +91,7 @@ struct GFX_EXPORT TextRunHarfBuzz { Font::Weight weight; bool strike; bool underline; + bool heavy_underline; private: DISALLOW_COPY_AND_ASSIGN(TextRunHarfBuzz); @@ -193,13 +194,6 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText { friend class test::RenderTextTestApi; friend class RenderTextHarfBuzzTest; - // Specify the width of a glyph for test. The width of glyphs is very - // platform-dependent and environment-dependent. Otherwise multiline test - // will become really flaky. - void set_glyph_width_for_test(float test_width) { - glyph_width_for_test_ = test_width; - } - // Return the run index that contains the argument; or the length of the // |runs_| vector if argument exceeds the text length or width. size_t GetRunContainingCaret(const SelectionModel& caret); @@ -245,14 +239,12 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText { // Makes sure that text runs for layout text are shaped. void EnsureLayoutRunList(); - // Returns the current run list, |display_run_list_| if the text is - // elided, or |layout_run_list_| otherwise. - internal::TextRunList* GetRunList(); - const internal::TextRunList* GetRunList() const; - // RenderText: + internal::TextRunList* GetRunList() override; + const internal::TextRunList* GetRunList() const override; bool GetDecoratedTextForRange(const Range& range, DecoratedText* decorated_text) override; + void SetGlyphWidthForTest(float test_width) override; // Text run list for |layout_text_| and |display_text_|. // |display_run_list_| is created only when the text is elided. diff --git a/chromium/ui/gfx/render_text_mac.mm b/chromium/ui/gfx/render_text_mac.mm index c6f256d01c1..bf162b3ddfc 100644 --- a/chromium/ui/gfx/render_text_mac.mm +++ b/chromium/ui/gfx/render_text_mac.mm @@ -360,8 +360,10 @@ base::ScopedCFTypeRef<CFMutableArrayRef> RenderTextMac::ApplyStyles( kCTForegroundColorAttributeName, foreground); CFArrayAppendValue(attributes, foreground); - if (style.style(UNDERLINE)) { - CTUnderlineStyle value = kCTUnderlineStyleSingle; + if (style.style(UNDERLINE) || style.style(HEAVY_UNDERLINE)) { + CTUnderlineStyle value = style.style(HEAVY_UNDERLINE) + ? kCTUnderlineStyleThick + : kCTUnderlineStyleSingle; base::ScopedCFTypeRef<CFNumberRef> underline_value( CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); CFAttributedStringSetAttribute( diff --git a/chromium/ui/gfx/render_text_test_api.h b/chromium/ui/gfx/render_text_test_api.h new file mode 100644 index 00000000000..dbb6c4436e6 --- /dev/null +++ b/chromium/ui/gfx/render_text_test_api.h @@ -0,0 +1,87 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/macros.h" +#include "ui/gfx/break_list.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/render_text.h" +#include "ui/gfx/selection_model.h" + +namespace gfx { +namespace test { + +class RenderTextTestApi { + public: + RenderTextTestApi(RenderText* render_text) : render_text_(render_text) {} + + static cc::PaintFlags& GetRendererPaint( + internal::SkiaTextRenderer* renderer) { + return renderer->flags_; + } + + // Callers must ensure that the associated RenderText object is a + // RenderTextHarfBuzz instance. + const internal::TextRunList* GetHarfBuzzRunList() const { + return render_text_->GetRunList(); + } + + void DrawVisualText(internal::SkiaTextRenderer* renderer) { + render_text_->EnsureLayout(); + render_text_->DrawVisualText(renderer); + } + + const BreakList<SkColor>& colors() const { return render_text_->colors(); } + + const BreakList<BaselineStyle>& baselines() const { + return render_text_->baselines(); + } + + const BreakList<Font::Weight>& weights() const { + return render_text_->weights(); + } + + const std::vector<BreakList<bool>>& styles() const { + return render_text_->styles(); + } + + const std::vector<internal::Line>& lines() const { + return render_text_->lines(); + } + + SelectionModel EdgeSelectionModel(VisualCursorDirection direction) { + return render_text_->EdgeSelectionModel(direction); + } + + size_t TextIndexToDisplayIndex(size_t index) { + return render_text_->TextIndexToDisplayIndex(index); + } + + size_t DisplayIndexToTextIndex(size_t index) { + return render_text_->DisplayIndexToTextIndex(index); + } + + void EnsureLayout() { render_text_->EnsureLayout(); } + + Vector2d GetAlignmentOffset(size_t line_number) { + return render_text_->GetAlignmentOffset(line_number); + } + + int GetDisplayTextBaseline() { + return render_text_->GetDisplayTextBaseline(); + } + + // Callers must ensure that the underlying RenderText object is a + // RenderTextHarfBuzz instance. + void SetGlyphWidth(float test_width) { + render_text_->SetGlyphWidthForTest(test_width); + } + + private: + RenderText* render_text_; + + DISALLOW_COPY_AND_ASSIGN(RenderTextTestApi); +}; + +} // namespace test +} // namespace gfx diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc index ea11f5453ed..5a47cee1adf 100644 --- a/chromium/ui/gfx/render_text_unittest.cc +++ b/chromium/ui/gfx/render_text_unittest.cc @@ -39,6 +39,7 @@ #include "ui/gfx/range/range.h" #include "ui/gfx/range/range_f.h" #include "ui/gfx/render_text_harfbuzz.h" +#include "ui/gfx/render_text_test_api.h" #include "ui/gfx/switches.h" #include "ui/gfx/text_utils.h" @@ -58,77 +59,6 @@ using base::UTF8ToUTF16; using base::WideToUTF16; namespace gfx { -namespace test { - -class RenderTextTestApi { - public: - RenderTextTestApi(RenderText* render_text) : render_text_(render_text) {} - - static cc::PaintFlags& GetRendererPaint( - internal::SkiaTextRenderer* renderer) { - return renderer->flags_; - } - - // Callers should ensure that the associated RenderText object is a - // RenderTextHarfBuzz instance. - const internal::TextRunList* GetHarfBuzzRunList() const { - RenderTextHarfBuzz* render_text = - static_cast<RenderTextHarfBuzz*>(render_text_); - return render_text->GetRunList(); - } - - void DrawVisualText(internal::SkiaTextRenderer* renderer) { - render_text_->EnsureLayout(); - render_text_->DrawVisualText(renderer); - } - - const BreakList<SkColor>& colors() const { return render_text_->colors(); } - - const BreakList<BaselineStyle>& baselines() const { - return render_text_->baselines(); - } - - const BreakList<Font::Weight>& weights() const { - return render_text_->weights(); - } - - const std::vector<BreakList<bool>>& styles() const { - return render_text_->styles(); - } - - const std::vector<internal::Line>& lines() const { - return render_text_->lines(); - } - - SelectionModel EdgeSelectionModel(VisualCursorDirection direction) { - return render_text_->EdgeSelectionModel(direction); - } - - size_t TextIndexToDisplayIndex(size_t index) { - return render_text_->TextIndexToDisplayIndex(index); - } - - size_t DisplayIndexToTextIndex(size_t index) { - return render_text_->DisplayIndexToTextIndex(index); - } - - void EnsureLayout() { render_text_->EnsureLayout(); } - - Vector2d GetAlignmentOffset(size_t line_number) { - return render_text_->GetAlignmentOffset(line_number); - } - - int GetDisplayTextBaseline() { - return render_text_->GetDisplayTextBaseline(); - } - - private: - RenderText* render_text_; - - DISALLOW_COPY_AND_ASSIGN(RenderTextTestApi); -}; - -} // namespace test namespace { @@ -533,8 +463,7 @@ class RenderTextTest : public testing::Test, #endif Rect GetSubstringBoundsUnion(const Range& range) { - const std::vector<Rect> bounds = - render_text_->GetSubstringBoundsForTesting(range); + const std::vector<Rect> bounds = render_text_->GetSubstringBounds(range); return std::accumulate(bounds.begin(), bounds.end(), Rect(), UnionRects); } @@ -616,7 +545,7 @@ class RenderTextHarfBuzzTest : public RenderTextTest { protected: void SetGlyphWidth(float test_width) { - GetRenderTextHarfBuzz()->set_glyph_width_for_test(test_width); + test_api()->SetGlyphWidth(test_width); } bool ShapeRunWithFont(const base::string16& text, @@ -1479,6 +1408,102 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursor_Word) { SELECTION_EXTEND, &expected); } +// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618 +TEST_P(RenderTextHarfBuzzTest, MoveCursor_Word_RTL) { + RenderText* render_text = GetRenderText(); + render_text->SetText(UTF8ToUTF16("אבג דהו זחט")); + std::vector<Range> expected; + + // SELECTION_NONE. + render_text->SelectRange(Range(6)); + + // Move right twice. + expected.push_back(Range(4)); + expected.push_back(Range(0)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_RIGHT, + SELECTION_NONE, &expected); + + // Move left twice. +#if defined(OS_WIN) // Move word left includes space/punctuation. + expected.push_back(Range(4)); + expected.push_back(Range(8)); +#else // Non-Windows: move word left does NOT include space/punctuation. + expected.push_back(Range(3)); + expected.push_back(Range(7)); +#endif + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_LEFT, + SELECTION_NONE, &expected); + + // SELECTION_CARET. + render_text->SelectRange(Range(6)); + + // Move right. + expected.push_back(Range(6, 4)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_RIGHT, + SELECTION_CARET, &expected); + + // Move left twice. + expected.push_back(Range(6)); +#if defined(OS_WIN) // Select word left includes space/punctuation. + expected.push_back(Range(6, 8)); +#else // Non-Windows: select word left does NOT include space/punctuation. + expected.push_back(Range(6, 7)); +#endif + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_LEFT, + SELECTION_CARET, &expected); + + // Move right. + expected.push_back(Range(6)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_RIGHT, + SELECTION_CARET, &expected); + + // SELECTION_RETAIN. + render_text->SelectRange(Range(6)); + + // Move right. + expected.push_back(Range(6, 4)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_RIGHT, + SELECTION_RETAIN, &expected); + + // Move left twice. +#if defined(OS_WIN) // Select word left includes space/punctuation. + expected.push_back(Range(6, 8)); +#else // Non-Windows: select word left does NOT include space/punctuation. + expected.push_back(Range(6, 7)); +#endif + expected.push_back(Range(6, 11)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_LEFT, + SELECTION_RETAIN, &expected); + + // Move right. + expected.push_back(Range(6, 8)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_RIGHT, + SELECTION_RETAIN, &expected); + + // SELECTION_EXTEND. + render_text->SelectRange(Range(6)); + + // Move right. + expected.push_back(Range(6, 4)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_RIGHT, + SELECTION_EXTEND, &expected); + + // Move left twice. +#if defined(OS_WIN) // Select word left includes space/punctuation. + expected.push_back(Range(4, 8)); +#else // Non-Windows: select word left does NOT include space/punctuation. + expected.push_back(Range(4, 7)); +#endif + expected.push_back(Range(4, 11)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_LEFT, + SELECTION_EXTEND, &expected); + + // Move right. + expected.push_back(Range(4, 8)); + RunMoveCursorTestAndClearExpectations(render_text, WORD_BREAK, CURSOR_RIGHT, + SELECTION_EXTEND, &expected); +} + TEST_P(RenderTextTest, MoveCursor_Line) { RenderText* render_text = GetRenderText(); render_text->SetText(UTF8ToUTF16("123 456 789")); @@ -2477,25 +2502,26 @@ TEST_P(RenderTextTest, StringSizeEmptyString) { } TEST_P(RenderTextTest, StringSizeRespectsFontListMetrics) { - // Check that Arial and the CJK font have different font metrics. - Font arial_font("Arial", 16); - ASSERT_EQ("arial", - base::ToLowerASCII(arial_font.GetActualFontNameForTesting())); + // Check that Verdana and the CJK font have different font metrics. + Font verdana_font("Verdana", 16); + ASSERT_EQ("verdana", + base::ToLowerASCII(verdana_font.GetActualFontNameForTesting())); Font cjk_font(kCJKFontName, 16); ASSERT_EQ(base::ToLowerASCII(kCJKFontName), base::ToLowerASCII(cjk_font.GetActualFontNameForTesting())); - EXPECT_NE(arial_font.GetHeight(), cjk_font.GetHeight()); - EXPECT_NE(arial_font.GetBaseline(), cjk_font.GetBaseline()); - // "a" should be rendered with Arial, not with the CJK font. - const char* arial_font_text = "a"; - // "円" (U+5168 Han character YEN) should render with the CJK font, not Arial. + EXPECT_NE(verdana_font.GetHeight(), cjk_font.GetHeight()); + EXPECT_NE(verdana_font.GetBaseline(), cjk_font.GetBaseline()); + // "a" should be rendered with Verdana, not with the CJK font. + const char* verdana_font_text = "a"; + // "円" (U+5168 Han character YEN) should render with the CJK font, not + // Verdana. const char* cjk_font_text = "\u5168"; - Font smaller_font = arial_font; + Font smaller_font = verdana_font; Font larger_font = cjk_font; - const char* smaller_font_text = arial_font_text; + const char* smaller_font_text = verdana_font_text; const char* larger_font_text = cjk_font_text; - if (cjk_font.GetHeight() < arial_font.GetHeight() && - cjk_font.GetBaseline() < arial_font.GetBaseline()) { + if (cjk_font.GetHeight() < verdana_font.GetHeight() && + cjk_font.GetBaseline() < verdana_font.GetBaseline()) { std::swap(smaller_font, larger_font); std::swap(smaller_font_text, larger_font_text); } diff --git a/chromium/ui/gfx/sequential_id_generator_unittest.cc b/chromium/ui/gfx/sequential_id_generator_unittest.cc index 049ed7ac556..c4f98b795b6 100644 --- a/chromium/ui/gfx/sequential_id_generator_unittest.cc +++ b/chromium/ui/gfx/sequential_id_generator_unittest.cc @@ -44,4 +44,5 @@ TEST(SequentialIDGeneratorTest, MaybeRemoveNumbers) { EXPECT_FALSE(generator.HasGeneratedIDFor(42)); generator.ReleaseNumber(42); } + } // namespace ui diff --git a/chromium/ui/gfx/shadow_value.cc b/chromium/ui/gfx/shadow_value.cc index 9f177974801..ba552bace1b 100644 --- a/chromium/ui/gfx/shadow_value.cc +++ b/chromium/ui/gfx/shadow_value.cc @@ -10,6 +10,7 @@ #include "base/strings/stringprintf.h" #include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" #include "ui/gfx/geometry/vector2d_conversions.h" namespace gfx { @@ -28,8 +29,7 @@ Insets GetInsets(const ShadowValues& shadows, bool include_inner_blur) { double blur = shadow.blur(); if (!include_inner_blur) blur /= 2; - // Add 0.5 to round up to the next integer. - int blur_length = static_cast<int>(blur + 0.5); + int blur_length = ToRoundedInt(blur); left = std::max(left, blur_length - shadow.x()); top = std::max(top, blur_length - shadow.y()); @@ -42,16 +42,6 @@ Insets GetInsets(const ShadowValues& shadows, bool include_inner_blur) { } // namespace -ShadowValue::ShadowValue() : blur_(0), color_(0) {} - -ShadowValue::ShadowValue(const gfx::Vector2d& offset, - double blur, - SkColor color) - : offset_(offset), blur_(blur), color_(color) { -} - -ShadowValue::~ShadowValue() {} - ShadowValue ShadowValue::Scale(float scale) const { gfx::Vector2d scaled_offset = gfx::ToFlooredVector2d(gfx::ScaleVector2d(offset_, scale)); diff --git a/chromium/ui/gfx/shadow_value.h b/chromium/ui/gfx/shadow_value.h index 7723a8b1e07..d212678ff29 100644 --- a/chromium/ui/gfx/shadow_value.h +++ b/chromium/ui/gfx/shadow_value.h @@ -6,6 +6,7 @@ #define UI_GFX_SHADOW_VALUE_H_ #include <string> +#include <tuple> #include <vector> #include "third_party/skia/include/core/SkColor.h" @@ -23,15 +24,20 @@ typedef std::vector<ShadowValue> ShadowValues; // shadow's offset, blur amount and color. class GFX_EXPORT ShadowValue { public: - ShadowValue(); - ShadowValue(const gfx::Vector2d& offset, double blur, SkColor color); - ~ShadowValue(); + constexpr ShadowValue() = default; + constexpr ShadowValue(const gfx::Vector2d& offset, double blur, SkColor color) + : offset_(offset), blur_(blur), color_(color) {} - int x() const { return offset_.x(); } - int y() const { return offset_.y(); } - const gfx::Vector2d& offset() const { return offset_; } - double blur() const { return blur_; } - SkColor color() const { return color_; } + constexpr int x() const { return offset_.x(); } + constexpr int y() const { return offset_.y(); } + constexpr const gfx::Vector2d& offset() const { return offset_; } + constexpr double blur() const { return blur_; } + constexpr SkColor color() const { return color_; } + + constexpr bool operator==(const ShadowValue& other) const { + return offset_ == other.offset_ && blur_ == other.blur_ && + color_ == other.color_; + } ShadowValue Scale(float scale) const; @@ -63,16 +69,11 @@ class GFX_EXPORT ShadowValue { // amount of 4.0 means to have a blurry shadow edge of 4 pixels that // transitions from full shadow color to fully transparent and with 2 pixels // inside the shadow and 2 pixels goes beyond the edge. - double blur_; + double blur_ = 0.; - SkColor color_; + SkColor color_ = SK_ColorTRANSPARENT; }; -inline bool operator==(const ShadowValue& lhs, const ShadowValue& rhs) { - return lhs.offset() == rhs.offset() && lhs.blur() == rhs.blur() && - lhs.color() == rhs.color(); -} - } // namespace gfx #endif // UI_GFX_SHADOW_VALUE_H_ diff --git a/chromium/ui/gfx/shadow_value_unittest.cc b/chromium/ui/gfx/shadow_value_unittest.cc index fb065b82e21..d93e0967bbf 100644 --- a/chromium/ui/gfx/shadow_value_unittest.cc +++ b/chromium/ui/gfx/shadow_value_unittest.cc @@ -13,45 +13,49 @@ namespace gfx { TEST(ShadowValueTest, GetMargin) { - const struct TestCase { + constexpr struct TestCase { Insets expected_margin; size_t shadow_count; ShadowValue shadows[2]; } kTestCases[] = { - { - Insets(), 0, {}, - }, - { - Insets(-2, -2, -2, -2), - 1, - { ShadowValue(gfx::Vector2d(0, 0), 4, 0), }, - }, - { - Insets(0, -1, -4, -3), - 1, - { ShadowValue(gfx::Vector2d(1, 2), 4, 0), }, - }, - { - Insets(-4, -3, 0, -1), - 1, - { ShadowValue(gfx::Vector2d(-1, -2), 4, 0), }, - }, - { - Insets(0, -1, -5, -4), - 2, { - ShadowValue(gfx::Vector2d(1, 2), 4, 0), - ShadowValue(gfx::Vector2d(2, 3), 4, 0), + Insets(), 0, {}, }, - }, - { - Insets(-4, -3, -5, -4), - 2, { - ShadowValue(gfx::Vector2d(-1, -2), 4, 0), - ShadowValue(gfx::Vector2d(2, 3), 4, 0), + Insets(-2, -2, -2, -2), + 1, + { + {gfx::Vector2d(0, 0), 4, 0}, + }, + }, + { + Insets(0, -1, -4, -3), + 1, + { + {gfx::Vector2d(1, 2), 4, 0}, + }, + }, + { + Insets(-4, -3, 0, -1), + 1, + { + {gfx::Vector2d(-1, -2), 4, 0}, + }, + }, + { + Insets(0, -1, -5, -4), + 2, + { + {gfx::Vector2d(1, 2), 4, 0}, {gfx::Vector2d(2, 3), 4, 0}, + }, + }, + { + Insets(-4, -3, -5, -4), + 2, + { + {gfx::Vector2d(-1, -2), 4, 0}, {gfx::Vector2d(2, 3), 4, 0}, + }, }, - }, }; for (size_t i = 0; i < arraysize(kTestCases); ++i) { diff --git a/chromium/ui/gfx/skia_paint_util.cc b/chromium/ui/gfx/skia_paint_util.cc index 3c126e73566..df9dcded399 100644 --- a/chromium/ui/gfx/skia_paint_util.cc +++ b/chromium/ui/gfx/skia_paint_util.cc @@ -40,8 +40,9 @@ sk_sp<cc::PaintShader> CreateImageRepShaderForScale( return cc::PaintShader::MakeImage( cc::PaintImageBuilder::WithDefault() - .set_id(cc::PaintImage::kNonLazyStableId) - .set_image(SkImage::MakeFromBitmap(image_rep.sk_bitmap())) + .set_id(cc::PaintImage::GetNextId()) + .set_image(SkImage::MakeFromBitmap(image_rep.sk_bitmap()), + cc::PaintImage::GetNextContentId()) .TakePaintImage(), tile_mode, tile_mode, &shader_scale); } diff --git a/chromium/ui/gfx/text_constants.h b/chromium/ui/gfx/text_constants.h index 431195c7707..0ca89b1f228 100644 --- a/chromium/ui/gfx/text_constants.h +++ b/chromium/ui/gfx/text_constants.h @@ -81,6 +81,7 @@ enum TextStyle { ITALIC = 0, STRIKE, UNDERLINE, + HEAVY_UNDERLINE, NUM_TEXT_STYLES, }; diff --git a/chromium/ui/gfx/text_utils.cc b/chromium/ui/gfx/text_utils.cc index 9dbc32b2662..d462b678c9e 100644 --- a/chromium/ui/gfx/text_utils.cc +++ b/chromium/ui/gfx/text_utils.cc @@ -7,6 +7,7 @@ #include <stdint.h> #include "base/i18n/char_iterator.h" +#include "base/i18n/rtl.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "third_party/icu/source/common/unicode/uchar.h" @@ -108,4 +109,13 @@ size_t FindValidBoundaryAfter(const base::string16& text, size_t index) { return static_cast<size_t>(text_index); } +HorizontalAlignment MaybeFlipForRTL(HorizontalAlignment alignment) { + if (base::i18n::IsRTL() && + (alignment == gfx::ALIGN_LEFT || alignment == gfx::ALIGN_RIGHT)) { + alignment = + (alignment == gfx::ALIGN_LEFT) ? gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT; + } + return alignment; +} + } // namespace gfx diff --git a/chromium/ui/gfx/text_utils.h b/chromium/ui/gfx/text_utils.h index 010c7cab062..462d7690dd7 100644 --- a/chromium/ui/gfx/text_utils.h +++ b/chromium/ui/gfx/text_utils.h @@ -47,6 +47,9 @@ FindValidBoundaryBefore(const base::string16& text, size_t index); GFX_EXPORT size_t FindValidBoundaryAfter(const base::string16& text, size_t index); +// If the UI layout is right-to-left, flip the alignment direction. +GFX_EXPORT HorizontalAlignment MaybeFlipForRTL(HorizontalAlignment alignment); + } // namespace gfx #endif // UI_GFX_TEXT_UTILS_H_ diff --git a/chromium/ui/gfx/vector_icon_types.h b/chromium/ui/gfx/vector_icon_types.h index d1cba9b3e7d..fae6871dffb 100644 --- a/chromium/ui/gfx/vector_icon_types.h +++ b/chromium/ui/gfx/vector_icon_types.h @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file provides defines needed by PaintVectorIcon and is implemented -// by the generated file vector_icons.cc. - #ifndef UI_GFX_VECTOR_ICON_TYPES_H_ #define UI_GFX_VECTOR_ICON_TYPES_H_ @@ -66,7 +63,8 @@ enum CommandType { // Parameters are delay (ms), duration (ms), and tween type // (gfx::Tween::Type). TRANSITION_END, - // Marks the end of the list of commands. + // Marks the end of the list of commands. TODO(estade): remove this sentinel + // value and rely on VectorIcon::path_size. END }; @@ -86,8 +84,20 @@ struct VectorIcon { bool is_empty() const { return !path; } - const gfx::PathElement* path; - const gfx::PathElement* path_1x; + const gfx::PathElement* path = nullptr; + // The length of |path|. + size_t path_size = 0u; + + const gfx::PathElement* path_1x = nullptr; + // The length of |path_1x|. + size_t path_1x_size = 0u; + + // A human-readable name, useful for debugging, derived from the name of the + // icon file. This can also be used as an identifier, but vector icon targets + // should be careful to ensure this is unique. + const char* name = nullptr; + + bool operator<(const VectorIcon& other) const; private: DISALLOW_COPY_AND_ASSIGN(VectorIcon); diff --git a/chromium/ui/gfx/vsync_provider.cc b/chromium/ui/gfx/vsync_provider.cc index d54ffe8c060..6276b7f3d0a 100644 --- a/chromium/ui/gfx/vsync_provider.cc +++ b/chromium/ui/gfx/vsync_provider.cc @@ -19,8 +19,12 @@ bool FixedVSyncProvider::GetVSyncParametersIfAvailable( return true; } -bool FixedVSyncProvider::SupportGetVSyncParametersIfAvailable() { +bool FixedVSyncProvider::SupportGetVSyncParametersIfAvailable() const { return true; } +bool FixedVSyncProvider::IsHWClock() const { + return false; +} + } // namespace gfx diff --git a/chromium/ui/gfx/vsync_provider.h b/chromium/ui/gfx/vsync_provider.h index a1c1098d185..e8aa0fe7028 100644 --- a/chromium/ui/gfx/vsync_provider.h +++ b/chromium/ui/gfx/vsync_provider.h @@ -33,7 +33,10 @@ class GFX_EXPORT VSyncProvider { base::TimeDelta* interval) = 0; // Returns true, if GetVSyncParametersIfAvailable is supported. - virtual bool SupportGetVSyncParametersIfAvailable() = 0; + virtual bool SupportGetVSyncParametersIfAvailable() const = 0; + + // Returns true, if VSyncProvider gets VSync timebase from HW. + virtual bool IsHWClock() const = 0; }; // Provides a constant timebase and interval. @@ -48,7 +51,8 @@ class GFX_EXPORT FixedVSyncProvider : public VSyncProvider { void GetVSyncParameters(const UpdateVSyncCallback& callback) override; bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, base::TimeDelta* interval) override; - bool SupportGetVSyncParametersIfAvailable() override; + bool SupportGetVSyncParametersIfAvailable() const override; + bool IsHWClock() const override; private: base::TimeTicks timebase_; diff --git a/chromium/ui/gfx/win/rendering_window_manager.cc b/chromium/ui/gfx/win/rendering_window_manager.cc index 4f2cbfb7b90..5c7261f5a36 100644 --- a/chromium/ui/gfx/win/rendering_window_manager.cc +++ b/chromium/ui/gfx/win/rendering_window_manager.cc @@ -22,6 +22,12 @@ void RenderingWindowManager::RegisterParent(HWND parent) { info_.emplace(parent, EmeddingInfo()); } +void SetParentAndMoveToBottom(HWND child, HWND parent) { + ::SetParent(child, parent); + // Move D3D window behind Chrome's window to avoid losing some messages. + ::SetWindowPos(child, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); +} + bool RenderingWindowManager::RegisterChild(HWND parent, HWND child) { if (!child) return false; @@ -44,7 +50,7 @@ bool RenderingWindowManager::RegisterChild(HWND parent, HWND child) { if (info.call_set_parent) { base::PostTaskWithTraits( FROM_HERE, {base::TaskPriority::USER_BLOCKING}, - base::BindOnce(base::IgnoreResult(&::SetParent), child, parent)); + base::BindOnce(&SetParentAndMoveToBottom, child, parent)); } return true; @@ -64,14 +70,14 @@ void RenderingWindowManager::DoSetParentOnChild(HWND parent) { DCHECK(!info.call_set_parent); info.call_set_parent = true; - // Call ::SetParent() once RegisterChild() is called. + // Call SetParentAndMoveToBottom() once RegisterChild() is called. if (!info.child) return; child = info.child; } - ::SetParent(child, parent); + SetParentAndMoveToBottom(child, parent); } void RenderingWindowManager::UnregisterParent(HWND parent) { diff --git a/chromium/ui/gfx/x/x11.h b/chromium/ui/gfx/x/x11.h index 979ad844ee5..eb53d6dd906 100644 --- a/chromium/ui/gfx/x/x11.h +++ b/chromium/ui/gfx/x/x11.h @@ -80,25 +80,40 @@ extern "C" { // in the x11 namespace below. This is the main purpose of this header // file. -// Not redefining common words is extra important for jumbo builds +// Not using common words is extra important for jumbo builds // where cc files are merged. Those merged filed get to see many more // headers than initially expected, including system headers like // those from X11. -#undef None // Defined by X11/X.h to 0L #undef Status // Defined by X11/Xlib.h to int -#undef True // Defined by X11/Xlib.h to 1 -#undef False // Defined by X11/Xlib.h to 0 #undef Bool // Defined by X11/Xlib.h to int #undef RootWindow // Defined by X11/Xlib.h -#undef CurrentTime // Defined by X11/X.h to 0L -#undef Success // Defined by X11/X.h to 0 #undef DestroyAll // Defined by X11/X.h to 0 #undef COUNT // Defined by X11/extensions/XI.h to 0 #undef CREATE // Defined by X11/extensions/XI.h to 1 #undef DeviceAdded // Defined by X11/extensions/XI.h to 0 #undef DeviceMode // Defined by X11/extensions/XI.h to 1 #undef DeviceRemoved // Defined by X11/extensions/XI.h to 1 + +// The constants below are made available in the x11 namespace with +// their original values so we double check that the value is what we +// expect using static_assert. +static_assert(FocusIn == 9 && FocusOut == 10, "Unexpected focus constants"); +#undef FocusIn // Defined by X.h to 9 +#undef FocusOut // Defined by X.h to 10 + +static_assert(None == 0, "Unexpected value for X11 constant 'None'"); +#undef None // Defined by X11/X.h to 0L + +static_assert(True == 1 && False == 0, "Unexpected X11 truth values"); +#undef True // Defined by X11/Xlib.h to 1 +#undef False // Defined by X11/Xlib.h to 0 + +static_assert(CurrentTime == 0, "Unexpected value for X11 'CurrentTime'"); +#undef CurrentTime // Defined by X11/X.h to 0L + +static_assert(Success == 0, "Unexpected value for X11 'Success'"); +#undef Success // Defined by X11/X.h to 0 } // The x11 namespace allows to scope X11 constants and types that @@ -109,6 +124,8 @@ static const long CurrentTime = 0L; static const int False = 0; static const int True = 1; static const int Success = 0; +static const int FocusIn = 9; +static const int FocusOut = 10; typedef int Bool; typedef int Status; } // namespace x11 diff --git a/chromium/ui/gfx/x/x11_types.cc b/chromium/ui/gfx/x/x11_types.cc index 7540f8ae288..502589f3ec8 100644 --- a/chromium/ui/gfx/x/x11_types.cc +++ b/chromium/ui/gfx/x/x11_types.cc @@ -149,17 +149,17 @@ void PutARGBImage(XDisplay* display, for (int y = 0; y < data_height; ++y) { for (int x = 0; x < data_width; ++x) { const uint32_t pixel = *(bitmap_in++); - uint16_t out_pixel = ((pixel >> 8) & 0xf800) | - ((pixel >> 5) & 0x07e0) | - ((pixel >> 3) & 0x001f); + uint16_t out_pixel = ((pixel >> 8) & 0b1111100000000000) | + ((pixel >> 5) & 0b0000011111100000) | + ((pixel >> 3) & 0b0000000000011111); *(bitmap16++) = out_pixel; } } image.data = reinterpret_cast<char*>(orig_bitmap16); - image.red_mask = 0xf800; - image.green_mask = 0x07e0; - image.blue_mask = 0x001f; + image.red_mask = 0b1111100000000000; + image.green_mask = 0b0000011111100000; + image.blue_mask = 0b0000000000011111; XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image, src_x, src_y, dst_x, dst_y, diff --git a/chromium/ui/gl/BUILD.gn b/chromium/ui/gl/BUILD.gn index 6e476ff9f23..238df5099a5 100644 --- a/chromium/ui/gl/BUILD.gn +++ b/chromium/ui/gl/BUILD.gn @@ -16,7 +16,6 @@ declare_args() { (target_cpu == "x86" || target_cpu == "x64") } -use_egl = is_win || is_android || is_linux || is_fuchsia use_glx = use_x11 || ozone_platform_x11 if (is_android) { @@ -28,6 +27,7 @@ buildflag_header("gl_features") { header = "gl_features.h" flags = [ "ENABLE_SWIFTSHADER=$enable_swiftshader", + "USE_EGL_ON_MAC=$use_egl_on_mac", "USE_STATIC_ANGLE=$use_static_angle", ] } @@ -155,6 +155,7 @@ component("gl") { public_configs = [ "//third_party/khronos:khronos_headers" ] deps = [ + ":gl_features", "//base/third_party/dynamic_annotations", # Remove after fixing crbug.com/724999. @@ -239,6 +240,7 @@ component("gl") { deps += [ "//ui/base/x" ] + assert(use_egl) data_deps += [ "//third_party/angle:libEGL", "//third_party/angle:libGLESv2", @@ -291,6 +293,7 @@ component("gl") { libs = [ "dwmapi.lib" ] ldflags = [ "/DELAYLOAD:dwmapi.dll" ] + assert(use_egl) data_deps += [ "//third_party/angle:libEGL", "//third_party/angle:libGLESv2", @@ -318,6 +321,18 @@ component("gl") { "OpenGL.framework", "Quartz.framework", ] + + if (use_egl) { + sources += [ + "gl_image_io_surface_egl.h", + "gl_image_io_surface_egl.mm", + ] + + data_deps += [ + "//third_party/angle:libEGL", + "//third_party/angle:libGLESv2", + ] + } } if (is_android) { sources += [ diff --git a/chromium/ui/gl/features.gni b/chromium/ui/gl/features.gni index 7e948472f4e..75a55a3a095 100644 --- a/chromium/ui/gl/features.gni +++ b/chromium/ui/gl/features.gni @@ -6,4 +6,12 @@ declare_args() { # Whether ANGLE should be linked statically # False by default, enabling currently supported only on Android use_static_angle = false + + # Whether experimental support for ANGLE on Mac should be enabled. + # False by default since it is experimental + use_egl_on_mac = false } + +# Should EGL support be compiled +use_egl = + is_win || is_android || is_linux || is_fuchsia || (is_mac && use_egl_on_mac) diff --git a/chromium/ui/gl/gl_bindings.h b/chromium/ui/gl/gl_bindings.h index 2fc96618dfe..4e7c09b173b 100644 --- a/chromium/ui/gl/gl_bindings.h +++ b/chromium/ui/gl/gl_bindings.h @@ -99,6 +99,7 @@ #define GL_ALPHA8_EXT 0x803C #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_RGB10_A2_EXT 0x8059 #define GL_RGBA32F_EXT 0x8814 #define GL_RGB32F_EXT 0x8815 #define GL_ALPHA32F_EXT 0x8816 @@ -106,13 +107,13 @@ #define GL_LUMINANCE_ALPHA32F_EXT 0x8819 #define GL_RGBA16F_EXT 0x881A #define GL_RGB16F_EXT 0x881B -#define GL_RG16F_EXT 0x822F -#define GL_R16F_EXT 0x822D +#define GL_RG16F_EXT 0x822F +#define GL_R16F_EXT 0x822D #define GL_ALPHA16F_EXT 0x881C #define GL_LUMINANCE16F_EXT 0x881E #define GL_LUMINANCE_ALPHA16F_EXT 0x881F -#define GL_R32F_EXT 0x822E -#define GL_RG32F_EXT 0x8230 +#define GL_R32F_EXT 0x822E +#define GL_RG32F_EXT 0x8230 #define GL_BGRA8_EXT 0x93A1 // GL_ANGLE_instanced_arrays diff --git a/chromium/ui/gl/gl_fence_android_native_fence_sync.cc b/chromium/ui/gl/gl_fence_android_native_fence_sync.cc index 3c46d4b77ff..ae1b0aa33c2 100644 --- a/chromium/ui/gl/gl_fence_android_native_fence_sync.cc +++ b/chromium/ui/gl/gl_fence_android_native_fence_sync.cc @@ -61,7 +61,7 @@ std::unique_ptr<gfx::GpuFence> GLFenceAndroidNativeFenceSync::GetGpuFence() { handle.type = gfx::GpuFenceHandleType::kAndroidNativeFenceSync; handle.native_fd = base::FileDescriptor(sync_fd, /*auto_close=*/true); - return base::MakeUnique<gfx::GpuFence>(handle); + return std::make_unique<gfx::GpuFence>(handle); } } // namespace gl diff --git a/chromium/ui/gl/gl_gl_api_implementation.cc b/chromium/ui/gl/gl_gl_api_implementation.cc index 22d51ae8a6d..250bb1c2909 100644 --- a/chromium/ui/gl/gl_gl_api_implementation.cc +++ b/chromium/ui/gl/gl_gl_api_implementation.cc @@ -31,21 +31,8 @@ static bool g_debug_bindings_enabled = false; namespace { -static inline GLenum GetInternalFormat(const GLVersionInfo* version, - GLenum internal_format) { - if (!version->is_es) { - if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT) - return GL_RGBA8; - } - if (version->is_es3 && version->is_mesa) { - // Mesa bug workaround: Mipmapping does not work when using GL_BGRA_EXT - if (internal_format == GL_BGRA_EXT) - return GL_RGBA; - } - return internal_format; -} - -// TODO(epenner): Could the above function be merged into this and removed? +// TODO(epenner): Could the above function be merged into GetInternalFormat and +// removed? static inline GLenum GetTexInternalFormat(const GLVersionInfo* version, GLenum internal_format, GLenum format, @@ -244,6 +231,19 @@ static inline GLenum GetPixelType(const GLVersionInfo* version, } // anonymous namespace +GLenum GetInternalFormat(const GLVersionInfo* version, GLenum internal_format) { + if (!version->is_es) { + if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT) + return GL_RGBA8; + } + if (version->is_es3 && version->is_mesa) { + // Mesa bug workaround: Mipmapping does not work when using GL_BGRA_EXT + if (internal_format == GL_BGRA_EXT) + return GL_RGBA; + } + return internal_format; +} + void InitializeStaticGLBindingsGL() { g_current_gl_context_tls = new base::ThreadLocalPointer<CurrentGL>; g_no_context_current_gl = new CurrentGL; diff --git a/chromium/ui/gl/gl_gl_api_implementation.h b/chromium/ui/gl/gl_gl_api_implementation.h index 6d6c7f5489d..6fd49e028c8 100644 --- a/chromium/ui/gl/gl_gl_api_implementation.h +++ b/chromium/ui/gl/gl_gl_api_implementation.h @@ -17,6 +17,9 @@ namespace gl { struct GLVersionInfo; +GL_EXPORT GLenum GetInternalFormat(const GLVersionInfo* version, + GLenum internal_format); + GL_EXPORT void InitializeStaticGLBindingsGL(); GL_EXPORT void ClearBindingsGL(); diff --git a/chromium/ui/gl/gl_image_io_surface.h b/chromium/ui/gl/gl_image_io_surface.h index eba2ee3722e..fd9741d9f08 100644 --- a/chromium/ui/gl/gl_image_io_surface.h +++ b/chromium/ui/gl/gl_image_io_surface.h @@ -85,10 +85,9 @@ class GL_EXPORT GLImageIOSurface : public GLImage { static GLImageIOSurface* FromGLImage(GLImage* image); protected: - ~GLImageIOSurface() override; - - private: GLImageIOSurface(const gfx::Size& size, unsigned internalformat); + ~GLImageIOSurface() override; + virtual bool BindTexImageImpl(unsigned internalformat); Type GetType() const override; class RGBConverter; diff --git a/chromium/ui/gl/gl_image_io_surface.mm b/chromium/ui/gl/gl_image_io_surface.mm index da406da75c1..12bb7790c11 100644 --- a/chromium/ui/gl/gl_image_io_surface.mm +++ b/chromium/ui/gl/gl_image_io_surface.mm @@ -18,9 +18,16 @@ #include "ui/gfx/mac/io_surface.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" +#include "ui/gl/gl_enums.h" +#include "ui/gl/gl_features.h" +#include "ui/gl/gl_version_info.h" #include "ui/gl/scoped_binders.h" #include "ui/gl/yuv_to_rgb_converter.h" +#if BUILDFLAG(USE_EGL_ON_MAC) +#include "ui/gl/gl_image_io_surface_egl.h" +#endif // BUILDFLAG(USE_EGL_ON_MAC) + // Note that this must be included after gl_bindings.h to avoid conflicts. #include <OpenGL/CGLIOSurface.h> #include <Quartz/Quartz.h> @@ -38,6 +45,7 @@ bool ValidInternalFormat(unsigned internalformat) { case GL_RG: case GL_BGRA_EXT: case GL_RGB: + case GL_RGB10_A2_EXT: case GL_RGB_YCBCR_420V_CHROMIUM: case GL_RGB_YCBCR_422_CHROMIUM: case GL_RGBA: @@ -68,6 +76,7 @@ bool ValidFormat(gfx::BufferFormat format) { case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_4444: case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::YVU_420: return false; } @@ -85,7 +94,7 @@ GLenum TextureFormat(gfx::BufferFormat format) { case gfx::BufferFormat::RG_88: return GL_RG; case gfx::BufferFormat::BGRA_8888: - case gfx::BufferFormat::BGRX_8888: + case gfx::BufferFormat::BGRX_8888: // See https://crbug.com/595948. case gfx::BufferFormat::RGBA_8888: case gfx::BufferFormat::RGBA_F16: return GL_RGBA; @@ -93,8 +102,9 @@ GLenum TextureFormat(gfx::BufferFormat format) { case gfx::BufferFormat::YUV_420_BIPLANAR: return GL_RGB_YCBCR_420V_CHROMIUM; case gfx::BufferFormat::BGRX_1010102: - // CGLTexImageIOSurface2D() (and OpenGL ES 3.0, for the case) support only - // GL_RGBA despite the hardware ignoring it. + // Technically we should use GL_RGB but CGLTexImageIOSurface2D() (and + // OpenGL ES 3.0, for the case) support only GL_RGBA (the hardware ignores + // the alpha channel anyway), see https://crbug.com/797347. return GL_RGBA; case gfx::BufferFormat::ATC: case gfx::BufferFormat::ATCIA: @@ -104,6 +114,7 @@ GLenum TextureFormat(gfx::BufferFormat format) { case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_4444: case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::YVU_420: NOTREACHED(); return 0; @@ -123,7 +134,7 @@ GLenum DataFormat(gfx::BufferFormat format) { return GL_RG; case gfx::BufferFormat::BGRA_8888: case gfx::BufferFormat::BGRX_8888: - case gfx::BufferFormat::RGBA_8888: + case gfx::BufferFormat::RGBA_8888: // See https://crbug.com/533677#c6. case gfx::BufferFormat::BGRX_1010102: return GL_BGRA; case gfx::BufferFormat::RGBA_F16: @@ -138,9 +149,10 @@ GLenum DataFormat(gfx::BufferFormat format) { case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_4444: case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: - NOTREACHED(); + NOTREACHED() << gfx::BufferFormatToString(format); return 0; } @@ -173,9 +185,10 @@ GLenum DataType(gfx::BufferFormat format) { case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_4444: case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: - NOTREACHED(); + NOTREACHED() << gfx::BufferFormatToString(format); return 0; } @@ -186,7 +199,7 @@ GLenum DataType(gfx::BufferFormat format) { // When an IOSurface is bound to a texture with internalformat "GL_RGB", many // OpenGL operations are broken. Therefore, don't allow an IOSurface to be bound // with GL_RGB unless overridden via BindTexImageWithInternalformat. -// crbug.com/595948, crbug.com/699566. +// https://crbug.com/595948, https://crbug.com/699566. GLenum ConvertRequestedInternalFormat(GLenum internalformat) { if (internalformat == GL_RGB) return GL_RGBA; @@ -198,6 +211,12 @@ GLenum ConvertRequestedInternalFormat(GLenum internalformat) { // static GLImageIOSurface* GLImageIOSurface::Create(const gfx::Size& size, unsigned internalformat) { +#if BUILDFLAG(USE_EGL_ON_MAC) + if (GLContext::GetCurrent()->GetVersionInfo()->is_angle) { + return new GLImageIOSurfaceEGL(size, internalformat); + } +#endif // BUILDFLAG(USE_EGL_ON_MAC) + return new GLImageIOSurface(size, internalformat); } @@ -217,9 +236,14 @@ bool GLImageIOSurface::Initialize(IOSurfaceRef io_surface, gfx::BufferFormat format) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!io_surface_); + if (!io_surface) { + LOG(ERROR) << "Invalid IOSurface"; + return false; + } if (!ValidInternalFormat(internalformat_)) { - LOG(ERROR) << "Invalid internalformat: " << internalformat_; + LOG(ERROR) << "Invalid internalformat: " + << GLEnums::GetStringEnum(internalformat_); return false; } @@ -282,24 +306,33 @@ bool GLImageIOSurface::BindTexImageWithInternalformat(unsigned target, return false; } + DCHECK(io_surface_); + + if (!BindTexImageImpl(internalformat)) { + return false; + } + + UMA_HISTOGRAM_TIMES("GPU.IOSurface.TexImageTime", + base::TimeTicks::Now() - start_time); + return true; +} + +bool GLImageIOSurface::BindTexImageImpl(unsigned internalformat) { CGLContextObj cgl_context = static_cast<CGLContextObj>(GLContext::GetCurrent()->GetHandle()); - DCHECK(io_surface_); - GLenum texture_format = internalformat ? internalformat : TextureFormat(format_); CGLError cgl_error = CGLTexImageIOSurface2D( - cgl_context, target, texture_format, size_.width(), size_.height(), - DataFormat(format_), DataType(format_), io_surface_.get(), 0); + cgl_context, GL_TEXTURE_RECTANGLE_ARB, texture_format, size_.width(), + size_.height(), DataFormat(format_), DataType(format_), io_surface_.get(), + 0); if (cgl_error != kCGLNoError) { LOG(ERROR) << "Error in CGLTexImageIOSurface2D: " << CGLErrorString(cgl_error); return false; } - UMA_HISTOGRAM_TIMES("GPU.IOSurface.TexImageTime", - base::TimeTicks::Now() - start_time); return true; } diff --git a/chromium/ui/gl/gl_image_io_surface_egl.h b/chromium/ui/gl/gl_image_io_surface_egl.h new file mode 100644 index 00000000000..17d96825ec4 --- /dev/null +++ b/chromium/ui/gl/gl_image_io_surface_egl.h @@ -0,0 +1,35 @@ +// Copyright 2018 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_GL_GL_IMAGE_IO_SURFACE_EGL_H_ +#define UI_GL_GL_IMAGE_IO_SURFACE_EGL_H_ + +#include "ui/gl/gl_image_io_surface.h" + +#include <egl/EGL.h> + +namespace gl { + +// Implements a IOSurface-backed GLImage that uses the +// EGL_ANGLE_iosurface_client_buffer extension to bind the IOSurface to textures +class GL_EXPORT GLImageIOSurfaceEGL : public GLImageIOSurface { + public: + GLImageIOSurfaceEGL(const gfx::Size& size, unsigned internalformat); + + void ReleaseTexImage(unsigned target) override; + + protected: + ~GLImageIOSurfaceEGL() override; + bool BindTexImageImpl(unsigned internalformat) override; + + private: + EGLDisplay display_; + EGLSurface pbuffer_; + EGLConfig dummy_config_; + bool texture_bound_; +}; + +} // namespace gl + +#endif // UI_GL_GL_IMAGE_IO_SURFACE_EGL_H_ diff --git a/chromium/ui/gl/gl_image_io_surface_egl.mm b/chromium/ui/gl/gl_image_io_surface_egl.mm new file mode 100644 index 00000000000..787870d540a --- /dev/null +++ b/chromium/ui/gl/gl_image_io_surface_egl.mm @@ -0,0 +1,154 @@ +// Copyright 2018 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/gl/gl_image_io_surface_egl.h" + +#include "ui/gl/gl_surface_egl.h" + +// Enums for the EGL_ANGLE_iosurface_client_buffer extension +#define EGL_IOSURFACE_ANGLE 0x3454 +#define EGL_IOSURFACE_PLANE_ANGLE 0x345A +#define EGL_TEXTURE_RECTANGLE_ANGLE 0x345B +#define EGL_TEXTURE_TYPE_ANGLE 0x345C +#define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D + +namespace gl { + +namespace { + +struct InternalFormatType { + InternalFormatType(GLenum format, GLenum type) : format(format), type(type) {} + + GLenum format; + GLenum type; +}; + +// Convert a gfx::BufferFormat to a (internal format, type) combination from the +// EGL_ANGLE_iosurface_client_buffer extension spec. +InternalFormatType BufferFormatToInternalFormatType(gfx::BufferFormat format) { + switch (format) { + case gfx::BufferFormat::R_8: + return {GL_RED, GL_UNSIGNED_BYTE}; + case gfx::BufferFormat::R_16: + return {GL_RED_INTEGER, GL_UNSIGNED_SHORT}; + case gfx::BufferFormat::RG_88: + return {GL_RG, GL_UNSIGNED_BYTE}; + case gfx::BufferFormat::BGRA_8888: + case gfx::BufferFormat::BGRX_8888: // See https://crbug.com/595948. + case gfx::BufferFormat::RGBA_8888: + return {GL_BGRA_EXT, GL_UNSIGNED_BYTE}; + case gfx::BufferFormat::RGBA_F16: + return {GL_RGBA, GL_HALF_FLOAT}; + case gfx::BufferFormat::UYVY_422: + case gfx::BufferFormat::YUV_420_BIPLANAR: + case gfx::BufferFormat::BGRX_1010102: + NOTIMPLEMENTED(); + return {GL_NONE, GL_NONE}; + case gfx::BufferFormat::ATC: + case gfx::BufferFormat::ATCIA: + case gfx::BufferFormat::DXT1: + case gfx::BufferFormat::DXT5: + case gfx::BufferFormat::ETC1: + case gfx::BufferFormat::BGR_565: + case gfx::BufferFormat::RGBA_4444: + case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::YVU_420: + NOTREACHED(); + return {GL_NONE, GL_NONE}; + } + + NOTREACHED(); + return {GL_NONE, GL_NONE}; +} + +} // anonymous namespace + +GLImageIOSurfaceEGL::GLImageIOSurfaceEGL(const gfx::Size& size, + unsigned internalformat) + : GLImageIOSurface(size, internalformat), + display_(GLSurfaceEGL::GetHardwareDisplay()), + pbuffer_(EGL_NO_SURFACE), + dummy_config_(nullptr), + texture_bound_(false) { + DCHECK(display_ != EGL_NO_DISPLAY); + + // When creating a pbuffer we need to supply an EGLConfig. On ANGLE and + // Swiftshader on Mac, there's only ever one config. Query it from EGL. + EGLint numConfigs = 0; + EGLBoolean result = + eglChooseConfig(display_, nullptr, &dummy_config_, 1, &numConfigs); + DCHECK(result == EGL_TRUE); + DCHECK(numConfigs = 1); + DCHECK(dummy_config_ != nullptr); +} + +GLImageIOSurfaceEGL::~GLImageIOSurfaceEGL() { + if (pbuffer_ != EGL_NO_SURFACE) { + EGLBoolean result = eglDestroySurface(display_, pbuffer_); + DCHECK(result == EGL_TRUE); + } +} + +void GLImageIOSurfaceEGL::ReleaseTexImage(unsigned target) { + DCHECK(target == GL_TEXTURE_RECTANGLE_ARB); + DCHECK(pbuffer_ != EGL_NO_SURFACE); + DCHECK(texture_bound_); + + EGLBoolean result = eglReleaseTexImage(display_, pbuffer_, EGL_BACK_BUFFER); + DCHECK(result == EGL_TRUE); + texture_bound_ = false; +} + +bool GLImageIOSurfaceEGL::BindTexImageImpl(unsigned internalformat) { + // TODO(cwallez@chromium.org): internalformat is used by Blink's + // DrawingBuffer::SetupRGBEmulationForBlitFramebuffer to bind an RGBA + // IOSurface as RGB. We should support this. + if (internalformat != 0) { + LOG(ERROR) << "GLImageIOSurfaceEGL doesn't support binding with a custom " + "internal format yet."; + return false; + } + + // Create the pbuffer representing this IOSurface lazily because we don't know + // in the constructor if we're going to be used to bind plane 0 to a texture, + // or to transform YUV to RGB. + if (pbuffer_ == EGL_NO_SURFACE) { + InternalFormatType formatType = BufferFormatToInternalFormatType(format_); + + // clang-format off + const EGLint attribs[] = { + EGL_WIDTH, size_.width(), + EGL_HEIGHT, size_.height(), + EGL_IOSURFACE_PLANE_ANGLE, 0, + EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE, + EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, formatType.format, + EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_TEXTURE_TYPE_ANGLE, formatType.type, + EGL_NONE, EGL_NONE, + }; + // clang-format off + + pbuffer_ = eglCreatePbufferFromClientBuffer(display_, EGL_IOSURFACE_ANGLE, + io_surface_.get(), dummy_config_, attribs); + if (pbuffer_ == EGL_NO_SURFACE) { + LOG(ERROR) << "eglCreatePbufferFromClientBuffer failed, EGL error is " + << eglGetError(); + return false; + } + } + + DCHECK(!texture_bound_); + EGLBoolean result = eglBindTexImage(display_, pbuffer_, EGL_BACK_BUFFER); + + if (result != EGL_TRUE) { + LOG(ERROR) << "eglBindTexImage failed, EGL error is " + << eglGetError(); + return false; + } + + texture_bound_ = true; + return true; +} + +} // namespace gl diff --git a/chromium/ui/gl/gl_image_io_surface_unittest.cc b/chromium/ui/gl/gl_image_io_surface_unittest.cc index 1b7c837ed16..3ec385e7496 100644 --- a/chromium/ui/gl/gl_image_io_surface_unittest.cc +++ b/chromium/ui/gl/gl_image_io_surface_unittest.cc @@ -5,6 +5,7 @@ #include <stddef.h> #include <stdint.h> +#include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/mac/io_surface.h" @@ -36,13 +37,27 @@ class GLImageIOSurfaceTestDelegate : public GLImageTestDelegateBase { IOSurfaceRef surface_ref = gfx::CreateIOSurface(size, format); IOReturn status = IOSurfaceLock(surface_ref, 0, nullptr); EXPECT_NE(status, kIOReturnCannotLock); + + uint8_t corrected_color[4]; + if (format == gfx::BufferFormat::RGBA_8888) { + // GL_RGBA is not supported by CGLTexImageIOSurface2D(), so we pretend it + // is GL_BGRA, (see https://crbug.com/533677#c6) swizzle the channels for + // the purpose of this test. + corrected_color[0] = color[2]; + corrected_color[1] = color[1]; + corrected_color[2] = color[0]; + corrected_color[3] = color[3]; + } else { + memcpy(corrected_color, color, arraysize(corrected_color)); + } + for (size_t plane = 0; plane < NumberOfPlanesForBufferFormat(format); ++plane) { void* data = IOSurfaceGetBaseAddressOfPlane(surface_ref, plane); GLImageTestSupport::SetBufferDataToColor( size.width(), size.height(), IOSurfaceGetBytesPerRowOfPlane(surface_ref, plane), plane, format, - color, static_cast<uint8_t*>(data)); + corrected_color, static_cast<uint8_t*>(data)); } IOSurfaceUnlock(surface_ref, 0, nullptr); @@ -55,7 +70,18 @@ class GLImageIOSurfaceTestDelegate : public GLImageTestDelegateBase { unsigned GetTextureTarget() const { return GL_TEXTURE_RECTANGLE_ARB; } - const uint8_t* GetImageColor() { return kImageColor; } + const uint8_t* GetImageColor() { + if (format != gfx::BufferFormat::BGRX_8888) + return kImageColor; + + // BGRX_8888 is actually treated as BGRA because many operations are broken + // when binding an IOSurface as GL_RGB, see https://crbug.com/595948. This + // makes the alpha value comparison fail, because we expect 0xFF but are + // actually writing something (0xAA). Correct the alpha value for the test. + static uint8_t bgrx_image_color[] = {kImageColor[0], kImageColor[1], + kImageColor[2], 0xAA}; + return bgrx_image_color; + } int GetAdmissibleError() const { return format == gfx::BufferFormat::YUV_420_BIPLANAR ? 1 : 0; @@ -65,6 +91,7 @@ class GLImageIOSurfaceTestDelegate : public GLImageTestDelegateBase { using GLImageTestTypes = testing::Types< GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>, GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>, + GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_8888>, GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>, GLImageIOSurfaceTestDelegate<gfx::BufferFormat::YUV_420_BIPLANAR>, GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_1010102>>; @@ -74,6 +101,7 @@ INSTANTIATE_TYPED_TEST_CASE_P(GLImageIOSurface, GLImageTest, GLImageTestTypes); using GLImageRGBTestTypes = testing::Types< GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>, GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>, + GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_8888>, GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>, GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_1010102>>; @@ -82,8 +110,11 @@ INSTANTIATE_TYPED_TEST_CASE_P(GLImageIOSurface, GLImageRGBTestTypes); using GLImageBindTestTypes = testing::Types< - // TODO(mcasas): enable BGRX_1010102 entry, https://crbug.com/803473. - GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>>; + GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>, + GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>, + GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_8888>, + GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>, + GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_1010102>>; INSTANTIATE_TYPED_TEST_CASE_P(GLImageIOSurface, GLImageBindTest, diff --git a/chromium/ui/gl/gl_image_memory.cc b/chromium/ui/gl/gl_image_memory.cc index 87a5c1df395..1f5b76838bd 100644 --- a/chromium/ui/gl/gl_image_memory.cc +++ b/chromium/ui/gl/gl_image_memory.cc @@ -12,6 +12,7 @@ #include "ui/gfx/buffer_format_util.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" +#include "ui/gl/gl_enums.h" #include "ui/gl/gl_version_info.h" using gfx::BufferFormat; @@ -30,6 +31,7 @@ bool ValidInternalFormat(unsigned internalformat) { case GL_RG: case GL_RGB: case GL_RGBA: + case GL_RGB10_A2_EXT: case GL_BGRA_EXT: return true; default: @@ -52,10 +54,11 @@ bool ValidFormat(gfx::BufferFormat format) { case gfx::BufferFormat::RGBX_8888: case gfx::BufferFormat::RGBA_8888: case gfx::BufferFormat::BGRX_8888: + case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::BGRA_8888: case gfx::BufferFormat::RGBA_F16: return true; - case gfx::BufferFormat::BGRX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::UYVY_422: @@ -82,10 +85,11 @@ bool IsCompressedFormat(gfx::BufferFormat format) { case gfx::BufferFormat::RGBX_8888: case gfx::BufferFormat::RGBA_8888: case gfx::BufferFormat::BGRX_8888: + case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::BGRA_8888: case gfx::BufferFormat::RGBA_F16: return false; - case gfx::BufferFormat::BGRX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::UYVY_422: @@ -126,6 +130,10 @@ GLenum TextureFormat(gfx::BufferFormat format) { case gfx::BufferFormat::BGRX_8888: return GL_RGB; case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: + // Technically speaking we should use an opaque format, but neither + // OpenGLES nor OpenGL supports the hypothetical GL_RGB10_EXT. + return GL_RGB10_A2_EXT; case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::UYVY_422: @@ -140,8 +148,10 @@ GLenum TextureFormat(gfx::BufferFormat format) { GLenum DataFormat(gfx::BufferFormat format) { switch (format) { case gfx::BufferFormat::RGBX_8888: + case gfx::BufferFormat::RGBX_1010102: return GL_RGBA; case gfx::BufferFormat::BGRX_8888: + case gfx::BufferFormat::BGRX_1010102: return GL_BGRA_EXT; case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_4444: @@ -157,7 +167,6 @@ GLenum DataFormat(gfx::BufferFormat format) { case gfx::BufferFormat::DXT5: case gfx::BufferFormat::ETC1: return TextureFormat(format); - case gfx::BufferFormat::BGRX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::UYVY_422: @@ -186,12 +195,14 @@ GLenum DataType(gfx::BufferFormat format) { return GL_UNSIGNED_SHORT; case gfx::BufferFormat::RGBA_F16: return GL_HALF_FLOAT_OES; + case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: + return GL_UNSIGNED_INT_2_10_10_10_REV; case gfx::BufferFormat::ATC: case gfx::BufferFormat::ATCIA: case gfx::BufferFormat::DXT1: case gfx::BufferFormat::DXT5: case gfx::BufferFormat::ETC1: - case gfx::BufferFormat::BGRX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::UYVY_422: @@ -213,6 +224,8 @@ GLint DataRowLength(size_t stride, gfx::BufferFormat format) { case gfx::BufferFormat::RGBX_8888: case gfx::BufferFormat::RGBA_8888: case gfx::BufferFormat::BGRX_8888: + case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::BGRA_8888: return base::checked_cast<GLint>(stride) / 4; case gfx::BufferFormat::RGBA_F16: @@ -224,7 +237,6 @@ GLint DataRowLength(size_t stride, gfx::BufferFormat format) { case gfx::BufferFormat::DXT1: case gfx::BufferFormat::DXT5: case gfx::BufferFormat::ETC1: - case gfx::BufferFormat::BGRX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::UYVY_422: @@ -330,6 +342,8 @@ std::unique_ptr<uint8_t[]> GLES2Data(const gfx::Size& size, data_format, data_type, data_row_length); case gfx::BufferFormat::RGBA_4444: case gfx::BufferFormat::RGBA_8888: + case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::BGRA_8888: case gfx::BufferFormat::RGBA_F16: case gfx::BufferFormat::R_8: @@ -356,11 +370,10 @@ std::unique_ptr<uint8_t[]> GLES2Data(const gfx::Size& size, case gfx::BufferFormat::DXT5: case gfx::BufferFormat::ETC1: return nullptr; // No data conversion needed - case gfx::BufferFormat::BGRX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::UYVY_422: - NOTREACHED(); + NOTREACHED() << gfx::BufferFormatToString(format); return nullptr; } @@ -390,12 +403,13 @@ bool GLImageMemory::Initialize(const unsigned char* memory, gfx::BufferFormat format, size_t stride) { if (!ValidInternalFormat(internalformat_)) { - LOG(ERROR) << "Invalid internalformat: " << internalformat_; + LOG(ERROR) << "Invalid internalformat: " + << GLEnums::GetStringEnum(internalformat_); return false; } if (!ValidFormat(format)) { - LOG(ERROR) << "Invalid format: " << static_cast<int>(format); + LOG(ERROR) << "Invalid format: " << gfx::BufferFormatToString(format); return false; } diff --git a/chromium/ui/gl/gl_image_native_pixmap.cc b/chromium/ui/gl/gl_image_native_pixmap.cc index 2c397340386..a917940b89b 100644 --- a/chromium/ui/gl/gl_image_native_pixmap.cc +++ b/chromium/ui/gl/gl_image_native_pixmap.cc @@ -24,6 +24,7 @@ #define DRM_FORMAT_XRGB8888 FOURCC('X', 'R', '2', '4') #define DRM_FORMAT_XBGR8888 FOURCC('X', 'B', '2', '4') #define DRM_FORMAT_XRGB2101010 FOURCC('X', 'R', '3', '0') +#define DRM_FORMAT_XBGR2101010 FOURCC('X', 'B', '3', '0') #define DRM_FORMAT_YVU420 FOURCC('Y', 'V', '1', '2') #define DRM_FORMAT_NV12 FOURCC('N', 'V', '1', '2') @@ -42,9 +43,11 @@ bool ValidInternalFormat(unsigned internalformat, gfx::BufferFormat format) { case GL_RGB_YCBCR_420V_CHROMIUM: return format == gfx::BufferFormat::YUV_420_BIPLANAR; case GL_RGBA: - return format == gfx::BufferFormat::RGBA_8888; + return format == gfx::BufferFormat::RGBA_8888 || + format == gfx::BufferFormat::RGBX_1010102; case GL_BGRA_EXT: - return format == gfx::BufferFormat::BGRA_8888; + return format == gfx::BufferFormat::BGRA_8888 || + format == gfx::BufferFormat::BGRX_1010102; case GL_RED_EXT: return format == gfx::BufferFormat::R_8; case GL_R16_EXT: @@ -67,6 +70,7 @@ bool ValidFormat(gfx::BufferFormat format) { case gfx::BufferFormat::BGRA_8888: case gfx::BufferFormat::BGRX_8888: case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YUV_420_BIPLANAR: return true; @@ -105,6 +109,8 @@ EGLint FourCC(gfx::BufferFormat format) { return DRM_FORMAT_XRGB8888; case gfx::BufferFormat::BGRX_1010102: return DRM_FORMAT_XRGB2101010; + case gfx::BufferFormat::RGBX_1010102: + return DRM_FORMAT_XBGR2101010; case gfx::BufferFormat::YVU_420: return DRM_FORMAT_YVU420; case gfx::BufferFormat::YUV_420_BIPLANAR: @@ -141,6 +147,8 @@ gfx::BufferFormat GetBufferFormatFromFourCCFormat(int format) { return gfx::BufferFormat::BGRX_8888; case DRM_FORMAT_XRGB2101010: return gfx::BufferFormat::BGRX_1010102; + case DRM_FORMAT_XBGR2101010: + return gfx::BufferFormat::RGBX_1010102; case DRM_FORMAT_RGB565: return gfx::BufferFormat::BGR_565; case DRM_FORMAT_NV12: @@ -412,10 +420,12 @@ unsigned GLImageNativePixmap::GetInternalFormatForTesting( case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBX_8888: case gfx::BufferFormat::BGRX_8888: - case gfx::BufferFormat::BGRX_1010102: return GL_RGB; case gfx::BufferFormat::RGBA_8888: return GL_RGBA; + case gfx::BufferFormat::BGRX_1010102: + case gfx::BufferFormat::RGBX_1010102: + return GL_RGB10_A2_EXT; case gfx::BufferFormat::BGRA_8888: return GL_BGRA_EXT; case gfx::BufferFormat::YVU_420: diff --git a/chromium/ui/gl/gl_image_shared_memory_unittest.cc b/chromium/ui/gl/gl_image_shared_memory_unittest.cc index fdef8d937c8..e48ed75c8f0 100644 --- a/chromium/ui/gl/gl_image_shared_memory_unittest.cc +++ b/chromium/ui/gl/gl_image_shared_memory_unittest.cc @@ -7,6 +7,7 @@ #include "base/memory/shared_memory.h" #include "base/sys_info.h" +#include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_image_shared_memory.h" #include "ui/gl/test/gl_image_test_template.h" @@ -50,6 +51,13 @@ using GLImageTestTypes = testing::Types< GLImageSharedMemoryTestDelegate<gfx::BufferFormat::RGBX_8888>, GLImageSharedMemoryTestDelegate<gfx::BufferFormat::RGBA_8888>, GLImageSharedMemoryTestDelegate<gfx::BufferFormat::BGRX_8888>, +#if defined(OS_LINUX) + // Fails on Win nVidia and linux android: the test writes nothing (we read + // back the color used to clear the buffer). + // TODO(mcasas): enable those paltforms https://crbug.com/803451. + GLImageSharedMemoryTestDelegate<gfx::BufferFormat::BGRX_1010102>, + GLImageSharedMemoryTestDelegate<gfx::BufferFormat::RGBX_1010102>, +#endif GLImageSharedMemoryTestDelegate<gfx::BufferFormat::BGRA_8888>>; INSTANTIATE_TYPED_TEST_CASE_P(GLImageSharedMemory, diff --git a/chromium/ui/gl/gl_surface_egl.cc b/chromium/ui/gl/gl_surface_egl.cc index 67255b5f33a..f1413f215a3 100644 --- a/chromium/ui/gl/gl_surface_egl.cc +++ b/chromium/ui/gl/gl_surface_egl.cc @@ -29,6 +29,7 @@ #include "ui/gl/gl_context_egl.h" #include "ui/gl/gl_image.h" #include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_presentation_helper.h" #include "ui/gl/gl_surface_stub.h" #include "ui/gl/gl_utils.h" #include "ui/gl/scoped_make_current.h" @@ -198,6 +199,8 @@ class EGLSyncControlVSyncProvider : public SyncControlVSyncProvider { return false; } + bool IsHWClock() const override { return true; } + private: EGLSurface surface_; @@ -981,7 +984,8 @@ bool NativeViewGLSurfaceEGL::Initialize(GLSurfaceFormat format) { vsync_provider_internal_ = std::make_unique<EGLSyncControlVSyncProvider>(surface_); } - + presentation_helper_ = + std::make_unique<GLSurfacePresentationHelper>(GetVSyncProvider()); return true; } @@ -1034,11 +1038,16 @@ void NativeViewGLSurfaceEGL::SetEnableSwapTimestamps() { use_egl_timestamps_ = !supported_egl_timestamps_.empty(); } +bool NativeViewGLSurfaceEGL::SupportsPresentationCallback() { + return true; +} + bool NativeViewGLSurfaceEGL::InitializeNativeWindow() { return true; } void NativeViewGLSurfaceEGL::Destroy() { + presentation_helper_ = nullptr; vsync_provider_internal_ = nullptr; if (surface_) { @@ -1056,7 +1065,6 @@ bool NativeViewGLSurfaceEGL::IsOffscreen() { gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers( const PresentationCallback& callback) { - // TODO(penghuang): Provide presentation feedback. https://crbug.com/776877 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers", "width", GetSize().width(), "height", GetSize().height()); @@ -1073,17 +1081,16 @@ gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers( !!eglGetNextFrameIdANDROID(GetDisplay(), surface_, &newFrameId); } + GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers( + presentation_helper_.get(), callback); if (!eglSwapBuffers(GetDisplay(), surface_)) { DVLOG(1) << "eglSwapBuffers failed with error " << GetLastEGLErrorString(); - return gfx::SwapResult::SWAP_FAILED; - } - - if (use_egl_timestamps_) { + scoped_swap_buffers.set_result(gfx::SwapResult::SWAP_FAILED); + } else if (use_egl_timestamps_) { UpdateSwapEvents(newFrameId, newFrameIdIsValid); } - - return gfx::SwapResult::SWAP_ACK; + return scoped_swap_buffers.result(); } void NativeViewGLSurfaceEGL::UpdateSwapEvents(EGLuint64KHR newFrameId, @@ -1271,21 +1278,22 @@ bool NativeViewGLSurfaceEGL::BuffersFlipped() const { gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffersWithDamage( const std::vector<int>& rects, const PresentationCallback& callback) { - // TODO(penghuang): Provide presentation feedback. https://crbug.com/776877 DCHECK(supports_swap_buffer_with_damage_); if (!CommitAndClearPendingOverlays()) { DVLOG(1) << "Failed to commit pending overlay planes."; return gfx::SwapResult::SWAP_FAILED; } + GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers( + presentation_helper_.get(), callback); if (!eglSwapBuffersWithDamageKHR(GetDisplay(), surface_, const_cast<EGLint*>(rects.data()), static_cast<EGLint>(rects.size() / 4))) { DVLOG(1) << "eglSwapBuffersWithDamageKHR failed with error " << GetLastEGLErrorString(); - return gfx::SwapResult::SWAP_FAILED; + scoped_swap_buffers.set_result(gfx::SwapResult::SWAP_FAILED); } - return gfx::SwapResult::SWAP_ACK; + return scoped_swap_buffers.result(); } gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer( @@ -1294,7 +1302,6 @@ gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer( int width, int height, const PresentationCallback& callback) { - // TODO(penghuang): Provide presentation feedback. https://crbug.com/776877 DCHECK(supports_post_sub_buffer_); if (!CommitAndClearPendingOverlays()) { DVLOG(1) << "Failed to commit pending overlay planes."; @@ -1306,12 +1313,15 @@ gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer( // bottom left. y = GetSize().height() - y - height; } + + GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers( + presentation_helper_.get(), callback); if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) { DVLOG(1) << "eglPostSubBufferNV failed with error " << GetLastEGLErrorString(); - return gfx::SwapResult::SWAP_FAILED; + scoped_swap_buffers.set_result(gfx::SwapResult::SWAP_FAILED); } - return gfx::SwapResult::SWAP_ACK; + return scoped_swap_buffers.result(); } bool NativeViewGLSurfaceEGL::SupportsCommitOverlayPlanes() { @@ -1324,13 +1334,21 @@ bool NativeViewGLSurfaceEGL::SupportsCommitOverlayPlanes() { gfx::SwapResult NativeViewGLSurfaceEGL::CommitOverlayPlanes( const PresentationCallback& callback) { - // TODO(penghuang): Provide presentation feedback. https://crbug.com/776877 DCHECK(SupportsCommitOverlayPlanes()); // Here we assume that the overlays scheduled on this surface will display // themselves to the screen right away in |CommitAndClearPendingOverlays|, // rather than being queued and waiting for a "swap" signal. - return CommitAndClearPendingOverlays() ? gfx::SwapResult::SWAP_ACK - : gfx::SwapResult::SWAP_FAILED; + GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers( + presentation_helper_.get(), callback); + if (!CommitAndClearPendingOverlays()) + scoped_swap_buffers.set_result(gfx::SwapResult::SWAP_FAILED); + return scoped_swap_buffers.result(); +} + +bool NativeViewGLSurfaceEGL::OnMakeCurrent(GLContext* context) { + if (presentation_helper_) + presentation_helper_->OnMakeCurrent(context, this); + return GLSurfaceEGL::OnMakeCurrent(context); } gfx::VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() { @@ -1367,9 +1385,13 @@ bool NativeViewGLSurfaceEGL::CommitAndClearPendingOverlays() { return true; bool success = true; +#if defined(OS_ANDROID) for (const auto& overlay : pending_overlays_) success &= overlay.ScheduleOverlayPlane(window_); pending_overlays_.clear(); +#else + NOTIMPLEMENTED(); +#endif return success; } diff --git a/chromium/ui/gl/gl_surface_egl.h b/chromium/ui/gl/gl_surface_egl.h index 30a71969d2b..1e8cb17097c 100644 --- a/chromium/ui/gl/gl_surface_egl.h +++ b/chromium/ui/gl/gl_surface_egl.h @@ -28,6 +28,8 @@ namespace gl { +class GLSurfacePresentationHelper; + // If adding a new type, also add it to EGLDisplayType in // tools/metrics/histograms/histograms.xml. Don't remove or reorder entries. enum DisplayType { @@ -104,10 +106,10 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL { std::unique_ptr<gfx::VSyncProvider> vsync_provider); // Implement GLSurface. - using GLSurfaceEGL::Initialize; bool Initialize(GLSurfaceFormat format) override; bool SupportsSwapTimestamps() const override; void SetEnableSwapTimestamps() override; + bool SupportsPresentationCallback() override; void Destroy() override; bool Resize(const gfx::Size& size, float scale_factor, @@ -127,6 +129,7 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL { bool SupportsCommitOverlayPlanes() override; gfx::SwapResult CommitOverlayPlanes( const PresentationCallback& callback) override; + bool OnMakeCurrent(GLContext* context) override; gfx::VSyncProvider* GetVSyncProvider() override; bool ScheduleOverlayPlane(int z_order, gfx::OverlayTransform transform, @@ -180,6 +183,8 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL { base::queue<SwapInfo> swap_info_queue_; + std::unique_ptr<GLSurfacePresentationHelper> presentation_helper_; + DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceEGL); }; diff --git a/chromium/ui/gl/gl_surface_glx.cc b/chromium/ui/gl/gl_surface_glx.cc index ba10ace1d50..fb426317082 100644 --- a/chromium/ui/gl/gl_surface_glx.cc +++ b/chromium/ui/gl/gl_surface_glx.cc @@ -168,6 +168,8 @@ class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider { return true; } + bool IsHWClock() const override { return true; } + private: GLXWindow glx_window_; @@ -344,8 +346,8 @@ class SGIVideoSyncVSyncProvider const gfx::VSyncProvider::UpdateVSyncCallback& callback) override { // Only one outstanding request per surface. if (!pending_callback_) { - pending_callback_.reset( - new gfx::VSyncProvider::UpdateVSyncCallback(callback)); + pending_callback_ = + std::make_unique<gfx::VSyncProvider::UpdateVSyncCallback>(callback); vsync_thread_->task_runner()->PostTask( FROM_HERE, base::BindOnce(&SGIVideoSyncProviderThreadShim::GetVSyncParameters, @@ -361,7 +363,8 @@ class SGIVideoSyncVSyncProvider return false; } - bool SupportGetVSyncParametersIfAvailable() override { return false; } + bool SupportGetVSyncParametersIfAvailable() const override { return false; } + bool IsHWClock() const override { return false; } private: void PendingCallbackRunner(const base::TimeTicks timebase, @@ -475,6 +478,10 @@ bool GLSurfaceGLX::InitializeExtensionSettingsOneOff() { if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) { Display* video_sync_display = gfx::OpenNewXDisplay(); + if (!video_sync_display) { + LOG(ERROR) << "Could not open video sync display"; + return false; + } if (!CreateDummyWindow(video_sync_display)) { LOG(ERROR) << "CreateDummyWindow(video_sync_display) failed"; return false; @@ -609,13 +616,15 @@ bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) { } if (g_glx_oml_sync_control_supported) { - vsync_provider_.reset(new OMLSyncControlVSyncProvider(glx_window_)); - presentation_helper_ = std::make_unique<GLSurfacePresentationHelper>( - vsync_provider_.get(), true); + vsync_provider_ = + std::make_unique<OMLSyncControlVSyncProvider>(glx_window_); + presentation_helper_ = + std::make_unique<GLSurfacePresentationHelper>(vsync_provider_.get()); } else if (g_glx_sgi_video_sync_supported) { - vsync_provider_.reset(new SGIVideoSyncVSyncProvider(parent_window_)); - presentation_helper_ = std::make_unique<GLSurfacePresentationHelper>( - vsync_provider_.get(), false); + vsync_provider_ = + std::make_unique<SGIVideoSyncVSyncProvider>(parent_window_); + presentation_helper_ = + std::make_unique<GLSurfacePresentationHelper>(vsync_provider_.get()); } else { // Assume a refresh rate of 59.9 Hz, which will cause us to skip // 1 frame every 10 seconds on a 60Hz monitor, but will prevent us @@ -625,8 +634,8 @@ bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) { const base::TimeTicks kDefaultTimebase; const base::TimeDelta kDefaultInterval = base::TimeDelta::FromSeconds(1) / 59.9; - vsync_provider_.reset( - new gfx::FixedVSyncProvider(kDefaultTimebase, kDefaultInterval)); + vsync_provider_ = std::make_unique<gfx::FixedVSyncProvider>( + kDefaultTimebase, kDefaultInterval); presentation_helper_ = std::make_unique<GLSurfacePresentationHelper>( kDefaultTimebase, kDefaultInterval); } @@ -668,10 +677,10 @@ gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers( const PresentationCallback& callback) { TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", "width", GetSize().width(), "height", GetSize().height()); - presentation_helper_->PreSwapBuffers(callback); + GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers( + presentation_helper_.get(), callback); glXSwapBuffers(g_display, GetDrawableHandle()); - presentation_helper_->PostSwapBuffers(); - return gfx::SwapResult::SWAP_ACK; + return scoped_swap_buffers.result(); } gfx::Size NativeViewGLSurfaceGLX::GetSize() { @@ -711,10 +720,11 @@ gfx::SwapResult NativeViewGLSurfaceGLX::PostSubBuffer( int height, const PresentationCallback& callback) { DCHECK(g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer); - presentation_helper_->PreSwapBuffers(callback); + + GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers( + presentation_helper_.get(), callback); glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height); - presentation_helper_->PostSwapBuffers(); - return gfx::SwapResult::SWAP_ACK; + return scoped_swap_buffers.result(); } bool NativeViewGLSurfaceGLX::OnMakeCurrent(GLContext* context) { diff --git a/chromium/ui/gl/gl_surface_presentation_helper.cc b/chromium/ui/gl/gl_surface_presentation_helper.cc index 41acab425f3..6825fda6a77 100644 --- a/chromium/ui/gl/gl_surface_presentation_helper.cc +++ b/chromium/ui/gl/gl_surface_presentation_helper.cc @@ -11,6 +11,19 @@ namespace gl { +GLSurfacePresentationHelper::ScopedSwapBuffers::ScopedSwapBuffers( + GLSurfacePresentationHelper* helper, + const GLSurface::PresentationCallback& callback) + : helper_(helper) { + if (helper_) + helper_->PreSwapBuffers(callback); +} + +GLSurfacePresentationHelper::ScopedSwapBuffers::~ScopedSwapBuffers() { + if (helper_) + helper_->PostSwapBuffers(result_); +} + GLSurfacePresentationHelper::Frame::Frame(Frame&& other) = default; GLSurfacePresentationHelper::Frame::Frame( @@ -24,19 +37,13 @@ GLSurfacePresentationHelper::Frame& GLSurfacePresentationHelper::Frame:: operator=(Frame&& other) = default; GLSurfacePresentationHelper::GLSurfacePresentationHelper( - gfx::VSyncProvider* vsync_provider, - bool hw_clock) - : vsync_provider_(vsync_provider), - hw_clock_(hw_clock), - weak_ptr_factory_(this) { - DCHECK(vsync_provider_); -} + gfx::VSyncProvider* vsync_provider) + : vsync_provider_(vsync_provider), weak_ptr_factory_(this) {} GLSurfacePresentationHelper::GLSurfacePresentationHelper( base::TimeTicks timebase, base::TimeDelta interval) : vsync_provider_(nullptr), - hw_clock_(false), vsync_timebase_(timebase), vsync_interval_(interval), weak_ptr_factory_(this) {} @@ -88,9 +95,21 @@ void GLSurfacePresentationHelper::PreSwapBuffers( pending_frames_.push_back(Frame(std::move(timer), callback)); } -void GLSurfacePresentationHelper::PostSwapBuffers() { - if (!waiting_for_vsync_parameters_) - CheckPendingFrames(); +void GLSurfacePresentationHelper::PostSwapBuffers(gfx::SwapResult result) { + DCHECK(!pending_frames_.empty()); + if (result == gfx::SwapResult::SWAP_ACK && gpu_timing_client_) { + if (!waiting_for_vsync_parameters_) + CheckPendingFrames(); + return; + } + + auto frame = std::move(pending_frames_.back()); + pending_frames_.pop_back(); + if (frame.timer) { + bool has_context = gl_context_ && gl_context_->IsCurrent(surface_); + frame.timer->Destroy(has_context); + } + frame.callback.Run(gfx::PresentationFeedback()); } void GLSurfacePresentationHelper::CheckPendingFrames() { @@ -113,7 +132,8 @@ void GLSurfacePresentationHelper::CheckPendingFrames() { if (gl_context_ && !gl_context_->IsCurrent(surface_)) { gpu_timing_client_ = nullptr; for (auto& frame : pending_frames_) { - frame.timer->Destroy(false /* has_context */); + if (frame.timer) + frame.timer->Destroy(false /* has_context */); frame.callback.Run(gfx::PresentationFeedback()); } pending_frames_.clear(); @@ -155,6 +175,7 @@ void GLSurfacePresentationHelper::CheckPendingFrames() { }; const bool fixed_vsync = !vsync_provider_; + const bool hw_clock = vsync_provider_ && vsync_provider_->IsHWClock(); if (vsync_interval_.is_zero() || fixed_vsync) { // If VSync parameters are fixed or not avaliable, we just run // presentation callbacks with timestamp from GPUTimers. @@ -170,7 +191,7 @@ void GLSurfacePresentationHelper::CheckPendingFrames() { // The |vsync_timebase_| is the closest VSync's timestamp after the GPU // finished renderering. timestamp = vsync_timebase_; - if (hw_clock_) + if (hw_clock) flags |= gfx::PresentationFeedback::kHWClock; } else { // The |vsync_timebase_| isn't the closest VSync's timestamp after the diff --git a/chromium/ui/gl/gl_surface_presentation_helper.h b/chromium/ui/gl/gl_surface_presentation_helper.h index b00f6e94ea3..6baf88fafcb 100644 --- a/chromium/ui/gl/gl_surface_presentation_helper.h +++ b/chromium/ui/gl/gl_surface_presentation_helper.h @@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" +#include "ui/gfx/swap_result.h" #include "ui/gl/gl_export.h" #include "ui/gl/gl_surface.h" @@ -26,8 +27,24 @@ class GPUTimer; // implementations. class GL_EXPORT GLSurfacePresentationHelper { public: - GLSurfacePresentationHelper(gfx::VSyncProvider* vsync_provider, - bool hw_clock); + class GL_EXPORT ScopedSwapBuffers { + public: + ScopedSwapBuffers(GLSurfacePresentationHelper* helper, + const GLSurface::PresentationCallback& callback); + ~ScopedSwapBuffers(); + + void set_result(gfx::SwapResult result) { result_ = result; } + gfx::SwapResult result() const { return result_; } + + private: + GLSurfacePresentationHelper* const helper_; + gfx::SwapResult result_ = gfx::SwapResult::SWAP_ACK; + + DISALLOW_COPY_AND_ASSIGN(ScopedSwapBuffers); + }; + + explicit GLSurfacePresentationHelper(gfx::VSyncProvider* vsync_provider); + // For using fixed VSync provider. GLSurfacePresentationHelper(const base::TimeTicks timebase, const base::TimeDelta interval); @@ -35,7 +52,7 @@ class GL_EXPORT GLSurfacePresentationHelper { void OnMakeCurrent(GLContext* context, GLSurface* surface); void PreSwapBuffers(const GLSurface::PresentationCallback& callback); - void PostSwapBuffers(); + void PostSwapBuffers(gfx::SwapResult result); private: struct Frame { @@ -58,7 +75,6 @@ class GL_EXPORT GLSurfacePresentationHelper { const base::TimeDelta interval); gfx::VSyncProvider* const vsync_provider_; - const bool hw_clock_; scoped_refptr<GLContext> gl_context_; GLSurface* surface_ = nullptr; scoped_refptr<GPUTimingClient> gpu_timing_client_; diff --git a/chromium/ui/gl/init/BUILD.gn b/chromium/ui/gl/init/BUILD.gn index 3400ef6be17..d55a06bf481 100644 --- a/chromium/ui/gl/init/BUILD.gn +++ b/chromium/ui/gl/init/BUILD.gn @@ -26,6 +26,7 @@ jumbo_component("init") { deps = [ "//base", "//ui/gfx", + "//ui/gl:gl_features", ] public_deps = [ @@ -37,7 +38,6 @@ jumbo_component("init") { "gl_factory_android.cc", "gl_initializer_android.cc", ] - deps += [ "//ui/gl:gl_features" ] } else if (is_win) { sources += [ "gl_factory_win.cc", @@ -46,7 +46,6 @@ jumbo_component("init") { libs = [ "dwmapi.lib" ] ldflags = [ "/DELAYLOAD:dwmapi.dll" ] - deps += [ "//ui/gl:gl_features" ] } else if (is_mac) { sources += [ "gl_factory_mac.cc", @@ -60,10 +59,7 @@ jumbo_component("init") { "gl_initializer_x11.cc", ] - deps += [ - "//ui/gfx/x", - "//ui/gl:gl_features", - ] + deps += [ "//ui/gfx/x" ] } else if (use_ozone) { sources += [ "gl_factory_ozone.cc", diff --git a/chromium/ui/gl/init/create_gr_gl_interface.cc b/chromium/ui/gl/init/create_gr_gl_interface.cc index e7b1c6e7afe..283dd1f028f 100644 --- a/chromium/ui/gl/init/create_gr_gl_interface.cc +++ b/chromium/ui/gl/init/create_gr_gl_interface.cc @@ -487,14 +487,6 @@ sk_sp<const GrGLInterface> CreateGrGLInterface( functions->fWaitSync = gl->glWaitSyncFn; functions->fDeleteSync = gl->glDeleteSyncFn; - functions->fBindImageTexture = gl->glBindImageTextureEXTFn; - // TODO(piman): skia type is wrong. - functions->fMemoryBarrier = - reinterpret_cast<GrGLMemoryBarrierProc>(gl->glMemoryBarrierEXTFn); - - // GL 4.5 or GL_ARB_ES3_1_compatibility or ES 3.1 - // functions->fMemoryBarrierByRegion = gl->glMemoryBarrierByRegionFn; - functions->fGetInternalformativ = gl->glGetInternalformativFn; interface->fStandard = standard; diff --git a/chromium/ui/gl/init/gl_factory_mac.cc b/chromium/ui/gl/init/gl_factory_mac.cc index 72037d428e0..52544651c31 100644 --- a/chromium/ui/gl/init/gl_factory_mac.cc +++ b/chromium/ui/gl/init/gl_factory_mac.cc @@ -11,6 +11,7 @@ #include "ui/gl/gl_context_cgl.h" #include "ui/gl/gl_context_osmesa.h" #include "ui/gl/gl_context_stub.h" +#include "ui/gl/gl_features.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_surface.h" @@ -18,6 +19,11 @@ #include "ui/gl/gl_surface_stub.h" #include "ui/gl/gl_switches.h" +#if BUILDFLAG(USE_EGL_ON_MAC) +#include "ui/gl/gl_context_egl.h" +#include "ui/gl/gl_surface_egl.h" +#endif // BUILDFLAG(USE_EGL_ON_MAC) + namespace gl { namespace init { @@ -59,6 +65,9 @@ class NoOpGLSurface : public GLSurface { std::vector<GLImplementation> GetAllowedGLImplementations() { std::vector<GLImplementation> impls; impls.push_back(kGLImplementationDesktopGLCoreProfile); +#if BUILDFLAG(USE_EGL_ON_MAC) + impls.push_back(kGLImplementationEGLGLES2); +#endif // BUILDFLAG(USE_EGL_ON_MAC) impls.push_back(kGLImplementationDesktopGL); impls.push_back(kGLImplementationAppleGL); impls.push_back(kGLImplementationOSMesaGL); @@ -77,12 +86,13 @@ scoped_refptr<GLContext> CreateGLContext(GLShareGroup* share_group, case kGLImplementationDesktopGL: case kGLImplementationDesktopGLCoreProfile: case kGLImplementationAppleGL: - // Note that with virtualization we might still be able to make current - // a different onscreen surface with this context later. But we should - // always be creating the context with an offscreen surface first. - DCHECK(compatible_surface->IsOffscreen()); return InitializeGLContext(new GLContextCGL(share_group), compatible_surface, attribs); +#if BUILDFLAG(USE_EGL_ON_MAC) + case kGLImplementationEGLGLES2: + return InitializeGLContext(new GLContextEGL(share_group), + compatible_surface, attribs); +#endif // BUILDFLAG(USE_EGL_ON_MAC) case kGLImplementationOSMesaGL: return InitializeGLContext(new GLContextOSMesa(share_group), compatible_surface, attribs); @@ -105,7 +115,8 @@ scoped_refptr<GLSurface> CreateViewGLSurface(gfx::AcceleratedWidget window) { switch (GetGLImplementation()) { case kGLImplementationDesktopGL: case kGLImplementationDesktopGLCoreProfile: - case kGLImplementationAppleGL: { + case kGLImplementationAppleGL: + case kGLImplementationEGLGLES2: { NOTIMPLEMENTED() << "No onscreen support on Mac."; return nullptr; } @@ -134,6 +145,16 @@ scoped_refptr<GLSurface> CreateOffscreenGLSurfaceWithFormat( case kGLImplementationAppleGL: return InitializeGLSurfaceWithFormat( new NoOpGLSurface(size), format); +#if BUILDFLAG(USE_EGL_ON_MAC) + case kGLImplementationEGLGLES2: + if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() && + size.width() == 0 && size.height() == 0) { + return InitializeGLSurfaceWithFormat(new SurfacelessEGL(size), format); + } else { + return InitializeGLSurfaceWithFormat(new PbufferGLSurfaceEGL(size), + format); + } +#endif // BUILDFLAG(USE_EGL_ON_MAC) case kGLImplementationMockGL: case kGLImplementationStubGL: return new GLSurfaceStub; diff --git a/chromium/ui/gl/init/gl_initializer_mac.cc b/chromium/ui/gl/init/gl_initializer_mac.cc index 828ce9bb013..3ca3b88be3f 100644 --- a/chromium/ui/gl/init/gl_initializer_mac.cc +++ b/chromium/ui/gl/init/gl_initializer_mac.cc @@ -17,12 +17,18 @@ #include "base/threading/thread_restrictions.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" +#include "ui/gl/gl_features.h" #include "ui/gl/gl_gl_api_implementation.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_osmesa_api_implementation.h" #include "ui/gl/gl_surface.h" #include "ui/gl/gpu_switching_manager.h" +#if BUILDFLAG(USE_EGL_ON_MAC) +#include "ui/gl/gl_egl_api_implementation.h" +#include "ui/gl/gl_surface_egl.h" +#endif // BUILDFLAG(USE_EGL_ON_MAC) + namespace gl { namespace init { @@ -127,6 +133,56 @@ bool InitializeStaticCGLInternal(GLImplementation implementation) { return true; } +#if BUILDFLAG(USE_EGL_ON_MAC) +const char kGLESv2ANGLELibraryName[] = "libGLESv2.dylib"; +const char kEGLANGLELibraryName[] = "libEGL.dylib"; + +bool InitializeStaticEGLInternal(GLImplementation implementation) { + if (implementation == kGLImplementationSwiftShaderGL) { + return false; + } + + base::FilePath module_path; + if (!PathService::Get(base::DIR_MODULE, &module_path)) { + return false; + } + + base::FilePath glesv2_path = module_path.Append(kGLESv2ANGLELibraryName); + base::NativeLibrary gles_library = LoadLibraryAndPrintError(glesv2_path); + if (!gles_library) { + return false; + } + + base::FilePath egl_path = module_path.Append(kEGLANGLELibraryName); + base::NativeLibrary egl_library = LoadLibraryAndPrintError(egl_path); + if (!egl_library) { + base::UnloadNativeLibrary(gles_library); + return false; + } + + GLGetProcAddressProc get_proc_address = + reinterpret_cast<GLGetProcAddressProc>( + base::GetFunctionPointerFromNativeLibrary(egl_library, + "eglGetProcAddress")); + if (!get_proc_address) { + LOG(ERROR) << "eglGetProcAddress not found."; + base::UnloadNativeLibrary(egl_library); + base::UnloadNativeLibrary(gles_library); + return false; + } + + SetGLGetProcAddressProc(get_proc_address); + AddGLNativeLibrary(egl_library); + AddGLNativeLibrary(gles_library); + SetGLImplementation(kGLImplementationEGLGLES2); + + InitializeStaticGLBindingsGL(); + InitializeStaticGLBindingsEGL(); + + return true; +} +#endif // BUILDFLAG(USE_EGL_ON_MAC) + } // namespace bool InitializeGLOneOffPlatform() { @@ -139,6 +195,14 @@ bool InitializeGLOneOffPlatform() { return false; } return true; +#if BUILDFLAG(USE_EGL_ON_MAC) + case kGLImplementationEGLGLES2: + if (!GLSurfaceEGL::InitializeOneOff(0)) { + LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; + return false; + } + return true; +#endif // BUILDFLAG(USE_EGL_ON_MAC) default: return true; } @@ -163,6 +227,10 @@ bool InitializeStaticGLBindings(GLImplementation implementation) { case kGLImplementationDesktopGLCoreProfile: case kGLImplementationAppleGL: return InitializeStaticCGLInternal(implementation); +#if BUILDFLAG(USE_EGL_ON_MAC) + case kGLImplementationEGLGLES2: + return InitializeStaticEGLInternal(implementation); +#endif // BUILDFLAG(USE_EGL_ON_MAC) case kGLImplementationMockGL: case kGLImplementationStubGL: SetGLImplementation(implementation); diff --git a/chromium/ui/gl/init/ozone_util.h b/chromium/ui/gl/init/ozone_util.h index 02360ee291f..11c04d0c7e7 100644 --- a/chromium/ui/gl/init/ozone_util.h +++ b/chromium/ui/gl/init/ozone_util.h @@ -20,7 +20,7 @@ inline ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() { // Returns true if there is an GLOzone for the specified GL implementation. inline bool HasGLOzone(GLImplementation impl) { - return GetSurfaceFactoryOzone()->GetGLOzone(impl) != nullptr; + return GetSurfaceFactoryOzone() && GetSurfaceFactoryOzone()->GetGLOzone(impl); } // Returns true if there is an GLOzone for the set GL implementation. diff --git a/chromium/ui/gl/sync_control_vsync_provider.cc b/chromium/ui/gl/sync_control_vsync_provider.cc index 7f9c6c01aec..2b94e43a57d 100644 --- a/chromium/ui/gl/sync_control_vsync_provider.cc +++ b/chromium/ui/gl/sync_control_vsync_provider.cc @@ -65,13 +65,9 @@ bool SyncControlVSyncProvider::GetVSyncParametersIfAvailable( // Both Intel and Mali drivers will return TRUE for GetSyncValues // but a value of 0 for MSC if they cannot access the CRTC data structure // associated with the surface. crbug.com/231945 - bool prev_invalid_msc = invalid_msc_; invalid_msc_ = (media_stream_counter == 0); - if (invalid_msc_) { - LOG_IF(ERROR, !prev_invalid_msc) << "glXGetSyncValuesOML " - "should not return TRUE with a media stream counter of 0."; + if (invalid_msc_) return false; - } struct timespec real_time; clock_gettime(CLOCK_REALTIME, &real_time); @@ -164,7 +160,7 @@ bool SyncControlVSyncProvider::GetVSyncParametersIfAvailable( #endif // defined(OS_LINUX) } -bool SyncControlVSyncProvider::SupportGetVSyncParametersIfAvailable() { +bool SyncControlVSyncProvider::SupportGetVSyncParametersIfAvailable() const { #if defined(OS_LINUX) return true; #else diff --git a/chromium/ui/gl/sync_control_vsync_provider.h b/chromium/ui/gl/sync_control_vsync_provider.h index 7612e60a0fc..735d7ee61c9 100644 --- a/chromium/ui/gl/sync_control_vsync_provider.h +++ b/chromium/ui/gl/sync_control_vsync_provider.h @@ -23,7 +23,7 @@ class SyncControlVSyncProvider : public gfx::VSyncProvider { void GetVSyncParameters(const UpdateVSyncCallback& callback) override; bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, base::TimeDelta* interval) override; - bool SupportGetVSyncParametersIfAvailable() override; + bool SupportGetVSyncParametersIfAvailable() const override; static constexpr bool IsSupported() { #if defined(OS_LINUX) diff --git a/chromium/ui/gl/vsync_provider_win.cc b/chromium/ui/gl/vsync_provider_win.cc index 041cdd7b395..34dc007783f 100644 --- a/chromium/ui/gl/vsync_provider_win.cc +++ b/chromium/ui/gl/vsync_provider_win.cc @@ -122,7 +122,11 @@ bool VSyncProviderWin::GetVSyncParametersIfAvailable( return true; } -bool VSyncProviderWin::SupportGetVSyncParametersIfAvailable() { +bool VSyncProviderWin::SupportGetVSyncParametersIfAvailable() const { + return true; +} + +bool VSyncProviderWin::IsHWClock() const { return true; } diff --git a/chromium/ui/gl/vsync_provider_win.h b/chromium/ui/gl/vsync_provider_win.h index 0ec5644276c..3ee9a29856b 100644 --- a/chromium/ui/gl/vsync_provider_win.h +++ b/chromium/ui/gl/vsync_provider_win.h @@ -22,7 +22,8 @@ class GL_EXPORT VSyncProviderWin : public gfx::VSyncProvider { void GetVSyncParameters(const UpdateVSyncCallback& callback) override; bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, base::TimeDelta* interval) override; - bool SupportGetVSyncParametersIfAvailable() override; + bool SupportGetVSyncParametersIfAvailable() const override; + bool IsHWClock() const override; private: gfx::AcceleratedWidget window_; diff --git a/chromium/ui/keyboard/BUILD.gn b/chromium/ui/keyboard/BUILD.gn index 3b2816104d8..ccf79d43925 100644 --- a/chromium/ui/keyboard/BUILD.gn +++ b/chromium/ui/keyboard/BUILD.gn @@ -35,6 +35,8 @@ jumbo_component("keyboard") { "keyboard_util.h", "notification_manager.cc", "notification_manager.h", + "queued_container_type.cc", + "queued_container_type.h", ] defines = [ "KEYBOARD_IMPLEMENTATION" ] diff --git a/chromium/ui/keyboard/container_behavior.h b/chromium/ui/keyboard/container_behavior.h index e6224c3552d..d641d88bff6 100644 --- a/chromium/ui/keyboard/container_behavior.h +++ b/chromium/ui/keyboard/container_behavior.h @@ -60,9 +60,11 @@ class KEYBOARD_EXPORT ContainerBehavior { virtual bool IsDragHandle(const gfx::Vector2d& offset, const gfx::Size& keyboard_size) const = 0; - virtual void SavePosition(const gfx::Point& position) = 0; + virtual void SavePosition(const gfx::Rect& keyboard_bounds, + const gfx::Size& screen_size) = 0; - virtual void HandlePointerEvent(const ui::LocatedEvent& event) = 0; + virtual void HandlePointerEvent(const ui::LocatedEvent& event, + const gfx::Rect& display_bounds) = 0; virtual ContainerType GetType() const = 0; diff --git a/chromium/ui/keyboard/container_floating_behavior.cc b/chromium/ui/keyboard/container_floating_behavior.cc index 9d93d393baf..855cdc202cf 100644 --- a/chromium/ui/keyboard/container_floating_behavior.cc +++ b/chromium/ui/keyboard/container_floating_behavior.cc @@ -69,7 +69,7 @@ const gfx::Rect ContainerFloatingBehavior::AdjustSetBoundsRequest( const gfx::Rect& requested_bounds) { gfx::Rect keyboard_bounds = requested_bounds; - if (UseDefaultPosition()) { + if (!default_position_) { // If the keyboard hasn't been shown yet, ignore the request and use // default. gfx::Point default_location = @@ -80,18 +80,39 @@ const gfx::Rect ContainerFloatingBehavior::AdjustSetBoundsRequest( // the screen. keyboard_bounds = ContainKeyboardToScreenBounds(keyboard_bounds, display_bounds); + SavePosition(keyboard_bounds, display_bounds.size()); } return keyboard_bounds; } +void ContainerFloatingBehavior::SavePosition(const gfx::Rect& keyboard_bounds, + const gfx::Size& screen_size) { + int left_distance = keyboard_bounds.x(); + int right_distance = screen_size.width() - (keyboard_bounds.right()); + int top_distance = keyboard_bounds.y(); + int bottom_distance = screen_size.height() - (keyboard_bounds.bottom()); + + double available_width = left_distance + right_distance; + double available_height = top_distance + bottom_distance; + + if (!default_position_) { + default_position_ = std::make_unique<KeyboardPosition>(); + } + + default_position_->left_padding_allotment_ratio = + left_distance / available_width; + default_position_->top_padding_allotment_ratio = + top_distance / available_height; +} + gfx::Rect ContainerFloatingBehavior::ContainKeyboardToScreenBounds( const gfx::Rect& keyboard_bounds, const gfx::Rect& display_bounds) const { int left = keyboard_bounds.x(); int top = keyboard_bounds.y(); - int right = left + keyboard_bounds.width(); - int bottom = top + keyboard_bounds.height(); + int right = keyboard_bounds.right(); + int bottom = keyboard_bounds.bottom(); // Prevent keyboard from appearing off screen or overlapping with the edge. if (left < 0) { @@ -118,37 +139,36 @@ bool ContainerFloatingBehavior::IsOverscrollAllowed() const { return false; } -bool ContainerFloatingBehavior::UseDefaultPosition() const { - // (-1, -1) is used as a sentinel unset value. - return default_position_.x() == -1; -} - gfx::Point ContainerFloatingBehavior::GetPositionForShowingKeyboard( const gfx::Size& keyboard_size, const gfx::Rect& display_bounds) const { // Start with the last saved position - gfx::Point position = default_position_; - if (UseDefaultPosition()) { + gfx::Point top_left_offset; + KeyboardPosition* position = default_position_.get(); + if (position == nullptr) { // If there is none, center the keyboard along the bottom of the screen. - position.set_x(display_bounds.width() - keyboard_size.width() - - kDefaultDistanceFromScreenRight); - position.set_y(display_bounds.height() - keyboard_size.height() - - kDefaultDistanceFromScreenBottom); + top_left_offset.set_x(display_bounds.width() - keyboard_size.width() - + kDefaultDistanceFromScreenRight); + top_left_offset.set_y(display_bounds.height() - keyboard_size.height() - + kDefaultDistanceFromScreenBottom); + } else { + double left = (display_bounds.width() - keyboard_size.width()) * + position->left_padding_allotment_ratio; + double top = (display_bounds.height() - keyboard_size.height()) * + position->top_padding_allotment_ratio; + top_left_offset.set_x((int)left); + top_left_offset.set_y((int)top); } // Make sure that this location is valid according to the current size of the // screen. - gfx::Rect keyboard_bounds = gfx::Rect(position, keyboard_size); + gfx::Rect keyboard_bounds = gfx::Rect(top_left_offset, keyboard_size); gfx::Rect valid_keyboard_bounds = ContainKeyboardToScreenBounds(keyboard_bounds, display_bounds); return valid_keyboard_bounds.origin(); } -void ContainerFloatingBehavior::SavePosition(const gfx::Point& position) { - default_position_ = position; -} - bool ContainerFloatingBehavior::IsDragHandle( const gfx::Vector2d& offset, const gfx::Size& keyboard_size) const { @@ -156,7 +176,8 @@ bool ContainerFloatingBehavior::IsDragHandle( } void ContainerFloatingBehavior::HandlePointerEvent( - const ui::LocatedEvent& event) { + const ui::LocatedEvent& event, + const gfx::Rect& display_bounds) { // Cannot call UI-backed operations without a KeyboardController DCHECK(controller_); auto kb_offset = gfx::Vector2d(event.x(), event.y()); @@ -205,7 +226,7 @@ void ContainerFloatingBehavior::HandlePointerEvent( const gfx::Rect new_bounds = gfx::Rect(new_keyboard_location, keyboard_bounds.size()); controller_->MoveKeyboard(new_bounds); - SavePosition(container->bounds().origin()); + SavePosition(container->bounds(), display_bounds.size()); handle_drag = true; } if (!handle_drag && drag_descriptor_) { @@ -219,9 +240,10 @@ void ContainerFloatingBehavior::SetCanonicalBounds( const gfx::Rect& display_bounds) { gfx::Point keyboard_location = GetPositionForShowingKeyboard(container->bounds().size(), display_bounds); - SavePosition(keyboard_location); - container->SetBounds( - gfx::Rect(keyboard_location, container->bounds().size())); + gfx::Rect keyboard_bounds = + gfx::Rect(keyboard_location, container->bounds().size()); + SavePosition(keyboard_bounds, display_bounds.size()); + container->SetBounds(keyboard_bounds); } bool ContainerFloatingBehavior::TextBlurHidesKeyboard() const { diff --git a/chromium/ui/keyboard/container_floating_behavior.h b/chromium/ui/keyboard/container_floating_behavior.h index 89124dfa9a4..6ea2b2abfde 100644 --- a/chromium/ui/keyboard/container_floating_behavior.h +++ b/chromium/ui/keyboard/container_floating_behavior.h @@ -23,6 +23,11 @@ namespace keyboard { constexpr int kDefaultDistanceFromScreenBottom = 20; constexpr int kDefaultDistanceFromScreenRight = 20; +struct KeyboardPosition { + double left_padding_allotment_ratio; + double top_padding_allotment_ratio; +}; + class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior { public: ContainerFloatingBehavior(KeyboardController* controller); @@ -42,8 +47,10 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior { bool IsOverscrollAllowed() const override; bool IsDragHandle(const gfx::Vector2d& offset, const gfx::Size& keyboard_size) const override; - void SavePosition(const gfx::Point& position) override; - void HandlePointerEvent(const ui::LocatedEvent& event) override; + void SavePosition(const gfx::Rect& keyboard_bounds, + const gfx::Size& screen_size) override; + void HandlePointerEvent(const ui::LocatedEvent& event, + const gfx::Rect& display_bounds) override; void SetCanonicalBounds(aura::Window* container, const gfx::Rect& display_bounds) override; ContainerType GetType() const override; @@ -52,6 +59,11 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior { bool BoundsAffectWorkspaceLayout() const override; bool SetDraggableArea(const gfx::Rect& rect) override; + // Calculate the position of the keyboard for when it is being shown. + gfx::Point GetPositionForShowingKeyboard( + const gfx::Size& keyboard_size, + const gfx::Rect& display_bounds) const; + private: // Ensures that the keyboard is neither off the screen nor overlapping an // edge. @@ -62,19 +74,11 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior { // Saves the current keyboard location for use the next time it is displayed. void UpdateLastPoint(const gfx::Point& position); - // Returns true if the keyboard has not been display/moved yet and the default - // position should be used. - bool UseDefaultPosition() const; - - // Calculate the position of the keyboard for when it is being shown. - gfx::Point GetPositionForShowingKeyboard( - const gfx::Size& keyboard_size, - const gfx::Rect& display_bounds) const; - KeyboardController* controller_; // TODO(blakeo): cache the default_position_ on a per-display basis. - gfx::Point default_position_ = gfx::Point(-1, -1); + std::unique_ptr<struct keyboard::KeyboardPosition> default_position_ = + nullptr; // Current state of a cursor drag to move the keyboard, if one exists. // Otherwise nullptr. diff --git a/chromium/ui/keyboard/container_floating_behavior_unittest.cc b/chromium/ui/keyboard/container_floating_behavior_unittest.cc index c3e81c710f4..6db3b404566 100644 --- a/chromium/ui/keyboard/container_floating_behavior_unittest.cc +++ b/chromium/ui/keyboard/container_floating_behavior_unittest.cc @@ -32,7 +32,8 @@ TEST(ContainerFloatingBehaviorTest, AdjustSetBoundsRequest) { keyboard_height); // Save an arbitrary position so that default location will not be used. - floating_behavior.SavePosition(gfx::Point(0, 0)); + floating_behavior.SavePosition( + gfx::Rect(0, 0, keyboard_width, keyboard_height), workspace.size()); gfx::Rect result = floating_behavior.AdjustSetBoundsRequest(workspace, center); @@ -49,6 +50,69 @@ TEST(ContainerFloatingBehaviorTest, AdjustSetBoundsRequest) { result); } +TEST(ContainerFloatingBehaviorTest, AdjustSetBoundsRequestVariousSides) { + ContainerFloatingBehavior floating_behavior(nullptr); + + const int keyboard_width = 100; + const int keyboard_height = 100; + gfx::Size keyboard_size = gfx::Size(keyboard_width, keyboard_height); + gfx::Rect workspace_wide(0, 0, 1000, 500); + gfx::Rect workspace_tall(0, 0, 500, 1000); + gfx::Rect top_left(0, 0, keyboard_width, keyboard_height); + gfx::Rect top_right(900, 0, keyboard_width, keyboard_height); + gfx::Rect bottom_left(0, 400, keyboard_width, keyboard_height); + gfx::Rect bottom_right(900, 400, keyboard_width, keyboard_height); + gfx::Rect bottomish_center(450, 390, keyboard_width, keyboard_height); + + // Save an arbitrary position so that default location will not be used. + floating_behavior.SavePosition( + gfx::Rect(0, 0, keyboard_width, keyboard_height), workspace_wide.size()); + + floating_behavior.AdjustSetBoundsRequest(workspace_wide, top_left); + gfx::Point result = floating_behavior.GetPositionForShowingKeyboard( + keyboard_size, workspace_wide); + ASSERT_EQ(gfx::Point(0, 0), result); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_tall); + ASSERT_EQ(gfx::Point(0, 0), result); + + floating_behavior.AdjustSetBoundsRequest(workspace_wide, top_right); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_wide); + ASSERT_EQ(gfx::Point(900, 0), result); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_tall); + ASSERT_EQ(gfx::Point(400, 0), result); + + floating_behavior.AdjustSetBoundsRequest(workspace_wide, bottom_left); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_wide); + ASSERT_EQ(gfx::Point(0, 400), result); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_tall); + ASSERT_EQ(gfx::Point(0, 900), result); + + floating_behavior.AdjustSetBoundsRequest(workspace_wide, bottom_right); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_wide); + ASSERT_EQ(gfx::Point(900, 400), result); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_tall); + ASSERT_EQ(gfx::Point(400, 900), result); + + floating_behavior.AdjustSetBoundsRequest(workspace_wide, bottomish_center); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_wide); + ASSERT_EQ(gfx::Point(450, 390), result); + result = floating_behavior.GetPositionForShowingKeyboard(keyboard_size, + workspace_tall); + + // rather than 400:0 for the vertical padding, use 390:10 + // with 900 pixels available this ratio results in 877.5, which is truncated. + // 390 / 400 * 900 = 877.5 + ASSERT_EQ(gfx::Point(200, 877), result); +} + TEST(ContainerFloatingBehaviorTest, DontSaveCoordinatesUntilKeyboardMoved) { ContainerFloatingBehavior floating_behavior(nullptr); @@ -77,7 +141,8 @@ TEST(ContainerFloatingBehaviorTest, DontSaveCoordinatesUntilKeyboardMoved) { // Simulate the user clicking and moving the keyboard to some arbitrary // location (it doesn't matter where). Now that the coordinate is known to be // user-determined. - floating_behavior.SavePosition(gfx::Point(10, 10)); + floating_behavior.SavePosition( + gfx::Rect(10, 10, keyboard_width, keyboard_height), workspace.size()); // Move the keyboard somewhere else. The coordinates should be taken as-is // without being adjusted. diff --git a/chromium/ui/keyboard/container_full_width_behavior.cc b/chromium/ui/keyboard/container_full_width_behavior.cc index 15cbf04698c..2dca9c087ec 100644 --- a/chromium/ui/keyboard/container_full_width_behavior.cc +++ b/chromium/ui/keyboard/container_full_width_behavior.cc @@ -82,7 +82,8 @@ bool ContainerFullWidthBehavior::IsOverscrollAllowed() const { return controller_ && !controller_->keyboard_locked(); } -void ContainerFullWidthBehavior::SavePosition(const gfx::Point& position) { +void ContainerFullWidthBehavior::SavePosition(const gfx::Rect& keyboard_bounds, + const gfx::Size& screen_size) { // No-op. Nothing to save. } @@ -93,7 +94,8 @@ bool ContainerFullWidthBehavior::IsDragHandle( } void ContainerFullWidthBehavior::HandlePointerEvent( - const ui::LocatedEvent& event) { + const ui::LocatedEvent& event, + const gfx::Rect& display_bounds) { // No-op. Nothing special to do for pointer events. } diff --git a/chromium/ui/keyboard/container_full_width_behavior.h b/chromium/ui/keyboard/container_full_width_behavior.h index 5a5d1a493d7..077d3b92eb6 100644 --- a/chromium/ui/keyboard/container_full_width_behavior.h +++ b/chromium/ui/keyboard/container_full_width_behavior.h @@ -39,8 +39,10 @@ class KEYBOARD_EXPORT ContainerFullWidthBehavior : public ContainerBehavior { bool IsOverscrollAllowed() const override; bool IsDragHandle(const gfx::Vector2d& offset, const gfx::Size& keyboard_size) const override; - void SavePosition(const gfx::Point& position) override; - void HandlePointerEvent(const ui::LocatedEvent& event) override; + void SavePosition(const gfx::Rect& keyboard_bounds, + const gfx::Size& screen_size) override; + void HandlePointerEvent(const ui::LocatedEvent& event, + const gfx::Rect& display_bounds) override; void SetCanonicalBounds(aura::Window* container, const gfx::Rect& display_bounds) override; ContainerType GetType() const override; diff --git a/chromium/ui/keyboard/keyboard_controller.cc b/chromium/ui/keyboard/keyboard_controller.cc index 76a576bfe09..b9ba7f519ef 100644 --- a/chromium/ui/keyboard/keyboard_controller.cc +++ b/chromium/ui/keyboard/keyboard_controller.cc @@ -12,6 +12,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" @@ -25,6 +26,7 @@ #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/display/types/display_constants.h" +#include "ui/events/base_event_utils.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/path.h" @@ -36,6 +38,7 @@ #include "ui/keyboard/keyboard_ui.h" #include "ui/keyboard/keyboard_util.h" #include "ui/keyboard/notification_manager.h" +#include "ui/keyboard/queued_container_type.h" #include "ui/wm/core/window_animations.h" #if defined(OS_CHROMEOS) @@ -51,6 +54,13 @@ constexpr int kHideKeyboardDelayMs = 100; // intermediate state for more than 5 seconds. constexpr int kReportLingeringStateDelayMs = 5000; +// Delay threshold after the keyboard enters the WILL_HIDE state. If text focus +// is regained during this threshold, the keyboard will show again, even if it +// is an asynchronous event. This is for the benefit of things like login flow +// where the password field may get text focus after an animation that plays +// after the user enters their username. +constexpr int kTransientBlurThresholdMs = 3500; + // State transition diagram (document linked from crbug.com/719905) bool isAllowedStateTransition(keyboard::KeyboardControllerState from, keyboard::KeyboardControllerState to) { @@ -202,12 +212,11 @@ KeyboardController::KeyboardController(std::unique_ptr<KeyboardUI> ui, show_on_content_update_(false), keyboard_locked_(false), state_(KeyboardControllerState::UNKNOWN), - enqueued_container_type_(ContainerType::FULL_WIDTH), weak_factory_report_lingering_state_(this), weak_factory_will_hide_(this) { ui_->GetInputMethod()->AddObserver(this); ui_->SetController(this); - SetContainerBehaviorInternal(enqueued_container_type_); + SetContainerBehaviorInternal(ContainerType::FULL_WIDTH); ChangeState(KeyboardControllerState::INITIAL); } @@ -385,11 +394,8 @@ void KeyboardController::HideKeyboard(HideReason reason) { } void KeyboardController::HideAnimationFinished() { - if (state_ != KeyboardControllerState::HIDDEN) - return; - - if (enqueued_container_type_ != container_behavior_->GetType()) { - SetContainerBehaviorInternal(enqueued_container_type_); + if (state_ == KeyboardControllerState::HIDDEN && queued_container_type_) { + SetContainerBehaviorInternal(queued_container_type_->container_type()); ShowKeyboard(false /* lock */); } } @@ -498,17 +504,36 @@ void KeyboardController::OnTextInputStateChanged( return; } } else { - // Abort a pending keyboard hide. - if (WillHideKeyboard()) - ChangeState(KeyboardControllerState::SHOWN); + switch (state_) { + case KeyboardControllerState::WILL_HIDE: + // Abort a pending keyboard hide. + ChangeState(KeyboardControllerState::SHOWN); + return; + case KeyboardControllerState::HIDDEN: + if (focused) + ShowKeyboardIfWithinTransientBlurThreshold(); + return; + default: + break; + } // Do not explicitly show the Virtual keyboard unless it is in the process - // of hiding. Instead, the virtual keyboard is shown in response to a user - // gesture (mouse or touch) that is received while an element has input - // focus. Showing the keyboard requires an explicit call to - // OnShowImeIfNeeded. + // of hiding or the hide duration was very short (transient blur). Instead, + // the virtual keyboard is shown in response to a user gesture (mouse or + // touch) that is received while an element has input focus. Showing the + // keyboard requires an explicit call to OnShowImeIfNeeded. } } +void KeyboardController::ShowKeyboardIfWithinTransientBlurThreshold() { + static const base::TimeDelta kTransientBlurThreshold = + base::TimeDelta::FromMilliseconds(kTransientBlurThresholdMs); + + const base::Time now = base::Time::Now(); + const base::TimeDelta time_since_last_blur = now - time_of_last_blur_; + if (time_since_last_blur < kTransientBlurThreshold) + ShowKeyboard(false); +} + void KeyboardController::OnShowImeIfNeeded() { // Calling |ShowKeyboardInternal| may move the keyboard to another display. if (IsKeyboardEnabled() && !keyboard_locked()) @@ -624,6 +649,10 @@ void KeyboardController::PopulateKeyboardContent(int64_t display_id, container_behavior_->DoShowingAnimation(container_.get(), &settings); + // the queued container behavior will notify JS to change layout when it + // gets destroyed. + queued_container_type_ = nullptr; + ChangeState(KeyboardControllerState::SHOWN); NotifyKeyboardBoundsChangingAndEnsureCaretInWorkArea(); } @@ -678,6 +707,8 @@ void KeyboardController::ChangeState(KeyboardControllerState state) { if (state_ == state) return; + KeyboardControllerState original_state = state_; + state_ = state; if (state != KeyboardControllerState::WILL_HIDE) @@ -691,11 +722,16 @@ void KeyboardController::ChangeState(KeyboardControllerState state) { switch (state_) { case KeyboardControllerState::LOADING_EXTENSION: case KeyboardControllerState::WILL_HIDE: + if (state_ == KeyboardControllerState::WILL_HIDE && + original_state == KeyboardControllerState::SHOWN) { + time_of_last_blur_ = base::Time::Now(); + } base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::BindOnce(&KeyboardController::ReportLingeringState, weak_factory_report_lingering_state_.GetWeakPtr()), base::TimeDelta::FromMilliseconds(kReportLingeringStateDelayMs)); + break; default: // Do nothing @@ -737,18 +773,31 @@ bool KeyboardController::IsOverscrollAllowed() const { } void KeyboardController::HandlePointerEvent(const ui::LocatedEvent& event) { - container_behavior_->HandlePointerEvent(event); + container_behavior_->HandlePointerEvent( + event, container_->GetRootWindow()->bounds()); } -void KeyboardController::SetContainerType(const ContainerType type) { - if (container_behavior_->GetType() == type) + +void KeyboardController::SetContainerType( + const ContainerType type, + base::OnceCallback<void(bool)> callback) { + if (container_behavior_->GetType() == type) { + std::move(callback).Run(false); return; + } - enqueued_container_type_ = type; if (state_ == KeyboardControllerState::SHOWN) { + // Keyboard is already shown. Hiding the keyboard at first then switching + // container type. + queued_container_type_ = + std::make_unique<QueuedContainerType>(this, type, std::move(callback)); HideKeyboard(HIDE_REASON_AUTOMATIC); } else { + // Keyboard is hidden. Switching the container type immediately and invoking + // the passed callback now. SetContainerBehaviorInternal(type); + DCHECK(GetActiveContainerType() == type); + std::move(callback).Run(true /* change_successful */); } } diff --git a/chromium/ui/keyboard/keyboard_controller.h b/chromium/ui/keyboard/keyboard_controller.h index c702b72940b..ef9356317a4 100644 --- a/chromium/ui/keyboard/keyboard_controller.h +++ b/chromium/ui/keyboard/keyboard_controller.h @@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/observer_list.h" +#include "base/time/time.h" #include "ui/aura/window_observer.h" #include "ui/base/ime/input_method_observer.h" #include "ui/base/ime/text_input_type.h" @@ -22,6 +23,7 @@ #include "ui/keyboard/keyboard_layout_delegate.h" #include "ui/keyboard/keyboard_util.h" #include "ui/keyboard/notification_manager.h" +#include "ui/keyboard/queued_container_type.h" namespace aura { class Window; @@ -152,6 +154,10 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver, KeyboardControllerState GetStateForTest() const { return state_; } + ContainerType GetActiveContainerType() const { + return container_behavior_->GetType(); + } + const gfx::Rect AdjustSetBoundsRequest( const gfx::Rect& display_bounds, const gfx::Rect& requested_bounds) const; @@ -170,7 +176,8 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver, // Sets the active container type. If the keyboard is currently shown, this // will trigger a hide animation and a subsequent show animation. Otherwise // the ContainerBehavior change is synchronous. - void SetContainerType(const ContainerType type); + void SetContainerType(const ContainerType type, + base::OnceCallback<void(bool)> callback); // Sets floating keyboard drggable rect. bool SetDraggableArea(const gfx::Rect& rect); @@ -240,6 +247,10 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver, // Reports error histogram in case lingering in an intermediate state. void ReportLingeringState(); + // Shows the keyboard if the last time the keyboard was hidden was a small + // time ago. + void ShowKeyboardIfWithinTransientBlurThreshold(); + void SetContainerBehaviorInternal(const ContainerType type); std::unique_ptr<KeyboardUI> ui_; @@ -252,6 +263,8 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver, // Current active visual behavior for the keyboard container. std::unique_ptr<ContainerBehavior> container_behavior_; + std::unique_ptr<QueuedContainerType> queued_container_type_; + // If true, show the keyboard window when keyboard UI content updates. bool show_on_content_update_; @@ -268,10 +281,10 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver, KeyboardControllerState state_; - ContainerType enqueued_container_type_; - NotificationManager notification_manager_; + base::Time time_of_last_blur_ = base::Time::UnixEpoch(); + static KeyboardController* instance_; base::WeakPtrFactory<KeyboardController> weak_factory_report_lingering_state_; diff --git a/chromium/ui/keyboard/keyboard_controller_observer.h b/chromium/ui/keyboard/keyboard_controller_observer.h index bdaa053ac8d..822d07a3a1e 100644 --- a/chromium/ui/keyboard/keyboard_controller_observer.h +++ b/chromium/ui/keyboard/keyboard_controller_observer.h @@ -30,26 +30,26 @@ class KEYBOARD_EXPORT KeyboardControllerObserver { virtual ~KeyboardControllerObserver() {} // Called when the keyboard is shown or closed. - virtual void OnKeyboardAvailabilityChanging(const bool is_available) {} + virtual void OnKeyboardAvailabilityChanged(const bool is_available) {} // Called when the keyboard bounds are changing. - virtual void OnKeyboardVisibleBoundsChanging(const gfx::Rect& new_bounds) {} + virtual void OnKeyboardVisibleBoundsChanged(const gfx::Rect& new_bounds) {} // Called when the keyboard bounds have changed in a way that should affect // the usable region of the workspace. - virtual void OnKeyboardWorkspaceOccludedBoundsChanging( + virtual void OnKeyboardWorkspaceOccludedBoundsChanged( const gfx::Rect& new_bounds) {} // Called when the keyboard bounds have changed in a way that affects how the // workspace should change to not take up the screen space occupied by the // keyboard. - virtual void OnKeyboardWorkspaceDisplacingBoundsChanging( + virtual void OnKeyboardWorkspaceDisplacingBoundsChanged( const gfx::Rect& new_bounds){}; // Redundant with other various notification methods. Use this if the state of // multiple properties need to be conveyed simultaneously to observer // implementations without the need to track multiple stateful properties. - virtual void OnKeyboardAppearanceChanging( + virtual void OnKeyboardAppearanceChanged( const KeyboardStateDescriptor& state){}; // Called when the keyboard was closed. diff --git a/chromium/ui/keyboard/keyboard_controller_unittest.cc b/chromium/ui/keyboard/keyboard_controller_unittest.cc index fad8f1e77a7..8ecafe94069 100644 --- a/chromium/ui/keyboard/keyboard_controller_unittest.cc +++ b/chromium/ui/keyboard/keyboard_controller_unittest.cc @@ -14,7 +14,7 @@ #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/client/focus_client.h" -#include "ui/aura/test/aura_test_helper.h" +#include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" #include "ui/base/ime/dummy_text_input_client.h" @@ -176,15 +176,39 @@ class TestKeyboardLayoutDelegate : public KeyboardLayoutDelegate { DISALLOW_COPY_AND_ASSIGN(TestKeyboardLayoutDelegate); }; +class SetModeCallbackInvocationCounter { + public: + SetModeCallbackInvocationCounter() : weak_factory_invoke_(this) {} + + void Invoke(bool status) { + if (status) + invocation_count_success_++; + else + invocation_count_failure_++; + } + + base::OnceCallback<void(bool)> GetInvocationCallback() { + return base::BindOnce(&SetModeCallbackInvocationCounter::Invoke, + weak_factory_invoke_.GetWeakPtr()); + } + + int invocation_count_for_status(bool status) { + return status ? invocation_count_success_ : invocation_count_failure_; + } + + private: + int invocation_count_success_ = 0; + int invocation_count_failure_ = 0; + base::WeakPtrFactory<SetModeCallbackInvocationCounter> weak_factory_invoke_; +}; + } // namespace -class KeyboardControllerTest : public testing::Test, +class KeyboardControllerTest : public aura::test::AuraTestBase, public KeyboardControllerObserver { public: KeyboardControllerTest() - : scoped_task_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::UI), - visible_bounds_number_of_calls_(0), + : visible_bounds_number_of_calls_(0), occluding_bounds_number_of_calls_(0), is_available_number_of_calls_(0), is_available_(false), @@ -192,24 +216,14 @@ class KeyboardControllerTest : public testing::Test, ~KeyboardControllerTest() override {} void SetUp() override { - // The ContextFactory must exist before any Compositors are created. - bool enable_pixel_output = false; - ui::ContextFactory* context_factory = nullptr; - ui::ContextFactoryPrivate* context_factory_private = nullptr; - - ui::InitializeContextFactoryForTests(enable_pixel_output, &context_factory, - &context_factory_private); - ui::SetUpInputMethodFactoryForTesting(); - aura_test_helper_.reset(new aura::test::AuraTestHelper()); - aura_test_helper_->SetUp(context_factory, context_factory_private); - new wm::DefaultActivationClient(aura_test_helper_->root_window()); + aura::test::AuraTestBase::SetUp(); + new wm::DefaultActivationClient(root_window()); focus_controller_.reset(new TestFocusController(root_window())); layout_delegate_.reset(new TestKeyboardLayoutDelegate()); - controller_.reset( - new KeyboardController(std::make_unique<TestKeyboardUI>( - aura_test_helper_->host()->GetInputMethod()), - layout_delegate_.get())); + controller_.reset(new KeyboardController( + std::make_unique<TestKeyboardUI>(host()->GetInputMethod()), + layout_delegate_.get())); controller()->AddObserver(this); } @@ -218,11 +232,9 @@ class KeyboardControllerTest : public testing::Test, controller()->RemoveObserver(this); controller_.reset(); focus_controller_.reset(); - aura_test_helper_->TearDown(); - ui::TerminateContextFactoryForTests(); + aura::test::AuraTestBase::TearDown(); } - aura::Window* root_window() { return aura_test_helper_->root_window(); } KeyboardUI* ui() { return controller_->ui(); } KeyboardController* controller() { return controller_.get(); } @@ -240,16 +252,16 @@ class KeyboardControllerTest : public testing::Test, protected: // KeyboardControllerObserver overrides - void OnKeyboardVisibleBoundsChanging(const gfx::Rect& new_bounds) override { + void OnKeyboardVisibleBoundsChanged(const gfx::Rect& new_bounds) override { visible_bounds_ = new_bounds; visible_bounds_number_of_calls_++; } - void OnKeyboardWorkspaceOccludedBoundsChanging( + void OnKeyboardWorkspaceOccludedBoundsChanged( const gfx::Rect& new_bounds) override { occluding_bounds_ = new_bounds; occluding_bounds_number_of_calls_++; } - void OnKeyboardAvailabilityChanging(bool is_available) override { + void OnKeyboardAvailabilityChanged(bool is_available) override { is_available_ = is_available; is_available_number_of_calls_++; } @@ -271,6 +283,15 @@ class KeyboardControllerTest : public testing::Test, bool IsKeyboardClosed() { return keyboard_closed_; } + void SetProgrammaticFocus(ui::TextInputClient* client) { + controller_->OnTextInputStateChanged(client); + } + + void AddTimeToTransientBlurCounter(double seconds) { + controller_->time_of_last_blur_ -= + base::TimeDelta::FromMilliseconds((int)(1000 * seconds)); + } + void SetFocus(ui::TextInputClient* client) { ui::InputMethod* input_method = ui()->GetInputMethod(); input_method->SetFocusedTextInputClient(client); @@ -308,8 +329,6 @@ class KeyboardControllerTest : public testing::Test, run_loop->Run(); } - base::test::ScopedTaskEnvironment scoped_task_environment_; - std::unique_ptr<aura::test::AuraTestHelper> aura_test_helper_; std::unique_ptr<TestFocusController> focus_controller_; private: @@ -449,6 +468,82 @@ TEST_F(KeyboardControllerTest, ClickDoesNotFocusKeyboard) { keyboard_container->RemovePreTargetHandler(&observer); } +// Tests that blur-then-focus that occur in less than the transient threshold +// cause the keyboard to re-show. +TEST_F(KeyboardControllerTest, TransientBlurShortDelay) { + ScopedAccessibilityKeyboardEnabler scoped_keyboard_enabler; + ui::DummyTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT); + ui::DummyTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE); + base::RunLoop run_loop; + aura::Window* keyboard_container(controller()->GetContainerWindow()); + std::unique_ptr<KeyboardContainerObserver> keyboard_container_observer( + new KeyboardContainerObserver(keyboard_container, &run_loop)); + root_window()->AddChild(keyboard_container); + + // Keyboard is hidden + EXPECT_FALSE(keyboard_container->IsVisible()); + + // Set programmatic focus to the text field. Nothing happens + SetProgrammaticFocus(&input_client); + EXPECT_FALSE(keyboard_container->IsVisible()); + + // Click it for real. Keyboard starts to appear. + SetFocus(&input_client); + EXPECT_TRUE(keyboard_container->IsVisible()); + + // Focus a non text field + SetFocus(&no_input_client); + + // It waits 100 ms and then hides. Wait for this routine to finish. + EXPECT_TRUE(WillHideKeyboard()); + RunLoop(&run_loop); + EXPECT_FALSE(keyboard_container->IsVisible()); + + // Virtually wait half a second + AddTimeToTransientBlurCounter(0.5); + // Apply programmatic focus to the text field. + SetProgrammaticFocus(&input_client); + EXPECT_TRUE(keyboard_container->IsVisible()); + EXPECT_FALSE(WillHideKeyboard()); +} + +// Tests that blur-then-focus that occur past the transient threshold do not +// cause the keyboard to re-show. +TEST_F(KeyboardControllerTest, TransientBlurLongDelay) { + ScopedAccessibilityKeyboardEnabler scoped_keyboard_enabler; + ui::DummyTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT); + ui::DummyTextInputClient no_input_client(ui::TEXT_INPUT_TYPE_NONE); + base::RunLoop run_loop; + aura::Window* keyboard_container(controller()->GetContainerWindow()); + std::unique_ptr<KeyboardContainerObserver> keyboard_container_observer( + new KeyboardContainerObserver(keyboard_container, &run_loop)); + root_window()->AddChild(keyboard_container); + + // Keyboard is hidden + EXPECT_FALSE(keyboard_container->IsVisible()); + + // Set programmatic focus to the text field. Nothing happens + SetProgrammaticFocus(&input_client); + EXPECT_FALSE(keyboard_container->IsVisible()); + + // Click it for real. Keyboard starts to appear. + SetFocus(&input_client); + EXPECT_TRUE(keyboard_container->IsVisible()); + + // Focus a non text field + SetFocus(&no_input_client); + + // It waits 100 ms and then hides. Wait for this routine to finish. + EXPECT_TRUE(WillHideKeyboard()); + RunLoop(&run_loop); + EXPECT_FALSE(keyboard_container->IsVisible()); + + // Wait 5 seconds and then set programmatic focus to a text field + AddTimeToTransientBlurCounter(5.0); + SetProgrammaticFocus(&input_client); + EXPECT_FALSE(keyboard_container->IsVisible()); +} + TEST_F(KeyboardControllerTest, VisibilityChangeWithTextInputTypeChange) { ScopedAccessibilityKeyboardEnabler scoped_keyboard_enabler; ui::DummyTextInputClient input_client_0(ui::TEXT_INPUT_TYPE_TEXT); @@ -655,13 +750,27 @@ TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) { EXPECT_EQ(gfx::Rect(), notified_occluding_bounds()); EXPECT_FALSE(notified_is_available()); - controller()->SetContainerType(ContainerType::FLOATING); + SetModeCallbackInvocationCounter invocation_counter; + controller()->SetContainerType(ContainerType::FLOATING, + invocation_counter.GetInvocationCallback()); + EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true)); + EXPECT_EQ(0, invocation_counter.invocation_count_for_status(false)); ShowKeyboard(); RunAnimationForLayer(layer); + EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true)); + EXPECT_EQ(0, invocation_counter.invocation_count_for_status(false)); // Visible bounds and occluding bounds are now different. EXPECT_EQ(keyboard_container()->bounds(), notified_visible_bounds()); EXPECT_EQ(gfx::Rect(), notified_occluding_bounds()); EXPECT_TRUE(notified_is_available()); + + // callback should do nothing when container mode is set to the current active + // container type. An unnecessary call gets registered synchronously as a + // failure status to the callback. + controller()->SetContainerType(ContainerType::FLOATING, + invocation_counter.GetInvocationCallback()); + EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true)); + EXPECT_EQ(1, invocation_counter.invocation_count_for_status(false)); } // Show keyboard during keyboard hide animation should abort the hide animation diff --git a/chromium/ui/keyboard/keyboard_util.cc b/chromium/ui/keyboard/keyboard_util.cc index 356253966e7..35b70957c3a 100644 --- a/chromium/ui/keyboard/keyboard_util.cc +++ b/chromium/ui/keyboard/keyboard_util.cc @@ -18,6 +18,7 @@ #include "ui/base/ime/input_method_base.h" #include "ui/base/ime/text_input_client.h" #include "ui/base/ime/text_input_flags.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches.h" #include "ui/events/event_sink.h" #include "ui/events/event_utils.h" @@ -245,12 +246,14 @@ bool SendKeyEvent(const std::string type, if (!input_method) return false; + // This can be null if no text input field is not focused. ui::TextInputClient* tic = input_method->GetTextInputClient(); SendProcessKeyEvent(ui::ET_KEY_PRESSED, host); ui::KeyEvent char_event(key_value, code, ui::EF_NONE); - tic->InsertChar(char_event); + if (tic) + tic->InsertChar(char_event); SendProcessKeyEvent(ui::ET_KEY_RELEASED, host); } } else { diff --git a/chromium/ui/keyboard/notification_manager.cc b/chromium/ui/keyboard/notification_manager.cc index 5ef18d8da2a..4838d2b3fc2 100644 --- a/chromium/ui/keyboard/notification_manager.cc +++ b/chromium/ui/keyboard/notification_manager.cc @@ -59,20 +59,20 @@ void NotificationManager::SendNotifications( for (KeyboardControllerObserver& observer : observers) { if (send_availability_notification) - observer.OnKeyboardAvailabilityChanging(is_available); + observer.OnKeyboardAvailabilityChanged(is_available); if (send_visual_bounds_notification) - observer.OnKeyboardVisibleBoundsChanging(bounds); + observer.OnKeyboardVisibleBoundsChanged(bounds); if (send_occluded_bounds_notification) - observer.OnKeyboardWorkspaceOccludedBoundsChanging(occluded_region); + observer.OnKeyboardWorkspaceOccludedBoundsChanged(occluded_region); if (send_displaced_bounds_notification) { - observer.OnKeyboardWorkspaceDisplacingBoundsChanging( + observer.OnKeyboardWorkspaceDisplacingBoundsChanged( workspace_layout_offset_region); } - observer.OnKeyboardAppearanceChanging(state); + observer.OnKeyboardAppearanceChanged(state); } } diff --git a/chromium/ui/keyboard/queued_container_type.cc b/chromium/ui/keyboard/queued_container_type.cc new file mode 100644 index 00000000000..2cf7b882e24 --- /dev/null +++ b/chromium/ui/keyboard/queued_container_type.cc @@ -0,0 +1,24 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" +#include "ui/keyboard/keyboard_controller.h" + +namespace keyboard { + +QueuedContainerType::QueuedContainerType( + KeyboardController* controller, + ContainerType container_type, + base::OnceCallback<void(bool success)> callback) + : controller_(controller), + container_type_(container_type), + callback_(std::move(callback)){}; + +QueuedContainerType::~QueuedContainerType() { + bool change_successful = + controller_->GetActiveContainerType() == container_type_; + std::move(callback_).Run(change_successful); +}; + +} // namespace keyboard diff --git a/chromium/ui/keyboard/queued_container_type.h b/chromium/ui/keyboard/queued_container_type.h new file mode 100644 index 00000000000..ce58d930e28 --- /dev/null +++ b/chromium/ui/keyboard/queued_container_type.h @@ -0,0 +1,37 @@ +// Copyright 2018 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_KEYBOARD_QUEUED_CONTAINER_TYPE_H_ +#define UI_KEYBOARD_QUEUED_CONTAINER_TYPE_H_ + +#include "base/bind.h" +#include "ui/keyboard/container_type.h" + +namespace keyboard { + +class KeyboardController; + +// Tracks a queued ContainerType change request. Couples a container type with a +// callback to invoke once the necessary animation and container changes are +// complete. +// The callback will be invoked once this object goes out of scope. Success +// is defined as the KeyboardController's current container behavior matching +// the same container type as the queued container type. +class QueuedContainerType { + public: + QueuedContainerType(KeyboardController* controller, + ContainerType container_type, + base::OnceCallback<void(bool success)> callback); + ~QueuedContainerType(); + ContainerType container_type() { return container_type_; } + + private: + KeyboardController* controller_; + ContainerType container_type_; + base::OnceCallback<void(bool success)> callback_; +}; + +} // namespace keyboard + +#endif // UI_KEYBOARD_QUEUED_CONTAINER_TYPE_H_ diff --git a/chromium/ui/keyboard/resources/inputview_adapter.js b/chromium/ui/keyboard/resources/inputview_adapter.js index cbafd012b8b..eedf5648d8e 100644 --- a/chromium/ui/keyboard/resources/inputview_adapter.js +++ b/chromium/ui/keyboard/resources/inputview_adapter.js @@ -163,7 +163,8 @@ function registerInputviewApi() { NONE: 0, ALT: 8, CONTROL: 4, - SHIFT: 2 + SHIFT: 2, + CAPSLOCK: 256 }; // Mapping from keyName to keyCode (see ui::KeyEvent). @@ -295,8 +296,10 @@ function registerInputviewApi() { event.modifiers |= Modifier.ALT; if (data.ctrlKey) event.modifiers |= Modifier.CONTROL; - if (data.shiftKey || data.capsLock) + if (data.shiftKey) event.modifiers |= Modifier.SHIFT; + if (data.capsLock) + event.modifiers |= Modifier.CAPSLOCK; chrome.virtualKeyboardPrivate.sendKeyEvent(event, logIfError_); }); diff --git a/chromium/ui/latency/latency_tracker.cc b/chromium/ui/latency/latency_tracker.cc index 6b50846afd6..85e25920566 100644 --- a/chromium/ui/latency/latency_tracker.cc +++ b/chromium/ui/latency/latency_tracker.cc @@ -104,13 +104,6 @@ void LatencyTracker::OnGpuSwapBuffersCompleted(const LatencyInfo& latency) { } } -void LatencyTracker::ReportRapporScrollLatency( - const std::string& name, - const LatencyInfo::LatencyComponent& start_component, - const LatencyInfo::LatencyComponent& end_component) { - // Only supported by RenderWidgetHostLatencyTracker. -} - void LatencyTracker::ReportUkmScrollLatency( const InputMetricEvent& metric_event, const LatencyInfo::LatencyComponent& start_component, @@ -193,10 +186,6 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms( original_component, gpu_swap_begin_component); } - ReportRapporScrollLatency("Event.Latency.ScrollBegin." + input_modality + - ".TimeToScrollUpdateSwapBegin2", - original_component, gpu_swap_begin_component); - } else if (latency.FindLatency( ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, &original_component)) { @@ -215,10 +204,6 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms( original_component, gpu_swap_begin_component); } - ReportRapporScrollLatency("Event.Latency.ScrollUpdate." + input_modality + - ".TimeToScrollUpdateSwapBegin2", - original_component, gpu_swap_begin_component); - } else if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, &original_component)) { if (latency.source_event_type() == SourceEventType::KEY_PRESS) { diff --git a/chromium/ui/latency/latency_tracker.h b/chromium/ui/latency/latency_tracker.h index f0180ebc45d..24397fc4ba6 100644 --- a/chromium/ui/latency/latency_tracker.h +++ b/chromium/ui/latency/latency_tracker.h @@ -29,11 +29,6 @@ class LatencyTracker { protected: ukm::SourceId ukm_source_id() const { return ukm_source_id_; } - virtual void ReportRapporScrollLatency( - const std::string& name, - const LatencyInfo::LatencyComponent& start_component, - const LatencyInfo::LatencyComponent& end_component); - private: enum class InputMetricEvent { SCROLL_BEGIN_TOUCH = 0, diff --git a/chromium/ui/login/account_picker/md_user_pod_template.css b/chromium/ui/login/account_picker/md_user_pod_template.css index 7b5d8f189f9..96794332ac3 100644 --- a/chromium/ui/login/account_picker/md_user_pod_template.css +++ b/chromium/ui/login/account_picker/md_user_pod_template.css @@ -13,3 +13,28 @@ text-transform: none; z-index: 6; } + +/* TODO(crbug.com/814922): Merge most of these with the default values. */ +pin-keyboard { + --pin-keyboard-backspace-opacity: 1; + --pin-keyboard-backspace-color: #FFF; + --pin-keyboard-backspace-paper-ripple-offset: 9px; + --pin-keyboard-digit-button: { + margin: 15px; + opacity: 1; + width: 48px; + }; + + --pin-keyboard-letter-color: rgba(255, 255, 255, .34); + --pin-keyboard-number-color: #FFF; + + --pin-keyboard-paper-ripple: { + border-radius: 50%; + color: rgba(0, 0, 0, .34); + height: 60px; + left: -6px; + position: absolute; + top: -6px; + width: 60px; + }; +} diff --git a/chromium/ui/login/display_manager.js b/chromium/ui/login/display_manager.js index b1bededb799..3102fbfef19 100644 --- a/chromium/ui/login/display_manager.js +++ b/chromium/ui/login/display_manager.js @@ -56,6 +56,7 @@ /** @const */ var ACCELERATOR_APP_LAUNCH_NETWORK_CONFIG = 'app_launch_network_config'; /** @const */ var ACCELERATOR_BOOTSTRAPPING_SLAVE = "bootstrapping_slave"; +/** @const */ var ACCELERATOR_DEMO_MODE = "demo_mode"; /* Signin UI state constants. Used to control header bar UI. */ /** @const */ var SIGNIN_UI_STATE = { @@ -91,7 +92,8 @@ USER_ADDING: 'user-adding', APP_LAUNCH_SPLASH: 'app-launch-splash', ARC_KIOSK_SPLASH: 'arc-kiosk-splash', - DESKTOP_USER_MANAGER: 'login-add-user' + DESKTOP_USER_MANAGER: 'login-add-user', + GAIA_SIGNIN: 'gaia-signin' }; /* Possible lock screen enabled app activity state. */ @@ -186,6 +188,15 @@ cr.define('cr.ui.login', function() { SCREEN_OOBE_RESET, ]; + /** + * Group of screens (screen IDs) where demo mode setup invocation is + * available. + * @type Array<string> + * @const + */ + var DEMO_MODE_SETUP_AVAILABLE_SCREEN_GROUP = [ + SCREEN_GAIA_SIGNIN, + ]; /** * OOBE screens group index. @@ -297,10 +308,17 @@ cr.define('cr.ui.login', function() { loadTimeData.getString('showViewsLock') == 'on' && (this.displayType_ == DISPLAY_TYPE.LOCK || this.displayType_ == DISPLAY_TYPE.USER_ADDING); - var showingViewsLogin = loadTimeData.valueExists('showViewsLogin') && + return showingViewsLock || this.showingViewsLogin; + }, + + /** + * Returns true if we are showing views based login screen. + * @return {boolean} + */ + get showingViewsLogin() { + return loadTimeData.valueExists('showViewsLogin') && loadTimeData.getString('showViewsLogin') == 'on' && - (this.displayType_ == DISPLAY_TYPE.LOGIN); - return showingViewsLock || showingViewsLogin; + (this.displayType_ == DISPLAY_TYPE.GAIA_SIGNIN); }, /** @@ -423,6 +441,11 @@ cr.define('cr.ui.login', function() { chrome.send('networkConfigRequest'); } else if (name == ACCELERATOR_BOOTSTRAPPING_SLAVE) { chrome.send('setOobeBootstrappingSlave'); + } else if (name == ACCELERATOR_DEMO_MODE) { + if (DEMO_MODE_SETUP_AVAILABLE_SCREEN_GROUP.indexOf(currentStepId) != + -1) { + chrome.send('setupDemoMode'); + } } }, @@ -547,10 +570,6 @@ cr.define('cr.ui.login', function() { newStep.setAttribute( 'aria-label', loadTimeData.getString('signinScreenTitle')); - } else if (nextStepId == SCREEN_OOBE_NETWORK) { - newStep.setAttribute( - 'aria-label', - loadTimeData.getString('networkScreenAccessibleTitle')); } // Default control to be focused (if specified). @@ -640,6 +659,10 @@ cr.define('cr.ui.login', function() { return; var screenId = screen.id; + if (screenId == SCREEN_ACCOUNT_PICKER && this.showingViewsLogin) { + chrome.send('updateGaiaDialogVisibility', [false]); + return; + } // Make sure the screen is decorated. this.preloadScreen(screen); @@ -735,6 +758,12 @@ cr.define('cr.ui.login', function() { // This requires |screen| to have 'box-sizing: border-box'. screen.style.width = width + 'px'; screen.style.height = height + 'px'; + + if (this.showingViewsLogin) { + chrome.send('updateGaiaDialogSize', [width, height]); + $('scroll-container').classList.toggle('disable-scroll', true); + $('scroll-container').scrollTop = $('inner-container').offsetTop; + } }, /** diff --git a/chromium/ui/message_center/BUILD.gn b/chromium/ui/message_center/BUILD.gn index b684c1e02de..ed816055fb4 100644 --- a/chromium/ui/message_center/BUILD.gn +++ b/chromium/ui/message_center/BUILD.gn @@ -17,6 +17,7 @@ aggregate_vector_icons("message_center_vector_icons") { "notification_close_button.icon", "notification_expand_less.icon", "notification_expand_more.icon", + "notification_inline_reply.icon", "notification_settings_button.1x.icon", "notification_settings_button.icon", "product.icon", @@ -28,11 +29,14 @@ jumbo_component("message_center") { deps = [ "//base", "//ui/base", - "//ui/message_center/public/cpp", "//ui/strings", "//url", ] + public_deps = [ + "//ui/message_center/public/cpp", + ] + defines = [ "MESSAGE_CENTER_IMPLEMENTATION" ] if (enable_message_center) { @@ -58,8 +62,6 @@ jumbo_component("message_center") { "//build/config/compiler:no_size_t_to_int_warning", ] sources = [ - "change_queue.cc", - "change_queue.h", "cocoa/notification_controller.h", "cocoa/notification_controller.mm", "cocoa/opaque_views.h", @@ -74,21 +76,15 @@ jumbo_component("message_center") { "message_center_impl.cc", "message_center_impl.h", "message_center_observer.h", + "message_center_stats_collector.cc", + "message_center_stats_collector.h", "message_center_style.cc", "message_center_style.h", "message_center_types.h", - "notification.cc", - "notification.h", "notification_blocker.cc", "notification_blocker.h", - "notification_delegate.cc", - "notification_delegate.h", "notification_list.cc", "notification_list.h", - "notification_types.cc", - "notification_types.h", - "notifier_id.cc", - "notifier_id.h", "popup_timer.cc", "popup_timer.h", "popup_timers_controller.cc", @@ -120,7 +116,6 @@ jumbo_component("message_center") { sources += [ "views/bounded_label.cc", "views/bounded_label.h", - "views/constants.h", "views/desktop_popup_alignment_delegate.cc", "views/desktop_popup_alignment_delegate.h", "views/message_popup_collection.cc", @@ -168,21 +163,7 @@ jumbo_component("message_center") { # Notification service disabled. sources = [ "dummy_message_center.cc", - "notification_delegate.cc", - "notification_delegate.h", ] - - # Android implements its own notification UI manager instead of deferring to - # the message center (when notifications are enabled). Include a minimal - # set of files required for notifications on Android. - if (is_android) { - sources += [ - "notification.cc", - "notification.h", - "notifier_id.cc", - "notifier_id.h", - ] - } } } @@ -207,18 +188,18 @@ if (enable_message_center) { public_deps = [ ":message_center", + "//ui/message_center/public/cpp", ] } test("message_center_unittests") { sources = [ - "change_queue_unittest.cc", "cocoa/notification_controller_unittest.mm", "cocoa/popup_collection_unittest.mm", "cocoa/popup_controller_unittest.mm", "message_center_impl_unittest.cc", - "notification_delegate_unittest.cc", "notification_list_unittest.cc", + "public/cpp/notification_delegate_unittest.cc", "test/run_all_unittests.cc", "ui_controller_unittest.cc", ] @@ -228,6 +209,7 @@ if (enable_message_center) { ":test_support", "//base", "//base/test:test_support", + "//mojo/edk/system", "//skia", "//testing/gmock", "//testing/gtest", @@ -252,10 +234,10 @@ if (enable_message_center) { ] if (is_chromeos) { - sources += [ "mojo/struct_traits_unittest.cc" ] + sources += [ "public/mojo/struct_traits_unittest.cc" ] deps += [ "//mojo/edk/system", - "//ui/message_center/mojo:test_interfaces", + "//ui/message_center/public/mojo:test_interfaces", ] } diff --git a/chromium/ui/message_center/change_queue.cc b/chromium/ui/message_center/change_queue.cc deleted file mode 100644 index a61dcd2989e..00000000000 --- a/chromium/ui/message_center/change_queue.cc +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/message_center/change_queue.h" - -#include "ui/message_center/message_center_impl.h" -#include "ui/message_center/notification.h" - -namespace message_center { - -// Change represents an operation made on a notification. Since it contains -// the final state of the notification, except complex cases, we generally -// optimize the list and keep only the last change for a particular notification -// that is in the notification list around. There are two ids; |id_| is the -// post-update notification id that has been assigned by an update, and -// |previous_id| is the previous id of the notification before the Change. -// The two ids are same unless the Change changes the id of the notification. -// See the comments of id() and previous_id() for reference. -class ChangeQueue::Change { - public: - Change(ChangeType type, - const std::string& id, - std::unique_ptr<Notification> notification); - ~Change(); - - // Used to transfer ownership of the contained notification. - std::unique_ptr<Notification> PassNotification(); - - Notification* notification() const { return notification_.get(); } - // Returns the post-update ID. It means: - // - ADD event: ID of the notification to be added. In this case, this must be - // same as |previous_id()|. - // - UPDATE event: ID of the notification after the change. If the change - // doesn't update its ID, this value is same as |previous_id()|. - // - DELETE event: ID of the notification to be deleted. This must be same as - // |previous_id()|. - const std::string& id() const { return id_; } - ChangeType type() const { return type_; } - bool by_user() const { return by_user_; } - void set_by_user(bool by_user) { by_user_ = by_user; } - // Returns the ID which is used in the notification list. In other word, it - // means the ID before the change. - const std::string& previous_id() const { return previous_id_; } - void set_type(const ChangeType new_type) { type_ = new_type; } - void ReplaceNotification(std::unique_ptr<Notification> new_notification); - - private: - ChangeType type_; - std::string id_; - std::string previous_id_; - bool by_user_; - std::unique_ptr<Notification> notification_; - - DISALLOW_COPY_AND_ASSIGN(Change); -}; - -//////////////////////////////////////////////////////////////////////////////// -// ChangeFinder - -struct ChangeFinder { - explicit ChangeFinder(const std::string& id) : id(id) {} - bool operator()(const std::unique_ptr<ChangeQueue::Change>& change) { - return change->id() == id; - } - - std::string id; -}; - -//////////////////////////////////////////////////////////////////////////////// -// ChangeQueue::Change - -ChangeQueue::Change::Change(ChangeType type, - const std::string& id, - std::unique_ptr<Notification> notification) - : type_(type), - previous_id_(id), - by_user_(false), - notification_(std::move(notification)) { - DCHECK(!id.empty()); - DCHECK(type != CHANGE_TYPE_DELETE || !notification_); - - id_ = notification_ ? notification_->id() : previous_id_; -} - -ChangeQueue::Change::~Change() {} - -std::unique_ptr<Notification> ChangeQueue::Change::PassNotification() { - return std::move(notification_); -} - -void ChangeQueue::Change::ReplaceNotification( - std::unique_ptr<Notification> new_notification) { - id_ = new_notification ? new_notification->id() : previous_id_; - notification_.swap(new_notification); -} - -//////////////////////////////////////////////////////////////////////////////// -// ChangeQueue - -ChangeQueue::ChangeQueue() = default; - -ChangeQueue::~ChangeQueue() = default; - -void ChangeQueue::ApplyChanges(MessageCenterImpl* message_center) { - while (!changes_.empty()) { - auto iter = changes_.begin(); - std::unique_ptr<Change> change(std::move(*iter)); - changes_.erase(iter); - ApplyChangeInternal(message_center, std::move(change)); - } -} - -void ChangeQueue::AddNotification(std::unique_ptr<Notification> notification) { - std::string id = notification->id(); - changes_.push_back( - std::make_unique<Change>(CHANGE_TYPE_ADD, id, std::move(notification))); -} - -void ChangeQueue::UpdateNotification( - const std::string& old_id, - std::unique_ptr<Notification> notification) { - changes_.push_back(std::make_unique<Change>(CHANGE_TYPE_UPDATE, old_id, - std::move(notification))); -} - -void ChangeQueue::RemoveNotification(const std::string& id, bool by_user) { - auto change = std::make_unique<Change>(CHANGE_TYPE_DELETE, id, nullptr); - change->set_by_user(by_user); - changes_.push_back(std::move(change)); -} - -Notification* ChangeQueue::GetLatestNotification(const std::string& id) const { - auto iter = - std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(id)); - if (iter == changes_.rend()) - return nullptr; - - if ((*iter)->type() == CHANGE_TYPE_DELETE) - return nullptr; - - return (*iter)->notification(); -} - -void ChangeQueue::ApplyChangeInternal(MessageCenterImpl* message_center, - std::unique_ptr<Change> change) { - switch (change->type()) { - case CHANGE_TYPE_ADD: - message_center->AddNotificationImmediately(change->PassNotification()); - break; - case CHANGE_TYPE_UPDATE: - message_center->UpdateNotificationImmediately(change->previous_id(), - change->PassNotification()); - break; - case CHANGE_TYPE_DELETE: - message_center->RemoveNotificationImmediately(change->previous_id(), - change->by_user()); - break; - default: - NOTREACHED(); - } -} - -} // namespace message_center diff --git a/chromium/ui/message_center/change_queue.h b/chromium/ui/message_center/change_queue.h deleted file mode 100644 index b2c9d287c6b..00000000000 --- a/chromium/ui/message_center/change_queue.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_MESSAGE_CENTER_CHANGE_QUEUE_H_ -#define UI_MESSAGE_CENTER_CHANGE_QUEUE_H_ - -#include <vector> - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "ui/message_center/message_center_export.h" - -namespace message_center { - -class MessageCenterImpl; -class Notification; - -// ChangeQueue keeps track of all the changes. This class can be used for -// queuing changes during the message center can't be updated. -class MESSAGE_CENTER_EXPORT ChangeQueue { - public: - enum ChangeType { - CHANGE_TYPE_ADD = 0, - CHANGE_TYPE_UPDATE, - CHANGE_TYPE_DELETE - }; - - // Change represents an operation made on a notification. Since it contains - // the final state of the notification, we only keep the last change for a - // particular notification that is in the notification list around. There are - // two ids; |id_| is the newest notification id that has been assigned by an - // update, and |notification_list_id_| is the id of the notification it should - // be updating as it exists in the notification list. - class Change; - - ChangeQueue(); - ~ChangeQueue(); - - // Called when the message center has appropriate visibility. Modifies - // |message_center| but does not retain it. This also causes the queue to - // empty itself. - void ApplyChanges(MessageCenterImpl* message_center); - - // Causes a TYPE_ADD change to be added to the queue. - void AddNotification(std::unique_ptr<Notification> notification); - - // Causes a TYPE_UPDATE change to be added to the queue. - void UpdateNotification(const std::string& old_id, - std::unique_ptr<Notification> notification); - - // Causes a TYPE_DELETE change to be added to the queue. - void RemoveNotification(const std::string& id, bool by_user); - - // Returns the pointer to the Notification in the latest Change which has the - // given ID. If the Change is UPDATE, the ID after the change is searched. - // If the Change id REMOVE, this returns nullptr. - // ChangeQueue keeps retaining ownership of the Notification. The returned - // notification can be modified or be copied by caller. - Notification* GetLatestNotification(const std::string& id) const; - - private: - void ApplyChangeInternal(MessageCenterImpl* message_center, - std::unique_ptr<Change> change); - - std::vector<std::unique_ptr<Change>> changes_; - - DISALLOW_COPY_AND_ASSIGN(ChangeQueue); -}; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_CHANGE_QUEUE_H_ diff --git a/chromium/ui/message_center/change_queue_unittest.cc b/chromium/ui/message_center/change_queue_unittest.cc deleted file mode 100644 index bf475f2d052..00000000000 --- a/chromium/ui/message_center/change_queue_unittest.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/message_center/change_queue.h" - -#include <utility> - -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/message_center/message_center_impl.h" - -using base::UTF8ToUTF16; - -namespace message_center { - -namespace { - -Notification* CreateSimpleNotification(const std::string& id) { - RichNotificationData optional_fields; - optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo"))); - optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo"))); - return new Notification( - NOTIFICATION_TYPE_SIMPLE, id, UTF8ToUTF16("title"), UTF8ToUTF16(id), - gfx::Image() /* icon */, base::string16() /* display_source */, GURL(), - NotifierId(NotifierId::APPLICATION, "change_queue_test"), optional_fields, - NULL); -} - -} // namespace - -class ChangeQueueTest : public testing::Test { - public: - ChangeQueueTest() = default; - ~ChangeQueueTest() override = default; - - MessageCenterImpl* message_center() { return &message_center_; } - - private: - MessageCenterImpl message_center_; -}; - -TEST_F(ChangeQueueTest, Queueing) { - ChangeQueue queue; - std::string id("id1"); - std::string id2("id2"); - NotifierId notifier_id1(NotifierId::APPLICATION, "app1"); - - // First, add and update a notification to ensure updates happen - // normally. - std::unique_ptr<Notification> notification(CreateSimpleNotification(id)); - message_center()->AddNotification(std::move(notification)); - notification.reset(CreateSimpleNotification(id2)); - message_center()->UpdateNotification(id, std::move(notification)); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(id2)); - EXPECT_FALSE(message_center()->FindVisibleNotificationById(id)); - - // Then update a notification; nothing should have happened. - notification.reset(CreateSimpleNotification(id)); - queue.UpdateNotification(id2, std::move(notification)); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(id2)); - EXPECT_FALSE(message_center()->FindVisibleNotificationById(id)); - - // Apply the changes from the queue. - queue.ApplyChanges(message_center()); - - // Close the message center; then the update should have propagated. - EXPECT_FALSE(message_center()->FindVisibleNotificationById(id2)); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(id)); -} - -TEST_F(ChangeQueueTest, SimpleQueueing) { - ChangeQueue queue; - std::string ids[6] = {"0", "1", "2", "3", "4", "5"}; - NotifierId notifier_id1(NotifierId::APPLICATION, "app1"); - - std::unique_ptr<Notification> notification; - // Prepare initial notifications on NotificationList. - // NL: ["0", "1", "2", "4"] - int i = 0; - for (; i < 3; i++) { - notification.reset(CreateSimpleNotification(ids[i])); - message_center()->AddNotification(std::move(notification)); - } - for (i = 0; i < 3; i++) { - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[i])); - } - for (; i < 6; i++) { - EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[i])); - } - - // This should update notification "1" to have id "4". - notification.reset(CreateSimpleNotification(ids[4])); - queue.AddNotification(std::move(notification)); - - // Change the ID: "2" -> "5", "5" -> "3". - notification.reset(CreateSimpleNotification(ids[5])); - queue.UpdateNotification(ids[2], std::move(notification)); - notification.reset(CreateSimpleNotification(ids[3])); - queue.UpdateNotification(ids[5], std::move(notification)); - - // This should update notification "4" to "5". - notification.reset(CreateSimpleNotification(ids[5])); - queue.UpdateNotification(ids[4], std::move(notification)); - - // This should create a new "4", that doesn't overwrite the update from 4 - // before. - notification.reset(CreateSimpleNotification(ids[4])); - queue.AddNotification(std::move(notification)); - - // The NL should still be the same: ["0", "1", "2", "4"] - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[0])); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[1])); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[2])); - EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[3])); - EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[4])); - EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[5])); - EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 3u); - - // Apply the changes from the queue. - queue.ApplyChanges(message_center()); - - // Changes should be applied. - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[0])); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[1])); - EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[2])); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[3])); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[4])); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[5])); - EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 5u); -} - -} // namespace message_center diff --git a/chromium/ui/message_center/cocoa/notification_controller.mm b/chromium/ui/message_center/cocoa/notification_controller.mm index 61e9c0e63ee..38cb370b42b 100644 --- a/chromium/ui/message_center/cocoa/notification_controller.mm +++ b/chromium/ui/message_center/cocoa/notification_controller.mm @@ -22,8 +22,8 @@ #include "ui/gfx/text_utils.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_style.h" -#include "ui/message_center/notification.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" #include "ui/resources/grit/ui_resources.h" #include "ui/strings/grit/ui_strings.h" #include "url/gurl.h" diff --git a/chromium/ui/message_center/cocoa/notification_controller_unittest.mm b/chromium/ui/message_center/cocoa/notification_controller_unittest.mm index 99bb8049325..72c3441def9 100644 --- a/chromium/ui/message_center/cocoa/notification_controller_unittest.mm +++ b/chromium/ui/message_center/cocoa/notification_controller_unittest.mm @@ -15,9 +15,9 @@ #import "ui/base/cocoa/hover_image_button.h" #import "ui/base/test/cocoa_helper.h" #include "ui/message_center/fake_message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_types.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" using base::ASCIIToUTF16; using base::UTF8ToUTF16; @@ -148,7 +148,7 @@ TEST_F(NotificationControllerTest, BasicLayout) { TEST_F(NotificationControllerTest, NotificationSetttingsButtonLayout) { message_center::RichNotificationData data; - data.settings_button_handler = SettingsButtonHandler::TRAY; + data.settings_button_handler = SettingsButtonHandler::INLINE; std::unique_ptr<message_center::Notification> notification( new message_center::Notification( message_center::NOTIFICATION_TYPE_SIMPLE, "", @@ -302,16 +302,16 @@ TEST_F(NotificationControllerTest, Image) { TEST_F(NotificationControllerTest, List) { message_center::RichNotificationData optional; - message_center::NotificationItem item1( - UTF8ToUTF16("First title"), UTF8ToUTF16("first message")); + message_center::NotificationItem item1{UTF8ToUTF16("First title"), + UTF8ToUTF16("first message")}; optional.items.push_back(item1); - message_center::NotificationItem item2( + message_center::NotificationItem item2{ UTF8ToUTF16("Second title"), - UTF8ToUTF16("second slightly longer message")); + UTF8ToUTF16("second slightly longer message")}; optional.items.push_back(item2); - message_center::NotificationItem item3( + message_center::NotificationItem item3{ UTF8ToUTF16(""), // Test for empty string. - UTF8ToUTF16(" ")); // Test for string containing only spaces. + UTF8ToUTF16(" ")}; // Test for string containing only spaces. optional.items.push_back(item3); optional.context_message = UTF8ToUTF16("Context Message"); diff --git a/chromium/ui/message_center/cocoa/popup_collection_unittest.mm b/chromium/ui/message_center/cocoa/popup_collection_unittest.mm index 0bdc39689fb..e8a5d3fe9b3 100644 --- a/chromium/ui/message_center/cocoa/popup_collection_unittest.mm +++ b/chromium/ui/message_center/cocoa/popup_collection_unittest.mm @@ -16,8 +16,8 @@ #import "ui/message_center/cocoa/notification_controller.h" #import "ui/message_center/cocoa/popup_controller.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" using base::ASCIIToUTF16; diff --git a/chromium/ui/message_center/cocoa/popup_controller_unittest.mm b/chromium/ui/message_center/cocoa/popup_controller_unittest.mm index cbe289e56e1..191b2d68463 100644 --- a/chromium/ui/message_center/cocoa/popup_controller_unittest.mm +++ b/chromium/ui/message_center/cocoa/popup_controller_unittest.mm @@ -10,7 +10,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #import "ui/base/test/cocoa_helper.h" -#include "ui/message_center/notification.h" +#include "ui/message_center/public/cpp/notification.h" using base::ASCIIToUTF16; diff --git a/chromium/ui/message_center/fake_message_center.cc b/chromium/ui/message_center/fake_message_center.cc index 6bb96cc932a..7bc04916264 100644 --- a/chromium/ui/message_center/fake_message_center.cc +++ b/chromium/ui/message_center/fake_message_center.cc @@ -39,7 +39,7 @@ bool FakeMessageCenter::IsQuietMode() const { return false; } -message_center::Notification* FakeMessageCenter::FindVisibleNotificationById( +Notification* FakeMessageCenter::FindVisibleNotificationById( const std::string& id) { for (auto* notification : GetVisibleNotifications()) { if (id == notification->id()) diff --git a/chromium/ui/message_center/fake_message_center.h b/chromium/ui/message_center/fake_message_center.h index b10be1b57ef..0c4ad7243eb 100644 --- a/chromium/ui/message_center/fake_message_center.h +++ b/chromium/ui/message_center/fake_message_center.h @@ -27,8 +27,7 @@ class FakeMessageCenter : public MessageCenter { size_t NotificationCount() const override; bool HasPopupNotifications() const override; bool IsQuietMode() const override; - message_center::Notification* FindVisibleNotificationById( - const std::string& id) override; + Notification* FindVisibleNotificationById(const std::string& id) override; const NotificationList::Notifications& GetVisibleNotifications() override; NotificationList::PopupNotifications GetPopupNotifications() override; void AddNotification(std::unique_ptr<Notification> notification) override; diff --git a/chromium/ui/message_center/message_center.h b/chromium/ui/message_center/message_center.h index c0666c34dc8..493c1454813 100644 --- a/chromium/ui/message_center/message_center.h +++ b/chromium/ui/message_center/message_center.h @@ -24,7 +24,7 @@ class DownloadNotificationTestBase; // is shown, closed, or clicked on. // // MessageCenter is agnostic of profiles; it uses the string returned by -// message_center::Notification::id() to uniquely identify a notification. It is +// Notification::id() to uniquely identify a notification. It is // the caller's responsibility to formulate the id so that 2 different // notification should have different ids. For example, if the caller supports // multiple profiles, then caller should encode both profile characteristics and @@ -73,8 +73,7 @@ class MESSAGE_CENTER_EXPORT MessageCenter { // Find the notification with the corresponding id. Returns null if not // found. The returned instance is owned by the message center. - virtual message_center::Notification* FindVisibleNotificationById( - const std::string& id) = 0; + virtual Notification* FindVisibleNotificationById(const std::string& id) = 0; // Gets all notifications to be shown to the user in the message center. Note // that queued changes due to the message center being open are not reflected diff --git a/chromium/ui/message_center/message_center_impl.cc b/chromium/ui/message_center/message_center_impl.cc index 98421d1b534..53485f966a1 100644 --- a/chromium/ui/message_center/message_center_impl.cc +++ b/chromium/ui/message_center/message_center_impl.cc @@ -18,58 +18,23 @@ #include "base/strings/string_util.h" #include "build/build_config.h" #include "ui/message_center/message_center_types.h" -#include "ui/message_center/notification.h" #include "ui/message_center/notification_blocker.h" #include "ui/message_center/notification_list.h" -#include "ui/message_center/notification_types.h" #include "ui/message_center/popup_timers_controller.h" #include "ui/message_center/public/cpp/message_center_constants.h" -#include "ui/message_center/public/cpp/message_center_switches.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" namespace message_center { -namespace internal { - -//////////////////////////////////////////////////////////////////////////////// -// ScopedNotificationsIterationLock - -class ScopedNotificationsIterationLock { - public: - // Lock may be used recursively. - explicit ScopedNotificationsIterationLock(MessageCenterImpl* message_center) - : message_center_(message_center), - original_value_(message_center->iterating_) { - message_center_->iterating_ = true; - } - - ~ScopedNotificationsIterationLock() { - DCHECK(message_center_->iterating_); - - // |original_value_| must be false. But handle the other case just in case. - message_center_->iterating_ = original_value_; - if (!original_value_) { - message_center_->notification_change_queue_->ApplyChanges( - message_center_); - } - } - - private: - MessageCenterImpl* message_center_; - const bool original_value_; - - DISALLOW_COPY_AND_ASSIGN(ScopedNotificationsIterationLock); -}; - -} // namespace internal - //////////////////////////////////////////////////////////////////////////////// // MessageCenterImpl MessageCenterImpl::MessageCenterImpl() : MessageCenter(), - popup_timers_controller_(new PopupTimersController(this)) { + popup_timers_controller_(std::make_unique<PopupTimersController>(this)), + stats_collector_(this) { notification_list_.reset(new NotificationList(this)); - notification_change_queue_.reset(new ChangeQueue()); } MessageCenterImpl::~MessageCenterImpl() { @@ -107,29 +72,25 @@ void MessageCenterImpl::RemoveNotificationBlocker( void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); - std::list<const Notification*> blocked; + std::list<std::string> blocked; NotificationList::PopupNotifications popups = notification_list_->GetPopupNotifications(blockers_, &blocked); // Close already displayed pop-ups that are blocked now. - for (const auto* notification : blocked) { + for (const std::string& notification_id : blocked) { // Do not call MessageCenterImpl::MarkSinglePopupAsShown() directly here // just for performance reason. MessageCenterImpl::MarkSinglePopupAsShown() // calls NotificationList::MarkSinglePopupAsShown(), but the whole cache // will be recreated below. - if (notification->IsRead()) - notification_list_->MarkSinglePopupAsShown(notification->id(), true); + if (FindVisibleNotificationById(notification_id)->IsRead()) + notification_list_->MarkSinglePopupAsShown(notification_id, true); } visible_notifications_ = notification_list_->GetVisibleNotifications(blockers_); - { - internal::ScopedNotificationsIterationLock lock(this); - for (const auto* notification : blocked) { - for (auto& observer : observer_list_) - observer.OnNotificationUpdated(notification->id()); - } + for (const std::string& notification_id : blocked) { + for (auto& observer : observer_list_) + observer.OnNotificationUpdated(notification_id); } for (auto& observer : observer_list_) observer.OnBlockingStateChanged(blocker); @@ -137,19 +98,15 @@ void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) { void MessageCenterImpl::SetVisibility(Visibility visibility) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); visible_ = (visibility == VISIBILITY_MESSAGE_CENTER); if (visible_) { std::set<std::string> updated_ids; notification_list_->SetNotificationsShown(blockers_, &updated_ids); - { - internal::ScopedNotificationsIterationLock lock(this); - for (const auto& id : updated_ids) { - for (auto& observer : observer_list_) - observer.OnNotificationUpdated(id); - } + for (const auto& id : updated_ids) { + for (auto& observer : observer_list_) + observer.OnNotificationUpdated(id); } } @@ -178,7 +135,7 @@ bool MessageCenterImpl::IsQuietMode() const { return notification_list_->quiet_mode(); } -message_center::Notification* MessageCenterImpl::FindVisibleNotificationById( +Notification* MessageCenterImpl::FindVisibleNotificationById( const std::string& id) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); return notification_list_->GetNotificationById(id); @@ -193,7 +150,7 @@ MessageCenterImpl::GetVisibleNotifications() { NotificationList::PopupNotifications MessageCenterImpl::GetPopupNotifications() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - return notification_list_->GetPopupNotifications(blockers_, NULL); + return notification_list_->GetPopupNotifications(blockers_, nullptr); } //------------------------------------------------------------------------------ @@ -206,20 +163,6 @@ void MessageCenterImpl::AddNotification( for (size_t i = 0; i < blockers_.size(); ++i) blockers_[i]->CheckState(); - if (iterating_) { - notification_change_queue_->AddNotification(std::move(notification)); - return; - } - - AddNotificationImmediately(std::move(notification)); -} - -void MessageCenterImpl::AddNotificationImmediately( - std::unique_ptr<Notification> notification) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); - const std::string id = notification->id(); - // Sometimes the notification can be added with the same id and the // |notification_list| will replace the notification instead of adding new. // This is essentially an update rather than addition. @@ -228,13 +171,10 @@ void MessageCenterImpl::AddNotificationImmediately( visible_notifications_ = notification_list_->GetVisibleNotifications(blockers_); - if (already_exists) { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) + for (auto& observer : observer_list_) { + if (already_exists) observer.OnNotificationUpdated(id); - } else { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) + else observer.OnNotificationAdded(id); } } @@ -246,35 +186,18 @@ void MessageCenterImpl::UpdateNotification( for (size_t i = 0; i < blockers_.size(); ++i) blockers_[i]->CheckState(); - if (iterating_) { - notification_change_queue_->UpdateNotification(old_id, - std::move(new_notification)); - return; - } - - UpdateNotificationImmediately(old_id, std::move(new_notification)); -} - -void MessageCenterImpl::UpdateNotificationImmediately( - const std::string& old_id, - std::unique_ptr<Notification> new_notification) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); std::string new_id = new_notification->id(); notification_list_->UpdateNotificationMessage(old_id, std::move(new_notification)); visible_notifications_ = notification_list_->GetVisibleNotifications(blockers_); - if (old_id == new_id) { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) + for (auto& observer : observer_list_) { + if (old_id == new_id) { observer.OnNotificationUpdated(new_id); - } else { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) + } else { observer.OnNotificationRemoved(old_id, false); - for (auto& observer : observer_list_) observer.OnNotificationAdded(new_id); + } } } @@ -282,21 +205,8 @@ void MessageCenterImpl::RemoveNotification(const std::string& id, bool by_user) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (iterating_) { - notification_change_queue_->RemoveNotification(id, by_user); - return; - } - - RemoveNotificationImmediately(id, by_user); -} - -void MessageCenterImpl::RemoveNotificationImmediately( - const std::string& id, bool by_user) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); - Notification* notification = FindVisibleNotificationById(id); - if (notification == NULL) + if (!notification) return; if (by_user && notification->pinned()) { @@ -319,27 +229,8 @@ void MessageCenterImpl::RemoveNotificationImmediately( notification_list_->RemoveNotification(copied_id); visible_notifications_ = notification_list_->GetVisibleNotifications(blockers_); - { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) - observer.OnNotificationRemoved(copied_id, by_user); - } -} - -Notification* MessageCenterImpl::GetLatestNotificationIncludingQueued( - const std::string& id) const { - Notification* queued_notification = - notification_change_queue_->GetLatestNotification(id); - if (queued_notification) { - DCHECK(iterating_); - return queued_notification; - } - - Notification* notification = notification_list_->GetNotificationById(id); - if (notification) - return notification; - - return nullptr; + for (auto& observer : observer_list_) + observer.OnNotificationRemoved(copied_id, by_user); } void MessageCenterImpl::RemoveNotificationsForNotifierId( @@ -357,7 +248,6 @@ void MessageCenterImpl::RemoveNotificationsForNotifierId( void MessageCenterImpl::RemoveAllNotifications(bool by_user, RemoveType type) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); bool remove_pinned = (type == RemoveType::ALL); const NotificationBlockers& blockers = @@ -382,12 +272,9 @@ void MessageCenterImpl::RemoveAllNotifications(bool by_user, RemoveType type) { visible_notifications_ = notification_list_->GetVisibleNotifications(blockers_); } - { - internal::ScopedNotificationsIterationLock lock(this); - for (const auto& id : ids) { - for (auto& observer : observer_list_) - observer.OnNotificationRemoved(id, by_user); - } + for (const auto& id : ids) { + for (auto& observer : observer_list_) + observer.OnNotificationRemoved(id, by_user); } } @@ -395,21 +282,7 @@ void MessageCenterImpl::SetNotificationIcon(const std::string& notification_id, const gfx::Image& image) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (iterating_) { - Notification* notification = - GetLatestNotificationIncludingQueued(notification_id); - if (notification) { - std::unique_ptr<Notification> copied_notification = - std::make_unique<Notification>(*notification); - copied_notification->set_icon(image); - notification_change_queue_->UpdateNotification( - notification_id, std::move(copied_notification)); - } - return; - } - if (notification_list_->SetNotificationIcon(notification_id, image)) { - internal::ScopedNotificationsIterationLock lock(this); for (auto& observer : observer_list_) observer.OnNotificationUpdated(notification_id); } @@ -417,22 +290,8 @@ void MessageCenterImpl::SetNotificationIcon(const std::string& notification_id, void MessageCenterImpl::SetNotificationImage(const std::string& notification_id, const gfx::Image& image) { - if (iterating_) { - Notification* notification = - GetLatestNotificationIncludingQueued(notification_id); - if (notification) { - std::unique_ptr<Notification> copied_notification = - std::make_unique<Notification>(*notification); - copied_notification->set_image(image); - notification_change_queue_->UpdateNotification( - notification_id, std::move(copied_notification)); - } - return; - } - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (notification_list_->SetNotificationImage(notification_id, image)) { - internal::ScopedNotificationsIterationLock lock(this); for (auto& observer : observer_list_) observer.OnNotificationUpdated(notification_id); } @@ -441,23 +300,9 @@ void MessageCenterImpl::SetNotificationImage(const std::string& notification_id, void MessageCenterImpl::SetNotificationButtonIcon( const std::string& notification_id, int button_index, const gfx::Image& image) { - if (iterating_) { - Notification* notification = - GetLatestNotificationIncludingQueued(notification_id); - if (notification) { - std::unique_ptr<Notification> copied_notification = - std::make_unique<Notification>(*notification); - copied_notification->SetButtonIcon(button_index, image); - notification_change_queue_->UpdateNotification( - notification_id, std::move(copied_notification)); - } - return; - } - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (notification_list_->SetNotificationButtonIcon(notification_id, button_index, image)) { - internal::ScopedNotificationsIterationLock lock(this); for (auto& observer : observer_list_) observer.OnNotificationUpdated(notification_id); } @@ -465,7 +310,6 @@ void MessageCenterImpl::SetNotificationButtonIcon( void MessageCenterImpl::ClickOnNotification(const std::string& id) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); if (FindVisibleNotificationById(id) == NULL) return; #if defined(OS_CHROMEOS) @@ -474,19 +318,15 @@ void MessageCenterImpl::ClickOnNotification(const std::string& id) { #endif scoped_refptr<NotificationDelegate> delegate = notification_list_->GetNotificationDelegate(id); + for (auto& observer : observer_list_) + observer.OnNotificationClicked(id); if (delegate.get()) delegate->Click(); - { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) - observer.OnNotificationClicked(id); - } } void MessageCenterImpl::ClickOnNotificationButton(const std::string& id, int button_index) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); if (!FindVisibleNotificationById(id)) return; #if defined(OS_CHROMEOS) @@ -495,13 +335,10 @@ void MessageCenterImpl::ClickOnNotificationButton(const std::string& id, #endif scoped_refptr<NotificationDelegate> delegate = notification_list_->GetNotificationDelegate(id); + for (auto& observer : observer_list_) + observer.OnNotificationButtonClicked(id, button_index); if (delegate.get()) delegate->ButtonClick(button_index); - { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) - observer.OnNotificationButtonClicked(id, button_index); - } } void MessageCenterImpl::ClickOnNotificationButtonWithReply( @@ -517,18 +354,14 @@ void MessageCenterImpl::ClickOnNotificationButtonWithReply( #endif scoped_refptr<NotificationDelegate> delegate = notification_list_->GetNotificationDelegate(id); + for (auto& observer : observer_list_) + observer.OnNotificationButtonClickedWithReply(id, button_index, reply); if (delegate.get()) delegate->ButtonClickWithReply(button_index, reply); - { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) - observer.OnNotificationButtonClickedWithReply(id, button_index, reply); - } } void MessageCenterImpl::ClickOnSettingsButton(const std::string& id) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); Notification* notification = notification_list_->GetNotificationById(id); bool handled_by_delegate = @@ -538,16 +371,12 @@ void MessageCenterImpl::ClickOnSettingsButton(const std::string& id) { if (handled_by_delegate) notification->delegate()->SettingsClick(); - { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) - observer.OnNotificationSettingsClicked(handled_by_delegate); - } + for (auto& observer : observer_list_) + observer.OnNotificationSettingsClicked(handled_by_delegate); } void MessageCenterImpl::DisableNotification(const std::string& id) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!iterating_); Notification* notification = notification_list_->GetNotificationById(id); if (notification && notification->delegate()) { @@ -562,20 +391,12 @@ void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id, if (FindVisibleNotificationById(id) == NULL) return; -// This method doesn't check the |iterating_| flag, since this is called -// during iteration. -// TODO(yoshiki): Investigate and not to call this method during iteration if -// necessary. - #if !defined(OS_CHROMEOS) RemoveNotification(id, false); #else notification_list_->MarkSinglePopupAsShown(id, mark_notification_as_read); - { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) - observer.OnNotificationUpdated(id); - } + for (auto& observer : observer_list_) + observer.OnNotificationUpdated(id); #endif // defined(OS_CHROMEOS) } @@ -594,11 +415,8 @@ void MessageCenterImpl::DisplayedNotification( notification_list_->MarkSinglePopupAsDisplayed(id); scoped_refptr<NotificationDelegate> delegate = notification_list_->GetNotificationDelegate(id); - { - internal::ScopedNotificationsIterationLock lock(this); - for (auto& observer : observer_list_) - observer.OnNotificationDisplayed(id, source); - } + for (auto& observer : observer_list_) + observer.OnNotificationDisplayed(id, source); } void MessageCenterImpl::SetQuietMode(bool in_quiet_mode) { diff --git a/chromium/ui/message_center/message_center_impl.h b/chromium/ui/message_center/message_center_impl.h index 0c9e263c060..36270ff1a66 100644 --- a/chromium/ui/message_center/message_center_impl.h +++ b/chromium/ui/message_center/message_center_impl.h @@ -16,20 +16,16 @@ #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "ui/message_center/change_queue.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_observer.h" +#include "ui/message_center/message_center_stats_collector.h" #include "ui/message_center/message_center_types.h" #include "ui/message_center/notification_blocker.h" -#include "ui/message_center/notifier_id.h" #include "ui/message_center/popup_timers_controller.h" +#include "ui/message_center/public/cpp/notifier_id.h" namespace message_center { -namespace internal { -class ScopedNotificationsIterationLock; -}; - // The default implementation of MessageCenter. class MESSAGE_CENTER_EXPORT MessageCenterImpl : public MessageCenter, @@ -48,8 +44,7 @@ class MESSAGE_CENTER_EXPORT MessageCenterImpl size_t NotificationCount() const override; bool HasPopupNotifications() const override; bool IsQuietMode() const override; - message_center::Notification* FindVisibleNotificationById( - const std::string& id) override; + Notification* FindVisibleNotificationById(const std::string& id) override; const NotificationList::Notifications& GetVisibleNotifications() override; NotificationList::PopupNotifications GetPopupNotifications() override; void AddNotification(std::unique_ptr<Notification> notification) override; @@ -88,23 +83,10 @@ class MESSAGE_CENTER_EXPORT MessageCenterImpl // NotificationBlocker::Observer overrides: void OnBlockingStateChanged(NotificationBlocker* blocker) override; - // Unexposed methods: - void AddNotificationImmediately(std::unique_ptr<Notification> notification); - void UpdateNotificationImmediately( - const std::string& old_id, - std::unique_ptr<Notification> new_notification); - void RemoveNotificationImmediately(const std::string& id, bool by_user); - protected: void DisableTimersForTest() override; private: - friend internal::ScopedNotificationsIterationLock; - class ScopedNotificationsLock; - - Notification* GetLatestNotificationIncludingQueued( - const std::string& id) const; - THREAD_CHECKER(thread_checker_); std::unique_ptr<NotificationList> notification_list_; @@ -113,15 +95,13 @@ class MESSAGE_CENTER_EXPORT MessageCenterImpl std::unique_ptr<PopupTimersController> popup_timers_controller_; std::unique_ptr<base::OneShotTimer> quiet_mode_timer_; std::vector<NotificationBlocker*> blockers_; - std::unique_ptr<ChangeQueue> notification_change_queue_; bool visible_ = false; - // modified by ScopedNotificationsIterationLock. - bool iterating_ = false; - base::string16 system_notification_app_name_; + MessageCenterStatsCollector stats_collector_; + DISALLOW_COPY_AND_ASSIGN(MessageCenterImpl); }; diff --git a/chromium/ui/message_center/message_center_impl_unittest.cc b/chromium/ui/message_center/message_center_impl_unittest.cc index 9921fa5f0f7..3ca85df31f2 100644 --- a/chromium/ui/message_center/message_center_impl_unittest.cc +++ b/chromium/ui/message_center/message_center_impl_unittest.cc @@ -23,9 +23,9 @@ #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_types.h" #include "ui/message_center/notification_blocker.h" -#include "ui/message_center/notification_types.h" -#include "ui/message_center/notifier_id.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification_types.h" +#include "ui/message_center/public/cpp/notifier_id.h" using base::UTF8ToUTF16; @@ -73,8 +73,7 @@ class RemoveObserver : public MessageCenterObserver { } // anonymous namespace -class MessageCenterImplTest : public testing::Test, - public MessageCenterObserver { +class MessageCenterImplTest : public testing::Test { public: MessageCenterImplTest() {} @@ -118,14 +117,13 @@ class MessageCenterImplTest : public testing::Test, } Notification* CreateNotification(const std::string& id, - message_center::NotificationType type) { + NotificationType type) { return CreateNotificationWithNotifierId(id, "app1", type); } - Notification* CreateNotificationWithNotifierId( - const std::string& id, - const std::string& notifier_id, - message_center::NotificationType type) { + Notification* CreateNotificationWithNotifierId(const std::string& id, + const std::string& notifier_id, + NotificationType type) { RichNotificationData optional_fields; optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo"))); optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo"))); @@ -163,7 +161,7 @@ class ToggledNotificationBlocker : public NotificationBlocker { // NotificationBlocker overrides: bool ShouldShowNotificationAsPopup( - const message_center::Notification& notification) const override { + const Notification& notification) const override { return notifications_enabled_; } @@ -403,8 +401,7 @@ TEST_F(MessageCenterImplTest, NotificationBlocker) { EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size()); // "id1" is displayed as a pop-up so that it will be closed when blocked. - message_center()->DisplayedNotification("id1", - message_center::DISPLAY_SOURCE_POPUP); + message_center()->DisplayedNotification("id1", DISPLAY_SOURCE_POPUP); // Block all notifications. All popups are gone and message center should be // hidden. @@ -452,8 +449,7 @@ TEST_F(MessageCenterImplTest, NotificationsDuringBlocked) { EXPECT_EQ(1u, message_center()->GetVisibleNotifications().size()); // "id1" is displayed as a pop-up so that it will be closed when blocked. - message_center()->DisplayedNotification("id1", - message_center::DISPLAY_SOURCE_POPUP); + message_center()->DisplayedNotification("id1", DISPLAY_SOURCE_POPUP); // Create a notification during blocked. Still no popups. blocker.SetNotificationsEnabled(false); @@ -493,8 +489,7 @@ TEST_F(MessageCenterImplTest, NotificationBlockerAllowsPopups) { notifier_id2, RichNotificationData(), NULL))); // "id1" is displayed as a pop-up so that it will be closed when blocked. - message_center()->DisplayedNotification("id1", - message_center::DISPLAY_SOURCE_POPUP); + message_center()->DisplayedNotification("id1", DISPLAY_SOURCE_POPUP); // "id1" is closed but "id2" is still visible as a popup. blocker.SetNotificationsEnabled(false); @@ -787,36 +782,5 @@ TEST_F(MessageCenterImplTest, RemoveWhileMessageCenterVisible) { EXPECT_FALSE(message_center()->FindVisibleNotificationById(id)); } -TEST_F(MessageCenterImplTest, RemoveWhileIteratingObserver) { - std::string id("id1"); - CheckObserver check1(message_center(), id); - CheckObserver check2(message_center(), id); - RemoveObserver remove(message_center(), id); - - // Prepare a notification - std::unique_ptr<Notification> notification(CreateSimpleNotification(id)); - message_center()->AddNotification(std::move(notification)); - EXPECT_TRUE(message_center()->FindVisibleNotificationById(id)); - - // Install the test handlers - message_center()->AddObserver(&check1); - message_center()->AddObserver(&remove); - message_center()->AddObserver(&check2); - - // Update the notification. The notification will be removed in the observer, - // but the actual removal will be done at the end of the iteration. - // Notification keeps alive during iteration. This is checked by - // CheckObserver. - notification.reset(CreateSimpleNotification(id)); - message_center()->UpdateNotification(id, std::move(notification)); - - // Notification is removed correctly. - EXPECT_FALSE(message_center()->FindVisibleNotificationById(id)); - - message_center()->RemoveObserver(&check1); - message_center()->RemoveObserver(&remove); - message_center()->RemoveObserver(&check2); -} - } // namespace internal } // namespace message_center diff --git a/chromium/ui/message_center/message_center_observer.h b/chromium/ui/message_center/message_center_observer.h index feb358bd0a9..9ef0ec65c84 100644 --- a/chromium/ui/message_center/message_center_observer.h +++ b/chromium/ui/message_center/message_center_observer.h @@ -14,6 +14,8 @@ namespace message_center { class NotificationBlocker; // An observer class for the change of notifications in the MessageCenter. +// WARNING: It is not safe to modify the message center from within these +// callbacks. class MESSAGE_CENTER_EXPORT MessageCenterObserver { public: virtual ~MessageCenterObserver() {} diff --git a/chromium/ui/message_center/message_center_stats_collector.cc b/chromium/ui/message_center/message_center_stats_collector.cc new file mode 100644 index 00000000000..210e0bf85f5 --- /dev/null +++ b/chromium/ui/message_center/message_center_stats_collector.cc @@ -0,0 +1,153 @@ +// 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/message_center/message_center_stats_collector.h" + +#include <stddef.h> + +#include <string> + +#include "base/metrics/histogram_macros.h" +#include "base/metrics/user_metrics.h" +#include "ui/message_center/message_center.h" + +namespace message_center { + +MessageCenterStatsCollector::NotificationStats::NotificationStats() {} + +MessageCenterStatsCollector::NotificationStats::NotificationStats( + const std::string& id) + : id_(id) { + for (size_t i = 0; i < NOTIFICATION_ACTION_COUNT; i++) { + actions_[i] = false; + } +} + +MessageCenterStatsCollector::NotificationStats::~NotificationStats() {} + +void MessageCenterStatsCollector::NotificationStats::CollectAction( + NotificationActionType type) { + DCHECK(!id_.empty()); + + UMA_HISTOGRAM_ENUMERATION("Notifications.Actions", type, + NOTIFICATION_ACTION_COUNT); + actions_[type] = true; +} + +void MessageCenterStatsCollector::NotificationStats::RecordAggregateStats() { + DCHECK(!id_.empty()); + + for (size_t i = 0; i < NOTIFICATION_ACTION_COUNT; i++) { + if (!actions_[i]) + continue; + UMA_HISTOGRAM_ENUMERATION("Notifications.PerNotificationActions", + static_cast<NotificationActionType>(i), + NOTIFICATION_ACTION_COUNT); + } +} + +MessageCenterStatsCollector::MessageCenterStatsCollector( + MessageCenter* message_center) + : message_center_(message_center) { + message_center_->AddObserver(this); +} + +MessageCenterStatsCollector::~MessageCenterStatsCollector() { + message_center_->RemoveObserver(this); +} + +void MessageCenterStatsCollector::OnNotificationAdded( + const std::string& notification_id) { + stats_[notification_id] = NotificationStats(notification_id); + + StatsCollection::iterator iter = stats_.find(notification_id); + DCHECK(iter != stats_.end()); + + stats_[notification_id].CollectAction(NOTIFICATION_ACTION_ADD); +} + +void MessageCenterStatsCollector::OnNotificationRemoved( + const std::string& notification_id, + bool by_user) { + StatsCollection::iterator iter = stats_.find(notification_id); + if (iter == stats_.end()) + return; + NotificationStats& notification_stat = iter->second; + notification_stat.CollectAction(by_user + ? NOTIFICATION_ACTION_CLOSE_BY_USER + : NOTIFICATION_ACTION_CLOSE_BY_SYSTEM); + notification_stat.RecordAggregateStats(); + stats_.erase(notification_id); +} + +void MessageCenterStatsCollector::OnNotificationUpdated( + const std::string& notification_id) { + StatsCollection::iterator iter = stats_.find(notification_id); + if (iter == stats_.end()) + return; + NotificationStats& notification_stat = iter->second; + + notification_stat.CollectAction(NOTIFICATION_ACTION_UPDATE); +} + +void MessageCenterStatsCollector::OnNotificationClicked( + const std::string& notification_id) { + StatsCollection::iterator iter = stats_.find(notification_id); + if (iter == stats_.end()) + return; + NotificationStats& notification_stat = iter->second; + + notification_stat.CollectAction(NOTIFICATION_ACTION_CLICK); +} + +void MessageCenterStatsCollector::OnNotificationButtonClicked( + const std::string& notification_id, + int button_index) { + StatsCollection::iterator iter = stats_.find(notification_id); + if (iter == stats_.end()) + return; + NotificationStats& notification_stat = iter->second; + + notification_stat.CollectAction(NOTIFICATION_ACTION_BUTTON_CLICK); +} + +void MessageCenterStatsCollector::OnNotificationSettingsClicked(bool handled) { + base::RecordAction(base::UserMetricsAction("Notifications.ShowSiteSettings")); +} + +void MessageCenterStatsCollector::OnNotificationDisplayed( + const std::string& notification_id, + const DisplaySource source) { + StatsCollection::iterator iter = stats_.find(notification_id); + if (iter == stats_.end()) + return; + NotificationStats& notification_stat = iter->second; + + notification_stat.CollectAction(NOTIFICATION_ACTION_DISPLAY); +} + +void MessageCenterStatsCollector::OnCenterVisibilityChanged( + Visibility visibility) { + switch (visibility) { + case VISIBILITY_TRANSIENT: + break; + case VISIBILITY_MESSAGE_CENTER: + base::RecordAction( + base::UserMetricsAction("Notifications.ShowMessageCenter")); + break; + case VISIBILITY_SETTINGS: + base::RecordAction(base::UserMetricsAction("Notifications.ShowSettings")); + break; + } +} + +void MessageCenterStatsCollector::OnQuietModeChanged(bool in_quiet_mode) { + if (in_quiet_mode) { + base::RecordAction(base::UserMetricsAction("Notifications.Mute")); + } else { + base::RecordAction(base::UserMetricsAction("Notifications.Unmute")); + } +} + +} // namespace message_center diff --git a/chromium/ui/message_center/message_center_stats_collector.h b/chromium/ui/message_center/message_center_stats_collector.h new file mode 100644 index 00000000000..6906f65d42f --- /dev/null +++ b/chromium/ui/message_center/message_center_stats_collector.h @@ -0,0 +1,89 @@ +// 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_MESSAGE_CENTER_MESSAGE_CENTER_STATS_COLLECTOR_H_ +#define UI_MESSAGE_CENTER_MESSAGE_CENTER_STATS_COLLECTOR_H_ + +#include <set> +#include <string> + +#include "base/macros.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/message_center_observer.h" +#include "ui/message_center/message_center_types.h" + +namespace message_center { + +class MessageCenter; + +// MessageCenterStatsCollector sends both raw and per-notification statistics +// to the UMA servers, if the user has opted in. It observes the message center +// to gather its data. +class MessageCenterStatsCollector : public MessageCenterObserver { + public: + enum NotificationActionType { + NOTIFICATION_ACTION_UNKNOWN, + NOTIFICATION_ACTION_ADD, + NOTIFICATION_ACTION_UPDATE, + NOTIFICATION_ACTION_CLICK, + NOTIFICATION_ACTION_BUTTON_CLICK, + NOTIFICATION_ACTION_DISPLAY, + NOTIFICATION_ACTION_CLOSE_BY_USER, + NOTIFICATION_ACTION_CLOSE_BY_SYSTEM, + // NOTE: Add new action types only immediately above this line. Also, + // make sure the enum list in tools/histogram/histograms.xml is + // updated with any change in here. + NOTIFICATION_ACTION_COUNT + }; + + explicit MessageCenterStatsCollector(MessageCenter* message_center); + ~MessageCenterStatsCollector() override; + + private: + // Represents the aggregate stats for each notification. + class NotificationStats { + public: + // Default constructor for map. + NotificationStats(); + + explicit NotificationStats(const std::string& id); + virtual ~NotificationStats(); + + // Called when we get an action from the message center. + void CollectAction(NotificationActionType type); + + // Sends aggregate data to UMA. + void RecordAggregateStats(); + + private: + std::string id_; + bool actions_[NOTIFICATION_ACTION_COUNT]; + }; + + // MessageCenterObserver + void OnNotificationAdded(const std::string& notification_id) override; + void OnNotificationRemoved(const std::string& notification_id, + bool by_user) override; + void OnNotificationUpdated(const std::string& notification_id) override; + void OnNotificationClicked(const std::string& notification_id) override; + void OnNotificationButtonClicked(const std::string& notification_id, + int button_index) override; + void OnNotificationSettingsClicked(bool handled) override; + void OnNotificationDisplayed(const std::string& notification_id, + const DisplaySource source) override; + void OnCenterVisibilityChanged(Visibility visibility) override; + void OnQuietModeChanged(bool in_quiet_mode) override; + + // Weak, global. + MessageCenter* message_center_; + + typedef std::map<std::string, NotificationStats> StatsCollection; + StatsCollection stats_; + + DISALLOW_COPY_AND_ASSIGN(MessageCenterStatsCollector); +}; + +} // namespace message_center + +#endif // UI_MESSAGE_CENTER_MESSAGE_CENTER_STATS_COLLECTOR_H_ diff --git a/chromium/ui/message_center/message_center_switches.h b/chromium/ui/message_center/message_center_switches.h deleted file mode 100644 index a589933161b..00000000000 --- a/chromium/ui/message_center/message_center_switches.h +++ /dev/null @@ -1,20 +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 UI_MESSAGE_CENTER_MESSAGE_CENTER_SWITCHES_H_ -#define UI_MESSAGE_CENTER_MESSAGE_CENTER_SWITCHES_H_ - -#include "base/compiler_specific.h" -#include "ui/message_center/message_center_export.h" - -namespace switches { - -MESSAGE_CENTER_EXPORT extern const char - kEnableMessageCenterNewStyleNotification[]; -MESSAGE_CENTER_EXPORT extern const char - kDisableMessageCenterNewStyleNotification[]; - -} // namespace switches - -#endif // UI_MESSAGE_CENTER_MESSAGE_CENTER_SWITCHES_H_ diff --git a/chromium/ui/message_center/mojo/notification.mojom b/chromium/ui/message_center/mojo/notification.mojom deleted file mode 100644 index 73985b2d1c3..00000000000 --- a/chromium/ui/message_center/mojo/notification.mojom +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module message_center.mojom; - -import "mojo/common/string16.mojom"; -import "ui/gfx/image/mojo/image.mojom"; -import "url/mojo/url.mojom"; - -// Matches message_center::NotificationType. -enum NotificationType { - SIMPLE = 0, - BASE_FORMAT = 1, - IMAGE = 2, - MULTIPLE = 3, - PROGRESS = 4, - CUSTOM = 5, -}; - -// These fields and their meanings are identical to those in -// message_center::RichNotificationData. -// TODO(estade): Add the rest of the fields for RichNotificationData. -struct RichNotificationData { - int32 progress; - mojo.common.mojom.String16 progress_status; - bool should_make_spoken_feedback_for_popup_updates; - bool clickable; - bool pinned; - mojo.common.mojom.String16 accessible_name; - uint32 accent_color; -}; - -// TODO(mhashmi): Add the rest of the fields for a Notification -struct Notification { - NotificationType type; - - // TODO(mhashmi): Server-side code (in Ash) needs to make sure this id won't - // collide with ids from different clients - string id; - - mojo.common.mojom.String16 title; - mojo.common.mojom.String16 message; - gfx.mojom.ImageSkia? icon; - mojo.common.mojom.String16 display_source; - url.mojom.Url origin_url; - - RichNotificationData optional_fields; -}; diff --git a/chromium/ui/message_center/mojo/notification_struct_traits.cc b/chromium/ui/message_center/mojo/notification_struct_traits.cc deleted file mode 100644 index 2a6ae93193e..00000000000 --- a/chromium/ui/message_center/mojo/notification_struct_traits.cc +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/message_center/mojo/notification_struct_traits.h" - -#include "mojo/common/string16_struct_traits.h" -#include "ui/gfx/image/mojo/image_skia_struct_traits.h" -#include "url/mojo/url_gurl_struct_traits.h" - -namespace mojo { - -using message_center::mojom::NotificationDataView; -using message_center::mojom::RichNotificationDataDataView; -using message_center::Notification; -using message_center::RichNotificationData; -using NotificationStructTraits = - StructTraits<NotificationDataView, Notification>; -using RichNotificationDataStructTraits = - StructTraits<RichNotificationDataDataView, RichNotificationData>; - -// static -int RichNotificationDataStructTraits::progress( - const message_center::RichNotificationData& r) { - return r.progress; -} - -// static -const base::string16& RichNotificationDataStructTraits::progress_status( - const message_center::RichNotificationData& r) { - return r.progress_status; -} - -// static -bool RichNotificationDataStructTraits:: - should_make_spoken_feedback_for_popup_updates( - const message_center::RichNotificationData& r) { - return r.should_make_spoken_feedback_for_popup_updates; -} - -// static -bool RichNotificationDataStructTraits::clickable( - const message_center::RichNotificationData& r) { - return r.clickable; -} - -// static -bool RichNotificationDataStructTraits::pinned( - const message_center::RichNotificationData& r) { - return r.pinned; -} - -// static -const base::string16& RichNotificationDataStructTraits::accessible_name( - const message_center::RichNotificationData& r) { - return r.accessible_name; -} - -// static -SkColor RichNotificationDataStructTraits::accent_color( - const message_center::RichNotificationData& r) { - return r.accent_color; -} - -// static -bool RichNotificationDataStructTraits::Read(RichNotificationDataDataView data, - RichNotificationData* out) { - out->progress = data.progress(); - out->should_make_spoken_feedback_for_popup_updates = - data.should_make_spoken_feedback_for_popup_updates(); - out->clickable = data.clickable(); - out->pinned = data.pinned(); - out->accent_color = data.accent_color(); - return data.ReadProgressStatus(&out->progress_status) && - data.ReadAccessibleName(&out->accessible_name); -} - -// static -message_center::NotificationType NotificationStructTraits::type( - const Notification& n) { - return n.type(); -} - -// static -const std::string& NotificationStructTraits::id(const Notification& n) { - return n.id(); -} - -// static -const base::string16& NotificationStructTraits::title(const Notification& n) { - return n.title(); -} - -// static -const base::string16& NotificationStructTraits::message(const Notification& n) { - return n.message(); -} - -// static -gfx::ImageSkia NotificationStructTraits::icon(const Notification& n) { - return n.icon().AsImageSkia(); -} - -// static -const base::string16& NotificationStructTraits::display_source( - const Notification& n) { - return n.display_source(); -} - -// static -const GURL& NotificationStructTraits::origin_url(const Notification& n) { - return n.origin_url(); -} - -// static -const RichNotificationData& NotificationStructTraits::optional_fields( - const Notification& n) { - return n.rich_notification_data(); -} - -// static -bool NotificationStructTraits::Read(NotificationDataView data, - Notification* out) { - gfx::ImageSkia icon; - if (!data.ReadIcon(&icon)) - return false; - out->set_icon(gfx::Image(icon)); - return EnumTraits<message_center::mojom::NotificationType, - message_center::NotificationType>::FromMojom(data.type(), - &out->type_) && - data.ReadId(&out->id_) && data.ReadTitle(&out->title_) && - data.ReadMessage(&out->message_) && - data.ReadDisplaySource(&out->display_source_) && - data.ReadOriginUrl(&out->origin_url_) && - data.ReadOptionalFields(&out->optional_fields_); -} - -} // namespace mojo diff --git a/chromium/ui/message_center/mojo/notification_struct_traits.h b/chromium/ui/message_center/mojo/notification_struct_traits.h deleted file mode 100644 index 8042ad49149..00000000000 --- a/chromium/ui/message_center/mojo/notification_struct_traits.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_MESSAGE_CENTER_NOTIFICATION_STRUCT_TRAITS_H_ -#define UI_MESSAGE_CENTER_NOTIFICATION_STRUCT_TRAITS_H_ - -#include "third_party/skia/include/core/SkColor.h" -#include "ui/message_center/mojo/notification.mojom-shared.h" -#include "ui/message_center/notification.h" - -namespace mojo { - -template <> -struct EnumTraits<message_center::mojom::NotificationType, - message_center::NotificationType> { - static message_center::mojom::NotificationType ToMojom( - message_center::NotificationType type) { - switch (type) { - case message_center::NOTIFICATION_TYPE_SIMPLE: - return message_center::mojom::NotificationType::SIMPLE; - case message_center::NOTIFICATION_TYPE_BASE_FORMAT: - return message_center::mojom::NotificationType::BASE_FORMAT; - case message_center::NOTIFICATION_TYPE_IMAGE: - return message_center::mojom::NotificationType::IMAGE; - case message_center::NOTIFICATION_TYPE_MULTIPLE: - return message_center::mojom::NotificationType::MULTIPLE; - case message_center::NOTIFICATION_TYPE_PROGRESS: - return message_center::mojom::NotificationType::PROGRESS; - case message_center::NOTIFICATION_TYPE_CUSTOM: - return message_center::mojom::NotificationType::CUSTOM; - } - NOTREACHED(); - return message_center::mojom::NotificationType::SIMPLE; - } - - static bool FromMojom(message_center::mojom::NotificationType input, - message_center::NotificationType* out) { - switch (input) { - case message_center::mojom::NotificationType::SIMPLE: - *out = message_center::NOTIFICATION_TYPE_SIMPLE; - return true; - case message_center::mojom::NotificationType::BASE_FORMAT: - *out = message_center::NOTIFICATION_TYPE_BASE_FORMAT; - return true; - case message_center::mojom::NotificationType::IMAGE: - *out = message_center::NOTIFICATION_TYPE_IMAGE; - return true; - case message_center::mojom::NotificationType::MULTIPLE: - *out = message_center::NOTIFICATION_TYPE_MULTIPLE; - return true; - case message_center::mojom::NotificationType::PROGRESS: - *out = message_center::NOTIFICATION_TYPE_PROGRESS; - return true; - case message_center::mojom::NotificationType::CUSTOM: - *out = message_center::NOTIFICATION_TYPE_CUSTOM; - return true; - } - NOTREACHED(); - return false; - } -}; - -template <> -struct StructTraits<message_center::mojom::RichNotificationDataDataView, - message_center::RichNotificationData> { - static int progress(const message_center::RichNotificationData& r); - static const base::string16& progress_status( - const message_center::RichNotificationData& r); - static bool should_make_spoken_feedback_for_popup_updates( - const message_center::RichNotificationData& r); - static bool clickable(const message_center::RichNotificationData& r); - static bool pinned(const message_center::RichNotificationData& r); - static const base::string16& accessible_name( - const message_center::RichNotificationData& r); - static SkColor accent_color(const message_center::RichNotificationData& r); - static bool Read(message_center::mojom::RichNotificationDataDataView data, - message_center::RichNotificationData* out); -}; - -template <> -struct StructTraits<message_center::mojom::NotificationDataView, - message_center::Notification> { - static message_center::NotificationType type( - const message_center::Notification& n); - static const std::string& id(const message_center::Notification& n); - static const base::string16& title(const message_center::Notification& n); - static const base::string16& message(const message_center::Notification& n); - static gfx::ImageSkia icon(const message_center::Notification& n); - static const base::string16& display_source( - const message_center::Notification& n); - static const GURL& origin_url(const message_center::Notification& n); - static const message_center::RichNotificationData& optional_fields( - const message_center::Notification& n); - static bool Read(message_center::mojom::NotificationDataView data, - message_center::Notification* out); -}; - -} // namespace mojo - -#endif // UI_MESSAGE_CENTER_NOTIFICATION_STRUCT_TRAITS_H_ diff --git a/chromium/ui/message_center/notification_blocker.h b/chromium/ui/message_center/notification_blocker.h index f9408f0f0a5..1082c349cf0 100644 --- a/chromium/ui/message_center/notification_blocker.h +++ b/chromium/ui/message_center/notification_blocker.h @@ -7,7 +7,7 @@ #include "base/observer_list.h" #include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification.h" +#include "ui/message_center/public/cpp/notification.h" namespace message_center { class MessageCenter; diff --git a/chromium/ui/message_center/notification_delegate.h b/chromium/ui/message_center/notification_delegate.h deleted file mode 100644 index 96288541d2f..00000000000 --- a/chromium/ui/message_center/notification_delegate.h +++ /dev/null @@ -1,89 +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_MESSAGE_CENTER_NOTIFICATION_DELEGATE_H_ -#define UI_MESSAGE_CENTER_NOTIFICATION_DELEGATE_H_ - -#include <memory> -#include <string> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/optional.h" -#include "base/strings/string16.h" -#include "ui/message_center/message_center_export.h" - -namespace message_center { - -// Delegate for a notification. This class has two roles: to implement callback -// methods for notification, and to provide an identity of the associated -// notification. -class MESSAGE_CENTER_EXPORT NotificationDelegate - : public base::RefCountedThreadSafe<NotificationDelegate> { - public: - // To be called when the desktop notification is closed. If closed by a - // user explicitly (as opposed to timeout/script), |by_user| should be true. - virtual void Close(bool by_user); - - // To be called when a desktop notification is clicked. - virtual void Click(); - - // To be called when the user clicks a button in a notification. - virtual void ButtonClick(int button_index); - - // To be called when the user types a reply to a notification. - // TODO(crbug.com/599859) Support this feature in the message center - - // currently it is only supported on Android. - virtual void ButtonClickWithReply(int button_index, - const base::string16& reply); - - // To be called when the user clicks the settings button in a notification - // which has a CUSTOM settings button action. - virtual void SettingsClick(); - - // Called when the user attempts to disable the notification. - virtual void DisableNotification(); - - protected: - virtual ~NotificationDelegate() {} - - private: - friend class base::RefCountedThreadSafe<NotificationDelegate>; -}; - -// A simple notification delegate which invokes the passed closure when the body -// or a button is clicked. -class MESSAGE_CENTER_EXPORT HandleNotificationClickDelegate - : public NotificationDelegate { - public: - // The parameter is the index of the button that was clicked, or nullopt if - // the body was clicked. - using ButtonClickCallback = - base::RepeatingCallback<void(base::Optional<int>)>; - - // Creates a delegate that handles clicks on a button or on the body. - explicit HandleNotificationClickDelegate(const ButtonClickCallback& callback); - - // Creates a delegate that only handles clicks on the body of the - // notification. - explicit HandleNotificationClickDelegate( - const base::RepeatingClosure& closure); - - // message_center::NotificationDelegate overrides: - void Click() override; - void ButtonClick(int button_index) override; - - protected: - ~HandleNotificationClickDelegate() override; - - private: - ButtonClickCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(HandleNotificationClickDelegate); -}; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_NOTIFICATION_DELEGATE_H_ diff --git a/chromium/ui/message_center/notification_list.cc b/chromium/ui/message_center/notification_list.cc index 505ff1a80b6..03882443b45 100644 --- a/chromium/ui/message_center/notification_list.cc +++ b/chromium/ui/message_center/notification_list.cc @@ -12,10 +12,10 @@ #include "base/values.h" #include "ui/gfx/image/image.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" #include "ui/message_center/notification_blocker.h" -#include "ui/message_center/notification_types.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" namespace message_center { @@ -177,9 +177,9 @@ bool NotificationList::HasPopupNotifications( return false; } -NotificationList::PopupNotifications NotificationList::GetPopupNotifications( - const NotificationBlockers& blockers, - std::list<const Notification*>* blocked) { +NotificationList::PopupNotifications +NotificationList::GetPopupNotifications(const NotificationBlockers& blockers, + std::list<std::string>* blocked) { PopupNotifications result; size_t default_priority_popup_count = 0; @@ -196,7 +196,7 @@ NotificationList::PopupNotifications NotificationList::GetPopupNotifications( if (!ShouldShowNotificationAsPopup(*notification, blockers)) { if (blocked) - blocked->push_back(notification); + blocked->push_back(notification->id()); continue; } diff --git a/chromium/ui/message_center/notification_list.h b/chromium/ui/message_center/notification_list.h index 9acf7fabcfe..c5a7935e93f 100644 --- a/chromium/ui/message_center/notification_list.h +++ b/chromium/ui/message_center/notification_list.h @@ -15,7 +15,7 @@ #include "base/macros.h" #include "ui/message_center/message_center_export.h" #include "ui/message_center/notification_blocker.h" -#include "ui/message_center/notification_types.h" +#include "ui/message_center/public/cpp/notification_types.h" namespace base { class TimeDelta; @@ -113,9 +113,8 @@ class MESSAGE_CENTER_EXPORT NotificationList { // It also stores the list of notifications which are blocked by |blockers| // to |blocked|. |blocked| can be NULL if the caller doesn't care which // notifications are blocked. - PopupNotifications GetPopupNotifications( - const NotificationBlockers& blockers, - std::list<const Notification*>* blocked); + PopupNotifications GetPopupNotifications(const NotificationBlockers& blockers, + std::list<std::string>* blocked); // Marks a specific popup item as shown. Set |mark_notification_as_read| to // true in case marking the notification as read too. diff --git a/chromium/ui/message_center/notification_list_unittest.cc b/chromium/ui/message_center/notification_list_unittest.cc index 71b181508b3..995358660d6 100644 --- a/chromium/ui/message_center/notification_list_unittest.cc +++ b/chromium/ui/message_center/notification_list_unittest.cc @@ -16,9 +16,9 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/message_center/fake_message_center.h" #include "ui/message_center/notification_blocker.h" -#include "ui/message_center/notification_types.h" -#include "ui/message_center/notifier_id.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification_types.h" +#include "ui/message_center/public/cpp/notifier_id.h" using base::UTF8ToUTF16; @@ -39,8 +39,7 @@ class NotificationListTest : public testing::Test { // Currently NotificationListTest doesn't care about some fields like title or // message, so put a simple template on it. Returns the id of the new // notification. - std::string AddNotification( - const message_center::RichNotificationData& optional_fields) { + std::string AddNotification(const RichNotificationData& optional_fields) { std::string new_id; std::unique_ptr<Notification> notification( MakeNotification(optional_fields, &new_id)); @@ -50,16 +49,16 @@ class NotificationListTest : public testing::Test { } std::string AddNotification() { - return AddNotification(message_center::RichNotificationData()); + return AddNotification(RichNotificationData()); } // Construct a new notification for testing, but don't add it to the list yet. std::unique_ptr<Notification> MakeNotification( - const message_center::RichNotificationData& optional_fields, + const RichNotificationData& optional_fields, std::string* id_out) { *id_out = base::StringPrintf(kIdFormat, counter_); std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, *id_out, + NOTIFICATION_TYPE_SIMPLE, *id_out, UTF8ToUTF16(base::StringPrintf(kTitleFormat, counter_)), UTF8ToUTF16(base::StringPrintf(kMessageFormat, counter_)), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), @@ -69,12 +68,12 @@ class NotificationListTest : public testing::Test { } std::unique_ptr<Notification> MakeNotification(std::string* id_out) { - return MakeNotification(message_center::RichNotificationData(), id_out); + return MakeNotification(RichNotificationData(), id_out); } // Utility methods of AddNotification. std::string AddPriorityNotification(NotificationPriority priority) { - message_center::RichNotificationData optional; + RichNotificationData optional; optional.priority = priority; return AddNotification(optional); } @@ -169,12 +168,11 @@ TEST_F(NotificationListTest, UpdateNotification) { std::string id0 = AddNotification(); std::string replaced = id0 + "_replaced"; EXPECT_EQ(1u, notification_list()->NotificationCount(blockers())); - std::unique_ptr<Notification> notification( - new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, replaced, - UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), - gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), - NotifierId(NotifierId::APPLICATION, kExtensionId), - message_center::RichNotificationData(), NULL)); + std::unique_ptr<Notification> notification(new Notification( + NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), + NotifierId(NotifierId::APPLICATION, kExtensionId), RichNotificationData(), + NULL)); notification_list()->UpdateNotificationMessage(id0, std::move(notification)); EXPECT_EQ(1u, notification_list()->NotificationCount(blockers())); const NotificationList::Notifications notifications = @@ -223,34 +221,34 @@ TEST_F(NotificationListTest, GetNotificationsByNotifierId) { NotifierId id2(GURL("http://example.com")); NotifierId id3(NotifierId::SYSTEM_COMPONENT, "system-notifier"); std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, "id0", UTF8ToUTF16("title0"), + NOTIFICATION_TYPE_SIMPLE, "id0", UTF8ToUTF16("title0"), UTF8ToUTF16("message0"), gfx::Image(), UTF8ToUTF16("source0"), GURL(), - id0, message_center::RichNotificationData(), NULL)); + id0, RichNotificationData(), NULL)); notification_list()->AddNotification(std::move(notification)); notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, "id1", UTF8ToUTF16("title1"), + NOTIFICATION_TYPE_SIMPLE, "id1", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source0"), GURL(), - id0, message_center::RichNotificationData(), NULL)); + id0, RichNotificationData(), NULL)); notification_list()->AddNotification(std::move(notification)); notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, "id2", UTF8ToUTF16("title1"), + NOTIFICATION_TYPE_SIMPLE, "id2", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source1"), GURL(), - id0, message_center::RichNotificationData(), NULL)); + id0, RichNotificationData(), NULL)); notification_list()->AddNotification(std::move(notification)); notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, "id3", UTF8ToUTF16("title1"), + NOTIFICATION_TYPE_SIMPLE, "id3", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source2"), GURL(), - id1, message_center::RichNotificationData(), NULL)); + id1, RichNotificationData(), NULL)); notification_list()->AddNotification(std::move(notification)); notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, "id4", UTF8ToUTF16("title1"), + NOTIFICATION_TYPE_SIMPLE, "id4", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source2"), GURL(), - id2, message_center::RichNotificationData(), NULL)); + id2, RichNotificationData(), NULL)); notification_list()->AddNotification(std::move(notification)); notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, "id5", UTF8ToUTF16("title1"), + NOTIFICATION_TYPE_SIMPLE, "id5", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source2"), GURL(), - id3, message_center::RichNotificationData(), NULL)); + id3, RichNotificationData(), NULL)); notification_list()->AddNotification(std::move(notification)); NotificationList::Notifications by_notifier_id = @@ -390,12 +388,11 @@ TEST_F(NotificationListTest, PriorityPromotion) { std::string replaced = id0 + "_replaced"; EXPECT_EQ(1u, notification_list()->NotificationCount(blockers())); EXPECT_EQ(0u, GetPopupCounts()); - message_center::RichNotificationData optional; + RichNotificationData optional; optional.priority = 1; std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, replaced, - UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), - UTF8ToUTF16(kDisplaySource), GURL(), + NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), optional, NULL)); notification_list()->UpdateNotificationMessage(id0, std::move(notification)); EXPECT_EQ(1u, notification_list()->NotificationCount(blockers())); @@ -416,10 +413,10 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { EXPECT_EQ(0u, GetPopupCounts()); // id0 promoted to LOW->DEFAULT, it'll appear as toast (popup). - message_center::RichNotificationData priority; + RichNotificationData priority; priority.priority = DEFAULT_PRIORITY; std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle"), + NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL)); notification_list()->UpdateNotificationMessage(id0, std::move(notification)); @@ -429,7 +426,7 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { // update with no promotion change for id0, it won't appear as a toast. notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle2"), + NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle2"), UTF8ToUTF16("newbody2"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL)); @@ -439,7 +436,7 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { // id1 promoted to DEFAULT->HIGH, it'll appear as toast (popup). priority.priority = HIGH_PRIORITY; notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle"), + NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL)); notification_list()->UpdateNotificationMessage(id1, std::move(notification)); @@ -450,7 +447,7 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { // id1 promoted to HIGH->MAX, it'll appear as toast again. priority.priority = MAX_PRIORITY; notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle2"), + NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle2"), UTF8ToUTF16("newbody2"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL)); @@ -462,7 +459,7 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { // id1 demoted to MAX->DEFAULT, no appearing as toast. priority.priority = DEFAULT_PRIORITY; notification.reset(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle3"), + NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle3"), UTF8ToUTF16("newbody3"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL)); @@ -473,11 +470,10 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { TEST_F(NotificationListTest, WebNotificationUpdatePromotion) { std::string notification_id = "replaced-web-notification"; std::unique_ptr<Notification> original_notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, + NOTIFICATION_TYPE_SIMPLE, notification_id, UTF8ToUTF16("Web Notification"), UTF8ToUTF16("Notification contents"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), - NotifierId(GURL("https://example.com/")), - message_center::RichNotificationData(), NULL)); + NotifierId(GURL("https://example.com/")), RichNotificationData(), NULL)); EXPECT_EQ(0u, GetPopupCounts()); notification_list()->AddNotification(std::move(original_notification)); @@ -487,12 +483,11 @@ TEST_F(NotificationListTest, WebNotificationUpdatePromotion) { EXPECT_EQ(0u, GetPopupCounts()); std::unique_ptr<Notification> replaced_notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, + NOTIFICATION_TYPE_SIMPLE, notification_id, UTF8ToUTF16("Web Notification Replacement"), UTF8ToUTF16("New notification contents"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), - NotifierId(GURL("https://example.com/")), - message_center::RichNotificationData(), NULL)); + NotifierId(GURL("https://example.com/")), RichNotificationData(), NULL)); // Web Notifications will be re-shown as popups even if their priority didn't // change, to match the behavior of the Web Notification API. @@ -503,7 +498,7 @@ TEST_F(NotificationListTest, WebNotificationUpdatePromotion) { TEST_F(NotificationListTest, NotificationOrderAndPriority) { base::Time now = base::Time::Now(); - message_center::RichNotificationData optional; + RichNotificationData optional; optional.timestamp = now; optional.priority = 2; std::string max_id = AddNotification(optional); @@ -592,12 +587,11 @@ TEST_F(NotificationListTest, UpdateAfterMarkedAsShown) { EXPECT_TRUE(n1->IsRead()); const std::string replaced("test-replaced-id"); - std::unique_ptr<Notification> notification( - new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, replaced, - UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), - gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), - NotifierId(NotifierId::APPLICATION, kExtensionId), - message_center::RichNotificationData(), NULL)); + std::unique_ptr<Notification> notification(new Notification( + NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), + NotifierId(NotifierId::APPLICATION, kExtensionId), RichNotificationData(), + NULL)); notification_list()->UpdateNotificationMessage(id1, std::move(notification)); n1 = GetNotification(id1); EXPECT_TRUE(n1 == NULL); @@ -638,21 +632,21 @@ TEST_F(NotificationListTest, TestPushingShownNotification) { TEST_F(NotificationListTest, TestHasNotificationOfType) { std::string id = AddNotification(); - EXPECT_TRUE(notification_list()->HasNotificationOfType( - id, message_center::NOTIFICATION_TYPE_SIMPLE)); + EXPECT_TRUE( + notification_list()->HasNotificationOfType(id, NOTIFICATION_TYPE_SIMPLE)); EXPECT_FALSE(notification_list()->HasNotificationOfType( - id, message_center::NOTIFICATION_TYPE_PROGRESS)); + id, NOTIFICATION_TYPE_PROGRESS)); - std::unique_ptr<Notification> updated_notification(new Notification( - message_center::NOTIFICATION_TYPE_PROGRESS, id, UTF8ToUTF16("updated"), - UTF8ToUTF16("updated"), gfx::Image(), base::string16(), GURL(), - NotifierId(), RichNotificationData(), NULL)); + std::unique_ptr<Notification> updated_notification( + new Notification(NOTIFICATION_TYPE_PROGRESS, id, UTF8ToUTF16("updated"), + UTF8ToUTF16("updated"), gfx::Image(), base::string16(), + GURL(), NotifierId(), RichNotificationData(), NULL)); notification_list()->AddNotification(std::move(updated_notification)); - EXPECT_FALSE(notification_list()->HasNotificationOfType( - id, message_center::NOTIFICATION_TYPE_SIMPLE)); + EXPECT_FALSE( + notification_list()->HasNotificationOfType(id, NOTIFICATION_TYPE_SIMPLE)); EXPECT_TRUE(notification_list()->HasNotificationOfType( - id, message_center::NOTIFICATION_TYPE_PROGRESS)); + id, NOTIFICATION_TYPE_PROGRESS)); } } // namespace message_center diff --git a/chromium/ui/message_center/notification_types.cc b/chromium/ui/message_center/notification_types.cc deleted file mode 100644 index a54ed7bd325..00000000000 --- a/chromium/ui/message_center/notification_types.cc +++ /dev/null @@ -1,22 +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/message_center/notification_types.h" - -namespace message_center { - -const char kPriorityKey[] = "priority"; -const char kTimestampKey[] = "timestamp"; -const char kButtonOneTitleKey[] = "button_one_title"; -const char kButtonOneIconUrlKey[] = "button_one_icon_url"; -const char kButtonTwoTitleKey[] = "button_two_title"; -const char kButtonTwoIconUrlKey[] = "button_two_icon_url"; -const char kExpandedMessageKey[] = "expanded_message"; -const char kImageUrlKey[] = "image_url"; -const char kItemsKey[] = "items"; -const char kItemTitleKey[] = "title"; -const char kItemMessageKey[] = "message"; -const char kPrivateNeverTimeoutKey[] = "private_never_timeout"; - -} // namespace message_center diff --git a/chromium/ui/message_center/notification_types.h b/chromium/ui/message_center/notification_types.h deleted file mode 100644 index 965fdd7fd9d..00000000000 --- a/chromium/ui/message_center/notification_types.h +++ /dev/null @@ -1,57 +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_MESSAGE_CENTER_NOTIFICATION_TYPES_H_ -#define UI_MESSAGE_CENTER_NOTIFICATION_TYPES_H_ - -#include "ui/message_center/message_center_export.h" - -namespace message_center { - -// Keys for optional fields in Notification. -MESSAGE_CENTER_EXPORT extern const char kPriorityKey[]; -MESSAGE_CENTER_EXPORT extern const char kTimestampKey[]; -MESSAGE_CENTER_EXPORT extern const char kButtonOneTitleKey[]; -MESSAGE_CENTER_EXPORT extern const char kButtonOneIconUrlKey[]; -MESSAGE_CENTER_EXPORT extern const char kButtonTwoTitleKey[]; -MESSAGE_CENTER_EXPORT extern const char kButtonTwoIconUrlKey[]; -MESSAGE_CENTER_EXPORT extern const char kExpandedMessageKey[]; -MESSAGE_CENTER_EXPORT extern const char kImageUrlKey[]; -MESSAGE_CENTER_EXPORT extern const char kItemsKey[]; -MESSAGE_CENTER_EXPORT extern const char kItemTitleKey[]; -MESSAGE_CENTER_EXPORT extern const char kItemMessageKey[]; -// This key should not be used by the extension API handler. It's not allowed -// to use it there, it's used to cancel timeout for webkit notifications. -MESSAGE_CENTER_EXPORT extern const char kPrivateNeverTimeoutKey[]; - -// Notification types. Note that the values in this enumeration are being -// recoded in a histogram, updates should not change the entries' values. -enum NotificationType { - NOTIFICATION_TYPE_SIMPLE = 0, - NOTIFICATION_TYPE_BASE_FORMAT = 1, - NOTIFICATION_TYPE_IMAGE = 2, - NOTIFICATION_TYPE_MULTIPLE = 3, - NOTIFICATION_TYPE_PROGRESS = 4, // Notification with progress bar. - NOTIFICATION_TYPE_CUSTOM = 5, - - // Add new values before this line. - NOTIFICATION_TYPE_LAST = NOTIFICATION_TYPE_CUSTOM -}; - -enum NotificationPriority { - MIN_PRIORITY = -2, - LOW_PRIORITY = -1, - DEFAULT_PRIORITY = 0, - HIGH_PRIORITY = 1, - MAX_PRIORITY = 2, - - // Top priority for system-level notifications.. This can't be set from - // kPriorityKey, instead you have to call SetSystemPriority() of - // Notification object. - SYSTEM_PRIORITY = 3, -}; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_NOTIFICATION_TYPES_H_ diff --git a/chromium/ui/message_center/public/DEPS b/chromium/ui/message_center/public/DEPS new file mode 100644 index 00000000000..5502cd434d1 --- /dev/null +++ b/chromium/ui/message_center/public/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "-ui/message_center", + "+ui/message_center/public", +] diff --git a/chromium/ui/message_center/public/cpp/BUILD.gn b/chromium/ui/message_center/public/cpp/BUILD.gn index 75ce71c849c..a647bb534f5 100644 --- a/chromium/ui/message_center/public/cpp/BUILD.gn +++ b/chromium/ui/message_center/public/cpp/BUILD.gn @@ -6,11 +6,20 @@ import("//build/config/jumbo.gni") # C++ headers and sources that can be used outside message_center. jumbo_component("cpp") { + output_name = "ui_message_center_cpp" + sources = [ + "features.cc", + "features.h", "message_center_constants.h", "message_center_public_export.h", - "message_center_switches.cc", - "message_center_switches.h", + "notification.cc", + "notification.h", + "notification_delegate.cc", + "notification_delegate.h", + "notification_types.h", + "notifier_id.cc", + "notifier_id.h", ] defines = [ "MESSAGE_CENTER_PUBLIC_IMPLEMENTATION" ] @@ -19,5 +28,7 @@ jumbo_component("cpp") { "//base", "//skia", "//ui/gfx", + "//ui/strings", + "//url", ] } diff --git a/chromium/ui/message_center/public/cpp/features.cc b/chromium/ui/message_center/public/cpp/features.cc new file mode 100644 index 00000000000..079e49bfdf5 --- /dev/null +++ b/chromium/ui/message_center/public/cpp/features.cc @@ -0,0 +1,18 @@ +// 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 "ui/message_center/public/cpp/features.h" + +namespace message_center { + +const base::Feature kNewStyleNotifications { + "NewStyleNotifications", +#if defined(OS_CHROMEOS) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; + +} // namespace message_center diff --git a/chromium/ui/message_center/public/cpp/features.h b/chromium/ui/message_center/public/cpp/features.h new file mode 100644 index 00000000000..dadaddbb22e --- /dev/null +++ b/chromium/ui/message_center/public/cpp/features.h @@ -0,0 +1,19 @@ +// Copyright 2018 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_MESSAGE_CENTER_PUBLIC_CPP_FEATURES_H_ +#define UI_MESSAGE_CENTER_PUBLIC_CPP_FEATURES_H_ + +#include "base/feature_list.h" +#include "ui/message_center/public/cpp/message_center_public_export.h" + +namespace message_center { + +// This feature controls whether the new (material design) style notifications +// should be used. +MESSAGE_CENTER_PUBLIC_EXPORT extern const base::Feature kNewStyleNotifications; + +} // namespace message_center + +#endif // UI_MESSAGE_CENTER_PUBLIC_CPP_FEATURES_H_ diff --git a/chromium/ui/message_center/public/cpp/message_center_constants.h b/chromium/ui/message_center/public/cpp/message_center_constants.h index 39f52903846..6cdbadde8c3 100644 --- a/chromium/ui/message_center/public/cpp/message_center_constants.h +++ b/chromium/ui/message_center/public/cpp/message_center_constants.h @@ -35,8 +35,9 @@ const size_t kMaxVisiblePopupNotifications = 3; const int kNotificationWidth = 360; // Colors. -const SkColor kMessageCenterBorderColor = SkColorSetRGB(0xC7, 0xCA, 0xCE); -const SkColor kMessageCenterShadowColor = SkColorSetA(SK_ColorBLACK, 0.5 * 255); +constexpr SkColor kMessageCenterBorderColor = SkColorSetRGB(0xC7, 0xCA, 0xCE); +constexpr SkColor kMessageCenterShadowColor = + SkColorSetA(SK_ColorBLACK, 0.5 * 255); // Within a notification /////////////////////////////////////////////////////// @@ -64,30 +65,30 @@ const int kMessageLineHeight = 18; // In DIPs. // Colors. // Background of the card. -const SkColor kNotificationBackgroundColor = SK_ColorWHITE; +constexpr SkColor kNotificationBackgroundColor = SK_ColorWHITE; // Background of the image. -const SkColor kImageBackgroundColor = kNotificationBackgroundColor; +constexpr SkColor kImageBackgroundColor = kNotificationBackgroundColor; // Title, message, ... -const SkColor kRegularTextColor = SkColorSetRGB(0x33, 0x33, 0x33); -const SkColor kDimTextColor = SkColorSetRGB(0x7f, 0x7f, 0x7f); +constexpr SkColor kRegularTextColor = SkColorSetRGB(0x33, 0x33, 0x33); +constexpr SkColor kDimTextColor = SkColorSetRGB(0x7f, 0x7f, 0x7f); // The focus border. -const SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250); +constexpr SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250); // Foreground of small icon image. -const SkColor kSmallImageMaskForegroundColor = SK_ColorWHITE; +constexpr SkColor kSmallImageMaskForegroundColor = SK_ColorWHITE; // Background of small icon image. -const SkColor kSmallImageMaskBackgroundColor = SkColorSetRGB(0xa3, 0xa3, 0xa3); +constexpr SkColor kSmallImageMaskBackgroundColor = + SkColorSetRGB(0xa3, 0xa3, 0xa3); // Background of the close button and the settings button -const SkColor kControlButtonBackgroundColor = +constexpr SkColor kControlButtonBackgroundColor = SkColorSetA(SK_ColorWHITE, 0.9 * 0xff); // Accent colors of system notifications. -const SkColor kSystemNotificationColorNormal = SkColorSetRGB(0x33, 0x67, 0xd6); -const SkColor kSystemNotificationColorWarning = SkColorSetRGB(0xea, 0x61, 0x0); -const SkColor kSystemNotificationColorCriticalWarning = - SkColorSetRGB(0xc5, 0x39, 0x29); +constexpr SkColor kSystemNotificationColorNormal = gfx::kGoogleBlue700; +constexpr SkColor kSystemNotificationColorWarning = gfx::kGoogleYellow900; +constexpr SkColor kSystemNotificationColorCriticalWarning = gfx::kGoogleRed700; // Default accent color of notifications that are not generated by system. -const SkColor kNotificationDefaultAccentColor = gfx::kChromeIconGrey; +constexpr SkColor kNotificationDefaultAccentColor = gfx::kChromeIconGrey; // For list notifications. // Not used when --enabled-new-style-notification is set. @@ -106,8 +107,8 @@ const int kButtonIconTopPadding = 11; // In DIPs. const int kButtonIconToTitlePadding = 16; // In DIPs. #if !defined(OS_LINUX) || defined(USE_AURA) -const SkColor kButtonSeparatorColor = SkColorSetRGB(234, 234, 234); -const SkColor kHoveredButtonBackgroundColor = SkColorSetRGB(243, 243, 243); +constexpr SkColor kButtonSeparatorColor = SkColorSetRGB(234, 234, 234); +constexpr SkColor kHoveredButtonBackgroundColor = SkColorSetRGB(243, 243, 243); #endif // Progress bar. @@ -115,8 +116,8 @@ const int kProgressBarTopPadding = 16; #if defined(OS_MACOSX) const int kProgressBarThickness = 5; const int kProgressBarCornerRadius = 3; -const SkColor kProgressBarBackgroundColor = SkColorSetARGB(26, 0, 0, 0); -const SkColor kProgressBarSliceColor = SkColorSetRGB(26, 194, 34); +constexpr SkColor kProgressBarBackgroundColor = SkColorSetARGB(26, 0, 0, 0); +constexpr SkColor kProgressBarSliceColor = SkColorSetRGB(26, 194, 34); #endif // Line limits. @@ -137,9 +138,6 @@ constexpr int kMarginBetweenItemsInList = 8; // Horizontal & vertical space around & between popup notifications. constexpr int kMarginBetweenPopups = 10; -// Shadow in the tray. -const SkColor kShadowColor = SkColorSetARGB(0.3 * 255, 0, 0, 0); - // Radius of the rounded corners of a notification. // The corners are only rounded in Chrome OS. constexpr int kNotificationCornerRadius = 2; diff --git a/chromium/ui/message_center/public/cpp/message_center_switches.cc b/chromium/ui/message_center/public/cpp/message_center_switches.cc deleted file mode 100644 index 08bcec0d04d..00000000000 --- a/chromium/ui/message_center/public/cpp/message_center_switches.cc +++ /dev/null @@ -1,36 +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 "ui/message_center/public/cpp/message_center_switches.h" - -#include "base/command_line.h" - -namespace message_center { - -bool IsNewStyleNotificationEnabled() { -// For Chrome OS, the default is Enabled. -// For other platforms, the default is Disabled. -#if defined(OS_CHROMEOS) - // Returns true if not explicitly disabled. - return !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableMessageCenterNewStyleNotification); -#else - // Returns true if explicitly enabled. - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableMessageCenterNewStyleNotification); -#endif -} - -namespace switches { - -// Flag to enable or disable new-style notification. This flag will be removed -// once the feature gets stable. -const char kEnableMessageCenterNewStyleNotification[] = - "enabled-new-style-notification"; -const char kDisableMessageCenterNewStyleNotification[] = - "disabled-new-style-notification"; - -} // namespace switches - -} // namespace message_center diff --git a/chromium/ui/message_center/public/cpp/message_center_switches.h b/chromium/ui/message_center/public/cpp/message_center_switches.h deleted file mode 100644 index 461b81d6048..00000000000 --- a/chromium/ui/message_center/public/cpp/message_center_switches.h +++ /dev/null @@ -1,27 +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 UI_MESSAGE_CENTER_PUBLIC_CPP_MESSAGE_CENTER_SWITCHES_H_ -#define UI_MESSAGE_CENTER_PUBLIC_CPP_MESSAGE_CENTER_SWITCHES_H_ - -#include "ui/message_center/public/cpp/message_center_public_export.h" - -namespace message_center { - -// Returns if new style notification is enabled, i.e. NotificationViewMD is -// used instead of NotificationView. -bool MESSAGE_CENTER_PUBLIC_EXPORT IsNewStyleNotificationEnabled(); - -namespace switches { - -MESSAGE_CENTER_PUBLIC_EXPORT extern const char - kEnableMessageCenterNewStyleNotification[]; -MESSAGE_CENTER_PUBLIC_EXPORT extern const char - kDisableMessageCenterNewStyleNotification[]; - -} // namespace switches - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_PUBLIC_CPP_MESSAGE_CENTER_SWITCHES_H_ diff --git a/chromium/ui/message_center/notification.cc b/chromium/ui/message_center/public/cpp/notification.cc index d5fda30e3ed..dd06417bce3 100644 --- a/chromium/ui/message_center/notification.cc +++ b/chromium/ui/message_center/public/cpp/notification.cc @@ -2,25 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/message_center/notification.h" +#include "ui/message_center/public/cpp/notification.h" +#include <map> #include <memory> +#include "base/lazy_instance.h" #include "base/logging.h" -#include "ui/base/l10n/l10n_util.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icon_types.h" -#include "ui/message_center/notification_delegate.h" -#include "ui/message_center/notification_types.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification_delegate.h" +#include "ui/message_center/public/cpp/notification_types.h" namespace message_center { namespace { -unsigned g_next_serial_number_ = 0; +unsigned g_next_serial_number = 0; + +base::LazyInstance<std::map<std::string, const gfx::VectorIcon&>>::Leaky + g_vector_icon_registry = LAZY_INSTANCE_INITIALIZER; const gfx::ImageSkia CreateSolidColorImage(int width, int height, @@ -40,50 +44,20 @@ gfx::Image DeepCopyImage(const gfx::Image& image) { } // namespace -NotificationItem::NotificationItem(const base::string16& title, - const base::string16& message) - : title(title), - message(message) { -} - -ButtonInfo::ButtonInfo(const base::string16& title) - : title(title) { -} +ButtonInfo::ButtonInfo(const base::string16& title) : title(title) {} ButtonInfo::ButtonInfo(const ButtonInfo& other) = default; +ButtonInfo::ButtonInfo() = default; + ButtonInfo::~ButtonInfo() = default; ButtonInfo& ButtonInfo::operator=(const ButtonInfo& other) = default; RichNotificationData::RichNotificationData() : timestamp(base::Time::Now()) {} -RichNotificationData::RichNotificationData(const RichNotificationData& other) - : priority(other.priority), - never_timeout(other.never_timeout), - timestamp(other.timestamp), - context_message(other.context_message), - image(other.image), - small_image(other.small_image), - vector_small_image(other.vector_small_image), - items(other.items), - progress(other.progress), - progress_status(other.progress_status), - buttons(other.buttons), - should_make_spoken_feedback_for_popup_updates( - other.should_make_spoken_feedback_for_popup_updates), - clickable(other.clickable), -#if defined(OS_CHROMEOS) - pinned(other.pinned), -#endif // defined(OS_CHROMEOS) - vibration_pattern(other.vibration_pattern), - renotify(other.renotify), - silent(other.silent), - accessible_name(other.accessible_name), - accent_color(other.accent_color), - settings_button_handler(other.settings_button_handler), - fullscreen_visibility(other.fullscreen_visibility) { -} +RichNotificationData::RichNotificationData(const RichNotificationData& other) = + default; RichNotificationData::~RichNotificationData() = default; @@ -107,60 +81,21 @@ Notification::Notification(NotificationType type, display_source_(display_source), origin_url_(origin_url), notifier_id_(notifier_id), - serial_number_(g_next_serial_number_++), optional_fields_(optional_fields), + serial_number_(g_next_serial_number++), shown_as_popup_(false), is_read_(false), delegate_(std::move(delegate)) {} Notification::Notification(const std::string& id, const Notification& other) - : type_(other.type_), - id_(id), - title_(other.title_), - message_(other.message_), - icon_(other.icon_), - display_source_(other.display_source_), - origin_url_(other.origin_url_), - notifier_id_(other.notifier_id_), - serial_number_(other.serial_number_), - optional_fields_(other.optional_fields_), - shown_as_popup_(other.shown_as_popup_), - is_read_(other.is_read_), - delegate_(other.delegate_) {} - -Notification::Notification(const Notification& other) - : type_(other.type_), - id_(other.id_), - title_(other.title_), - message_(other.message_), - icon_(other.icon_), - display_source_(other.display_source_), - origin_url_(other.origin_url_), - notifier_id_(other.notifier_id_), - serial_number_(other.serial_number_), - optional_fields_(other.optional_fields_), - shown_as_popup_(other.shown_as_popup_), - is_read_(other.is_read_), - delegate_(other.delegate_) {} - -Notification& Notification::operator=(const Notification& other) { - type_ = other.type_; - id_ = other.id_; - title_ = other.title_; - message_ = other.message_; - icon_ = other.icon_; - display_source_ = other.display_source_; - origin_url_ = other.origin_url_; - notifier_id_ = other.notifier_id_; - serial_number_ = other.serial_number_; - optional_fields_ = other.optional_fields_; - shown_as_popup_ = other.shown_as_popup_; - is_read_ = other.is_read_; - delegate_ = other.delegate_; - - return *this; + : Notification(other) { + id_ = id; } +Notification::Notification(const Notification& other) = default; + +Notification& Notification::operator=(const Notification& other) = default; + Notification::~Notification() = default; // static @@ -241,7 +176,7 @@ std::unique_ptr<Notification> Notification::CreateSystemNotification( const base::string16& message, const gfx::Image& icon, const std::string& system_component_id, - const base::Closure& click_callback) { + const base::RepeatingClosure& click_callback) { DCHECK(!click_callback.is_null()); std::unique_ptr<Notification> notification = CreateSystemNotification( NOTIFICATION_TYPE_SIMPLE, notification_id, title, message, icon, @@ -270,29 +205,38 @@ std::unique_ptr<Notification> Notification::CreateSystemNotification( const gfx::VectorIcon& small_image, SystemNotificationWarningLevel color_type) { DCHECK_EQ(NotifierId::SYSTEM_COMPONENT, notifier_id.type); - SkColor color = message_center::kSystemNotificationColorNormal; + SkColor color = kSystemNotificationColorNormal; switch (color_type) { case SystemNotificationWarningLevel::NORMAL: - color = message_center::kSystemNotificationColorNormal; + color = kSystemNotificationColorNormal; break; case SystemNotificationWarningLevel::WARNING: - color = message_center::kSystemNotificationColorWarning; + color = kSystemNotificationColorWarning; break; case SystemNotificationWarningLevel::CRITICAL_WARNING: - color = message_center::kSystemNotificationColorCriticalWarning; + color = kSystemNotificationColorCriticalWarning; break; } std::unique_ptr<Notification> notification = std::make_unique<Notification>( type, id, title, message, icon, display_source, origin_url, notifier_id, optional_fields, delegate); notification->set_accent_color(color); - notification->set_small_image( - small_image.is_empty() ? gfx::Image() - : gfx::Image(gfx::CreateVectorIcon( - small_image, kSmallImageSizeMD, color))); if (!small_image.is_empty()) notification->set_vector_small_image(small_image); return notification; } +// static +void RegisterVectorIcon(const gfx::VectorIcon& vector_icon) { + g_vector_icon_registry.Get().insert( + std::pair<std::string, const gfx::VectorIcon&>(vector_icon.name, + vector_icon)); +} + +// static +const gfx::VectorIcon* GetRegisteredVectorIcon(const std::string& id) { + auto iter = g_vector_icon_registry.Get().find(id); + return iter != g_vector_icon_registry.Get().end() ? &iter->second : nullptr; +} + } // namespace message_center diff --git a/chromium/ui/message_center/notification.h b/chromium/ui/message_center/public/cpp/notification.h index 8fc687babce..c91d0dac645 100644 --- a/chromium/ui/message_center/notification.h +++ b/chromium/ui/message_center/public/cpp/notification.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_MESSAGE_CENTER_NOTIFICATION_H_ -#define UI_MESSAGE_CENTER_NOTIFICATION_H_ +#ifndef UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_H_ +#define UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_H_ #include <stddef.h> @@ -11,6 +11,7 @@ #include <vector> #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "base/strings/string16.h" #include "base/time/time.h" #include "base/values.h" @@ -21,10 +22,10 @@ #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/vector_icon_types.h" -#include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification_delegate.h" -#include "ui/message_center/notification_types.h" -#include "ui/message_center/notifier_id.h" +#include "ui/message_center/public/cpp/message_center_public_export.h" +#include "ui/message_center/public/cpp/notification_delegate.h" +#include "ui/message_center/public/cpp/notification_types.h" +#include "ui/message_center/public/cpp/notifier_id.h" #include "url/gurl.h" namespace gfx { @@ -38,34 +39,24 @@ class NotificationDataView; } // Represents an individual item in NOTIFICATION_TYPE_MULTIPLE notifications. -struct MESSAGE_CENTER_EXPORT NotificationItem { - NotificationItem(const base::string16& title, const base::string16& message); - +struct MESSAGE_CENTER_PUBLIC_EXPORT NotificationItem { base::string16 title; base::string16 message; }; -enum class ButtonType { - // A simple button having an icon and a title that the user can click on. - BUTTON, - - // A button having an icon and a title that should also enable the user to - // input text, enabling them to quickly respond from the notification. - TEXT -}; - enum class SettingsButtonHandler { - NONE, // No button. This is the default. - TRAY, // Button shown, the tray handles clicks. Only used on Chrome OS. - DELEGATE // Button shown, notification's delegate handles action. + NONE = 0, // No button. This is the default. + INLINE = 1, // Button shown, settings inline. + DELEGATE = 2 // Button shown, notification's delegate handles action. }; enum class SystemNotificationWarningLevel { NORMAL, WARNING, CRITICAL_WARNING }; // Represents a button to be shown as part of a notification. -struct MESSAGE_CENTER_EXPORT ButtonInfo { +struct MESSAGE_CENTER_PUBLIC_EXPORT ButtonInfo { explicit ButtonInfo(const base::string16& title); ButtonInfo(const ButtonInfo& other); + ButtonInfo(); ~ButtonInfo(); ButtonInfo& operator=(const ButtonInfo& other); @@ -77,25 +68,20 @@ struct MESSAGE_CENTER_EXPORT ButtonInfo { // requirements of the notification. gfx::Image icon; - // Type of this button. - ButtonType type = ButtonType::BUTTON; - - // The placeholder string that should be displayed in the input field for TEXT - // type buttons until the user has entered a response themselves. - base::string16 placeholder; + // The placeholder string that should be displayed in the input field for + // text input type buttons until the user has entered a response themselves. + // If the value is null, there is no input field associated with the button. + base::Optional<base::string16> placeholder; }; -// TODO(estade): add an ALWAYS value to mark notifications as additionally -// visible over system fullscreen windows such as Chrome OS login so we don't -// need to centrally track Ash system notification IDs. enum class FullscreenVisibility { - NONE, // Don't show the notification over fullscreen (default). - OVER_USER, // Show over the current fullscreened client window. - // windows (like Chrome OS login). + NONE = 0, // Don't show the notification over fullscreen (default). + OVER_USER = 1, // Show over the current fullscreened client window. + // windows (like Chrome OS login). }; // Represents rich features available for notifications. -class MESSAGE_CENTER_EXPORT RichNotificationData { +class MESSAGE_CENTER_PUBLIC_EXPORT RichNotificationData { public: RichNotificationData(); RichNotificationData(const RichNotificationData& other); @@ -198,7 +184,7 @@ class MESSAGE_CENTER_EXPORT RichNotificationData { FullscreenVisibility fullscreen_visibility = FullscreenVisibility::NONE; }; -class MESSAGE_CENTER_EXPORT Notification { +class MESSAGE_CENTER_PUBLIC_EXPORT Notification { public: // Default constructor needed for generated mojom files. Notification(); @@ -406,9 +392,7 @@ class MESSAGE_CENTER_EXPORT Notification { } bool clickable() const { return optional_fields_.clickable; } - void set_clickable(bool clickable) { - optional_fields_.clickable = clickable; - } + void set_clickable(bool clickable) { optional_fields_.clickable = clickable; } bool pinned() const { #if defined(OS_CHROMEOS) @@ -478,7 +462,7 @@ class MESSAGE_CENTER_EXPORT Notification { const base::string16& message, const gfx::Image& icon, const std::string& system_component_id, - const base::Closure& click_callback); + const base::RepeatingClosure& click_callback); // Factory method to create all kinds of notifications generated by system, // from normal priority ones to critical priority ones. @@ -523,16 +507,29 @@ class MESSAGE_CENTER_EXPORT Notification { // it's a system notification. GURL origin_url_; NotifierId notifier_id_; - unsigned serial_number_; RichNotificationData optional_fields_; + + // TODO(estade): these book-keeping fields should be moved into + // NotificationList. + unsigned serial_number_; bool shown_as_popup_; // True if this has been shown as a popup. - bool is_read_; // True if this has been seen in the message center. + bool is_read_; // True if this has been seen in the message center. // A proxy object that allows access back to the JavaScript object that // represents the notification, for firing events. scoped_refptr<NotificationDelegate> delegate_; }; +// Registering a vector icon allows it to later be looked up by name. This is +// useful for vector icons sent over mojo: assuming the receiver has a known set +// of icons it expects to see, this allows for icon lookup without +// serialization/deserialization. +MESSAGE_CENTER_PUBLIC_EXPORT +void RegisterVectorIcon(const gfx::VectorIcon& vector_icon); + +MESSAGE_CENTER_PUBLIC_EXPORT +const gfx::VectorIcon* GetRegisteredVectorIcon(const std::string& id); + } // namespace message_center -#endif // UI_MESSAGE_CENTER_NOTIFICATION_H_ +#endif // UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_H_ diff --git a/chromium/ui/message_center/notification_delegate.cc b/chromium/ui/message_center/public/cpp/notification_delegate.cc index 27cc82096c6..42b536b97ac 100644 --- a/chromium/ui/message_center/notification_delegate.cc +++ b/chromium/ui/message_center/public/cpp/notification_delegate.cc @@ -2,29 +2,52 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/message_center/notification_delegate.h" +#include "ui/message_center/public/cpp/notification_delegate.h" #include "base/bind.h" #include "base/logging.h" namespace message_center { -// NotificationDelegate: +// ThunkNotificationDelegate: -void NotificationDelegate::Close(bool by_user) {} +ThunkNotificationDelegate::ThunkNotificationDelegate( + base::WeakPtr<NotificationObserver> impl) + : impl_(impl) {} -void NotificationDelegate::Click() {} +void ThunkNotificationDelegate::Close(bool by_user) { + if (impl_) + impl_->Close(by_user); +} + +void ThunkNotificationDelegate::Click() { + if (impl_) + impl_->Click(); +} -void NotificationDelegate::ButtonClick(int button_index) {} +void ThunkNotificationDelegate::ButtonClick(int button_index) { + if (impl_) + impl_->ButtonClick(button_index); +} -void NotificationDelegate::ButtonClickWithReply(int button_index, - const base::string16& reply) { - NOTIMPLEMENTED(); +void ThunkNotificationDelegate::ButtonClickWithReply( + int button_index, + const base::string16& reply) { + if (impl_) + impl_->ButtonClickWithReply(button_index, reply); } -void NotificationDelegate::SettingsClick() {} +void ThunkNotificationDelegate::SettingsClick() { + if (impl_) + impl_->SettingsClick(); +} + +void ThunkNotificationDelegate::DisableNotification() { + if (impl_) + impl_->DisableNotification(); +} -void NotificationDelegate::DisableNotification() {} +ThunkNotificationDelegate::~ThunkNotificationDelegate() = default; // HandleNotificationClickDelegate: @@ -33,7 +56,7 @@ HandleNotificationClickDelegate::HandleNotificationClickDelegate( if (!callback.is_null()) { // Create a callback that consumes and ignores the button index parameter, // and just runs the provided closure. - callback_ = base::Bind( + callback_ = base::BindRepeating( [](const base::RepeatingClosure& closure, base::Optional<int> button_index) { DCHECK(!button_index); diff --git a/chromium/ui/message_center/public/cpp/notification_delegate.h b/chromium/ui/message_center/public/cpp/notification_delegate.h new file mode 100644 index 00000000000..8f5a5321969 --- /dev/null +++ b/chromium/ui/message_center/public/cpp/notification_delegate.h @@ -0,0 +1,119 @@ +// 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_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_DELEGATE_H_ +#define UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_DELEGATE_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" +#include "base/strings/string16.h" +#include "ui/message_center/public/cpp/message_center_public_export.h" + +namespace message_center { + +// Handles actions performed on a notification. +class MESSAGE_CENTER_PUBLIC_EXPORT NotificationObserver { + public: + // To be called when the desktop notification is closed. If closed by a + // user explicitly (as opposed to timeout/script), |by_user| should be true. + virtual void Close(bool by_user) {} + + // To be called when a desktop notification is clicked. + virtual void Click() {} + + // To be called when the user clicks a button in a notification. + virtual void ButtonClick(int button_index) {} + + // To be called when the user types a reply to a notification. + virtual void ButtonClickWithReply(int button_index, + const base::string16& reply) {} + + // To be called when the user clicks the settings button in a notification + // which has a DELEGATE settings button action. + virtual void SettingsClick() {} + + // Called when the user attempts to disable the notification. + virtual void DisableNotification() {} +}; + +// Ref counted version of NotificationObserver, required to satisfy +// message_center::Notification::delegate_. +class MESSAGE_CENTER_PUBLIC_EXPORT NotificationDelegate + : public NotificationObserver, + public base::RefCountedThreadSafe<NotificationDelegate> { + protected: + virtual ~NotificationDelegate() = default; + + private: + friend class base::RefCountedThreadSafe<NotificationDelegate>; +}; + +// A pass-through which converts the RefCounted requirement to a WeakPtr +// requirement. This class replaces the need for individual delegates that pass +// through to an actual controller class, and which only exist because the +// actual controller has a strong ownership model. TODO(estade): replace many +// existing NotificationDelegate overrides with an instance of this class. +class MESSAGE_CENTER_PUBLIC_EXPORT ThunkNotificationDelegate + : public NotificationDelegate { + public: + explicit ThunkNotificationDelegate(base::WeakPtr<NotificationObserver> impl); + + // NotificationDelegate: + void Close(bool by_user) override; + void Click() override; + void ButtonClick(int button_index) override; + void ButtonClickWithReply(int button_index, + const base::string16& reply) override; + void SettingsClick() override; + void DisableNotification() override; + + protected: + ~ThunkNotificationDelegate() override; + + private: + base::WeakPtr<NotificationObserver> impl_; + + DISALLOW_COPY_AND_ASSIGN(ThunkNotificationDelegate); +}; + +// A simple notification delegate which invokes the passed closure when the body +// or a button is clicked. +class MESSAGE_CENTER_PUBLIC_EXPORT HandleNotificationClickDelegate + : public NotificationDelegate { + public: + // The parameter is the index of the button that was clicked, or nullopt if + // the body was clicked. + using ButtonClickCallback = + base::RepeatingCallback<void(base::Optional<int>)>; + + // Creates a delegate that handles clicks on a button or on the body. + explicit HandleNotificationClickDelegate(const ButtonClickCallback& callback); + + // Creates a delegate that only handles clicks on the body of the + // notification. + explicit HandleNotificationClickDelegate( + const base::RepeatingClosure& closure); + + // NotificationDelegate overrides: + void Click() override; + void ButtonClick(int button_index) override; + + protected: + ~HandleNotificationClickDelegate() override; + + private: + ButtonClickCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(HandleNotificationClickDelegate); +}; + +} // namespace message_center + +#endif // UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_DELEGATE_H_ diff --git a/chromium/ui/message_center/notification_delegate_unittest.cc b/chromium/ui/message_center/public/cpp/notification_delegate_unittest.cc index c45ee0ba9ff..09874d1ceeb 100644 --- a/chromium/ui/message_center/notification_delegate_unittest.cc +++ b/chromium/ui/message_center/public/cpp/notification_delegate_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/message_center/notification_delegate.h" +#include "ui/message_center/public/cpp/notification_delegate.h" #include "base/bind.h" #include "base/callback.h" diff --git a/chromium/ui/message_center/public/cpp/notification_types.h b/chromium/ui/message_center/public/cpp/notification_types.h new file mode 100644 index 00000000000..1ab3876b7e6 --- /dev/null +++ b/chromium/ui/message_center/public/cpp/notification_types.h @@ -0,0 +1,39 @@ +// 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_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_TYPES_H_ +#define UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_TYPES_H_ + +namespace message_center { + +// Notification types. Note that the values in this enumeration are being +// recoded in a histogram, updates should not change the entries' values. +enum NotificationType { + NOTIFICATION_TYPE_SIMPLE = 0, + NOTIFICATION_TYPE_BASE_FORMAT = 1, + NOTIFICATION_TYPE_IMAGE = 2, + NOTIFICATION_TYPE_MULTIPLE = 3, + NOTIFICATION_TYPE_PROGRESS = 4, // Notification with progress bar. + NOTIFICATION_TYPE_CUSTOM = 5, + + // Add new values before this line. + NOTIFICATION_TYPE_LAST = NOTIFICATION_TYPE_CUSTOM +}; + +enum NotificationPriority { + MIN_PRIORITY = -2, + LOW_PRIORITY = -1, + DEFAULT_PRIORITY = 0, + HIGH_PRIORITY = 1, + MAX_PRIORITY = 2, + + // Top priority for system-level notifications.. This can't be set from + // kPriorityKey, instead you have to call SetSystemPriority() of + // Notification object. + SYSTEM_PRIORITY = 3, +}; + +} // namespace message_center + +#endif // UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_TYPES_H_ diff --git a/chromium/ui/message_center/notifier_id.cc b/chromium/ui/message_center/public/cpp/notifier_id.cc index 6bf32a3352f..c25aaeb47b1 100644 --- a/chromium/ui/message_center/notifier_id.cc +++ b/chromium/ui/message_center/public/cpp/notifier_id.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/message_center/notifier_id.h" +#include "ui/message_center/public/cpp/notifier_id.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" diff --git a/chromium/ui/message_center/notifier_id.h b/chromium/ui/message_center/public/cpp/notifier_id.h index ac11acd0f48..720d3a74655 100644 --- a/chromium/ui/message_center/notifier_id.h +++ b/chromium/ui/message_center/public/cpp/notifier_id.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_MESSAGE_CENTER_NOTIFIER_ID_H_ -#define UI_MESSAGE_CENTER_NOTIFIER_ID_H_ +#ifndef UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFIER_ID_H_ +#define UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFIER_ID_H_ #include <stddef.h> @@ -13,15 +13,14 @@ #include "base/macros.h" #include "base/strings/string16.h" #include "ui/gfx/image/image.h" -#include "ui/message_center/message_center_export.h" +#include "ui/message_center/public/cpp/message_center_public_export.h" #include "url/gurl.h" namespace message_center { // A struct that identifies the source of notifications. For example, a web page // might send multiple notifications but they'd all have the same NotifierId. -// TODO(estade): move to public directory. -struct MESSAGE_CENTER_EXPORT NotifierId { +struct MESSAGE_CENTER_PUBLIC_EXPORT NotifierId { // This enum is being used for histogram reporting and the elements should not // be re-ordered. enum NotifierType : int { @@ -62,4 +61,4 @@ struct MESSAGE_CENTER_EXPORT NotifierId { } // namespace message_center -#endif // UI_MESSAGE_CENTER_NOTIFIER_ID_H_ +#endif // UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFIER_ID_H_ diff --git a/chromium/ui/message_center/mojo/BUILD.gn b/chromium/ui/message_center/public/mojo/BUILD.gn index b28d9663823..d6aaf8314fe 100644 --- a/chromium/ui/message_center/mojo/BUILD.gn +++ b/chromium/ui/message_center/public/mojo/BUILD.gn @@ -13,7 +13,7 @@ mojom("mojo") { public_deps = [ "//mojo/common:common_custom_types", "//ui/gfx/image/mojo:interfaces", - "//url/mojo:url_mojom_gurl", + "//url/mojom:url_mojom_gurl", ] } @@ -43,7 +43,7 @@ source_set("struct_traits") { "//mojo/public/cpp/bindings", "//ui/gfx", "//ui/gfx/image/mojo:struct_traits", - "//ui/message_center", - "//url/mojo:url_mojom_gurl", + "//ui/message_center/public/cpp", + "//url/mojom:url_mojom_gurl", ] } diff --git a/chromium/ui/message_center/mojo/DEPS b/chromium/ui/message_center/public/mojo/DEPS index 6cfa565faca..6cfa565faca 100644 --- a/chromium/ui/message_center/mojo/DEPS +++ b/chromium/ui/message_center/public/mojo/DEPS diff --git a/chromium/ui/message_center/mojo/OWNERS b/chromium/ui/message_center/public/mojo/OWNERS index fae57c3c2c5..fae57c3c2c5 100644 --- a/chromium/ui/message_center/mojo/OWNERS +++ b/chromium/ui/message_center/public/mojo/OWNERS diff --git a/chromium/ui/message_center/public/mojo/notification.mojom b/chromium/ui/message_center/public/mojo/notification.mojom new file mode 100644 index 00000000000..1b1b4ba3cd2 --- /dev/null +++ b/chromium/ui/message_center/public/mojo/notification.mojom @@ -0,0 +1,93 @@ +// 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. + +module message_center.mojom; + +import "mojo/common/time.mojom"; +import "mojo/public/mojom/base/string16.mojom"; +import "ui/gfx/image/mojo/image.mojom"; +import "ui/message_center/public/mojo/notifier_id.mojom"; +import "url/mojom/url.mojom"; + +// Matches message_center::NotificationType. +enum NotificationType { + SIMPLE = 0, + BASE_FORMAT = 1, + IMAGE = 2, + MULTIPLE = 3, + PROGRESS = 4, + CUSTOM = 5, +}; + +// Matches message_center::SettingsButtonHandler. +enum SettingsButtonHandler { + NONE = 0, + INLINE = 1, + DELEGATE = 2, +}; + +// Matches message_center::FullscreenVisibility. +enum FullscreenVisibility { + NONE= 0, + OVER_USER = 1, +}; + +// The fields and their meanings match message_center::NotificationItem. +struct NotificationItem { + mojo_base.mojom.String16 title; + mojo_base.mojom.String16 message; +}; + +// The fields and their meanings match message_center::ButtonInfo. +struct ButtonInfo { + mojo_base.mojom.String16 title; + gfx.mojom.ImageSkia? icon; + mojo_base.mojom.String16? placeholder; +}; + +// These fields and their meanings are identical to those in +// message_center::RichNotificationData. +struct RichNotificationData { + int32 priority; + bool never_time_out; + mojo.common.mojom.Time timestamp; + // |context_message| intentionally omitted. See https://crbug.com/797084 + gfx.mojom.ImageSkia? image; + gfx.mojom.ImageSkia? small_image; + array<NotificationItem> items; + int32 progress; + mojo_base.mojom.String16 progress_status; + array<ButtonInfo> buttons; + bool should_make_spoken_feedback_for_popup_updates; + bool clickable; + bool pinned; + // |vibration_pattern| intentionally omitted + // |renotify| intentionally omitted + // |silent| intentionally omitted + mojo_base.mojom.String16 accessible_name; + string vector_small_image_id; + uint32 accent_color; + SettingsButtonHandler settings_button_handler; + FullscreenVisibility fullscreen_visibility; +}; + +struct Notification { + NotificationType type; + + // TODO(mhashmi): Server-side code (in Ash) needs to make sure this id won't + // collide with ids from different clients + string id; + + mojo_base.mojom.String16 title; + mojo_base.mojom.String16 message; + gfx.mojom.ImageSkia? icon; + mojo_base.mojom.String16 display_source; + url.mojom.Url origin_url; + NotifierId notifier_id; + RichNotificationData optional_fields; + // |serial_number_| intentionally omitted. + // |shown_as_popup_| intentionally omitted. + // |is_read_| intentionally omitted. + // |delegate_| intentionally omitted. +}; diff --git a/chromium/ui/message_center/mojo/notification.typemap b/chromium/ui/message_center/public/mojo/notification.typemap index 1e613e5e66d..c56dfa79be4 100644 --- a/chromium/ui/message_center/mojo/notification.typemap +++ b/chromium/ui/message_center/public/mojo/notification.typemap @@ -2,14 +2,17 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -mojom = "//ui/message_center/mojo/notification.mojom" -public_headers = [ "//ui/message_center/notification.h" ] -traits_headers = [ "//ui/message_center/mojo/notification_struct_traits.h" ] +mojom = "//ui/message_center/public/mojo/notification.mojom" +public_headers = [ "//ui/message_center/public/cpp/notification.h" ] +traits_headers = + [ "//ui/message_center/public/mojo/notification_struct_traits.h" ] deps = [ "//ui/gfx/image/mojo:struct_traits", - "//ui/message_center/mojo:struct_traits", + "//ui/message_center/public/mojo:struct_traits", ] type_mappings = [ + "message_center.mojom.NotificationItem=message_center::NotificationItem", + "message_center.mojom.ButtonInfo=message_center::ButtonInfo", "message_center.mojom.RichNotificationData=message_center::RichNotificationData", "message_center.mojom.NotificationType=message_center::NotificationType", "message_center.mojom.Notification=message_center::Notification", diff --git a/chromium/ui/message_center/public/mojo/notification_struct_traits.cc b/chromium/ui/message_center/public/mojo/notification_struct_traits.cc new file mode 100644 index 00000000000..35b84fdf5e0 --- /dev/null +++ b/chromium/ui/message_center/public/mojo/notification_struct_traits.cc @@ -0,0 +1,268 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/message_center/public/mojo/notification_struct_traits.h" + +#include "mojo/common/time_struct_traits.h" +#include "mojo/public/cpp/base/string16_mojom_traits.h" +#include "ui/gfx/image/mojo/image_skia_struct_traits.h" +#include "ui/message_center/public/mojo/notifier_id_struct_traits.h" +#include "url/mojom/url_gurl_mojom_traits.h" + +namespace mojo { + +using message_center::mojom::NotificationDataView; +using message_center::mojom::RichNotificationDataDataView; +using message_center::NotificationItem; +using message_center::ButtonInfo; +using message_center::Notification; +using message_center::RichNotificationData; +using NotificationItemStructTraits = + StructTraits<message_center::mojom::NotificationItemDataView, + NotificationItem>; +using ButtonInfoStructTraits = + StructTraits<message_center::mojom::ButtonInfoDataView, ButtonInfo>; +using RichNotificationDataStructTraits = + StructTraits<RichNotificationDataDataView, RichNotificationData>; +using NotificationStructTraits = + StructTraits<NotificationDataView, Notification>; + +// static +bool NotificationItemStructTraits::Read( + message_center::mojom::NotificationItemDataView data, + message_center::NotificationItem* out) { + return data.ReadTitle(&out->title) && data.ReadMessage(&out->message); +} + +// static +gfx::ImageSkia ButtonInfoStructTraits::icon( + const message_center::ButtonInfo& b) { + return b.icon.AsImageSkia(); +} + +// static +bool ButtonInfoStructTraits::Read( + message_center::mojom::ButtonInfoDataView data, + ButtonInfo* out) { + gfx::ImageSkia icon; + if (!data.ReadIcon(&icon)) + return false; + out->icon = gfx::Image(icon); + return data.ReadTitle(&out->title) && data.ReadPlaceholder(&out->placeholder); +} + +// static +int RichNotificationDataStructTraits::priority(const RichNotificationData& r) { + return r.priority; +} + +// static +bool RichNotificationDataStructTraits::never_time_out( + const RichNotificationData& r) { + return r.never_timeout; +} + +// static +const base::Time& RichNotificationDataStructTraits::timestamp( + const RichNotificationData& r) { + return r.timestamp; +} + +// static +gfx::ImageSkia RichNotificationDataStructTraits::image( + const RichNotificationData& r) { + return r.image.AsImageSkia(); +} + +// static +gfx::ImageSkia RichNotificationDataStructTraits::small_image( + const RichNotificationData& r) { + return r.small_image.AsImageSkia(); +} + +// static +const std::vector<NotificationItem>& RichNotificationDataStructTraits::items( + const RichNotificationData& r) { + return r.items; +} + +// static +int RichNotificationDataStructTraits::progress(const RichNotificationData& r) { + return r.progress; +} + +// static +const base::string16& RichNotificationDataStructTraits::progress_status( + const RichNotificationData& r) { + return r.progress_status; +} + +// static +const std::vector<ButtonInfo>& RichNotificationDataStructTraits::buttons( + const RichNotificationData& r) { + return r.buttons; +} + +// static +bool RichNotificationDataStructTraits:: + should_make_spoken_feedback_for_popup_updates( + const RichNotificationData& r) { + return r.should_make_spoken_feedback_for_popup_updates; +} + +// static +bool RichNotificationDataStructTraits::clickable( + const RichNotificationData& r) { + return r.clickable; +} + +// static +bool RichNotificationDataStructTraits::pinned(const RichNotificationData& r) { + return r.pinned; +} + +// static +const base::string16& RichNotificationDataStructTraits::accessible_name( + const RichNotificationData& r) { + return r.accessible_name; +} + +// static +std::string RichNotificationDataStructTraits::vector_small_image_id( + const message_center::RichNotificationData& r) { + if (r.vector_small_image && r.vector_small_image->name) + return r.vector_small_image->name; + return std::string(); +} + +// static +SkColor RichNotificationDataStructTraits::accent_color( + const RichNotificationData& r) { + return r.accent_color; +} + +// static +message_center::SettingsButtonHandler +RichNotificationDataStructTraits::settings_button_handler( + const RichNotificationData& r) { + return r.settings_button_handler; +} + +// static +message_center::FullscreenVisibility +RichNotificationDataStructTraits::fullscreen_visibility( + const RichNotificationData& r) { + return r.fullscreen_visibility; +} + +// static +bool RichNotificationDataStructTraits::Read(RichNotificationDataDataView data, + RichNotificationData* out) { + out->priority = data.priority(); + out->never_timeout = data.never_time_out(); + gfx::ImageSkia image, small_image; + if (!data.ReadImage(&image)) + return false; + out->image = gfx::Image(image); + if (!data.ReadSmallImage(&small_image)) + return false; + out->small_image = gfx::Image(small_image); + out->progress = data.progress(); + out->should_make_spoken_feedback_for_popup_updates = + data.should_make_spoken_feedback_for_popup_updates(); + out->clickable = data.clickable(); + out->pinned = data.pinned(); + + // Look up the vector icon by ID. This will only work if RegisterVectorIcon + // has been called with an appropriate icon. + std::string icon_id; + if (data.ReadVectorSmallImageId(&icon_id) && !icon_id.empty()) { + out->vector_small_image = message_center::GetRegisteredVectorIcon(icon_id); + if (!out->vector_small_image) + LOG(ERROR) << "Couldn't find icon: " + icon_id; + } + + out->accent_color = data.accent_color(); + return data.ReadTimestamp(&out->timestamp) && data.ReadItems(&out->items) && + data.ReadButtons(&out->buttons) && + data.ReadProgressStatus(&out->progress_status) && + data.ReadAccessibleName(&out->accessible_name) && + EnumTraits<message_center::mojom::SettingsButtonHandler, + message_center::SettingsButtonHandler>:: + FromMojom(data.settings_button_handler(), + &out->settings_button_handler) && + EnumTraits<message_center::mojom::FullscreenVisibility, + message_center::FullscreenVisibility>:: + FromMojom(data.fullscreen_visibility(), + &out->fullscreen_visibility); +} + +// static +message_center::NotificationType NotificationStructTraits::type( + const Notification& n) { + return n.type(); +} + +// static +const std::string& NotificationStructTraits::id(const Notification& n) { + return n.id(); +} + +// static +const base::string16& NotificationStructTraits::title(const Notification& n) { + return n.title(); +} + +// static +const base::string16& NotificationStructTraits::message(const Notification& n) { + return n.message(); +} + +// static +gfx::ImageSkia NotificationStructTraits::icon(const Notification& n) { + return n.icon().AsImageSkia(); +} + +// static +const base::string16& NotificationStructTraits::display_source( + const Notification& n) { + return n.display_source(); +} + +// static +const GURL& NotificationStructTraits::origin_url(const Notification& n) { + return n.origin_url(); +} + +// static +const message_center::NotifierId& NotificationStructTraits::notifier_id( + const Notification& n) { + return n.notifier_id(); +} + +// static +const RichNotificationData& NotificationStructTraits::optional_fields( + const Notification& n) { + return n.rich_notification_data(); +} + +// static +bool NotificationStructTraits::Read(NotificationDataView data, + Notification* out) { + gfx::ImageSkia icon; + if (!data.ReadIcon(&icon)) + return false; + out->set_icon(gfx::Image(icon)); + return EnumTraits<message_center::mojom::NotificationType, + message_center::NotificationType>::FromMojom(data.type(), + &out->type_) && + data.ReadId(&out->id_) && data.ReadTitle(&out->title_) && + data.ReadMessage(&out->message_) && + data.ReadDisplaySource(&out->display_source_) && + data.ReadOriginUrl(&out->origin_url_) && + data.ReadNotifierId(&out->notifier_id_) && + data.ReadOptionalFields(&out->optional_fields_); +} + +} // namespace mojo diff --git a/chromium/ui/message_center/public/mojo/notification_struct_traits.h b/chromium/ui/message_center/public/mojo/notification_struct_traits.h new file mode 100644 index 00000000000..e97e4a6c504 --- /dev/null +++ b/chromium/ui/message_center/public/mojo/notification_struct_traits.h @@ -0,0 +1,215 @@ +// 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 UI_MESSAGE_CENTER_PUBLIC_MOJO_NOTIFICATION_STRUCT_TRAITS_H_ +#define UI_MESSAGE_CENTER_PUBLIC_MOJO_NOTIFICATION_STRUCT_TRAITS_H_ + +#include "third_party/skia/include/core/SkColor.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/mojo/notification.mojom-shared.h" + +namespace mojo { + +template <> +struct EnumTraits<message_center::mojom::NotificationType, + message_center::NotificationType> { + static message_center::mojom::NotificationType ToMojom( + message_center::NotificationType type) { + switch (type) { + case message_center::NOTIFICATION_TYPE_SIMPLE: + return message_center::mojom::NotificationType::SIMPLE; + case message_center::NOTIFICATION_TYPE_BASE_FORMAT: + return message_center::mojom::NotificationType::BASE_FORMAT; + case message_center::NOTIFICATION_TYPE_IMAGE: + return message_center::mojom::NotificationType::IMAGE; + case message_center::NOTIFICATION_TYPE_MULTIPLE: + return message_center::mojom::NotificationType::MULTIPLE; + case message_center::NOTIFICATION_TYPE_PROGRESS: + return message_center::mojom::NotificationType::PROGRESS; + case message_center::NOTIFICATION_TYPE_CUSTOM: + return message_center::mojom::NotificationType::CUSTOM; + } + NOTREACHED(); + return message_center::mojom::NotificationType::SIMPLE; + } + + static bool FromMojom(message_center::mojom::NotificationType input, + message_center::NotificationType* out) { + switch (input) { + case message_center::mojom::NotificationType::SIMPLE: + *out = message_center::NOTIFICATION_TYPE_SIMPLE; + return true; + case message_center::mojom::NotificationType::BASE_FORMAT: + *out = message_center::NOTIFICATION_TYPE_BASE_FORMAT; + return true; + case message_center::mojom::NotificationType::IMAGE: + *out = message_center::NOTIFICATION_TYPE_IMAGE; + return true; + case message_center::mojom::NotificationType::MULTIPLE: + *out = message_center::NOTIFICATION_TYPE_MULTIPLE; + return true; + case message_center::mojom::NotificationType::PROGRESS: + *out = message_center::NOTIFICATION_TYPE_PROGRESS; + return true; + case message_center::mojom::NotificationType::CUSTOM: + *out = message_center::NOTIFICATION_TYPE_CUSTOM; + return true; + } + NOTREACHED(); + return false; + } +}; + +template <> +struct EnumTraits<message_center::mojom::SettingsButtonHandler, + message_center::SettingsButtonHandler> { + static message_center::mojom::SettingsButtonHandler ToMojom( + message_center::SettingsButtonHandler type) { + switch (type) { + case message_center::SettingsButtonHandler::NONE: + return message_center::mojom::SettingsButtonHandler::NONE; + case message_center::SettingsButtonHandler::INLINE: + return message_center::mojom::SettingsButtonHandler::INLINE; + case message_center::SettingsButtonHandler::DELEGATE: + return message_center::mojom::SettingsButtonHandler::DELEGATE; + } + NOTREACHED(); + return message_center::mojom::SettingsButtonHandler::NONE; + } + + static bool FromMojom(message_center::mojom::SettingsButtonHandler input, + message_center::SettingsButtonHandler* out) { + switch (input) { + case message_center::mojom::SettingsButtonHandler::NONE: + *out = message_center::SettingsButtonHandler::NONE; + return true; + case message_center::mojom::SettingsButtonHandler::INLINE: + *out = message_center::SettingsButtonHandler::INLINE; + return true; + case message_center::mojom::SettingsButtonHandler::DELEGATE: + *out = message_center::SettingsButtonHandler::DELEGATE; + return true; + } + NOTREACHED(); + return false; + } +}; + +template <> +struct EnumTraits<message_center::mojom::FullscreenVisibility, + message_center::FullscreenVisibility> { + static message_center::mojom::FullscreenVisibility ToMojom( + message_center::FullscreenVisibility type) { + switch (type) { + case message_center::FullscreenVisibility::NONE: + return message_center::mojom::FullscreenVisibility::NONE; + case message_center::FullscreenVisibility::OVER_USER: + return message_center::mojom::FullscreenVisibility::OVER_USER; + } + NOTREACHED(); + return message_center::mojom::FullscreenVisibility::NONE; + } + + static bool FromMojom(message_center::mojom::FullscreenVisibility input, + message_center::FullscreenVisibility* out) { + switch (input) { + case message_center::mojom::FullscreenVisibility::NONE: + *out = message_center::FullscreenVisibility::NONE; + return true; + case message_center::mojom::FullscreenVisibility::OVER_USER: + *out = message_center::FullscreenVisibility::OVER_USER; + return true; + } + NOTREACHED(); + return false; + } +}; + +template <> +struct StructTraits<message_center::mojom::NotificationItemDataView, + message_center::NotificationItem> { + static const base::string16& title( + const message_center::NotificationItem& n) { + return n.title; + } + static const base::string16& message( + const message_center::NotificationItem& n) { + return n.message; + } + static bool Read(message_center::mojom::NotificationItemDataView data, + message_center::NotificationItem* out); +}; + +template <> +struct StructTraits<message_center::mojom::ButtonInfoDataView, + message_center::ButtonInfo> { + static const base::string16& title(const message_center::ButtonInfo& b) { + return b.title; + } + static gfx::ImageSkia icon(const message_center::ButtonInfo& b); + static const base::Optional<base::string16>& placeholder( + const message_center::ButtonInfo& b) { + return b.placeholder; + } + static bool Read(message_center::mojom::ButtonInfoDataView data, + message_center::ButtonInfo* out); +}; + +template <> +struct StructTraits<message_center::mojom::RichNotificationDataDataView, + message_center::RichNotificationData> { + static int priority(const message_center::RichNotificationData& r); + static bool never_time_out(const message_center::RichNotificationData& r); + static const base::Time& timestamp( + const message_center::RichNotificationData& r); + static gfx::ImageSkia image(const message_center::RichNotificationData& r); + static gfx::ImageSkia small_image( + const message_center::RichNotificationData& r); + static const std::vector<message_center::NotificationItem>& items( + const message_center::RichNotificationData& r); + static int progress(const message_center::RichNotificationData& r); + static const base::string16& progress_status( + const message_center::RichNotificationData& r); + static const std::vector<message_center::ButtonInfo>& buttons( + const message_center::RichNotificationData& r); + static bool should_make_spoken_feedback_for_popup_updates( + const message_center::RichNotificationData& r); + static bool clickable(const message_center::RichNotificationData& r); + static bool pinned(const message_center::RichNotificationData& r); + static const base::string16& accessible_name( + const message_center::RichNotificationData& r); + static std::string vector_small_image_id( + const message_center::RichNotificationData& r); + static SkColor accent_color(const message_center::RichNotificationData& r); + static message_center::SettingsButtonHandler settings_button_handler( + const message_center::RichNotificationData& r); + static message_center::FullscreenVisibility fullscreen_visibility( + const message_center::RichNotificationData& r); + static bool Read(message_center::mojom::RichNotificationDataDataView data, + message_center::RichNotificationData* out); +}; + +template <> +struct StructTraits<message_center::mojom::NotificationDataView, + message_center::Notification> { + static message_center::NotificationType type( + const message_center::Notification& n); + static const std::string& id(const message_center::Notification& n); + static const base::string16& title(const message_center::Notification& n); + static const base::string16& message(const message_center::Notification& n); + static gfx::ImageSkia icon(const message_center::Notification& n); + static const base::string16& display_source( + const message_center::Notification& n); + static const GURL& origin_url(const message_center::Notification& n); + static const message_center::NotifierId& notifier_id( + const message_center::Notification& n); + static const message_center::RichNotificationData& optional_fields( + const message_center::Notification& n); + static bool Read(message_center::mojom::NotificationDataView data, + message_center::Notification* out); +}; + +} // namespace mojo + +#endif // UI_MESSAGE_CENTER_PUBLIC_MOJO_NOTIFICATION_STRUCT_TRAITS_H_ diff --git a/chromium/ui/message_center/mojo/notifier_id.mojom b/chromium/ui/message_center/public/mojo/notifier_id.mojom index cf7a9a6167f..0227ad3f250 100644 --- a/chromium/ui/message_center/mojo/notifier_id.mojom +++ b/chromium/ui/message_center/public/mojo/notifier_id.mojom @@ -4,16 +4,16 @@ module message_center.mojom; -import "mojo/common/string16.mojom"; -import "url/mojo/url.mojom"; +import "mojo/public/mojom/base/string16.mojom"; +import "url/mojom/url.mojom"; // Equivalent to message_center::NotifierId::NotifierType. Used in UMA, so it // should not be reordered. enum NotifierType { - APPLICATION, - ARC_APPLICATION, - WEB_PAGE, - SYSTEM_COMPONENT, + APPLICATION = 0, + ARC_APPLICATION = 1, + WEB_PAGE = 2, + SYSTEM_COMPONENT = 3, SIZE, }; diff --git a/chromium/ui/message_center/mojo/notifier_id.typemap b/chromium/ui/message_center/public/mojo/notifier_id.typemap index 00a923cd955..743319ce232 100644 --- a/chromium/ui/message_center/mojo/notifier_id.typemap +++ b/chromium/ui/message_center/public/mojo/notifier_id.typemap @@ -2,11 +2,12 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -mojom = "//ui/message_center/mojo/notifier_id.mojom" -public_headers = [ "//ui/message_center/notifier_id.h" ] -traits_headers = [ "//ui/message_center/mojo/notifier_id_struct_traits.h" ] +mojom = "//ui/message_center/public/mojo/notifier_id.mojom" +public_headers = [ "//ui/message_center/public/cpp/notifier_id.h" ] +traits_headers = + [ "//ui/message_center/public/mojo/notifier_id_struct_traits.h" ] deps = [ - "//ui/message_center/mojo:struct_traits", + "//ui/message_center/public/mojo:struct_traits", ] type_mappings = [ "message_center.mojom.NotifierId=message_center::NotifierId", diff --git a/chromium/ui/message_center/mojo/notifier_id_struct_traits.cc b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc index 424df76756c..d2b9f6b3e64 100644 --- a/chromium/ui/message_center/mojo/notifier_id_struct_traits.cc +++ b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/message_center/mojo/notifier_id_struct_traits.h" +#include "ui/message_center/public/mojo/notifier_id_struct_traits.h" #include "mojo/common/common_custom_types_struct_traits.h" -#include "url/mojo/url_gurl_struct_traits.h" +#include "url/mojom/url_gurl_mojom_traits.h" namespace mojo { diff --git a/chromium/ui/message_center/mojo/notifier_id_struct_traits.h b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.h index bf55f0c266c..fefc0d91f17 100644 --- a/chromium/ui/message_center/mojo/notifier_id_struct_traits.h +++ b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.h @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_MESSAGE_CENTER_NOTIFIER_ID_STRUCT_TRAITS_H_ -#define UI_MESSAGE_CENTER_NOTIFIER_ID_STRUCT_TRAITS_H_ +#ifndef UI_MESSAGE_CENTER_PUBLIC_MOJO_NOTIFIER_ID_STRUCT_TRAITS_H_ +#define UI_MESSAGE_CENTER_PUBLIC_MOJO_NOTIFIER_ID_STRUCT_TRAITS_H_ -#include "ui/message_center/mojo/notifier_id.mojom-shared.h" -#include "ui/message_center/notifier_id.h" +#include "ui/message_center/public/cpp/notifier_id.h" +#include "ui/message_center/public/mojo/notifier_id.mojom-shared.h" namespace mojo { @@ -68,4 +68,4 @@ struct StructTraits<message_center::mojom::NotifierIdDataView, } // namespace mojo -#endif // UI_MESSAGE_CENTER_NOTIFIER_ID_STRUCT_TRAITS_H_ +#endif // UI_MESSAGE_CENTER_PUBLIC_MOJO_NOTIFIER_ID_STRUCT_TRAITS_H_ diff --git a/chromium/ui/message_center/mojo/struct_traits_unittest.cc b/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc index 5ddbea3e1e3..59f0263524b 100644 --- a/chromium/ui/message_center/mojo/struct_traits_unittest.cc +++ b/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc @@ -7,11 +7,12 @@ #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "mojo/public/cpp/bindings/binding_set.h" +#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/image/image_unittest_util.h" -#include "ui/message_center/mojo/traits_test_service.mojom.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notifier_id.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notifier_id.h" +#include "ui/message_center/public/mojo/traits_test_service.mojom.h" namespace message_center { namespace { @@ -36,6 +37,12 @@ class StructTraitsTest : public testing::Test, public mojom::TraitsTestService { EXPECT_EQ(input.icon().Height(), output.icon().Height()); EXPECT_EQ(input.display_source(), output.display_source()); EXPECT_EQ(input.origin_url(), output.origin_url()); + EXPECT_EQ(input.notifier_id(), output.notifier_id()); + EXPECT_EQ(input.priority(), output.priority()); + EXPECT_TRUE(gfx::test::AreImagesEqual(input.image(), output.image())); + EXPECT_TRUE( + gfx::test::AreImagesEqual(input.small_image(), output.small_image())); + EXPECT_EQ(input.timestamp(), output.timestamp()); EXPECT_EQ(input.progress(), output.progress()); EXPECT_EQ(input.progress_status(), output.progress_status()); EXPECT_EQ(input.rich_notification_data() @@ -45,6 +52,9 @@ class StructTraitsTest : public testing::Test, public mojom::TraitsTestService { EXPECT_EQ(input.clickable(), output.clickable()); EXPECT_EQ(input.accessible_name(), output.accessible_name()); EXPECT_EQ(input.accent_color(), output.accent_color()); + EXPECT_EQ(input.should_show_settings_button(), + output.should_show_settings_button()); + EXPECT_EQ(input.fullscreen_visibility(), output.fullscreen_visibility()); } private: @@ -71,8 +81,11 @@ TEST_F(StructTraitsTest, Notification) { base::string16 display_source(base::ASCIIToUTF16("display_source")); GURL origin_url("www.example.com"); NotifierId notifier_id(NotifierId::NotifierType::APPLICATION, id); + notifier_id.profile_id = "profile_id"; + RichNotificationData optional_fields; + optional_fields.settings_button_handler = SettingsButtonHandler::INLINE; Notification input(type, id, title, message, icon, display_source, origin_url, - notifier_id, RichNotificationData(), nullptr); + notifier_id, optional_fields, nullptr); mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy(); Notification output; @@ -80,11 +93,15 @@ TEST_F(StructTraitsTest, Notification) { Compare(input, output); // Set some optional fields to non-default values and test again. + input.set_never_timeout(true); input.set_type(NotificationType::NOTIFICATION_TYPE_PROGRESS); input.set_progress(50); input.set_progress_status(base::ASCIIToUTF16("progress text")); input.set_clickable(!input.clickable()); + input.set_image(gfx::test::CreateImage(48, 48)); + input.set_small_image(gfx::test::CreateImage(16, 16)); input.set_accent_color(SK_ColorMAGENTA); + input.set_fullscreen_visibility(FullscreenVisibility::OVER_USER); proxy->EchoNotification(input, &output); Compare(input, output); } diff --git a/chromium/ui/message_center/mojo/traits_test_service.mojom b/chromium/ui/message_center/public/mojo/traits_test_service.mojom index e5c96fe3eeb..bb1ed449928 100644 --- a/chromium/ui/message_center/mojo/traits_test_service.mojom +++ b/chromium/ui/message_center/public/mojo/traits_test_service.mojom @@ -4,7 +4,7 @@ module message_center.mojom; -import "ui/message_center/mojo/notification.mojom"; +import "ui/message_center/public/mojo/notification.mojom"; // All functions on this interface echo their arguments to test StructTraits // serialization and deserialization. diff --git a/chromium/ui/message_center/mojo/typemaps.gni b/chromium/ui/message_center/public/mojo/typemaps.gni index a7f5b3d481c..a215ae335f0 100644 --- a/chromium/ui/message_center/mojo/typemaps.gni +++ b/chromium/ui/message_center/public/mojo/typemaps.gni @@ -3,6 +3,6 @@ # found in the LICENSE file. typemaps = [ - "//ui/message_center/mojo/notification.typemap", - "//ui/message_center/mojo/notifier_id.typemap", + "//ui/message_center/public/mojo/notification.typemap", + "//ui/message_center/public/mojo/notifier_id.typemap", ] diff --git a/chromium/ui/message_center/ui_controller.cc b/chromium/ui/message_center/ui_controller.cc index 3fd67d1474d..997b24750f9 100644 --- a/chromium/ui/message_center/ui_controller.cc +++ b/chromium/ui/message_center/ui_controller.cc @@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/observer_list.h" #include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/simple_menu_model.h" @@ -42,20 +41,16 @@ bool UiController::ShowMessageCenterBubble(bool show_by_click) { message_center_visible_ = delegate_->ShowMessageCenter(show_by_click); if (message_center_visible_) { - message_center_->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER); + message_center_->SetVisibility(VISIBILITY_MESSAGE_CENTER); NotifyUiControllerChanged(); } return message_center_visible_; } bool UiController::HideMessageCenterBubble() { -#if defined(OS_CHROMEOS) - // TODO(yoshiki): Move the message center bubble related logic to ash/. - hide_empty_message_center_callback_.reset(); -#endif - if (!message_center_visible_) return false; + delegate_->HideMessageCenter(); MarkMessageCenterHidden(); @@ -66,7 +61,7 @@ void UiController::MarkMessageCenterHidden() { if (!message_center_visible_) return; message_center_visible_ = false; - message_center_->SetVisibility(message_center::VISIBILITY_TRANSIENT); + message_center_->SetVisibility(VISIBILITY_TRANSIENT); // Some notifications (like system ones) should appear as popups again // after the message center is closed. @@ -117,7 +112,7 @@ void UiController::ShowNotifierSettingsBubble() { HidePopupBubbleInternal(); message_center_visible_ = delegate_->ShowNotifierSettings(); - message_center_->SetVisibility(message_center::VISIBILITY_SETTINGS); + message_center_->SetVisibility(VISIBILITY_SETTINGS); NotifyUiControllerChanged(); } @@ -166,26 +161,11 @@ void UiController::OnBlockingStateChanged(NotificationBlocker* blocker) { } void UiController::OnMessageCenterChanged() { -#if defined(OS_CHROMEOS) - // TODO(yoshiki): Move the message center bubble related logic to ash/. if (message_center_visible_ && message_center_->NotificationCount() == 0) { - if (hide_empty_message_center_callback_) - return; - - hide_empty_message_center_callback_ = - std::make_unique<base::CancelableClosure>(base::Bind( - base::IgnoreResult(&UiController::HideMessageCenterBubble), - base::Unretained(this))); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, hide_empty_message_center_callback_->callback()); + HideMessageCenterBubble(); return; } - // Cancel the callback if necessary. - if (hide_empty_message_center_callback_) - hide_empty_message_center_callback_.reset(); -#endif - if (popups_visible_ && !message_center_->HasPopupNotifications()) HidePopupBubbleInternal(); else if (!popups_visible_ && message_center_->HasPopupNotifications()) diff --git a/chromium/ui/message_center/ui_controller.h b/chromium/ui/message_center/ui_controller.h index bbe26caa972..582ad520d4e 100644 --- a/chromium/ui/message_center/ui_controller.h +++ b/chromium/ui/message_center/ui_controller.h @@ -5,13 +5,12 @@ #ifndef UI_MESSAGE_CENTER_UI_CONTROLLER_H_ #define UI_MESSAGE_CENTER_UI_CONTROLLER_H_ -#include "base/cancelable_callback.h" #include "base/macros.h" #include "base/observer_list.h" #include "base/strings/string16.h" #include "ui/message_center/message_center_export.h" #include "ui/message_center/message_center_observer.h" -#include "ui/message_center/notifier_id.h" +#include "ui/message_center/public/cpp/notifier_id.h" #include "ui/message_center/ui_delegate.h" namespace message_center { @@ -53,10 +52,8 @@ class MESSAGE_CENTER_EXPORT UiController : public MessageCenterObserver { bool message_center_visible() { return message_center_visible_; } bool popups_visible() { return popups_visible_; } UiDelegate* delegate() { return delegate_; } - const message_center::MessageCenter* message_center() const { - return message_center_; - } - message_center::MessageCenter* message_center() { return message_center_; } + const MessageCenter* message_center() const { return message_center_; } + MessageCenter* message_center() { return message_center_; } // Overridden from MessageCenterObserver: void OnNotificationAdded(const std::string& notification_id) override; @@ -77,15 +74,11 @@ class MESSAGE_CENTER_EXPORT UiController : public MessageCenterObserver { void NotifyUiControllerChanged(); void HidePopupBubbleInternal(); - message_center::MessageCenter* message_center_; + MessageCenter* message_center_; bool message_center_visible_ = false; bool popups_visible_ = false; UiDelegate* delegate_; -#if defined(OS_CHROMEOS) - std::unique_ptr<base::CancelableClosure> hide_empty_message_center_callback_; -#endif - DISALLOW_COPY_AND_ASSIGN(UiController); }; diff --git a/chromium/ui/message_center/ui_controller_unittest.cc b/chromium/ui/message_center/ui_controller_unittest.cc index 75795f7277e..a7163fe6d46 100644 --- a/chromium/ui/message_center/ui_controller_unittest.cc +++ b/chromium/ui/message_center/ui_controller_unittest.cc @@ -11,15 +11,15 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/models/menu_model.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_types.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" using base::ASCIIToUTF16; namespace message_center { namespace { -class TestNotificationDelegate : public message_center::NotificationDelegate { +class TestNotificationDelegate : public NotificationDelegate { public: TestNotificationDelegate() = default; @@ -78,13 +78,11 @@ class UiControllerTest : public testing::Test { } Notification* AddNotification(const std::string& id, NotifierId notifier_id) { - std::unique_ptr<Notification> notification( - new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, id, - ASCIIToUTF16("Test Web Notification"), - ASCIIToUTF16("Notification message body."), - gfx::Image(), ASCIIToUTF16("www.test.org"), GURL(), - notifier_id, message_center::RichNotificationData(), - new TestNotificationDelegate())); + std::unique_ptr<Notification> notification(new Notification( + NOTIFICATION_TYPE_SIMPLE, id, ASCIIToUTF16("Test Web Notification"), + ASCIIToUTF16("Notification message body."), gfx::Image(), + ASCIIToUTF16("www.test.org"), GURL(), notifier_id, + RichNotificationData(), new TestNotificationDelegate())); Notification* notification_ptr = notification.get(); message_center_->AddNotification(std::move(notification)); return notification_ptr; @@ -185,12 +183,11 @@ TEST_F(UiControllerTest, MessageCenterReopenPopupsForSystemPriority) { ASSERT_FALSE(ui_controller_->message_center_visible()); std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, - "MessageCenterReopnPopupsForSystemPriority", + NOTIFICATION_TYPE_SIMPLE, "MessageCenterReopnPopupsForSystemPriority", ASCIIToUTF16("Test Web Notification"), ASCIIToUTF16("Notification message body."), gfx::Image(), ASCIIToUTF16("www.test.org"), GURL(), DummyNotifierId(), - message_center::RichNotificationData(), NULL /* delegate */)); + RichNotificationData(), NULL /* delegate */)); notification->SetSystemPriority(); message_center_->AddNotification(std::move(notification)); diff --git a/chromium/ui/message_center/vector_icons/OWNERS b/chromium/ui/message_center/vector_icons/OWNERS new file mode 100644 index 00000000000..d7ec991d34a --- /dev/null +++ b/chromium/ui/message_center/vector_icons/OWNERS @@ -0,0 +1 @@ +file://components/vector_icons/OWNERS diff --git a/chromium/ui/message_center/vector_icons/notification_inline_reply.icon b/chromium/ui/message_center/vector_icons/notification_inline_reply.icon new file mode 100644 index 00000000000..e12869934bf --- /dev/null +++ b/chromium/ui/message_center/vector_icons/notification_inline_reply.icon @@ -0,0 +1,13 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 96, +MOVE_TO, 10.04f, 82, +LINE_TO, 86, 48, +LINE_TO, 10.04f, 14, +LINE_TO, 10, 40.44f, +LINE_TO, 64.29f, 48, +LINE_TO, 10, 55.56f, +CLOSE, +END
\ No newline at end of file diff --git a/chromium/ui/message_center/vector_icons/vector_icons.cc.template b/chromium/ui/message_center/vector_icons/vector_icons.cc.template index 7a94527074b..7473cb40556 100644 --- a/chromium/ui/message_center/vector_icons/vector_icons.cc.template +++ b/chromium/ui/message_center/vector_icons/vector_icons.cc.template @@ -10,11 +10,7 @@ #include "base/logging.h" #include "ui/gfx/vector_icon_types.h" -#define PATH_ELEMENT_TEMPLATE(path_name, ...) \ -static constexpr gfx::PathElement path_name[] = {__VA_ARGS__}; - -#define VECTOR_ICON_TEMPLATE(icon_name, path_name, path_name_1x) \ -const gfx::VectorIcon icon_name = { path_name , path_name_1x }; +#include "components/vector_icons/cc_macros.h" namespace message_center { diff --git a/chromium/ui/message_center/views/bounded_label.cc b/chromium/ui/message_center/views/bounded_label.cc index 334cc34f830..01ad8a33463 100644 --- a/chromium/ui/message_center/views/bounded_label.cc +++ b/chromium/ui/message_center/views/bounded_label.cc @@ -278,9 +278,9 @@ BoundedLabel::BoundedLabel(const base::string16& text) BoundedLabel::~BoundedLabel() { } -void BoundedLabel::SetColors(SkColor textColor, SkColor backgroundColor) { - label_->SetEnabledColor(textColor); - label_->SetBackgroundColor(backgroundColor); +void BoundedLabel::SetColor(SkColor text_color) { + label_->SetEnabledColor(text_color); + label_->SetAutoColorReadabilityEnabled(false); } void BoundedLabel::SetLineHeight(int height) { diff --git a/chromium/ui/message_center/views/bounded_label.h b/chromium/ui/message_center/views/bounded_label.h index 1ae1a16f581..ff7aa7a4228 100644 --- a/chromium/ui/message_center/views/bounded_label.h +++ b/chromium/ui/message_center/views/bounded_label.h @@ -38,7 +38,7 @@ class MESSAGE_CENTER_EXPORT BoundedLabel : public views::View { BoundedLabel(const base::string16& text); ~BoundedLabel() override; - void SetColors(SkColor textColor, SkColor backgroundColor); + void SetColor(SkColor text_color); void SetLineHeight(int height); // Pass in 0 for default height. void SetLineLimit(int lines); // Pass in -1 for no limit. void SetText(const base::string16& text); // Additionally clears caches. diff --git a/chromium/ui/message_center/views/constants.h b/chromium/ui/message_center/views/constants.h deleted file mode 100644 index 5ef550d405a..00000000000 --- a/chromium/ui/message_center/views/constants.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_MESSAGE_CENTER_VIEWS_CONSTANTS_H_ -#define UI_MESSAGE_CENTER_VIEWS_CONSTANTS_H_ - -#include <stddef.h> - -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/geometry/size.h" -#include "ui/message_center/public/cpp/message_center_constants.h" - -namespace message_center { - -// The text background colors below are used only to keep -// view::Label from modifying the text color and will not actually be drawn. -// See view::Label's RecalculateColors() for details. -const SkColor kRegularTextBackgroundColor = SK_ColorWHITE; -const SkColor kDimTextBackgroundColor = SK_ColorWHITE; -const SkColor kContextTextBackgroundColor = SK_ColorWHITE; - -const int kTextBottomPadding = 12; -const int kItemTitleToMessagePadding = 3; -const int kButtonVerticalPadding = 0; -const int kButtonTitleTopPadding = 0; -const int kNotificationSettingsPadding = 5; - -// Character limits: Displayed text will be subject to the line limits above, -// but we also remove trailing characters from text to reduce processing cost. -// Character limit = pixels per line * line limit / min. pixels per character. -const int kMinPixelsPerTitleCharacter = 4; -const size_t kMessageCharacterLimit = - message_center::kNotificationWidth * - message_center::kMessageExpandedLineLimit / 3; -const size_t kContextMessageCharacterLimit = - message_center::kNotificationWidth * - message_center::kContextMessageLineLimit / 3; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_VIEWS_CONSTANTS_H_ diff --git a/chromium/ui/message_center/views/desktop_popup_alignment_delegate.cc b/chromium/ui/message_center/views/desktop_popup_alignment_delegate.cc index 56aa3b95cc6..e0d9364527c 100644 --- a/chromium/ui/message_center/views/desktop_popup_alignment_delegate.cc +++ b/chromium/ui/message_center/views/desktop_popup_alignment_delegate.cc @@ -39,7 +39,7 @@ int DesktopPopupAlignmentDelegate::GetToastOriginX( return work_area_.right() - kMarginBetweenPopups - toast_bounds.width(); } -int DesktopPopupAlignmentDelegate::GetBaseLine() const { +int DesktopPopupAlignmentDelegate::GetBaseline() const { return IsTopDown() ? work_area_.y() + kMarginBetweenPopups : work_area_.bottom() - kMarginBetweenPopups; } diff --git a/chromium/ui/message_center/views/desktop_popup_alignment_delegate.h b/chromium/ui/message_center/views/desktop_popup_alignment_delegate.h index 93c05fc57cc..93fb52cfd54 100644 --- a/chromium/ui/message_center/views/desktop_popup_alignment_delegate.h +++ b/chromium/ui/message_center/views/desktop_popup_alignment_delegate.h @@ -33,7 +33,7 @@ class MESSAGE_CENTER_EXPORT DesktopPopupAlignmentDelegate // Overridden from PopupAlignmentDelegate: int GetToastOriginX(const gfx::Rect& toast_bounds) const override; - int GetBaseLine() const override; + int GetBaseline() const override; gfx::Rect GetWorkArea() const override; bool IsTopDown() const override; bool IsFromLeft() const override; diff --git a/chromium/ui/message_center/views/message_popup_collection.cc b/chromium/ui/message_center/views/message_popup_collection.cc index 45871e6e7e4..edd1bbdf3ad 100644 --- a/chromium/ui/message_center/views/message_popup_collection.cc +++ b/chromium/ui/message_center/views/message_popup_collection.cc @@ -7,19 +7,21 @@ #include <set> #include "base/bind.h" +#include "base/feature_list.h" #include "base/i18n/rtl.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" -#include "base/run_loop.h" #include "base/time/time.h" #include "base/timer/timer.h" -#include "ui/accessibility/ax_enums.h" +#include "build/build_config.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" #include "ui/message_center/notification_list.h" +#include "ui/message_center/public/cpp/features.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/ui_controller.h" #include "ui/message_center/views/message_view.h" #include "ui/message_center/views/message_view_context_menu_controller.h" @@ -36,11 +38,6 @@ namespace message_center { namespace { -// Timeout between the last user-initiated close of the toast and the moment -// when normal layout/update of the toast stack continues. If the last toast was -// just closed, the timeout is shorter. -const int kMouseExitedDeferTimeoutMs = 200; - // The margin between messages (and between the anchor unless // first_item_has_no_margin was specified). const int kToastMarginY = kMarginBetweenPopups; @@ -55,11 +52,11 @@ MessagePopupCollection::MessagePopupCollection( tray_(tray), alignment_delegate_(alignment_delegate) { DCHECK(message_center_); - defer_timer_.reset(new base::OneShotTimer); message_center_->AddObserver(this); alignment_delegate_->set_collection(this); #if !defined(OS_CHROMEOS) - context_menu_controller_.reset(new MessageViewContextMenuController()); + if (!base::FeatureList::IsEnabled(message_center::kNewStyleNotifications)) + context_menu_controller_.reset(new MessageViewContextMenuController()); #endif } @@ -123,12 +120,37 @@ void MessagePopupCollection::UpdateWidgets() { } bool top_down = alignment_delegate_->IsTopDown(); - int base = GetBaseLine(toasts_.empty() ? NULL : toasts_.back()); + int base = GetBaseline(); #if defined(OS_CHROMEOS) bool is_primary_display = alignment_delegate_->IsPrimaryDisplayForNotification(); #endif + // Check if the popups contain a new notification. + bool has_new_toasts = false; + for (auto* popup : popups) { + if (!FindToast(popup->id())) { + has_new_toasts = true; + break; + } + } + + // If a new notification is found, collapse all existing notifications + // beforehand. + if (has_new_toasts) { + for (Toasts::const_iterator iter = toasts_.begin(); + iter != toasts_.end();) { + // SetExpanded() may fire PreferredSizeChanged(), which may end up + // removing the toast in OnNotificationUpdated(). So we have to increment + // the iterator in a way that is safe even if the current iterator is + // invalidated during the loop. + MessageView* view = (*iter++)->message_view(); + if (view->IsMouseHovered() || view->IsManuallyExpandedOrCollapsed()) + continue; + view->SetExpanded(false); + } + } + // Iterate in the reverse order to keep the oldest toasts on screen. Newer // items may be ignored if there are no room to place them. for (NotificationList::PopupNotifications::const_reverse_iterator iter = @@ -150,10 +172,6 @@ void MessagePopupCollection::UpdateWidgets() { // Create top-level notification. MessageView* view = MessageViewFactory::Create(notification, true); observed_views_.Add(view); -#if defined(OS_CHROMEOS) - // Disable pinned feature since this is a popup. - view->set_force_disable_pinned(); -#endif // defined(OS_CHROMEOS) view->SetExpanded(true); #if !defined(OS_CHROMEOS) @@ -198,11 +216,11 @@ void MessagePopupCollection::UpdateWidgets() { if (views::ViewsDelegate::GetInstance()) { views::ViewsDelegate::GetInstance()->NotifyAccessibilityEvent( - toast, ui::AX_EVENT_ALERT); + toast, ax::mojom::Event::kAlert); } - message_center_->DisplayedNotification( - notification.id(), message_center::DISPLAY_SOURCE_POPUP); + message_center_->DisplayedNotification(notification.id(), + DISPLAY_SOURCE_POPUP); } } @@ -212,9 +230,6 @@ void MessagePopupCollection::OnMouseEntered(ToastContentsView* toast_entered) { latest_toast_entered_ = toast_entered; PausePopupTimers(); - - if (user_is_closing_toasts_by_clicking_) - defer_timer_->Stop(); } void MessagePopupCollection::OnMouseExited(ToastContentsView* toast_exited) { @@ -224,15 +239,7 @@ void MessagePopupCollection::OnMouseExited(ToastContentsView* toast_exited) { return; latest_toast_entered_ = NULL; - if (user_is_closing_toasts_by_clicking_) { - defer_timer_->Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kMouseExitedDeferTimeoutMs), - this, - &MessagePopupCollection::OnDeferTimerExpired); - } else { - RestartPopupTimers(); - } + RestartPopupTimers(); } std::set<std::string> MessagePopupCollection::CloseAllWidgets() { @@ -270,8 +277,8 @@ void MessagePopupCollection::RemoveToast(ToastContentsView* toast, void MessagePopupCollection::RepositionWidgets() { bool top_down = alignment_delegate_->IsTopDown(); - int base = GetBaseLine(NULL); // We don't want to position relative to last - // toast - we want re-position. + // We don't want to position relative to last toast - we want re-position. + int base = alignment_delegate_->GetBaseline(); for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end();) { Toasts::const_iterator curr = iter++; @@ -299,60 +306,27 @@ void MessagePopupCollection::RepositionWidgets() { } } -void MessagePopupCollection::RepositionWidgetsWithTarget() { +int MessagePopupCollection::GetBaseline() const { if (toasts_.empty()) - return; + return alignment_delegate_->GetBaseline(); - bool top_down = alignment_delegate_->IsTopDown(); - - // Nothing to do if there are no widgets above target if bottom-aligned or no - // widgets below target if top-aligned. - if (top_down ? toasts_.back()->origin().y() < target_top_edge_ - : toasts_.back()->origin().y() > target_top_edge_) - return; - - Toasts::reverse_iterator iter = toasts_.rbegin(); - for (; iter != toasts_.rend(); ++iter) { - // We only reposition widgets above target if bottom-aligned or widgets - // below target if top-aligned. - if (top_down ? (*iter)->origin().y() < target_top_edge_ - : (*iter)->origin().y() > target_top_edge_) - break; - } - --iter; - - // Slide length is the number of pixels the widgets should move so that their - // bottom edge (top-edge if top-aligned) touches the target. - int slide_length = std::abs(target_top_edge_ - (*iter)->origin().y()); - for (;; --iter) { - gfx::Rect bounds((*iter)->bounds()); - - // If top-aligned, shift widgets upwards by slide_length. If bottom-aligned, - // shift them downwards by slide_length. - if (top_down) - bounds.set_y(bounds.y() - slide_length); - else - bounds.set_y(bounds.y() + slide_length); - (*iter)->SetBoundsWithAnimation(bounds); + if (alignment_delegate_->IsTopDown()) + return toasts_.back()->bounds().bottom() + kToastMarginY; - if (iter == toasts_.rbegin()) - break; - } + return toasts_.back()->origin().y() - kToastMarginY; } -int MessagePopupCollection::GetBaseLine(ToastContentsView* last_toast) const { - if (!last_toast) { - return alignment_delegate_->GetBaseLine(); - } else if (alignment_delegate_->IsTopDown()) { - return toasts_.back()->bounds().bottom() + kToastMarginY; - } else { - return toasts_.back()->origin().y() - kToastMarginY; - } +int MessagePopupCollection::GetBaselineForToast( + ToastContentsView* toast) const { + if (alignment_delegate_->IsTopDown()) + return toast->bounds().y(); + else + return toast->bounds().bottom(); } void MessagePopupCollection::OnNotificationAdded( const std::string& notification_id) { - DoUpdateIfPossible(); + DoUpdate(); } void MessagePopupCollection::OnNotificationRemoved( @@ -367,34 +341,10 @@ void MessagePopupCollection::OnNotificationRemoved( if (iter == toasts_.end()) return; - target_top_edge_ = (*iter)->bounds().y(); - if (by_user && !user_is_closing_toasts_by_clicking_) { - // [Re] start a timeout after which the toasts re-position to their - // normal locations after tracking the mouse pointer for easy deletion. - // This provides a period of time when toasts are easy to remove because - // they re-position themselves to have Close button right under the mouse - // pointer. If the user continue to remove the toasts, the delay is reset. - // Once user stopped removing the toasts, the toasts re-populate/rearrange - // after the specified delay. - user_is_closing_toasts_by_clicking_ = true; - IncrementDeferCounter(); - } - - // CloseWithAnimation ultimately causes a call to RemoveToast, which calls - // OnMouseExited. This means that |user_is_closing_toasts_by_clicking_| must - // have been set before this call, otherwise it will remain true even after - // the toast is closed, since the defer timer won't be started. RemoveToast(*iter, /*mark_as_shown=*/true); if (by_user) - RepositionWidgetsWithTarget(); -} - -void MessagePopupCollection::OnDeferTimerExpired() { - user_is_closing_toasts_by_clicking_ = false; - DecrementDeferCounter(); - - RestartPopupTimers(); + RepositionWidgets(); } void MessagePopupCollection::OnNotificationUpdated( @@ -439,10 +389,7 @@ void MessagePopupCollection::OnNotificationUpdated( if (!updated) RemoveToast(*toast_iter, /*mark_as_shown=*/true); - if (user_is_closing_toasts_by_clicking_) - RepositionWidgetsWithTarget(); - else - DoUpdateIfPossible(); + DoUpdate(); } ToastContentsView* MessagePopupCollection::FindToast( @@ -455,42 +402,16 @@ ToastContentsView* MessagePopupCollection::FindToast( return NULL; } -void MessagePopupCollection::IncrementDeferCounter() { - defer_counter_++; -} - -void MessagePopupCollection::DecrementDeferCounter() { - defer_counter_--; - DCHECK(defer_counter_ >= 0); - DoUpdateIfPossible(); -} - // This is the main sequencer of tasks. It does a step, then waits for // all started transitions to play out before doing the next step. // First, remove all expired toasts. -// Then, reposition widgets (the reposition on close happens before all -// deferred tasks are even able to run) +// Then, reposition widgets. // Then, see if there is vacant space for new toasts. -void MessagePopupCollection::DoUpdateIfPossible() { - if (defer_counter_ > 0) - return; - +void MessagePopupCollection::DoUpdate() { RepositionWidgets(); - if (defer_counter_ > 0) - return; - // Reposition could create extra space which allows additional widgets. UpdateWidgets(); - - if (defer_counter_ > 0) - return; - - // Test support. Quit the test run loop when no more updates are deferred, - // meaining th echeck for updates did not cause anything to change so no new - // transition animations were started. - if (run_loop_for_test_.get()) - run_loop_for_test_->Quit(); } void MessagePopupCollection::OnDisplayMetricsChanged( @@ -508,17 +429,7 @@ views::Widget* MessagePopupCollection::GetWidgetForTest(const std::string& id) return NULL; } -void MessagePopupCollection::CreateRunLoopForTest() { - run_loop_for_test_.reset(new base::RunLoop()); -} - -void MessagePopupCollection::WaitForTest() { - run_loop_for_test_->Run(); - run_loop_for_test_.reset(); -} - gfx::Rect MessagePopupCollection::GetToastRectAt(size_t index) const { - DCHECK(defer_counter_ == 0) << "Fetching the bounds with animations active."; size_t i = 0; for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end(); ++iter) { diff --git a/chromium/ui/message_center/views/message_popup_collection.h b/chromium/ui/message_center/views/message_popup_collection.h index 51af94202cf..178e41f9b77 100644 --- a/chromium/ui/message_center/views/message_popup_collection.h +++ b/chromium/ui/message_center/views/message_popup_collection.h @@ -22,10 +22,6 @@ #include "ui/views/view_observer.h" #include "ui/views/widget/widget_observer.h" -namespace base { -class RunLoop; -} - namespace display { class Display; } @@ -74,17 +70,8 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection void OnMouseEntered(ToastContentsView* toast_entered); void OnMouseExited(ToastContentsView* toast_exited); - // Invoked by toasts when they start/finish their animations. - // While "defer counter" is greater than zero, the popup collection does - // not perform updates. It is used to wait for various animations and user - // actions like serial closing of the toasts, when the remaining toasts "flow - // under the mouse". - void IncrementDeferCounter(); - void DecrementDeferCounter(); - - // Runs the next step in update/animate sequence, if the defer counter is not - // zero. Otherwise, simply waits when it becomes zero. - void DoUpdateIfPossible(); + // Runs the next step in update/animate sequence. + void DoUpdate(); // Removes the toast from our internal list of toasts; this is called when the // toast is irrevocably closed (such as within RemoveToast). @@ -110,14 +97,13 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection // Repositions all of the widgets based on the current work area. void RepositionWidgets(); - // Repositions widgets to the top edge of the notification toast that was - // just removed, so that the user can click close button without mouse moves. - // See crbug.com/224089 - void RepositionWidgetsWithTarget(); - - // The base line is an (imaginary) line that would touch the bottom of the + // The baseline is an (imaginary) line that would touch the bottom of the // next created notification if bottom-aligned or its top if top-aligned. - int GetBaseLine(ToastContentsView* last_toast) const; + int GetBaseline() const; + + // Returns the top of the toast when IsTopDown() is true, otherwise returns + // the bottom of the toast. + int GetBaselineForToast(ToastContentsView* toast) const; // Overridden from MessageCenterObserver: void OnNotificationAdded(const std::string& notification_id) override; @@ -135,8 +121,6 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection // "ForTest" methods. views::Widget* GetWidgetForTest(const std::string& id) const; - void CreateRunLoopForTest(); - void WaitForTest(); gfx::Rect GetToastRectAt(size_t index) const; MessageCenter* message_center_; @@ -145,30 +129,14 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection PopupAlignmentDelegate* alignment_delegate_; - int defer_counter_ = 0; - // This is only used to compare with incoming events, do not assume that // the toast will be valid if this pointer is non-NULL. ToastContentsView* latest_toast_entered_ = nullptr; - // Denotes a mode when user is clicking the Close button of toasts in a - // sequence, w/o moving the mouse. We reposition the toasts so the next one - // happens to be right under the mouse, and the user can just dispose of - // multipel toasts by clicking. The mode ends when defer_timer_ expires. - bool user_is_closing_toasts_by_clicking_ = false; - std::unique_ptr<base::OneShotTimer> defer_timer_; - // The top edge to align the position of the next toast during 'close by - // clicking" mode. - // Only to be used when user_is_closing_toasts_by_clicking_ is true. - int target_top_edge_ = 0; - // This is the number of pause request for timer. If it's more than zero, the // timer is paused. If zero, the timer is not paused. int timer_pause_counter_ = 0; - // Weak, only exists temporarily in tests. - std::unique_ptr<base::RunLoop> run_loop_for_test_; - std::unique_ptr<MessageViewContextMenuController> context_menu_controller_; ScopedObserver<views::View, views::ViewObserver> observed_views_{this}; diff --git a/chromium/ui/message_center/views/message_popup_collection_unittest.cc b/chromium/ui/message_center/views/message_popup_collection_unittest.cc index f1c48b1fd8f..c643fa73c94 100644 --- a/chromium/ui/message_center/views/message_popup_collection_unittest.cc +++ b/chromium/ui/message_center/views/message_popup_collection_unittest.cc @@ -12,8 +12,8 @@ #include <numeric> #include <utility> -#include "base/message_loop/message_loop.h" #include "base/optional.h" +#include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -25,6 +25,7 @@ #include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/image_unittest_util.h" #include "ui/message_center/fake_message_center.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/views/desktop_popup_alignment_delegate.h" @@ -33,23 +34,22 @@ #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" +namespace message_center { + namespace { -std::unique_ptr<message_center::Notification> CreateTestNotification( - std::string id, - std::string text) { - return std::make_unique<message_center::Notification>( - message_center::NOTIFICATION_TYPE_BASE_FORMAT, id, - base::UTF8ToUTF16("test title"), base::ASCIIToUTF16(text), gfx::Image(), +std::unique_ptr<Notification> CreateTestNotification(std::string id, + std::string text) { + return std::make_unique<Notification>( + NOTIFICATION_TYPE_BASE_FORMAT, id, base::UTF8ToUTF16("test title"), + base::ASCIIToUTF16(text), gfx::Image(), base::string16() /* display_source */, GURL(), - message_center::NotifierId(message_center::NotifierId::APPLICATION, id), - message_center::RichNotificationData(), - new message_center::NotificationDelegate()); + NotifierId(NotifierId::APPLICATION, id), RichNotificationData(), + new NotificationDelegate()); } // Provides an aura window context for widget creation. -class TestPopupAlignmentDelegate - : public message_center::DesktopPopupAlignmentDelegate { +class TestPopupAlignmentDelegate : public DesktopPopupAlignmentDelegate { public: explicit TestPopupAlignmentDelegate(gfx::NativeWindow context) : context_(context) {} @@ -70,10 +70,10 @@ class TestPopupAlignmentDelegate } // namespace -namespace message_center { namespace test { -class MessagePopupCollectionTest : public views::ViewsTestBase { +class MessagePopupCollectionTest : public views::ViewsTestBase, + public views::WidgetObserver { public: void SetUp() override { views::ViewsTestBase::SetUp(); @@ -85,10 +85,9 @@ class MessagePopupCollectionTest : public views::ViewsTestBase { // This size fits test machines resolution and also can keep a few toasts // w/o ill effects of hitting the screen overflow. This allows us to assume // and verify normal layout of the toast stack. - SetDisplayInfo(gfx::Rect(0, 0, 600, 390), // taskbar at the bottom. - gfx::Rect(0, 0, 600, 400)); + SetDisplayInfo(gfx::Rect(0, 0, 1920, 1070), // taskbar at the bottom. + gfx::Rect(0, 0, 1920, 1080)); id_ = 0; - PrepareForWait(); } void TearDown() override { @@ -123,7 +122,6 @@ class MessagePopupCollectionTest : public views::ViewsTestBase { dummy_display.set_bounds(display_bounds); dummy_display.set_work_area(work_area); alignment_delegate_->RecomputeAlignment(dummy_display); - PrepareForWait(); } gfx::Rect GetWorkArea() { @@ -142,34 +140,52 @@ class MessagePopupCollectionTest : public views::ViewsTestBase { std::string AddNotification() { std::string id = base::IntToString(id_++); - std::unique_ptr<Notification> notification(new Notification( + std::unique_ptr<Notification> notification = std::make_unique<Notification>( NOTIFICATION_TYPE_BASE_FORMAT, id, base::UTF8ToUTF16("test title"), base::UTF8ToUTF16("test message"), gfx::Image(), base::string16() /* display_source */, GURL(), NotifierId(), - message_center::RichNotificationData(), new NotificationDelegate())); + RichNotificationData(), new NotificationDelegate()); MessageCenter::Get()->AddNotification(std::move(notification)); return id; } - void PrepareForWait() { collection_->CreateRunLoopForTest(); } - - // Assumes there is non-zero pending work. - void WaitForTransitionsDone() { - collection_->WaitForTest(); - collection_->CreateRunLoopForTest(); + std::string AddImageNotification() { + std::string id = base::IntToString(id_++); + std::unique_ptr<Notification> notification = std::make_unique<Notification>( + NOTIFICATION_TYPE_IMAGE, id, base::UTF8ToUTF16("test title"), + base::UTF8ToUTF16("test message"), gfx::Image(), + base::string16() /* display_source */, GURL(), NotifierId(), + RichNotificationData(), new NotificationDelegate()); + notification->set_image(gfx::test::CreateImage(100, 100)); + MessageCenter::Get()->AddNotification(std::move(notification)); + return id; } void CloseAllToasts() { // Assumes there is at least one toast to close. EXPECT_TRUE(GetToastCounts() > 0); - MessageCenter::Get()->RemoveAllNotifications( - false /* by_user */, MessageCenter::RemoveType::ALL); + + auto toasts = collection_->toasts_; + for (ToastContentsView* toast : toasts) { + toast->GetWidget()->CloseNow(); + } } gfx::Rect GetToastRectAt(size_t index) { return collection_->GetToastRectAt(index); } + void RemoveToastAndWaitForClose(const std::string& id) { + GetWidget(id)->AddObserver(this); + MessageCenter::Get()->RemoveNotification(id, true /* by_user */); + widget_close_run_loop_.Run(); + } + + // views::WidgetObserver + void OnWidgetDestroyed(views::Widget* widget) override { + widget_close_run_loop_.Quit(); + } + // Checks: // 1) sizes of toast and corresponding widget are equal; // 2) widgets do not owerlap; @@ -177,6 +193,7 @@ class MessagePopupCollectionTest : public views::ViewsTestBase { class CheckedAnimationDelegate : public gfx::AnimationDelegate { public: explicit CheckedAnimationDelegate(MessagePopupCollectionTest* test); + ~CheckedAnimationDelegate() override; // returns first encountered error const base::Optional<std::string>& error_msg() const { return error_msg_; } @@ -214,6 +231,7 @@ class MessagePopupCollectionTest : public views::ViewsTestBase { const MessagePopupCollection::Toasts& toasts); private: + base::RunLoop widget_close_run_loop_; std::unique_ptr<MessagePopupCollection> collection_; std::unique_ptr<DesktopPopupAlignmentDelegate> alignment_delegate_; int id_; @@ -226,6 +244,11 @@ MessagePopupCollectionTest::CheckedAnimationDelegate::CheckedAnimationDelegate( animation_delegate().bounds_animation_->set_delegate(this); } +MessagePopupCollectionTest::CheckedAnimationDelegate:: + ~CheckedAnimationDelegate() { + animation_delegate().bounds_animation_->set_delegate(&animation_delegate()); +} + void MessagePopupCollectionTest::CheckedAnimationDelegate::AnimationEnded( const gfx::Animation* animation) { animation_delegate().AnimationEnded(animation); @@ -334,21 +357,18 @@ TEST_F(MessagePopupCollectionTest, DismissOnClick) { std::string id1 = AddNotification(); std::string id2 = AddNotification(); - WaitForTransitionsDone(); EXPECT_EQ(2u, GetToastCounts()); EXPECT_TRUE(IsToastShown(id1)); EXPECT_TRUE(IsToastShown(id2)); MessageCenter::Get()->ClickOnNotification(id2); - WaitForTransitionsDone(); EXPECT_EQ(1u, GetToastCounts()); EXPECT_TRUE(IsToastShown(id1)); EXPECT_FALSE(IsToastShown(id2)); MessageCenter::Get()->ClickOnNotificationButton(id1, 0); - WaitForTransitionsDone(); EXPECT_EQ(0u, GetToastCounts()); EXPECT_FALSE(IsToastShown(id1)); EXPECT_FALSE(IsToastShown(id2)); @@ -359,21 +379,20 @@ TEST_F(MessagePopupCollectionTest, DismissOnClick) { TEST_F(MessagePopupCollectionTest, NotDismissedOnClick) { std::string id1 = AddNotification(); std::string id2 = AddNotification(); - WaitForTransitionsDone(); EXPECT_EQ(2u, GetToastCounts()); EXPECT_TRUE(IsToastShown(id1)); EXPECT_TRUE(IsToastShown(id2)); MessageCenter::Get()->ClickOnNotification(id2); - collection()->DoUpdateIfPossible(); + collection()->DoUpdate(); EXPECT_EQ(2u, GetToastCounts()); EXPECT_TRUE(IsToastShown(id1)); EXPECT_TRUE(IsToastShown(id2)); MessageCenter::Get()->ClickOnNotificationButton(id1, 0); - collection()->DoUpdateIfPossible(); + collection()->DoUpdate(); EXPECT_EQ(2u, GetToastCounts()); EXPECT_TRUE(IsToastShown(id1)); EXPECT_TRUE(IsToastShown(id2)); @@ -387,7 +406,6 @@ TEST_F(MessagePopupCollectionTest, NotDismissedOnClick) { TEST_F(MessagePopupCollectionTest, ShutdownDuringShowing) { std::string id1 = AddNotification(); std::string id2 = AddNotification(); - WaitForTransitionsDone(); EXPECT_EQ(2u, GetToastCounts()); EXPECT_TRUE(IsToastShown(id1)); EXPECT_TRUE(IsToastShown(id2)); @@ -405,7 +423,6 @@ TEST_F(MessagePopupCollectionTest, DefaultPositioning) { std::string id1 = AddNotification(); std::string id2 = AddNotification(); std::string id3 = AddNotification(); - WaitForTransitionsDone(); gfx::Rect r0 = GetToastRectAt(0); gfx::Rect r1 = GetToastRectAt(1); @@ -436,7 +453,6 @@ TEST_F(MessagePopupCollectionTest, DefaultPositioning) { CloseAllToasts(); EXPECT_EQ(0u, GetToastCounts()); - WaitForTransitionsDone(); } TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) { @@ -447,7 +463,6 @@ TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) { gfx::Rect(0, 0, 600, 400)); // Display-bounds. std::string id0 = AddNotification(); std::string id1 = AddNotification(); - WaitForTransitionsDone(); gfx::Rect r0 = GetToastRectAt(0); gfx::Rect r1 = GetToastRectAt(1); @@ -463,7 +478,6 @@ TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) { CloseAllToasts(); EXPECT_EQ(0u, GetToastCounts()); - WaitForTransitionsDone(); } TEST_F(MessagePopupCollectionTest, TopDownPositioningWithTopTaskbar) { @@ -472,7 +486,6 @@ TEST_F(MessagePopupCollectionTest, TopDownPositioningWithTopTaskbar) { gfx::Rect(0, 0, 600, 400)); // Display-bounds. std::string id0 = AddNotification(); std::string id1 = AddNotification(); - WaitForTransitionsDone(); gfx::Rect r0 = GetToastRectAt(0); gfx::Rect r1 = GetToastRectAt(1); @@ -488,7 +501,6 @@ TEST_F(MessagePopupCollectionTest, TopDownPositioningWithTopTaskbar) { CloseAllToasts(); EXPECT_EQ(0u, GetToastCounts()); - WaitForTransitionsDone(); } TEST_F(MessagePopupCollectionTest, TopDownPositioningWithLeftAndTopTaskbar) { @@ -500,7 +512,6 @@ TEST_F(MessagePopupCollectionTest, TopDownPositioningWithLeftAndTopTaskbar) { gfx::Rect(0, 0, 600, 400)); // Display-bounds. std::string id0 = AddNotification(); std::string id1 = AddNotification(); - WaitForTransitionsDone(); gfx::Rect r0 = GetToastRectAt(0); gfx::Rect r1 = GetToastRectAt(1); @@ -516,7 +527,6 @@ TEST_F(MessagePopupCollectionTest, TopDownPositioningWithLeftAndTopTaskbar) { CloseAllToasts(); EXPECT_EQ(0u, GetToastCounts()); - WaitForTransitionsDone(); } TEST_F(MessagePopupCollectionTest, TopDownPositioningWithBottomAndTopTaskbar) { @@ -528,7 +538,6 @@ TEST_F(MessagePopupCollectionTest, TopDownPositioningWithBottomAndTopTaskbar) { gfx::Rect(0, 0, 600, 400)); // Display-bounds. std::string id0 = AddNotification(); std::string id1 = AddNotification(); - WaitForTransitionsDone(); gfx::Rect r0 = GetToastRectAt(0); gfx::Rect r1 = GetToastRectAt(1); @@ -544,7 +553,6 @@ TEST_F(MessagePopupCollectionTest, TopDownPositioningWithBottomAndTopTaskbar) { CloseAllToasts(); EXPECT_EQ(0u, GetToastCounts()); - WaitForTransitionsDone(); } TEST_F(MessagePopupCollectionTest, LeftPositioningWithLeftTaskbar) { @@ -553,7 +561,6 @@ TEST_F(MessagePopupCollectionTest, LeftPositioningWithLeftTaskbar) { gfx::Rect(0, 0, 600, 400)); // Display-bounds. std::string id0 = AddNotification(); std::string id1 = AddNotification(); - WaitForTransitionsDone(); gfx::Rect r0 = GetToastRectAt(0); gfx::Rect r1 = GetToastRectAt(1); @@ -572,13 +579,34 @@ TEST_F(MessagePopupCollectionTest, LeftPositioningWithLeftTaskbar) { CloseAllToasts(); EXPECT_EQ(0u, GetToastCounts()); - WaitForTransitionsDone(); +} + +// Regression test for https://crbug.com/679397 +TEST_F(MessagePopupCollectionTest, MultipleNotificationHeight) { + std::string id0 = AddNotification(); + std::string id1 = AddImageNotification(); + EXPECT_EQ(2u, GetToastCounts()); + + gfx::Rect r0 = GetToast(id0)->bounds(); + + RemoveToastAndWaitForClose(id0); + EXPECT_EQ(1u, GetToastCounts()); + + gfx::Rect r1 = GetToast(id1)->bounds(); + + // The heights should be different as one is an image notification while + // another is a basic notification, but the bottom positions after the + // animation should be same even though the heights are different. + EXPECT_NE(r0.height(), r1.height()); + EXPECT_EQ(r0.bottom(), r1.bottom()); + + CloseAllToasts(); + EXPECT_EQ(0u, GetToastCounts()); } TEST_F(MessagePopupCollectionTest, DetectMouseHover) { std::string id0 = AddNotification(); std::string id1 = AddNotification(); - WaitForTransitionsDone(); views::WidgetDelegateView* toast0 = GetToast(id0); EXPECT_TRUE(toast0 != NULL); @@ -614,7 +642,6 @@ TEST_F(MessagePopupCollectionTest, DetectMouseHover) { TEST_F(MessagePopupCollectionTest, DetectMouseHoverWithUserClose) { std::string id0 = AddNotification(); std::string id1 = AddNotification(); - WaitForTransitionsDone(); views::WidgetDelegateView* toast0 = GetToast(id0); EXPECT_TRUE(toast0 != NULL); @@ -624,18 +651,15 @@ TEST_F(MessagePopupCollectionTest, DetectMouseHoverWithUserClose) { ui::MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), 0, 0); toast1->OnMouseEntered(event); - static_cast<MessageCenterObserver*>(collection())->OnNotificationRemoved( - id1, true); + RemoveToastAndWaitForClose(id1); EXPECT_FALSE(MouseInCollection()); std::string id2 = AddNotification(); - WaitForTransitionsDone(); views::WidgetDelegateView* toast2 = GetToast(id2); EXPECT_TRUE(toast2 != NULL); CloseAllToasts(); - WaitForTransitionsDone(); } TEST_F(MessagePopupCollectionTest, ManyPopupNotifications) { @@ -646,7 +670,6 @@ TEST_F(MessagePopupCollectionTest, ManyPopupNotifications) { ids[i] = AddNotification(); } - WaitForTransitionsDone(); for (size_t i = 0; i < notifications_to_add - 1; ++i) { EXPECT_TRUE(IsToastShown(ids[i])) << "Should show the " << i << "th ID"; @@ -654,7 +677,6 @@ TEST_F(MessagePopupCollectionTest, ManyPopupNotifications) { EXPECT_FALSE(IsToastShown(ids[notifications_to_add - 1])); CloseAllToasts(); - WaitForTransitionsDone(); } #if defined(OS_CHROMEOS) @@ -667,12 +689,11 @@ TEST_F(MessagePopupCollectionTest, CloseNonClosableNotifications) { base::UTF8ToUTF16("test title"), base::UTF8ToUTF16("test message"), gfx::Image(), base::string16() /* display_source */, GURL(), NotifierId(NotifierId::APPLICATION, kNotificationId), - message_center::RichNotificationData(), new NotificationDelegate())); + RichNotificationData(), new NotificationDelegate())); notification->set_pinned(true); // Add a pinned notification. MessageCenter::Get()->AddNotification(std::move(notification)); - WaitForTransitionsDone(); // Confirms that there is a toast. EXPECT_EQ(1u, GetToastCounts()); @@ -686,7 +707,6 @@ TEST_F(MessagePopupCollectionTest, CloseNonClosableNotifications) { toast1->OnMouseEntered(event); static_cast<MessageCenterObserver*>(collection()) ->OnNotificationRemoved(kNotificationId, true); - WaitForTransitionsDone(); // Confirms that there is no toast. EXPECT_EQ(0u, GetToastCounts()); @@ -727,7 +747,6 @@ TEST_F(MessagePopupCollectionTest, ChangingNotificationSize) { } } - WaitForTransitionsDone(); // Confirms that there are 2 toasts of 3 notifications. EXPECT_EQ(3u, GetToastCounts()); @@ -741,8 +760,6 @@ TEST_F(MessagePopupCollectionTest, ChangingNotificationSize) { CheckedAnimationDelegate checked_animation(this); - WaitForTransitionsDone(); - EXPECT_FALSE(checked_animation.error_msg()) << "Animation error, test case: " << id << ' ' << update.name << ":\n" << *checked_animation.error_msg(); @@ -750,7 +767,6 @@ TEST_F(MessagePopupCollectionTest, ChangingNotificationSize) { } CloseAllToasts(); - WaitForTransitionsDone(); } } // namespace test diff --git a/chromium/ui/message_center/views/message_view.cc b/chromium/ui/message_center/views/message_view.cc index 25904ad06cf..41912b341f7 100644 --- a/chromium/ui/message_center/views/message_view.cc +++ b/chromium/ui/message_center/views/message_view.cc @@ -4,6 +4,7 @@ #include "ui/message_center/views/message_view.h" +#include "base/feature_list.h" #include "base/strings/utf_string_conversions.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" @@ -14,8 +15,8 @@ #include "ui/gfx/shadow_util.h" #include "ui/gfx/shadow_value.h" #include "ui/message_center/message_center.h" +#include "ui/message_center/public/cpp/features.h" #include "ui/message_center/public/cpp/message_center_constants.h" -#include "ui/message_center/public/cpp/message_center_switches.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -26,6 +27,8 @@ #include "ui/views/painter.h" #include "ui/views/widget/widget.h" +namespace message_center { + namespace { const SkColor kBorderColor = SkColorSetARGB(0x1F, 0x0, 0x0, 0x0); @@ -37,8 +40,7 @@ bool sidebar_enabled = false; // Creates a text for spoken feedback from the data contained in the // notification. -base::string16 CreateAccessibleName( - const message_center::Notification& notification) { +base::string16 CreateAccessibleName(const Notification& notification) { if (!notification.accessible_name().empty()) return notification.accessible_name(); @@ -46,10 +48,8 @@ base::string16 CreateAccessibleName( std::vector<base::string16> accessible_lines = { notification.title(), notification.message(), notification.context_message()}; - std::vector<message_center::NotificationItem> items = notification.items(); - for (size_t i = 0; - i < items.size() && i < message_center::kNotificationMaximumItems; - ++i) { + std::vector<NotificationItem> items = notification.items(); + for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) { accessible_lines.push_back(items[i].title + base::ASCIIToUTF16(" ") + items[i].message); } @@ -57,17 +57,11 @@ base::string16 CreateAccessibleName( } bool ShouldRoundMessageViewCorners() { -#if defined(OS_CHROMEOS) - return true; -#else - return message_center::IsNewStyleNotificationEnabled(); -#endif + return base::FeatureList::IsEnabled(message_center::kNewStyleNotifications); } } // namespace -namespace message_center { - // static const char MessageView::kViewClassName[] = "MessageView"; @@ -96,8 +90,7 @@ MessageView::MessageView(const Notification& notification) UpdateWithNotification(notification); } -MessageView::~MessageView() { -} +MessageView::~MessageView() {} void MessageView::UpdateWithNotification(const Notification& notification) { pinned_ = notification.pinned(); @@ -140,6 +133,15 @@ bool MessageView::IsExpanded() const { return false; } +bool MessageView::IsManuallyExpandedOrCollapsed() const { + // Not implemented by default. + return false; +} + +void MessageView::SetManuallyExpandedOrCollapsed(bool value) { + // Not implemented by default. +} + void MessageView::OnContainerAnimationStarted() { // Not implemented by default. } @@ -149,9 +151,9 @@ void MessageView::OnContainerAnimationEnded() { } void MessageView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_BUTTON; + node_data->role = ax::mojom::Role::kButton; node_data->AddStringAttribute( - ui::AX_ATTR_ROLE_DESCRIPTION, + ax::mojom::StringAttribute::kRoleDescription, l10n_util::GetStringUTF8( IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME)); node_data->SetName(accessible_name_); @@ -274,7 +276,9 @@ void MessageView::OnSlideOut() { } bool MessageView::GetPinned() const { - return pinned_ && !force_disable_pinned_; + // Only nested notifications can be pinned. Standalones (i.e. popups) can't + // be. + return pinned_ && is_nested_; } void MessageView::OnCloseButtonPressed() { @@ -282,7 +286,7 @@ void MessageView::OnCloseButtonPressed() { true /* by_user */); } -void MessageView::OnSettingsButtonPressed() { +void MessageView::OnSettingsButtonPressed(const ui::Event& event) { MessageCenter::Get()->ClickOnSettingsButton(notification_id_); } diff --git a/chromium/ui/message_center/views/message_view.h b/chromium/ui/message_center/views/message_view.h index 48d4d5a3995..0cbbaf18602 100644 --- a/chromium/ui/message_center/views/message_view.h +++ b/chromium/ui/message_center/views/message_view.h @@ -15,9 +15,10 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_delegate.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_delegate.h" #include "ui/message_center/views/slide_out_controller.h" +#include "ui/views/animation/ink_drop_host_view.h" #include "ui/views/view.h" namespace views { @@ -33,7 +34,7 @@ class NotificationControlButtonsView; // An base class for a notification entry. Contains background and other // elements shared by derived notification views. class MESSAGE_CENTER_EXPORT MessageView - : public views::View, + : public views::InkDropHostView, public views::SlideOutController::Delegate { public: static const char kViewClassName[]; @@ -61,6 +62,8 @@ class MESSAGE_CENTER_EXPORT MessageView virtual void SetExpanded(bool expanded); virtual bool IsExpanded() const; + virtual bool IsManuallyExpandedOrCollapsed() const; + virtual void SetManuallyExpandedOrCollapsed(bool value); // Invoked when the container view of MessageView (e.g. MessageCenterView in // ash) is starting the animation that possibly hides some part of @@ -70,7 +73,7 @@ class MESSAGE_CENTER_EXPORT MessageView virtual void OnContainerAnimationEnded(); void OnCloseButtonPressed(); - virtual void OnSettingsButtonPressed(); + virtual void OnSettingsButtonPressed(const ui::Event& event); // views::View void GetAccessibleNodeData(ui::AXNodeData* node_data) override; @@ -94,11 +97,6 @@ class MESSAGE_CENTER_EXPORT MessageView void set_scroller(views::ScrollView* scroller) { scroller_ = scroller; } std::string notification_id() const { return notification_id_; } -#if defined(OS_CHROMEOS) - // By calling this, all notifications are treated as non-pinned forcibly. - void set_force_disable_pinned() { force_disable_pinned_ = true; } -#endif - protected: // Creates and add close button to view hierarchy when necessary. Derived // classes should call this after its view hierarchy is populated to ensure @@ -112,6 +110,8 @@ class MESSAGE_CENTER_EXPORT MessageView views::View* background_view() { return background_view_; } views::ScrollView* scroller() { return scroller_; } + bool is_nested() const { return is_nested_; } + private: std::string notification_id_; views::View* background_view_ = nullptr; // Owned by views hierarchy. @@ -121,9 +121,6 @@ class MESSAGE_CENTER_EXPORT MessageView // Flag if the notification is set to pinned or not. bool pinned_ = false; - // Flag if pin is forcibly disabled on this view. If true, the view is never - // pinned regardless of the value of |pinned_|. - bool force_disable_pinned_ = false; std::unique_ptr<views::Painter> focus_painter_; diff --git a/chromium/ui/message_center/views/message_view_context_menu_controller.cc b/chromium/ui/message_center/views/message_view_context_menu_controller.cc index 811f8bc2fef..bcd9817db11 100644 --- a/chromium/ui/message_center/views/message_view_context_menu_controller.cc +++ b/chromium/ui/message_center/views/message_view_context_menu_controller.cc @@ -27,6 +27,12 @@ void MessageViewContextMenuController::ShowContextMenuForView( Notification* notification = MessageCenter::Get()->FindVisibleNotificationById( message_view->notification_id()); + + // Notification is null if the notification view is being removed or some + // invalid status. In this case, just returns. + if (!notification) + return; + menu_model_ = std::make_unique<NotificationMenuModel>(*notification); if (!menu_model_ || menu_model_->GetItemCount() == 0) diff --git a/chromium/ui/message_center/views/message_view_factory.cc b/chromium/ui/message_center/views/message_view_factory.cc index a4d78220bf9..07ed14273ea 100644 --- a/chromium/ui/message_center/views/message_view_factory.cc +++ b/chromium/ui/message_center/views/message_view_factory.cc @@ -5,9 +5,10 @@ #include "ui/message_center/views/message_view_factory.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/lazy_instance.h" -#include "ui/message_center/notification_types.h" -#include "ui/message_center/public/cpp/message_center_switches.h" +#include "ui/message_center/public/cpp/features.h" +#include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/views/notification_view.h" #include "ui/message_center/views/notification_view_md.h" @@ -35,7 +36,7 @@ MessageView* MessageViewFactory::Create(const Notification& notification, case NOTIFICATION_TYPE_SIMPLE: case NOTIFICATION_TYPE_PROGRESS: // All above roads lead to the generic NotificationView. - if (IsNewStyleNotificationEnabled()) + if (base::FeatureList::IsEnabled(message_center::kNewStyleNotifications)) notification_view = new NotificationViewMD(notification); else notification_view = new NotificationView(notification); diff --git a/chromium/ui/message_center/views/message_view_factory.h b/chromium/ui/message_center/views/message_view_factory.h index acb39f02c14..883257ebff7 100644 --- a/chromium/ui/message_center/views/message_view_factory.h +++ b/chromium/ui/message_center/views/message_view_factory.h @@ -24,8 +24,7 @@ class MESSAGE_CENTER_EXPORT MessageViewFactory { public: // A function that creates MessageView for a NOTIFICATION_TYPE_CUSTOM // notification. - typedef base::Callback<std::unique_ptr<message_center::MessageView>( - const message_center::Notification&)> + typedef base::Callback<std::unique_ptr<MessageView>(const Notification&)> CustomMessageViewFactoryFunction; static MessageView* Create(const Notification& notification, bool top_level); diff --git a/chromium/ui/message_center/views/notification_button.cc b/chromium/ui/message_center/views/notification_button.cc index f4110cce723..5f92deff742 100644 --- a/chromium/ui/message_center/views/notification_button.cc +++ b/chromium/ui/message_center/views/notification_button.cc @@ -7,7 +7,6 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/insets.h" #include "ui/message_center/public/cpp/message_center_constants.h" -#include "ui/message_center/views/constants.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/image_view.h" @@ -25,12 +24,10 @@ NotificationButton::NotificationButton(views::ButtonListener* listener) SetBackground(views::CreateSolidBackground(kNotificationBackgroundColor)); set_notify_enter_exit_on_child(true); SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::kHorizontal, - gfx::Insets(kButtonVerticalPadding, - message_center::kButtonHorizontalPadding), - message_center::kButtonIconToTitlePadding)); + views::BoxLayout::kHorizontal, gfx::Insets(0, kButtonHorizontalPadding), + kButtonIconToTitlePadding)); SetFocusPainter(views::Painter::CreateSolidFocusPainter( - message_center::kFocusBorderColor, gfx::Insets(1, 2, 2, 2))); + kFocusBorderColor, gfx::Insets(1, 2, 2, 2))); } NotificationButton::~NotificationButton() { @@ -43,41 +40,36 @@ void NotificationButton::SetIcon(const gfx::ImageSkia& image) { icon_ = NULL; } else { icon_ = new views::ImageView(); - icon_->SetImageSize(gfx::Size(message_center::kNotificationButtonIconSize, - message_center::kNotificationButtonIconSize)); + icon_->SetImageSize( + gfx::Size(kNotificationButtonIconSize, kNotificationButtonIconSize)); icon_->SetImage(image); icon_->SetHorizontalAlignment(views::ImageView::LEADING); icon_->SetVerticalAlignment(views::ImageView::LEADING); - icon_->SetBorder(views::CreateEmptyBorder( - message_center::kButtonIconTopPadding, 0, 0, 0)); + icon_->SetBorder(views::CreateEmptyBorder(kButtonIconTopPadding, 0, 0, 0)); AddChildViewAt(icon_, 0); } } void NotificationButton::SetTitle(const base::string16& title) { - if (title_ != NULL) + if (title_) delete title_; // This removes the title from this view's children. - if (title.empty()) { - title_ = NULL; - } else { + title_ = nullptr; + if (!title.empty()) { title_ = new views::Label(title); title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - title_->SetEnabledColor(message_center::kRegularTextColor); - title_->SetBackgroundColor(kRegularTextBackgroundColor); - title_->SetBorder( - views::CreateEmptyBorder(kButtonTitleTopPadding, 0, 0, 0)); + title_->SetEnabledColor(kRegularTextColor); + title_->SetAutoColorReadabilityEnabled(false); AddChildView(title_); } SetAccessibleName(title); } gfx::Size NotificationButton::CalculatePreferredSize() const { - return gfx::Size(message_center::kNotificationWidth, - message_center::kButtonHeight); + return gfx::Size(kNotificationWidth, kButtonHeight); } int NotificationButton::GetHeightForWidth(int width) const { - return message_center::kButtonHeight; + return kButtonHeight; } void NotificationButton::OnFocus() { @@ -95,8 +87,7 @@ void NotificationButton::ViewHierarchyChanged( void NotificationButton::StateChanged(ButtonState old_state) { if (state() == STATE_HOVERED || state() == STATE_PRESSED) { - SetBackground(views::CreateSolidBackground( - message_center::kHoveredButtonBackgroundColor)); + SetBackground(views::CreateSolidBackground(kHoveredButtonBackgroundColor)); } else { SetBackground(views::CreateSolidBackground(kNotificationBackgroundColor)); } diff --git a/chromium/ui/message_center/views/notification_control_buttons_view.cc b/chromium/ui/message_center/views/notification_control_buttons_view.cc index b4fb713601a..bf1dae50e71 100644 --- a/chromium/ui/message_center/views/notification_control_buttons_view.cc +++ b/chromium/ui/message_center/views/notification_control_buttons_view.cc @@ -20,6 +20,8 @@ #include "ui/views/background.h" #include "ui/views/layout/box_layout.h" +namespace message_center { + namespace { // This value should be the same as the duration of reveal animation of @@ -28,13 +30,10 @@ constexpr auto kBackgroundColorChangeDuration = base::TimeDelta::FromMilliseconds(360); // The initial background color of the view. -constexpr SkColor kInitialBackgroundColor = - message_center::kControlButtonBackgroundColor; +constexpr SkColor kInitialBackgroundColor = kControlButtonBackgroundColor; } // anonymous namespace -namespace message_center { - const char NotificationControlButtonsView::kViewClassName[] = "NotificationControlButtonsView"; @@ -58,7 +57,7 @@ NotificationControlButtonsView::~NotificationControlButtonsView() = default; void NotificationControlButtonsView::ShowCloseButton(bool show) { if (show && !close_button_) { - close_button_ = std::make_unique<message_center::PaddedButton>(this); + close_button_ = std::make_unique<PaddedButton>(this); close_button_->set_owned_by_client(); close_button_->SetImage(views::Button::STATE_NORMAL, gfx::CreateVectorIcon(kNotificationCloseButtonIcon, @@ -81,7 +80,7 @@ void NotificationControlButtonsView::ShowCloseButton(bool show) { void NotificationControlButtonsView::ShowSettingsButton(bool show) { if (show && !settings_button_) { - settings_button_ = std::make_unique<message_center::PaddedButton>(this); + settings_button_ = std::make_unique<PaddedButton>(this); settings_button_->set_owned_by_client(); settings_button_->SetImage( views::Button::STATE_NORMAL, @@ -156,7 +155,7 @@ void NotificationControlButtonsView::ButtonPressed(views::Button* sender, if (close_button_ && sender == close_button_.get()) { message_view_->OnCloseButtonPressed(); } else if (settings_button_ && sender == settings_button_.get()) { - message_view_->OnSettingsButtonPressed(); + message_view_->OnSettingsButtonPressed(event); } } diff --git a/chromium/ui/message_center/views/notification_control_buttons_view.h b/chromium/ui/message_center/views/notification_control_buttons_view.h index 31441a979dc..176221ee972 100644 --- a/chromium/ui/message_center/views/notification_control_buttons_view.h +++ b/chromium/ui/message_center/views/notification_control_buttons_view.h @@ -77,8 +77,8 @@ class MESSAGE_CENTER_EXPORT NotificationControlButtonsView private: MessageView* message_view_; - std::unique_ptr<message_center::PaddedButton> close_button_; - std::unique_ptr<message_center::PaddedButton> settings_button_; + std::unique_ptr<PaddedButton> close_button_; + std::unique_ptr<PaddedButton> settings_button_; std::unique_ptr<gfx::LinearAnimation> bgcolor_animation_; SkColor bgcolor_origin_; diff --git a/chromium/ui/message_center/views/notification_header_view.cc b/chromium/ui/message_center/views/notification_header_view.cc index d6f7a7e5f20..731494c65f6 100644 --- a/chromium/ui/message_center/views/notification_header_view.cc +++ b/chromium/ui/message_center/views/notification_header_view.cc @@ -9,6 +9,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" +#include "build/build_config.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/color_palette.h" @@ -36,27 +37,27 @@ constexpr int kHeaderHorizontalSpacing = 2; // The padding outer the header and the control buttons. constexpr gfx::Insets kHeaderOuterPadding(2, 2, 0, 2); -// Paddings of the views of texts. -// Top: 9px = 11px (from the mock) - 2px (outer padding) -// Buttom: 6px from the mock -constexpr gfx::Insets kTextViewPadding(9, 0, 6, 0); +// Default paddings of the views of texts. Adjusted on Windows. +// Top: 9px = 11px (from the mock) - 2px (outer padding). +// Buttom: 6px from the mock. +constexpr gfx::Insets kTextViewPaddingDefault(9, 0, 6, 0); // Paddings of the entire header. -// Left: 14px = 16px (from the mock) - 2px (outer padding) -// Right: 2px = minimum padding between the control buttons and the header +// Left: 14px = 16px (from the mock) - 2px (outer padding). +// Right: 2px = minimum padding between the control buttons and the header. constexpr gfx::Insets kHeaderPadding(0, 14, 0, 2); // Paddings of the app icon (small image). -// Top: 8px = 10px (from the mock) - 2px (outer padding) -// Bottom: 4px from the mock -// Right: 4px = 6px (from the mock) - kHeaderHorizontalSpacing +// Top: 8px = 10px (from the mock) - 2px (outer padding). +// Bottom: 4px from the mock. +// Right: 4px = 6px (from the mock) - kHeaderHorizontalSpacing. constexpr gfx::Insets kAppIconPadding(8, 0, 4, 4); // Size of the expand icon. 8px = 32px - 15px - 9px (values from the mock). constexpr int kExpandIconSize = 8; // Paddings of the expand buttons. -// Top: 13px = 15px (from the mock) - 2px (outer padding) -// Bottom: 9px from the mock +// Top: 13px = 15px (from the mock) - 2px (outer padding). +// Bottom: 9px from the mock. constexpr gfx::Insets kExpandIconViewPadding(13, 2, 9, 0); // Bullet character. The divider symbol between different parts of the header. @@ -115,7 +116,7 @@ void ExpandButton::OnBlur() { } void ExpandButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_BUTTON; + node_data->role = ax::mojom::Role::kButton; node_data->SetName(views::ImageView::GetTooltipText()); } @@ -157,6 +158,27 @@ gfx::FontList GetHeaderTextFontList() { return gfx::FontList(font); } +gfx::Insets CalculateTopPadding(int font_list_height) { +#if defined(OS_WIN) + // On Windows, the fonts can have slightly different metrics reported, + // depending on where the code runs. In Chrome, DirectWrite is on, which means + // font metrics are reported from Skia, which rounds from float using ceil. + // In unit tests, however, GDI is used to report metrics, and the height + // reported there is consistent with other platforms. This means there is a + // difference of 1px in height between Chrome on Windows and everything else + // (where everything else includes unit tests on Windows). This 1px causes the + // text and everything else to stop aligning correctly, so we account for it + // by shrinking the top padding by 1. + if (font_list_height != 15) { + DCHECK_EQ(16, font_list_height); + return kTextViewPaddingDefault - gfx::Insets(1 /* top */, 0, 0, 0); + } +#endif + + DCHECK_EQ(15, font_list_height); + return kTextViewPaddingDefault; +} + } // namespace NotificationHeaderView::NotificationHeaderView( @@ -188,11 +210,10 @@ NotificationHeaderView::NotificationHeaderView( DCHECK_EQ(kInnerHeaderHeight, app_icon_view_->GetPreferredSize().height()); app_info_container->AddChildView(app_icon_view_); - // Font list for text views. The height must be 15px to match with the mock. + // Font list for text views. gfx::FontList font_list = GetHeaderTextFontList(); - DCHECK_EQ(15, font_list.GetHeight()); - const int font_list_height = font_list.GetHeight(); + gfx::Insets text_view_padding(CalculateTopPadding(font_list_height)); // App name view app_name_view_ = new views::Label(base::string16()); @@ -200,7 +221,7 @@ NotificationHeaderView::NotificationHeaderView( app_name_view_->SetLineHeight(font_list_height); app_name_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); app_name_view_->SetEnabledColor(accent_color_); - app_name_view_->SetBorder(views::CreateEmptyBorder(kTextViewPadding)); + app_name_view_->SetBorder(views::CreateEmptyBorder(text_view_padding)); DCHECK_EQ(kInnerHeaderHeight, app_name_view_->GetPreferredSize().height()); app_info_container->AddChildView(app_name_view_); @@ -210,7 +231,7 @@ NotificationHeaderView::NotificationHeaderView( summary_text_divider_->SetFontList(font_list); summary_text_divider_->SetLineHeight(font_list_height); summary_text_divider_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - summary_text_divider_->SetBorder(views::CreateEmptyBorder(kTextViewPadding)); + summary_text_divider_->SetBorder(views::CreateEmptyBorder(text_view_padding)); summary_text_divider_->SetVisible(false); DCHECK_EQ(kInnerHeaderHeight, summary_text_divider_->GetPreferredSize().height()); @@ -221,7 +242,7 @@ NotificationHeaderView::NotificationHeaderView( summary_text_view_->SetFontList(font_list); summary_text_view_->SetLineHeight(font_list_height); summary_text_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - summary_text_view_->SetBorder(views::CreateEmptyBorder(kTextViewPadding)); + summary_text_view_->SetBorder(views::CreateEmptyBorder(text_view_padding)); summary_text_view_->SetVisible(false); DCHECK_EQ(kInnerHeaderHeight, summary_text_view_->GetPreferredSize().height()); @@ -233,7 +254,7 @@ NotificationHeaderView::NotificationHeaderView( timestamp_divider_->SetFontList(font_list); timestamp_divider_->SetLineHeight(font_list_height); timestamp_divider_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - timestamp_divider_->SetBorder(views::CreateEmptyBorder(kTextViewPadding)); + timestamp_divider_->SetBorder(views::CreateEmptyBorder(text_view_padding)); timestamp_divider_->SetVisible(false); DCHECK_EQ(kInnerHeaderHeight, timestamp_divider_->GetPreferredSize().height()); @@ -244,7 +265,7 @@ NotificationHeaderView::NotificationHeaderView( timestamp_view_->SetFontList(font_list); timestamp_view_->SetLineHeight(font_list_height); timestamp_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - timestamp_view_->SetBorder(views::CreateEmptyBorder(kTextViewPadding)); + timestamp_view_->SetBorder(views::CreateEmptyBorder(text_view_padding)); timestamp_view_->SetVisible(false); DCHECK_EQ(kInnerHeaderHeight, timestamp_view_->GetPreferredSize().height()); app_info_container->AddChildView(timestamp_view_); @@ -352,6 +373,14 @@ bool NotificationHeaderView::IsExpandButtonEnabled() { return expand_button_->visible(); } +void NotificationHeaderView::SetSubpixelRenderingEnabled(bool enabled) { + app_name_view_->SetSubpixelRenderingEnabled(enabled); + summary_text_divider_->SetSubpixelRenderingEnabled(enabled); + summary_text_view_->SetSubpixelRenderingEnabled(enabled); + timestamp_divider_->SetSubpixelRenderingEnabled(enabled); + timestamp_view_->SetSubpixelRenderingEnabled(enabled); +} + std::unique_ptr<views::InkDrop> NotificationHeaderView::CreateInkDrop() { return std::make_unique<views::InkDropStub>(); } diff --git a/chromium/ui/message_center/views/notification_header_view.h b/chromium/ui/message_center/views/notification_header_view.h index 7a316d38f1c..dd40f3f5ebf 100644 --- a/chromium/ui/message_center/views/notification_header_view.h +++ b/chromium/ui/message_center/views/notification_header_view.h @@ -40,6 +40,7 @@ class NotificationHeaderView : public views::Button { void ClearOverflowIndicator(); void ClearTimestamp(); bool IsExpandButtonEnabled(); + void SetSubpixelRenderingEnabled(bool enabled); // Button override: std::unique_ptr<views::InkDrop> CreateInkDrop() override; @@ -52,7 +53,7 @@ class NotificationHeaderView : public views::Button { // Update visibility for both |summary_text_view_| and |timestamp_view_|. void UpdateSummaryTextVisibility(); - SkColor accent_color_ = message_center::kNotificationDefaultAccentColor; + SkColor accent_color_ = kNotificationDefaultAccentColor; views::Label* app_name_view_ = nullptr; views::Label* summary_text_divider_ = nullptr; diff --git a/chromium/ui/message_center/views/notification_menu_model.h b/chromium/ui/message_center/views/notification_menu_model.h index 867f1f1752f..22658b74b00 100644 --- a/chromium/ui/message_center/views/notification_menu_model.h +++ b/chromium/ui/message_center/views/notification_menu_model.h @@ -8,7 +8,7 @@ #include "base/macros.h" #include "ui/base/models/simple_menu_model.h" #include "ui/message_center/message_center_export.h" -#include "ui/message_center/notification.h" +#include "ui/message_center/public/cpp/notification.h" namespace message_center { diff --git a/chromium/ui/message_center/views/notification_menu_model_unittest.cc b/chromium/ui/message_center/views/notification_menu_model_unittest.cc index e5b9f010fad..ab0ca492524 100644 --- a/chromium/ui/message_center/views/notification_menu_model_unittest.cc +++ b/chromium/ui/message_center/views/notification_menu_model_unittest.cc @@ -11,14 +11,14 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/models/menu_model.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_types.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/ui_controller.h" namespace message_center { namespace { -class TestNotificationDelegate : public message_center::NotificationDelegate { +class TestNotificationDelegate : public NotificationDelegate { public: TestNotificationDelegate() = default; @@ -54,12 +54,11 @@ class NotificationMenuModelTest : public testing::Test { Notification* AddNotification(const std::string& id, NotifierId notifier_id) { std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, id, + NOTIFICATION_TYPE_SIMPLE, id, base::ASCIIToUTF16("Test Web Notification"), base::ASCIIToUTF16("Notification message body."), gfx::Image(), base::ASCIIToUTF16("www.test.org"), GURL(), notifier_id, - message_center::RichNotificationData(), - new TestNotificationDelegate())); + RichNotificationData(), new TestNotificationDelegate())); Notification* notification_ptr = notification.get(); message_center_->AddNotification(std::move(notification)); return notification_ptr; @@ -81,11 +80,11 @@ TEST_F(NotificationMenuModelTest, ContextMenuTestWithMessageCenter) { NotifierId notifier_id2(NotifierId::APPLICATION, "sample-app"); std::unique_ptr<Notification> notification = std::make_unique<Notification>( - message_center::NOTIFICATION_TYPE_SIMPLE, id2, + NOTIFICATION_TYPE_SIMPLE, id2, base::ASCIIToUTF16("Test Web Notification"), base::ASCIIToUTF16("Notification message body."), gfx::Image(), - display_source, GURL(), notifier_id2, - message_center::RichNotificationData(), new TestNotificationDelegate()); + display_source, GURL(), notifier_id2, RichNotificationData(), + new TestNotificationDelegate()); std::unique_ptr<ui::MenuModel> model( std::make_unique<NotificationMenuModel>(*notification)); diff --git a/chromium/ui/message_center/views/notification_view.cc b/chromium/ui/message_center/views/notification_view.cc index 8b34638444c..7dc5d5d0346 100644 --- a/chromium/ui/message_center/views/notification_view.cc +++ b/chromium/ui/message_center/views/notification_view.cc @@ -23,11 +23,10 @@ #include "ui/gfx/text_elider.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_style.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_types.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/views/bounded_label.h" -#include "ui/message_center/views/constants.h" #include "ui/message_center/views/notification_button.h" #include "ui/message_center/views/notification_control_buttons_view.h" #include "ui/message_center/views/padded_button.h" @@ -52,6 +51,18 @@ namespace message_center { namespace { +const int kTextBottomPadding = 12; +const int kItemTitleToMessagePadding = 3; + +// Character limit = pixels per line * line limit / min. pixels per character. +const int kMinPixelsPerTitleCharacter = 4; + +constexpr size_t kMessageCharacterLimit = + kNotificationWidth * kMessageExpandedLineLimit / 3; + +constexpr size_t kContextMessageCharacterLimit = + kNotificationWidth * kContextMessageLineLimit / 3; + // Dimensions. const int kProgressBarBottomPadding = 0; @@ -109,14 +120,14 @@ NotificationItemView::NotificationItemView(const NotificationItem& item) { title->set_collapse_when_hidden(true); title->SetHorizontalAlignment(gfx::ALIGN_LEFT); title->SetEnabledColor(kRegularTextColor); - title->SetBackgroundColor(kRegularTextBackgroundColor); + title->SetAutoColorReadabilityEnabled(false); AddChildView(title); views::Label* message = new views::Label(item.message); message->set_collapse_when_hidden(true); message->SetHorizontalAlignment(gfx::ALIGN_LEFT); message->SetEnabledColor(kDimTextColor); - message->SetBackgroundColor(kDimTextBackgroundColor); + message->SetAutoColorReadabilityEnabled(false); AddChildView(message); PreferredSizeChanged(); @@ -391,19 +402,18 @@ void NotificationView::CreateOrUpdateTitleView( const gfx::FontList& font_list = views::Label().font_list().DeriveWithSizeDelta(2); - int title_character_limit = + constexpr int kTitleCharacterLimit = kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter; - base::string16 title = gfx::TruncateString(notification.title(), - title_character_limit, - gfx::WORD_BREAK); + base::string16 title = gfx::TruncateString( + notification.title(), kTitleCharacterLimit, gfx::WORD_BREAK); if (!title_view_) { int padding = kTitleLineHeight - font_list.GetHeight(); title_view_ = new BoundedLabel(title, font_list); title_view_->SetLineHeight(kTitleLineHeight); title_view_->SetLineLimit(kMaxTitleLines); - title_view_->SetColors(kRegularTextColor, kRegularTextBackgroundColor); + title_view_->SetColor(kRegularTextColor); title_view_->SetBorder(MakeTextBorder(padding, 3, 0)); top_view_->AddChildView(title_view_); } else { @@ -429,7 +439,7 @@ void NotificationView::CreateOrUpdateMessageView( int padding = kMessageLineHeight - views::Label().font_list().GetHeight(); message_view_ = new BoundedLabel(text); message_view_->SetLineHeight(kMessageLineHeight); - message_view_->SetColors(kRegularTextColor, kDimTextBackgroundColor); + message_view_->SetColor(kRegularTextColor); message_view_->SetBorder(MakeTextBorder(padding, 4, 0)); top_view_->AddChildView(message_view_); } else { @@ -473,8 +483,7 @@ void NotificationView::CreateOrUpdateContextMessageView( context_message_view_ = new BoundedLabel(message); context_message_view_->SetLineLimit(kContextMessageLineLimit); context_message_view_->SetLineHeight(kMessageLineHeight); - context_message_view_->SetColors(kDimTextColor, - kContextTextBackgroundColor); + context_message_view_->SetColor(kDimTextColor); context_message_view_->SetBorder(MakeTextBorder(padding, 4, 0)); top_view_->AddChildView(context_message_view_); } else { diff --git a/chromium/ui/message_center/views/notification_view.h b/chromium/ui/message_center/views/notification_view.h index c1da69280ed..f1f0e2fbdef 100644 --- a/chromium/ui/message_center/views/notification_view.h +++ b/chromium/ui/message_center/views/notification_view.h @@ -85,7 +85,7 @@ class MESSAGE_CENTER_EXPORT NotificationView void CreateOrUpdateSmallIconView(const Notification& notification); void CreateOrUpdateImageView(const Notification& notification); void CreateOrUpdateActionButtonViews(const Notification& notification); - // TODO(yoshiki): Move this to message_center::MessageView + // TODO(yoshiki): Move this to MessageView void UpdateControlButtonsVisibilityWithNotification( const Notification& notification); diff --git a/chromium/ui/message_center/views/notification_view_md.cc b/chromium/ui/message_center/views/notification_view_md.cc index fa12e58aa31..eaf1c4852b6 100644 --- a/chromium/ui/message_center/views/notification_view_md.cc +++ b/chromium/ui/message_center/views/notification_view_md.cc @@ -13,23 +13,24 @@ #include "ui/base/cursor/cursor.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/text_elider.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_types.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/vector_icons.h" #include "ui/message_center/views/bounded_label.h" -#include "ui/message_center/views/constants.h" #include "ui/message_center/views/notification_control_buttons_view.h" #include "ui/message_center/views/notification_header_view.h" #include "ui/message_center/views/padded_button.h" #include "ui/message_center/views/proportional_image_view.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -64,31 +65,37 @@ constexpr gfx::Size kLargeImageMinSize(328, 0); constexpr gfx::Size kLargeImageMaxSize(328, 218); constexpr gfx::Insets kLeftContentPadding(2, 4, 0, 4); constexpr gfx::Insets kLeftContentPaddingWithIcon(2, 4, 0, 12); -constexpr gfx::Insets kNotificationInputPadding(0, 16, 0, 16); +constexpr gfx::Insets kInputTextfieldPadding(16, 16, 16, 0); +constexpr gfx::Insets kInputReplyButtonPadding(0, 14, 0, 14); constexpr gfx::Insets kSettingsRowPadding(8, 0, 0, 0); constexpr gfx::Insets kSettingsRadioButtonPadding(14, 18, 14, 18); constexpr gfx::Insets kSettingsButtonRowPadding(8); // Background of inline actions area. -const SkColor kActionsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee); -// Base ink drop color of action buttons. -const SkColor kActionButtonInkDropBaseColor = SkColorSetRGB(0x0, 0x0, 0x0); +constexpr SkColor kActionsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee); // Ripple ink drop opacity of action buttons. const float kActionButtonInkDropRippleVisibleOpacity = 0.08f; // Highlight (hover) ink drop opacity of action buttons. const float kActionButtonInkDropHighlightVisibleOpacity = 0.08f; // Text color of action button. -const SkColor kActionButtonTextColor = SkColorSetRGB(0x33, 0x67, 0xD6); +constexpr SkColor kActionButtonTextColor = gfx::kGoogleBlue700; // Background color of the large image. -const SkColor kLargeImageBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5); +constexpr SkColor kLargeImageBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5); -const SkColor kRegularTextColorMD = SkColorSetRGB(0x21, 0x21, 0x21); -const SkColor kDimTextColorMD = SkColorSetRGB(0x75, 0x75, 0x75); +constexpr SkColor kRegularTextColorMD = SkColorSetRGB(0x21, 0x21, 0x21); +constexpr SkColor kDimTextColorMD = SkColorSetRGB(0x75, 0x75, 0x75); -// The text color and the background color of inline reply input field. -const SkColor kInputTextColor = SkColorSetRGB(0xFF, 0xFF, 0xFF); -const SkColor kInputPlaceholderColor = SkColorSetARGB(0x8A, 0xFF, 0xFF, 0xFF); -const SkColor kInputBackgroundColor = SkColorSetRGB(0x33, 0x67, 0xD6); +// Background of inline settings area. +const SkColor kSettingsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee); + +// Text color and icon color of inline reply area when the textfield is empty. +constexpr SkColor kTextfieldPlaceholderTextColorMD = + SkColorSetA(SK_ColorWHITE, 0x8A); +constexpr SkColor kTextfieldPlaceholderIconColorMD = + SkColorSetA(SK_ColorWHITE, 0x60); + +// The icon size of inline reply input field. +constexpr int kInputReplyButtonSize = 20; // Max number of lines for message_view_. constexpr int kMaxLinesForMessageView = 1; @@ -99,17 +106,23 @@ constexpr int kCompactTitleMessageViewSpacing = 12; constexpr int kProgressBarHeight = 4; constexpr int kMessageViewWidthWithIcon = - message_center::kNotificationWidth - kIconViewSize.width() - + kNotificationWidth - kIconViewSize.width() - kLeftContentPaddingWithIcon.left() - kLeftContentPaddingWithIcon.right() - kContentRowPadding.left() - kContentRowPadding.right(); constexpr int kMessageViewWidth = - message_center::kNotificationWidth - kLeftContentPadding.left() - + kNotificationWidth - kLeftContentPadding.left() - kLeftContentPadding.right() - kContentRowPadding.left() - kContentRowPadding.right(); -// "Roboto-Regular, 13sp" is specified in the mock. -constexpr int kTextFontSize = 13; +const int kMinPixelsPerTitleCharacterMD = 4; + +// Character limit = pixels per line * line limit / min. pixels per character. +constexpr size_t kMessageCharacterLimitMD = + kNotificationWidth * kMessageExpandedLineLimit / 3; + +// The default is 12, so this normally come out to 13. +constexpr int kTextFontSizeDelta = 1; // In progress notification, if both the title and the message are long, the // message would be prioritized and the title would be elided. @@ -117,13 +130,21 @@ constexpr int kTextFontSize = 13; // the ratio of the message width is limited to this value. constexpr double kProgressNotificationMessageRatio = 0.7; +// Users on ChromeOS are used to the Settings and Close buttons not being +// visible at all times, but users on other platforms expect them to be visible. +constexpr bool AlwaysShowControlButtons() { +#if defined(OS_CHROMEOS) + return false; +#else + return true; +#endif +} + // FontList for the texts except for the header. gfx::FontList GetTextFontList() { gfx::Font default_font; - int font_size_delta = kTextFontSize - default_font.GetFontSize(); - gfx::Font font = default_font.Derive(font_size_delta, gfx::Font::NORMAL, + gfx::Font font = default_font.Derive(kTextFontSizeDelta, gfx::Font::NORMAL, gfx::Font::Weight::NORMAL); - DCHECK_EQ(kTextFontSize, font.GetFontSize()); return gfx::FontList(font); } @@ -150,7 +171,7 @@ class ClickActivator : public ui::EventHandler { // ItemView //////////////////////////////////////////////////////////////////// -ItemView::ItemView(const message_center::NotificationItem& item) { +ItemView::ItemView(const NotificationItem& item) { SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::kHorizontal, gfx::Insets(), 0)); @@ -160,8 +181,8 @@ ItemView::ItemView(const message_center::NotificationItem& item) { title->SetFontList(font_list); title->set_collapse_when_hidden(true); title->SetHorizontalAlignment(gfx::ALIGN_LEFT); - title->SetEnabledColor(message_center::kRegularTextColorMD); - title->SetBackgroundColor(message_center::kDimTextBackgroundColor); + title->SetEnabledColor(kRegularTextColorMD); + title->SetAutoColorReadabilityEnabled(false); AddChildView(title); views::Label* message = new views::Label(l10n_util::GetStringFUTF16( @@ -170,7 +191,7 @@ ItemView::ItemView(const message_center::NotificationItem& item) { message->set_collapse_when_hidden(true); message->SetHorizontalAlignment(gfx::ALIGN_LEFT); message->SetEnabledColor(kDimTextColorMD); - message->SetBackgroundColor(message_center::kDimTextBackgroundColor); + message->SetAutoColorReadabilityEnabled(false); AddChildView(message); } @@ -189,29 +210,30 @@ const char* CompactTitleMessageView::GetClassName() const { } CompactTitleMessageView::CompactTitleMessageView() { - SetLayoutManager(std::make_unique<views::FillLayout>()); - const gfx::FontList& font_list = GetTextFontList(); - title_view_ = new views::Label(); - title_view_->SetFontList(font_list); - title_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - title_view_->SetEnabledColor(kRegularTextColorMD); - AddChildView(title_view_); - - message_view_ = new views::Label(); - message_view_->SetFontList(font_list); - message_view_->SetHorizontalAlignment(gfx::ALIGN_RIGHT); - message_view_->SetEnabledColor(kDimTextColorMD); - AddChildView(message_view_); + title_ = new views::Label(); + title_->SetFontList(font_list); + title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + title_->SetEnabledColor(kRegularTextColorMD); + AddChildView(title_); + + message_ = new views::Label(); + message_->SetFontList(font_list); + message_->SetHorizontalAlignment(gfx::ALIGN_RIGHT); + message_->SetEnabledColor(kDimTextColorMD); + AddChildView(message_); } -void CompactTitleMessageView::OnPaint(gfx::Canvas* canvas) { - base::string16 title = title_; - base::string16 message = message_; - - const gfx::FontList& font_list = GetTextFontList(); +gfx::Size CompactTitleMessageView::CalculatePreferredSize() const { + gfx::Size title_size = title_->GetPreferredSize(); + gfx::Size message_size = message_->GetPreferredSize(); + return gfx::Size(title_size.width() + message_size.width() + + kCompactTitleMessageViewSpacing, + std::max(title_size.height(), message_size.height())); +} +void CompactTitleMessageView::Layout() { // Elides title and message. // * If the message is too long, the message occupies at most // kProgressNotificationMessageRatio of the width. @@ -220,21 +242,24 @@ void CompactTitleMessageView::OnPaint(gfx::Canvas* canvas) { // title is shown. // * If they are short enough, the title is left-aligned and the message is // right-aligned. - message = gfx::ElideText( - message, font_list, - title.empty() - ? width() - : static_cast<int>(kProgressNotificationMessageRatio * width()), - gfx::ELIDE_TAIL); - const int message_width = gfx::Canvas::GetStringWidthF(message, font_list); + const int message_width = std::min( + message_->GetPreferredSize().width(), + title_->GetPreferredSize().width() > 0 + ? static_cast<int>(kProgressNotificationMessageRatio * width()) + : width()); const int title_width = std::max(0, width() - message_width - kCompactTitleMessageViewSpacing); - title = gfx::ElideText(title, font_list, title_width, gfx::ELIDE_TAIL); - title_view_->SetText(title); - message_view_->SetText(message); + title_->SetBounds(0, 0, title_width, height()); + message_->SetBounds(width() - message_width, 0, message_width, height()); +} - views::View::OnPaint(canvas); +void CompactTitleMessageView::set_title(const base::string16& title) { + title_->SetText(title); +} + +void CompactTitleMessageView::set_message(const base::string16& message) { + message_->SetText(message); } // LargeImageView ////////////////////////////////////////////////////////////// @@ -301,8 +326,7 @@ LargeImageContainerView::LargeImageContainerView() : image_view_(new LargeImageView()) { SetLayoutManager(std::make_unique<views::FillLayout>()); SetBorder(views::CreateEmptyBorder(kLargeImageContainerPadding)); - SetBackground( - views::CreateSolidBackground(message_center::kImageBackgroundColor)); + SetBackground(views::CreateSolidBackground(kImageBackgroundColor)); AddChildView(image_view_); } @@ -318,19 +342,18 @@ const char* LargeImageContainerView::GetClassName() const { // NotificationButtonMD //////////////////////////////////////////////////////// -NotificationButtonMD::NotificationButtonMD(views::ButtonListener* listener, - bool is_inline_reply, - const base::string16& label, - const base::string16& placeholder) +NotificationButtonMD::NotificationButtonMD( + views::ButtonListener* listener, + const base::string16& label, + const base::Optional<base::string16>& placeholder) : views::LabelButton(listener, base::i18n::ToUpper(label), views::style::CONTEXT_BUTTON_MD), - is_inline_reply_(is_inline_reply), placeholder_(placeholder) { SetHorizontalAlignment(gfx::ALIGN_CENTER); SetInkDropMode(views::LabelButton::InkDropMode::ON); set_has_ink_drop_action_on_click(true); - set_ink_drop_base_color(kActionButtonInkDropBaseColor); + set_ink_drop_base_color(SK_ColorBLACK); set_ink_drop_visible_opacity(kActionButtonInkDropRippleVisibleOpacity); SetEnabledTextColors(kActionButtonTextColor); SetBorder(views::CreateEmptyBorder(kActionButtonPadding)); @@ -356,35 +379,141 @@ NotificationButtonMD::CreateInkDropHighlight() const { return highlight; } -// NotificationInputMD ///////////////////////////////////////////////////////// +// NotificationInputTextfieldMD //////////////////////////////////////////////// -NotificationInputMD::NotificationInputMD(NotificationInputDelegate* delegate) - : delegate_(delegate), index_(0) { - set_controller(this); - SetTextColor(kInputTextColor); - SetBackgroundColor(kInputBackgroundColor); - set_placeholder_text_color(kInputPlaceholderColor); - SetBorder(views::CreateEmptyBorder(kNotificationInputPadding)); +NotificationInputTextfieldMD::NotificationInputTextfieldMD( + views::TextfieldController* controller) + : index_(0) { + set_controller(controller); + SetTextColor(SK_ColorWHITE); + SetBackgroundColor(SK_ColorTRANSPARENT); + set_placeholder_text_color(kTextfieldPlaceholderTextColorMD); + SetBorder(views::CreateEmptyBorder(kInputTextfieldPadding)); } -NotificationInputMD::~NotificationInputMD() = default; +NotificationInputTextfieldMD::~NotificationInputTextfieldMD() = default; + +void NotificationInputTextfieldMD::set_placeholder( + const base::string16& placeholder) { + if (placeholder.empty()) { + set_placeholder_text(l10n_util::GetStringUTF16( + IDS_MESSAGE_CENTER_NOTIFICATION_INLINE_REPLY_PLACEHOLDER)); + } else { + set_placeholder_text(placeholder); + } +} + +// NotificationInputReplyButtonMD ////////////////////////////////////////////// + +NotificationInputReplyButtonMD::NotificationInputReplyButtonMD( + views::ButtonListener* listener) + : views::ImageButton(listener) { + SetPlaceholderImage(); + SetBorder(views::CreateEmptyBorder(kInputReplyButtonPadding)); + SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE); +} + +NotificationInputReplyButtonMD::~NotificationInputReplyButtonMD() = default; + +void NotificationInputReplyButtonMD::SetNormalImage() { + SetImage(STATE_NORMAL, + gfx::CreateVectorIcon(kNotificationInlineReplyIcon, + kInputReplyButtonSize, SK_ColorWHITE)); +} -bool NotificationInputMD::HandleKeyEvent(views::Textfield* sender, - const ui::KeyEvent& event) { +void NotificationInputReplyButtonMD::SetPlaceholderImage() { + SetImage( + STATE_NORMAL, + gfx::CreateVectorIcon(kNotificationInlineReplyIcon, kInputReplyButtonSize, + kTextfieldPlaceholderIconColorMD)); +} + +// NotificationInputContainerMD //////////////////////////////////////////////// + +NotificationInputContainerMD::NotificationInputContainerMD( + NotificationInputDelegate* delegate) + : delegate_(delegate), + ink_drop_container_(new views::InkDropContainerView()), + textfield_(new NotificationInputTextfieldMD(this)), + button_(new NotificationInputReplyButtonMD(this)) { + auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::kHorizontal, gfx::Insets(), 0)); + SetBackground(views::CreateSolidBackground(kActionsRowBackgroundColor)); + + SetInkDropMode(InkDropMode::ON); + set_ink_drop_visible_opacity(1); + + ink_drop_container_->SetPaintToLayer(); + ink_drop_container_->layer()->SetFillsBoundsOpaquely(false); + AddChildView(ink_drop_container_); + + AddChildView(textfield_); + layout->SetFlexForView(textfield_, 1); + + AddChildView(button_); +} + +NotificationInputContainerMD::~NotificationInputContainerMD() = default; + +void NotificationInputContainerMD::AnimateBackground( + const ui::LocatedEvent& event) { + if (View::HitTestPoint(event.location())) + AnimateInkDrop(views::InkDropState::ACTION_PENDING, + ui::LocatedEvent::FromIfValid(&event)); +} + +void NotificationInputContainerMD::AddInkDropLayer(ui::Layer* ink_drop_layer) { + textfield_->SetPaintToLayer(); + textfield_->layer()->SetFillsBoundsOpaquely(false); + button_->SetPaintToLayer(); + button_->layer()->SetFillsBoundsOpaquely(false); + ink_drop_container_->AddInkDropLayer(ink_drop_layer); + InstallInkDropMask(ink_drop_layer); +} + +void NotificationInputContainerMD::RemoveInkDropLayer( + ui::Layer* ink_drop_layer) { + textfield_->DestroyLayer(); + button_->DestroyLayer(); + ResetInkDropMask(); + ink_drop_container_->RemoveInkDropLayer(ink_drop_layer); +} + +std::unique_ptr<views::InkDropRipple> +NotificationInputContainerMD::CreateInkDropRipple() const { + return std::make_unique<views::FloodFillInkDropRipple>( + size(), GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(), + ink_drop_visible_opacity()); +} + +SkColor NotificationInputContainerMD::GetInkDropBaseColor() const { + return gfx::kGoogleBlue700; +} + +bool NotificationInputContainerMD::HandleKeyEvent(views::Textfield* sender, + const ui::KeyEvent& event) { if (event.type() == ui::ET_KEY_PRESSED && event.key_code() == ui::VKEY_RETURN) { - delegate_->OnNotificationInputSubmit(index_, text()); + delegate_->OnNotificationInputSubmit(textfield_->index(), + textfield_->text()); return true; } return event.type() == ui::ET_KEY_RELEASED; } -void NotificationInputMD::set_placeholder(const base::string16& placeholder) { - if (placeholder.empty()) { - set_placeholder_text(l10n_util::GetStringUTF16( - IDS_MESSAGE_CENTER_NOTIFICATION_INLINE_REPLY_PLACEHOLDER)); +void NotificationInputContainerMD::OnAfterUserAction(views::Textfield* sender) { + if (textfield_->text().empty()) { + button_->SetPlaceholderImage(); } else { - set_placeholder_text(placeholder); + button_->SetNormalImage(); + } +} + +void NotificationInputContainerMD::ButtonPressed(views::Button* sender, + const ui::Event& event) { + if (sender == button_) { + delegate_->OnNotificationInputSubmit(textfield_->index(), + textfield_->text()); } } @@ -396,6 +525,7 @@ class InlineSettingsRadioButton : public views::RadioButton { : views::RadioButton(label_text, 1 /* group */, true /* force_md */) { label()->SetFontList(GetTextFontList()); label()->SetEnabledColor(kRegularTextColorMD); + label()->SetSubpixelRenderingEnabled(false); } }; @@ -460,10 +590,18 @@ void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) { } NotificationViewMD::NotificationViewMD(const Notification& notification) - : MessageView(notification), clickable_(notification.clickable()) { + : MessageView(notification), + ink_drop_container_(new views::InkDropContainerView()), + clickable_(notification.clickable()) { SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::kVertical, gfx::Insets(), 0)); + set_ink_drop_visible_opacity(1); + + ink_drop_container_->SetPaintToLayer(); + ink_drop_container_->layer()->SetFillsBoundsOpaquely(false); + AddChildView(ink_drop_container_); + control_buttons_view_ = std::make_unique<NotificationControlButtonsView>(this); control_buttons_view_->set_owned_by_client(); @@ -511,10 +649,9 @@ NotificationViewMD::NotificationViewMD(const Notification& notification) action_buttons_row_->SetVisible(false); actions_row_->AddChildView(action_buttons_row_); - // |inline_reply_| is a textfield for inline reply. - inline_reply_ = new NotificationInputMD(this); + // |inline_reply_| is a container for an inline textfield. + inline_reply_ = new NotificationInputContainerMD(this); inline_reply_->SetVisible(false); - actions_row_->AddChildView(inline_reply_); CreateOrUpdateViews(notification); @@ -561,6 +698,16 @@ void NotificationViewMD::Layout() { action_buttons_row_->set_clip_path(path); inline_reply_->set_clip_path(path); } + + // The animation is needed to run inside of the border, which is shown only + // when the notification is nested. + if (is_nested()) { + gfx::Rect ink_drop_bounds = GetLocalBounds(); + ink_drop_bounds.Inset(gfx::Insets(kNotificationBorderThickness)); + ink_drop_container_->SetBoundsRect(ink_drop_bounds); + } else { + ink_drop_container_->SetBoundsRect(GetLocalBounds()); + } } void NotificationViewMD::OnFocus() { @@ -595,16 +742,6 @@ gfx::NativeCursor NotificationViewMD::GetCursor(const ui::MouseEvent& event) { return views::GetNativeHandCursor(); } -void NotificationViewMD::OnMouseEntered(const ui::MouseEvent& event) { - MessageView::OnMouseEntered(event); - UpdateControlButtonsVisibility(); -} - -void NotificationViewMD::OnMouseExited(const ui::MouseEvent& event) { - MessageView::OnMouseExited(event); - UpdateControlButtonsVisibility(); -} - bool NotificationViewMD::OnMousePressed(const ui::MouseEvent& event) { if (!event.IsOnlyLeftMouseButton()) return false; @@ -625,6 +762,20 @@ bool NotificationViewMD::OnMousePressed(const ui::MouseEvent& event) { return MessageView::OnMousePressed(event); } +void NotificationViewMD::OnMouseEvent(ui::MouseEvent* event) { + switch (event->type()) { + case ui::ET_MOUSE_ENTERED: + UpdateControlButtonsVisibility(); + break; + case ui::ET_MOUSE_EXITED: + UpdateControlButtonsVisibility(); + break; + default: + break; + } + View::OnMouseEvent(event); +} + void NotificationViewMD::UpdateWithNotification( const Notification& notification) { MessageView::UpdateWithNotification(notification); @@ -654,7 +805,8 @@ void NotificationViewMD::ButtonPressed(views::Button* sender, // Tapping anywhere on |header_row_| can expand the notification, though only // |expand_button| can be focused by TAB. if (sender == header_row_) { - if (IsExpandable()) { + if (IsExpandable() && content_row_->visible()) { + SetManuallyExpandedOrCollapsed(true); ToggleExpanded(); Layout(); SchedulePaint(); @@ -666,9 +818,12 @@ void NotificationViewMD::ButtonPressed(views::Button* sender, for (size_t i = 0; i < action_buttons_.size(); ++i) { if (sender != action_buttons_[i]) continue; - if (action_buttons_[i]->is_inline_reply()) { - inline_reply_->set_index(i); - inline_reply_->set_placeholder(action_buttons_[i]->placeholder()); + if (action_buttons_[i]->placeholder()) { + inline_reply_->textfield()->set_index(i); + inline_reply_->textfield()->set_placeholder( + *action_buttons_[i]->placeholder()); + inline_reply_->textfield()->RequestFocus(); + inline_reply_->AnimateBackground(*event.AsLocatedEvent()); inline_reply_->SetVisible(true); action_buttons_row_->SetVisible(false); Layout(); @@ -682,7 +837,7 @@ void NotificationViewMD::ButtonPressed(views::Button* sender, if (sender == settings_done_button_) { if (block_all_button_->checked()) MessageCenter::Get()->DisableNotification(id); - ToggleInlineSettings(); + ToggleInlineSettings(event); return; } } @@ -703,10 +858,9 @@ void NotificationViewMD::RequestFocusOnCloseButton() { void NotificationViewMD::CreateOrUpdateContextTitleView( const Notification& notification) { - header_row_->SetAccentColor( - notification.accent_color() == SK_ColorTRANSPARENT - ? message_center::kNotificationDefaultAccentColor - : notification.accent_color()); + header_row_->SetAccentColor(notification.accent_color() == SK_ColorTRANSPARENT + ? kNotificationDefaultAccentColor + : notification.accent_color()); header_row_->SetTimestamp(notification.timestamp()); base::string16 app_name = notification.display_source(); @@ -733,7 +887,7 @@ void NotificationViewMD::CreateOrUpdateTitleView( } int title_character_limit = - kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter; + kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacterMD; base::string16 title = gfx::TruncateString( notification.title(), title_character_limit, gfx::WORD_BREAK); @@ -761,14 +915,14 @@ void NotificationViewMD::CreateOrUpdateMessageView( } base::string16 text = gfx::TruncateString( - notification.message(), kMessageCharacterLimit, gfx::WORD_BREAK); + notification.message(), kMessageCharacterLimitMD, gfx::WORD_BREAK); const gfx::FontList& font_list = GetTextFontList(); if (!message_view_) { message_view_ = new BoundedLabel(text, font_list); message_view_->SetLineLimit(kMaxLinesForMessageView); - message_view_->SetColors(kDimTextColorMD, kContextTextBackgroundColor); + message_view_->SetColor(kDimTextColorMD); left_content_->AddChildView(message_view_); } else { @@ -812,8 +966,8 @@ void NotificationViewMD::CreateOrUpdateProgressBarView( if (!progress_bar_view_) { progress_bar_view_ = new views::ProgressBar(kProgressBarHeight, /* allow_round_corner */ false); - progress_bar_view_->SetBorder(views::CreateEmptyBorder( - message_center::kProgressBarTopPadding, 0, 0, 0)); + progress_bar_view_->SetBorder( + views::CreateEmptyBorder(kProgressBarTopPadding, 0, 0, 0)); left_content_->AddChildView(progress_bar_view_); } @@ -875,8 +1029,13 @@ void NotificationViewMD::CreateOrUpdateListItemViews( void NotificationViewMD::CreateOrUpdateIconView( const Notification& notification) { + const bool use_image_for_icon = notification.icon().IsEmpty(); + + gfx::ImageSkia icon = use_image_for_icon ? notification.image().AsImageSkia() + : notification.icon().AsImageSkia(); + if (notification.type() == NOTIFICATION_TYPE_PROGRESS || - notification.type() == NOTIFICATION_TYPE_MULTIPLE) { + notification.type() == NOTIFICATION_TYPE_MULTIPLE || icon.isNull()) { DCHECK(!icon_view_ || right_content_->Contains(icon_view_)); delete icon_view_; icon_view_ = nullptr; @@ -888,12 +1047,6 @@ void NotificationViewMD::CreateOrUpdateIconView( right_content_->AddChildView(icon_view_); } - const bool use_image_for_icon = notification.icon().IsEmpty(); - gfx::ImageSkia icon; - if (use_image_for_icon) - icon = notification.image().AsImageSkia(); - else - icon = notification.icon().AsImageSkia(); icon_view_->SetImage(icon, icon.size()); // Hide the icon on the right side when the notification is expanded. @@ -902,10 +1055,15 @@ void NotificationViewMD::CreateOrUpdateIconView( void NotificationViewMD::CreateOrUpdateSmallIconView( const Notification& notification) { - if (notification.small_image().IsEmpty()) - header_row_->ClearAppIcon(); - else + if (!notification.vector_small_image().is_empty()) { + header_row_->SetAppIcon( + gfx::CreateVectorIcon(notification.vector_small_image(), + kSmallImageSizeMD, notification.accent_color())); + } else if (!notification.small_image().IsEmpty()) { header_row_->SetAppIcon(notification.small_image().AsImageSkia()); + } else { + header_row_->ClearAppIcon(); + } } void NotificationViewMD::CreateOrUpdateImageView( @@ -930,7 +1088,7 @@ void NotificationViewMD::CreateOrUpdateImageView( void NotificationViewMD::CreateOrUpdateActionButtonViews( const Notification& notification) { - std::vector<ButtonInfo> buttons = notification.buttons(); + const std::vector<ButtonInfo>& buttons = notification.buttons(); bool new_buttons = action_buttons_.size() != buttons.size(); if (new_buttons || buttons.size() == 0) { @@ -944,10 +1102,8 @@ void NotificationViewMD::CreateOrUpdateActionButtonViews( for (size_t i = 0; i < buttons.size(); ++i) { ButtonInfo button_info = buttons[i]; if (new_buttons) { - bool is_inline_reply = - button_info.type == message_center::ButtonType::TEXT; NotificationButtonMD* button = new NotificationButtonMD( - this, is_inline_reply, button_info.title, button_info.placeholder); + this, button_info.title, button_info.placeholder); action_buttons_.push_back(button); action_buttons_row_->AddChildView(button); } else { @@ -980,13 +1136,13 @@ void NotificationViewMD::CreateOrUpdateActionButtonViews( void NotificationViewMD::CreateOrUpdateInlineSettingsViews( const Notification& notification) { if (settings_row_) { - DCHECK_EQ(SettingsButtonHandler::TRAY, + DCHECK_EQ(SettingsButtonHandler::INLINE, notification.rich_notification_data().settings_button_handler); return; } if (notification.rich_notification_data().settings_button_handler != - SettingsButtonHandler::TRAY) { + SettingsButtonHandler::INLINE) { return; } @@ -994,11 +1150,28 @@ void NotificationViewMD::CreateOrUpdateInlineSettingsViews( settings_row_ = new views::View(); settings_row_->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::kVertical, kSettingsRowPadding, 0)); - settings_row_->SetBackground( - views::CreateSolidBackground(kActionsRowBackgroundColor)); + + int block_notifications_message_id = 0; + switch (notification.notifier_id().type) { + case NotifierId::APPLICATION: + case NotifierId::ARC_APPLICATION: + block_notifications_message_id = + IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS_APP; + break; + case NotifierId::WEB_PAGE: + block_notifications_message_id = + IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS_SITE; + break; + case NotifierId::SYSTEM_COMPONENT: + case NotifierId::SIZE: + block_notifications_message_id = + IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS; + break; + } + DCHECK_NE(block_notifications_message_id, 0); block_all_button_ = new InlineSettingsRadioButton( - l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS)); + l10n_util::GetStringUTF16(block_notifications_message_id)); block_all_button_->set_listener(this); block_all_button_->SetBorder( views::CreateEmptyBorder(kSettingsRadioButtonPadding)); @@ -1013,8 +1186,10 @@ void NotificationViewMD::CreateOrUpdateInlineSettingsViews( settings_row_->SetVisible(false); settings_done_button_ = new NotificationButtonMD( - this, false, l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS_DONE), - base::EmptyString16()); + this, l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS_DONE), + base::nullopt); + settings_done_button_->SetTextSubpixelRenderingEnabled(false); + auto* settings_button_row = new views::View; auto settings_button_layout = std::make_unique<views::BoxLayout>( views::BoxLayout::kHorizontal, kSettingsButtonRowPadding, 0); @@ -1078,10 +1253,9 @@ void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { list_items_count_ - (expanded ? item_views_.size() : kMaxLinesForMessageView)); - if (icon_view_) - icon_view_->SetVisible(!hide_icon_on_expanded_ || !expanded); - - if (icon_view_ && icon_view_->visible()) { + right_content_->SetVisible(icon_view_ && + (!hide_icon_on_expanded_ || !expanded)); + if (right_content_->visible()) { left_content_->SetBorder( views::CreateEmptyBorder(kLeftContentPaddingWithIcon)); @@ -1099,34 +1273,38 @@ void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { } } -void NotificationViewMD::ToggleInlineSettings() { +void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) { DCHECK(settings_row_); bool inline_settings_visible = !settings_row_->visible(); settings_row_->SetVisible(inline_settings_visible); content_row_->SetVisible(!inline_settings_visible); - actions_row_->SetVisible(expanded_ && !inline_settings_visible); - - // When inline settings is shown, the background color of the entire - // notification should be |kActionsRowBackgroundColor|. - header_row_->SetBackground(views::CreateSolidBackground( - inline_settings_visible ? kActionsRowBackgroundColor - : kNotificationBackgroundColor)); // Always check "Don't block" when inline settings is shown. // If it's already blocked, users should not see inline settings. // Toggling should reset the state. dont_block_button_->SetChecked(true); + SetExpanded(!inline_settings_visible); + PreferredSizeChanged(); + + if (inline_settings_visible) + AddBackgroundAnimation(event); + else + RemoveBackgroundAnimation(); + + Layout(); + SchedulePaint(); } // TODO(yoshiki): Move this to the parent class (MessageView) and share the code // among NotificationView and ArcNotificationView. void NotificationViewMD::UpdateControlButtonsVisibility() { const bool target_visibility = - IsMouseHovered() || control_buttons_view_->IsCloseButtonFocused() || + AlwaysShowControlButtons() || IsMouseHovered() || + control_buttons_view_->IsCloseButtonFocused() || control_buttons_view_->IsSettingsButtonFocused(); control_buttons_view_->SetVisible(target_visibility); @@ -1151,11 +1329,19 @@ void NotificationViewMD::SetExpanded(bool expanded) { PreferredSizeChanged(); } -void NotificationViewMD::OnSettingsButtonPressed() { +bool NotificationViewMD::IsManuallyExpandedOrCollapsed() const { + return manually_expanded_or_collapsed_; +} + +void NotificationViewMD::SetManuallyExpandedOrCollapsed(bool value) { + manually_expanded_or_collapsed_ = value; +} + +void NotificationViewMD::OnSettingsButtonPressed(const ui::Event& event) { if (settings_row_) - ToggleInlineSettings(); + ToggleInlineSettings(event); else - MessageView::OnSettingsButtonPressed(); + MessageView::OnSettingsButtonPressed(event); } void NotificationViewMD::Activate() { @@ -1163,4 +1349,78 @@ void NotificationViewMD::Activate() { GetWidget()->Activate(); } +void NotificationViewMD::AddBackgroundAnimation(const ui::Event& event) { + SetInkDropMode(InkDropMode::ON); + // In case the animation is triggered from keyboard operation. + if (!event.IsLocatedEvent()) { + AnimateInkDrop(views::InkDropState::ACTION_PENDING, nullptr); + return; + } + + // Convert the point of |event| from the coordinate system of + // |control_buttons_view_| to that of NotificationViewMD, create a new + // LocatedEvent which has the new point. + views::View* target = static_cast<views::View*>(event.target()); + const gfx::Point& location = event.AsLocatedEvent()->location(); + gfx::Point converted_location(location); + View::ConvertPointToTarget(target, this, &converted_location); + std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(event); + ui::LocatedEvent* cloned_located_event = cloned_event->AsLocatedEvent(); + cloned_located_event->set_location(converted_location); + + if (View::HitTestPoint(event.AsLocatedEvent()->location())) { + AnimateInkDrop(views::InkDropState::ACTION_PENDING, + ui::LocatedEvent::FromIfValid(cloned_located_event)); + } +} + +void NotificationViewMD::RemoveBackgroundAnimation() { + AnimateInkDrop(views::InkDropState::HIDDEN, nullptr); +} + +void NotificationViewMD::AddInkDropLayer(ui::Layer* ink_drop_layer) { + GetInkDrop()->AddObserver(this); + header_row_->SetPaintToLayer(); + header_row_->layer()->SetFillsBoundsOpaquely(false); + block_all_button_->SetPaintToLayer(); + block_all_button_->layer()->SetFillsBoundsOpaquely(false); + dont_block_button_->SetPaintToLayer(); + dont_block_button_->layer()->SetFillsBoundsOpaquely(false); + settings_done_button_->SetPaintToLayer(); + settings_done_button_->layer()->SetFillsBoundsOpaquely(false); + ink_drop_container_->AddInkDropLayer(ink_drop_layer); + InstallInkDropMask(ink_drop_layer); +} + +void NotificationViewMD::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { + header_row_->DestroyLayer(); + block_all_button_->DestroyLayer(); + dont_block_button_->DestroyLayer(); + settings_done_button_->DestroyLayer(); + ResetInkDropMask(); + ink_drop_container_->RemoveInkDropLayer(ink_drop_layer); + GetInkDrop()->RemoveObserver(this); +} + +std::unique_ptr<views::InkDropRipple> NotificationViewMD::CreateInkDropRipple() + const { + return std::make_unique<views::FloodFillInkDropRipple>( + ink_drop_container_->size(), GetInkDropCenterBasedOnLastEvent(), + GetInkDropBaseColor(), ink_drop_visible_opacity()); +} + +SkColor NotificationViewMD::GetInkDropBaseColor() const { + return kSettingsRowBackgroundColor; +} + +void NotificationViewMD::InkDropAnimationStarted() { + header_row_->SetSubpixelRenderingEnabled(false); +} + +void NotificationViewMD::InkDropRippleAnimationEnded( + views::InkDropState ink_drop_state) { + if (ink_drop_state == views::InkDropState::HIDDEN) + header_row_->SetSubpixelRenderingEnabled(true); +} + } // namespace message_center diff --git a/chromium/ui/message_center/views/notification_view_md.h b/chromium/ui/message_center/views/notification_view_md.h index fff369554b1..d9ed79d902b 100644 --- a/chromium/ui/message_center/views/notification_view_md.h +++ b/chromium/ui/message_center/views/notification_view_md.h @@ -9,15 +9,19 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "base/optional.h" #include "ui/message_center/message_center_export.h" #include "ui/message_center/views/message_view.h" +#include "ui/views/animation/ink_drop_observer.h" #include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield_controller.h" #include "ui/views/view_targeter_delegate.h" namespace views { +class ImageButton; class Label; class LabelButton; class ProgressBar; @@ -34,7 +38,7 @@ class ProportionalImageView; // message next to each other within a single column. class ItemView : public views::View { public: - explicit ItemView(const message_center::NotificationItem& item); + explicit ItemView(const NotificationItem& item); ~ItemView() override; const char* GetClassName() const override; @@ -52,19 +56,17 @@ class CompactTitleMessageView : public views::View { const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; + gfx::Size CalculatePreferredSize() const override; + void Layout() override; - void set_title(const base::string16& title) { title_ = title; } - void set_message(const base::string16& message) { message_ = message; } + void set_title(const base::string16& title); + void set_message(const base::string16& message); private: DISALLOW_COPY_AND_ASSIGN(CompactTitleMessageView); - base::string16 title_; - base::string16 message_; - - views::Label* title_view_ = nullptr; - views::Label* message_view_ = nullptr; + views::Label* title_ = nullptr; + views::Label* message_ = nullptr; }; class LargeImageView : public views::View { @@ -112,9 +114,8 @@ class NotificationButtonMD : public views::LabelButton { // |placeholder| is placeholder text shown on the input field. Only used when // |is_inline_reply| is true. NotificationButtonMD(views::ButtonListener* listener, - bool is_inline_reply, const base::string16& label, - const base::string16& placeholder); + const base::Optional<base::string16>& placeholder); ~NotificationButtonMD() override; void SetText(const base::string16& text) override; @@ -125,12 +126,12 @@ class NotificationButtonMD : public views::LabelButton { SkColor enabled_color_for_testing() { return label()->enabled_color(); } - bool is_inline_reply() const { return is_inline_reply_; } - const base::string16& placeholder() const { return placeholder_; } + const base::Optional<base::string16>& placeholder() const { + return placeholder_; + } private: - const bool is_inline_reply_; - const base::string16 placeholder_; + const base::Optional<base::string16> placeholder_; DISALLOW_COPY_AND_ASSIGN(NotificationButtonMD); }; @@ -142,26 +143,71 @@ class NotificationInputDelegate { virtual ~NotificationInputDelegate() = default; }; -class NotificationInputMD : public views::Textfield, - public views::TextfieldController { +class NotificationInputTextfieldMD : public views::Textfield { public: - NotificationInputMD(NotificationInputDelegate* delegate); - ~NotificationInputMD() override; - - bool HandleKeyEvent(views::Textfield* sender, - const ui::KeyEvent& key_event) override; + NotificationInputTextfieldMD(views::TextfieldController* controller); + ~NotificationInputTextfieldMD() override; void set_index(size_t index) { index_ = index; } void set_placeholder(const base::string16& placeholder); - private: - NotificationInputDelegate* const delegate_; + size_t index() const { return index_; }; + private: // |index_| is the notification action index that should be passed as the // argument of ClickOnNotificationButtonWithReply. size_t index_ = 0; - DISALLOW_COPY_AND_ASSIGN(NotificationInputMD); + DISALLOW_COPY_AND_ASSIGN(NotificationInputTextfieldMD); +}; + +class NotificationInputReplyButtonMD : public views::ImageButton { + public: + NotificationInputReplyButtonMD(views::ButtonListener* listener); + ~NotificationInputReplyButtonMD() override; + + void SetNormalImage(); + void SetPlaceholderImage(); + + private: + DISALLOW_COPY_AND_ASSIGN(NotificationInputReplyButtonMD); +}; + +class NotificationInputContainerMD : public views::InkDropHostView, + public views::ButtonListener, + public views::TextfieldController { + public: + NotificationInputContainerMD(NotificationInputDelegate* delegate); + ~NotificationInputContainerMD() override; + + void AnimateBackground(const ui::LocatedEvent& event); + + // Overridden from views::InkDropHostView: + void AddInkDropLayer(ui::Layer* ink_drop_layer) override; + void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + SkColor GetInkDropBaseColor() const override; + + // Overridden from views::TextfieldController: + bool HandleKeyEvent(views::Textfield* sender, + const ui::KeyEvent& key_event) override; + void OnAfterUserAction(views::Textfield* sender) override; + + // Overridden from views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + NotificationInputTextfieldMD* textfield() const { return textfield_; }; + NotificationInputReplyButtonMD* button() const { return button_; }; + + private: + NotificationInputDelegate* const delegate_; + + views::InkDropContainerView* const ink_drop_container_; + + NotificationInputTextfieldMD* const textfield_; + NotificationInputReplyButtonMD* const button_; + + DISALLOW_COPY_AND_ASSIGN(NotificationInputContainerMD); }; // View that displays all current types of notification (web, basic, image, and @@ -170,6 +216,7 @@ class NotificationInputMD : public views::Textfield, // returned by the Create() factory method below. class MESSAGE_CENTER_EXPORT NotificationViewMD : public MessageView, + public views::InkDropObserver, public NotificationInputDelegate, public views::ButtonListener, public views::ViewTargeterDelegate { @@ -179,14 +226,22 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD void Activate(); + void AddBackgroundAnimation(const ui::Event& event); + void RemoveBackgroundAnimation(); + // Overridden from views::View: void Layout() override; void OnFocus() override; void ScrollRectToVisible(const gfx::Rect& rect) override; gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override; - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; bool OnMousePressed(const ui::MouseEvent& event) override; + void OnMouseEvent(ui::MouseEvent* event) override; + + // Overridden from views::InkDropHostView: + void AddInkDropLayer(ui::Layer* ink_drop_layer) override; + void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + SkColor GetInkDropBaseColor() const override; // Overridden from MessageView: void UpdateWithNotification(const Notification& notification) override; @@ -197,7 +252,14 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD NotificationControlButtonsView* GetControlButtonsView() const override; bool IsExpanded() const override; void SetExpanded(bool expanded) override; - void OnSettingsButtonPressed() override; + bool IsManuallyExpandedOrCollapsed() const override; + void SetManuallyExpandedOrCollapsed(bool value) override; + + void OnSettingsButtonPressed(const ui::Event& event) override; + + // views::InkDropObserver: + void InkDropAnimationStarted() override; + void InkDropRippleAnimationEnded(views::InkDropState ink_drop_state) override; // Overridden from NotificationInputDelegate: void OnNotificationInputSubmit(size_t index, @@ -216,6 +278,7 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ExpandLongMessage); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestAccentColor); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UseImageAsIcon); + FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, NotificationWithoutIcon); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings); friend class NotificationViewMDTest; @@ -241,7 +304,9 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD bool IsExpandable(); void ToggleExpanded(); void UpdateViewForExpandedState(bool expanded); - void ToggleInlineSettings(); + void ToggleInlineSettings(const ui::Event& event); + + views::InkDropContainerView* const ink_drop_container_; // View containing close and settings buttons std::unique_ptr<NotificationControlButtonsView> control_buttons_view_; @@ -249,6 +314,10 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD // Whether this notification is expanded or not. bool expanded_ = false; + // True if the notification is expanded/collapsed by user interaction. + // If true, MessagePopupCollection will not auto-collapse the notification. + bool manually_expanded_or_collapsed_ = false; + // Whether hiding icon on the right side when expanded. bool hide_icon_on_expanded_ = false; @@ -279,7 +348,7 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD views::ProgressBar* progress_bar_view_ = nullptr; CompactTitleMessageView* compact_title_message_view_ = nullptr; views::View* action_buttons_row_ = nullptr; - NotificationInputMD* inline_reply_ = nullptr; + NotificationInputContainerMD* inline_reply_ = nullptr; // Views for inline settings. views::RadioButton* block_all_button_ = nullptr; 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 f4d8a89d983..f8574e2975f 100644 --- a/chromium/ui/message_center/views/notification_view_md_unittest.cc +++ b/chromium/ui/message_center/views/notification_view_md_unittest.cc @@ -54,6 +54,11 @@ class NotificationTestDelegate : public NotificationDelegate { submitted_reply_string_ = reply; } + void Reset() { + clicked_button_index_ = -1; + submitted_reply_string_ = base::EmptyString16(); + } + void DisableNotification() override { disable_notification_called_ = true; } int clicked_button_index() const { return clicked_button_index_; } @@ -142,7 +147,7 @@ void NotificationViewMDTest::SetUp() { // Create a dummy notification. delegate_ = new NotificationTestDelegate(); data_.reset(new RichNotificationData()); - data_->settings_button_handler = SettingsButtonHandler::TRAY; + data_->settings_button_handler = SettingsButtonHandler::INLINE; notification_.reset(new Notification( NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"), base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), @@ -173,6 +178,7 @@ void NotificationViewMDTest::SetUp() { } void NotificationViewMDTest::TearDown() { + notification_view_->SetInkDropMode(MessageView::InkDropMode::OFF); notification_view_->RemoveObserver(this); widget()->Close(); notification_view_.reset(); @@ -308,8 +314,7 @@ TEST_F(NotificationViewMDTest, CreateOrUpdateTest) { EXPECT_EQ(nullptr, notification_view()->title_view_); EXPECT_EQ(nullptr, notification_view()->message_view_); EXPECT_EQ(nullptr, notification_view()->image_container_view_); - // We still expect an icon view for all layouts. - EXPECT_NE(nullptr, notification_view()->icon_view_); + EXPECT_EQ(nullptr, notification_view()->icon_view_); } TEST_F(NotificationViewMDTest, TestIconSizing) { @@ -468,7 +473,7 @@ TEST_F(NotificationViewMDTest, TestInlineReply) { delegate_->set_expecting_reply_submission(true); std::vector<ButtonInfo> buttons = CreateButtons(2); - buttons[1].type = ButtonType::TEXT; + buttons[1].placeholder = base::string16(); notification()->set_buttons(buttons); UpdateNotificationViews(); widget()->Show(); @@ -501,17 +506,53 @@ TEST_F(NotificationViewMDTest, TestInlineReply) { generator.ClickLeftButton(); generator.ClickLeftButton(); EXPECT_TRUE(notification_view()->inline_reply_->visible()); - EXPECT_TRUE(notification_view()->inline_reply_->HasFocus()); + EXPECT_TRUE(notification_view()->inline_reply_->textfield()->visible()); + EXPECT_TRUE(notification_view()->inline_reply_->textfield()->HasFocus()); - // Type the text and submit. - ui::KeyboardCode keycodes[] = {ui::VKEY_T, ui::VKEY_E, ui::VKEY_S, ui::VKEY_T, - ui::VKEY_RETURN}; + // Type the text. + ui::KeyboardCode keycodes[] = {ui::VKEY_T, ui::VKEY_E, ui::VKEY_S, + ui::VKEY_T}; + for (ui::KeyboardCode keycode : keycodes) { + generator.PressKey(keycode, ui::EF_NONE); + generator.ReleaseKey(keycode, ui::EF_NONE); + } + // Submit by typing RETURN key. + generator.PressKey(ui::VKEY_RETURN, ui::EF_NONE); + generator.ReleaseKey(ui::VKEY_RETURN, ui::EF_NONE); + EXPECT_EQ(1, delegate_->clicked_button_index()); + EXPECT_EQ(base::ASCIIToUTF16("test"), delegate_->submitted_reply_string()); + + // Reset values. + delegate_->Reset(); + + // Now construct a mouse click event 1 pixel inside the boundary of the action + // button. + cursor_location = gfx::Point(1, 1); + views::View::ConvertPointToScreen(notification_view()->action_buttons_[1], + &cursor_location); + generator.MoveMouseTo(cursor_location); + generator.ClickLeftButton(); + + // Nothing should be submitted at this point. + EXPECT_EQ(-1, delegate_->clicked_button_index()); + EXPECT_EQ(base::EmptyString16(), delegate_->submitted_reply_string()); + + // Click the button again and focus on the inline textfield. + generator.ClickLeftButton(); + + // Type the text. for (ui::KeyboardCode keycode : keycodes) { generator.PressKey(keycode, ui::EF_NONE); generator.ReleaseKey(keycode, ui::EF_NONE); } + // Submit by clicking the reply button. + cursor_location = gfx::Point(1, 1); + views::View::ConvertPointToScreen( + notification_view()->inline_reply_->button(), &cursor_location); + generator.MoveMouseTo(cursor_location); + generator.ClickLeftButton(); EXPECT_EQ(1, delegate_->clicked_button_index()); EXPECT_EQ(base::ASCIIToUTF16("test"), delegate_->submitted_reply_string()); } @@ -637,11 +678,25 @@ TEST_F(NotificationViewMDTest, ExpandLongMessage) { EXPECT_EQ(collapsed_height, notification_view()->message_view_->height()); EXPECT_EQ(collapsed_preferred_height, notification_view()->GetPreferredSize().height()); + + // Test |manually_expanded_or_collapsed| being set when the toggle is done by + // user interaction. + EXPECT_FALSE(notification_view()->IsManuallyExpandedOrCollapsed()); + + // Construct a mouse click event 1 pixel inside the header. + gfx::Point done_cursor_location(1, 1); + views::View::ConvertPointToScreen(notification_view()->header_row_, + &done_cursor_location); + ui::test::EventGenerator generator(widget()->GetNativeWindow()); + generator.MoveMouseTo(done_cursor_location); + generator.ClickLeftButton(); + + EXPECT_TRUE(notification_view()->IsManuallyExpandedOrCollapsed()); } TEST_F(NotificationViewMDTest, TestAccentColor) { - const SkColor kActionButtonTextColor = SkColorSetRGB(0x33, 0x67, 0xD6); - const SkColor kCustomAccentColor = SkColorSetRGB(0xea, 0x61, 0x0); + constexpr SkColor kActionButtonTextColor = gfx::kGoogleBlue700; + constexpr SkColor kCustomAccentColor = gfx::kGoogleYellow900; notification()->set_buttons(CreateButtons(2)); UpdateNotificationViews(); @@ -654,7 +709,7 @@ TEST_F(NotificationViewMDTest, TestAccentColor) { // By default, header does not have accent color (default grey), and // buttons have default accent color. - EXPECT_EQ(message_center::kNotificationDefaultAccentColor, + EXPECT_EQ(kNotificationDefaultAccentColor, notification_view()->header_row_->accent_color_for_testing()); EXPECT_EQ( kActionButtonTextColor, @@ -689,24 +744,43 @@ TEST_F(NotificationViewMDTest, UseImageAsIcon) { UpdateNotificationViews(); EXPECT_FALSE(notification_view()->expanded_); EXPECT_TRUE(notification_view()->icon_view_->visible()); + EXPECT_TRUE(notification_view()->right_content_->visible()); // Icon on the right side is still visible when expanded. notification_view()->ToggleExpanded(); EXPECT_TRUE(notification_view()->expanded_); EXPECT_TRUE(notification_view()->icon_view_->visible()); + EXPECT_TRUE(notification_view()->right_content_->visible()); notification_view()->ToggleExpanded(); EXPECT_FALSE(notification_view()->expanded_); - // Test notification with use_image_as_icon e.g. screenshot preview. + // Test notification with |use_image_for_icon| e.g. screenshot preview. notification()->set_icon(gfx::Image()); UpdateNotificationViews(); EXPECT_TRUE(notification_view()->icon_view_->visible()); + EXPECT_TRUE(notification_view()->right_content_->visible()); // Icon on the right side is not visible when expanded. notification_view()->ToggleExpanded(); EXPECT_TRUE(notification_view()->expanded_); - EXPECT_FALSE(notification_view()->icon_view_->visible()); + EXPECT_TRUE(notification_view()->icon_view_->visible()); + EXPECT_FALSE(notification_view()->right_content_->visible()); +} + +TEST_F(NotificationViewMDTest, NotificationWithoutIcon) { + notification()->set_icon(gfx::Image()); + notification()->set_image(gfx::Image()); + UpdateNotificationViews(); + + // If the notification has no icon, |icon_view_| shouldn't be created. + EXPECT_FALSE(notification_view()->icon_view_); + EXPECT_FALSE(notification_view()->right_content_->visible()); + + // Toggling should not affect the icon. + notification_view()->ToggleExpanded(); + EXPECT_FALSE(notification_view()->icon_view_); + EXPECT_FALSE(notification_view()->right_content_->visible()); } TEST_F(NotificationViewMDTest, InlineSettings) { @@ -715,22 +789,27 @@ TEST_F(NotificationViewMDTest, InlineSettings) { // Inline settings will be shown by clicking settings button. EXPECT_FALSE(notification_view()->settings_row_->visible()); - notification_view()->OnSettingsButtonPressed(); + gfx::Point settings_cursor_location(1, 1); + views::View::ConvertPointToScreen( + notification_view()->control_buttons_view_.get()->settings_button(), + &settings_cursor_location); + ui::test::EventGenerator generator(widget()->GetNativeWindow()); + generator.MoveMouseTo(settings_cursor_location); + generator.ClickLeftButton(); EXPECT_TRUE(notification_view()->settings_row_->visible()); // By clicking settings button again, it will toggle. - notification_view()->OnSettingsButtonPressed(); + generator.ClickLeftButton(); EXPECT_FALSE(notification_view()->settings_row_->visible()); // Show inline settings again. - notification_view()->OnSettingsButtonPressed(); + generator.ClickLeftButton(); EXPECT_TRUE(notification_view()->settings_row_->visible()); // Construct a mouse click event 1 pixel inside the done button. gfx::Point done_cursor_location(1, 1); views::View::ConvertPointToScreen(notification_view()->settings_done_button_, &done_cursor_location); - ui::test::EventGenerator generator(widget()->GetNativeWindow()); generator.MoveMouseTo(done_cursor_location); generator.ClickLeftButton(); @@ -738,7 +817,8 @@ TEST_F(NotificationViewMDTest, InlineSettings) { EXPECT_FALSE(notification_view()->settings_row_->visible()); EXPECT_FALSE(delegate_->disable_notification_called()); - notification_view()->OnSettingsButtonPressed(); + generator.MoveMouseTo(settings_cursor_location); + generator.ClickLeftButton(); EXPECT_TRUE(notification_view()->settings_row_->visible()); // Construct a mouse click event 1 pixel inside the block all button. diff --git a/chromium/ui/message_center/views/notification_view_unittest.cc b/chromium/ui/message_center/views/notification_view_unittest.cc index dcd68529217..583b2a7e1c1 100644 --- a/chromium/ui/message_center/views/notification_view_unittest.cc +++ b/chromium/ui/message_center/views/notification_view_unittest.cc @@ -24,10 +24,10 @@ #include "ui/gfx/image/image.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_style.h" -#include "ui/message_center/notification.h" #include "ui/message_center/notification_list.h" -#include "ui/message_center/notification_types.h" -#include "ui/message_center/views/constants.h" +#include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/views/message_view_factory.h" #include "ui/message_center/views/notification_button.h" #include "ui/message_center/views/notification_control_buttons_view.h" @@ -284,7 +284,7 @@ TEST_F(NotificationViewTest, CreateOrUpdateTest) { } TEST_F(NotificationViewTest, CreateOrUpdateTestSettingsButton) { - data()->settings_button_handler = SettingsButtonHandler::TRAY; + data()->settings_button_handler = SettingsButtonHandler::INLINE; Notification notification( NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"), base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), @@ -492,7 +492,7 @@ TEST_F(NotificationViewTest, UpdateButtonCountTest) { } TEST_F(NotificationViewTest, SettingsButtonTest) { - data()->settings_button_handler = SettingsButtonHandler::TRAY; + data()->settings_button_handler = SettingsButtonHandler::INLINE; Notification notf( NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"), base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), @@ -562,10 +562,10 @@ TEST_F(NotificationViewTest, FormatContextMessageTest) { "veryveryveryveryveyryveryveryveryveryveyryveryvery.veryveryveyrylong." "chromium.org/hello"; - Notification notification1( - NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), base::UTF8ToUTF16(""), - base::UTF8ToUTF16(""), CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(), message_center::NotifierId(GURL()), *data(), NULL); + Notification notification1(NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), + base::UTF8ToUTF16(""), base::UTF8ToUTF16(""), + CreateTestImage(80, 80), base::UTF8ToUTF16(""), + GURL(), NotifierId(GURL()), *data(), NULL); notification1.set_context_message(base::ASCIIToUTF16(kRegularContextText)); base::string16 result = @@ -579,7 +579,7 @@ TEST_F(NotificationViewTest, FormatContextMessageTest) { Notification notification2( NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), base::UTF8ToUTF16(""), base::UTF8ToUTF16(""), CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(kUrlContext), message_center::NotifierId(GURL()), *data(), NULL); + GURL(kUrlContext), NotifierId(GURL()), *data(), NULL); notification2.set_context_message(base::ASCIIToUTF16("")); result = notification_view()->FormatContextMessage(notification2); @@ -590,7 +590,7 @@ TEST_F(NotificationViewTest, FormatContextMessageTest) { Notification notification3( NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), base::UTF8ToUTF16(""), base::UTF8ToUTF16(""), CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(kChromeUrl), message_center::NotifierId(GURL()), *data(), NULL); + GURL(kChromeUrl), NotifierId(GURL()), *data(), NULL); notification3.set_context_message(base::ASCIIToUTF16("")); result = notification_view()->FormatContextMessage(notification3); EXPECT_TRUE(result.empty()); @@ -599,7 +599,7 @@ TEST_F(NotificationViewTest, FormatContextMessageTest) { Notification notification4( NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), base::UTF8ToUTF16(""), base::UTF8ToUTF16(""), CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(kLongUrlContext), message_center::NotifierId(GURL()), *data(), NULL); + GURL(kLongUrlContext), NotifierId(GURL()), *data(), NULL); notification4.set_context_message(base::ASCIIToUTF16("")); result = notification_view()->FormatContextMessage(notification4); @@ -671,6 +671,7 @@ TEST_F(NotificationViewTest, SlideOutPinned) { ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); notification()->set_pinned(true); + notification_view()->SetIsNested(); UpdateNotificationViews(); std::string notification_id = notification()->id(); @@ -682,12 +683,11 @@ TEST_F(NotificationViewTest, SlideOutPinned) { EXPECT_FALSE(IsRemoved(notification_id)); } -TEST_F(NotificationViewTest, SlideOutForceDisablePinned) { +TEST_F(NotificationViewTest, PopupsCantPin) { ui::ScopedAnimationDurationScaleMode zero_duration_scope( ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); notification()->set_pinned(true); - notification_view()->set_force_disable_pinned(); UpdateNotificationViews(); std::string notification_id = notification()->id(); @@ -711,13 +711,14 @@ TEST_F(NotificationViewTest, SlideOutForceDisablePinned) { } TEST_F(NotificationViewTest, Pinned) { + // Notifications are popups by default (can't be pinned). notification()->set_pinned(true); UpdateNotificationViews(); - EXPECT_EQ(NULL, GetCloseButton()); + EXPECT_TRUE(GetCloseButton()); - notification_view()->set_force_disable_pinned(); + notification_view()->SetIsNested(); UpdateNotificationViews(); - EXPECT_TRUE(GetCloseButton()); + EXPECT_FALSE(GetCloseButton()); } #endif // defined(OS_CHROMEOS) diff --git a/chromium/ui/message_center/views/popup_alignment_delegate.cc b/chromium/ui/message_center/views/popup_alignment_delegate.cc index 95636377057..219e721760c 100644 --- a/chromium/ui/message_center/views/popup_alignment_delegate.cc +++ b/chromium/ui/message_center/views/popup_alignment_delegate.cc @@ -14,7 +14,7 @@ PopupAlignmentDelegate::~PopupAlignmentDelegate() {} void PopupAlignmentDelegate::DoUpdateIfPossible() { if (collection_) - collection_->DoUpdateIfPossible(); + collection_->DoUpdate(); } } // namespace message_center diff --git a/chromium/ui/message_center/views/popup_alignment_delegate.h b/chromium/ui/message_center/views/popup_alignment_delegate.h index 48787456927..43e6a62ae3c 100644 --- a/chromium/ui/message_center/views/popup_alignment_delegate.h +++ b/chromium/ui/message_center/views/popup_alignment_delegate.h @@ -33,7 +33,7 @@ class MESSAGE_CENTER_EXPORT PopupAlignmentDelegate { // Returns the baseline height of the current work area. That is the starting // point if there are no other toasts. - virtual int GetBaseLine() const = 0; + virtual int GetBaseline() const = 0; // Returns the rect of the current work area. virtual gfx::Rect GetWorkArea() const = 0; diff --git a/chromium/ui/message_center/views/proportional_image_view.cc b/chromium/ui/message_center/views/proportional_image_view.cc index 8a260960f38..b0d0d3ce84a 100644 --- a/chromium/ui/message_center/views/proportional_image_view.cc +++ b/chromium/ui/message_center/views/proportional_image_view.cc @@ -53,7 +53,7 @@ gfx::Size ProportionalImageView::GetImageDrawingSize() { gfx::Size max_size = max_image_size_; max_size.SetToMin(GetContentsBounds().size()); - return message_center::GetImageSizeForContainerSize(max_size, image_.size()); + return GetImageSizeForContainerSize(max_size, image_.size()); } } // namespace message_center diff --git a/chromium/ui/message_center/views/toast_contents_view.cc b/chromium/ui/message_center/views/toast_contents_view.cc index 151715785a7..285ca0b30a2 100644 --- a/chromium/ui/message_center/views/toast_contents_view.cc +++ b/chromium/ui/message_center/views/toast_contents_view.cc @@ -18,8 +18,8 @@ #include "ui/display/screen.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/slide_animation.h" -#include "ui/message_center/notification.h" #include "ui/message_center/public/cpp/message_center_constants.h" +#include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/views/message_popup_collection.h" #include "ui/message_center/views/message_view.h" #include "ui/message_center/views/popup_alignment_delegate.h" @@ -83,6 +83,7 @@ ToastContentsView::~ToastContentsView() { void ToastContentsView::SetContents(MessageView* view, bool a11y_feedback_for_updates) { + message_view_ = view; bool already_has_contents = child_count() > 0; RemoveAllChildViews(true); AddChildView(view); @@ -93,7 +94,7 @@ void ToastContentsView::SetContents(MessageView* view, // The notification type should be ALERT, otherwise the accessibility message // won't be read for this view which returns ROLE_WINDOW. if (already_has_contents && a11y_feedback_for_updates) - NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false); + NotifyAccessibilityEvent(ax::mojom::Event::kAlert, false); } void ToastContentsView::UpdateContents(const Notification& notification, @@ -103,7 +104,7 @@ void ToastContentsView::UpdateContents(const Notification& notification, message_view->UpdateWithNotification(notification); UpdatePreferredSize(); if (a11y_feedback_for_updates) - NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false); + NotifyAccessibilityEvent(ax::mojom::Event::kAlert, false); } void ToastContentsView::RevealWithAnimation(gfx::Point origin) { @@ -163,9 +164,6 @@ void ToastContentsView::SetBoundsWithAnimation(gfx::Rect new_bounds) { animated_bounds_start_ = GetWidget()->GetWindowBoundsInScreen(); animated_bounds_end_ = new_bounds; - if (collection_) - collection_->IncrementDeferCounter(); - if (bounds_animation_.get()) bounds_animation_->Stop(); @@ -174,9 +172,6 @@ void ToastContentsView::SetBoundsWithAnimation(gfx::Rect new_bounds) { } void ToastContentsView::StartFadeIn() { - // The decrement is done in OnBoundsAnimationEndedOrCancelled callback. - if (collection_) - collection_->IncrementDeferCounter(); fade_animation_->Stop(); GetWidget()->SetOpacity(0); @@ -186,9 +181,6 @@ void ToastContentsView::StartFadeIn() { } void ToastContentsView::StartFadeOut() { - // The decrement is done in OnBoundsAnimationEndedOrCancelled callback. - if (collection_) - collection_->IncrementDeferCounter(); fade_animation_->Stop(); closing_animation_ = (is_closing_ ? fade_animation_.get() : nullptr); @@ -218,13 +210,6 @@ void ToastContentsView::OnBoundsAnimationEndedOrCancelled( widget->Close(); } - - // This cannot be called before GetWidget()->Close(). Decrementing defer count - // will invoke update, which may invoke another close animation with - // incrementing defer counter. Close() after such process will cause a - // mismatch between increment/decrement. See crbug.com/238477 - if (collection_) - collection_->DecrementDeferCounter(); } // gfx::AnimationDelegate @@ -250,7 +235,7 @@ void ToastContentsView::AnimationCanceled( // views::WidgetDelegate void ToastContentsView::WindowClosing() { - if (!is_closing_ && collection_.get()) + if (!is_closing_ && collection_) collection_->ForgetToast(this); } @@ -331,7 +316,7 @@ void ToastContentsView::UpdatePreferredSize() { void ToastContentsView::GetAccessibleNodeData(ui::AXNodeData* node_data) { if (child_count() > 0) child_at(0)->GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_WINDOW; + node_data->role = ax::mojom::Role::kWindow; } const char* ToastContentsView::GetClassName() const { diff --git a/chromium/ui/message_center/views/toast_contents_view.h b/chromium/ui/message_center/views/toast_contents_view.h index 83227548bb5..87c0aa9bd64 100644 --- a/chromium/ui/message_center/views/toast_contents_view.h +++ b/chromium/ui/message_center/views/toast_contents_view.h @@ -80,6 +80,8 @@ class MESSAGE_CENTER_EXPORT ToastContentsView const std::string& id() const { return id_; } + MessageView* message_view() { return message_view_; } + // Overridden from views::View: void OnMouseEntered(const ui::MouseEvent& event) override; void OnMouseExited(const ui::MouseEvent& event) override; @@ -141,6 +143,9 @@ class MESSAGE_CENTER_EXPORT ToastContentsView gfx::Point origin_; gfx::Size preferred_size_; + // Weak reference to the MessageView. + MessageView* message_view_ = nullptr; + DISALLOW_COPY_AND_ASSIGN(ToastContentsView); }; diff --git a/chromium/ui/native_theme/native_theme_aura.cc b/chromium/ui/native_theme/native_theme_aura.cc index 31d5186f5a7..fb7a9c93450 100644 --- a/chromium/ui/native_theme/native_theme_aura.cc +++ b/chromium/ui/native_theme/native_theme_aura.cc @@ -148,7 +148,7 @@ void NativeThemeAura::PaintArrowButton(cc::PaintCanvas* canvas, break; case kHovered: bg_color = SkColorSetRGB(0xD2, 0xD2, 0xD2); - // Fall through. + FALLTHROUGH; case kNormal: arrow_color = SkColorSetRGB(0x50, 0x50, 0x50); break; diff --git a/chromium/ui/ozone/demo/BUILD.gn b/chromium/ui/ozone/demo/BUILD.gn index ad191666a65..8a01fb9b10e 100644 --- a/chromium/ui/ozone/demo/BUILD.gn +++ b/chromium/ui/ozone/demo/BUILD.gn @@ -10,16 +10,16 @@ group("demo") { executable("ozone_demo") { sources = [ - "gl_renderer.cc", - "gl_renderer.h", "ozone_demo.cc", "renderer.h", "renderer_base.cc", "renderer_base.h", + "skia_renderer.cc", + "skia_renderer.h", "software_renderer.cc", "software_renderer.h", - "surfaceless_gl_renderer.cc", - "surfaceless_gl_renderer.h", + "surfaceless_skia_renderer.cc", + "surfaceless_skia_renderer.h", ] deps = [ diff --git a/chromium/ui/ozone/demo/gl_renderer.cc b/chromium/ui/ozone/demo/gl_renderer.cc deleted file mode 100644 index bc9d2a5bfd3..00000000000 --- a/chromium/ui/ozone/demo/gl_renderer.cc +++ /dev/null @@ -1,77 +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 "ui/ozone/demo/gl_renderer.h" - -#include "base/location.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/trace_event/trace_event.h" -#include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_surface.h" -#include "ui/gl/init/gl_factory.h" - -namespace ui { - -GlRenderer::GlRenderer(gfx::AcceleratedWidget widget, - const scoped_refptr<gl::GLSurface>& surface, - const gfx::Size& size) - : RendererBase(widget, size), surface_(surface), weak_ptr_factory_(this) {} - -GlRenderer::~GlRenderer() { -} - -bool GlRenderer::Initialize() { - context_ = gl::init::CreateGLContext(nullptr, surface_.get(), - gl::GLContextAttribs()); - if (!context_.get()) { - LOG(ERROR) << "Failed to create GL context"; - return false; - } - - surface_->Resize(size_, 1.f, gl::GLSurface::ColorSpace::UNSPECIFIED, true); - - if (!context_->MakeCurrent(surface_.get())) { - LOG(ERROR) << "Failed to make GL context current"; - return false; - } - - PostRenderFrameTask(gfx::SwapResult::SWAP_ACK); - return true; -} - -void GlRenderer::RenderFrame() { - TRACE_EVENT0("ozone", "GlRenderer::RenderFrame"); - - float fraction = NextFraction(); - - context_->MakeCurrent(surface_.get()); - - glViewport(0, 0, size_.width(), size_.height()); - glClearColor(1 - fraction, fraction, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (surface_->SupportsAsyncSwap()) { - surface_->SwapBuffersAsync(base::Bind(&GlRenderer::PostRenderFrameTask, - weak_ptr_factory_.GetWeakPtr()), - base::Bind(&GlRenderer::OnPresentation, - weak_ptr_factory_.GetWeakPtr())); - } else { - PostRenderFrameTask(surface_->SwapBuffers(base::Bind( - &GlRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr()))); - } -} - -void GlRenderer::PostRenderFrameTask(gfx::SwapResult result) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&GlRenderer::RenderFrame, weak_ptr_factory_.GetWeakPtr())); -} - -void GlRenderer::OnPresentation(const gfx::PresentationFeedback& feedback) { - DCHECK(surface_->SupportsPresentationCallback()); - LOG_IF(ERROR, feedback.timestamp.is_null()) << "Last frame is discarded!"; -} - -} // namespace ui diff --git a/chromium/ui/ozone/demo/gl_renderer.h b/chromium/ui/ozone/demo/gl_renderer.h deleted file mode 100644 index f6c8b2bf2d0..00000000000 --- a/chromium/ui/ozone/demo/gl_renderer.h +++ /dev/null @@ -1,52 +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 UI_OZONE_DEMO_GL_RENDERER_H_ -#define UI_OZONE_DEMO_GL_RENDERER_H_ - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "ui/gfx/swap_result.h" -#include "ui/ozone/demo/renderer_base.h" - -namespace gfx { -struct PresentationFeedback; -} // namespace gfx - -namespace gl { -class GLContext; -class GLSurface; -} // namespace gl - -namespace ui { - -class GlRenderer : public RendererBase { - public: - GlRenderer(gfx::AcceleratedWidget widget, - const scoped_refptr<gl::GLSurface>& surface, - const gfx::Size& size); - ~GlRenderer() override; - - // Renderer: - bool Initialize() override; - - protected: - virtual void RenderFrame(); - virtual void PostRenderFrameTask(gfx::SwapResult result); - - scoped_refptr<gl::GLSurface> surface_; - scoped_refptr<gl::GLContext> context_; - - private: - void OnPresentation(const gfx::PresentationFeedback& feedback); - - base::WeakPtrFactory<GlRenderer> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(GlRenderer); -}; - -} // namespace ui - -#endif // UI_OZONE_DEMO_GL_RENDERER_H_ diff --git a/chromium/ui/ozone/demo/ozone_demo.cc b/chromium/ui/ozone/demo/ozone_demo.cc index 38d3c919691..fc989906f2e 100644 --- a/chromium/ui/ozone/demo/ozone_demo.cc +++ b/chromium/ui/ozone/demo/ozone_demo.cc @@ -6,6 +6,7 @@ #include "base/at_exit.h" #include "base/command_line.h" +#include "base/debug/stack_trace.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" @@ -26,9 +27,9 @@ #include "ui/gfx/geometry/size.h" #include "ui/gl/gl_surface.h" #include "ui/gl/init/gl_factory.h" -#include "ui/ozone/demo/gl_renderer.h" +#include "ui/ozone/demo/skia_renderer.h" #include "ui/ozone/demo/software_renderer.h" -#include "ui/ozone/demo/surfaceless_gl_renderer.h" +#include "ui/ozone/demo/surfaceless_skia_renderer.h" #include "ui/ozone/public/ozone_gpu_test_helper.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/ozone/public/ozone_switches.h" @@ -39,7 +40,6 @@ const int kTestWindowWidth = 800; const int kTestWindowHeight = 600; const char kDisableGpu[] = "disable-gpu"; - const char kDisableSurfaceless[] = "disable-surfaceless"; const char kWindowSize[] = "window-size"; @@ -58,7 +58,7 @@ scoped_refptr<gl::GLSurface> CreateGLSurface(gfx::AcceleratedWidget widget) { class RendererFactory { public: enum RendererType { - GL, + SKIA, SOFTWARE, }; @@ -176,7 +176,8 @@ class DemoWindow : public ui::PlatformWindowDelegate { void StartOnGpu() { renderer_ = renderer_factory_->CreateRenderer(GetAcceleratedWidget(), GetSize()); - renderer_->Initialize(); + if (!renderer_->Initialize()) + LOG(ERROR) << "Failed to initialize renderer."; } WindowManager* window_manager_; // Not owned. @@ -206,11 +207,12 @@ bool RendererFactory::Initialize() { ui::OzonePlatform::InitParams params; params.single_process = true; ui::OzonePlatform::InitializeForGPU(params); + ui::OzonePlatform::GetInstance()->AfterSandboxEntry(); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff() && gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get())) { - type_ = GL; + type_ = SKIA; } else { type_ = SOFTWARE; } @@ -222,16 +224,15 @@ std::unique_ptr<ui::Renderer> RendererFactory::CreateRenderer( gfx::AcceleratedWidget widget, const gfx::Size& size) { switch (type_) { - case GL: { + case SKIA: { scoped_refptr<gl::GLSurface> surface = CreateGLSurface(widget); if (!surface) LOG(FATAL) << "Failed to create GL surface"; if (surface->IsSurfaceless()) { - return std::make_unique<ui::SurfacelessGlRenderer>(widget, surface, - size); - } else { - return std::make_unique<ui::GlRenderer>(widget, surface, size); + return std::make_unique<ui::SurfacelessSkiaRenderer>(widget, surface, + size); } + return std::make_unique<ui::SkiaRenderer>(widget, surface, size); } case SOFTWARE: return std::make_unique<ui::SoftwareRenderer>(widget, size); @@ -334,6 +335,8 @@ int main(int argc, char** argv) { base::CommandLine::Init(argc, argv); base::AtExitManager exit_manager; + base::debug::EnableInProcessStackDumping(); + // Initialize logging so we can enable VLOG messages. logging::LoggingSettings settings; logging::InitLogging(settings); diff --git a/chromium/ui/ozone/demo/renderer_base.cc b/chromium/ui/ozone/demo/renderer_base.cc index 577176bcd98..ccbcae74993 100644 --- a/chromium/ui/ozone/demo/renderer_base.cc +++ b/chromium/ui/ozone/demo/renderer_base.cc @@ -19,13 +19,16 @@ RendererBase::RendererBase(gfx::AcceleratedWidget widget, const gfx::Size& size) RendererBase::~RendererBase() { } -float RendererBase::NextFraction() { +float RendererBase::CurrentFraction() const { float fraction = (sinf(iteration_ * 2 * base::kPiFloat / kAnimationSteps) + 1) / 2; + return fraction; +} +float RendererBase::NextFraction() { + float fraction = CurrentFraction(); iteration_++; iteration_ %= kAnimationSteps; - return fraction; } diff --git a/chromium/ui/ozone/demo/renderer_base.h b/chromium/ui/ozone/demo/renderer_base.h index 8d7acd50fac..7199798bdcd 100644 --- a/chromium/ui/ozone/demo/renderer_base.h +++ b/chromium/ui/ozone/demo/renderer_base.h @@ -17,6 +17,7 @@ class RendererBase : public Renderer { ~RendererBase() override; protected: + float CurrentFraction() const; float NextFraction(); gfx::AcceleratedWidget widget_; diff --git a/chromium/ui/ozone/demo/skia_renderer.cc b/chromium/ui/ozone/demo/skia_renderer.cc new file mode 100644 index 00000000000..a8d7947ed8f --- /dev/null +++ b/chromium/ui/ozone/demo/skia_renderer.cc @@ -0,0 +1,243 @@ +// Copyright 2018 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/ozone/demo/skia_renderer.h" + +#include "base/command_line.h" +#include "base/location.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/trace_event/trace_event.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/effects/SkGradientShader.h" +#include "third_party/skia/include/gpu/GrBackendSurface.h" +#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface.h" +#include "ui/gl/init/gl_factory.h" + +namespace ui { + +namespace { + +const GrGLInterface* GrGLCreateNativeInterface() { + return GrGLAssembleInterface(nullptr, [](void* ctx, const char name[]) { + return gl::GetGLProcAddress(name); + }); +} + +const char kUseDDL[] = "use-ddl"; + +} // namespace + +SkiaRenderer::SkiaRenderer(gfx::AcceleratedWidget widget, + const scoped_refptr<gl::GLSurface>& surface, + const gfx::Size& size) + : RendererBase(widget, size), + gl_surface_(surface), + use_ddl_(base::CommandLine::ForCurrentProcess()->HasSwitch(kUseDDL)), + condition_variable_(&lock_), + weak_ptr_factory_(this) {} + +SkiaRenderer::~SkiaRenderer() { + if (use_ddl_) + StopDDLRenderThread(); +} + +bool SkiaRenderer::Initialize() { + gl_context_ = gl::init::CreateGLContext(nullptr, gl_surface_.get(), + gl::GLContextAttribs()); + if (!gl_context_.get()) { + LOG(FATAL) << "Failed to create GL context"; + return false; + } + + gl_surface_->Resize(size_, 1.f, gl::GLSurface::ColorSpace::UNSPECIFIED, true); + + if (!gl_context_->MakeCurrent(gl_surface_.get())) { + LOG(FATAL) << "Failed to make GL context current"; + return false; + } + + auto native_interface = + sk_sp<const GrGLInterface>(GrGLCreateNativeInterface()); + DCHECK(native_interface); + GrContextOptions options; + if (use_ddl_) + options.fExplicitlyAllocateGPUResources = GrContextOptions::Enable::kYes; + gr_context_ = GrContext::MakeGL(std::move(native_interface), options); + DCHECK(gr_context_); + + PostRenderFrameTask(gfx::SwapResult::SWAP_ACK); + return true; +} + +void SkiaRenderer::RenderFrame() { + TRACE_EVENT0("ozone", "SkiaRenderer::RenderFrame"); + + // LegacyFontHost will get LCD text and skia figures out what type to use. + SkSurfaceProps surface_props = + SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); + + if (!sk_surface_) { + GrGLFramebufferInfo framebuffer_info; + framebuffer_info.fFBOID = 0; + GrBackendRenderTarget render_target(size_.width(), size_.height(), 0, 8, + kRGBA_8888_GrPixelConfig, + framebuffer_info); + + sk_surface_ = SkSurface::MakeFromBackendRenderTarget( + gr_context_.get(), render_target, kBottomLeft_GrSurfaceOrigin, nullptr, + &surface_props); + } + + if (use_ddl_) { + StartDDLRenderThreadIfNecessary(sk_surface_.get()); + auto ddl = GetDDL(); + sk_surface_->draw(ddl.get()); + } else { + Draw(sk_surface_->getCanvas(), NextFraction()); + } + gr_context_->flush(); + glFinish(); + + if (gl_surface_->SupportsAsyncSwap()) { + gl_surface_->SwapBuffersAsync( + base::BindRepeating(&SkiaRenderer::PostRenderFrameTask, + weak_ptr_factory_.GetWeakPtr()), + base::BindRepeating(&SkiaRenderer::OnPresentation, + weak_ptr_factory_.GetWeakPtr())); + } else { + PostRenderFrameTask(gl_surface_->SwapBuffers(base::BindRepeating( + &SkiaRenderer::OnPresentation, weak_ptr_factory_.GetWeakPtr()))); + } +} + +void SkiaRenderer::PostRenderFrameTask(gfx::SwapResult result) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindRepeating(&SkiaRenderer::RenderFrame, + weak_ptr_factory_.GetWeakPtr())); +} + +void SkiaRenderer::Draw(SkCanvas* canvas, float fraction) { + TRACE_EVENT0("ozone", "SkiaRenderer::Draw"); + // Clear background + canvas->clear(SkColorSetARGB(255, 255 * fraction, 255 * (1 - fraction), 0)); + + SkPaint paint; + paint.setColor(SK_ColorRED); + + // Draw a rectangle with red paint + SkRect rect = SkRect::MakeXYWH(10, 10, 128, 128); + canvas->drawRect(rect, paint); + + // Set up a linear gradient and draw a circle + { + SkPoint linearPoints[] = {{0, 0}, {300, 300}}; + SkColor linearColors[] = {SK_ColorGREEN, SK_ColorBLACK}; + paint.setShader(SkGradientShader::MakeLinear( + linearPoints, linearColors, nullptr, 2, SkShader::kMirror_TileMode)); + paint.setAntiAlias(true); + + canvas->drawCircle(200, 200, 64, paint); + + // Detach shader + paint.setShader(nullptr); + } + + // Draw a message with a nice black paint + paint.setSubpixelText(true); + paint.setColor(SK_ColorBLACK); + paint.setTextSize(32); + + canvas->save(); + static const char message[] = "Hello Ozone"; + static const char message_ddl[] = "Hello Ozone + DDL"; + + // Translate and rotate + canvas->translate(300, 300); + rotation_angle_ += 0.2f; + if (rotation_angle_ > 360) { + rotation_angle_ -= 360; + } + canvas->rotate(rotation_angle_); + + const char* text = use_ddl_ ? message_ddl : message; + // Draw the text + canvas->drawText(text, strlen(text), 0, 0, paint); + + canvas->restore(); +} + +void SkiaRenderer::StartDDLRenderThreadIfNecessary(SkSurface* sk_surface) { + DCHECK(use_ddl_); + if (ddl_render_thread_) + return; + DCHECK(!surface_charaterization_.isValid()); + DCHECK(sk_surface); + + if (!sk_surface->characterize(&surface_charaterization_)) + LOG(FATAL) << "Failed to cheracterize the skia surface!"; + ddl_render_thread_ = + std::make_unique<base::DelegateSimpleThread>(this, "DDLRenderThread"); + ddl_render_thread_->Start(); +} + +void SkiaRenderer::StopDDLRenderThread() { + if (!ddl_render_thread_) + return; + { + base::AutoLock auto_lock_(lock_); + surface_charaterization_ = SkSurfaceCharacterization(); + condition_variable_.Signal(); + } + ddl_render_thread_->Join(); + ddl_render_thread_ = nullptr; + while (!ddls_.empty()) + ddls_.pop(); +} + +std::unique_ptr<SkDeferredDisplayList> SkiaRenderer::GetDDL() { + base::AutoLock auto_lock_(lock_); + DCHECK(surface_charaterization_.isValid()); + // Wait until DDL is generated by DDL render thread. + while (ddls_.empty()) + condition_variable_.Wait(); + auto ddl = std::move(ddls_.front()); + ddls_.pop(); + condition_variable_.Signal(); + return ddl; +} + +void SkiaRenderer::Run() { + base::AutoLock auto_lock(lock_); + while (true) { + // Wait until ddls_ is consumed or surface_charaterization_ is reset. + constexpr size_t kMaxPendingDDLS = 4; + while (surface_charaterization_.isValid() && + ddls_.size() == kMaxPendingDDLS) + condition_variable_.Wait(); + if (!surface_charaterization_.isValid()) + break; + DCHECK_LT(ddls_.size(), kMaxPendingDDLS); + SkDeferredDisplayListRecorder recorder(surface_charaterization_); + std::unique_ptr<SkDeferredDisplayList> ddl; + { + base::AutoUnlock auto_unlock(lock_); + Draw(recorder.getCanvas(), NextFraction()); + ddl = recorder.detach(); + } + ddls_.push(std::move(ddl)); + condition_variable_.Signal(); + } +} + +void SkiaRenderer::OnPresentation(const gfx::PresentationFeedback& feedback) { + DCHECK(gl_surface_->SupportsPresentationCallback()); + LOG_IF(ERROR, feedback.timestamp.is_null()) << "Last frame is discarded!"; +} + +} // namespace ui diff --git a/chromium/ui/ozone/demo/skia_renderer.h b/chromium/ui/ozone/demo/skia_renderer.h new file mode 100644 index 00000000000..e13f5bfd6c5 --- /dev/null +++ b/chromium/ui/ozone/demo/skia_renderer.h @@ -0,0 +1,86 @@ +// Copyright 2018 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_OZONE_DEMO_SKIA_RENDERER_H_ +#define UI_OZONE_DEMO_SKIA_RENDERER_H_ + +#include "base/containers/queue.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/synchronization/condition_variable.h" +#include "base/synchronization/lock.h" +#include "base/threading/simple_thread.h" +#include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/gpu/GrContext.h" +#include "ui/gfx/swap_result.h" +#include "ui/ozone/demo/renderer_base.h" + +namespace gfx { +struct PresentationFeedback; +} // namespace gfx + +namespace gl { +class GLContext; +class GLSurface; +} // namespace gl + +namespace ui { + +class SkiaRenderer : public RendererBase, + public base::DelegateSimpleThread::Delegate { + public: + SkiaRenderer(gfx::AcceleratedWidget widget, + const scoped_refptr<gl::GLSurface>& surface, + const gfx::Size& size); + ~SkiaRenderer() override; + + // Renderer: + bool Initialize() override; + + protected: + virtual void RenderFrame(); + virtual void PostRenderFrameTask(gfx::SwapResult result); + + void Draw(SkCanvas* canvas, float fraction); + void StartDDLRenderThreadIfNecessary(SkSurface* sk_surface); + void StopDDLRenderThread(); + std::unique_ptr<SkDeferredDisplayList> GetDDL(); + + scoped_refptr<gl::GLSurface> gl_surface_; + scoped_refptr<gl::GLContext> gl_context_; + + sk_sp<GrContext> gr_context_; + const bool use_ddl_; + + private: + // base::DelegateSimpleThread::Delegate: + void Run() override; + + void OnPresentation(const gfx::PresentationFeedback& feedback); + + sk_sp<SkSurface> sk_surface_; + + float rotation_angle_ = 0.f; + + std::unique_ptr<base::SimpleThread> ddl_render_thread_; + + // The lock to protect |surface_charaterization_| and |ddls_|. + base::Lock lock_; + + // The condition variable for signalling change of |ddls_|. + base::ConditionVariable condition_variable_; + + SkSurfaceCharacterization surface_charaterization_; + base::queue<std::unique_ptr<SkDeferredDisplayList>> ddls_; + + base::WeakPtrFactory<SkiaRenderer> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(SkiaRenderer); +}; + +} // namespace ui + +#endif // UI_OZONE_DEMO_SKIA_RENDERER_H_ diff --git a/chromium/ui/ozone/demo/surfaceless_gl_renderer.h b/chromium/ui/ozone/demo/surfaceless_gl_renderer.h deleted file mode 100644 index 4086ffc562c..00000000000 --- a/chromium/ui/ozone/demo/surfaceless_gl_renderer.h +++ /dev/null @@ -1,74 +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 UI_OZONE_DEMO_SURFACELESS_GL_RENDERER_H_ -#define UI_OZONE_DEMO_SURFACELESS_GL_RENDERER_H_ - -#include <memory> - -#include "base/macros.h" -#include "ui/gfx/geometry/rect_f.h" -#include "ui/ozone/demo/gl_renderer.h" - -namespace gl { -class GLImage; -} - -namespace ui { -class OverlayCandidatesOzone; - -class SurfacelessGlRenderer : public GlRenderer { - public: - SurfacelessGlRenderer(gfx::AcceleratedWidget widget, - const scoped_refptr<gl::GLSurface>& surface, - const gfx::Size& size); - ~SurfacelessGlRenderer() override; - - // Renderer: - bool Initialize() override; - - private: - // GlRenderer: - void RenderFrame() override; - void PostRenderFrameTask(gfx::SwapResult result) override; - - class BufferWrapper { - public: - BufferWrapper(); - ~BufferWrapper(); - - gl::GLImage* image() const { return image_.get(); } - - bool Initialize(gfx::AcceleratedWidget widget, const gfx::Size& size); - void BindFramebuffer(); - - const gfx::Size size() const { return size_; } - - private: - gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; - gfx::Size size_; - - scoped_refptr<gl::GLImage> image_; - unsigned int gl_fb_ = 0; - unsigned int gl_tex_ = 0; - }; - - std::unique_ptr<BufferWrapper> buffers_[2]; - - std::unique_ptr<BufferWrapper> overlay_buffer_[2]; - bool disable_primary_plane_ = false; - gfx::Rect primary_plane_rect_; - - std::unique_ptr<OverlayCandidatesOzone> overlay_checker_; - - int back_buffer_ = 0; - - base::WeakPtrFactory<SurfacelessGlRenderer> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(SurfacelessGlRenderer); -}; - -} // namespace ui - -#endif // UI_OZONE_DEMO_SURFACELESS_GL_RENDERER_H_ diff --git a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc b/chromium/ui/ozone/demo/surfaceless_skia_renderer.cc index 77f617e92ff..fef66dff8af 100644 --- a/chromium/ui/ozone/demo/surfaceless_gl_renderer.cc +++ b/chromium/ui/ozone/demo/surfaceless_skia_renderer.cc @@ -1,15 +1,22 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. +// Copyright 2018 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/ozone/demo/surfaceless_gl_renderer.h" +#include "ui/ozone/demo/surfaceless_skia_renderer.h" #include <stddef.h> #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/command_line.h" #include "base/macros.h" #include "base/trace_event/trace_event.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/gpu/GrBackendSurface.h" +#include "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" #include "ui/display/types/display_snapshot.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gl/gl_bindings.h" @@ -26,6 +33,10 @@ namespace ui { namespace { +const char kPartialPrimaryPlane[] = "partial-primary-plane"; +const char kEnableOverlay[] = "enable-overlay"; +const char kDisablePrimaryPlane[] = "disable-primary-plane"; + OverlaySurfaceCandidate MakeOverlayCandidate(int z_order, gfx::Rect bounds_rect, gfx::RectF crop_rect) { @@ -37,6 +48,10 @@ OverlaySurfaceCandidate MakeOverlayCandidate(int z_order, OverlaySurfaceCandidate overlay_candidate; + // Use default display format since this should be compatible with most + // devices. + overlay_candidate.format = display::DisplaySnapshot::PrimaryFormat(); + // The bounds rectangle of the candidate overlay buffer. overlay_candidate.buffer_size = bounds_rect.size(); // The same rectangle in floating point coordinates. @@ -54,23 +69,43 @@ OverlaySurfaceCandidate MakeOverlayCandidate(int z_order, } // namespace -SurfacelessGlRenderer::BufferWrapper::BufferWrapper() { -} +class SurfacelessSkiaRenderer::BufferWrapper { + public: + BufferWrapper(); + ~BufferWrapper(); + + gl::GLImage* image() const { return image_.get(); } + SkSurface* sk_surface() const { return sk_surface_.get(); } + + bool Initialize(GrContext* gr_context, + gfx::AcceleratedWidget widget, + const gfx::Size& size); + void BindFramebuffer(); -SurfacelessGlRenderer::BufferWrapper::~BufferWrapper() { - if (gl_fb_) - glDeleteFramebuffersEXT(1, &gl_fb_); + const gfx::Size size() const { return size_; } + private: + gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; + gfx::Size size_; + + scoped_refptr<gl::GLImage> image_; + unsigned int gl_tex_ = 0; + sk_sp<SkSurface> sk_surface_; +}; + +SurfacelessSkiaRenderer::BufferWrapper::BufferWrapper() = default; + +SurfacelessSkiaRenderer::BufferWrapper::~BufferWrapper() { if (gl_tex_) { image_->ReleaseTexImage(GL_TEXTURE_2D); glDeleteTextures(1, &gl_tex_); } } -bool SurfacelessGlRenderer::BufferWrapper::Initialize( +bool SurfacelessSkiaRenderer::BufferWrapper::Initialize( + GrContext* gr_context, gfx::AcceleratedWidget widget, const gfx::Size& size) { - glGenFramebuffersEXT(1, &gl_fb_); glGenTextures(1, &gl_tex_); gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat(); @@ -86,82 +121,82 @@ bool SurfacelessGlRenderer::BufferWrapper::Initialize( } image_ = image; - glBindFramebufferEXT(GL_FRAMEBUFFER, gl_fb_); glBindTexture(GL_TEXTURE_2D, gl_tex_); image_->BindTexImage(GL_TEXTURE_2D); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - gl_tex_, 0); - if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LOG(ERROR) << "Failed to create framebuffer " - << glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); - return false; - } - widget_ = widget; size_ = size; - return true; -} + GrGLTextureInfo texture_info; + texture_info.fTarget = GL_TEXTURE_2D; + texture_info.fID = gl_tex_; + texture_info.fFormat = GL_RGBA; + GrBackendTexture backend_texture(size_.width(), size_.height(), + kRGBA_8888_GrPixelConfig, texture_info); + sk_surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget( + gr_context, backend_texture, kTopLeft_GrSurfaceOrigin, 0, nullptr, + nullptr); + if (!sk_surface_) { + LOG(ERROR) << "Failed to create skia surface"; + return false; + } -void SurfacelessGlRenderer::BufferWrapper::BindFramebuffer() { - glBindFramebufferEXT(GL_FRAMEBUFFER, gl_fb_); + return true; } -SurfacelessGlRenderer::SurfacelessGlRenderer( +SurfacelessSkiaRenderer::SurfacelessSkiaRenderer( gfx::AcceleratedWidget widget, const scoped_refptr<gl::GLSurface>& surface, const gfx::Size& size) - : GlRenderer(widget, surface, size), + : SkiaRenderer(widget, surface, size), overlay_checker_(ui::OzonePlatform::GetInstance() ->GetOverlayManager() ->CreateOverlayCandidates(widget)), weak_ptr_factory_(this) {} -SurfacelessGlRenderer::~SurfacelessGlRenderer() { +SurfacelessSkiaRenderer::~SurfacelessSkiaRenderer() { // Need to make current when deleting the framebuffer resources allocated in // the buffers. - context_->MakeCurrent(surface_.get()); + gl_context_->MakeCurrent(gl_surface_.get()); } -bool SurfacelessGlRenderer::Initialize() { - if (!GlRenderer::Initialize()) +bool SurfacelessSkiaRenderer::Initialize() { + if (!SkiaRenderer::Initialize()) return false; base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch("partial-primary-plane")) + if (command_line->HasSwitch(kPartialPrimaryPlane)) primary_plane_rect_ = gfx::Rect(200, 200, 800, 800); else primary_plane_rect_ = gfx::Rect(size_); for (size_t i = 0; i < arraysize(buffers_); ++i) { buffers_[i].reset(new BufferWrapper()); - if (!buffers_[i]->Initialize(widget_, primary_plane_rect_.size())) + if (!buffers_[i]->Initialize(gr_context_.get(), widget_, + primary_plane_rect_.size())) return false; } - if (command_line->HasSwitch("enable-overlay")) { + if (command_line->HasSwitch(kEnableOverlay)) { gfx::Size overlay_size = gfx::Size(size_.width() / 8, size_.height() / 8); for (size_t i = 0; i < arraysize(overlay_buffer_); ++i) { overlay_buffer_[i].reset(new BufferWrapper()); - overlay_buffer_[i]->Initialize(gfx::kNullAcceleratedWidget, overlay_size); - - glViewport(0, 0, overlay_size.width(), overlay_size.height()); - glClearColor(i, 1.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + overlay_buffer_[i]->Initialize(gr_context_.get(), + gfx::kNullAcceleratedWidget, overlay_size); + SkCanvas* sk_canvas = overlay_buffer_[i]->sk_surface()->getCanvas(); + sk_canvas->clear(SkColorSetARGB(255, 255 * i, 255, 0)); } } - disable_primary_plane_ = command_line->HasSwitch("disable-primary-plane"); + disable_primary_plane_ = command_line->HasSwitch(kDisablePrimaryPlane); PostRenderFrameTask(gfx::SwapResult::SWAP_ACK); return true; } -void SurfacelessGlRenderer::RenderFrame() { - TRACE_EVENT0("ozone", "SurfacelessGlRenderer::RenderFrame"); - - float fraction = NextFraction(); +void SurfacelessSkiaRenderer::RenderFrame() { + TRACE_EVENT0("ozone", "SurfacelessSkiaRenderer::RenderFrame"); + float fraction = CurrentFraction(); gfx::Rect overlay_rect; OverlayCandidatesOzone::OverlaySurfaceCandidateList overlay_list; @@ -194,44 +229,51 @@ void SurfacelessGlRenderer::RenderFrame() { // later time. overlay_checker_->CheckOverlaySupport(&overlay_list); - context_->MakeCurrent(surface_.get()); - buffers_[back_buffer_]->BindFramebuffer(); + gl_context_->MakeCurrent(gl_surface_.get()); - glViewport(0, 0, size_.width(), size_.height()); - glClearColor(1 - fraction, 0.0, fraction, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + SkSurface* sk_surface = buffers_[back_buffer_]->sk_surface(); + if (use_ddl_) { + StartDDLRenderThreadIfNecessary(sk_surface); + auto ddl = GetDDL(); + sk_surface->draw(ddl.get()); + } else { + Draw(sk_surface->getCanvas(), NextFraction()); + } + gr_context_->flush(); + glFinish(); if (!disable_primary_plane_) { CHECK(overlay_list.front().overlay_handled); - surface_->ScheduleOverlayPlane(0, gfx::OVERLAY_TRANSFORM_NONE, - buffers_[back_buffer_]->image(), - primary_plane_rect_, gfx::RectF(0, 0, 1, 1)); + gl_surface_->ScheduleOverlayPlane( + 0, gfx::OVERLAY_TRANSFORM_NONE, buffers_[back_buffer_]->image(), + primary_plane_rect_, gfx::RectF(0, 0, 1, 1)); } if (overlay_buffer_[0] && overlay_list.back().overlay_handled) { - surface_->ScheduleOverlayPlane(1, gfx::OVERLAY_TRANSFORM_NONE, - overlay_buffer_[back_buffer_]->image(), - overlay_rect, gfx::RectF(0, 0, 1, 1)); + gl_surface_->ScheduleOverlayPlane(1, gfx::OVERLAY_TRANSFORM_NONE, + overlay_buffer_[back_buffer_]->image(), + overlay_rect, gfx::RectF(0, 0, 1, 1)); } back_buffer_ ^= 1; - surface_->SwapBuffersAsync( - base::Bind(&SurfacelessGlRenderer::PostRenderFrameTask, - weak_ptr_factory_.GetWeakPtr()), - base::Bind([](const gfx::PresentationFeedback&) {})); + gl_surface_->SwapBuffersAsync( + base::BindRepeating(&SurfacelessSkiaRenderer::PostRenderFrameTask, + weak_ptr_factory_.GetWeakPtr()), + base::DoNothing()); } -void SurfacelessGlRenderer::PostRenderFrameTask(gfx::SwapResult result) { +void SurfacelessSkiaRenderer::PostRenderFrameTask(gfx::SwapResult result) { switch (result) { case gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS: for (size_t i = 0; i < arraysize(buffers_); ++i) { buffers_[i].reset(new BufferWrapper()); - if (!buffers_[i]->Initialize(widget_, primary_plane_rect_.size())) + if (!buffers_[i]->Initialize(gr_context_.get(), widget_, + primary_plane_rect_.size())) LOG(FATAL) << "Failed to recreate buffer"; } - // Fall through since we want to render a new frame anyways. + FALLTHROUGH; // We want to render a new frame anyways. case gfx::SwapResult::SWAP_ACK: - GlRenderer::PostRenderFrameTask(result); + SkiaRenderer::PostRenderFrameTask(result); break; case gfx::SwapResult::SWAP_FAILED: LOG(FATAL) << "Failed to swap buffers"; diff --git a/chromium/ui/ozone/demo/surfaceless_skia_renderer.h b/chromium/ui/ozone/demo/surfaceless_skia_renderer.h new file mode 100644 index 00000000000..b61a19dbb12 --- /dev/null +++ b/chromium/ui/ozone/demo/surfaceless_skia_renderer.h @@ -0,0 +1,51 @@ +// Copyright 2018 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_OZONE_DEMO_SURFACELESS_SKIA_RENDERER_H_ +#define UI_OZONE_DEMO_SURFACELESS_SKIA_RENDERER_H_ + +#include <memory> + +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/ozone/demo/skia_renderer.h" + +namespace ui { +class OverlayCandidatesOzone; + +class SurfacelessSkiaRenderer : public SkiaRenderer { + public: + SurfacelessSkiaRenderer(gfx::AcceleratedWidget widget, + const scoped_refptr<gl::GLSurface>& surface, + const gfx::Size& size); + ~SurfacelessSkiaRenderer() override; + + // Renderer: + bool Initialize() override; + + private: + // SkiaRenderer: + void RenderFrame() override; + void PostRenderFrameTask(gfx::SwapResult result) override; + + class BufferWrapper; + + std::unique_ptr<BufferWrapper> buffers_[2]; + + std::unique_ptr<BufferWrapper> overlay_buffer_[2]; + bool disable_primary_plane_ = false; + gfx::Rect primary_plane_rect_; + + std::unique_ptr<OverlayCandidatesOzone> overlay_checker_; + + int back_buffer_ = 0; + + base::WeakPtrFactory<SurfacelessSkiaRenderer> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(SurfacelessSkiaRenderer); +}; + +} // namespace ui + +#endif // UI_OZONE_DEMO_SURFACELESS_SKIA_RENDERER_H_ diff --git a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc index 66e1fefbe4c..52a42f83617 100644 --- a/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc +++ b/chromium/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc @@ -9,6 +9,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/client_native_pixmap.h" +#include "ui/gfx/client_native_pixmap_factory.h" #include "ui/gl/gl_image_native_pixmap.h" #include "ui/gl/test/gl_image_test_template.h" #include "ui/ozone/public/client_native_pixmap_factory_ozone.h" @@ -25,8 +26,11 @@ template <gfx::BufferUsage usage, gfx::BufferFormat format> class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase { public: GLImageNativePixmapTestDelegate() { - client_pixmap_factory_ = ui::CreateClientNativePixmapFactoryOzone(); + ui::CreateClientNativePixmapFactoryOzone(); } + + ~GLImageNativePixmapTestDelegate() override = default; + scoped_refptr<GLImage> CreateSolidColorImage(const gfx::Size& size, const uint8_t color[4]) const { ui::SurfaceFactoryOzone* surface_factory = @@ -37,8 +41,9 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase { DCHECK(pixmap); if (usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE || usage == gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE) { - auto client_pixmap = client_pixmap_factory_->ImportFromHandle( - pixmap->ExportHandle(), size, usage); + auto client_pixmap = + gfx::ClientNativePixmapFactory::GetInstance()->ImportFromHandle( + pixmap->ExportHandle(), size, usage); bool mapped = client_pixmap->Map(); EXPECT_TRUE(mapped); @@ -72,7 +77,7 @@ class GLImageNativePixmapTestDelegate : public GLImageTestDelegateBase { } private: - std::unique_ptr<gfx::ClientNativePixmapFactory> client_pixmap_factory_; + DISALLOW_COPY_AND_ASSIGN(GLImageNativePixmapTestDelegate); }; using GLImageScanoutType = testing::Types< diff --git a/chromium/ui/ozone/platform/cast/BUILD.gn b/chromium/ui/ozone/platform/cast/BUILD.gn index fd92abf268b..eac0aae8c8b 100644 --- a/chromium/ui/ozone/platform/cast/BUILD.gn +++ b/chromium/ui/ozone/platform/cast/BUILD.gn @@ -40,7 +40,7 @@ source_set("cast") { deps = [ "//base", - "//chromecast:chromecast_features", + "//chromecast:chromecast_buildflags", "//chromecast/base:base", "//chromecast/graphics:libcast_graphics_1.0", "//ui/events/ozone:events_ozone", diff --git a/chromium/ui/ozone/platform/cast/DEPS b/chromium/ui/ozone/platform/cast/DEPS index ffc9eafa338..06cf3c34e0b 100644 --- a/chromium/ui/ozone/platform/cast/DEPS +++ b/chromium/ui/ozone/platform/cast/DEPS @@ -1,6 +1,6 @@ include_rules = [ "+chromecast/base/cast_features.h", "+chromecast/base/chromecast_switches.h", - "+chromecast/chromecast_features.h", + "+chromecast/chromecast_buildflags.h", "+chromecast/public" ] diff --git a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc index b2eed765638..bf14fa286ed 100644 --- a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc +++ b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc @@ -10,7 +10,7 @@ #include "base/lazy_instance.h" #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "chromecast/chromecast_features.h" +#include "chromecast/chromecast_buildflags.h" #include "chromecast/public/cast_egl_platform.h" #include "chromecast/public/cast_egl_platform_shlib.h" #include "ui/display/types/native_display_delegate.h" diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn index 3eee6279e62..99fc0d66bf2 100644 --- a/chromium/ui/ozone/platform/drm/BUILD.gn +++ b/chromium/ui/ozone/platform/drm/BUILD.gn @@ -81,6 +81,8 @@ source_set("gbm") { "gpu/screen_manager.h", "host/drm_cursor.cc", "host/drm_cursor.h", + "host/drm_device_connector.cc", + "host/drm_device_connector.h", "host/drm_device_handle.cc", "host/drm_device_handle.h", "host/drm_display_host.cc", diff --git a/chromium/ui/ozone/platform/drm/DEPS b/chromium/ui/ozone/platform/drm/DEPS index 7d49ef1703b..69f499a9025 100644 --- a/chromium/ui/ozone/platform/drm/DEPS +++ b/chromium/ui/ozone/platform/drm/DEPS @@ -2,6 +2,7 @@ include_rules = [ "+mojo/public", "+services/service_manager", "+services/ui", + "+ui/base/ui_base_features.h", "+ui/base/ui_base_switches.h", "+ui/base/ui_features.h", # UI features doesn't bring in all of ui/base. "+ui/display/util", diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc index ef596c0689b..88456854b97 100644 --- a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc +++ b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.cc @@ -120,12 +120,6 @@ bool CrtcController::SchedulePageFlip( return true; } -bool CrtcController::IsFormatSupported(uint32_t fourcc_format, - uint32_t z_order) const { - return drm_->plane_manager()->IsFormatSupported(fourcc_format, z_order, - crtc_); -} - std::vector<uint64_t> CrtcController::GetFormatModifiers(uint32_t format) { return drm_->plane_manager()->GetFormatModifiers(crtc_, format); } diff --git a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h index dcbd0ae0e0f..98b276711bd 100644 --- a/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h +++ b/chromium/ui/ozone/platform/drm/gpu/crtc_controller.h @@ -59,10 +59,6 @@ class CrtcController : public base::SupportsWeakPtr<CrtcController> { bool test_only, scoped_refptr<PageFlipRequest> page_flip_request); - // Returns true if hardware plane with z_order equal to |z_order| can support - // |fourcc_format| format. - bool IsFormatSupported(uint32_t fourcc_format, uint32_t z_order) const; - // Returns a vector of format modifiers for the given fourcc format // on this CRTCs primary plane. A format modifier describes the // actual layout of the buffer, such as whether it's linear, tiled diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc index 1abc94f9e20..15d5bae1977 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc @@ -75,18 +75,9 @@ std::vector<OverlayCheckReturn_Params> DrmOverlayValidator::TestPageFlip( continue; } - uint32_t original_format = - params[i].plane_z_order - ? GetFourCCFormatFromBufferFormat(params[i].format) - : GetFourCCFormatForOpaqueFramebuffer(params[i].format); - if (!controller->IsFormatSupported(original_format, - params[i].plane_z_order)) { - returns[i].status = OVERLAY_STATUS_NOT; - continue; - } - scoped_refptr<ScanoutBuffer> buffer = - GetBufferForPageFlipTest(drm, params[i].buffer_size, original_format, + GetBufferForPageFlipTest(drm, params[i].buffer_size, + GetFourCCFormatFromBufferFormat(params[i].format), buffer_generator_, &reusable_buffers); OverlayPlane plane(buffer, params[i].plane_z_order, params[i].transform, diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc index a00011f7bb2..566de8b0b67 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc @@ -77,17 +77,18 @@ class GbmDeviceGenerator : public DrmDeviceGenerator { } // namespace -DrmThread::DrmThread() - : base::Thread("DrmThread"), binding_(this), weak_ptr_factory_(this) {} +DrmThread::DrmThread() : base::Thread("DrmThread"), weak_ptr_factory_(this) {} DrmThread::~DrmThread() { Stop(); } -void DrmThread::Start() { +void DrmThread::Start(base::OnceClosure binding_completer) { + complete_early_binding_requests_ = std::move(binding_completer); base::Thread::Options thread_options; thread_options.message_loop_type = base::MessageLoop::TYPE_IO; thread_options.priority = base::ThreadPriority::DISPLAY; + if (!StartWithOptions(thread_options)) LOG(FATAL) << "Failed to create DRM thread"; } @@ -104,6 +105,13 @@ void DrmThread::Init() { display_manager_.reset( new DrmGpuDisplayManager(screen_manager_.get(), device_manager_.get())); + + DCHECK(task_runner()) + << "DrmThread::Init -- thread doesn't have a task_runner"; + + // DRM thread is running now so can safely handle binding requests. So drain + // the queue of as-yet unhandled binding requests if there are any. + std::move(complete_early_binding_requests_).Run(); } void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget, @@ -343,12 +351,12 @@ void DrmThread::StartDrmDevice(StartDrmDeviceCallback callback) { // be used from multiple threads in multiple processes. void DrmThread::AddBindingCursorDevice( ozone::mojom::DeviceCursorRequest request) { - bindings_.AddBinding(this, std::move(request)); + cursor_bindings_.AddBinding(this, std::move(request)); } void DrmThread::AddBindingDrmDevice(ozone::mojom::DrmDeviceRequest request) { TRACE_EVENT0("drm", "DrmThread::AddBindingDrmDevice"); - binding_.Bind(std::move(request)); + drm_bindings_.AddBinding(this, std::move(request)); } } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h index 5c0dcad5c22..1faf99947a0 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h @@ -62,7 +62,7 @@ class DrmThread : public base::Thread, DrmThread(); ~DrmThread() override; - void Start(); + void Start(base::OnceClosure binding_completer); // Must be called on the DRM thread. All methods for use from the GPU thread. // DrmThreadProxy (on GPU)thread) is the client for these methods. @@ -150,12 +150,16 @@ class DrmThread : public base::Thread, std::unique_ptr<ScreenManager> screen_manager_; std::unique_ptr<DrmGpuDisplayManager> display_manager_; + base::OnceClosure complete_early_binding_requests_; + // The mojo implementation requires a BindingSet because the DrmThread serves // requests from two different client threads. - mojo::BindingSet<ozone::mojom::DeviceCursor> bindings_; + mojo::BindingSet<ozone::mojom::DeviceCursor> cursor_bindings_; - // The mojo implementation of DrmDevice can use a simple binding. - mojo::Binding<ozone::mojom::DrmDevice> binding_; + // The mojo implementation of DrmDevice requires a BindingSet because the + // DrmThread services requests from different client threads when operating in + // mus mode + mojo::BindingSet<ozone::mojom::DrmDevice> drm_bindings_; base::WeakPtrFactory<DrmThread> weak_ptr_factory_; diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc index 24a88ec901a..6e1d4a749e3 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc @@ -26,10 +26,6 @@ void DrmThreadMessageProxy::SetDrmThread(DrmThread* thread) { void DrmThreadMessageProxy::OnFilterAdded(IPC::Channel* channel) { sender_ = channel; - - // The DRM thread needs to be started late since we need to wait for the - // sandbox to start. - drm_thread_->Start(); } bool DrmThreadMessageProxy::OnMessageReceived(const IPC::Message& message) { diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc index bdc798cd2f8..2bad52ddd44 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc @@ -17,13 +17,15 @@ DrmThreadProxy::DrmThreadProxy() {} DrmThreadProxy::~DrmThreadProxy() {} +// Used only with the paramtraits implementation. void DrmThreadProxy::BindThreadIntoMessagingProxy( InterThreadMessagingProxy* messaging_proxy) { messaging_proxy->SetDrmThread(&drm_thread_); } -void DrmThreadProxy::StartDrmThread() { - drm_thread_.Start(); +// Used only for the mojo implementation. +void DrmThreadProxy::StartDrmThread(base::OnceClosure binding_drainer) { + drm_thread_.Start(std::move(binding_drainer)); } std::unique_ptr<DrmWindowProxy> DrmThreadProxy::CreateDrmWindowProxy( @@ -36,7 +38,10 @@ scoped_refptr<GbmBuffer> DrmThreadProxy::CreateBuffer( const gfx::Size& size, gfx::BufferFormat format, gfx::BufferUsage usage) { + DCHECK(drm_thread_.task_runner()) + << "no task runner! in DrmThreadProxy::CreateBuffer"; scoped_refptr<GbmBuffer> buffer; + PostSyncTask( drm_thread_.task_runner(), base::Bind(&DrmThread::CreateBuffer, base::Unretained(&drm_thread_), @@ -77,6 +82,9 @@ void DrmThreadProxy::AddBindingCursorDevice( void DrmThreadProxy::AddBindingDrmDevice( ozone::mojom::DrmDeviceRequest request) { + DCHECK(drm_thread_.task_runner()) << "DrmThreadProxy::AddBindingDrmDevice " + "drm_thread_ task runner missing"; + drm_thread_.task_runner()->PostTask( FROM_HERE, base::Bind(&DrmThread::AddBindingDrmDevice, diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h index c8a0b4b9c0b..d46de5a5faf 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h @@ -27,7 +27,7 @@ class DrmThreadProxy { void BindThreadIntoMessagingProxy(InterThreadMessagingProxy* messaging_proxy); - void StartDrmThread(); + void StartDrmThread(base::OnceClosure binding_drainer); std::unique_ptr<DrmWindowProxy> CreateDrmWindowProxy( gfx::AcceleratedWidget widget); diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.cc b/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.cc index 7f47511740d..4b153e21255 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.cc +++ b/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.cc @@ -23,8 +23,12 @@ bool DrmVSyncProvider::GetVSyncParametersIfAvailable( return false; } -bool DrmVSyncProvider::SupportGetVSyncParametersIfAvailable() { +bool DrmVSyncProvider::SupportGetVSyncParametersIfAvailable() const { return false; } +bool DrmVSyncProvider::IsHWClock() const { + return true; +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.h b/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.h index 6db9948ee68..d0ec9a6e142 100644 --- a/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.h +++ b/chromium/ui/ozone/platform/drm/gpu/drm_vsync_provider.h @@ -21,7 +21,8 @@ class DrmVSyncProvider : public gfx::VSyncProvider { void GetVSyncParameters(const UpdateVSyncCallback& callback) override; bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, base::TimeDelta* interval) override; - bool SupportGetVSyncParametersIfAvailable() override; + bool SupportGetVSyncParametersIfAvailable() const override; + bool IsHWClock() const override; private: DrmWindowProxy* window_; diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc index 2574cf69d67..de661e983a7 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.cc @@ -145,17 +145,6 @@ bool HardwareDisplayController::ActualSchedulePageFlip( return status; } -bool HardwareDisplayController::IsFormatSupported(uint32_t fourcc_format, - uint32_t z_order) const { - for (size_t i = 0; i < crtc_controllers_.size(); ++i) { - // Make sure all displays have overlay to support this format. - if (!crtc_controllers_[i]->IsFormatSupported(fourcc_format, z_order)) - return false; - } - - return true; -} - std::vector<uint64_t> HardwareDisplayController::GetFormatModifiers( uint32_t format) { std::vector<uint64_t> modifiers; @@ -235,39 +224,51 @@ void HardwareDisplayController::AddCrtc( std::unique_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( const scoped_refptr<DrmDevice>& drm, uint32_t crtc) { - for (auto it = crtc_controllers_.begin(); it != crtc_controllers_.end(); - ++it) { - if ((*it)->drm() == drm && (*it)->crtc() == crtc) { - std::unique_ptr<CrtcController> controller(std::move(*it)); - crtc_controllers_.erase(it); - - // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. - bool found = false; - for (auto it = crtc_controllers_.begin(); it != crtc_controllers_.end(); - ++it) { - if ((*it)->drm() == controller->drm()) { - found = true; - break; - } - } - if (found) { - std::vector<HardwareDisplayPlane*> all_planes; - HardwareDisplayPlaneList* plane_list = - owned_hardware_planes_[drm.get()].get(); - all_planes.swap(plane_list->old_plane_list); - for (auto* plane : all_planes) { - if (plane->owning_crtc() != crtc) - plane_list->old_plane_list.push_back(plane); - } - } else { - owned_hardware_planes_.erase(controller->drm().get()); - } - - return controller; - } + auto controller_it = std::find_if( + crtc_controllers_.begin(), crtc_controllers_.end(), + [drm, crtc](const std::unique_ptr<CrtcController>& crtc_controller) { + return crtc_controller->drm() == drm && crtc_controller->crtc() == crtc; + }); + if (controller_it == crtc_controllers_.end()) + return nullptr; + + std::unique_ptr<CrtcController> controller(std::move(*controller_it)); + crtc_controllers_.erase(controller_it); + + // Remove and disable only the planes owned by the CRTC we just + // removed. + std::vector<HardwareDisplayPlane*>& old_plane_list = + owned_hardware_planes_[drm.get()]->old_plane_list; + + // Move all the planes that have been committed in the last pageflip for this + // CRTC at the end of the collection. + auto first_plane_to_disable_it = + std::partition(old_plane_list.begin(), old_plane_list.end(), + [crtc](const HardwareDisplayPlane* plane) { + return plane->owning_crtc() != crtc; + }); + + // Disable the planes enabled with the last commit on |crtc|, otherwise + // the planes will be visible if the crtc is reassigned to another connector. + HardwareDisplayPlaneList hardware_plane_list; + std::copy(first_plane_to_disable_it, old_plane_list.end(), + std::back_inserter(hardware_plane_list.old_plane_list)); + drm->plane_manager()->DisableOverlayPlanes(&hardware_plane_list); + + // If it was the only CRTC for this drm device, we can remove the hardware + // planes list in |owned_hardware_planes_|. + if (std::find_if(crtc_controllers_.begin(), crtc_controllers_.end(), + [drm](const std::unique_ptr<CrtcController>& crtc) { + return crtc->drm() == drm; + }) == crtc_controllers_.end()) { + owned_hardware_planes_.erase(controller->drm().get()); + } else { + // Otherwise we can remove the planes assigned to |crtc| but we can't + // remove the entry in |owned_hardware_planes_|. + old_plane_list.erase(first_plane_to_disable_it, old_plane_list.end()); } - return nullptr; + return controller; } bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm, diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h index d96d66f4c9b..1fa3665c7dd 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_controller.h @@ -123,8 +123,6 @@ class HardwareDisplayController { // doesn't change any state. bool TestPageFlip(const OverlayPlaneList& plane_list); - bool IsFormatSupported(uint32_t fourcc_format, uint32_t z_order) const; - // Return the supported modifiers for |fourcc_format| for this // controller. std::vector<uint64_t> GetFormatModifiers(uint32_t fourcc_format); diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc index c102c12a820..b74520781ae 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc @@ -310,39 +310,6 @@ const std::vector<uint32_t>& HardwareDisplayPlaneManager::GetSupportedFormats() return supported_formats_; } -bool HardwareDisplayPlaneManager::IsFormatSupported(uint32_t fourcc_format, - uint32_t z_order, - uint32_t crtc_id) const { - bool format_supported = false; - int crtc_index = LookupCrtcIndex(crtc_id); - if (crtc_index < 0) { - LOG(ERROR) << "Cannot find crtc " << crtc_id; - return format_supported; - } - - // We dont have a way to query z_order of a plane. This is a temporary - // solution till driver exposes z_order property. - uint32_t plane_z_order = 0; - for (const auto& hardware_plane : planes_) { - if (plane_z_order > z_order) - break; - - if (!hardware_plane->CanUseForCrtc(crtc_index)) - continue; - - if (plane_z_order == z_order) { - if (hardware_plane->IsSupportedFormat(fourcc_format)) - format_supported = true; - - break; - } else { - plane_z_order++; - } - } - - return format_supported; -} - std::vector<uint64_t> HardwareDisplayPlaneManager::GetFormatModifiers( uint32_t crtc_id, uint32_t format) { diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h index 175ca07a60c..f49d7cbd611 100644 --- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h +++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h @@ -109,13 +109,8 @@ class HardwareDisplayPlaneManager { virtual void RequestPlanesReadyCallback(const OverlayPlaneList& planes, base::OnceClosure callback) = 0; - // Returns all formats which can be scanned out by this PlaneManager. Use - // IsFormatSupported to find if a given format is supported on a particular - // plane for a given crtc. + // Returns all formats which can be scanned out by this PlaneManager. const std::vector<uint32_t>& GetSupportedFormats() const; - bool IsFormatSupported(uint32_t fourcc_format, - uint32_t z_order, - uint32_t crtc_id) const; std::vector<uint64_t> GetFormatModifiers(uint32_t crtc_id, uint32_t format); diff --git a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc index ee3d518cc7b..2fe14daad7d 100644 --- a/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc +++ b/chromium/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc @@ -22,8 +22,6 @@ namespace { -void EmptySwapCallback(gfx::SwapResult, const gfx::PresentationFeedback&) {} - // Create a basic mode for a 6x4 screen. const drmModeModeInfo kDefaultMode = {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}}; @@ -505,7 +503,7 @@ TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) { window->SchedulePageFlip( std::vector<ui::OverlayPlane>( 1, ui::OverlayPlane(buffer, base::kInvalidPlatformFile)), - base::Bind(&EmptySwapCallback)); + base::DoNothing()); screen_manager_->AddWindow(1, std::move(window)); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); @@ -532,7 +530,7 @@ TEST_F(ScreenManagerTest, RejectBufferWithIncompatibleModifiers) { window->SchedulePageFlip( std::vector<ui::OverlayPlane>( 1, ui::OverlayPlane(buffer, base::kInvalidPlatformFile)), - base::Bind(&EmptySwapCallback)); + base::DoNothing()); screen_manager_->AddWindow(1, std::move(window)); screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector); diff --git a/chromium/ui/ozone/platform/drm/host/drm_device_connector.cc b/chromium/ui/ozone/platform/drm/host/drm_device_connector.cc new file mode 100644 index 00000000000..6bfc3cb1001 --- /dev/null +++ b/chromium/ui/ozone/platform/drm/host/drm_device_connector.cc @@ -0,0 +1,137 @@ +// Copyright 2018 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/ozone/platform/drm/host/drm_device_connector.h" + +#include "mojo/public/cpp/bindings/interface_request.h" +#include "mojo/public/cpp/system/message_pipe.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/ui/public/interfaces/constants.mojom.h" +#include "ui/base/ui_base_features.h" +#include "ui/ozone/platform/drm/host/host_drm_device.h" +#include "ui/ozone/public/gpu_platform_support_host.h" + +namespace { +// TODO(rjkroege): In the future when ozone/drm is always mojo-based, remove +// this utility code. +using BinderCallback = ui::GpuPlatformSupportHost::GpuHostBindInterfaceCallback; + +void BindInterfaceInGpuProcess(const std::string& interface_name, + mojo::ScopedMessagePipeHandle interface_pipe, + const BinderCallback& binder_callback) { + return binder_callback.Run(interface_name, std::move(interface_pipe)); +} + +template <typename Interface> +void BindInterfaceInGpuProcess(mojo::InterfaceRequest<Interface> request, + const BinderCallback& binder_callback) { + BindInterfaceInGpuProcess( + Interface::Name_, std::move(request.PassMessagePipe()), binder_callback); +} + +} // namespace + +namespace ui { + +DrmDeviceConnector::DrmDeviceConnector( + service_manager::Connector* connector, + scoped_refptr<HostDrmDevice> host_drm_device_) + : connector_(connector), + host_drm_device_(host_drm_device_), + ws_runner_(base::ThreadTaskRunnerHandle::IsSet() + ? base::ThreadTaskRunnerHandle::Get() + : nullptr) { + // Invariant: we only have a runner at startup if executing in mus mode. + DCHECK((ws_runner_ && features::IsMusEnabled()) || + (!ws_runner_ && !features::IsMusEnabled())); +} + +DrmDeviceConnector::~DrmDeviceConnector() {} + +void DrmDeviceConnector::OnGpuProcessLaunched( + int host_id, + scoped_refptr<base::SingleThreadTaskRunner> ui_runner, + scoped_refptr<base::SingleThreadTaskRunner> send_runner, + const base::RepeatingCallback<void(IPC::Message*)>& send_callback) { + NOTREACHED(); +} + +void DrmDeviceConnector::OnChannelDestroyed(int host_id) { + // TODO(rjkroege): Handle Viz restarting. + NOTIMPLEMENTED(); +} + +void DrmDeviceConnector::OnGpuServiceLaunched( + scoped_refptr<base::SingleThreadTaskRunner> ui_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_runner, + GpuHostBindInterfaceCallback binder) { + // We need to preserve |binder| to let us bind interfaces later. + binder_callback_ = std::move(binder); + if (am_running_in_ws_mode()) { + ui::ozone::mojom::DrmDevicePtr drm_device_ptr_ui, drm_device_ptr_ws; + ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ws, cursor_ptr_io; + + BindInterfaceDrmDevice(&drm_device_ptr_ui); + BindInterfaceDrmDevice(&drm_device_ptr_ws); + BindInterfaceDeviceCursor(&cursor_ptr_ws); + BindInterfaceDeviceCursor(&cursor_ptr_io); + + ws_runner_->PostTask( + FROM_HERE, + base::BindOnce(&HostDrmDevice::OnGpuServiceLaunched, host_drm_device_, + std::move(drm_device_ptr_ws), std::move(cursor_ptr_ws), + std::move(cursor_ptr_io))); + + ui_runner->PostTask( + FROM_HERE, + base::BindOnce(&HostDrmDevice::OnGpuServiceLaunchedCompositor, + host_drm_device_, std::move(drm_device_ptr_ui))); + + } else { + ui::ozone::mojom::DrmDevicePtr drm_device_ptr_ui; + ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui, cursor_ptr_io; + + BindInterfaceDrmDevice(&drm_device_ptr_ui); + BindInterfaceDeviceCursor(&cursor_ptr_ui); + BindInterfaceDeviceCursor(&cursor_ptr_io); + + ui_runner->PostTask( + FROM_HERE, + base::BindOnce(&HostDrmDevice::OnGpuServiceLaunched, host_drm_device_, + std::move(drm_device_ptr_ui), std::move(cursor_ptr_ui), + std::move(cursor_ptr_io))); + + ui_runner->PostTask( + FROM_HERE, + base::BindOnce(&HostDrmDevice::OnGpuServiceLaunchedCompositor, + host_drm_device_, std::move(drm_device_ptr_ui))); + } +} + +void DrmDeviceConnector::OnMessageReceived(const IPC::Message& message) { + NOTREACHED() << "This class should only be used with mojo transport but here " + "we're wrongly getting invoked to handle IPC communication."; +} + +void DrmDeviceConnector::BindInterfaceDrmDevice( + ui::ozone::mojom::DrmDevicePtr* drm_device_ptr) const { + if (connector_) { + connector_->BindInterface(ui::mojom::kServiceName, drm_device_ptr); + } else { + auto request = mojo::MakeRequest(drm_device_ptr); + BindInterfaceInGpuProcess(std::move(request), binder_callback_); + } +} + +void DrmDeviceConnector::BindInterfaceDeviceCursor( + ui::ozone::mojom::DeviceCursorPtr* cursor_ptr) const { + if (connector_) { + connector_->BindInterface(ui::mojom::kServiceName, cursor_ptr); + } else { + auto request = mojo::MakeRequest(cursor_ptr); + BindInterfaceInGpuProcess(std::move(request), binder_callback_); + } +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/drm/host/drm_device_connector.h b/chromium/ui/ozone/platform/drm/host/drm_device_connector.h new file mode 100644 index 00000000000..16659f78674 --- /dev/null +++ b/chromium/ui/ozone/platform/drm/host/drm_device_connector.h @@ -0,0 +1,73 @@ +// Copyright 2018 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_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_CONNECTOR_H_ +#define UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_CONNECTOR_H_ + +#include "ui/ozone/public/gpu_platform_support_host.h" +#include "ui/ozone/public/interfaces/device_cursor.mojom.h" +#include "ui/ozone/public/interfaces/drm_device.mojom.h" + +namespace service_manager { +class Connector; +} + +namespace ui { +class HostDrmDevice; + +// DrmDeviceConnector sets up mojo pipes connecting the Viz host to the DRM +// service. It operates in two modes: running on the I/O thread when invoked +// from content and running on the VizHost main thread when operating with a +// service_manager. +class DrmDeviceConnector : public GpuPlatformSupportHost { + public: + DrmDeviceConnector(service_manager::Connector* connector, + scoped_refptr<HostDrmDevice> host_drm_device_); + ~DrmDeviceConnector() override; + + // GpuPlatformSupportHost: + void OnGpuProcessLaunched( + int host_id, + scoped_refptr<base::SingleThreadTaskRunner> ui_runner, + scoped_refptr<base::SingleThreadTaskRunner> send_runner, + const base::RepeatingCallback<void(IPC::Message*)>& send_callback) + override; + void OnChannelDestroyed(int host_id) override; + void OnMessageReceived(const IPC::Message& message) override; + void OnGpuServiceLaunched( + scoped_refptr<base::SingleThreadTaskRunner> ui_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_runner, + GpuHostBindInterfaceCallback binder) override; + + // BindInterface arranges for the drm_device_ptr to be connected. + void BindInterfaceDrmDevice( + ui::ozone::mojom::DrmDevicePtr* drm_device_ptr) const; + + // BindInterface arranges for the cursor_ptr to be wired up. + void BindInterfaceDeviceCursor( + ui::ozone::mojom::DeviceCursorPtr* cursor_ptr) const; + + // BindableNow returns true if this DrmDeviceConnector is capable of binding a + // mojo endpoint for the DrmDevice service. + bool BindableNow() const { return !!connector_; } + + private: + bool am_running_in_ws_mode() { return !!ws_runner_; } + + // This will be present if the Viz host has a service manager. + service_manager::Connector* connector_; + + // This will be used if we are operating under content/gpu without a service + // manager. + GpuHostBindInterfaceCallback binder_callback_; + + scoped_refptr<HostDrmDevice> host_drm_device_; + scoped_refptr<base::SingleThreadTaskRunner> ws_runner_; + + DISALLOW_COPY_AND_ASSIGN(DrmDeviceConnector); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_CONNECTOR_H_
\ No newline at end of file diff --git a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc index c8267a2b827..6c7f4f4b510 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc +++ b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc @@ -9,6 +9,7 @@ #include "base/command_line.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h" #include "ui/ozone/common/gpu/ozone_gpu_messages.h" @@ -94,7 +95,7 @@ DrmGpuPlatformSupportHost::DrmGpuPlatformSupportHost(DrmCursor* cursor) if (ui_runner_) { weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); } else { - DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kMus)); + DCHECK(!features::IsMusEnabled()); } } @@ -117,6 +118,14 @@ bool DrmGpuPlatformSupportHost::IsConnected() { return host_id_ >= 0 && channel_established_; } +void DrmGpuPlatformSupportHost::OnGpuServiceLaunched( + scoped_refptr<base::SingleThreadTaskRunner> ui_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_runner, + GpuHostBindInterfaceCallback binder) { + NOTREACHED() << "DrmGpuPlatformSupportHost::OnGpuServiceLaunched shouldn't " + "be used with pre-mojo IPC"; +} + void DrmGpuPlatformSupportHost::OnGpuProcessLaunched( int host_id, scoped_refptr<base::SingleThreadTaskRunner> ui_runner, diff --git a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h index 1de15cee1cb..ebcb9d5ea0d 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h +++ b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h @@ -41,6 +41,10 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, scoped_refptr<base::SingleThreadTaskRunner> send_runner, const base::Callback<void(IPC::Message*)>& send_callback) override; void OnChannelDestroyed(int host_id) override; + void OnGpuServiceLaunched( + scoped_refptr<base::SingleThreadTaskRunner> ui_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_runner, + GpuHostBindInterfaceCallback binder) override; void OnMessageReceived(const IPC::Message& message) override; diff --git a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.h b/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.h index 03b5e6619a5..1dd9aa15595 100644 --- a/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.h +++ b/chromium/ui/ozone/platform/drm/host/drm_overlay_manager.h @@ -71,7 +71,7 @@ class DrmOverlayManager : public OverlayManagerOzone { base::MRUCache<OverlaySurfaceCandidateList, OverlayValidationCacheValue> cache_; // The cache can be accessed from multiple threads in some cases (e.g. with - // --mus, it can be accessed from the UI thread, and the window-service + // mus, it can be accessed from the UI thread, and the window-service // thread.) // TODO(rjkroege): In the future (with --enable-viz), this code will not need // the lock, but will require farther refactoring. diff --git a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc index ba5baeec450..fa2880dcb27 100644 --- a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc +++ b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.cc @@ -6,15 +6,17 @@ #include "services/service_manager/public/cpp/connector.h" #include "services/ui/public/interfaces/constants.mojom.h" +#include "ui/ozone/public/gpu_platform_support_host.h" namespace ui { -// We assume that this is invoked only on the UI thread. -HostCursorProxy::HostCursorProxy(service_manager::Connector* connector) - : connector_(connector->Clone()) { - ui_thread_ref_ = base::PlatformThread::CurrentRef(); - connector->BindInterface(ui::mojom::kServiceName, &main_cursor_ptr_); -} +// We assume that this is invoked only on the Mus/UI thread. +HostCursorProxy::HostCursorProxy( + ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr, + ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr) + : main_cursor_ptr_(std::move(main_cursor_ptr)), + evdev_cursor_ptr_(std::move(evdev_cursor_ptr)), + ui_thread_ref_(base::PlatformThread::CurrentRef()) {} HostCursorProxy::~HostCursorProxy() {} @@ -46,8 +48,14 @@ void HostCursorProxy::Move(gfx::AcceleratedWidget widget, // when the GpuThread/DrmThread pair are once again running), we need to run it // on cursor motions. void HostCursorProxy::InitializeOnEvdevIfNecessary() { + // TODO(rjkroege): Rebind on Viz process restart. + if (evdev_bound_) + return; + if (ui_thread_ref_ != base::PlatformThread::CurrentRef()) { - connector_->BindInterface(ui::mojom::kServiceName, &evdev_cursor_ptr_); + // Rebind the mojo pipe on the current thread. We expect this to be the + // thread running EVDEV. + evdev_cursor_ptr_.Bind(evdev_cursor_ptr_.PassInterface()); } } diff --git a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h index 42feece0e0e..87115dd28d7 100644 --- a/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h +++ b/chromium/ui/ozone/platform/drm/host/host_cursor_proxy.h @@ -9,10 +9,6 @@ #include "ui/ozone/platform/drm/host/drm_cursor.h" #include "ui/ozone/public/interfaces/device_cursor.mojom.h" -namespace service_manager { -class Connector; -} - namespace ui { // Ozone requires a IPC from the browser (or mus-ws) process to the gpu (or @@ -22,7 +18,8 @@ namespace ui { // priviledged process. class HostCursorProxy : public DrmCursorProxy { public: - explicit HostCursorProxy(service_manager::Connector* connector); + HostCursorProxy(ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr, + ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr); ~HostCursorProxy() override; private: @@ -34,13 +31,13 @@ class HostCursorProxy : public DrmCursorProxy { void Move(gfx::AcceleratedWidget window, const gfx::Point& point) override; void InitializeOnEvdevIfNecessary() override; - std::unique_ptr<service_manager::Connector> connector_; - // Mojo implementation of the DrmCursorProxy. - ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr_; - ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr_; + ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr_ = nullptr; + ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr_ = nullptr; base::PlatformThreadRef ui_thread_ref_; + bool evdev_bound_ = false; + DISALLOW_COPY_AND_ASSIGN(HostCursorProxy); }; diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc index 9d1311b89a5..36ff79ce673 100644 --- a/chromium/ui/ozone/platform/drm/host/host_drm_device.cc +++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.cc @@ -13,19 +13,15 @@ #include "services/ui/public/interfaces/constants.mojom.h" #include "ui/display/types/display_snapshot.h" #include "ui/ozone/platform/drm/common/drm_util.h" +#include "ui/ozone/platform/drm/host/drm_device_connector.h" #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" #include "ui/ozone/platform/drm/host/drm_overlay_manager.h" #include "ui/ozone/platform/drm/host/host_cursor_proxy.h" namespace ui { -HostDrmDevice::HostDrmDevice(DrmCursor* cursor, - service_manager::Connector* connector) - : cursor_(cursor), connector_(connector), weak_ptr_factory_(this) { - // Bind the viz process pointer here. - // TODO(rjkroege): Reconnect on error as that would indicate that the Viz - // process has failed. - connector->BindInterface(ui::mojom::kServiceName, &drm_device_ptr_); +HostDrmDevice::HostDrmDevice(DrmCursor* cursor) : cursor_(cursor) { + DETACH_FROM_THREAD(on_io_thread_); } HostDrmDevice::~HostDrmDevice() { @@ -34,15 +30,39 @@ HostDrmDevice::~HostDrmDevice() { observer.OnGpuThreadRetired(); } -void HostDrmDevice::AsyncStartDrmDevice() { - auto callback = base::BindOnce(&HostDrmDevice::OnDrmServiceStartedCallback, - weak_ptr_factory_.GetWeakPtr()); +// Setup the DRM device if we are using the ServiceManager. +void HostDrmDevice::AsyncStartDrmDevice(const DrmDeviceConnector& connector) { + DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); + + // We bind here using the provided connector object. + if (!connector.BindableNow()) + return; + + connector.BindInterfaceDrmDevice(&drm_device_ptr_); + + // Launch the DRM thread. + auto callback = + base::BindOnce(&HostDrmDevice::OnDrmServiceStartedCallback, this); drm_device_ptr_->StartDrmDevice(std::move(callback)); + + // Bind the cursor interface pointers. + ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui, cursor_ptr_io; + connector.BindInterfaceDeviceCursor(&cursor_ptr_ui); + + // This interface pointer is bound on the wrong thread. But that's OK because + // we'll re-bind it the first time that it's used from the I/O thread in + // HostCursorProxy. + connector.BindInterfaceDeviceCursor(&cursor_ptr_io); + + // Stash the cursor_proxy so that we can install it in the callback. + cursor_proxy_ = std::make_unique<HostCursorProxy>(std::move(cursor_ptr_ui), + std::move(cursor_ptr_io)); } +// TODO(rjkroege): Remove the need for this entry point. void HostDrmDevice::BlockingStartDrmDevice() { // Wait until startup related tasks posted to this thread that must precede - // blocking on + // blocking. base::RunLoop().RunUntilIdle(); bool success; @@ -54,15 +74,20 @@ void HostDrmDevice::BlockingStartDrmDevice() { return; } +// The callback is executed in response to getting back a message from a +// DrmDevice service that we launched earlier via ServiceManager. void HostDrmDevice::OnDrmServiceStartedCallback(bool success) { // This can be called multiple times in the course of single-threaded startup. + // Ignore invocations after we've started. if (connected_) return; + if (success == true) { connected_ = true; RunObservers(); } - // TODO(rjkroege): Handle failure of launching a viz process. + // TODO(rjkroege): Handle failure of launching a viz process with the + // ServiceManager. } void HostDrmDevice::ProvideManagers(DrmDisplayHostManager* display_manager, @@ -78,10 +103,9 @@ void HostDrmDevice::RunObservers() { observer.OnGpuThreadReady(); } - // The cursor is special since it will process input events on the IO thread - // and can by-pass the UI thread. This means that we need to special case it - // and notify it after all other observers/handlers are notified. - cursor_->SetDrmCursorProxy(std::make_unique<HostCursorProxy>(connector_)); + DCHECK(cursor_proxy_) + << "We should have already created a cursor proxy previously"; + cursor_->SetDrmCursorProxy(std::move(cursor_proxy_)); // TODO(rjkroege): Call ResetDrmCursorProxy when the mojo connection to the // DRM thread is broken. @@ -146,36 +170,37 @@ bool HostDrmDevice::GpuWindowBoundsChanged(gfx::AcceleratedWidget widget, return false; drm_device_ptr_->SetWindowBounds(widget, bounds); + return true; } // Services needed for DrmOverlayManager. void HostDrmDevice::RegisterHandlerForDrmOverlayManager( DrmOverlayManager* handler) { - // TODO(rjkroege): Permit overlay manager to run in viz when the display - // compositor runs in viz. - DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); + // TODO(rjkroege): Permit overlay manager to run in Viz when the display + // compositor runs in Viz. + DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); overlay_manager_ = handler; } void HostDrmDevice::UnRegisterHandlerForDrmOverlayManager() { - DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); + DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); overlay_manager_ = nullptr; } bool HostDrmDevice::GpuCheckOverlayCapabilities( gfx::AcceleratedWidget widget, const OverlaySurfaceCandidateList& overlays) { - DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); + DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_); if (!IsConnected()) return false; auto callback = - base::BindOnce(&HostDrmDevice::GpuCheckOverlayCapabilitiesCallback, - weak_ptr_factory_.GetWeakPtr()); + base::BindOnce(&HostDrmDevice::GpuCheckOverlayCapabilitiesCallback, this); + + drm_device_ptr_compositor_->CheckOverlayCapabilities(widget, overlays, + std::move(callback)); - drm_device_ptr_->CheckOverlayCapabilities(widget, overlays, - std::move(callback)); return true; } @@ -183,10 +208,11 @@ bool HostDrmDevice::GpuRefreshNativeDisplays() { DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); if (!IsConnected()) return false; + auto callback = - base::BindOnce(&HostDrmDevice::GpuRefreshNativeDisplaysCallback, - weak_ptr_factory_.GetWeakPtr()); + base::BindOnce(&HostDrmDevice::GpuRefreshNativeDisplaysCallback, this); drm_device_ptr_->RefreshNativeDisplays(std::move(callback)); + return true; } @@ -200,11 +226,11 @@ bool HostDrmDevice::GpuConfigureNativeDisplay(int64_t id, // TODO(rjkroege): Remove the use of mode here. auto mode = CreateDisplayModeFromParams(pmode); auto callback = - base::BindOnce(&HostDrmDevice::GpuConfigureNativeDisplayCallback, - weak_ptr_factory_.GetWeakPtr()); + base::BindOnce(&HostDrmDevice::GpuConfigureNativeDisplayCallback, this); drm_device_ptr_->ConfigureNativeDisplay(id, std::move(mode), origin, std::move(callback)); + return true; } @@ -213,9 +239,10 @@ bool HostDrmDevice::GpuDisableNativeDisplay(int64_t id) { if (!IsConnected()) return false; auto callback = - base::BindOnce(&HostDrmDevice::GpuDisableNativeDisplayCallback, - weak_ptr_factory_.GetWeakPtr()); + base::BindOnce(&HostDrmDevice::GpuDisableNativeDisplayCallback, this); + drm_device_ptr_->DisableNativeDisplay(id, std::move(callback)); + return true; } @@ -223,9 +250,11 @@ bool HostDrmDevice::GpuTakeDisplayControl() { DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); if (!IsConnected()) return false; - auto callback = base::BindOnce(&HostDrmDevice::GpuTakeDisplayControlCallback, - weak_ptr_factory_.GetWeakPtr()); + auto callback = + base::BindOnce(&HostDrmDevice::GpuTakeDisplayControlCallback, this); + drm_device_ptr_->TakeDisplayControl(std::move(callback)); + return true; } @@ -234,9 +263,10 @@ bool HostDrmDevice::GpuRelinquishDisplayControl() { if (!IsConnected()) return false; auto callback = - base::BindOnce(&HostDrmDevice::GpuRelinquishDisplayControlCallback, - weak_ptr_factory_.GetWeakPtr()); + base::BindOnce(&HostDrmDevice::GpuRelinquishDisplayControlCallback, this); + drm_device_ptr_->RelinquishDisplayControl(std::move(callback)); + return true; } @@ -246,7 +276,9 @@ bool HostDrmDevice::GpuAddGraphicsDevice(const base::FilePath& path, if (!IsConnected()) return false; base::File file(fd.release()); + drm_device_ptr_->AddGraphicsDevice(path, std::move(file)); + return true; } @@ -254,7 +286,9 @@ bool HostDrmDevice::GpuRemoveGraphicsDevice(const base::FilePath& path) { DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); if (!IsConnected()) return false; + drm_device_ptr_->RemoveGraphicsDevice(std::move(path)); + return true; } @@ -262,9 +296,10 @@ bool HostDrmDevice::GpuGetHDCPState(int64_t display_id) { DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); if (!IsConnected()) return false; - auto callback = base::BindOnce(&HostDrmDevice::GpuGetHDCPStateCallback, - weak_ptr_factory_.GetWeakPtr()); + auto callback = base::BindOnce(&HostDrmDevice::GpuGetHDCPStateCallback, this); + drm_device_ptr_->GetHDCPState(display_id, std::move(callback)); + return true; } @@ -273,9 +308,10 @@ bool HostDrmDevice::GpuSetHDCPState(int64_t display_id, DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); if (!IsConnected()) return false; - auto callback = base::BindOnce(&HostDrmDevice::GpuSetHDCPStateCallback, - weak_ptr_factory_.GetWeakPtr()); + auto callback = base::BindOnce(&HostDrmDevice::GpuSetHDCPStateCallback, this); + drm_device_ptr_->SetHDCPState(display_id, state, std::move(callback)); + return true; } @@ -345,4 +381,37 @@ void HostDrmDevice::GpuSetHDCPStateCallback(int64_t display_id, display_manager_->GpuUpdatedHDCPState(display_id, success); } +// Invoked in response to the successful launching of the GPU service. +void HostDrmDevice::OnGpuServiceLaunched( + ui::ozone::mojom::DrmDevicePtr drm_device_ptr, + ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui, + ui::ozone::mojom::DeviceCursorPtr cursor_ptr_io) { + DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_); + + // Rebind InterfacePtrs to the window server thread. + cursor_ptr_ui.Bind(cursor_ptr_ui.PassInterface()); + drm_device_ptr.Bind(drm_device_ptr.PassInterface()); + + drm_device_ptr_ = std::move(drm_device_ptr); + + // Make sure that we've launched the DRM device service in the Viz process. + auto callback = + base::BindOnce(&HostDrmDevice::OnDrmServiceStartedCallback, this); + drm_device_ptr_->StartDrmDevice(std::move(callback)); + + // The cursor is special since it will process input events on the IO thread + // and can by-pass the UI thread. As a result, it has an InterfacePtr for both + // the window server and I/O thread. cursor_ptr_io is already bound correctly + // to an I/O thread by GpuProcessHost. + cursor_proxy_ = std::make_unique<HostCursorProxy>(std::move(cursor_ptr_ui), + std::move(cursor_ptr_io)); +} + +void HostDrmDevice::OnGpuServiceLaunchedCompositor( + ui::ozone::mojom::DrmDevicePtr drm_device_ptr_compositor) { + DETACH_FROM_THREAD(on_ui_thread_); + drm_device_ptr_compositor.Bind(drm_device_ptr_compositor.PassInterface()); + drm_device_ptr_compositor_ = std::move(drm_device_ptr_compositor); +} + } // namespace ui diff --git a/chromium/ui/ozone/platform/drm/host/host_drm_device.h b/chromium/ui/ozone/platform/drm/host/host_drm_device.h index 47c5b18170d..0a5b41c8df2 100644 --- a/chromium/ui/ozone/platform/drm/host/host_drm_device.h +++ b/chromium/ui/ozone/platform/drm/host/host_drm_device.h @@ -14,6 +14,7 @@ #include "ui/gfx/native_widget_types.h" #include "ui/ozone/platform/drm/host/drm_cursor.h" #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h" +#include "ui/ozone/public/gpu_platform_support_host.h" #include "ui/ozone/public/interfaces/device_cursor.mojom.h" #include "ui/ozone/public/interfaces/drm_device.mojom.h" @@ -21,25 +22,23 @@ namespace display { class DisplaySnapshot; } -namespace service_manager { -class Connector; -} - namespace ui { class DrmDisplayHostManager; class DrmOverlayManager; class GpuThreadObserver; +class DrmDeviceConnector; +class HostCursorProxy; // This is the Viz host-side library for the DRM device service provided by the // viz process. -class HostDrmDevice : public GpuThreadAdapter { +class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>, + public GpuThreadAdapter { public: - HostDrmDevice(DrmCursor* cursor, service_manager::Connector* connector); - ~HostDrmDevice() override; + explicit HostDrmDevice(DrmCursor* cursor); // Start the DRM service. Runs the |OnDrmServiceStartedCallback| when the // service has launched and initiates the remaining startup. - void AsyncStartDrmDevice(); + void AsyncStartDrmDevice(const DrmDeviceConnector& connector); // Blocks until the DRM service has come up. Use this entry point only when // supporting launch of the service where the ozone UI and GPU @@ -49,6 +48,13 @@ class HostDrmDevice : public GpuThreadAdapter { void ProvideManagers(DrmDisplayHostManager* display_manager, DrmOverlayManager* overlay_manager); + void OnGpuServiceLaunched(ui::ozone::mojom::DrmDevicePtr drm_device_ptr, + ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui, + ui::ozone::mojom::DeviceCursorPtr cursor_ptr_io); + + void OnGpuServiceLaunchedCompositor( + ui::ozone::mojom::DrmDevicePtr drm_device_ptr_compositor); + // GpuThreadAdapter void AddGpuThreadObserver(GpuThreadObserver* observer) override; void RemoveGpuThreadObserver(GpuThreadObserver* observer) override; @@ -93,8 +99,24 @@ class HostDrmDevice : public GpuThreadAdapter { const gfx::Rect& bounds) override; private: + friend class base::RefCountedThreadSafe<HostDrmDevice>; + ~HostDrmDevice() override; + + void HostOnGpuServiceLaunched(); + + // BindInterface arranges for the drm_device_ptr to be wired up. + void BindInterfaceDrmDevice( + ui::ozone::mojom::DrmDevicePtr* drm_device_ptr) const; + + // BindInterface arranges for the cursor_ptr to be wired up. + void BindInterfaceDeviceCursor( + ui::ozone::mojom::DeviceCursorPtr* cursor_ptr) const; + void OnDrmServiceStartedCallback(bool success); + + // TODO(rjkroege): Get rid of the need for this method in a subsequent CL. void PollForSingleThreadReady(int previous_delay); + void RunObservers(); void GpuCheckOverlayCapabilitiesCallback( @@ -115,21 +137,31 @@ class HostDrmDevice : public GpuThreadAdapter { display::HDCPState state) const; void GpuSetHDCPStateCallback(int64_t display_id, bool success) const; - // Mojo implementation of the DrmDevice. + // Mojo implementation of the DrmDevice. Will be bound on the "main" thread. ui::ozone::mojom::DrmDevicePtr drm_device_ptr_; + // When running under mus, this is the UI thread specific DrmDevice ptr for + // use by the compositor. + ui::ozone::mojom::DrmDevicePtr drm_device_ptr_compositor_; + DrmDisplayHostManager* display_manager_; // Not owned. DrmOverlayManager* overlay_manager_; // Not owned. DrmCursor* cursor_; // Not owned. - service_manager::Connector* connector_; + std::unique_ptr<HostCursorProxy> cursor_proxy_; + + THREAD_CHECKER(on_io_thread_); // Needs to be rebound as is allocated on the + // window server thread. THREAD_CHECKER(on_window_server_thread_); + // When running under mus, some entry points are used from the mus thread + // and some are used from the ui thread. In general. In that case, the + // on_ui_thread_ and on_window_server_thread_ will differ. In particular, + // entry points used by the compositor use the ui thread. + THREAD_CHECKER(on_ui_thread_); bool connected_ = false; base::ObserverList<GpuThreadObserver> gpu_thread_observers_; - base::WeakPtrFactory<HostDrmDevice> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(HostDrmDevice); }; diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc index 3ad0de48ed2..963f77e8804 100644 --- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc +++ b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc @@ -4,8 +4,6 @@ #include "ui/ozone/platform/drm/ozone_platform_gbm.h" -#include <dlfcn.h> -#include <fcntl.h> #include <gbm.h> #include <stdlib.h> #include <xf86drm.h> @@ -37,6 +35,7 @@ #include "ui/ozone/platform/drm/gpu/scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h" #include "ui/ozone/platform/drm/host/drm_cursor.h" +#include "ui/ozone/platform/drm/host/drm_device_connector.h" #include "ui/ozone/platform/drm/host/drm_display_host_manager.h" #include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h" #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h" @@ -60,26 +59,6 @@ namespace ui { namespace { -class GlApiLoader { - public: - GlApiLoader() - : glapi_lib_(dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL)) {} - - ~GlApiLoader() { - if (glapi_lib_) - dlclose(glapi_lib_); - } - - private: - // HACK: gbm drivers have broken linkage. The Mesa DRI driver references - // symbols in the libglapi library however it does not explicitly link against - // it. That caused linkage errors when running an application that does not - // explicitly link against libglapi. - void* glapi_lib_; - - DISALLOW_COPY_AND_ASSIGN(GlApiLoader); -}; - class OzonePlatformGbm : public OzonePlatform { public: OzonePlatformGbm() @@ -100,47 +79,85 @@ class OzonePlatformGbm : public OzonePlatform { return event_factory_ozone_->input_controller(); } IPC::MessageFilter* GetGpuMessageFilter() override { - return gpu_message_filter_.get(); + if (using_mojo_) { + return nullptr; + } else { + return gpu_message_filter_.get(); + } } + GpuPlatformSupportHost* GetGpuPlatformSupportHost() override { - return gpu_platform_support_host_.get(); + if (using_mojo_) { + return drm_device_connector_.get(); + } else { + return gpu_platform_support_host_.get(); + } } + std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override { return event_factory_ozone_->CreateSystemInputInjector(); } + // In multi-process mode, this function must be executed in Viz as it sets up + // the callbacks needed for Mojo bindings. In single process mode, it may be + // called on any thread. It must follow one of |InitializeUI| or + // |InitializeGPU|. Invocations of this method when not using mojo will be + // ignored. While the caller may choose to invoke this method before entering + // the sandbox, the actual interface adding has to happen on the DRM Device + // thread and so will be deferred until the DRM thread is running. void AddInterfaces( service_manager::BinderRegistryWithArgs< const service_manager::BindSourceInfo&>* registry) override { + if (!using_mojo_) + return; + registry->AddInterface<ozone::mojom::DeviceCursor>( base::Bind(&OzonePlatformGbm::CreateDeviceCursorBinding, weak_factory_.GetWeakPtr()), - gpu_task_runner_); + base::ThreadTaskRunnerHandle::Get()); registry->AddInterface<ozone::mojom::DrmDevice>( base::Bind(&OzonePlatformGbm::CreateDrmDeviceBinding, weak_factory_.GetWeakPtr()), - gpu_task_runner_); + base::ThreadTaskRunnerHandle::Get()); } + + // Runs on the thread where AddInterfaces was invoked. But the endpoint is + // always bound on the DRM thread. void CreateDeviceCursorBinding( ozone::mojom::DeviceCursorRequest request, const service_manager::BindSourceInfo& source_info) { - if (drm_thread_proxy_) + if (drm_thread_started_) drm_thread_proxy_->AddBindingCursorDevice(std::move(request)); else pending_cursor_requests_.push_back(std::move(request)); } - + // Runs on the thread where AddInterfaces was invoked. But the endpoint is + // always bound on the DRM thread. // service_manager::InterfaceFactory<ozone::mojom::DrmDevice>: void CreateDrmDeviceBinding( ozone::mojom::DrmDeviceRequest request, const service_manager::BindSourceInfo& source_info) { - if (drm_thread_proxy_) + if (drm_thread_started_) drm_thread_proxy_->AddBindingDrmDevice(std::move(request)); else pending_gpu_adapter_requests_.push_back(std::move(request)); } + // Runs on the thread that invoked |AddInterfaces| to drain the queue of + // binding requests that could not be satisfied until the DRM thread is + // available (i.e. if waiting until the sandbox has been entered.) + void DrainBindingRequests() { + for (auto& request : pending_cursor_requests_) + drm_thread_proxy_->AddBindingCursorDevice(std::move(request)); + pending_cursor_requests_.clear(); + for (auto& request : pending_gpu_adapter_requests_) + drm_thread_proxy_->AddBindingDrmDevice(std::move(request)); + pending_gpu_adapter_requests_.clear(); + + drm_thread_started_ = true; + } + std::unique_ptr<PlatformWindow> CreatePlatformWindow( PlatformWindowDelegate* delegate, const gfx::Rect& bounds) override { @@ -159,21 +176,31 @@ class OzonePlatformGbm : public OzonePlatform { override { return std::make_unique<DrmNativeDisplayDelegate>(display_manager_.get()); } + void InitializeUI(const InitParams& args) override { - // Ozone drm can operate in three modes configured at runtime: + // Ozone drm can operate in four modes configured at + // runtime. Three process modes: // 1. legacy mode where host and viz components communicate // via param traits IPC. // 2. single-process mode where host and viz components - // communicate via in-process mojo. + // communicate via in-process mojo. Single-process mode can be single + // or multi-threaded. // 3. multi-process mode where host and viz components communicate // via mojo IPC. + // + // and 2 connection modes + // a. Viz is launched via content::GpuProcessHost and it notifies the + // ozone host when Viz becomes available. b. The ozone host uses a service + // manager to launch and connect to Viz. + // + // Combinations 1a, 2b, and 3a, and 3b are supported and expected to work. + // Combination 1a will hopefully be deprecated and replaced with 3a. + // Combination 2b adds undesirable code-debt and the intent is to remove it. + single_process_ = args.single_process; - using_mojo_ = args.connector != nullptr; + using_mojo_ = args.using_mojo || args.connector != nullptr; host_thread_ = base::PlatformThread::CurrentRef(); - DCHECK(!(using_mojo_ && !single_process_)) - << "Multiprocess Mojo is not supported yet."; - device_manager_ = CreateDeviceManager(); window_manager_.reset(new DrmWindowHostManager()); cursor_.reset(new DrmCursor(window_manager_.get())); @@ -191,12 +218,10 @@ class OzonePlatformGbm : public OzonePlatform { GpuThreadAdapter* adapter; - if (single_process_) - gl_api_loader_.reset(new GlApiLoader()); - if (using_mojo_) { - host_drm_device_ = - std::make_unique<HostDrmDevice>(cursor_.get(), args.connector); + host_drm_device_ = base::MakeRefCounted<HostDrmDevice>(cursor_.get()); + drm_device_connector_ = std::make_unique<DrmDeviceConnector>( + args.connector, host_drm_device_); adapter = host_drm_device_.get(); } else { gpu_platform_support_host_.reset( @@ -214,22 +239,14 @@ class OzonePlatformGbm : public OzonePlatform { if (using_mojo_) { host_drm_device_->ProvideManagers(display_manager_.get(), overlay_manager_.get()); - host_drm_device_->AsyncStartDrmDevice(); + host_drm_device_->AsyncStartDrmDevice(*drm_device_connector_); } } void InitializeGPU(const InitParams& args) override { - // TODO(rjkroege): services/ui should initialize this with a connector. - // However, in-progress refactorings in services/ui make it difficult to - // require this at present. Set using_mojo_ like below once this is - // complete. - // TODO(rjk): Make it possible to turn this on. - // using_mojo_ = args.connector != nullptr; + using_mojo_ = args.using_mojo; gpu_task_runner_ = base::ThreadTaskRunnerHandle::Get(); - if (!single_process_) - gl_api_loader_.reset(new GlApiLoader()); - InterThreadMessagingProxy* itmp; if (!using_mojo_) { scoped_refptr<DrmThreadMessageProxy> message_proxy( @@ -239,52 +256,53 @@ class OzonePlatformGbm : public OzonePlatform { } // NOTE: Can't start the thread here since this is called before sandbox - // initialization in multi-process Chrome. In mus, we start the DRM thread. + // initialization in multi-process Chrome. drm_thread_proxy_.reset(new DrmThreadProxy()); surface_factory_.reset(new GbmSurfaceFactory(drm_thread_proxy_.get())); if (!using_mojo_) { drm_thread_proxy_->BindThreadIntoMessagingProxy(itmp); - } else { - drm_thread_proxy_->StartDrmThread(); } - // When the viz process (and hence the gpu portion of ozone/gbm) is - // operating in a single process, the AddInterfaces method is best - // invoked before the GPU thread launches. As a result, requests to add - // mojom bindings to the as yet un-launched service will fail so we queue - // incoming binding requests until the GPU thread is running and play them - // back here. - for (auto& request : pending_cursor_requests_) - drm_thread_proxy_->AddBindingCursorDevice(std::move(request)); - pending_cursor_requests_.clear(); - for (auto& request : pending_gpu_adapter_requests_) - drm_thread_proxy_->AddBindingDrmDevice(std::move(request)); - pending_gpu_adapter_requests_.clear(); - // If InitializeGPU and InitializeUI are invoked on the same thread, startup // sequencing is complicated because tasks are queued on the unbound mojo // pipe connecting the UI (the host) to the DRM thread before the DRM thread - // is launched above. Special case this sequence vis the + // is launched above. Special case this sequence via the // BlockingStartDrmDevice API. // TODO(rjkroege): In a future when we have completed splitting Viz, it will // be possible to simplify this logic. - if (using_mojo_ && single_process_ && - host_thread_ == base::PlatformThread::CurrentRef()) { + if (using_mojo_ && single_process_) { CHECK(host_drm_device_) << "Mojo single-process mode requires a HostDrmDevice."; - host_drm_device_->BlockingStartDrmDevice(); + + // Wait here if host and gpu are one and the same thread. + if (host_thread_ == base::PlatformThread::CurrentRef()) { + // One-thread exection does not permit use of the sandbox. + AfterSandboxEntry(); + host_drm_device_->BlockingStartDrmDevice(); + } } } + // The DRM thread needs to be started late because we need to wait for the + // sandbox to start. This entry point in the Ozne API gives platforms + // flexibility in handing this requirement. + void AfterSandboxEntry() override { + CHECK(drm_thread_proxy_) << "AfterSandboxEntry before InitializeForGPU is " + "invalid startup order.\n"; + // Defer the actual startup of the DRM thread to here. + auto safe_binding_resquest_drainer = CreateSafeOnceCallback(base::BindOnce( + &OzonePlatformGbm::DrainBindingRequests, weak_factory_.GetWeakPtr())); + + drm_thread_proxy_->StartDrmThread(std::move(safe_binding_resquest_drainer)); + } + private: bool using_mojo_; bool single_process_; - base::PlatformThreadRef host_thread_; // Objects in the GPU process. std::unique_ptr<DrmThreadProxy> drm_thread_proxy_; - std::unique_ptr<GlApiLoader> gl_api_loader_; std::unique_ptr<GbmSurfaceFactory> surface_factory_; scoped_refptr<IPC::MessageFilter> gpu_message_filter_; scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_; @@ -293,6 +311,7 @@ class OzonePlatformGbm : public OzonePlatform { // running in single process mode. std::vector<ozone::mojom::DeviceCursorRequest> pending_cursor_requests_; std::vector<ozone::mojom::DrmDeviceRequest> pending_gpu_adapter_requests_; + bool drm_thread_started_; // gpu_platform_support_host_ is the IPC bridge to the GPU process while // host_drm_device_ is the mojo bridge to the Viz process. Only one can be in @@ -304,9 +323,11 @@ class OzonePlatformGbm : public OzonePlatform { // To avoid a use after free, the following two members should be declared // before the two managers, so that they're deleted after them. std::unique_ptr<DrmGpuPlatformSupportHost> gpu_platform_support_host_; - std::unique_ptr<HostDrmDevice> host_drm_device_; - // Objects in the Browser process. + // Objects in the host process. + std::unique_ptr<DrmDeviceConnector> drm_device_connector_; + scoped_refptr<HostDrmDevice> host_drm_device_; + base::PlatformThreadRef host_thread_; std::unique_ptr<DeviceManager> device_manager_; std::unique_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_; std::unique_ptr<DrmWindowHostManager> window_manager_; diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn index b8566cfd5ee..01957d3740f 100644 --- a/chromium/ui/ozone/platform/wayland/BUILD.gn +++ b/chromium/ui/ozone/platform/wayland/BUILD.gn @@ -32,6 +32,8 @@ source_set("wayland") { "wayland_pointer.h", "wayland_surface_factory.cc", "wayland_surface_factory.h", + "wayland_touch.cc", + "wayland_touch.h", "wayland_window.cc", "wayland_window.h", "xdg_surface_wrapper.cc", @@ -61,6 +63,7 @@ source_set("wayland") { "//ui/display/manager", "//ui/events", "//ui/events:dom_keycode_converter", + "//ui/events/ozone:events_ozone", "//ui/events/ozone:events_ozone_layout", "//ui/events/platform", "//ui/gfx", @@ -90,6 +93,7 @@ source_set("wayland_unittests") { "wayland_surface_factory_unittest.cc", "wayland_test.cc", "wayland_test.h", + "wayland_touch_unittest.cc", "wayland_window_unittest.cc", ] @@ -107,10 +111,6 @@ source_set("wayland_unittests") { import("//ui/base/ui_features.gni") if (use_xkbcommon) { - sources += [ - "mock_wayland_xkb_keyboard_layout_engine.cc", - "mock_wayland_xkb_keyboard_layout_engine.h", - ] deps += [ "//ui/events/keycodes:xkb" ] } diff --git a/chromium/ui/ozone/platform/wayland/fake_server.cc b/chromium/ui/ozone/platform/wayland/fake_server.cc index 8e9199889e4..7adfe81029e 100644 --- a/chromium/ui/ozone/platform/wayland/fake_server.cc +++ b/chromium/ui/ozone/platform/wayland/fake_server.cc @@ -152,10 +152,21 @@ void GetKeyboard(wl_client* client, wl_resource* resource, uint32_t id) { seat->keyboard.reset(new MockKeyboard(keyboard_resource)); } +void GetTouch(wl_client* client, wl_resource* resource, uint32_t id) { + auto* seat = static_cast<MockSeat*>(wl_resource_get_user_data(resource)); + wl_resource* touch_resource = wl_resource_create( + client, &wl_touch_interface, wl_resource_get_version(resource), id); + if (!touch_resource) { + wl_client_post_no_memory(client); + return; + } + seat->touch.reset(new MockTouch(touch_resource)); +} + const struct wl_seat_interface seat_impl = { &GetPointer, // get_pointer &GetKeyboard, // get_keyboard - nullptr, // get_touch, + &GetTouch, // get_touch, &DestroyResource, // release }; @@ -172,6 +183,12 @@ const struct wl_pointer_interface pointer_impl = { &DestroyResource, // release }; +// wl_touch + +const struct wl_touch_interface touch_impl = { + &DestroyResource, // release +}; + // xdg_surface, zxdg_surface_v6 and zxdg_toplevel shared methods. void SetTitle(wl_client* client, wl_resource* resource, const char* title) { @@ -395,6 +412,13 @@ MockKeyboard::MockKeyboard(wl_resource* resource) : ServerObject(resource) { MockKeyboard::~MockKeyboard() {} +MockTouch::MockTouch(wl_resource* resource) : ServerObject(resource) { + wl_resource_set_implementation(resource, &touch_impl, this, + &ServerObject::OnResourceDestroyed); +} + +MockTouch::~MockTouch() {} + void GlobalDeleter::operator()(wl_global* global) { wl_global_destroy(global); } diff --git a/chromium/ui/ozone/platform/wayland/fake_server.h b/chromium/ui/ozone/platform/wayland/fake_server.h index 3b09bdb9c36..816f5815e6f 100644 --- a/chromium/ui/ozone/platform/wayland/fake_server.h +++ b/chromium/ui/ozone/platform/wayland/fake_server.h @@ -119,6 +119,15 @@ class MockKeyboard : public ServerObject { DISALLOW_COPY_AND_ASSIGN(MockKeyboard); }; +class MockTouch : public ServerObject { + public: + explicit MockTouch(wl_resource* resource); + ~MockTouch() override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockTouch); +}; + struct GlobalDeleter { void operator()(wl_global* global); }; @@ -188,7 +197,11 @@ class MockOutput : public Global { DISALLOW_COPY_AND_ASSIGN(MockOutput); }; -// Manage wl_seat object: group of input devices. +// Manage wl_seat object. A seat is a group of keyboards, pointer and touch +// devices. This object is published as a global during start up, or when such a +// device is hot plugged. A seat typically has a pointer and maintains a +// keyboard focus and a pointer focus. +// https://people.freedesktop.org/~whot/wayland-doxygen/wayland/Server/structwl__seat__interface.html class MockSeat : public Global { public: MockSeat(); @@ -196,6 +209,7 @@ class MockSeat : public Global { std::unique_ptr<MockPointer> pointer; std::unique_ptr<MockKeyboard> keyboard; + std::unique_ptr<MockTouch> touch; private: DISALLOW_COPY_AND_ASSIGN(MockSeat); diff --git a/chromium/ui/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.cc b/chromium/ui/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.cc deleted file mode 100644 index 4dd5c352778..00000000000 --- a/chromium/ui/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 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/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.h" -#include "ui/events/keycodes/keyboard_code_conversion.h" - -#if !BUILDFLAG(USE_XKBCOMMON) -#error "This file should only be compiled if USE_XKBCOMMON is enabled." -#endif - -namespace ui { - -bool MockWaylandXkbKeyboardLayoutEngine::Lookup( - ui::DomCode dom_code, - int event_flags, - ui::DomKey* dom_key, - ui::KeyboardCode* key_code) const { - return DomCodeToUsLayoutDomKey(dom_code, event_flags, dom_key, key_code); -} - -} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.h b/chromium/ui/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.h deleted file mode 100644 index 8d60d2bbe32..00000000000 --- a/chromium/ui/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 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_OZONE_PLATFORM_WAYLAND_MOCK_WAYLAND_XKB_KEYBOARD_LAYOUT_ENGINE_H_ -#define UI_OZONE_PLATFORM_WAYLAND_MOCK_WAYLAND_XKB_KEYBOARD_LAYOUT_ENGINE_H_ - -#include "ui/base/ui_features.h" - -#if !BUILDFLAG(USE_XKBCOMMON) -#error "This file should only be included if USE_XKBCOMMON is enabled." -#endif - -#include "ui/events/ozone/layout/xkb/xkb_evdev_codes.h" -#include "ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.h" - -namespace ui { - -class MockWaylandXkbKeyboardLayoutEngine - : public ui::WaylandXkbKeyboardLayoutEngine { - public: - MockWaylandXkbKeyboardLayoutEngine(const ui::XkbKeyCodeConverter& converter) - : WaylandXkbKeyboardLayoutEngine(converter) {} - - void UpdateModifiers(uint32_t depressed_mods, - uint32_t latched_mods, - uint32_t locked_mods, - uint32_t group) override {} - void SetEventModifiers(ui::EventModifiers* event_modifiers) override {} - - private: - bool Lookup(ui::DomCode dom_code, - int event_flags, - ui::DomKey* dom_key, - ui::KeyboardCode* key_code) const override; - - DISALLOW_COPY_AND_ASSIGN(MockWaylandXkbKeyboardLayoutEngine); -}; - -} // namespace ui - -#endif // UI_OZONE_PLATFORM_WAYLAND_MOCK_WAYLAND_XKB_KEYBOARD_LAYOUT_ENGINE_H_ diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc index e94ef56855f..843d7c99fdf 100644 --- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc +++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc @@ -77,7 +77,7 @@ class OzonePlatformWayland : public OzonePlatform { void InitializeUI(const InitParams& args) override { #if BUILDFLAG(USE_XKBCOMMON) KeyboardLayoutEngineManager::SetKeyboardLayoutEngine( - std::make_unique<WaylandXkbKeyboardLayoutEngineImpl>( + std::make_unique<WaylandXkbKeyboardLayoutEngine>( xkb_evdev_code_converter_)); #else KeyboardLayoutEngineManager::SetKeyboardLayoutEngine( diff --git a/chromium/ui/ozone/platform/wayland/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/wayland_connection.cc index c36a990ad13..89cf855b386 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_connection.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_connection.cc @@ -107,6 +107,8 @@ void WaylandConnection::AddWindow(gfx::AcceleratedWidget widget, } void WaylandConnection::RemoveWindow(gfx::AcceleratedWidget widget) { + if (touch_) + touch_->RemoveTouchPoints(window_map_[widget]); window_map_.erase(widget); } @@ -273,6 +275,21 @@ void WaylandConnection::Capabilities(void* data, } else if (connection->keyboard_) { connection->keyboard_.reset(); } + if (capabilities & WL_SEAT_CAPABILITY_TOUCH) { + if (!connection->touch_) { + wl_touch* touch = wl_seat_get_touch(connection->seat_.get()); + if (!touch) { + LOG(ERROR) << "Failed to get wl_touch from seat"; + return; + } + connection->touch_ = std::make_unique<WaylandTouch>( + touch, base::Bind(&WaylandConnection::DispatchUiEvent, + base::Unretained(connection))); + connection->touch_->set_connection(connection); + } + } else if (connection->touch_) { + connection->touch_.reset(); + } connection->ScheduleFlush(); } diff --git a/chromium/ui/ozone/platform/wayland/wayland_connection.h b/chromium/ui/ozone/platform/wayland/wayland_connection.h index 50019bbff0e..e745efd5b6b 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_connection.h +++ b/chromium/ui/ozone/platform/wayland/wayland_connection.h @@ -14,6 +14,7 @@ #include "ui/ozone/platform/wayland/wayland_object.h" #include "ui/ozone/platform/wayland/wayland_output.h" #include "ui/ozone/platform/wayland/wayland_pointer.h" +#include "ui/ozone/platform/wayland/wayland_touch.h" namespace ui { @@ -93,6 +94,7 @@ class WaylandConnection : public PlatformEventSource, std::unique_ptr<WaylandPointer> pointer_; std::unique_ptr<WaylandKeyboard> keyboard_; + std::unique_ptr<WaylandTouch> touch_; bool scheduled_flush_ = false; bool watching_ = false; diff --git a/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc b/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc index a033e2dc81a..a2b2329dfe8 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_keyboard.cc @@ -5,7 +5,6 @@ #include "ui/ozone/platform/wayland/wayland_keyboard.h" #include <sys/mman.h> -#include <wayland-client.h> #include "base/files/scoped_file.h" #include "ui/base/ui_features.h" @@ -30,9 +29,14 @@ const int kXkbKeycodeOffset = 8; } // namespace +// static +const wl_callback_listener WaylandKeyboard::callback_listener_ = { + WaylandKeyboard::SyncCallback, +}; + WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard, const EventDispatchCallback& callback) - : obj_(keyboard), callback_(callback) { + : obj_(keyboard), callback_(callback), auto_repeat_handler_(this) { static const wl_keyboard_listener listener = { &WaylandKeyboard::Keymap, &WaylandKeyboard::Enter, &WaylandKeyboard::Leave, &WaylandKeyboard::Key, @@ -86,6 +90,12 @@ void WaylandKeyboard::Leave(void* data, uint32_t serial, wl_surface* surface) { WaylandWindow::FromSurface(surface)->set_keyboard_focus(false); + + WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data); + DCHECK(keyboard); + + // Upon window focus lose, reset the key repeat timers. + keyboard->auto_repeat_handler_.StopKeyRepeat(); } void WaylandKeyboard::Key(void* data, @@ -95,32 +105,20 @@ void WaylandKeyboard::Key(void* data, uint32_t key, uint32_t state) { WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data); - keyboard->connection_->set_serial(serial); + DCHECK(keyboard); - DomCode dom_code = - KeycodeConverter::NativeKeycodeToDomCode(key + kXkbKeycodeOffset); - if (dom_code == ui::DomCode::NONE) - return; - - uint8_t flags = keyboard->event_modifiers_.GetModifierFlags(); - DomKey dom_key; - KeyboardCode key_code; - if (!KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup( - dom_code, flags, &dom_key, &key_code)) - return; + keyboard->connection_->set_serial(serial); bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED; + int device_id = keyboard->obj_.id(); - // TODO(tonikitoo,msisov): only the two lines below if not handling repeat. - int flag = ModifierDomKeyToEventFlag(dom_key); - keyboard->UpdateModifier(flag, down); + keyboard->auto_repeat_handler_.UpdateKeyRepeat( + key, down, false /*suppress_auto_repeat*/, device_id); - ui::KeyEvent event( - down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, dom_code, - keyboard->event_modifiers_.GetModifierFlags(), dom_key, - base::TimeTicks() + base::TimeDelta::FromMilliseconds(time)); - event.set_source_device_id(keyboard->obj_.id()); - keyboard->callback_.Run(&event); + // TODO(tonikitoo,msisov): Handler 'repeat' parameter below. + keyboard->DispatchKey( + key, down, false /*repeat*/, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(time), device_id); } void WaylandKeyboard::Modifiers(void* data, @@ -141,8 +139,66 @@ void WaylandKeyboard::RepeatInfo(void* data, wl_keyboard* obj, int32_t rate, int32_t delay) { - // TODO(tonikitoo): Implement proper repeat handling. - NOTIMPLEMENTED(); + WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data); + DCHECK(keyboard); + + keyboard->auto_repeat_handler_.SetAutoRepeatRate( + base::TimeDelta::FromMilliseconds(delay), + base::TimeDelta::FromMilliseconds(rate)); +} + +void WaylandKeyboard::FlushInput(base::OnceClosure closure) { + if (sync_callback_) + return; + + auto_repeat_closure_ = std::move(closure); + + // wl_display_sync gives a chance for any key "up" events to arrive. + // With a well behaved wayland compositor this should ensure we never + // get spurious repeats. + sync_callback_.reset(wl_display_sync(connection_->display())); + wl_callback_add_listener(sync_callback_.get(), &callback_listener_, this); + wl_display_flush(connection_->display()); +} + +void WaylandKeyboard::DispatchKey(uint32_t key, + bool down, + bool repeat, + base::TimeTicks timestamp, + int device_id) { + DomCode dom_code = + KeycodeConverter::NativeKeycodeToDomCode(key + kXkbKeycodeOffset); + if (dom_code == ui::DomCode::NONE) + return; + + uint8_t flags = event_modifiers_.GetModifierFlags(); + DomKey dom_key; + KeyboardCode key_code; + if (!KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup( + dom_code, flags, &dom_key, &key_code)) + return; + + if (!repeat) { + int flag = ModifierDomKeyToEventFlag(dom_key); + UpdateModifier(flag, down); + } + + ui::KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, + dom_code, event_modifiers_.GetModifierFlags(), dom_key, + timestamp); + event.set_source_device_id(device_id); + callback_.Run(&event); +} + +void WaylandKeyboard::SyncCallback(void* data, + struct wl_callback* cb, + uint32_t time) { + WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data); + DCHECK(keyboard); + + std::move(keyboard->auto_repeat_closure_).Run(); + DCHECK(keyboard->auto_repeat_closure_.is_null()); + keyboard->sync_callback_.reset(); } void WaylandKeyboard::UpdateModifier(int modifier_flag, bool down) { diff --git a/chromium/ui/ozone/platform/wayland/wayland_keyboard.h b/chromium/ui/ozone/platform/wayland/wayland_keyboard.h index 727a9930a58..18b535a6051 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_keyboard.h +++ b/chromium/ui/ozone/platform/wayland/wayland_keyboard.h @@ -5,15 +5,18 @@ #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_ #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_ +#include <wayland-client.h> + #include "ui/events/event_modifiers.h" #include "ui/events/ozone/evdev/event_dispatch_callback.h" +#include "ui/events/ozone/keyboard/event_auto_repeat_handler.h" #include "ui/ozone/platform/wayland/wayland_object.h" namespace ui { class WaylandConnection; -class WaylandKeyboard { +class WaylandKeyboard : public EventAutoRepeatHandler::Delegate { public: WaylandKeyboard(wl_keyboard* keyboard, const EventDispatchCallback& callback); virtual ~WaylandKeyboard(); @@ -58,12 +61,28 @@ class WaylandKeyboard { int32_t rate, int32_t delay); + static void SyncCallback(void* data, struct wl_callback* cb, uint32_t time); + void UpdateModifier(int modifier_flag, bool down); + // EventAutoRepeatHandler::Delegate + void FlushInput(base::OnceClosure closure) override; + void DispatchKey(unsigned int key, + bool down, + bool repeat, + base::TimeTicks timestamp, + int device_id) override; + WaylandConnection* connection_ = nullptr; wl::Object<wl_keyboard> obj_; EventDispatchCallback callback_; EventModifiers event_modifiers_; + + // Key repeat handler. + static const wl_callback_listener callback_listener_; + EventAutoRepeatHandler auto_repeat_handler_; + base::OnceClosure auto_repeat_closure_; + wl::Object<wl_callback> sync_callback_; }; } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc index f5a7d801f8d..7ce077a7e97 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc @@ -5,13 +5,13 @@ #include <linux/input.h> #include <wayland-server.h> +#include "base/test/test_mock_time_task_runner.h" +#include "base/timer/timer.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event.h" #include "ui/ozone/platform/wayland/fake_server.h" #include "ui/ozone/platform/wayland/wayland_test.h" -#include "ui/ozone/platform/wayland/wayland_window.h" -#include "ui/ozone/test/mock_platform_window_delegate.h" #if BUILDFLAG(USE_XKBCOMMON) #include "base/memory/free_deleter.h" @@ -326,6 +326,138 @@ TEST_P(WaylandKeyboardTest, CapsLockModifier) { } #endif +TEST_P(WaylandKeyboardTest, EventAutoRepeat) { + struct wl_array empty; + wl_array_init(&empty); + + wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty); + wl_array_release(&empty); + + // Auto repeat info in ms. + uint32_t rate = 75; + uint32_t delay = 25; + + wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay); + + wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */, + WL_KEYBOARD_KEY_STATE_PRESSED); + + std::unique_ptr<Event> event; + EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event)); + + Sync(); + + { + scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner = + new base::TestMockTimeTaskRunner(); + base::TestMockTimeTaskRunner::ScopedContext scoped_context( + mock_time_task_runner.get()); + + // Keep it pressed for doubled the rate time, to ensure events get fired. + mock_time_task_runner->FastForwardBy( + base::TimeDelta::FromMilliseconds(rate * 2)); + } + + Sync(); + + std::unique_ptr<Event> event2; + EXPECT_CALL(delegate, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event2)); + + wl_keyboard_send_key(keyboard->resource(), 3, 0, 30 /* a */, + WL_KEYBOARD_KEY_STATE_RELEASED); + Sync(); +} + +TEST_P(WaylandKeyboardTest, NoEventAutoRepeatOnLeave) { + struct wl_array empty; + wl_array_init(&empty); + + wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty); + wl_array_release(&empty); + + // Auto repeat info in ms. + uint32_t rate = 75; + uint32_t delay = 25; + + wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay); + + wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */, + WL_KEYBOARD_KEY_STATE_PRESSED); + + std::unique_ptr<Event> event; + EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event)); + + Sync(); + + { + scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner = + new base::TestMockTimeTaskRunner(); + base::TestMockTimeTaskRunner::ScopedContext scoped_context( + mock_time_task_runner.get()); + + // Keep it pressed for doubled the rate time, to ensure events get fired. + mock_time_task_runner->FastForwardBy( + base::TimeDelta::FromMilliseconds(rate * 2)); + } + + wl_keyboard_send_leave(keyboard->resource(), 3, surface->resource()); + + Sync(); + + EXPECT_CALL(delegate, DispatchEvent(_)).Times(0); + + wl_keyboard_send_key(keyboard->resource(), 4, 0, 30 /* a */, + WL_KEYBOARD_KEY_STATE_RELEASED); + Sync(); +} + +TEST_P(WaylandKeyboardTest, NoEventAutoRepeatBeforeTimeout) { + struct wl_array empty; + wl_array_init(&empty); + + wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty); + wl_array_release(&empty); + + // Auto repeat info in ms. + uint32_t rate = 500; + uint32_t delay = 50; + + wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay); + + wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */, + WL_KEYBOARD_KEY_STATE_PRESSED); + + std::unique_ptr<Event> event; + EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event)); + + Sync(); + + { + scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner = + new base::TestMockTimeTaskRunner(); + base::TestMockTimeTaskRunner::ScopedContext scoped_context( + mock_time_task_runner.get()); + + // Keep it pressed for a fifth of the rate time, and no auto repeat events + // should get dispatched. + mock_time_task_runner->FastForwardBy( + base::TimeDelta::FromMilliseconds(rate / 5)); + } + + wl_keyboard_send_key(keyboard->resource(), 4, 0, 30 /* a */, + WL_KEYBOARD_KEY_STATE_RELEASED); + + std::unique_ptr<Event> event2; + EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event2)); + + Sync(); + ASSERT_TRUE(event2); + ASSERT_TRUE(event2->IsKeyEvent()); + + auto* key_event2 = event2->AsKeyEvent(); + EXPECT_EQ(ET_KEY_RELEASED, key_event2->type()); +} + INSTANTIATE_TEST_CASE_P(XdgVersionV5Test, WaylandKeyboardTest, ::testing::Values(kXdgShellV5)); diff --git a/chromium/ui/ozone/platform/wayland/wayland_object.cc b/chromium/ui/ozone/platform/wayland/wayland_object.cc index f800a9cd994..056175f2957 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_object.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_object.cc @@ -32,11 +32,22 @@ void delete_seat(wl_seat* seat) { wl_seat_destroy(seat); } +void delete_touch(wl_touch* touch) { + if (wl_touch_get_version(touch) >= WL_TOUCH_RELEASE_SINCE_VERSION) + wl_touch_release(touch); + else + wl_touch_destroy(touch); +} + } // namespace const wl_interface* ObjectTraits<wl_buffer>::interface = &wl_buffer_interface; void (*ObjectTraits<wl_buffer>::deleter)(wl_buffer*) = &wl_buffer_destroy; +const wl_interface* ObjectTraits<wl_callback>::interface = + &wl_callback_interface; +void (*ObjectTraits<wl_callback>::deleter)(wl_callback*) = &wl_callback_destroy; + const wl_interface* ObjectTraits<wl_compositor>::interface = &wl_compositor_interface; void (*ObjectTraits<wl_compositor>::deleter)(wl_compositor*) = @@ -72,6 +83,9 @@ void (*ObjectTraits<wl_shm_pool>::deleter)(wl_shm_pool*) = &wl_shm_pool_destroy; const wl_interface* ObjectTraits<wl_surface>::interface = &wl_surface_interface; void (*ObjectTraits<wl_surface>::deleter)(wl_surface*) = &wl_surface_destroy; +const wl_interface* ObjectTraits<wl_touch>::interface = &wl_touch_interface; +void (*ObjectTraits<wl_touch>::deleter)(wl_touch*) = &delete_touch; + const wl_interface* ObjectTraits<xdg_shell>::interface = &xdg_shell_interface; void (*ObjectTraits<xdg_shell>::deleter)(xdg_shell*) = &xdg_shell_destroy; diff --git a/chromium/ui/ozone/platform/wayland/wayland_object.h b/chromium/ui/ozone/platform/wayland/wayland_object.h index d6512fb682a..6c6d4316695 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_object.h +++ b/chromium/ui/ozone/platform/wayland/wayland_object.h @@ -10,6 +10,7 @@ #include <memory> struct wl_buffer; +struct wl_callback; struct wl_compositor; struct wl_keyboard; struct wl_output; @@ -19,6 +20,7 @@ struct wl_seat; struct wl_shm; struct wl_shm_pool; struct wl_surface; +struct wl_touch; struct xdg_shell; struct xdg_surface; struct zxdg_shell_v6; @@ -37,6 +39,12 @@ struct ObjectTraits<wl_buffer> { }; template <> +struct ObjectTraits<wl_callback> { + static const wl_interface* interface; + static void (*deleter)(wl_callback*); +}; + +template <> struct ObjectTraits<wl_compositor> { static const wl_interface* interface; static void (*deleter)(wl_compositor*); @@ -97,6 +105,12 @@ struct ObjectTraits<wl_surface> { }; template <> +struct ObjectTraits<wl_touch> { + static const wl_interface* interface; + static void (*deleter)(wl_touch*); +}; + +template <> struct ObjectTraits<xdg_shell> { static const wl_interface* interface; static void (*deleter)(xdg_shell*); diff --git a/chromium/ui/ozone/platform/wayland/wayland_test.cc b/chromium/ui/ozone/platform/wayland/wayland_test.cc index 19814dfb01c..7bc6c91e462 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_test.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_test.cc @@ -8,7 +8,7 @@ #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" #if BUILDFLAG(USE_XKBCOMMON) -#include "ui/ozone/platform/wayland/mock_wayland_xkb_keyboard_layout_engine.h" +#include "ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.h" #else #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h" #endif @@ -21,7 +21,7 @@ namespace ui { WaylandTest::WaylandTest() { #if BUILDFLAG(USE_XKBCOMMON) KeyboardLayoutEngineManager::SetKeyboardLayoutEngine( - std::make_unique<WaylandXkbKeyboardLayoutEngineImpl>( + std::make_unique<WaylandXkbKeyboardLayoutEngine>( xkb_evdev_code_converter_)); #else KeyboardLayoutEngineManager::SetKeyboardLayoutEngine( diff --git a/chromium/ui/ozone/platform/wayland/wayland_touch.cc b/chromium/ui/ozone/platform/wayland/wayland_touch.cc new file mode 100644 index 00000000000..b8dc5437f79 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/wayland_touch.cc @@ -0,0 +1,167 @@ +// Copyright 2018 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/ozone/platform/wayland/wayland_touch.h" + +#include <sys/mman.h> +#include <wayland-client.h> + +#include "base/files/scoped_file.h" +#include "base/memory/ptr_util.h" +#include "ui/base/ui_features.h" +#include "ui/events/event.h" +#include "ui/ozone/platform/wayland/wayland_connection.h" +#include "ui/ozone/platform/wayland/wayland_window.h" + +namespace ui { + +WaylandTouch::TouchPoint::TouchPoint() = default; + +WaylandTouch::TouchPoint::TouchPoint(gfx::Point location, + wl_surface* current_surface) + : surface(current_surface), last_known_location(location) {} + +WaylandTouch::TouchPoint::~TouchPoint() = default; + +//----------------------------------------------------------------------------- + +WaylandTouch::WaylandTouch(wl_touch* touch, + const EventDispatchCallback& callback) + : obj_(touch), callback_(callback) { + static const wl_touch_listener listener = { + &WaylandTouch::Down, &WaylandTouch::Up, &WaylandTouch::Motion, + &WaylandTouch::Frame, &WaylandTouch::Cancel, + }; + + wl_touch_add_listener(obj_.get(), &listener, this); +} + +WaylandTouch::~WaylandTouch() { + DCHECK(current_points_.empty()); +} + +void WaylandTouch::RemoveTouchPoints(const WaylandWindow* window) { + base::EraseIf(current_points_, + [window](const TouchPoints::value_type& point) { + return point.second.surface == window->surface(); + }); +} + +void WaylandTouch::MaybeUnsetFocus(const WaylandTouch::TouchPoints& points, + int32_t id, + wl_surface* surface) { + for (const auto& point : points) { + // Return early on the first other point having this surface. + if (surface == point.second.surface && id != point.first) + return; + } + DCHECK(surface); + WaylandWindow::FromSurface(surface)->set_touch_focus(false); +} + +void WaylandTouch::Down(void* data, + wl_touch* obj, + uint32_t serial, + uint32_t time, + struct wl_surface* surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) { + if (!surface) + return; + WaylandTouch* touch = static_cast<WaylandTouch*>(data); + DCHECK(touch); + touch->connection_->set_serial(serial); + WaylandWindow::FromSurface(surface)->set_touch_focus(true); + + // Make sure this touch point wasn't present before. + if (touch->current_points_.find(id) != touch->current_points_.end()) { + LOG(WARNING) << "Touch down fired with wrong id"; + return; + } + + EventType type = ET_TOUCH_PRESSED; + gfx::Point location(wl_fixed_to_double(x), wl_fixed_to_double(y)); + base::TimeTicks time_stamp = + base::TimeTicks() + base::TimeDelta::FromMilliseconds(time); + PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id); + TouchEvent event(type, location, time_stamp, pointer_details); + touch->callback_.Run(&event); + + touch->current_points_[id] = TouchPoint(location, surface); +} + +void WaylandTouch::Up(void* data, + wl_touch* obj, + uint32_t serial, + uint32_t time, + int32_t id) { + WaylandTouch* touch = static_cast<WaylandTouch*>(data); + DCHECK(touch); + const auto iterator = touch->current_points_.find(id); + + // Make sure this touch point was present before. + if (iterator == touch->current_points_.end()) { + LOG(WARNING) << "Touch up fired with no matching touch down"; + return; + } + + EventType type = ET_TOUCH_RELEASED; + base::TimeTicks time_stamp = + base::TimeTicks() + base::TimeDelta::FromMilliseconds(time); + PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id); + TouchEvent event(type, touch->current_points_[id].last_known_location, + time_stamp, pointer_details); + touch->callback_.Run(&event); + + touch->MaybeUnsetFocus(touch->current_points_, id, + touch->current_points_[id].surface); + touch->current_points_.erase(iterator); +} + +void WaylandTouch::Motion(void* data, + wl_touch* obj, + uint32_t time, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) { + WaylandTouch* touch = static_cast<WaylandTouch*>(data); + DCHECK(touch); + + // Make sure this touch point wasn't present before. + if (touch->current_points_.find(id) == touch->current_points_.end()) { + LOG(WARNING) << "Touch event fired with wrong id"; + return; + } + + EventType type = ET_TOUCH_MOVED; + gfx::Point location(wl_fixed_to_double(x), wl_fixed_to_double(y)); + base::TimeTicks time_stamp = + base::TimeTicks() + base::TimeDelta::FromMilliseconds(time); + PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id); + TouchEvent event(type, location, time_stamp, pointer_details); + touch->callback_.Run(&event); + touch->current_points_[id].last_known_location = location; +} + +void WaylandTouch::Frame(void* data, wl_touch* obj) {} + +void WaylandTouch::Cancel(void* data, wl_touch* obj) { + WaylandTouch* touch = static_cast<WaylandTouch*>(data); + DCHECK(touch); + for (auto& point : touch->current_points_) { + int32_t id = point.first; + + EventType type = ET_TOUCH_CANCELLED; + base::TimeTicks time_stamp = base::TimeTicks::Now(); + PointerDetails pointer_details(EventPointerType::POINTER_TYPE_TOUCH, id); + TouchEvent event(type, gfx::Point(), time_stamp, pointer_details); + touch->callback_.Run(&event); + + WaylandWindow::FromSurface(point.second.surface)->set_touch_focus(false); + } + touch->current_points_.clear(); +} + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/wayland_touch.h b/chromium/ui/ozone/platform/wayland/wayland_touch.h new file mode 100644 index 00000000000..ae097fd05a5 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/wayland_touch.h @@ -0,0 +1,80 @@ +// Copyright 2018 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_OZONE_PLATFORM_WAYLAND_WAYLAND_TOUCH_H_ +#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TOUCH_H_ + +#include <memory> + +#include "base/containers/flat_map.h" +#include "ui/events/ozone/evdev/event_dispatch_callback.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/ozone/platform/wayland/wayland_object.h" + +namespace ui { + +class WaylandConnection; +class WaylandWindow; + +class WaylandTouch { + public: + WaylandTouch(wl_touch* touch, const EventDispatchCallback& callback); + virtual ~WaylandTouch(); + + void set_connection(WaylandConnection* connection) { + connection_ = connection; + } + + void RemoveTouchPoints(const WaylandWindow* window); + + private: + struct TouchPoint { + TouchPoint(); + TouchPoint(gfx::Point location, wl_surface* current_surface); + ~TouchPoint(); + + wl_surface* surface = nullptr; + gfx::Point last_known_location; + }; + + using TouchPoints = base::flat_map<int32_t, TouchPoint>; + + void MaybeUnsetFocus(const TouchPoints& points, + int32_t id, + wl_surface* surface); + + // wl_touch_listener + static void Down(void* data, + wl_touch* obj, + uint32_t serial, + uint32_t time, + struct wl_surface* surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y); + static void Up(void* data, + wl_touch* obj, + uint32_t serial, + uint32_t time, + int32_t id); + static void Motion(void* data, + wl_touch* obj, + uint32_t time, + int32_t id, + wl_fixed_t x, + wl_fixed_t y); + static void Frame(void* data, wl_touch* obj); + static void Cancel(void* data, wl_touch* obj); + + WaylandConnection* connection_ = nullptr; + wl::Object<wl_touch> obj_; + EventDispatchCallback callback_; + TouchPoints current_points_; + + DISALLOW_COPY_AND_ASSIGN(WaylandTouch); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_TOUCH_H_ diff --git a/chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc new file mode 100644 index 00000000000..c9afacb6a22 --- /dev/null +++ b/chromium/ui/ozone/platform/wayland/wayland_touch_unittest.cc @@ -0,0 +1,89 @@ +// Copyright 2018 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 <linux/input.h> +#include <wayland-server.h> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/event.h" +#include "ui/ozone/platform/wayland/fake_server.h" +#include "ui/ozone/platform/wayland/wayland_test.h" +#include "ui/ozone/platform/wayland/wayland_window.h" +#include "ui/ozone/test/mock_platform_window_delegate.h" + +using ::testing::SaveArg; +using ::testing::_; + +namespace ui { + +namespace { + +ACTION_P(CloneEvent, ptr) { + *ptr = Event::Clone(*arg0); +} + +} // namespace + +class WaylandTouchTest : public WaylandTest { + public: + WaylandTouchTest() {} + + void SetUp() override { + WaylandTest::SetUp(); + + wl_seat_send_capabilities(server.seat()->resource(), + WL_SEAT_CAPABILITY_TOUCH); + + Sync(); + + touch = server.seat()->touch.get(); + ASSERT_TRUE(touch); + } + + protected: + void CheckEventType(ui::EventType event_type, ui::Event* event) { + ASSERT_TRUE(event); + ASSERT_TRUE(event->IsTouchEvent()); + + auto* key_event = event->AsTouchEvent(); + EXPECT_EQ(event_type, key_event->type()); + } + + wl::MockTouch* touch; + + private: + DISALLOW_COPY_AND_ASSIGN(WaylandTouchTest); +}; + +TEST_P(WaylandTouchTest, KeypressAndMotion) { + std::unique_ptr<Event> event; + EXPECT_CALL(delegate, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event)); + + wl_touch_send_down(touch->resource(), 1, 0, surface->resource(), 0 /* id */, + wl_fixed_from_int(50), wl_fixed_from_int(100)); + + Sync(); + CheckEventType(ui::ET_TOUCH_PRESSED, event.get()); + + wl_touch_send_motion(touch->resource(), 500, 0 /* id */, + wl_fixed_from_int(100), wl_fixed_from_int(100)); + + Sync(); + CheckEventType(ui::ET_TOUCH_MOVED, event.get()); + + wl_touch_send_up(touch->resource(), 1, 1000, 0 /* id */); + + Sync(); + CheckEventType(ui::ET_TOUCH_RELEASED, event.get()); +} + +INSTANTIATE_TEST_CASE_P(XdgVersionV5Test, + WaylandTouchTest, + ::testing::Values(kXdgShellV5)); +INSTANTIATE_TEST_CASE_P(XdgVersionV6Test, + WaylandTouchTest, + ::testing::Values(kXdgShellV6)); + +} // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.cc b/chromium/ui/ozone/platform/wayland/wayland_window.cc index 88881bf042a..bed831b995c 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_window.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_window.cc @@ -48,7 +48,7 @@ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate, connection_(connection), xdg_shell_objects_factory_(new XDGShellObjectFactory()), bounds_(bounds), - state_(ui::PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN) {} + state_(PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN) {} WaylandWindow::~WaylandWindow() { if (xdg_surface_) { @@ -143,32 +143,47 @@ void WaylandWindow::ReleaseCapture() { void WaylandWindow::ToggleFullscreen() { DCHECK(xdg_surface_); - DCHECK(!IsMinimized()); // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says // if xdg_surface_set_fullscreen() is not provided with wl_output, it's up to // the compositor to choose which display will be used to map this surface. - if (!IsFullscreen()) + if (!IsFullscreen()) { + // Client might have requested a fullscreen state while the window was in + // a maximized state. Thus, |restored_bounds_| can contain the bounds of a + // "normal" state before the window was maximized. We don't override them + // unless they are empty, because |bounds_| can contain bounds of a + // maximized window instead. + if (restored_bounds_.IsEmpty()) + restored_bounds_ = bounds_; xdg_surface_->SetFullscreen(); - else + } else { xdg_surface_->UnSetFullscreen(); + } + connection_->ScheduleFlush(); } void WaylandWindow::Maximize() { DCHECK(xdg_surface_); - DCHECK(!IsMaximized()); if (IsFullscreen()) ToggleFullscreen(); + // Keeps track of the previous bounds, which are used to restore a window + // after unmaximize call. We don't override |restored_bounds_| if they have + // already had value, which means the previous state has been a fullscreen + // state. That is, the bounds can be stored during a change from a normal + // state to a maximize state, and then preserved to be the same, when changing + // from maximized to fullscreen and back to a maximized state. + if (restored_bounds_.IsEmpty()) + restored_bounds_ = bounds_; + xdg_surface_->SetMaximized(); connection_->ScheduleFlush(); } void WaylandWindow::Minimize() { DCHECK(xdg_surface_); - DCHECK(!IsMinimized()); DCHECK(xdg_surface_); xdg_surface_->SetMinimized(); @@ -177,7 +192,7 @@ void WaylandWindow::Minimize() { // Wayland doesn't say if a window is minimized. Handle this case manually // here. We can track if the window was unminimized once wayland sends the // window is activated, and the previous state was minimized. - state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED; + state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED; } void WaylandWindow::Restore() { @@ -225,6 +240,8 @@ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& native_event) { return has_pointer_focus_; if (event->IsKeyEvent()) return has_keyboard_focus_; + if (event->IsTouchEvent()) + return has_touch_focus_; return false; } @@ -240,34 +257,25 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width, bool is_maximized, bool is_fullscreen, bool is_activated) { - // Change the window state only if the window is activated, because it's the - // only way to know if the window is not minimized. - if (is_activated) { - bool was_minimized = IsMinimized(); - - state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL; - if (is_maximized && !is_fullscreen) - state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED; - else if (is_fullscreen) - state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN; - - // Do not flood the WindowServer unless the previous state was minimized. - if (was_minimized) - delegate_->OnWindowStateChanged(state_); - } + // Propagate the window state information to the client. + PlatformWindowState old_state = state_; + if (IsMinimized() && !is_activated) + state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED; + else if (is_fullscreen) + state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN; + else if (is_maximized) + state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED; + else + state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL; - // Width or height set 0 means that we should decide on width and height by - // ourselves, but we don't want to set to anything else. Use previous size. - if (width == 0 || height == 0) { - width = GetBounds().width(); - height = GetBounds().height(); - } + if (old_state != state_) + delegate_->OnWindowStateChanged(state_); // Rather than call SetBounds here for every configure event, just save the // most recent bounds, and have WaylandConnection call ApplyPendingBounds // when it has finished processing events. We may get many configure events // in a row during an interactive resize, and only the last one matters. - pending_bounds_ = gfx::Rect(0, 0, width, height); + SetPendingBounds(width, height); } void WaylandWindow::OnCloseRequest() { @@ -275,15 +283,36 @@ void WaylandWindow::OnCloseRequest() { } bool WaylandWindow::IsMinimized() const { - return state_ == ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED; + return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED; } bool WaylandWindow::IsMaximized() const { - return state_ == ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED; + return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED; } bool WaylandWindow::IsFullscreen() const { - return state_ == ui::PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN; + return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN; +} + +void WaylandWindow::SetPendingBounds(int32_t width, int32_t height) { + // Width or height set to 0 means that we should decide on width and height by + // ourselves, but we don't want to set them to anything else. Use restored + // bounds size or the current bounds. + // + // Note: if the browser was started with --start-fullscreen and a user exits + // the fullscreen mode, wayland may set the width and height to be 1. Instead, + // explicitly set the bounds to the current desired ones or the previous + // bounds. + if (width <= 1 || height <= 1) { + pending_bounds_.set_size(restored_bounds_.IsEmpty() + ? GetBounds().size() + : restored_bounds_.size()); + } else { + pending_bounds_ = gfx::Rect(0, 0, width, height); + } + + if (!IsFullscreen() && !IsMaximized()) + restored_bounds_ = gfx::Rect(); } } // namespace ui diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.h b/chromium/ui/ozone/platform/wayland/wayland_window.h index a4485911414..8d205fa48b4 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_window.h +++ b/chromium/ui/ozone/platform/wayland/wayland_window.h @@ -35,7 +35,7 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { bool Initialize(); - wl_surface* surface() { return surface_.get(); } + wl_surface* surface() const { return surface_.get(); } // Apply the bounds specified in the most recent configure event. This should // be called after processing all pending events in the wayland connection. @@ -47,6 +47,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { // Set whether this window has keyboard focus and should dispatch key events. void set_keyboard_focus(bool focus) { has_keyboard_focus_ = focus; } + // Set whether this window has touch focus and should dispatch touch events. + void set_touch_focus(bool focus) { has_touch_focus_ = focus; } + // PlatformWindow void Show() override; void Hide() override; @@ -83,6 +86,8 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { bool IsMaximized() const; bool IsFullscreen() const; + void SetPendingBounds(int32_t width, int32_t height); + // Creates a surface window, which is visible as a main window. void CreateXdgSurface(); @@ -103,8 +108,11 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher { gfx::Rect bounds_; gfx::Rect pending_bounds_; + // The bounds of our window before we were maximized or fullscreen. + gfx::Rect restored_bounds_; bool has_pointer_focus_ = false; bool has_keyboard_focus_ = false; + bool has_touch_focus_ = false; // Stores current states of the window. ui::PlatformWindowState state_; diff --git a/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc index a36d769370f..2c2e2679a2a 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc @@ -94,24 +94,47 @@ TEST_P(WaylandWindowTest, SetTitle) { } TEST_P(WaylandWindowTest, MaximizeAndRestore) { - uint32_t serial = 12; wl_array states; InitializeWlArrayWithActivatedState(&states); + EXPECT_CALL(delegate, + OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_MAXIMIZED))); SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states); EXPECT_CALL(*GetXdgSurface(), SetMaximized()); - EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); window->Maximize(); - SendConfigureEvent(0, 0, serial, &states); + SendConfigureEvent(0, 0, 1, &states); Sync(); + EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL))); + EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); window->Restore(); + // Reinitialize wl_array, which removes previous old states. + InitializeWlArrayWithActivatedState(&states); + SendConfigureEvent(0, 0, 2, &states); + Sync(); } TEST_P(WaylandWindowTest, Minimize) { + wl_array states; + wl_array_init(&states); + + // Initialize to normal first. + EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL))); + SendConfigureEvent(0, 0, 1, &states); + Sync(); + EXPECT_CALL(*GetXdgSurface(), SetMinimized()); + // The state of the window must retain minimized, which means we are not + // notified about the state, because 1) minimized state was set manually + // in WaylandWindow, and it has been confirmed in a back call from the server, + // which resulted in the same state as before. + EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0); window->Minimize(); + // Reinitialize wl_array, which removes previous old states. + wl_array_init(&states); + SendConfigureEvent(0, 0, 2, &states); + Sync(); } TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { @@ -121,34 +144,173 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states); EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); - EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); + EXPECT_CALL(delegate, + OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_FULLSCREEN))); window->ToggleFullscreen(); SendConfigureEvent(0, 0, 1, &states); Sync(); + EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); + EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL))); window->Restore(); + // Reinitialize wl_array, which removes previous old states. + InitializeWlArrayWithActivatedState(&states); + SendConfigureEvent(0, 0, 2, &states); + Sync(); } TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { wl_array states; InitializeWlArrayWithActivatedState(&states); + EXPECT_CALL(*GetXdgSurface(), SetMaximized()); + EXPECT_CALL(delegate, + OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_MAXIMIZED))); + window->Maximize(); + SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states); + SendConfigureEvent(0, 0, 2, &states); + Sync(); + EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); + EXPECT_CALL(delegate, + OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_FULLSCREEN))); + window->ToggleFullscreen(); + SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states); + SendConfigureEvent(0, 0, 3, &states); + Sync(); + EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); - EXPECT_CALL(*GetXdgSurface(), SetMaximized()); EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); + EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL))); + window->Restore(); + // Reinitialize wl_array, which removes previous old states. + InitializeWlArrayWithActivatedState(&states); + SendConfigureEvent(0, 0, 4, &states); + Sync(); +} +TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) { + const gfx::Rect current_bounds = window->GetBounds(); + + wl_array states; + InitializeWlArrayWithActivatedState(&states); + + const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768); + EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds))); window->Maximize(); SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states); + SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1, + &states); + Sync(); + + EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds))); + // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method. + // Thus, using a toplevel object in XdgV6 case is not right thing. Use a + // surface here instead. + EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(), + current_bounds.height())); + window->Restore(); + // Reinitialize wl_array, which removes previous old states. + InitializeWlArrayWithActivatedState(&states); SendConfigureEvent(0, 0, 2, &states); Sync(); +} + +TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) { + const gfx::Rect current_bounds = window->GetBounds(); + + wl_array states; + InitializeWlArrayWithActivatedState(&states); + const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720); + EXPECT_CALL(delegate, OnBoundsChanged(Eq(fullscreen_bounds))); window->ToggleFullscreen(); SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states); - SendConfigureEvent(0, 0, 3, &states); + SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 1, + &states); Sync(); + EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds))); + // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method. + // Thus, using a toplevel object in XdgV6 case is not right thing. Use a + // surface here instead. + EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(), + current_bounds.height())); window->Restore(); + // Reinitialize wl_array, which removes previous old states. + InitializeWlArrayWithActivatedState(&states); + SendConfigureEvent(0, 0, 2, &states); + Sync(); +} + +TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) { + const gfx::Rect current_bounds = window->GetBounds(); + + wl_array states; + InitializeWlArrayWithActivatedState(&states); + + const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768); + EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds))); + window->Maximize(); + SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states); + SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1, + &states); + Sync(); + + const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720); + EXPECT_CALL(delegate, OnBoundsChanged(Eq(fullscreen_bounds))); + window->ToggleFullscreen(); + SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states); + SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 2, + &states); + Sync(); + + EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds))); + window->Maximize(); + // Reinitialize wl_array, which removes previous old states. + InitializeWlArrayWithActivatedState(&states); + SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states); + SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 3, + &states); + Sync(); + + EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds))); + // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method. + // Thus, using a toplevel object in XdgV6 case is not right thing. Use a + // surface here instead. + EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(), + current_bounds.height())); + window->Restore(); + // Reinitialize wl_array, which removes previous old states. + InitializeWlArrayWithActivatedState(&states); + SendConfigureEvent(0, 0, 4, &states); + Sync(); +} + +TEST_P(WaylandWindowTest, SendsBoundsOnRequest) { + const gfx::Rect initial_bounds = window->GetBounds(); + + const gfx::Rect new_bounds = gfx::Rect(0, 0, initial_bounds.width() + 10, + initial_bounds.height() + 10); + EXPECT_CALL(delegate, OnBoundsChanged(Eq(new_bounds))); + window->SetBounds(new_bounds); + + wl_array states; + InitializeWlArrayWithActivatedState(&states); + + // First case is when Wayland sends a configure event with 0,0 height and + // widht. + EXPECT_CALL(*xdg_surface, + SetWindowGeometry(0, 0, new_bounds.width(), new_bounds.height())) + .Times(2); + SendConfigureEvent(0, 0, 2, &states); + Sync(); + + // Second case is when Wayland sends a configure event with 1, 1 height and + // width. It looks more like a bug in Gnome Shell with Wayland as long as the + // documentation says it must be set to 0, 0, when wayland requests bounds. + SendConfigureEvent(0, 0, 3, &states); + Sync(); } TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) { diff --git a/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.cc b/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.cc index 367eb621e1f..b2600adbbd7 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.cc +++ b/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.cc @@ -9,11 +9,7 @@ namespace ui { -WaylandXkbKeyboardLayoutEngineImpl::WaylandXkbKeyboardLayoutEngineImpl( - const XkbKeyCodeConverter& converter) - : WaylandXkbKeyboardLayoutEngine(converter) {} - -void WaylandXkbKeyboardLayoutEngineImpl::SetKeymap(xkb_keymap* keymap) { +void WaylandXkbKeyboardLayoutEngine::SetKeymap(xkb_keymap* keymap) { XkbKeyboardLayoutEngine::SetKeymap(keymap); xkb_mod_indexes_.control = @@ -23,11 +19,10 @@ void WaylandXkbKeyboardLayoutEngineImpl::SetKeymap(xkb_keymap* keymap) { xkb_mod_indexes_.caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); } -void WaylandXkbKeyboardLayoutEngineImpl::UpdateModifiers( - uint32_t depressed_mods, - uint32_t latched_mods, - uint32_t locked_mods, - uint32_t group) { +void WaylandXkbKeyboardLayoutEngine::UpdateModifiers(uint32_t depressed_mods, + uint32_t latched_mods, + uint32_t locked_mods, + uint32_t group) { xkb_state_update_mask(xkb_state_.get(), depressed_mods, latched_mods, locked_mods, 0, 0, group); @@ -55,7 +50,7 @@ void WaylandXkbKeyboardLayoutEngineImpl::UpdateModifiers( event_modifiers_->SetModifierLock(MODIFIER_CAPS_LOCK, false); } -void WaylandXkbKeyboardLayoutEngineImpl::SetEventModifiers( +void WaylandXkbKeyboardLayoutEngine::SetEventModifiers( EventModifiers* event_modifiers) { event_modifiers_ = event_modifiers; } diff --git a/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.h b/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.h index ccb02e91bf2..18c8f8c53a6 100644 --- a/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.h +++ b/chromium/ui/ozone/platform/wayland/wayland_xkb_keyboard_layout_engine.h @@ -20,24 +20,12 @@ class WaylandXkbKeyboardLayoutEngine : public XkbKeyboardLayoutEngine { // Used to sync up client side 'xkb_state' instance with modifiers status // update from the compositor. - virtual void UpdateModifiers(uint32_t depressed_mods, - uint32_t latched_mods, - uint32_t locked_mods, - uint32_t group) = 0; - virtual void SetEventModifiers(EventModifiers* event_modifiers) = 0; -}; - -class WaylandXkbKeyboardLayoutEngineImpl - : public WaylandXkbKeyboardLayoutEngine { - public: - WaylandXkbKeyboardLayoutEngineImpl(const XkbKeyCodeConverter& converter); - void UpdateModifiers(uint32_t depressed_mods, uint32_t latched_mods, uint32_t locked_mods, - uint32_t group) override; + uint32_t group); - void SetEventModifiers(EventModifiers* event_modifiers) override; + void SetEventModifiers(EventModifiers* event_modifiers); private: void SetKeymap(xkb_keymap* keymap) override; diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn index a060b1fb592..e73f2cf063b 100644 --- a/chromium/ui/ozone/platform/x11/BUILD.gn +++ b/chromium/ui/ozone/platform/x11/BUILD.gn @@ -18,14 +18,21 @@ source_set("x11") { "ozone_platform_x11.h", "x11_cursor_factory_ozone.cc", "x11_cursor_factory_ozone.h", + "x11_cursor_ozone.cc", + "x11_cursor_ozone.h", "x11_surface_factory.cc", "x11_surface_factory.h", + "x11_window_manager_ozone.cc", + "x11_window_manager_ozone.h", + "x11_window_ozone.cc", + "x11_window_ozone.h", ] deps = [ "//base", "//skia", "//ui/base", + "//ui/base/x", "//ui/display/manager", "//ui/events", "//ui/events/devices", diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc index 05910639099..476f69ff287 100644 --- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc +++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc @@ -19,12 +19,12 @@ #include "ui/ozone/common/stub_overlay_manager.h" #include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h" #include "ui/ozone/platform/x11/x11_surface_factory.h" +#include "ui/ozone/platform/x11/x11_window_manager_ozone.h" +#include "ui/ozone/platform/x11/x11_window_ozone.h" #include "ui/ozone/public/gpu_platform_support_host.h" #include "ui/ozone/public/input_controller.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/platform_window/platform_window.h" -#include "ui/platform_window/x11/x11_window_manager_ozone.h" -#include "ui/platform_window/x11/x11_window_ozone.h" namespace ui { diff --git a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h index f564fe4d6ae..48859f4bfd5 100644 --- a/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_cursor_factory_ozone.h @@ -12,8 +12,8 @@ #include "base/macros.h" #include "ui/base/cursor/cursor.h" #include "ui/gfx/x/x11.h" +#include "ui/ozone/platform/x11/x11_cursor_ozone.h" #include "ui/ozone/public/cursor_factory_ozone.h" -#include "ui/platform_window/x11/x11_cursor_ozone.h" namespace ui { diff --git a/chromium/ui/platform_window/x11/x11_cursor_ozone.cc b/chromium/ui/ozone/platform/x11/x11_cursor_ozone.cc index 003634144e3..2790329148f 100644 --- a/chromium/ui/platform_window/x11/x11_cursor_ozone.cc +++ b/chromium/ui/ozone/platform/x11/x11_cursor_ozone.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/platform_window/x11/x11_cursor_ozone.h" +#include "ui/ozone/platform/x11/x11_cursor_ozone.h" #include "base/logging.h" #include "third_party/skia/include/core/SkBitmap.h" diff --git a/chromium/ui/platform_window/x11/x11_cursor_ozone.h b/chromium/ui/ozone/platform/x11/x11_cursor_ozone.h index 347db15c6c6..fae79f9cf5d 100644 --- a/chromium/ui/platform_window/x11/x11_cursor_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_cursor_ozone.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_PLATFORM_WINDOW_X11_X11_CURSOR_OZONE_H_ -#define UI_PLATFORM_WINDOW_X11_X11_CURSOR_OZONE_H_ +#ifndef UI_OZONE_PLATFORM_X11_X11_CURSOR_OZONE_H_ +#define UI_OZONE_PLATFORM_X11_X11_CURSOR_OZONE_H_ #include <vector> @@ -11,7 +11,6 @@ #include "base/memory/ref_counted.h" #include "ui/base/cursor/cursor.h" #include "ui/gfx/x/x11.h" -#include "ui/platform_window/x11/x11_window_export.h" class SkBitmap; @@ -23,8 +22,7 @@ namespace ui { // Ref counted class to hold an X11 cursor resource. Handles creating X11 cursor // resources from SkBitmap/hotspot and clears the X11 resources on destruction. -class X11_WINDOW_EXPORT X11CursorOzone - : public base::RefCounted<X11CursorOzone> { +class X11CursorOzone : public base::RefCounted<X11CursorOzone> { public: X11CursorOzone(const SkBitmap& bitmap, const gfx::Point& hotspot); X11CursorOzone(const std::vector<SkBitmap>& bitmaps, @@ -34,7 +32,7 @@ class X11_WINDOW_EXPORT X11CursorOzone // Creates a new cursor that is invisible. static scoped_refptr<X11CursorOzone> CreateInvisible(); - ::Cursor xcursor() const { return xcursor_; } + XID xcursor() const { return xcursor_; } private: friend class base::RefCounted<X11CursorOzone>; @@ -42,10 +40,11 @@ class X11_WINDOW_EXPORT X11CursorOzone X11CursorOzone(); ~X11CursorOzone(); - ::Cursor xcursor_ = x11::None; + XID xcursor_ = x11::None; DISALLOW_COPY_AND_ASSIGN(X11CursorOzone); }; } // namespace ui -#endif // UI_PLATFORM_WINDOW_X11_X11_CURSOR_OZONE_H_ + +#endif // UI_OZONE_PLATFORM_X11_X11_CURSOR_OZONE_H_ diff --git a/chromium/ui/platform_window/x11/x11_window_manager_ozone.cc b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.cc index d47d1725ed8..494c43cd6f2 100644 --- a/chromium/ui/platform_window/x11/x11_window_manager_ozone.cc +++ b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.cc @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/platform_window/x11/x11_window_manager_ozone.h" +#include "ui/ozone/platform/x11/x11_window_manager_ozone.h" + +#include "ui/ozone/platform/x11/x11_window_ozone.h" namespace ui { diff --git a/chromium/ui/platform_window/x11/x11_window_manager_ozone.h b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.h index e3cfca34372..884425c8571 100644 --- a/chromium/ui/platform_window/x11/x11_window_manager_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_window_manager_ozone.h @@ -2,17 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_PLATFORM_WINDOW_X11_X11_WINDOW_MANAGER_OZONE_H_ -#define UI_PLATFORM_WINDOW_X11_X11_WINDOW_MANAGER_OZONE_H_ +#ifndef UI_OZONE_PLATFORM_X11_X11_WINDOW_MANAGER_OZONE_H_ +#define UI_OZONE_PLATFORM_X11_X11_WINDOW_MANAGER_OZONE_H_ #include "base/macros.h" -#include "ui/platform_window/x11/x11_window_export.h" namespace ui { class X11WindowOzone; -class X11_WINDOW_EXPORT X11WindowManagerOzone { +class X11WindowManagerOzone { public: X11WindowManagerOzone(); ~X11WindowManagerOzone(); @@ -35,4 +34,4 @@ class X11_WINDOW_EXPORT X11WindowManagerOzone { } // namespace ui -#endif // UI_PLATFORM_WINDOW_X11_X11_WINDOW_MANAGER_OZONE_H_ +#endif // UI_OZONE_PLATFORM_X11_X11_WINDOW_MANAGER_OZONE_H_ diff --git a/chromium/ui/platform_window/x11/x11_window_ozone.cc b/chromium/ui/ozone/platform/x11/x11_window_ozone.cc index d62184a7a7c..1ce459877dc 100644 --- a/chromium/ui/platform_window/x11/x11_window_ozone.cc +++ b/chromium/ui/ozone/platform/x11/x11_window_ozone.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/platform_window/x11/x11_window_ozone.h" +#include "ui/ozone/platform/x11/x11_window_ozone.h" #include "base/bind.h" #include "ui/events/event.h" @@ -10,8 +10,8 @@ #include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/x/x11.h" -#include "ui/platform_window/x11/x11_cursor_ozone.h" -#include "ui/platform_window/x11/x11_window_manager_ozone.h" +#include "ui/ozone/platform/x11/x11_cursor_ozone.h" +#include "ui/ozone/platform/x11/x11_window_manager_ozone.h" namespace ui { diff --git a/chromium/ui/platform_window/x11/x11_window_ozone.h b/chromium/ui/ozone/platform/x11/x11_window_ozone.h index 8405aac49b1..48568ca420c 100644 --- a/chromium/ui/platform_window/x11/x11_window_ozone.h +++ b/chromium/ui/ozone/platform/x11/x11_window_ozone.h @@ -2,23 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_PLATFORM_WINDOW_X11_X11_WINDOW_OZONE_H_ -#define UI_PLATFORM_WINDOW_X11_X11_WINDOW_OZONE_H_ +#ifndef UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_ +#define UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_ #include "base/macros.h" #include "ui/events/platform/platform_event_dispatcher.h" #include "ui/events/platform/x11/x11_event_source_libevent.h" #include "ui/platform_window/x11/x11_window_base.h" -#include "ui/platform_window/x11/x11_window_export.h" namespace ui { class X11WindowManagerOzone; // PlatformWindow implementation for X11 Ozone. PlatformEvents are ui::Events. -class X11_WINDOW_EXPORT X11WindowOzone : public X11WindowBase, - public PlatformEventDispatcher, - public XEventDispatcher { +class X11WindowOzone : public X11WindowBase, + public PlatformEventDispatcher, + public XEventDispatcher { public: X11WindowOzone(X11WindowManagerOzone* window_manager, PlatformWindowDelegate* delegate, @@ -54,4 +53,4 @@ class X11_WINDOW_EXPORT X11WindowOzone : public X11WindowBase, } // namespace ui -#endif // UI_PLATFORM_WINDOW_X11_X11_WINDOW_OZONE_H_ +#endif // UI_OZONE_PLATFORM_X11_X11_WINDOW_OZONE_H_ diff --git a/chromium/ui/ozone/public/interfaces/DEPS b/chromium/ui/ozone/public/DEPS index ef8ad28d9d4..ef8ad28d9d4 100644 --- a/chromium/ui/ozone/public/interfaces/DEPS +++ b/chromium/ui/ozone/public/DEPS diff --git a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc index 7d6428b48d8..110f816c557 100644 --- a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc +++ b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.cc @@ -4,17 +4,50 @@ #include "ui/ozone/public/client_native_pixmap_factory_ozone.h" +#include <memory> + +#include "base/memory/singleton.h" #include "base/trace_event/trace_event.h" +#include "ui/gfx/client_native_pixmap_factory.h" #include "ui/ozone/platform_object.h" #include "ui/ozone/platform_selection.h" namespace ui { +namespace { + +// Thread-safe owner of the gfx::ClientNativePixmapFactory. Not a LazyInstance +// because it uses PlatformObject<>::Create() for factory construction. +// TODO(jamescook|spang): This exists to solve a startup race for chrome with +// mash http://crbug.com/807781. Removing the factory entirely would be better, +// with something like http://crrev.com/c/899949. +class PixmapFactorySingleton { + public: + static PixmapFactorySingleton* GetInstance() { + return base::Singleton<PixmapFactorySingleton>::get(); + } + + private: + friend struct base::DefaultSingletonTraits<PixmapFactorySingleton>; + + PixmapFactorySingleton() { + TRACE_EVENT1("ozone", "CreateClientNativePixmapFactoryOzone", "platform", + GetOzonePlatformName()); + pixmap_factory_ = PlatformObject<gfx::ClientNativePixmapFactory>::Create(); + gfx::ClientNativePixmapFactory::SetInstance(pixmap_factory_.get()); + } + + std::unique_ptr<gfx::ClientNativePixmapFactory> pixmap_factory_; + + DISALLOW_COPY_AND_ASSIGN(PixmapFactorySingleton); +}; + +} // namespace -std::unique_ptr<gfx::ClientNativePixmapFactory> -CreateClientNativePixmapFactoryOzone() { - TRACE_EVENT1("ozone", "CreateClientNativePixmapFactoryOzone", "platform", - GetOzonePlatformName()); - return PlatformObject<gfx::ClientNativePixmapFactory>::Create(); +void CreateClientNativePixmapFactoryOzone() { + // Multiple threads may race to create the factory (e.g. when the UI service + // and ash service are running in the same process). Create the object as a + // side effect of a thread-safe singleton. + PixmapFactorySingleton::GetInstance(); } } // namespace ui diff --git a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h index 744e868ad85..29d6b5019e4 100644 --- a/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h +++ b/chromium/ui/ozone/public/client_native_pixmap_factory_ozone.h @@ -5,13 +5,14 @@ #ifndef UI_OZONE_PUBLIC_CLIENT_NATIVE_PIXMAP_FACTORY_OZONE_H_ #define UI_OZONE_PUBLIC_CLIENT_NATIVE_PIXMAP_FACTORY_OZONE_H_ -#include "ui/gfx/client_native_pixmap_factory.h" #include "ui/ozone/ozone_export.h" namespace ui { -OZONE_EXPORT std::unique_ptr<gfx::ClientNativePixmapFactory> -CreateClientNativePixmapFactoryOzone(); +// Creates a factory for pixmaps that can use be transported from the client to +// the GPU process using a low-level ozone-provided platform specific mechanism. +// The factory is installed as the gfx::ClientNativePixmapFactory instance. +OZONE_EXPORT void CreateClientNativePixmapFactoryOzone(); } // namespace ui diff --git a/chromium/ui/ozone/public/gpu_platform_support_host.cc b/chromium/ui/ozone/public/gpu_platform_support_host.cc index 98a23b1965c..586186c093f 100644 --- a/chromium/ui/ozone/public/gpu_platform_support_host.cc +++ b/chromium/ui/ozone/public/gpu_platform_support_host.cc @@ -23,6 +23,10 @@ class StubGpuPlatformSupportHost : public GpuPlatformSupportHost { void OnChannelDestroyed(int host_id) override {} void OnMessageReceived(const IPC::Message&) override {} + void OnGpuServiceLaunched( + scoped_refptr<base::SingleThreadTaskRunner> ui_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_runner, + GpuHostBindInterfaceCallback binder) override {} }; } // namespace diff --git a/chromium/ui/ozone/public/gpu_platform_support_host.h b/chromium/ui/ozone/public/gpu_platform_support_host.h index 50db642788d..f1120e74751 100644 --- a/chromium/ui/ozone/public/gpu_platform_support_host.h +++ b/chromium/ui/ozone/public/gpu_platform_support_host.h @@ -5,10 +5,13 @@ #ifndef UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_ #define UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_ +#include <string> + #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" +#include "mojo/public/cpp/bindings/binding.h" #include "ui/ozone/ozone_base_export.h" namespace ui { @@ -24,6 +27,10 @@ namespace ui { // to support additional messages needed by specific platforms. class OZONE_BASE_EXPORT GpuPlatformSupportHost { public: + using GpuHostBindInterfaceCallback = + base::RepeatingCallback<void(const std::string&, + mojo::ScopedMessagePipeHandle)>; + GpuPlatformSupportHost(); virtual ~GpuPlatformSupportHost(); @@ -42,6 +49,13 @@ class OZONE_BASE_EXPORT GpuPlatformSupportHost { // Called to handle an IPC message. Note that this can be called from any // thread. virtual void OnMessageReceived(const IPC::Message& message) = 0; + + // Called when the GPU service is launched. + // Called from the browser IO thread. + virtual void OnGpuServiceLaunched( + scoped_refptr<base::SingleThreadTaskRunner> host_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_runner, + GpuHostBindInterfaceCallback binder) = 0; }; // create a stub implementation. diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc index 8b41780f5db..58c114ba430 100644 --- a/chromium/ui/ozone/public/ozone_platform.cc +++ b/chromium/ui/ozone/public/ozone_platform.cc @@ -125,4 +125,6 @@ void OzonePlatform::AddInterfaces( service_manager::BinderRegistryWithArgs< const service_manager::BindSourceInfo&>* registry) {} +void OzonePlatform::AfterSandboxEntry() {} + } // namespace ui diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h index b6335ea7246..f715a6af03a 100644 --- a/chromium/ui/ozone/public/ozone_platform.h +++ b/chromium/ui/ozone/public/ozone_platform.h @@ -13,6 +13,7 @@ #include "services/service_manager/public/cpp/binder_registry.h" #include "ui/events/system_input_injector.h" #include "ui/ozone/ozone_export.h" +//#include "ui/ozone/public/interfaces/drm_device.mojom.h" namespace display { class NativeDisplayDelegate; @@ -64,14 +65,23 @@ class OZONE_EXPORT OzonePlatform { // retain a reference to this structure. struct InitParams { // Ozone may retain this pointer for later use. An Ozone platform embedder - // must set this parameter in order for the Ozone platform implementation to - // be able to use Mojo. + // may set this value if operating in the idiomatic mojo fashion with a + // service manager. Mojo transport does not require a service manager but in + // that case ozone will not be able to connect to the DRM and cursor + // services. Instead the host must invoke |OnGpuServiceLaunched| as + // described in ui/ozone/public/gpu_platform_support_host.h to inform the + // ozone host that a process containing these services is running. service_manager::Connector* connector = nullptr; // Setting this to true indicates that the platform implementation should // operate as a single process for platforms (i.e. drm) that are usually - // split between a main and gpu specific portion. + // split between a host and viz specific portion. bool single_process = false; + + // Setting this to true indicates that the platform implementation should + // use mojo. Setting this to true requires calling |AddInterfaces| + // afterwards in the Viz process and providing a connector as part + bool using_mojo = false; }; // Ensures the OzonePlatform instance without doing any initialization. @@ -131,11 +141,23 @@ class OZONE_EXPORT OzonePlatform { // service_manager::BinderRegistry* pointer to export all Mojo interfaces // defined within Ozone. // + // Requests arriving before they can be immediately handled will be queued and + // executed later. + // // A default do-nothing implementation is provided to permit platform // implementations to opt out of implementing any Mojo interfaces. virtual void AddInterfaces(service_manager::BinderRegistryWithArgs< const service_manager::BindSourceInfo&>* registry); + // The GPU-specific portion of Ozone would typically run in a sandboxed + // process for additional security. Some startup might need to wait until + // after the sandbox has been configured. The embedder should use this method + // to specify that the sandbox is configured and that GPU-side setup should + // complete. A default do-nothing implementation is provided to permit + // platform implementations to ignore sandboxing and any associated launch + // ordering issues. + virtual void AfterSandboxEntry(); + private: virtual void InitializeUI(const InitParams& params) = 0; virtual void InitializeGPU(const InitParams& params) = 0; diff --git a/chromium/ui/ozone/public/ozone_switches.cc b/chromium/ui/ozone/public/ozone_switches.cc index f7a772a55de..4669cfa471a 100644 --- a/chromium/ui/ozone/public/ozone_switches.cc +++ b/chromium/ui/ozone/public/ozone_switches.cc @@ -15,4 +15,9 @@ const char kOzoneDumpFile[] = "ozone-dump-file"; // Try to enable drm atomic. This works only with drm platform. const char kEnableDrmAtomic[] = "enable-drm-atomic"; +// Use mojo communication in the drm platform instead of paramtraits. Remove +// this switch (and associated code) when the drm platform always uses mojo +// communication. +const char kEnableDrmMojo[] = "enable-drm-mojo"; + } // namespace switches diff --git a/chromium/ui/ozone/public/ozone_switches.h b/chromium/ui/ozone/public/ozone_switches.h index e53912bf47c..b8360e803e4 100644 --- a/chromium/ui/ozone/public/ozone_switches.h +++ b/chromium/ui/ozone/public/ozone_switches.h @@ -16,6 +16,8 @@ OZONE_BASE_EXPORT extern const char kOzoneDumpFile[]; OZONE_BASE_EXPORT extern const char kEnableDrmAtomic[]; +OZONE_BASE_EXPORT extern const char kEnableDrmMojo[]; + } // namespace switches #endif // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_ diff --git a/chromium/ui/platform_window/x11/BUILD.gn b/chromium/ui/platform_window/x11/BUILD.gn index 09e5de517fc..3e46e8c94c9 100644 --- a/chromium/ui/platform_window/x11/BUILD.gn +++ b/chromium/ui/platform_window/x11/BUILD.gn @@ -34,20 +34,7 @@ jumbo_component("x11") { "x11_window_export.h", ] - if (ozone_platform_x11) { - sources += [ - "x11_cursor_ozone.cc", - "x11_cursor_ozone.h", - "x11_window_manager_ozone.cc", - "x11_window_manager_ozone.h", - "x11_window_ozone.cc", - "x11_window_ozone.h", - ] - deps += [ - "//ui/base", - "//ui/base/x", - ] - } else if (use_x11) { + if (use_x11) { sources += [ "x11_window.cc", "x11_window.h", diff --git a/chromium/ui/platform_window/x11/x11_window.cc b/chromium/ui/platform_window/x11/x11_window.cc index b5eaf13af85..d63c67e16d3 100644 --- a/chromium/ui/platform_window/x11/x11_window.cc +++ b/chromium/ui/platform_window/x11/x11_window.cc @@ -127,7 +127,7 @@ uint32_t X11Window::DispatchEvent(const PlatformEvent& event) { } case Expose: - case FocusOut: + case x11::FocusOut: case ConfigureNotify: case ClientMessage: { ProcessXWindowEvent(xev); diff --git a/chromium/ui/platform_window/x11/x11_window_base.cc b/chromium/ui/platform_window/x11/x11_window_base.cc index cb6d8e6e5e8..75cc3eef6ab 100644 --- a/chromium/ui/platform_window/x11/x11_window_base.cc +++ b/chromium/ui/platform_window/x11/x11_window_base.cc @@ -36,15 +36,16 @@ X11WindowBase::X11WindowBase(PlatformWindowDelegate* delegate, const gfx::Rect& bounds) : delegate_(delegate), xdisplay_(gfx::GetXDisplay()), - xwindow_(x11::None), xroot_window_(DefaultRootWindow(xdisplay_)), bounds_(bounds), state_(ui::PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN) { DCHECK(delegate_); Create(); + pointer_barriers_.fill(x11::None); } X11WindowBase::~X11WindowBase() { + UnConfineCursor(); Destroy(); } @@ -257,12 +258,49 @@ void X11WindowBase::MoveCursorTo(const gfx::Point& location) { bounds_.x() + location.x(), bounds_.y() + location.y()); } -void X11WindowBase::ConfineCursorToBounds(const gfx::Rect& bounds) {} +void X11WindowBase::ConfineCursorToBounds(const gfx::Rect& bounds) { + UnConfineCursor(); + + if (bounds.IsEmpty()) + return; + + gfx::Rect barrier = bounds + bounds_.OffsetFromOrigin(); + + // Top horizontal barrier. + pointer_barriers_[0] = XFixesCreatePointerBarrier( + xdisplay_, xroot_window_, barrier.x(), barrier.y(), barrier.right(), + barrier.y(), BarrierPositiveY, 0, XIAllDevices); + // Bottom horizontal barrier. + pointer_barriers_[1] = XFixesCreatePointerBarrier( + xdisplay_, xroot_window_, barrier.x(), barrier.bottom(), barrier.right(), + barrier.bottom(), BarrierNegativeY, 0, XIAllDevices); + // Left vertical barrier. + pointer_barriers_[2] = XFixesCreatePointerBarrier( + xdisplay_, xroot_window_, barrier.x(), barrier.y(), barrier.x(), + barrier.bottom(), BarrierPositiveX, 0, XIAllDevices); + // Right vertical barrier. + pointer_barriers_[3] = XFixesCreatePointerBarrier( + xdisplay_, xroot_window_, barrier.right(), barrier.y(), barrier.right(), + barrier.bottom(), BarrierNegativeX, 0, XIAllDevices); + + has_pointer_barriers_ = true; +} PlatformImeController* X11WindowBase::GetPlatformImeController() { return nullptr; } +void X11WindowBase::UnConfineCursor() { + if (!has_pointer_barriers_) + return; + + for (XID pointer_barrier : pointer_barriers_) + XFixesDestroyPointerBarrier(xdisplay_, pointer_barrier); + pointer_barriers_.fill(x11::None); + + has_pointer_barriers_ = false; +} + bool X11WindowBase::IsEventForXWindow(const XEvent& xev) const { return xwindow_ != x11::None && FindXEventTarget(xev) == xwindow_; } @@ -276,7 +314,7 @@ void X11WindowBase::ProcessXWindowEvent(XEvent* xev) { break; } - case FocusOut: + case x11::FocusOut: if (xev->xfocus.mode != NotifyGrab) delegate_->OnLostCapture(); break; diff --git a/chromium/ui/platform_window/x11/x11_window_base.h b/chromium/ui/platform_window/x11/x11_window_base.h index 70761af9580..b419dc19e8f 100644 --- a/chromium/ui/platform_window/x11/x11_window_base.h +++ b/chromium/ui/platform_window/x11/x11_window_base.h @@ -7,6 +7,8 @@ #include <stdint.h> +#include <array> + #include "base/callback.h" #include "base/containers/flat_set.h" #include "base/macros.h" @@ -55,6 +57,8 @@ class X11_WINDOW_EXPORT X11WindowBase : public PlatformWindow { XDisplay* xdisplay() { return xdisplay_; } XID xwindow() const { return xwindow_; } + void UnConfineCursor(); + // Checks if XEvent is for this XWindow. bool IsEventForXWindow(const XEvent& xev) const; @@ -69,10 +73,10 @@ class X11_WINDOW_EXPORT X11WindowBase : public PlatformWindow { bool IsMaximized() const; bool IsFullscreen() const; - PlatformWindowDelegate* delegate_; + PlatformWindowDelegate* const delegate_; XDisplay* xdisplay_; - XID xwindow_; + XID xwindow_ = x11::None; XID xroot_window_; std::unique_ptr<ui::XScopedEventSelector> xwindow_events_; @@ -87,6 +91,10 @@ class X11_WINDOW_EXPORT X11WindowBase : public PlatformWindow { // Stores current state of this window. ui::PlatformWindowState state_; + // Keep track of barriers to confine cursor. + bool has_pointer_barriers_ = false; + std::array<XID, 4> pointer_barriers_; + bool window_mapped_ = false; DISALLOW_COPY_AND_ASSIGN(X11WindowBase); diff --git a/chromium/ui/resources/default_100_percent/common/easy_unlock_spinner.png b/chromium/ui/resources/default_100_percent/common/easy_unlock_spinner.png Binary files differindex 4371d8293f6..2a6be6a5a1e 100644 --- a/chromium/ui/resources/default_100_percent/common/easy_unlock_spinner.png +++ b/chromium/ui/resources/default_100_percent/common/easy_unlock_spinner.png diff --git a/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png b/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png Binary files differindex 0657fe93842..f5a7faeaa7b 100644 --- a/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png +++ b/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png diff --git a/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png b/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png Binary files differindex 85ef5b21218..d356baf2076 100644 --- a/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png +++ b/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png diff --git a/chromium/ui/resources/default_100_percent/common/pointers/crosshair.png b/chromium/ui/resources/default_100_percent/common/pointers/crosshair.png Binary files differindex a1c55ab14dc..0162e16e830 100644 --- a/chromium/ui/resources/default_100_percent/common/pointers/crosshair.png +++ b/chromium/ui/resources/default_100_percent/common/pointers/crosshair.png diff --git a/chromium/ui/resources/default_100_percent/common/pointers/crosshair_big.png b/chromium/ui/resources/default_100_percent/common/pointers/crosshair_big.png Binary files differindex 99f8746c771..148be7d495c 100644 --- a/chromium/ui/resources/default_100_percent/common/pointers/crosshair_big.png +++ b/chromium/ui/resources/default_100_percent/common/pointers/crosshair_big.png diff --git a/chromium/ui/resources/default_100_percent/common/pointers/xterm.png b/chromium/ui/resources/default_100_percent/common/pointers/xterm.png Binary files differindex a3d5b95739e..2990d102469 100644 --- a/chromium/ui/resources/default_100_percent/common/pointers/xterm.png +++ b/chromium/ui/resources/default_100_percent/common/pointers/xterm.png diff --git a/chromium/ui/resources/default_100_percent/common/pointers/xterm_big.png b/chromium/ui/resources/default_100_percent/common/pointers/xterm_big.png Binary files differindex c8ca97d3075..6d3a20142b1 100644 --- a/chromium/ui/resources/default_100_percent/common/pointers/xterm_big.png +++ b/chromium/ui/resources/default_100_percent/common/pointers/xterm_big.png diff --git a/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png b/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png Binary files differindex 26384774fe1..6f960ce03cd 100644 --- a/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png +++ b/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz.png diff --git a/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz_big.png b/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz_big.png Binary files differindex 33f8addd43a..26e13bd2ff7 100644 --- a/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz_big.png +++ b/chromium/ui/resources/default_100_percent/common/pointers/xterm_horiz_big.png diff --git a/chromium/ui/resources/default_200_percent/common/default_favicon.png b/chromium/ui/resources/default_200_percent/common/default_favicon.png Binary files differindex 033ea1a0315..35eb3916231 100644 --- a/chromium/ui/resources/default_200_percent/common/default_favicon.png +++ b/chromium/ui/resources/default_200_percent/common/default_favicon.png diff --git a/chromium/ui/resources/default_200_percent/common/easy_unlock_spinner.png b/chromium/ui/resources/default_200_percent/common/easy_unlock_spinner.png Binary files differindex 9fdee1025da..8538f6a8136 100644 --- a/chromium/ui/resources/default_200_percent/common/easy_unlock_spinner.png +++ b/chromium/ui/resources/default_200_percent/common/easy_unlock_spinner.png diff --git a/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png b/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png Binary files differindex ba7b149c7b3..659dab6ae7e 100644 --- a/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png +++ b/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png diff --git a/chromium/ui/resources/default_200_percent/common/pointers/crosshair.png b/chromium/ui/resources/default_200_percent/common/pointers/crosshair.png Binary files differindex 8f5dca512a4..34b6a7c95f4 100644 --- a/chromium/ui/resources/default_200_percent/common/pointers/crosshair.png +++ b/chromium/ui/resources/default_200_percent/common/pointers/crosshair.png diff --git a/chromium/ui/resources/default_200_percent/common/pointers/xterm.png b/chromium/ui/resources/default_200_percent/common/pointers/xterm.png Binary files differindex 07871cf378a..83a661caf65 100644 --- a/chromium/ui/resources/default_200_percent/common/pointers/xterm.png +++ b/chromium/ui/resources/default_200_percent/common/pointers/xterm.png diff --git a/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png b/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png Binary files differindex a4d4ba9f0d1..afb370f5648 100644 --- a/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png +++ b/chromium/ui/resources/default_200_percent/common/pointers/xterm_horiz.png diff --git a/chromium/ui/resources/default_300_percent/common/default_favicon_64.png b/chromium/ui/resources/default_300_percent/common/default_favicon_64.png Binary files differindex 0c1e2bba7f9..2b28de54683 100644 --- a/chromium/ui/resources/default_300_percent/common/default_favicon_64.png +++ b/chromium/ui/resources/default_300_percent/common/default_favicon_64.png diff --git a/chromium/ui/resources/ui_resources.grd b/chromium/ui/resources/ui_resources.grd index 708caaf373a..10be1c5aa10 100644 --- a/chromium/ui/resources/ui_resources.grd +++ b/chromium/ui/resources/ui_resources.grd @@ -118,7 +118,7 @@ <structure type="chrome_scaled_image" name="IDR_MENU_HIERARCHY_ARROW" file="mac/menu_hierarchy_arrow.png" /> </if> <structure type="chrome_scaled_image" name="IDR_MENU_DROPARROW" file="cros/menu_droparrow.png" /> - <if expr="toolkit_views or is_macosx or is_ios"> + <if expr="toolkit_views or is_ios"> <if expr="is_win"> <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE" file="win/notification_close.png"/> <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_HOVER" file="win/notification_close_hover.png"/> diff --git a/chromium/ui/shell_dialogs/BUILD.gn b/chromium/ui/shell_dialogs/BUILD.gn index 762859b1750..e5018b276b1 100644 --- a/chromium/ui/shell_dialogs/BUILD.gn +++ b/chromium/ui/shell_dialogs/BUILD.gn @@ -8,6 +8,9 @@ import("//testing/test.gni") if (is_android) { import("//build/config/android/config.gni") } +if (is_mac) { + import("//build/config/mac/rules.gni") +} jumbo_component("shell_dialogs") { sources = [ @@ -76,11 +79,30 @@ jumbo_component("shell_dialogs") { } } +if (is_mac) { + mac_xib_bundle_data("shell_dialogs_unittests_xibs") { + testonly = true + sources = [ + "//chrome/app/nibs/SaveAccessoryView.xib", + ] + } + + mac_framework_bundle("shell_dialogs_unittests_bundle") { + testonly = true + info_plist = "//ui/base/test/framework-Info.plist" + deps = [ + ":shell_dialogs_unittests_xibs", + "//ui/resources:ui_test_pak_bundle_data", + ] + extra_substitutions = [ "CHROMIUM_BUNDLE_ID=$target_name" ] + } +} + test("shell_dialogs_unittests") { + testonly = true sources = [ - # TODO(karandeepb) : Revisit this once gn gets mac bundle support. - # "select_file_dialog_mac_unittest.mm", "run_all_unittests.cc", + "select_file_dialog_mac_unittest.mm", "select_file_dialog_unittest.cc", "select_file_dialog_win_unittest.cc", ] @@ -92,4 +114,8 @@ test("shell_dialogs_unittests") { "//testing/gtest", "//ui/base:base", ] + + if (is_mac) { + deps += [ ":shell_dialogs_unittests_bundle" ] + } } diff --git a/chromium/ui/shell_dialogs/run_all_unittests.cc b/chromium/ui/shell_dialogs/run_all_unittests.cc index 1f5b39d8082..6b5b9bf19fb 100644 --- a/chromium/ui/shell_dialogs/run_all_unittests.cc +++ b/chromium/ui/shell_dialogs/run_all_unittests.cc @@ -44,9 +44,8 @@ void ShellDialogsTestSuite::Initialize() { // Set up framework bundle so that tests on Mac can access nib files. base::FilePath path; PathService::Get(base::DIR_EXE, &path); - // The three DirName() calls strip "Contents/MacOS/<binary>" from the path. - path = path.DirName().DirName().DirName(); - path = path.Append(FILE_PATH_LITERAL("shell_dialogs_unittests.app")); + path = path.Append( + FILE_PATH_LITERAL("shell_dialogs_unittests_bundle.framework")); base::mac::SetOverrideFrameworkBundlePath(path); // Setup resource bundle. diff --git a/chromium/ui/shell_dialogs/select_file_dialog_android.cc b/chromium/ui/shell_dialogs/select_file_dialog_android.cc index 954e19c34d9..5a4fa530ce4 100644 --- a/chromium/ui/shell_dialogs/select_file_dialog_android.cc +++ b/chromium/ui/shell_dialogs/select_file_dialog_android.cc @@ -63,13 +63,16 @@ void SelectFileDialogImpl::OnMultipleFilesSelected( jsize length = env->GetArrayLength(filepaths); DCHECK(length == env->GetArrayLength(display_names)); for (int i = 0; i < length; ++i) { - std::string path = ConvertJavaStringToUTF8( + ScopedJavaLocalRef<jstring> path_ref( env, static_cast<jstring>(env->GetObjectArrayElement(filepaths, i))); - std::string display_name = ConvertJavaStringToUTF8( + base::FilePath file_path = + base::FilePath(ConvertJavaStringToUTF8(env, path_ref)); + + ScopedJavaLocalRef<jstring> display_name_ref( env, static_cast<jstring>(env->GetObjectArrayElement(display_names, i))); - - base::FilePath file_path = base::FilePath(path); + std::string display_name = + ConvertJavaStringToUTF8(env, display_name_ref.obj()); ui::SelectedFileInfo file_info; file_info.file_path = file_path; diff --git a/chromium/ui/shell_dialogs/select_file_dialog_mac.mm b/chromium/ui/shell_dialogs/select_file_dialog_mac.mm index e408e2158c9..cd747823e37 100644 --- a/chromium/ui/shell_dialogs/select_file_dialog_mac.mm +++ b/chromium/ui/shell_dialogs/select_file_dialog_mac.mm @@ -59,6 +59,7 @@ NSString* GetDescriptionFromExtension(const base::FilePath::StringType& ext) { } - (id)initWithSelectFileDialogImpl:(ui::SelectFileDialogImpl*)s; +- (void)selectFileDialogImplWillBeDestroyed; - (void)endedPanel:(NSSavePanel*)panel didCancel:(bool)did_cancel type:(ui::SelectFileDialog::Type)type @@ -209,7 +210,7 @@ void SelectFileDialogImpl::SelectFileImpl( [dialog setCanSelectHiddenExtension:YES]; } } else { - NSOpenPanel* open_dialog = (NSOpenPanel*)dialog; + NSOpenPanel* open_dialog = base::mac::ObjCCastStrict<NSOpenPanel>(dialog); if (type == SELECT_OPEN_MULTI_FILE) [open_dialog setAllowsMultipleSelection:YES]; @@ -235,13 +236,23 @@ void SelectFileDialogImpl::SelectFileImpl( [dialog setDirectoryURL:[NSURL fileURLWithPath:default_dir]]; if (default_filename) [dialog setNameFieldStringValue:default_filename]; + + // Ensure the bridge (rather than |this|) is retained by the block. + SelectFileDialogBridge* bridge = bridge_.get(); [dialog beginSheetModalForWindow:owning_window completionHandler:^(NSInteger result) { - [bridge_.get() endedPanel:dialog - didCancel:result != NSFileHandlingPanelOKButton - type:type - parentWindow:owning_window]; - }]; + [bridge endedPanel:dialog + didCancel:result != NSFileHandlingPanelOKButton + type:type + parentWindow:owning_window]; + + // Balance the setDelegate above. Note this should usually + // have been done already in FileWasSelected(). + [dialog setDelegate:nil]; + + // Balance the retain at the start of SelectFileImpl(). + [dialog release]; + }]; } SelectFileDialogImpl::DialogData::DialogData( @@ -263,6 +274,12 @@ SelectFileDialogImpl::~SelectFileDialogImpl() { for (const auto& panel : panels) [panel cancel:panel]; + + // Running |cancel| on all the panels should have run all the completion + // handlers, but retaining references to C++ objects inside an NSObject can + // result in subtle problems. Ensure the reference to |this| is cleared. + DCHECK(dialog_data_map_.empty()); + [bridge_ selectFileDialogImplWillBeDestroyed]; } // static @@ -384,10 +401,17 @@ SelectFileDialog* CreateSelectFileDialog( return self; } +- (void)selectFileDialogImplWillBeDestroyed { + selectFileDialogImpl_ = nullptr; +} + - (void)endedPanel:(NSSavePanel*)panel didCancel:(bool)did_cancel type:(ui::SelectFileDialog::Type)type parentWindow:(NSWindow*)parentWindow { + if (!selectFileDialogImpl_) + return; + int index = 0; std::vector<base::FilePath> paths; if (!did_cancel) { @@ -422,13 +446,24 @@ SelectFileDialog* CreateSelectFileDialog( isMulti, paths, index); - [panel release]; } - (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url { return [url isFileURL]; } +- (BOOL)panel:(id)sender validateURL:(NSURL*)url error:(NSError**)outError { + // Refuse to accept users closing the dialog with a key repeat, since the key + // may have been first pressed while the user was looking at insecure content. + // See https://crbug.com/637098. + if ([[NSApp currentEvent] type] == NSKeyDown && + [[NSApp currentEvent] isARepeat]) { + return NO; + } + + return YES; +} + @end @implementation ExtensionDropdownHandler diff --git a/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm b/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm index a9ad635e1a1..732d331e1ac 100644 --- a/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm +++ b/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm @@ -13,6 +13,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/shell_dialogs/select_file_policy.h" #define EXPECT_EQ_BOOL(a, b) \ EXPECT_EQ(static_cast<bool>(a), static_cast<bool>(b)) @@ -305,9 +306,12 @@ TEST_F(SelectFileDialogMacTest, EmptyDescription) { GetExtensionDescriptionList(popup); EXPECT_EQ(3lu, extension_descriptions.size()); // Verify that the correct system description is produced for known file types - // like pdf if no extension description is provided by the client. - EXPECT_EQ(base::ASCIIToUTF16("Portable Document Format (PDF)"), - extension_descriptions[0]); + // like pdf if no extension description is provided by the client. Search the + // string for "PDF" as the system may display: + // - Portable Document Format (PDF) + // - PDF document + EXPECT_NE(base::string16::npos, + extension_descriptions[0].find(base::ASCIIToUTF16("PDF"))); EXPECT_EQ(base::ASCIIToUTF16("Image"), extension_descriptions[1]); // Verify the description for unknown file types if no extension description // is provided by the client. @@ -440,6 +444,8 @@ TEST_F(SelectFileDialogMacTest, DefaultPath) { SelectFileWithParams(args); NSSavePanel* panel = GetPanel(); + [panel setExtensionHidden:NO]; + EXPECT_EQ(args.default_path.DirName(), base::mac::NSStringToFilePath([[panel directoryURL] path])); EXPECT_EQ(args.default_path.BaseName(), @@ -466,5 +472,34 @@ TEST_F(SelectFileDialogMacTest, MultipleExtension) { EXPECT_FALSE([panel isExtensionHidden]); } +// Test to ensure lifetime is sound if a reference to the panel outlives the +// delegate. +TEST_F(SelectFileDialogMacTest, Lifetime) { + base::scoped_nsobject<NSSavePanel> panel; + @autoreleasepool { + auto args = GetDefaultArguments(); + // Set a type (Save dialogs do not have a delegate). + args.type = SelectFileDialog::SELECT_OPEN_MULTI_FILE; + SelectFileWithParams(args); + panel.reset([GetPanel() retain]); + + EXPECT_TRUE([panel isVisible]); + EXPECT_NE(nil, [panel delegate]); + + // Newer versions of AppKit may clear out weak delegate pointers when + // dealloc is called on the delegate. Put a ref into the autorelease pool to + // simulate what happens on older versions. + [[[panel delegate] retain] autorelease]; + + ResetDialog(); + + // The SelectFileDialogImpl destructor invokes [panel cancel]. That should + // close the panel, and run the completion handler. + EXPECT_EQ(nil, [panel delegate]); + EXPECT_FALSE([panel isVisible]); + } + EXPECT_EQ(nil, [panel delegate]); +} + } // namespace test } // namespace ui diff --git a/chromium/ui/snapshot/BUILD.gn b/chromium/ui/snapshot/BUILD.gn index d48f92aaded..f2379880561 100644 --- a/chromium/ui/snapshot/BUILD.gn +++ b/chromium/ui/snapshot/BUILD.gn @@ -10,7 +10,6 @@ jumbo_component("snapshot") { sources = [ "screenshot_grabber.cc", "screenshot_grabber.h", - "screenshot_grabber_observer.h", "snapshot.cc", "snapshot.h", "snapshot_android.cc", diff --git a/chromium/ui/snapshot/screenshot_grabber.cc b/chromium/ui/snapshot/screenshot_grabber.cc index bd563946dac..6f0e6c1ce7d 100644 --- a/chromium/ui/snapshot/screenshot_grabber.cc +++ b/chromium/ui/snapshot/screenshot_grabber.cc @@ -9,8 +9,8 @@ #include <climits> #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/callback.h" -#include "base/files/file_util.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/ptr_util.h" @@ -18,10 +18,8 @@ #include "base/single_thread_task_runner.h" #include "base/task_runner.h" #include "base/task_scheduler/post_task.h" -#include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" -#include "ui/gfx/image/image.h" #include "ui/snapshot/snapshot.h" #if defined(USE_AURA) @@ -36,80 +34,8 @@ namespace { // more than 1000 to prevent the conflict of filenames. const int kScreenshotMinimumIntervalInMS = 1000; -using ShowNotificationCallback = - base::Callback<void(ScreenshotGrabberObserver::Result screenshot_result, - const base::FilePath& screenshot_path)>; - -void SaveScreenshot(scoped_refptr<base::TaskRunner> ui_task_runner, - const ShowNotificationCallback& callback, - const base::FilePath& screenshot_path, - scoped_refptr<base::RefCountedMemory> png_data, - ScreenshotGrabberDelegate::FileResult result, - const base::FilePath& local_path) { - DCHECK(!base::MessageLoopForUI::IsCurrent()); - DCHECK(!screenshot_path.empty()); - - // Convert FileResult into ScreenshotGrabberObserver::Result. - ScreenshotGrabberObserver::Result screenshot_result = - ScreenshotGrabberObserver::SCREENSHOT_SUCCESS; - switch (result) { - case ScreenshotGrabberDelegate::FILE_SUCCESS: - // Successfully got a local file to write to, write png data. - DCHECK_GT(static_cast<int>(png_data->size()), 0); - if (static_cast<size_t>(base::WriteFile( - local_path, reinterpret_cast<const char*>(png_data->front()), - static_cast<int>(png_data->size()))) != png_data->size()) { - LOG(ERROR) << "Failed to save to " << local_path.value(); - screenshot_result = - ScreenshotGrabberObserver::SCREENSHOT_WRITE_FILE_FAILED; - } - break; - case ScreenshotGrabberDelegate::FILE_CHECK_DIR_FAILED: - screenshot_result = - ScreenshotGrabberObserver::SCREENSHOT_CHECK_DIR_FAILED; - break; - case ScreenshotGrabberDelegate::FILE_CREATE_DIR_FAILED: - screenshot_result = - ScreenshotGrabberObserver::SCREENSHOT_CREATE_DIR_FAILED; - break; - case ScreenshotGrabberDelegate::FILE_CREATE_FAILED: - screenshot_result = - ScreenshotGrabberObserver::SCREENSHOT_CREATE_FILE_FAILED; - break; - } - - // Report the result on the UI thread. - ui_task_runner->PostTask( - FROM_HERE, base::Bind(callback, screenshot_result, screenshot_path)); -} - -void EnsureLocalDirectoryExists( - const base::FilePath& path, - ScreenshotGrabberDelegate::FileCallback callback) { - DCHECK(!base::MessageLoopForUI::IsCurrent()); - DCHECK(!path.empty()); - - if (!base::CreateDirectory(path.DirName())) { - LOG(ERROR) << "Failed to ensure the existence of " - << path.DirName().value(); - callback.Run(ScreenshotGrabberDelegate::FILE_CREATE_DIR_FAILED, path); - return; - } - - callback.Run(ScreenshotGrabberDelegate::FILE_SUCCESS, path); -} - } // namespace -void ScreenshotGrabberDelegate::PrepareFileAndRunOnBlockingPool( - const base::FilePath& path, - const FileCallback& callback_on_blocking_pool) { - base::PostTaskWithTraits( - FROM_HERE, - {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - base::Bind(EnsureLocalDirectoryExists, path, callback_on_blocking_pool)); -} - #if defined(USE_AURA) class ScreenshotGrabber::ScopedCursorHider { public: @@ -139,15 +65,14 @@ class ScreenshotGrabber::ScopedCursorHider { }; #endif -ScreenshotGrabber::ScreenshotGrabber(ScreenshotGrabberDelegate* client) - : client_(client), factory_(this) {} +ScreenshotGrabber::ScreenshotGrabber() : factory_(this) {} ScreenshotGrabber::~ScreenshotGrabber() { } void ScreenshotGrabber::TakeScreenshot(gfx::NativeWindow window, const gfx::Rect& rect, - const base::FilePath& screenshot_path) { + ScreenshotCallback callback) { DCHECK(base::MessageLoopForUI::IsCurrent()); last_screenshot_timestamp_ = base::TimeTicks::Now(); @@ -166,8 +91,8 @@ void ScreenshotGrabber::TakeScreenshot(gfx::NativeWindow window, ui::GrabWindowSnapshotAsyncPNG( window, rect, base::Bind(&ScreenshotGrabber::GrabWindowSnapshotAsyncCallback, - factory_.GetWeakPtr(), window_identifier, screenshot_path, - is_partial)); + factory_.GetWeakPtr(), window_identifier, is_partial, + base::Passed(&callback))); } bool ScreenshotGrabber::CanTakeScreenshot() { @@ -176,58 +101,32 @@ bool ScreenshotGrabber::CanTakeScreenshot() { base::TimeDelta::FromMilliseconds(kScreenshotMinimumIntervalInMS); } -void ScreenshotGrabber::NotifyScreenshotCompleted( - ScreenshotGrabberObserver::Result screenshot_result, - const base::FilePath& screenshot_path) { - DCHECK(base::MessageLoopForUI::IsCurrent()); -#if defined(USE_AURA) - cursor_hider_.reset(); -#endif - for (ScreenshotGrabberObserver& observer : observers_) - observer.OnScreenshotCompleted(screenshot_result, screenshot_path); -} - -void ScreenshotGrabber::AddObserver(ScreenshotGrabberObserver* observer) { - observers_.AddObserver(observer); -} - -void ScreenshotGrabber::RemoveObserver(ScreenshotGrabberObserver* observer) { - observers_.RemoveObserver(observer); -} - -bool ScreenshotGrabber::HasObserver( - const ScreenshotGrabberObserver* observer) const { - return observers_.HasObserver(observer); -} - void ScreenshotGrabber::GrabWindowSnapshotAsyncCallback( const std::string& window_identifier, - base::FilePath screenshot_path, bool is_partial, + ScreenshotCallback callback, scoped_refptr<base::RefCountedMemory> png_data) { DCHECK(base::MessageLoopForUI::IsCurrent()); + +#if defined(USE_AURA) + cursor_hider_.reset(); +#endif + if (!png_data.get()) { if (is_partial) { LOG(ERROR) << "Failed to grab the window screenshot"; - NotifyScreenshotCompleted( - ScreenshotGrabberObserver::SCREENSHOT_GRABWINDOW_PARTIAL_FAILED, - screenshot_path); + std::move(callback).Run(ScreenshotResult::GRABWINDOW_PARTIAL_FAILED, + nullptr); } else { LOG(ERROR) << "Failed to grab the window screenshot for " << window_identifier; - NotifyScreenshotCompleted( - ScreenshotGrabberObserver::SCREENSHOT_GRABWINDOW_FULL_FAILED, - screenshot_path); + std::move(callback).Run(ScreenshotResult::GRABWINDOW_FULL_FAILED, + nullptr); } return; } - ShowNotificationCallback notification_callback(base::Bind( - &ScreenshotGrabber::NotifyScreenshotCompleted, factory_.GetWeakPtr())); - client_->PrepareFileAndRunOnBlockingPool( - screenshot_path, - base::Bind(&SaveScreenshot, base::ThreadTaskRunnerHandle::Get(), - notification_callback, screenshot_path, png_data)); + std::move(callback).Run(ScreenshotResult::SUCCESS, std::move(png_data)); } } // namespace ui diff --git a/chromium/ui/snapshot/screenshot_grabber.h b/chromium/ui/snapshot/screenshot_grabber.h index 8cf7723d47d..d942d1018de 100644 --- a/chromium/ui/snapshot/screenshot_grabber.h +++ b/chromium/ui/snapshot/screenshot_grabber.h @@ -14,61 +14,44 @@ #include "base/macros.h" #include "base/memory/ref_counted_memory.h" #include "base/memory/weak_ptr.h" -#include "base/observer_list.h" #include "base/time/time.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" -#include "ui/snapshot/screenshot_grabber_observer.h" #include "ui/snapshot/snapshot_export.h" namespace ui { -// TODO(flackr): Componentize google drive so that we don't need the -// ScreenshotGrabberDelegate. -class SNAPSHOT_EXPORT ScreenshotGrabberDelegate { - public: - enum FileResult { - FILE_SUCCESS, - FILE_CHECK_DIR_FAILED, - FILE_CREATE_DIR_FAILED, - FILE_CREATE_FAILED - }; - - // Callback called with the |result| of trying to create a local writable - // |path| for the possibly remote path. - using FileCallback = - base::Callback<void(FileResult result, const base::FilePath& path)>; - - ScreenshotGrabberDelegate() {} - virtual ~ScreenshotGrabberDelegate() {} - - // Prepares a writable file for |path|. If |path| is a non-local path (i.e. - // Google drive) and it is supported this will create a local cached copy of - // the remote file and call the callback with the local path. - virtual void PrepareFileAndRunOnBlockingPool( - const base::FilePath& path, - const FileCallback& callback_on_blocking_pool); +// Result of the entire screenshotting attempt. This enum is fat for various +// file operations which could happen in the chrome layer. +enum class ScreenshotResult { + SUCCESS, + GRABWINDOW_PARTIAL_FAILED, + GRABWINDOW_FULL_FAILED, + CREATE_DIR_FAILED, + GET_DIR_FAILED, + CHECK_DIR_FAILED, + CREATE_FILE_FAILED, + WRITE_FILE_FAILED, + DISABLED }; class SNAPSHOT_EXPORT ScreenshotGrabber { public: - explicit ScreenshotGrabber(ScreenshotGrabberDelegate* client); + ScreenshotGrabber(); ~ScreenshotGrabber(); + // Callback for the new system, which ignores the observer crud. + using ScreenshotCallback = + base::OnceCallback<void(ui::ScreenshotResult screenshot_result, + scoped_refptr<base::RefCountedMemory> png_data)>; + // Takes a screenshot of |rect| in |window| in that window's coordinate space - // saving the result to |screenshot_path|. + // and return it to |callback|. void TakeScreenshot(gfx::NativeWindow window, const gfx::Rect& rect, - const base::FilePath& screenshot_path); - bool CanTakeScreenshot(); + ScreenshotCallback callback); - void NotifyScreenshotCompleted( - ScreenshotGrabberObserver::Result screenshot_result, - const base::FilePath& screenshot_path); - - void AddObserver(ScreenshotGrabberObserver* observer); - void RemoveObserver(ScreenshotGrabberObserver* observer); - bool HasObserver(const ScreenshotGrabberObserver* observer) const; + bool CanTakeScreenshot(); private: #if defined(USE_AURA) @@ -77,13 +60,10 @@ class SNAPSHOT_EXPORT ScreenshotGrabber { void GrabWindowSnapshotAsyncCallback( const std::string& window_identifier, - base::FilePath screenshot_path, bool is_partial, + ScreenshotCallback callback, scoped_refptr<base::RefCountedMemory> png_data); - // A weak pointer to the screenshot taker client. - ScreenshotGrabberDelegate* client_; - // The timestamp when the screenshot task was issued last time. base::TimeTicks last_screenshot_timestamp_; @@ -92,7 +72,6 @@ class SNAPSHOT_EXPORT ScreenshotGrabber { std::unique_ptr<ScopedCursorHider> cursor_hider_; #endif - base::ObserverList<ScreenshotGrabberObserver> observers_; base::WeakPtrFactory<ScreenshotGrabber> factory_; DISALLOW_COPY_AND_ASSIGN(ScreenshotGrabber); diff --git a/chromium/ui/snapshot/screenshot_grabber_observer.h b/chromium/ui/snapshot/screenshot_grabber_observer.h deleted file mode 100644 index 4d90306bb79..00000000000 --- a/chromium/ui/snapshot/screenshot_grabber_observer.h +++ /dev/null @@ -1,39 +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 UI_SNAPSHOT_SCREENSHOT_GRABBER_OBSERVER_H_ -#define UI_SNAPSHOT_SCREENSHOT_GRABBER_OBSERVER_H_ - -#include "base/files/file_path.h" -#include "ui/snapshot/snapshot_export.h" - -namespace ui { - -class SNAPSHOT_EXPORT ScreenshotGrabberObserver { - public: - enum Result { - SCREENSHOT_SUCCESS = 0, - SCREENSHOT_GRABWINDOW_PARTIAL_FAILED, - SCREENSHOT_GRABWINDOW_FULL_FAILED, - SCREENSHOT_CREATE_DIR_FAILED, - SCREENSHOT_GET_DIR_FAILED, - SCREENSHOT_CHECK_DIR_FAILED, - SCREENSHOT_CREATE_FILE_FAILED, - SCREENSHOT_WRITE_FILE_FAILED, - SCREENSHOTS_DISABLED, - SCREENSHOT_RESULT_COUNT - }; - - // Dispatched after attempting to take a screenshot with the |result| and - // |screenshot_path| of the taken screenshot (if successful). - virtual void OnScreenshotCompleted(Result screenshot_result, - const base::FilePath& screenshot_path) = 0; - - protected: - virtual ~ScreenshotGrabberObserver() {} -}; - -} // namespace ui - -#endif // UI_SNAPSHOT_SCREENSHOT_GRABBER_OBSERVER_H_ diff --git a/chromium/ui/snapshot/snapshot.cc b/chromium/ui/snapshot/snapshot.cc index 756f65dabf8..0c26ef287fb 100644 --- a/chromium/ui/snapshot/snapshot.cc +++ b/chromium/ui/snapshot/snapshot.cc @@ -21,6 +21,8 @@ namespace { scoped_refptr<base::RefCountedMemory> EncodeImageAsPNG( const gfx::Image& image) { + if (image.IsEmpty()) + return nullptr; std::vector<uint8_t> result; DCHECK(!image.AsImageSkia().GetRepresentation(1.0f).is_null()); gfx::PNGCodec::FastEncodeBGRASkBitmap(image.AsBitmap(), true, &result); diff --git a/chromium/ui/snapshot/snapshot_android.cc b/chromium/ui/snapshot/snapshot_android.cc index 8151090a11d..dbf0a8903ac 100644 --- a/chromium/ui/snapshot/snapshot_android.cc +++ b/chromium/ui/snapshot/snapshot_android.cc @@ -38,6 +38,11 @@ static void MakeAsyncCopyRequest( gfx::NativeWindow window, const gfx::Rect& source_rect, viz::CopyOutputRequest::CopyOutputRequestCallback callback) { + if (!window->GetCompositor()) { + std::move(callback).Run(std::make_unique<viz::CopyOutputResult>( + viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, gfx::Rect())); + return; + } std::unique_ptr<viz::CopyOutputRequest> request = std::make_unique<viz::CopyOutputRequest>( viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, diff --git a/chromium/ui/strings/translations/ui_strings_am.xtb b/chromium/ui/strings/translations/ui_strings_am.xtb index 8bfaec53c6d..1927ae2550e 100644 --- a/chromium/ui/strings/translations/ui_strings_am.xtb +++ b/chromium/ui/strings/translations/ui_strings_am.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">ስቀል</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">የሚመከሩ መተግበሪያዎች</translation> +<translation id="1368832886055348810">ከግራ ወደ ቀኝ</translation> <translation id="1398853756734560583">አስፋ</translation> <translation id="1413622004203049571">ከ<ph name="NOTIFIER_NAME" /> የሚመጡ ማሳወቂያዎችን አሰናክል</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 ደቂቃ እና }one{# ደቂቃዎች እና }other{# ደቂቃዎች እና }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">የኮከብ ደረጃ <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 ሰዓት እና }one{# ሰዓቶች እና }other{# ሰዓቶች እና }}</translation> <translation id="1842960171412779397">ምረጥ</translation> +<translation id="1859234291848436338">የአፃፃፍ አቅጣጫ</translation> <translation id="1860796786778352021">ማሳወቂያ ዝጋ</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">ወደላይ አንቀሳቅስ</translation> <translation id="2190355936436201913">(ባዶ)</translation> <translation id="219905428774326614">ማስጀመሪያ፣ ሁሉም መተግበሪያዎች</translation> +<translation id="2267918077332197517">ከዚህ ጣቢያ የሚመጡ ሁሉንም ማሳወቂያዎች አግድ</translation> <translation id="2289052229480071835">በማያ ገጽዎ ላይ ያሉት የንክኪ ዒላማዎችን መታ ያድርጉ።</translation> <translation id="2295140143284145483">የዳሰሳ ጥናት</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> ቴባ/ሰ</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">ወደ እዚህ ሸብልል</translation> <translation id="3234408098842461169">ዝቅዝቅ ቀስት</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 ቀን}one{# ቀኖች}other{# ቀኖች}}</translation> +<translation id="335581015389089642">ንግግር</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 ቀን ቀርቷል}one{# ቀኖች ቀርቷል}other{# ቀኖች ቀርተዋል}}</translation> +<translation id="3618849550573277856">«<ph name="LOOKUP_STRING" />»ን ፈልግ</translation> <translation id="364720409959344976">የሚሰቀል ዓቃፊ ይምረጡ</translation> <translation id="3660179305079774227">የላይ ቀስት</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> ጊባ/ሰ</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">ዝለል</translation> <translation id="4250229828105606438">ቅጽበታዊ ገጽ እይታ</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{ከ1 ወር በፊት}one{ከ# ወሮች በፊት}other{ከ# ወሮች በፊት}}</translation> +<translation id="4289300219472526559">መናገር ይጀምሩ</translation> <translation id="4316910396681052118">ሁሉም መተግበሪያዎች</translation> -<translation id="4320177379694898372">ምንም የበይነመረብ ግንኙነት የለም</translation> <translation id="4588090240171750605">ወደ ቀኝ ሸብልል</translation> <translation id="4724120544754982507">የማሳወቂያ ማዕከል፣ <ph name="UNREAD_NOTIFICATION_COUNT" /> ያልተነበቡ ማሳወቂያዎች</translation> <translation id="4730374152663651037">በብዛት ጥቅም ላይ የዋለ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">የመተግበሪያ አስተያየት ጥቆማዎች</translation> <translation id="6364916375976753737">ወደ ግራ ሸብልል</translation> <translation id="6394627529324717982">ኮማ</translation> +<translation id="6397363302884558537">መናገር አቁም</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 ሰከንድ በፊት}one{# ሰከንዶች በፊት}other{# ሰከንዶች በፊት}}</translation> +<translation id="6430678249303439055">ከዚህ መተግበሪያ የሚመጡ ሁሉንም ማሳወቂያዎች አግድ</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{ከ1 ሰከንድ በፊት}one{ከ# ሰከንዶች በፊት}other{ከ# ሰከንዶች በፊት}}</translation> <translation id="654149438358937226">ሁሉንም ማሳወቂያዎች አግድ</translation> <translation id="6567071839949112727">ዘር ማንዘርን ጠቅ አድርግ</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 ዓመት ቀርቷል}one{# ዓመቶች ቀርተዋል}other{# ዓመቶች ቀርተዋል}}</translation> <translation id="6945221475159498467">ይምረጡ</translation> <translation id="6965382102122355670">እሺ</translation> +<translation id="6974053822202609517">ከቀኝ ወደ ግራ</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">የመሆን ዕድላቸው ከፍ ያለ ነው</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">የግራ ጠርዝ</translation> <translation id="8331626408530291785">ወደ ላይ ሸብልል</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 አመት}one{# ዓመቶች}other{# ዓመቶች}}</translation> -<translation id="8371695176452482769">አሁን ይናገሩ</translation> <translation id="838869780401515933">አመልክት</translation> <translation id="8393700583063109961">መልዕክት ይላኩ</translation> <translation id="8394908167088220973">ሚዲያ አጫውት/ለአፍታ አቁም</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> ተጨማሪ</translation> <translation id="8730621377337864115">ተከናውኗል</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1ሰ}one{#ሰ}other{#ሰ}}</translation> +<translation id="8798099450830957504">እንደወረደ</translation> <translation id="8806053966018712535">አቃፊ <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">ምስልን አብራራ</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> ኪባ</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ar.xtb b/chromium/ui/strings/translations/ui_strings_ar.xtb index 234c1badbeb..228d5cd924a 100644 --- a/chromium/ui/strings/translations/ui_strings_ar.xtb +++ b/chromium/ui/strings/translations/ui_strings_ar.xtb @@ -8,8 +8,9 @@ <translation id="1243314992276662751">تحميل</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">تطبيقات مقترحة</translation> +<translation id="1368832886055348810">من اليسار لليمين</translation> <translation id="1398853756734560583">تكبير</translation> -<translation id="1413622004203049571">تعطيل الإشعارات من <ph name="NOTIFIER_NAME" /></translation> +<translation id="1413622004203049571">إيقاف الإشعارات من <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{دقيقة واحدة و }zero{# من الدقائق و }two{دقيقتان (#) و }few{# دقائق و }many{# دقيقة و }other{# من الدقائق و }}</translation> <translation id="1643823602425662293">الإشعار</translation> <translation id="1710340000377843106">الآن</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">تقييم بالنجوم <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{ساعة واحدة و }zero{# من الساعات و }two{ساعتان (#) و }few{# ساعات و }many{# ساعة و }other{# من الساعات و }}</translation> <translation id="1842960171412779397">الاختيار</translation> +<translation id="1859234291848436338">اتجاه الكتابة</translation> <translation id="1860796786778352021">إغلاق الإشعار</translation> <translation id="1871244248791675517">مفتاح Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">صفحة إلى أعلى</translation> <translation id="2190355936436201913">(فارغ)</translation> <translation id="219905428774326614">Launcher، جميع التطبيقات</translation> +<translation id="2267918077332197517">حظر جميع الإشعارات الواردة من هذا الموقع</translation> <translation id="2289052229480071835">انقر على أهداف اللمس على شاشتك.</translation> <translation id="2295140143284145483">الاستطلاع</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> تيرابايت/ثانية</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">التمرير إلى هنا</translation> <translation id="3234408098842461169">مفتاح سهم إلى أسفل</translation> <translation id="3291688615589870984">{DAYS,plural, =1{يوم واحد}zero{# من الأيام}two{يومان (#)}few{# أيام}many{# يومًا}other{# من الأيام}}</translation> +<translation id="335581015389089642">الحديث</translation> <translation id="3600566671520689681">{DAYS,plural, =1{يتبقى يوم واحد}zero{يتبقى عدد # من الأيام}two{يتبقى يومان (#)}few{يتبقى # أيام}many{يتبقى # يومًا}other{يتبقى # من الأيام}}</translation> +<translation id="3618849550573277856">البحث عن "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">حدد مجلدًا للتحميل</translation> <translation id="3660179305079774227">مفتاح سهم إلى أعلى</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> غيغابايت/ثانية</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">الدخول</translation> <translation id="4250229828105606438">لقطة شاشة</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{قبل شهر واحد}zero{قبل # شهر}two{قبل شهرين (#)}few{قبل # أشهر}many{قبل # شهرًا}other{قبل # شهر}}</translation> +<translation id="4289300219472526559">بدء التحدث</translation> <translation id="4316910396681052118">جميع التطبيقات</translation> -<translation id="4320177379694898372">لا يتوفر اتصال بالإنترنت</translation> <translation id="4588090240171750605">التمرير إلى اليسار</translation> <translation id="4724120544754982507">مركز الإشعارات، <ph name="UNREAD_NOTIFICATION_COUNT" /> من الإشعارات غير المقروءة</translation> <translation id="4730374152663651037">التطبيقات المستخدمة بشكل متكرر</translation> @@ -93,7 +98,7 @@ <translation id="6012623610530968780">صفحة <ph name="SELECTED_PAGE" /> من <ph name="TOTAL_PAGE_NUM" /></translation> <translation id="6022924867608035986">محو نص مربع البحث</translation> <translation id="6040143037577758943">إغلاق</translation> -<translation id="6119846243427417423">تنشيط</translation> +<translation id="6119846243427417423">تفعيل</translation> <translation id="6129953537138746214">مسافة</translation> <translation id="6135826906199951471">مفتاح Del (حذف)</translation> <translation id="6142413573757616983"><ph name="QUANTITY" /> بايت/ثانية</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">اقتراحات التطبيقات</translation> <translation id="6364916375976753737">التمرير إلى اليمين</translation> <translation id="6394627529324717982">فاصلة</translation> +<translation id="6397363302884558537">إيقاف التحدث</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{قبل ثانية واحدة}zero{ قبل # من الثواني}two{ قبل ثانيتين (#)}few{قبل # ثوانٍ}many{قبل # ثانية}other{قبل # من الثواني}}</translation> +<translation id="6430678249303439055">حظر جميع الإشعارات الواردة من هذا التطبيق</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{قبل ثانية واحدة}zero{قبل # ثانية}two{قبل ثانيتين (#)}few{قبل # ثوانٍ}many{قبل # ثانية}other{قبل # ثانية}}</translation> <translation id="654149438358937226">حظر جميع الإشعارات</translation> <translation id="6567071839949112727">النقر على العنصر الأصل</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{تتبقى سنة واحدة}zero{تتبقى # سنة}two{تتبقى سنتين (#)}few{تتبقى # سنوات}many{تتبقى # سنةً}other{تتبقى # سنة}}</translation> <translation id="6945221475159498467">تحديد</translation> <translation id="6965382102122355670">موافق</translation> +<translation id="6974053822202609517">من اليمين لليسار</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">التطبيقات التي يرجح النقر عليها</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">الحافة اليمنى</translation> <translation id="8331626408530291785">التمرير إلى أعلى</translation> <translation id="8352146631962686268">{YEARS,plural, =1{سنة واحدة}zero{# سنة}two{سنتان (#)}few{# سنوات}many{# سنةً}other{# سنة}}</translation> -<translation id="8371695176452482769">تحدث الآن</translation> <translation id="838869780401515933">الاختيار</translation> <translation id="8393700583063109961">إرسال رسالة</translation> <translation id="8394908167088220973">تشغيل/إيقاف الوسائط</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204"><ph name="NUMBER" />+ أخرى</translation> <translation id="8730621377337864115">تم</translation> <translation id="8772073294905169192">{HOURS,plural, =1{ساعة واحدة}zero{# ساعة}two{ساعتان (#)}few{# ساعات}many{# ساعةً}other{# ساعة}}</translation> +<translation id="8798099450830957504">التلقائي</translation> <translation id="8806053966018712535">مجلد <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">إضافة تعليق توضيحي على الصورة</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> كيلوبايت</translation> diff --git a/chromium/ui/strings/translations/ui_strings_bg.xtb b/chromium/ui/strings/translations/ui_strings_bg.xtb index 3c8d551c6ca..bab7796969d 100644 --- a/chromium/ui/strings/translations/ui_strings_bg.xtb +++ b/chromium/ui/strings/translations/ui_strings_bg.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Качване</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ПРЕПОРЪЧАНИ ПРИЛОЖЕНИЯ</translation> +<translation id="1368832886055348810">Отляво надясно</translation> <translation id="1398853756734560583">Увеличаване</translation> <translation id="1413622004203049571">Деактивиране на известията от <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 минута и }other{# минути и }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Оценка със звезди: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 час и }other{# часа и }}</translation> <translation id="1842960171412779397">Избиране</translation> +<translation id="1859234291848436338">Посока на писане</translation> <translation id="1860796786778352021">Затваряне на известието</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Страница нагоре</translation> <translation id="2190355936436201913">(празно)</translation> <translation id="219905428774326614">Стартов панел, всички приложения</translation> +<translation id="2267918077332197517">Блокиране на всички известия от този сайт</translation> <translation id="2289052229480071835">Докоснете съответните цели на екрана.</translation> <translation id="2295140143284145483">Анкета</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> ТБ/сек</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Превъртане до тук</translation> <translation id="3234408098842461169">Стрелка надолу</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 ден}other{# дни}}</translation> +<translation id="335581015389089642">Speech</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Остава 1 ден}other{Остават # дни}}</translation> +<translation id="3618849550573277856">Търсене на „<ph name="LOOKUP_STRING" />“</translation> <translation id="364720409959344976">Избиране на папка за качване</translation> <translation id="3660179305079774227">Стрелка нагоре</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/сек</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">преминаване</translation> <translation id="4250229828105606438">Eкранна снимка</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Преди 1 месец}other{Преди # месеца}}</translation> +<translation id="4289300219472526559">Start Speaking</translation> <translation id="4316910396681052118">ВСИЧКИ ПРИЛОЖЕНИЯ</translation> -<translation id="4320177379694898372">Няма връзка с интернет</translation> <translation id="4588090240171750605">Превъртане надясно</translation> <translation id="4724120544754982507">Център за известия, <ph name="UNREAD_NOTIFICATION_COUNT" /> непрочетени</translation> <translation id="4730374152663651037">ЧЕСТО ИЗПОЛЗВАНИ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ПРЕДЛОЖЕНИЯ ЗА ПРИЛОЖЕНИЯ</translation> <translation id="6364916375976753737">Превъртане наляво</translation> <translation id="6394627529324717982">Запетая</translation> +<translation id="6397363302884558537">Stop Speaking</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Преди 1 сек}other{Преди # сек}}</translation> +<translation id="6430678249303439055">Блокиране на всички известия от това приложение</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Преди 1 секунда}other{Преди # секунди}}</translation> <translation id="654149438358937226">Блокиране на всички известия</translation> <translation id="6567071839949112727">кликване върху елемента предшественик</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Остава 1 година}other{Остават # години}}</translation> <translation id="6945221475159498467">Изберете</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Отдясно наляво</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">НАЙ-ВЕРОЯТЕН ИЗБОР</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Ляв край</translation> <translation id="8331626408530291785">Превъртане нагоре</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 година}other{# години}}</translation> -<translation id="8371695176452482769">Говорете сега</translation> <translation id="838869780401515933">отмятане</translation> <translation id="8393700583063109961">Изпратете съобщение</translation> <translation id="8394908167088220973">Мултимедия, пускане/пауза</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+ още <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Готово</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 ч}other{# ч}}</translation> +<translation id="8798099450830957504">По подразбиране</translation> <translation id="8806053966018712535">Папка „<ph name="FOLDER_NAME" />“</translation> <translation id="883911313571074303">Добавяне на пояснение към изображението</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KБ</translation> diff --git a/chromium/ui/strings/translations/ui_strings_bn.xtb b/chromium/ui/strings/translations/ui_strings_bn.xtb index 2b0e65c5b70..b9f1648d1fe 100644 --- a/chromium/ui/strings/translations/ui_strings_bn.xtb +++ b/chromium/ui/strings/translations/ui_strings_bn.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">আপলোড</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">প্রস্তাবিত অ্যাপ</translation> +<translation id="1368832886055348810">বাঁ থেকে ডান</translation> <translation id="1398853756734560583">বড় করুন</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> এর থেকে বিজ্ঞপ্তিগুলি অক্ষম করুন</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{১ মিনিট এবং }one{# মিনিট এবং }other{# মিনিট এবং }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144"><ph name="RATING_SCORE" /> তারা রেটিং দিন</translation> <translation id="1830179671306812954">{HOURS,plural, =1{১ ঘণ্টা এবং }one{# ঘণ্টা এবং }other{# ঘণ্টা এবং }}</translation> <translation id="1842960171412779397">বেছে নিন</translation> +<translation id="1859234291848436338">লিখন নির্দেশনা</translation> <translation id="1860796786778352021">বিজ্ঞপ্তি বন্ধ করা হয়েছে</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">পৃষ্ঠা নিচে</translation> <translation id="2190355936436201913">(খালি)</translation> <translation id="219905428774326614">লঞ্চার, সমস্ত অ্যাপ</translation> +<translation id="2267918077332197517">এই সাইটের সমস্ত বিজ্ঞপ্তি ব্লক করুন</translation> <translation id="2289052229480071835">আপনার স্ক্রীনে স্পর্শ লক্ষ্যগুলি আলতা চাপুন।</translation> <translation id="2295140143284145483">সমীক্ষা</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">এখান পর্যন্ত স্ক্রোল করুন</translation> <translation id="3234408098842461169">Down Arrow</translation> <translation id="3291688615589870984">{DAYS,plural, =1{১ দিন}one{# দিন}other{# দিন}}</translation> +<translation id="335581015389089642">স্পিচ</translation> <translation id="3600566671520689681">{DAYS,plural, =1{১ দিন বাকি}one{# দিন বাকি}other{# দিন বাকি}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” খুঁজে দেখুন</translation> <translation id="364720409959344976">আপলোড করার জন্য ফোল্ডার বেছে নিন</translation> <translation id="3660179305079774227">Up Arrow</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">লাফ দিন</translation> <translation id="4250229828105606438">স্ক্রীনশট</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{১ মাস আগে}one{# মাস আগে}other{# মাস আগে}}</translation> +<translation id="4289300219472526559">কথা বলা শুরু করুন</translation> <translation id="4316910396681052118">সব অ্যাপ</translation> -<translation id="4320177379694898372">কোনো ইন্টারনেট সংযোগ নেই</translation> <translation id="4588090240171750605">ডান দিকে স্ক্রোল করুন</translation> <translation id="4724120544754982507">বিজ্ঞপ্তি কেন্দ্র, <ph name="UNREAD_NOTIFICATION_COUNT" />টি না পড়া বিজ্ঞপ্তি</translation> <translation id="4730374152663651037">ঘন ঘন ব্যবহার করা হয়</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">অ্যাপের প্রস্তাবনা</translation> <translation id="6364916375976753737">বাঁ দিকে স্ক্রোল করুন</translation> <translation id="6394627529324717982">কমা</translation> +<translation id="6397363302884558537">কথা বলা বন্ধ করুন</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{১ সেকেন্ড পূর্বে}one{# সেকেন্ড পূর্বে}other{# সেকেন্ড পূর্বে}}</translation> +<translation id="6430678249303439055">এই অ্যাপ থেকে সমস্ত বিজ্ঞপ্তি ব্লক করুন</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{১ সেকেন্ড আগে}one{# সেকেন্ড আগে}other{# সেকেন্ড আগে}}</translation> <translation id="654149438358937226">সমস্ত বিজ্ঞপ্তি ব্লক করুন</translation> <translation id="6567071839949112727">এটি সম্পর্কিত একটি পুরানো আইটেমে ক্লিক করুন</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{১ বছর বাকি}one{# বছর বাকি}other{# বছর বাকি}}</translation> <translation id="6945221475159498467">নির্বাচন</translation> <translation id="6965382102122355670">ঠিক আছে</translation> +<translation id="6974053822202609517">ডান থেকে বামে</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">সবথেকে বেশি সম্ভাবনা</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">বাঁ প্রান্ত</translation> <translation id="8331626408530291785">উপরে স্ক্রোল করুন</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 বছর}one{# বছর}other{# বছর}}</translation> -<translation id="8371695176452482769">এখনই বলুন</translation> <translation id="838869780401515933">চেক করুন</translation> <translation id="8393700583063109961">বার্তা পাঠান</translation> <translation id="8394908167088220973">মিডিয়া প্লে করুন/বিরতি</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">আরও <ph name="NUMBER" />টি</translation> <translation id="8730621377337864115">হয়ে গেছে</translation> <translation id="8772073294905169192">{HOURS,plural, =1{১ ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}</translation> +<translation id="8798099450830957504">ডিফল্ট</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> ফোল্ডার</translation> <translation id="883911313571074303">চিত্রের জন্য টিকা লিখুন</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ca.xtb b/chromium/ui/strings/translations/ui_strings_ca.xtb index 41256e7f56a..b9815bdaf59 100644 --- a/chromium/ui/strings/translations/ui_strings_ca.xtb +++ b/chromium/ui/strings/translations/ui_strings_ca.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Penja</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APLICACIONS RECOMANADES</translation> +<translation id="1368832886055348810">D'esquerra a dreta</translation> <translation id="1398853756734560583">Maximitza</translation> <translation id="1413622004203049571">Desactiva les notificacions de <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minut i }other{# minuts i }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Puntuació en estrelles: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 hora i }other{# hores i }}</translation> <translation id="1842960171412779397">selecciona</translation> +<translation id="1859234291848436338">Direcció de l'escriptura</translation> <translation id="1860796786778352021">Tanca la notificació</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Re Pàg</translation> <translation id="2190355936436201913">(buit)</translation> <translation id="219905428774326614">Menú d'aplicacions, totes les aplicacions</translation> +<translation id="2267918077332197517">Bloqueja totes les notificacions d'aquest lloc web</translation> <translation id="2289052229480071835">Toca els elements tàctils a la pantalla.</translation> <translation id="2295140143284145483">Enquesta</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Desplaçament fins aquí</translation> <translation id="3234408098842461169">Fletxa avall</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dia}other{# dies}}</translation> +<translation id="335581015389089642">Veu</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 dia restant}other{# dies restants}}</translation> +<translation id="3618849550573277856">Cerca "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Selecció d'una carpeta per penjar</translation> <translation id="3660179305079774227">Fletxa amunt</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">salta</translation> <translation id="4250229828105606438">Captura de pantalla</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Fa 1 mes}other{Fa # mesos}}</translation> +<translation id="4289300219472526559">Comença a parlar</translation> <translation id="4316910396681052118">TOTES LES APLICACIONS</translation> -<translation id="4320177379694898372">No hi ha connexió a Internet</translation> <translation id="4588090240171750605">Desplaçament a la dreta</translation> <translation id="4724120544754982507">Centre de notificacions, <ph name="UNREAD_NOTIFICATION_COUNT" /> notificacions no llegides</translation> <translation id="4730374152663651037">UTILITZADES FREQÜENTMENT</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGGERIMENTS D'APLICACIONS</translation> <translation id="6364916375976753737">Desplaçament a l'esquerra</translation> <translation id="6394627529324717982">Coma</translation> +<translation id="6397363302884558537">Deixa de parlar</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{fa 1 s}other{fa # s}}</translation> +<translation id="6430678249303439055">Bloqueja totes les notificacions d'aquesta aplicació</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Fa 1 segon}other{Fa # segons}}</translation> <translation id="654149438358937226">Bloqueja totes les notificacions</translation> <translation id="6567071839949112727">fes clic a l'antecedent</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{D'aquí a 1 any}other{D'aquí a # anys}}</translation> <translation id="6945221475159498467">Selecciona</translation> <translation id="6965382102122355670">D'acord</translation> +<translation id="6974053822202609517">De dreta a esquerra</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">LES MÉS PROBABLES</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Extrem esquerre</translation> <translation id="8331626408530291785">Desplaçament amunt</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 any}other{# anys}}</translation> -<translation id="8371695176452482769">Parla ara</translation> <translation id="838869780401515933">marca</translation> <translation id="8393700583063109961">Envia el missatge</translation> <translation id="8394908167088220973">Fitxer multimèdia: reprodueix/posa en pausa</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">i <ph name="NUMBER" /> més</translation> <translation id="8730621377337864115">Fet</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}other{# h}}</translation> +<translation id="8798099450830957504">Predeterminat</translation> <translation id="8806053966018712535">Carpeta <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Afegeix una anotació a la imatge</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_cs.xtb b/chromium/ui/strings/translations/ui_strings_cs.xtb index ad90798604c..b17832346ba 100644 --- a/chromium/ui/strings/translations/ui_strings_cs.xtb +++ b/chromium/ui/strings/translations/ui_strings_cs.xtb @@ -8,11 +8,12 @@ <translation id="1243314992276662751">Nahrát</translation> <translation id="1293699935367580298">Klávesa Esc</translation> <translation id="1306549533752902673">DOPORUČENÉ APLIKACE</translation> +<translation id="1368832886055348810">Zleva doprava</translation> <translation id="1398853756734560583">Maximalizovat</translation> <translation id="1413622004203049571">Deaktivovat oznámení ze služby <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuta a }few{# minuty a }many{# minuty a }other{# minut a }}</translation> <translation id="1643823602425662293">Oznámení</translation> -<translation id="1710340000377843106">nyní</translation> +<translation id="1710340000377843106">teď</translation> <translation id="1752946267035950200">{MINUTES,plural, =1{1 minuta}few{# minuty}many{# minuty}other{# minut}}</translation> <translation id="1761785978543082658"><ph name="QUANTITY" /> B</translation> <translation id="1801827354178857021">Tečka</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Hodnocení hvězdičkami: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 hodina a }few{# hodiny a }many{# hodiny a }other{# hodin a }}</translation> <translation id="1842960171412779397">zvolit</translation> +<translation id="1859234291848436338">Směr textu</translation> <translation id="1860796786778352021">Zavřít oznámení</translation> <translation id="1871244248791675517">Klávesa Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Klávesa PageUp</translation> <translation id="2190355936436201913">(prázdné)</translation> <translation id="219905428774326614">Spouštěč, všechny aplikace</translation> +<translation id="2267918077332197517">Blokovat všechna oznámení z tohoto webu</translation> <translation id="2289052229480071835">Klepněte na cíle klepnutí na obrazovce.</translation> <translation id="2295140143284145483">Průzkum</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Posunout sem</translation> <translation id="3234408098842461169">Klávesa šipka dolů</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 den}few{# dny}many{# dne}other{# dnů}}</translation> +<translation id="335581015389089642">Řeč</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Zbývá 1 den}few{Zbývají # dny}many{Zbývá # dne}other{Zbývá # dnů}}</translation> +<translation id="3618849550573277856">Vyhledat „<ph name="LOOKUP_STRING" />“</translation> <translation id="364720409959344976">Vyberte složku pro nahrávání</translation> <translation id="3660179305079774227">Klávesa šipka nahoru</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">přejít</translation> <translation id="4250229828105606438">Snímek obrazovky</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{před 1 měsícem}few{před # měsíci}many{před # měsíce}other{před # měsíci}}</translation> +<translation id="4289300219472526559">Začít mluvit</translation> <translation id="4316910396681052118">VŠECHNY APLIKACE</translation> -<translation id="4320177379694898372">Žádné připojení k internetu</translation> <translation id="4588090240171750605">Posuv doprava</translation> <translation id="4724120544754982507">Centrum oznámení – nepřečtená oznámení: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">ČASTO POUŽÍVANÉ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">NÁVRHY APLIKACÍ</translation> <translation id="6364916375976753737">Posuv doleva</translation> <translation id="6394627529324717982">Čárka</translation> +<translation id="6397363302884558537">Přestat mluvit</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Před 1 s}few{Před # s}many{Před # s}other{Před # s}}</translation> +<translation id="6430678249303439055">Blokovat všechna oznámení z této aplikace</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{před sekundou}few{před # sekundami}many{před # sekundy}other{před # sekundami}}</translation> <translation id="654149438358937226">Blokovat všechna oznámení</translation> <translation id="6567071839949112727">kliknutí na nadřazený prvek</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{zbývá 1 rok}few{zbývají # roky}many{zbývá # roku}other{zbývá # let}}</translation> <translation id="6945221475159498467">Vybrat</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Zprava doleva</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">NEJPRAVDĚPODOBNĚJŠÍ</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Levý okraj</translation> <translation id="8331626408530291785">Posuv nahoru</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 rok}few{# roky}many{# roku}other{# let}}</translation> -<translation id="8371695176452482769">Mluvte</translation> <translation id="838869780401515933">zaškrtnout</translation> <translation id="8393700583063109961">Odeslat zprávu</translation> <translation id="8394908167088220973">Média – přehrát/pozastavit</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">a ještě <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Hotovo</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}few{# h}many{# h}other{# h}}</translation> +<translation id="8798099450830957504">Výchozí</translation> <translation id="8806053966018712535">Složka <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Přidat k obrázku poznámku</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_da.xtb b/chromium/ui/strings/translations/ui_strings_da.xtb index 8185a98736d..7f9110a9eb2 100644 --- a/chromium/ui/strings/translations/ui_strings_da.xtb +++ b/chromium/ui/strings/translations/ui_strings_da.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Upload</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ANBEFALEDE APPS</translation> +<translation id="1368832886055348810">Venstre til højre</translation> <translation id="1398853756734560583">Maksimér</translation> <translation id="1413622004203049571">Deaktiver underretninger fra <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minut og }one{# minutter og }other{# minutter og }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Antal stjerner <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 time og }one{# timer og }other{# timer og }}</translation> <translation id="1842960171412779397">vælg</translation> +<translation id="1859234291848436338">Skriveretning</translation> <translation id="1860796786778352021">Luk underretning</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Side op</translation> <translation id="2190355936436201913">(tom)</translation> <translation id="219905428774326614">Starter. Alle apps</translation> +<translation id="2267918077332197517">Bloker alle underretninger fra dette website</translation> <translation id="2289052229480071835">Tryk på de punkter på skærmen, der kan trykkes på.</translation> <translation id="2295140143284145483">Undersøgelse</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/sek.</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Scroll hertil</translation> <translation id="3234408098842461169">Pil nedad</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dag}one{# dage}other{# dage}}</translation> +<translation id="335581015389089642">Tale</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 dag tilbage}one{# dage tilbage}other{# dage tilbage}}</translation> +<translation id="3618849550573277856">Slå "<ph name="LOOKUP_STRING" />" op</translation> <translation id="364720409959344976">Vælg den mappe, der skal uploades</translation> <translation id="3660179305079774227">Pil opad</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/sek.</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">hop</translation> <translation id="4250229828105606438">Screenshot</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{For 1 måned siden}one{For # måned siden}other{For # måneder siden}}</translation> +<translation id="4289300219472526559">Start indtaling</translation> <translation id="4316910396681052118">ALLE APPS</translation> -<translation id="4320177379694898372">Ingen internetforbindelse</translation> <translation id="4588090240171750605">Scroll til højre</translation> <translation id="4724120544754982507">Underretningscenter, <ph name="UNREAD_NOTIFICATION_COUNT" /> ulæste underretninger</translation> <translation id="4730374152663651037">OFTE ANVENDT</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">APPFORSLAG</translation> <translation id="6364916375976753737">Scroll Left</translation> <translation id="6394627529324717982">Komma</translation> +<translation id="6397363302884558537">Stop indtaling</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{for 1 sek. siden}one{for # sek. siden}other{for # sek. siden}}</translation> +<translation id="6430678249303439055">Bloker alle underretninger fra denne app</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{For 1 sekund siden}one{For # sekund siden}other{For # sekunder siden}}</translation> <translation id="654149438358937226">Bloker alle underretninger</translation> <translation id="6567071839949112727">klik på overordnet element</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Der er 1 år tilbage}one{Der er # år tilbage}other{Der er # år tilbage}}</translation> <translation id="6945221475159498467">Vælg</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Højre til venstre</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">HØJST SANDSYNLIGT</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Venstre kant</translation> <translation id="8331626408530291785">Scroll Up</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 år}one{# år}other{# år}}</translation> -<translation id="8371695176452482769">Indtal nu</translation> <translation id="838869780401515933">markér</translation> <translation id="8393700583063109961">Send en besked</translation> <translation id="8394908167088220973">Medie: Afspil/Pause</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> mere</translation> <translation id="8730621377337864115">Udfør</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 t}one{# t}other{# t}}</translation> +<translation id="8798099450830957504">Standard</translation> <translation id="8806053966018712535">Mappen <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Annoter billede</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_de.xtb b/chromium/ui/strings/translations/ui_strings_de.xtb index bda412d2aae..f01349c2950 100644 --- a/chromium/ui/strings/translations/ui_strings_de.xtb +++ b/chromium/ui/strings/translations/ui_strings_de.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Hochladen</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">EMPFOHLENE APPS</translation> +<translation id="1368832886055348810">Rechtsläufig</translation> <translation id="1398853756734560583">Vergrößern</translation> <translation id="1413622004203049571">Benachrichtigungen von <ph name="NOTIFIER_NAME" /> deaktivieren</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 Minute und }other{# Minuten und }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Bewertung <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 Stunde und }other{# Stunden und }}</translation> <translation id="1842960171412779397">auswählen</translation> +<translation id="1859234291848436338">Schreibrichtung</translation> <translation id="1860796786778352021">Benachrichtigung schließen</translation> <translation id="1871244248791675517">Einfg</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Nach oben</translation> <translation id="2190355936436201913">(leer)</translation> <translation id="219905428774326614">Launcher, alle Apps</translation> +<translation id="2267918077332197517">Alle Benachrichtigungen von dieser Website blockieren</translation> <translation id="2289052229480071835">Tippen Sie auf die Zielelemente auf dem Bildschirm.</translation> <translation id="2295140143284145483">Umfrage</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Hierher blättern</translation> <translation id="3234408098842461169">Abwärtspfeil</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 Tag}other{# Tage}}</translation> +<translation id="335581015389089642">Sprachausgabe</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 Tag übrig}other{# Tage übrig}}</translation> +<translation id="3618849550573277856">"<ph name="LOOKUP_STRING" />" nachschlagen</translation> <translation id="364720409959344976">Ordner zum Hochladen auswählen</translation> <translation id="3660179305079774227">Aufwärtspfeil</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">springen</translation> <translation id="4250229828105606438">Screenshot</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{vor 1 Monat}other{vor # Monaten}}</translation> +<translation id="4289300219472526559">Sprachausgabe starten</translation> <translation id="4316910396681052118">ALLE APPS</translation> -<translation id="4320177379694898372">Keine Internetverbindung</translation> <translation id="4588090240171750605">Nach rechts blättern</translation> <translation id="4724120544754982507">Benachrichtigungscenter, <ph name="UNREAD_NOTIFICATION_COUNT" /> ungelesene Benachrichtigungen</translation> <translation id="4730374152663651037">HÄUFIG VERWENDET</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">APP-VORSCHLÄGE</translation> <translation id="6364916375976753737">Nach links blättern</translation> <translation id="6394627529324717982">Komma</translation> +<translation id="6397363302884558537">Sprachausgabe stoppen</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 Sek. her}other{# Sek. her}}</translation> +<translation id="6430678249303439055">Alle Benachrichtigungen von dieser App blockieren</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Vor 1 Sekunde}other{Vor # Sekunden}}</translation> <translation id="654149438358937226">Alle Benachrichtigungen blockieren</translation> <translation id="6567071839949112727">Auf Vorgängerelement klicken</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{noch 1 Jahr}other{noch # Jahre}}</translation> <translation id="6945221475159498467">Auswählen</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Linksläufig</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">HOHE WAHRSCHEINLICHKEIT</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Linker Rand</translation> <translation id="8331626408530291785">Nach oben blättern</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 Jahr}other{# Jahre}}</translation> -<translation id="8371695176452482769">Jetzt sprechen</translation> <translation id="838869780401515933">auswählen</translation> <translation id="8393700583063109961">Nachricht senden</translation> <translation id="8394908167088220973">Medien – Wiedergabe/Pause</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> weitere</translation> <translation id="8730621377337864115">Fertig</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}other{# h}}</translation> +<translation id="8798099450830957504">Standardeinstellung</translation> <translation id="8806053966018712535">Ordner <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Bild mit Anmerkung versehen</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_el.xtb b/chromium/ui/strings/translations/ui_strings_el.xtb index a004e281818..1d1f001f571 100644 --- a/chromium/ui/strings/translations/ui_strings_el.xtb +++ b/chromium/ui/strings/translations/ui_strings_el.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Μεταφόρτωση</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ΠΡΟΤΕΙΝΟΜΕΝΕΣ ΕΦΑΡΜΟΓΕΣ</translation> +<translation id="1368832886055348810">Από αριστερά προς τα δεξιά</translation> <translation id="1398853756734560583">Μεγιστοποίηση</translation> <translation id="1413622004203049571">Απενεργοποίηση ειδοποιήσεων από <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 λεπτό και }other{# λεπτά και }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Αξιολόγηση με αστέρια <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 ώρα και }other{# ώρες και }}</translation> <translation id="1842960171412779397">επιλογή</translation> +<translation id="1859234291848436338">Κατεύθυνση γραφής</translation> <translation id="1860796786778352021">Κλείσιμο ειδοποίησης</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Προηγούμενη σελίδα</translation> <translation id="2190355936436201913">(κενό)</translation> <translation id="219905428774326614">Εφαρμογή εκκίνησης, όλες οι εφαρμογές</translation> +<translation id="2267918077332197517">Αποκλεισμός όλων των ειδοποιήσεων από αυτόν τον ιστότοπο</translation> <translation id="2289052229480071835">Πατήστε τους στόχους αφής στην οθόνη σας.</translation> <translation id="2295140143284145483">Έρευνα</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Κύλιση εδώ</translation> <translation id="3234408098842461169">Κάτω βέλος</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 ημέρα}other{# ημέρες}}</translation> +<translation id="335581015389089642">Ομιλία</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Απομένει 1 ημέρα}other{Απομένουν # ημέρες}}</translation> +<translation id="3618849550573277856">Αναζήτηση "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Επιλέξτε φάκελο για μεταφόρτωση</translation> <translation id="3660179305079774227">Πάνω βέλος</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">μεταπήδηση</translation> <translation id="4250229828105606438">Στιγμιότυπο οθόνης</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Πριν από 1 μήνα}other{Πριν από # μήνες}}</translation> +<translation id="4289300219472526559">Έναρξη ομιλίας</translation> <translation id="4316910396681052118">ΟΛΕΣ ΟΙ ΕΦΑΡΜΟΓΕΣ</translation> -<translation id="4320177379694898372">Χωρίς σύνδεση στο διαδίκτυο</translation> <translation id="4588090240171750605">Κύλιση δεξιά</translation> <translation id="4724120544754982507">Κέντρο ειδοποιήσεων, <ph name="UNREAD_NOTIFICATION_COUNT" /> μη αναγνωσμένες ειδοποιήσεις</translation> <translation id="4730374152663651037">ΣΥΧΝΗ ΧΡΗΣΗ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ΠΡΟΤΑΣΕΙΣ ΕΦΑΡΜΟΓΩΝ</translation> <translation id="6364916375976753737">Κύλιση αριστερά</translation> <translation id="6394627529324717982">Κόμμα</translation> +<translation id="6397363302884558537">Διακοπή ομιλίας</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Πριν από 1 δευτερόλεπτο}other{Πριν από # δευτερόλεπτα}}</translation> +<translation id="6430678249303439055">Αποκλεισμός όλων των ειδοποιήσεων από αυτή την εφαρμογή</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Πριν από 1 δευτερόλεπτο}other{Πριν από # δευτερόλεπτα}}</translation> <translation id="654149438358937226">Αποκλεισμός όλων των ειδοποιήσεων</translation> <translation id="6567071839949112727">γονικό κλικ</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Απομένει 1 χρόνος}other{Απομένουν # χρόνια}}</translation> <translation id="6945221475159498467">Επιλογή</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Από δεξιά προς τα αριστερά</translation> <translation id="7052633198403197513">Πλήκτρο F1</translation> <translation id="7130207228079676353">ΔΗΜΟΦΙΛΕΣΤΕΡΕΣ</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Αριστερή άκρη</translation> <translation id="8331626408530291785">Κύλιση επάνω</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 χρόνος}other{# χρόνια}}</translation> -<translation id="8371695176452482769">Μιλήστε τώρα</translation> <translation id="838869780401515933">ενεργοποίηση</translation> <translation id="8393700583063109961">Αποστολή μηνύματος</translation> <translation id="8394908167088220973">Αναπαραγωγή/παύση πολυμέσων</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> ακόμη</translation> <translation id="8730621377337864115">Ολοκληρώθηκε</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1ώρ.}other{#ώρ.}}</translation> +<translation id="8798099450830957504">Προεπιλογή</translation> <translation id="8806053966018712535">Φάκελος <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Σχολιασμός εικόνας</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_en-GB.xtb b/chromium/ui/strings/translations/ui_strings_en-GB.xtb index ac82ea40d75..fd7b83c3ada 100644 --- a/chromium/ui/strings/translations/ui_strings_en-GB.xtb +++ b/chromium/ui/strings/translations/ui_strings_en-GB.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Upload</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">RECOMMENDED APPS</translation> +<translation id="1368832886055348810">Left to Right</translation> <translation id="1398853756734560583">Maximise</translation> <translation id="1413622004203049571">Disable notifications from <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minute and }other{# minutes and }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Star rating <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 hour and }other{# hours and }}</translation> <translation id="1842960171412779397">select</translation> +<translation id="1859234291848436338">Writing Direction</translation> <translation id="1860796786778352021">Notification close</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Page Up</translation> <translation id="2190355936436201913">(empty)</translation> <translation id="219905428774326614">Launcher, all apps</translation> +<translation id="2267918077332197517">Block all notifications from this site</translation> <translation id="2289052229480071835">Tap the touch targets on your screen.</translation> <translation id="2295140143284145483">Survey</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Scroll to Here</translation> <translation id="3234408098842461169">Down Arrow</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 day}other{# days}}</translation> +<translation id="335581015389089642">Speech</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 day left}other{# days left}}</translation> +<translation id="3618849550573277856">Look Up “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Select Folder to Upload</translation> <translation id="3660179305079774227">Up Arrow</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">jump</translation> <translation id="4250229828105606438">Screenshot</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 month ago}other{# months ago}}</translation> +<translation id="4289300219472526559">Start Speaking</translation> <translation id="4316910396681052118">ALL APPS</translation> -<translation id="4320177379694898372">No internet connection</translation> <translation id="4588090240171750605">Scroll Right</translation> <translation id="4724120544754982507">Notification Centre, <ph name="UNREAD_NOTIFICATION_COUNT" /> unread notifications</translation> <translation id="4730374152663651037">FREQUENTLY USED</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">APP SUGGESTIONS</translation> <translation id="6364916375976753737">Scroll Left</translation> <translation id="6394627529324717982">Comma</translation> +<translation id="6397363302884558537">Stop Speaking</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 sec ago}other{# secs ago}}</translation> +<translation id="6430678249303439055">Block all notifications from this app</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 second ago}other{# seconds ago}}</translation> <translation id="654149438358937226">Block all notifications</translation> <translation id="6567071839949112727">click ancestor</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 year left}other{# years left}}</translation> <translation id="6945221475159498467">Select</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Right to Left</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MOST LIKELY</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Left Edge</translation> <translation id="8331626408530291785">Scroll Up</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 year}other{# years}}</translation> -<translation id="8371695176452482769">Speak now</translation> <translation id="838869780401515933">tick</translation> <translation id="8393700583063109961">Send message</translation> <translation id="8394908167088220973">Media Play/Pause</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> more</translation> <translation id="8730621377337864115">Done</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1h}other{#h}}</translation> +<translation id="8798099450830957504">Default</translation> <translation id="8806053966018712535">Folder <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Annotate image</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_es-419.xtb b/chromium/ui/strings/translations/ui_strings_es-419.xtb index 01a9478b5b4..2d51edc7332 100644 --- a/chromium/ui/strings/translations/ui_strings_es-419.xtb +++ b/chromium/ui/strings/translations/ui_strings_es-419.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Cargar</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APPS RECOMENDADAS</translation> +<translation id="1368832886055348810">De izquierda a derecha</translation> <translation id="1398853756734560583">Maximizar</translation> <translation id="1413622004203049571">Inhabilitar notificaciones de <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuto y }other{# minutos y }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Calificación por estrellas <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 hora y }other{# horas y }}</translation> <translation id="1842960171412779397">seleccionar</translation> +<translation id="1859234291848436338">Sentido de la escritura</translation> <translation id="1860796786778352021">Cerrar notificación</translation> <translation id="1871244248791675517">Insert</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Retroceder página</translation> <translation id="2190355936436201913">(vacío)</translation> <translation id="219905428774326614">Launcher, todas las apps</translation> +<translation id="2267918077332197517">No permitir las notificaciones de este sitio</translation> <translation id="2289052229480071835">Presiona los objetivos táctiles en tu pantalla.</translation> <translation id="2295140143284145483">Encuesta</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Desplazarse hasta aquí</translation> <translation id="3234408098842461169">Flecha abajo</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 día}other{# días}}</translation> +<translation id="335581015389089642">Voz</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 día.}other{Faltan # días.}}</translation> +<translation id="3618849550573277856">Buscar "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Seleccionar carpeta para cargar</translation> <translation id="3660179305079774227">Flecha arriba</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">saltar</translation> <translation id="4250229828105606438">Captura de pantalla</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Hace 1 mes}other{Hace # meses}}</translation> +<translation id="4289300219472526559">Empezar a hablar</translation> <translation id="4316910396681052118">TODAS LAS APPS</translation> -<translation id="4320177379694898372">Sin conexión a Internet</translation> <translation id="4588090240171750605">Desplazar a la derecha</translation> <translation id="4724120544754982507">Centro de notificaciones, notificaciones sin leer: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">USADAS CON FRECUENCIA</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGERENCIAS DE APPS</translation> <translation id="6364916375976753737">Desplazar hacia la izquierda</translation> <translation id="6394627529324717982">Coma</translation> +<translation id="6397363302884558537">Dejar de hablar</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Hace 1 s.}other{Hace # s.}}</translation> +<translation id="6430678249303439055">No permitir las notificaciones de esta app</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Hace 1 segundo}other{Hace # segundos}}</translation> <translation id="654149438358937226">Bloquear todas las notificaciones</translation> <translation id="6567071839949112727">hacer clic en principal</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Queda 1 año}other{Quedan # años}}</translation> <translation id="6945221475159498467">Seleccionar</translation> <translation id="6965382102122355670">Aceptar</translation> +<translation id="6974053822202609517">De derecha a izquierda</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MUY PROBABLES</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Borde izquierdo</translation> <translation id="8331626408530291785">Desplazar hacia arriba</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 año}other{# años}}</translation> -<translation id="8371695176452482769">Hablar ahora</translation> <translation id="838869780401515933">marcar</translation> <translation id="8393700583063109961">Enviar mensaje</translation> <translation id="8394908167088220973">Reproducir o pausar contenido multimedia</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204"><ph name="NUMBER" /> más</translation> <translation id="8730621377337864115">Listo</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}other{# h}}</translation> +<translation id="8798099450830957504">Predeterminado</translation> <translation id="8806053966018712535">Carpeta <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Escribir en la imagen</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_es.xtb b/chromium/ui/strings/translations/ui_strings_es.xtb index c8e5daf576c..8d22d321cd7 100644 --- a/chromium/ui/strings/translations/ui_strings_es.xtb +++ b/chromium/ui/strings/translations/ui_strings_es.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Subir</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APLICACIONES RECOMENDADAS</translation> +<translation id="1368832886055348810">De izquierda a derecha</translation> <translation id="1398853756734560583">Maximizar</translation> <translation id="1413622004203049571">Inhabilitar notificaciones de <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuto y }other{# minutos y }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Valoración por estrellas <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 hora y }other{# horas y }}</translation> <translation id="1842960171412779397">seleccionar</translation> +<translation id="1859234291848436338">Sentido de la escritura</translation> <translation id="1860796786778352021">Cerrar notificación</translation> <translation id="1871244248791675517">Insert</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Retroceder página</translation> <translation id="2190355936436201913">(vacío)</translation> <translation id="219905428774326614">Menú de aplicaciones, todas las aplicaciones</translation> +<translation id="2267918077332197517">Bloquear todas las notificaciones de este sitio web</translation> <translation id="2289052229480071835">Toca los elementos táctiles en la pantalla.</translation> <translation id="2295140143284145483">Encuesta</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Desplazarse hasta aquí</translation> <translation id="3234408098842461169">Flecha abajo</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 día}other{# días}}</translation> +<translation id="335581015389089642">Voz</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Queda 1 día}other{Quedan # días}}</translation> +<translation id="3618849550573277856">Buscar <ph name="LOOKUP_STRING" /></translation> <translation id="364720409959344976">Seleccionar una carpeta para subirla</translation> <translation id="3660179305079774227">Flecha arriba</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">saltar</translation> <translation id="4250229828105606438">Captura de pantalla</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Hace 1 mes}other{Hace # meses}}</translation> +<translation id="4289300219472526559">Empezar a hablar</translation> <translation id="4316910396681052118">TODAS LAS APLICACIONES</translation> -<translation id="4320177379694898372">No hay conexión a Internet</translation> <translation id="4588090240171750605">Desplazar a la derecha</translation> <translation id="4724120544754982507">Centro de notificaciones: <ph name="UNREAD_NOTIFICATION_COUNT" /> notificaciones sin leer</translation> <translation id="4730374152663651037">UTILIZADAS CON FRECUENCIA</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGERENCIAS DE APLICACIONES</translation> <translation id="6364916375976753737">Desplazar hacia la izquierda</translation> <translation id="6394627529324717982">Coma</translation> +<translation id="6397363302884558537">Dejar de hablar</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Hace 1 s}other{Hace # s}}</translation> +<translation id="6430678249303439055">Bloquear todas las notificaciones de esta aplicación</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Hace 1 segundo}other{Hace # segundos}}</translation> <translation id="654149438358937226">Bloquear todas las notificaciones</translation> <translation id="6567071839949112727">hacer clic en la superclase</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Queda 1 año}other{Quedan # años}}</translation> <translation id="6945221475159498467">Seleccionar</translation> <translation id="6965382102122355670">Aceptar</translation> +<translation id="6974053822202609517">De derecha a izquierda</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MÁS PROBABLES</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Borde izquierdo</translation> <translation id="8331626408530291785">Desplazar hacia arriba</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 año}other{# años}}</translation> -<translation id="8371695176452482769">Habla ahora</translation> <translation id="838869780401515933">marcar</translation> <translation id="8393700583063109961">Enviar mensaje</translation> <translation id="8394908167088220973">Pausar/Reproducir contenido multimedia</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204"><ph name="NUMBER" /> más</translation> <translation id="8730621377337864115">Listo</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}other{# h}}</translation> +<translation id="8798099450830957504">Predeterminado</translation> <translation id="8806053966018712535">Carpeta <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Anotar imagen</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_et.xtb b/chromium/ui/strings/translations/ui_strings_et.xtb index f690752e3b1..f2da3fb29a3 100644 --- a/chromium/ui/strings/translations/ui_strings_et.xtb +++ b/chromium/ui/strings/translations/ui_strings_et.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Laadi üles</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">SOOVITATUD RAKENDUSED</translation> +<translation id="1368832886055348810">Left to Right (Vasakult paremale)</translation> <translation id="1398853756734560583">Maksimeeri</translation> <translation id="1413622004203049571">Keela märguanded: <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minut ja }other{# minutit ja }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Tärnhinnang <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 tund ja }other{# tundi ja }}</translation> <translation id="1842960171412779397">vali</translation> +<translation id="1859234291848436338">Writing Direction (Kirjutamise suund)</translation> <translation id="1860796786778352021">Märguande sulgemine</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Lehekülje üles</translation> <translation id="2190355936436201913">(tühi)</translation> <translation id="219905428774326614">Käivitaja, kõik rakendused</translation> +<translation id="2267918077332197517">Blokeeri kõik märguanded sellelt saidilt</translation> <translation id="2289052229480071835">Puudutage ekraanil puutesihtmärke.</translation> <translation id="2295140143284145483">Küsitlus</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Keri siia</translation> <translation id="3234408098842461169">Allanool</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 päev}other{# päeva}}</translation> +<translation id="335581015389089642">Kõne</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 päev on jäänud}other{# päeva on jäänud}}</translation> +<translation id="3618849550573277856">Otsi terminit „<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Kausta valimine üleslaadimiseks</translation> <translation id="3660179305079774227">Ülesnool</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">liigu</translation> <translation id="4250229828105606438">Ekraanipilt</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 kuu tagasi}other{# kuud tagasi}}</translation> +<translation id="4289300219472526559">Alusta rääkimist</translation> <translation id="4316910396681052118">KÕIK RAKENDUSED</translation> -<translation id="4320177379694898372">Interneti-ühendus puudub</translation> <translation id="4588090240171750605">Keri paremale</translation> <translation id="4724120544754982507">Märguandekeskus, <ph name="UNREAD_NOTIFICATION_COUNT" /> lugemata märguannet</translation> <translation id="4730374152663651037">SAGELI KASUTATUD</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">RAKENDUSTE SOOVITUSED</translation> <translation id="6364916375976753737">Keri vasakule</translation> <translation id="6394627529324717982">Koma</translation> +<translation id="6397363302884558537">Lõpeta rääkimine</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 s tagasi}other{# s tagasi}}</translation> +<translation id="6430678249303439055">Blokeeri kõik märguanded sellelt rakenduselt</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 sekund tagasi}other{# sekundit tagasi}}</translation> <translation id="654149438358937226">Blokeeri kõik märguanded</translation> <translation id="6567071839949112727">kliki eellane</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 aasta jäänud}other{# aastat jäänud}}</translation> <translation id="6945221475159498467">Vali</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Right to Left (Paremalt vasakule)</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">KÕIGE TÕENÄOLISEMAD</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Vasak serv</translation> <translation id="8331626408530291785">Keri üles</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 aasta}other{# aastat}}</translation> -<translation id="8371695176452482769">Alustage rääkimist</translation> <translation id="838869780401515933">mrgista</translation> <translation id="8393700583063109961">Saatke sõnum</translation> <translation id="8394908167088220973">Meediumi esitamine/peatamine</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">ja veel <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Valmis</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1h}other{#h}}</translation> +<translation id="8798099450830957504">Vaikimisi</translation> <translation id="8806053966018712535">Kaust <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Lisa kujutisele märkused</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_fa.xtb b/chromium/ui/strings/translations/ui_strings_fa.xtb index 094e2111ba0..ba3ceda90d6 100644 --- a/chromium/ui/strings/translations/ui_strings_fa.xtb +++ b/chromium/ui/strings/translations/ui_strings_fa.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">بارگذاری</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">برنامههای توصیهشده</translation> +<translation id="1368832886055348810">چپ به راست</translation> <translation id="1398853756734560583">بزرگ کردن</translation> <translation id="1413622004203049571">غیرفعال کردن اعلانها از <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{۱ دقیقه و }one{# دقیقه و }other{# دقیقه و }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">رتبهبندی ستارهای <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{۱ ساعت و }one{# ساعت و }other{# ساعت و }}</translation> <translation id="1842960171412779397">انتخاب</translation> +<translation id="1859234291848436338">جهت نوشتن</translation> <translation id="1860796786778352021">بستن اعلان</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />٪</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">صفحه بالا</translation> <translation id="2190355936436201913">(خالی)</translation> <translation id="219905428774326614">راهانداز، همه برنامهها</translation> +<translation id="2267918077332197517">مسدود کردن همه اعلانهای این سایت</translation> <translation id="2289052229480071835">روی اهداف لمسی در صفحهتان ضربه بزنید.</translation> <translation id="2295140143284145483">نظرسنجی</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> ترابایت/ثانیه</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">پیمایش به اینجا</translation> <translation id="3234408098842461169">پیکان پایین</translation> <translation id="3291688615589870984">{DAYS,plural, =1{۱ روز}one{# روز}other{# روز}}</translation> +<translation id="335581015389089642">صدا</translation> <translation id="3600566671520689681">{DAYS,plural, =1{۱ روز باقی مانده است}one{# روز باقی مانده است}other{# روز باقی مانده است}}</translation> +<translation id="3618849550573277856">جستجوی «<ph name="LOOKUP_STRING" />»</translation> <translation id="364720409959344976">انتخاب پوشه برای بارگذاری</translation> <translation id="3660179305079774227">پیکان بالا</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> گیگابایت/ثانیه</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">پرش</translation> <translation id="4250229828105606438">عکس صفحهنمایش</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{۱ ماه قبل}one{# ماه قبل}other{# ماه قبل}}</translation> +<translation id="4289300219472526559">شروع صحبت</translation> <translation id="4316910396681052118">همه برنامهها</translation> -<translation id="4320177379694898372">اتصال اینترنتی ندارید</translation> <translation id="4588090240171750605">پیمایش به راست</translation> <translation id="4724120544754982507">مرکز اعلان، <ph name="UNREAD_NOTIFICATION_COUNT" /> اعلان خواندهنشده</translation> <translation id="4730374152663651037">مکرراً استفادهشده</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">پیشنهادات برنامه</translation> <translation id="6364916375976753737">پیمایش به چپ</translation> <translation id="6394627529324717982">کاما</translation> +<translation id="6397363302884558537">توقف صحبت</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{۱ ثانیه قبل}one{# ثانیه قبل}other{# ثانیه قبل}}</translation> +<translation id="6430678249303439055">مسدود کردن همه اعلانهای این برنامه</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{۱ ثانیه قبل}one{# ثانیه قبل}other{# ثانیه قبل}}</translation> <translation id="654149438358937226">مسدود کردن همه اعلانها</translation> <translation id="6567071839949112727">کلیک کردن روی نسخه اولیه</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{۱ سال باقی مانده است}one{#سال باقی مانده است}other{#سال باقی مانده است}}</translation> <translation id="6945221475159498467">انتخاب</translation> <translation id="6965382102122355670">قبول</translation> +<translation id="6974053822202609517">راست به چپ</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">به احتمال خیلی زیاد</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">حاشیه چپ</translation> <translation id="8331626408530291785">پیمایش به بالا</translation> <translation id="8352146631962686268">{YEARS,plural, =1{۱ سال}one{# سال}other{# سال}}</translation> -<translation id="8371695176452482769">اکنون صحبت کنید</translation> <translation id="838869780401515933">علامتگذاری</translation> <translation id="8393700583063109961">ارسال پیام</translation> <translation id="8394908167088220973">پخش/مکث رسانه</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204"><ph name="NUMBER" /> مورد دیگر</translation> <translation id="8730621377337864115">تمام</translation> <translation id="8772073294905169192">{HOURS,plural, =1{۱ ساعت}one{# ساعت}other{# ساعت}}</translation> +<translation id="8798099450830957504">پیشفرض</translation> <translation id="8806053966018712535">پوشه <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">حاشیهنویسی تصویر</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> کیلوبایت</translation> diff --git a/chromium/ui/strings/translations/ui_strings_fi.xtb b/chromium/ui/strings/translations/ui_strings_fi.xtb index 40462ce3795..8a415d066cb 100644 --- a/chromium/ui/strings/translations/ui_strings_fi.xtb +++ b/chromium/ui/strings/translations/ui_strings_fi.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Lähetä</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">SOVELLUSSUOSITUKSET</translation> +<translation id="1368832886055348810">Vasemmalta oikealle</translation> <translation id="1398853756734560583">Suurenna</translation> <translation id="1413622004203049571">Poista ilmoitukset käytöstä sovellukselta <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuutti ja }other{# minuuttia ja }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Tähtiluokitus: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 tunti ja }other{# tuntia ja }}</translation> <translation id="1842960171412779397">Valitse</translation> +<translation id="1859234291848436338">Kirjoitussuunta</translation> <translation id="1860796786778352021">Ilmoitus sulje</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Sivu ylös</translation> <translation id="2190355936436201913">(tyhjä)</translation> <translation id="219905428774326614">Käynnistysohjelma, kaikki sovellukset</translation> +<translation id="2267918077332197517">Estä kaikki tämän sivuston ilmoitukset</translation> <translation id="2289052229480071835">Napauta näytölläsi olevia kosketettavia kohteita.</translation> <translation id="2295140143284145483">Kysely</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> Tt/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Vieritä tähän</translation> <translation id="3234408098842461169">Nuoli al.</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 päivä}other{# päivää}}</translation> +<translation id="335581015389089642">Puhe</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 päivä jäljellä}other{# päivää jäljellä}}</translation> +<translation id="3618849550573277856">Hae ”<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Valitse lähetettävä kansio</translation> <translation id="3660179305079774227">Nuoli yl.</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> Gt/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">siirry</translation> <translation id="4250229828105606438">Kuvakaappaus</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 kuukausi sitten}other{# kuukautta sitten}}</translation> +<translation id="4289300219472526559">Aloita puhuminen</translation> <translation id="4316910396681052118">KAIKKI SOVELLUKSET</translation> -<translation id="4320177379694898372">Ei internetyhteyttä</translation> <translation id="4588090240171750605">Vieritä oikealle</translation> <translation id="4724120544754982507">Ilmoituskeskus, <ph name="UNREAD_NOTIFICATION_COUNT" /> lukematonta ilmoitusta</translation> <translation id="4730374152663651037">USEIN KÄYTETYT</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SOVELLUSEHDOTUKSET</translation> <translation id="6364916375976753737">Vieritä vasemmalle</translation> <translation id="6394627529324717982">Pilkku</translation> +<translation id="6397363302884558537">Lopeta puhuminen</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 s sitten}other{# s sitten}}</translation> +<translation id="6430678249303439055">Estä kaikki tämän sovelluksen ilmoitukset</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 sekunti sitten}other{# sekuntia sitten}}</translation> <translation id="654149438358937226">Estä kaikki ilmoitukset</translation> <translation id="6567071839949112727">klikkaa edeltäjää</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 vuosi jäljellä}other{# vuotta jäljellä}}</translation> <translation id="6945221475159498467">Valitse</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Oikealta vasemmalle</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">TODENNÄKÖISIMMÄT</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Vasen reuna</translation> <translation id="8331626408530291785">Vieritä ylös</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 vuosi}other{# vuotta}}</translation> -<translation id="8371695176452482769">Puhu nyt</translation> <translation id="838869780401515933">valitse</translation> <translation id="8393700583063109961">Lähetä viesti</translation> <translation id="8394908167088220973">Media: toista/keskeytä</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> lisää</translation> <translation id="8730621377337864115">Valmis</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}other{# h}}</translation> +<translation id="8798099450830957504">Oletus</translation> <translation id="8806053966018712535">Kansio <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Lisää kuvaan muistiinpano</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kt</translation> diff --git a/chromium/ui/strings/translations/ui_strings_fil.xtb b/chromium/ui/strings/translations/ui_strings_fil.xtb index fe31e77dc93..6bee96d96f6 100644 --- a/chromium/ui/strings/translations/ui_strings_fil.xtb +++ b/chromium/ui/strings/translations/ui_strings_fil.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">I-upload</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">MGA INIREREKOMENDANG APP</translation> +<translation id="1368832886055348810">Kaliwa papuntang Kanan</translation> <translation id="1398853756734560583">Maximize</translation> <translation id="1413622004203049571">I-disable ang mga notification mula sa <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuto at }one{# minuto at }other{# na minuto at }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Star na rating <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 oras at }one{# oras at }other{# na oras at }}</translation> <translation id="1842960171412779397">piliin</translation> +<translation id="1859234291848436338">Pagsulat ng Direksyon</translation> <translation id="1860796786778352021">Isara ang notification</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Pataas</translation> <translation id="2190355936436201913">(walang laman)</translation> <translation id="219905428774326614">Launcher, lahat ng app</translation> +<translation id="2267918077332197517">I-block ang lahat ng notification mula sa site na ito</translation> <translation id="2289052229480071835">I-tap ang mga target sa pagpindot sa iyong screen.</translation> <translation id="2295140143284145483">Survey</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> (na) TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Mag-scroll dito</translation> <translation id="3234408098842461169">Down Arrow</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 araw}one{# araw}other{# na araw}}</translation> +<translation id="335581015389089642">Pananalita</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 araw na lang ang natitira}one{# araw na lang ang natitira}other{# na araw na lang ang natitira}}</translation> +<translation id="3618849550573277856">Hanapin ang “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Pumili ng Folder na I-a-upload</translation> <translation id="3660179305079774227">Up Arrow</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> (na) GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">tumalon</translation> <translation id="4250229828105606438">Screenshot</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 buwan ang nakalipas}one{# buwan ang nakalipas}other{# na buwan ang nakalipas}}</translation> +<translation id="4289300219472526559">Simulan ang Pagsasalita</translation> <translation id="4316910396681052118">LAHAT NG APP</translation> -<translation id="4320177379694898372">Walang koneksyon sa internet</translation> <translation id="4588090240171750605">Mag-scroll Pakanan</translation> <translation id="4724120544754982507">Notification Center, <ph name="UNREAD_NOTIFICATION_COUNT" /> (na) hindi pa nababasang notification</translation> <translation id="4730374152663651037">MADALAS GAMITIN</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">MGA IMINUMUNGKAHING APP</translation> <translation id="6364916375976753737">Mag-scroll Pakaliwa</translation> <translation id="6394627529324717982">Kuwit</translation> +<translation id="6397363302884558537">Ihinto ang Pagsasalita</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 segundo ang nakalipas}one{# segundo ang nakalipas}other{# na segundo ang nakalipas}}</translation> +<translation id="6430678249303439055">I-block ang lahat ng notification mula sa app na ito</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 segundo ang nakalipas}one{# segundo ang nakalipas}other{# na segundo ang nakalipas}}</translation> <translation id="654149438358937226">I-block ang lahat ng notification</translation> <translation id="6567071839949112727">i-click ang ancestor</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 taon ang natitira}one{# taon ang natitira}other{# na taon ang natitira}}</translation> <translation id="6945221475159498467">Pumili</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Kanan papuntang Kaliwa</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">PINAKAMALAMANG</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Kalwang Edge</translation> <translation id="8331626408530291785">Mag-scroll Pataas</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 taon}one{# taon}other{# na taon}}</translation> -<translation id="8371695176452482769">Magsalita ngayon</translation> <translation id="838869780401515933">I-tsek</translation> <translation id="8393700583063109961">Ipadala ang mensahe</translation> <translation id="8394908167088220973">I-Play/I-Pause ang Media</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> pa</translation> <translation id="8730621377337864115">Tapos na</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 oras}one{# oras}other{# na oras}}</translation> +<translation id="8798099450830957504">Default</translation> <translation id="8806053966018712535">Folder <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">I-annotate ang larawan</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_fr.xtb b/chromium/ui/strings/translations/ui_strings_fr.xtb index fe00aaa874d..7bc623e0894 100644 --- a/chromium/ui/strings/translations/ui_strings_fr.xtb +++ b/chromium/ui/strings/translations/ui_strings_fr.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Importer</translation> <translation id="1293699935367580298">Échap</translation> <translation id="1306549533752902673">APPLICATIONS RECOMMANDÉES</translation> +<translation id="1368832886055348810">De gauche à droite</translation> <translation id="1398853756734560583">Agrandir</translation> <translation id="1413622004203049571">Désactiver les notifications <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minute et }one{# minute et }other{# minutes et }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Note : <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 heure et }one{# heure et }other{# heures et }}</translation> <translation id="1842960171412779397">sélectionner</translation> +<translation id="1859234291848436338">Sens de l'écriture</translation> <translation id="1860796786778352021">Fermer la notification</translation> <translation id="1871244248791675517">Insér.</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Page précédente</translation> <translation id="2190355936436201913">(vide)</translation> <translation id="219905428774326614">Lanceur d'applications, toutes les applications</translation> +<translation id="2267918077332197517">Bloquer toutes les notifications de ce site</translation> <translation id="2289052229480071835">Appuyez sur les cibles tactiles affichées à l'écran.</translation> <translation id="2295140143284145483">Enquête</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> To/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Défilement jusqu'ici</translation> <translation id="3234408098842461169">Bas</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 jour}one{# jour}other{# jours}}</translation> +<translation id="335581015389089642">Voix</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 jour restant}one{# jour restant}other{# jours restants}}</translation> +<translation id="3618849550573277856">Rechercher "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Sélectionner le dossier d'importation</translation> <translation id="3660179305079774227">Haut</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> Go/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">accéder</translation> <translation id="4250229828105606438">Capture d'écran</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Il y a 1 mois}one{Il y a # mois}other{Il y a # mois}}</translation> +<translation id="4289300219472526559">Commencer à parler</translation> <translation id="4316910396681052118">TOUTES LES APPLICATIONS</translation> -<translation id="4320177379694898372">Aucune connexion Internet.</translation> <translation id="4588090240171750605">Défilement vers la droite</translation> <translation id="4724120544754982507">Centre de notification, <ph name="UNREAD_NOTIFICATION_COUNT" /> notifications non lues</translation> <translation id="4730374152663651037">SOUVENT UTILISÉES</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGGESTIONS D'APPLICATIONS</translation> <translation id="6364916375976753737">Défilement vers la gauche</translation> <translation id="6394627529324717982">Virgule</translation> +<translation id="6397363302884558537">Arrêter de parler</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Il y a 1 s}one{Il y a # s}other{Il y a # s}}</translation> +<translation id="6430678249303439055">Bloquer toutes les notifications de cette application</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Il y a une seconde}one{Il y a # seconde}other{Il y a # secondes}}</translation> <translation id="654149438358937226">Bloquer toutes les notifications</translation> <translation id="6567071839949112727">cliquer sur l'ancêtre</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 an restant}one{# an restant}other{# ans restants}}</translation> <translation id="6945221475159498467">Sélectionner</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">De droite à gauche</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">CLIC PROBABLE</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Côté gauche</translation> <translation id="8331626408530291785">Défilement vers le haut</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 an}one{# an}other{# ans}}</translation> -<translation id="8371695176452482769">Parlez maintenant.</translation> <translation id="838869780401515933">cocher</translation> <translation id="8393700583063109961">Envoyer un message</translation> <translation id="8394908167088220973">Contenu multimédia : lecture/pause</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204"><ph name="NUMBER" /> autres</translation> <translation id="8730621377337864115">OK</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}one{# h}other{# h}}</translation> +<translation id="8798099450830957504">Par défaut</translation> <translation id="8806053966018712535">Dossier <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Annoter l'image</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> Ko</translation> diff --git a/chromium/ui/strings/translations/ui_strings_gu.xtb b/chromium/ui/strings/translations/ui_strings_gu.xtb index 1ee0eab8dc8..10b2bc01571 100644 --- a/chromium/ui/strings/translations/ui_strings_gu.xtb +++ b/chromium/ui/strings/translations/ui_strings_gu.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">અપલોડ કરો</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ભલામણ કરેલ ઍપ</translation> +<translation id="1368832886055348810">ડાબેથી જમણે</translation> <translation id="1398853756734560583">મોટું કરો</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> તરફથી સૂચનાઓ અક્ષમ કરો</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 મિનિટ અને }one{# મિનિટ અને }other{# મિનિટ અને }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">સ્ટાર રેટિંગ <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 કલાક અને }one{# કલાક અને }other{# કલાક અને }}</translation> <translation id="1842960171412779397">પસંદ કરો</translation> +<translation id="1859234291848436338">લેખનના દિશાનિર્દેશ</translation> <translation id="1860796786778352021">સૂચના બંધ છે</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">પૃષ્ઠ ઉપર</translation> <translation id="2190355936436201913">(ખાલી)</translation> <translation id="219905428774326614">લૉન્ચર, બધી ઍપ</translation> +<translation id="2267918077332197517">આ સાઇટના બધા નોટિફિકેશનો અવરોધિત કરો</translation> <translation id="2289052229480071835">તમારી સ્ક્રીન પર ટચ કરવાના લક્ષ્યોને ટૅપ કરો.</translation> <translation id="2295140143284145483">સર્વેક્ષણ</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">અહીં સુધી સ્ક્રોલ કરો</translation> <translation id="3234408098842461169">નીચલો એરો</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 દિવસ}one{# દિવસ}other{# દિવસ}}</translation> +<translation id="335581015389089642">ભાષા</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 દિવસ બાકી}one{# દિવસ બાકી}other{# દિવસ બાકી}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” શોધો</translation> <translation id="364720409959344976">અપલોડ કરવા માટે ફોલ્ડર પસંદ કરો</translation> <translation id="3660179305079774227">ઉપર એરો</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">જંપ કરો</translation> <translation id="4250229828105606438">સ્ક્રીનશૉટ</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 મહિના પહેલાં}one{# મહિના પહેલાં}other{# મહિના પહેલાં}}</translation> +<translation id="4289300219472526559">બોલવાનું પ્રારંભ કરો</translation> <translation id="4316910396681052118">બધી ઍપ્લિકેશનો</translation> -<translation id="4320177379694898372">કોઈ ઇન્ટરનેટ કનેક્શન નથી</translation> <translation id="4588090240171750605">જમણે સ્ક્રોલ કરો</translation> <translation id="4724120544754982507">સૂચના કેન્દ્ર, વાંચ્યા વગરની <ph name="UNREAD_NOTIFICATION_COUNT" /> સૂચનાઓ</translation> <translation id="4730374152663651037">વારંવાર વપરાયેલ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ઍપ સૂચનો</translation> <translation id="6364916375976753737">ડાબે સ્ક્રોલ કરો</translation> <translation id="6394627529324717982">અલ્પવિરામ</translation> +<translation id="6397363302884558537">બોલવાનું રોકો</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 સે પહેલાં}one{# સે પહેલાં}other{# સે પહેલાં}}</translation> +<translation id="6430678249303439055">આ ઍપના બધા નોટિફિકેશનો અવરોધિત કરો</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 સેકંડ પહેલાં}one{# સેકંડ પહેલાં}other{# સેકંડ પહેલાં}}</translation> <translation id="654149438358937226">તમામ નોટિફિકેશનને બ્લૉક કરો</translation> <translation id="6567071839949112727">ઍન્સેસ્ટર પર ક્લિક કરો</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 વર્ષ બાકી}one{# વર્ષ બાકી}other{# વર્ષ બાકી}}</translation> <translation id="6945221475159498467">પસંદ કરો</translation> <translation id="6965382102122355670">બરાબર, સમજાઇ ગયું</translation> +<translation id="6974053822202609517">જમણેથી ડાબે</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">સૌથી વધુ શક્ય</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">ડાબી કિનારી</translation> <translation id="8331626408530291785">ઉપર સ્ક્રોલ કરો</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 વર્ષ}one{# વર્ષ}other{# વર્ષ}}</translation> -<translation id="8371695176452482769">હવે બોલો</translation> <translation id="838869780401515933">તપાસો</translation> <translation id="8393700583063109961">સંદેશ મોકલો</translation> <translation id="8394908167088220973">મીડિયા ચલાવો/થોભાવો</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> વધુ</translation> <translation id="8730621377337864115">થઈ ગયું</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 ક}one{# ક}other{# ક}}</translation> +<translation id="8798099450830957504">ડિફૉલ્ટ</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> ફોલ્ડર</translation> <translation id="883911313571074303">છબીમાં ટીકા કરો</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_hi.xtb b/chromium/ui/strings/translations/ui_strings_hi.xtb index 27e6d7f4216..aa6556d2906 100644 --- a/chromium/ui/strings/translations/ui_strings_hi.xtb +++ b/chromium/ui/strings/translations/ui_strings_hi.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">अपलोड करें</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">सुझाए गए ऐप्लिकेशन</translation> +<translation id="1368832886055348810">बाएं से दाएं</translation> <translation id="1398853756734560583">बड़ा करें</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> से सूचनाएं अक्षम करें</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 मिनट और }one{# मिनट और }other{# मिनट और }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">तारा रेटिंग <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 घंटा और }one{# घंटे और }other{# घंटे और }}</translation> <translation id="1842960171412779397">चुनें</translation> +<translation id="1859234291848436338">लिखने के निर्देश</translation> <translation id="1860796786778352021">सूचना बंद करें</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">पेज ऊपर</translation> <translation id="2190355936436201913">(खाली)</translation> <translation id="219905428774326614">लॉन्चर, सभी ऐप्लिकेशन</translation> +<translation id="2267918077332197517">इस साइट से सभी सूचनाएं रोकें</translation> <translation id="2289052229480071835">अपनी स्क्रीन पर स्पर्श लक्ष्य पर टैप करें.</translation> <translation id="2295140143284145483">सर्वे</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">यहां तक स्क्रॉल करें</translation> <translation id="3234408098842461169">नीचे तीर</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 दिन}one{# दिन}other{# दिन}}</translation> +<translation id="335581015389089642">बोली</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 दिन शेष}one{# दिन शेष}other{# दिन शेष}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” को खोजें</translation> <translation id="364720409959344976">अपलोड करने के लिए फ़ोल्डर चुनें</translation> <translation id="3660179305079774227">ऊपर तीर</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">जाएं</translation> <translation id="4250229828105606438">स्क्रीनशॉट</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 माह पहले}one{# माह पहले}other{# माह पहले}}</translation> +<translation id="4289300219472526559">बोलना प्रारंभ करें</translation> <translation id="4316910396681052118">सभी ऐप्लिकेशन</translation> -<translation id="4320177379694898372">कोई इंटरनेट कनेक्शन नहीं</translation> <translation id="4588090240171750605">दाएं स्क्रॉल करें</translation> <translation id="4724120544754982507">सूचना केंद्र, <ph name="UNREAD_NOTIFICATION_COUNT" /> गैर-पढ़ी गई सूचनाएं</translation> <translation id="4730374152663651037">अक्सर उपयोग किए गए</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ऐप्लिकेशन सुझाव</translation> <translation id="6364916375976753737">बाएं स्क्रॉल करें</translation> <translation id="6394627529324717982">अल्पविराम</translation> +<translation id="6397363302884558537">बोलना रोकें</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 सेकंड पहले}one{# सेकंड पहले}other{# सेकंड पहले}}</translation> +<translation id="6430678249303439055">इस ऐप्लिकेशन से सभी सूचनाएं रोकें</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 सेकंड पहले}one{# सेकंड पहले}other{# सेकंड पहले}}</translation> <translation id="654149438358937226">सभी सूचनाएं ब्लॉक करें</translation> <translation id="6567071839949112727">पहले वाले पर क्लिक करें</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 वर्ष शेष}one{# वर्ष शेष}other{# वर्ष शेष}}</translation> <translation id="6945221475159498467">चुनें</translation> <translation id="6965382102122355670">ठीक है</translation> +<translation id="6974053822202609517">दाएं से बाएं</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">सबसे अधिक संभावना है</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">बायां सिरा</translation> <translation id="8331626408530291785">ऊपर स्क्रॉल करें</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 वर्ष}one{# वर्ष}other{# वर्ष}}</translation> -<translation id="8371695176452482769">अब बोलें</translation> <translation id="838869780401515933">चेक करें</translation> <translation id="8393700583063109961">संदेश भेजें</translation> <translation id="8394908167088220973">मीडिया चलाएं/रोकें</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> और</translation> <translation id="8730621377337864115">पूर्ण</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1h}one{#h}other{#h}}</translation> +<translation id="8798099450830957504">सामान्य</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> फ़ोल्डर</translation> <translation id="883911313571074303">व्याख्या चित्र</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_hr.xtb b/chromium/ui/strings/translations/ui_strings_hr.xtb index 564a135cf43..6cf47fc3fa9 100644 --- a/chromium/ui/strings/translations/ui_strings_hr.xtb +++ b/chromium/ui/strings/translations/ui_strings_hr.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Prenesi</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">PREPORUČENE APLIKACIJE</translation> +<translation id="1368832886055348810">Slijeva udesno</translation> <translation id="1398853756734560583">Maksimiziraj</translation> <translation id="1413622004203049571">Onemogući obavijesti pošiljatelja <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuta i }one{# minuta i }few{# minute i }other{# minuta i }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Broj zvjezdica: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 sat i }one{# sat i }few{# sata i }other{# sati i }}</translation> <translation id="1842960171412779397">odaberi</translation> +<translation id="1859234291848436338">Smjer pisanja</translation> <translation id="1860796786778352021">Zatvaranje obavijesti</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Stranica prema gore</translation> <translation id="2190355936436201913">(prazno)</translation> <translation id="219905428774326614">Pokretač, sve aplikacije</translation> +<translation id="2267918077332197517">Blokiraj sve obavijesti te web-lokacije</translation> <translation id="2289052229480071835">Dodirnite ciljeve dodira na zaslonu.</translation> <translation id="2295140143284145483">Anketa</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Pomakni ovdje</translation> <translation id="3234408098842461169">Strelica dolje</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}</translation> +<translation id="335581015389089642">Govor</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Još 1 dan}one{Još # dan}few{Još # dana}other{Još # dana}}</translation> +<translation id="3618849550573277856">Potraži "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Odabir mape za prijenos</translation> <translation id="3660179305079774227">Strelica prema gore</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">skoči</translation> <translation id="4250229828105606438">Snimka zaslona</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Prije mjesec dana}one{Prije # mjeseca}few{Prije # mjeseca}other{Prije # mjeseci}}</translation> +<translation id="4289300219472526559">Počni govoriti</translation> <translation id="4316910396681052118">SVE APLIKACIJE</translation> -<translation id="4320177379694898372">Nema internetske veze</translation> <translation id="4588090240171750605">Pomakni se desno</translation> <translation id="4724120544754982507">Centar za obavijesti, nepročitanih obavijesti: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">ČESTO KORIŠTENO</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">PRIJEDLOZI APLIKACIJA</translation> <translation id="6364916375976753737">Pomakni se lijevo</translation> <translation id="6394627529324717982">Zarez</translation> +<translation id="6397363302884558537">Prestani govoriti</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Prije 1 s}one{Prije # s}few{Prije # s}other{Prije # s}}</translation> +<translation id="6430678249303439055">Blokiraj sve obavijesti te aplikacije</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Prije 1 sekunde}one{Prije # sekunde}few{Prije # sekunde}other{Prije # sekundi}}</translation> <translation id="654149438358937226">Blokiraj sve obavijesti</translation> <translation id="6567071839949112727">klikni nadređeni element</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Još godinu dana}one{Još # godinu}few{Još # godine}other{Još # godina}}</translation> <translation id="6945221475159498467">Odaberi</translation> <translation id="6965382102122355670">U redu</translation> +<translation id="6974053822202609517">Zdesna ulijevo</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">NAJVJEROJATNIJE</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Lijevi rub</translation> <translation id="8331626408530291785">Pomakni se gore</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 godina}one{# godina}few{# godine}other{# godina}}</translation> -<translation id="8371695176452482769">Govorite sad</translation> <translation id="838869780401515933">označi</translation> <translation id="8393700583063109961">Pošaljite poruku</translation> <translation id="8394908167088220973">Reproduciraj/pauziraj Medije</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">Još <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Gotovo</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}one{# h}few{# h}other{# h}}</translation> +<translation id="8798099450830957504">Zadano</translation> <translation id="8806053966018712535">Mapa <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Dodaj napomenu slici</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_hu.xtb b/chromium/ui/strings/translations/ui_strings_hu.xtb index d1b0ad2d6e5..0fdafd9d858 100644 --- a/chromium/ui/strings/translations/ui_strings_hu.xtb +++ b/chromium/ui/strings/translations/ui_strings_hu.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Feltöltés</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">AJÁNLOTT ALKALMAZÁSOK</translation> +<translation id="1368832886055348810">Balról jobbra</translation> <translation id="1398853756734560583">Teljes méret</translation> <translation id="1413622004203049571">A(z) <ph name="NOTIFIER_NAME" /> értesítéseinek kikapcsolása</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 perc és }other{# perc és }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144"><ph name="RATING_SCORE" /> csillagos értékelés</translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 óra és }other{# óra és }}</translation> <translation id="1842960171412779397">Kiválasztás</translation> +<translation id="1859234291848436338">Írás iránya</translation> <translation id="1860796786778352021">Értesítés bezárása</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Oldal fel</translation> <translation id="2190355936436201913">(üres)</translation> <translation id="219905428774326614">Indító, minden alkalmazás</translation> +<translation id="2267918077332197517">Minden értesítés letiltása erről a webhelyről</translation> <translation id="2289052229480071835">Koppintson a képernyőn az érintési célpontokra.</translation> <translation id="2295140143284145483">Felmérés</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Görgessen ide</translation> <translation id="3234408098842461169">Lefelé nyíl</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 nap}other{# nap}}</translation> +<translation id="335581015389089642">Beszéd</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 nap van hátra}other{# nap van hátra}}</translation> +<translation id="3618849550573277856">A(z) „<ph name="LOOKUP_STRING" />” keresése</translation> <translation id="364720409959344976">Mappa kiválasztása a feltöltéshez</translation> <translation id="3660179305079774227">Felfelé nyíl</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">Mehet</translation> <translation id="4250229828105606438">Képernyőkép</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 hónapja}other{# hónapja}}</translation> +<translation id="4289300219472526559">Beszéd megkezdése</translation> <translation id="4316910396681052118">MINDEN ALKALMAZÁS</translation> -<translation id="4320177379694898372">Nincs internetkapcsolat</translation> <translation id="4588090240171750605">Görgetés jobbra</translation> <translation id="4724120544754982507">Értesítési központ, <ph name="UNREAD_NOTIFICATION_COUNT" /> olvasatlan értesítés</translation> <translation id="4730374152663651037">GYAKRAN HASZNÁLT</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ALKALMAZÁSJAVASLATOK</translation> <translation id="6364916375976753737">Görgetés balra</translation> <translation id="6394627529324717982">Vessző</translation> +<translation id="6397363302884558537">Beszéd leállítása</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 másodperce}other{# másodperce}}</translation> +<translation id="6430678249303439055">Minden értesítés letiltása ettől az alkalmazástól</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 másodperce}other{# másodperce}}</translation> <translation id="654149438358937226">Minden értesítés letiltása</translation> <translation id="6567071839949112727">kattintás az elődre</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{hátralévő idő: 1 év}other{hátralévő idő: # év}}</translation> <translation id="6945221475159498467">Kiválasztás</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Jobbról balra</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">NAGY VALÓSZÍNŰSÉGGEL</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Bal sarok</translation> <translation id="8331626408530291785">Görgetés felfelé</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 év}other{# év}}</translation> -<translation id="8371695176452482769">Most beszéljen</translation> <translation id="838869780401515933">Megjelölés</translation> <translation id="8393700583063109961">Üzenet küldése</translation> <translation id="8394908167088220973">Lejátszás/szüneteltetés</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">és <ph name="NUMBER" /> további</translation> <translation id="8730621377337864115">Kész</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 ó}other{# ó}}</translation> +<translation id="8798099450830957504">Alapértelmezett</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> mappa</translation> <translation id="883911313571074303">Megjegyzés fűzése a képhez</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_id.xtb b/chromium/ui/strings/translations/ui_strings_id.xtb index 391851af169..e1c9196b510 100644 --- a/chromium/ui/strings/translations/ui_strings_id.xtb +++ b/chromium/ui/strings/translations/ui_strings_id.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Upload</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APLIKASI YANG DIREKOMENDASIKAN</translation> +<translation id="1368832886055348810">Kiri ke Kanan</translation> <translation id="1398853756734560583">Perbesar</translation> <translation id="1413622004203049571">Nonaktifkan pemberitahuan dari <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 menit dan }other{# menit dan }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Skor bintang <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 jam dan }other{# jam dan }}</translation> <translation id="1842960171412779397">pilih</translation> +<translation id="1859234291848436338">Arah Penulisan</translation> <translation id="1860796786778352021">Tutup pemberitahuan</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Page Up</translation> <translation id="2190355936436201913">(kosong)</translation> <translation id="219905428774326614">Peluncur, semua aplikasi</translation> +<translation id="2267918077332197517">Blokir semua notifikasi dari situs ini</translation> <translation id="2289052229480071835">Tap target sentuh di layar.</translation> <translation id="2295140143284145483">Survei</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/dtk</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Gulir ke Sini</translation> <translation id="3234408098842461169">Panah Bawah</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 hari}other{# hari}}</translation> +<translation id="335581015389089642">Ucapan</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation> +<translation id="3618849550573277856">Cari "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Pilih Folder untuk Diunggah</translation> <translation id="3660179305079774227">Panah Atas</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/dtk</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">lompati</translation> <translation id="4250229828105606438">Screenshot</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 bulan yang lalu}other{# bulan yang lalu}}</translation> +<translation id="4289300219472526559">Mulai Berbicara</translation> <translation id="4316910396681052118">SEMUA APLIKASI</translation> -<translation id="4320177379694898372">Tidak ada sambungan internet</translation> <translation id="4588090240171750605">Gulir ke Kanan</translation> <translation id="4724120544754982507">Pusat Notifikasi, <ph name="UNREAD_NOTIFICATION_COUNT" /> notifikasi belum dibaca</translation> <translation id="4730374152663651037">SERING DIGUNAKAN</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SARAN APLIKASI</translation> <translation id="6364916375976753737">Gulir ke Kiri</translation> <translation id="6394627529324717982">Koma</translation> +<translation id="6397363302884558537">Berhenti Berbicara</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 dtk yang lalu}other{# dtk yang lalu}}</translation> +<translation id="6430678249303439055">Blokir semua notifikasi dari aplikasi ini</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 detik yang lalu}other{# detik yang lalu}}</translation> <translation id="654149438358937226">Blokir semua notifikasi</translation> <translation id="6567071839949112727">klik ancestor</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 tahun lagi}other{# tahun lagi}}</translation> <translation id="6945221475159498467">Pilih</translation> <translation id="6965382102122355670">Oke</translation> +<translation id="6974053822202609517">Kanan ke Kiri</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MUNGKIN DICARI</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Tepi Kiri</translation> <translation id="8331626408530291785">Gulir ke Atas</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 tahun}other{# tahun}}</translation> -<translation id="8371695176452482769">Bicaralah sekarang</translation> <translation id="838869780401515933">centangi</translation> <translation id="8393700583063109961">Kirim pesan</translation> <translation id="8394908167088220973">Putar/Jeda Media</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> lagi</translation> <translation id="8730621377337864115">Selesai</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1j}other{#j}}</translation> +<translation id="8798099450830957504">Default</translation> <translation id="8806053966018712535">Folder <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Gambar anotasi</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_it.xtb b/chromium/ui/strings/translations/ui_strings_it.xtb index ef6e1c7e37f..332b8572fe1 100644 --- a/chromium/ui/strings/translations/ui_strings_it.xtb +++ b/chromium/ui/strings/translations/ui_strings_it.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Carica</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APP CONSIGLIATE</translation> +<translation id="1368832886055348810">Da sinistra a destra</translation> <translation id="1398853756734560583">Ingrandisci</translation> <translation id="1413622004203049571">Disabilita notifiche da <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuto e }other{# minuti e }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Valutazione a stelle: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 ora e }other{# ore e }}</translation> <translation id="1842960171412779397">seleziona</translation> +<translation id="1859234291848436338">Direzione di scrittura</translation> <translation id="1860796786778352021">Chiusura notifica</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Pagina su</translation> <translation id="2190355936436201913">(vuoto)</translation> <translation id="219905428774326614">Avvio applicazioni, tutte le app</translation> +<translation id="2267918077332197517">Blocca tutte le notifiche da questo sito</translation> <translation id="2289052229480071835">Tocca i touch target sul tuo schermo.</translation> <translation id="2295140143284145483">Sondaggio</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Scorri fino a qui</translation> <translation id="3234408098842461169">Freccia GIÙ</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 giorno}other{# giorni}}</translation> +<translation id="335581015389089642">Voce</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 giorno rimanente}other{# giorni rimanenti}}</translation> +<translation id="3618849550573277856">Cerca "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Seleziona la cartella da caricare</translation> <translation id="3660179305079774227">Freccia SU</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">vai</translation> <translation id="4250229828105606438">Screenshot</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 mese fa}other{# mesi fa}}</translation> +<translation id="4289300219472526559">Avvia comandi vocali</translation> <translation id="4316910396681052118">TUTTE LE APP</translation> -<translation id="4320177379694898372">Nessuna connessione Internet</translation> <translation id="4588090240171750605">Scorri a destra</translation> <translation id="4724120544754982507">Centro notifiche, <ph name="UNREAD_NOTIFICATION_COUNT" /> notifiche da leggere</translation> <translation id="4730374152663651037">USATE SPESSO</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">APP SUGGERITE</translation> <translation id="6364916375976753737">Scorri a sinistra</translation> <translation id="6394627529324717982">Virgola</translation> +<translation id="6397363302884558537">Interrompi comandi vocali</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 sec fa}other{# sec fa}}</translation> +<translation id="6430678249303439055">Blocca tutte le notifiche da questa app</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 secondo fa}other{# secondi fa}}</translation> <translation id="654149438358937226">Blocca tutte le notifiche</translation> <translation id="6567071839949112727">fai clic su predecessore</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 anno rimasto}other{# anni rimasti}}</translation> <translation id="6945221475159498467">Seleziona</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Da destra a sinistra</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">PIÙ PROBABILI</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Margine sinistro</translation> <translation id="8331626408530291785">Scorri verso l'alto</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 anno}other{# anni}}</translation> -<translation id="8371695176452482769">Parla adesso</translation> <translation id="838869780401515933">seleziona</translation> <translation id="8393700583063109961">Invia messaggio</translation> <translation id="8394908167088220973">Play/Pausa contenuti multimediali</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+ altre <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Fine</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}other{# h}}</translation> +<translation id="8798099450830957504">Predefinito</translation> <translation id="8806053966018712535">Cartella <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Annota immagine</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_iw.xtb b/chromium/ui/strings/translations/ui_strings_iw.xtb index ff517ff09f3..3bb12bb04df 100644 --- a/chromium/ui/strings/translations/ui_strings_iw.xtb +++ b/chromium/ui/strings/translations/ui_strings_iw.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">העלה</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">אפליקציות מומלצות</translation> +<translation id="1368832886055348810">משמאל לימין</translation> <translation id="1398853756734560583">הגדל</translation> <translation id="1413622004203049571">השבת הודעות מאת <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{דקה אחת ו }two{# דקות ו }many{# דקות ו }other{# דקות ו }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">דירוג כוכבים: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{שעה אחת ו }two{שעתיים ו }many{# שעות ו }other{# שעות ו }}</translation> <translation id="1842960171412779397">בחר</translation> +<translation id="1859234291848436338">כיוון כתיבה</translation> <translation id="1860796786778352021">סגירת הודעה</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652">%<ph name="NUMBER" /></translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">דף למעלה</translation> <translation id="2190355936436201913">(ריק)</translation> <translation id="219905428774326614">מפעיל האפליקציות, כל האפליקציות</translation> +<translation id="2267918077332197517">חסימת כל ההודעות מהאתר הזה</translation> <translation id="2289052229480071835">הקש על יעדי המגע במסך.</translation> <translation id="2295140143284145483">סקר</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">גלול ל'כאן'</translation> <translation id="3234408098842461169">חץ למטה</translation> <translation id="3291688615589870984">{DAYS,plural, =1{יום אחד}two{יומיים}many{# ימים}other{# ימים}}</translation> +<translation id="335581015389089642">דיבור</translation> <translation id="3600566671520689681">{DAYS,plural, =1{נותר יום אחד}two{נותרו יומיים}many{נותרו # ימים}other{נותרו # ימים}}</translation> +<translation id="3618849550573277856">חפש “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">בחירת תיקיה להעלאה</translation> <translation id="3660179305079774227">חץ למעלה</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">קפוץ</translation> <translation id="4250229828105606438">צילום מסך</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{לפני חודש אחד}two{לפני חודשיים}many{לפני # חודשים}other{לפני # חודשים}}</translation> +<translation id="4289300219472526559">התחל לדבר</translation> <translation id="4316910396681052118">כל האפליקציות</translation> -<translation id="4320177379694898372">אין חיבור לאינטרנט</translation> <translation id="4588090240171750605">גלול ימינה</translation> <translation id="4724120544754982507">מרכז הודעות, <ph name="UNREAD_NOTIFICATION_COUNT" /> הודעות שלא נקראו</translation> <translation id="4730374152663651037">בשימוש לעתים קרובות</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">הצעות לאפליקציות</translation> <translation id="6364916375976753737">גלול שמאלה</translation> <translation id="6394627529324717982">פסיק</translation> +<translation id="6397363302884558537">הפסק לדבר</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{לפני שנ‘ אחת}two{לפני # שנ‘}many{לפני # שנ‘}other{לפני # שנ‘}}</translation> +<translation id="6430678249303439055">חסימת כל ההודעות מהאפליקציה הזו</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{לפני שנייה אחת}two{לפני # שניות}many{לפני # שניות}other{לפני # שניות}}</translation> <translation id="654149438358937226">חסימת כל ההודעות</translation> <translation id="6567071839949112727">לחיצה על אב</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{נותרה שנה אחת}two{נותרו שנתיים}many{נותרו # שנים}other{נותרו # שנים}}</translation> <translation id="6945221475159498467">בחר</translation> <translation id="6965382102122355670">אישור</translation> +<translation id="6974053822202609517">מימין לשמאל</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">סבירות גבוהה</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">קצה שמאלי</translation> <translation id="8331626408530291785">גלול למעלה</translation> <translation id="8352146631962686268">{YEARS,plural, =1{שנה אחת}two{שנתיים}many{# שנים}other{# שנים}}</translation> -<translation id="8371695176452482769">דבר עכשיו</translation> <translation id="838869780401515933">סמן</translation> <translation id="8393700583063109961">שלח הודעה</translation> <translation id="8394908167088220973">הפעלה/השהיה של המדיה</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">ועוד <ph name="NUMBER" /></translation> <translation id="8730621377337864115">בוצע</translation> <translation id="8772073294905169192">{HOURS,plural, =1{שעה}two{# שע}many{# שע}other{# שע}}</translation> +<translation id="8798099450830957504">ברירת מחדל</translation> <translation id="8806053966018712535">תיקייה <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">רשום הערה לתמונה</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ja.xtb b/chromium/ui/strings/translations/ui_strings_ja.xtb index f34ab50f6ed..ff073ffb2b4 100644 --- a/chromium/ui/strings/translations/ui_strings_ja.xtb +++ b/chromium/ui/strings/translations/ui_strings_ja.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">アップロード</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">おすすめのアプリ</translation> +<translation id="1368832886055348810">左から右</translation> <translation id="1398853756734560583">最大化</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> からの通知を無効にする</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 分 }other{# 分 }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">評価 <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 時間 }other{# 時間 }}</translation> <translation id="1842960171412779397">選択</translation> +<translation id="1859234291848436338">文章の方向</translation> <translation id="1860796786778352021">通知を閉じる</translation> <translation id="1871244248791675517">Insert</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">前のページへ</translation> <translation id="2190355936436201913">(なし)</translation> <translation id="219905428774326614">ランチャー、すべてのアプリ</translation> +<translation id="2267918077332197517">このサイトからのすべての通知をブロックする</translation> <translation id="2289052229480071835">画面に表示されるタップ ターゲットをタップします。</translation> <translation id="2295140143284145483">アンケート</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/秒</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">ここまでスクロール</translation> <translation id="3234408098842461169">下矢印キー</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 日}other{# 日}}</translation> +<translation id="335581015389089642">スピーチ</translation> <translation id="3600566671520689681">{DAYS,plural, =1{残り 1 日}other{残り # 日}}</translation> +<translation id="3618849550573277856">「<ph name="LOOKUP_STRING" />」を検索</translation> <translation id="364720409959344976">アップロードするフォルダを選択</translation> <translation id="3660179305079774227">上矢印キー</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/秒</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">ジャンプ</translation> <translation id="4250229828105606438">スクリーンショット</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 か月前}other{# か月前}}</translation> +<translation id="4289300219472526559">読み上げを開始</translation> <translation id="4316910396681052118">すべてのアプリ</translation> -<translation id="4320177379694898372">インターネットに接続されていません</translation> <translation id="4588090240171750605">右にスクロール</translation> <translation id="4724120544754982507">通知センター: <ph name="UNREAD_NOTIFICATION_COUNT" /> 件の未読通知</translation> <translation id="4730374152663651037">よく使用するアプリ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">アプリの候補</translation> <translation id="6364916375976753737">左にスクロール</translation> <translation id="6394627529324717982">カンマ</translation> +<translation id="6397363302884558537">読み上げを停止</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation> +<translation id="6430678249303439055">このアプリからのすべての通知をブロックする</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation> <translation id="654149438358937226">通知をすべてブロックする</translation> <translation id="6567071839949112727">上位要素をクリック</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{残り 1 年}other{残り # 年}}</translation> <translation id="6945221475159498467">選択</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">右から左</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">これですか?</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">左端</translation> <translation id="8331626408530291785">上にスクロール</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 年}other{# 年}}</translation> -<translation id="8371695176452482769">お話しください</translation> <translation id="838869780401515933">チェックを付ける</translation> <translation id="8393700583063109961">メッセージを送信</translation> <translation id="8394908167088220973">メディアの再生/一時停止</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">他 <ph name="NUMBER" /> 件</translation> <translation id="8730621377337864115">完了</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1時間}other{#時間}}</translation> +<translation id="8798099450830957504">既定</translation> <translation id="8806053966018712535">フォルダ <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">画像に注釈を付ける</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_kn.xtb b/chromium/ui/strings/translations/ui_strings_kn.xtb index 4e9c9f7b35d..28bd579f118 100644 --- a/chromium/ui/strings/translations/ui_strings_kn.xtb +++ b/chromium/ui/strings/translations/ui_strings_kn.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">ಅಪ್ಲೋಡ್</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ಶಿಫಾರಸು ಮಾಡಲಾದ ಅಪ್ಲಿಕೇಶನ್ಗಳು</translation> +<translation id="1368832886055348810">ಎಡದಿಂದ ಬಲಕ್ಕೆ</translation> <translation id="1398853756734560583">ಗರಿಷ್ಠಗೊಳಿಸು</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> ಅವರ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 ನಿಮಿಷ ಮತ್ತು }one{# ನಿಮಿಷಗಳು ಮತ್ತು }other{# ನಿಮಿಷಗಳು ಮತ್ತು }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">ಸ್ಟಾರ್ ರೇಟಿಂಗ್ <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 ಗಂಟೆ ಮತ್ತು }one{# ಗಂಟೆಗಳು ಮತ್ತು }other{# ಗಂಟೆಗಳು ಮತ್ತು }}</translation> <translation id="1842960171412779397">ಆಯ್ಕೆ ಮಾಡಿ</translation> +<translation id="1859234291848436338">ಬರವಣಿಗೆ ನಿರ್ದೇಶನ</translation> <translation id="1860796786778352021">ಅಧಿಸೂಚನೆ ಮುಚ್ಚು</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">ಪುಟ ಮೇಲೆ</translation> <translation id="2190355936436201913">(ಖಾಲಿ)</translation> <translation id="219905428774326614">ಲಾಂಚರ್, ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್ಗಳು</translation> +<translation id="2267918077332197517">ಈ ಸೈಟ್ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ</translation> <translation id="2289052229480071835">ನಿಮ್ಮ ಪರದೆಯಲ್ಲಿ ಸ್ಪರ್ಶ ಟಾರ್ಗೆಟ್ಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ.</translation> <translation id="2295140143284145483">ಸಮೀಕ್ಷೆ</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">ಇಲ್ಲಿಗೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation> <translation id="3234408098842461169">ಕೆಳಗಿನ ಬಾಣದ ಗುರುತು</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 ದಿನ}one{# ದಿನಗಳು}other{# ದಿನಗಳು}}</translation> +<translation id="335581015389089642">ಧ್ವನಿ</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 ದಿನ ಬಾಕಿ ಉಳಿದಿದೆ}one{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” ನೋಡಿ</translation> <translation id="364720409959344976">ಅಪ್ಲೋಡ್ ಮಾಡಲು ಫೋಲ್ಡರ್ ಆಯ್ಕೆಮಾಡಿ</translation> <translation id="3660179305079774227">ಮೇಲಿನ ಬಾಣದ ಗುರುತು</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">ಹಾರು</translation> <translation id="4250229828105606438">ಸ್ಕ್ರೀನ್ಶಾಟ್</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 ತಿಂಗಳ ಹಿಂದೆ}one{# ತಿಂಗಳುಗಳ ಹಿಂದೆ}other{# ತಿಂಗಳುಗಳ ಹಿಂದೆ}}</translation> +<translation id="4289300219472526559">ಮಾತನಾಡುವುದನ್ನು ಪ್ರಾರಂಭಿಸಿ</translation> <translation id="4316910396681052118">ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್ಗಳು</translation> -<translation id="4320177379694898372">ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ</translation> <translation id="4588090240171750605">ಬಲಕ್ಕೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation> <translation id="4724120544754982507">ಅಧಿಸೂಚನೆ ಕೇಂದ್ರ, <ph name="UNREAD_NOTIFICATION_COUNT" /> ಓದದಿರುವ ಅಧಿಸೂಚನೆಗಳು</translation> <translation id="4730374152663651037">ಪದೇ ಪದೇ ಬಳಸಿರುವುದು</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ಅಪ್ಲಿಕೇಶನ್ ಸಲಹೆಗಳು</translation> <translation id="6364916375976753737">ಎಡಕ್ಕೆ ಸ್ಕ್ರೋಲ್ ಮಾಡಿ</translation> <translation id="6394627529324717982">ಅರ್ಧವಿರಾಮ</translation> +<translation id="6397363302884558537">ಮಾತನಾಡುವುದನ್ನು ನಿಲ್ಲಿಸಿ</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 ಸೆಕೆಂ ಹಿಂದೆ}one{# ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ}other{# ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ}}</translation> +<translation id="6430678249303439055">ಈ ಅಪ್ಲಿಕೇಶನ್ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 ಸೆಕೆಂಡ್ ಹಿಂದೆ}one{# ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ}other{# ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ}}</translation> <translation id="654149438358937226">ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ</translation> <translation id="6567071839949112727">ಪೂರ್ವಜರನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 ವರ್ಷ ಉಳಿದಿದೆ}one{# ವರ್ಷಗಳು ಉಳಿದಿವೆ}other{# ವರ್ಷಗಳು ಉಳಿದಿವೆ}}</translation> <translation id="6945221475159498467">ಆಯ್ಕೆಮಾಡಿ</translation> <translation id="6965382102122355670">ಸರಿ</translation> +<translation id="6974053822202609517">ಬಲದಿಂದ ಎಡಕ್ಕೆ</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">ಹೆಚ್ಚಿನ ಸಾಧ್ಯತೆ ಇದೆ</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">ಎಡ ಬದಿ</translation> <translation id="8331626408530291785">ಮೇಲೆ ಸ್ಕ್ರೋಲ್ ಮಾಡು</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 ವರ್ಷ}one{# ವರ್ಷಗಳು}other{# ವರ್ಷಗಳು}}</translation> -<translation id="8371695176452482769">ಈಗ ಮಾತನಾಡಿ</translation> <translation id="838869780401515933">ಪರಿಶೀಲಿಸಿ</translation> <translation id="8393700583063109961">ಸಂದೇಶ ಕಳುಹಿಸು</translation> <translation id="8394908167088220973">ಮೀಡಿಯಾ ಪ್ಲೇ/ವಿರಾಮ</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+ <ph name="NUMBER" /> ಇನ್ನಷ್ಟು</translation> <translation id="8730621377337864115">ಮುಗಿದಿದೆ</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1ಗಂ}one{#ಗಂ}other{#ಗಂ}}</translation> +<translation id="8798099450830957504">ಡಿಫಾಲ್ಟ್</translation> <translation id="8806053966018712535">ಫೋಲ್ಡರ್ <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">ಚಿತ್ರವನ್ನು ಟಿಪ್ಪಣಿ ಮಾಡಿ</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ko.xtb b/chromium/ui/strings/translations/ui_strings_ko.xtb index 851abf243bc..b0e7af9a5a5 100644 --- a/chromium/ui/strings/translations/ui_strings_ko.xtb +++ b/chromium/ui/strings/translations/ui_strings_ko.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">업로드</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">추천 앱</translation> +<translation id="1368832886055348810">왼쪽에서 오른쪽으로</translation> <translation id="1398853756734560583">최대화</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" />의 알림 사용 중지</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1분 }other{#분 }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">별표 평점: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1시간 }other{#시간 }}</translation> <translation id="1842960171412779397">선택</translation> +<translation id="1859234291848436338">쓰기 방향</translation> <translation id="1860796786778352021">알림 닫기</translation> <translation id="1871244248791675517">Insert</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">페이지 위로</translation> <translation id="2190355936436201913">(비어있음)</translation> <translation id="219905428774326614">런처, 모든 앱</translation> +<translation id="2267918077332197517">이 사이트의 모든 알림 차단</translation> <translation id="2289052229480071835">화면에서 터치 대상을 탭하세요.</translation> <translation id="2295140143284145483">설문조사</translation> <translation id="2297836609126180313"><ph name="QUANTITY" />TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">여기로 스크롤</translation> <translation id="3234408098842461169">아래 화살표</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1일}other{#일}}</translation> +<translation id="335581015389089642">음성</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1일 남음}other{#일 남음}}</translation> +<translation id="3618849550573277856">'<ph name="LOOKUP_STRING" />' 찾기</translation> <translation id="364720409959344976">업로드할 폴더 선택</translation> <translation id="3660179305079774227">위쪽 화살표</translation> <translation id="3740362395218339114"><ph name="QUANTITY" />GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">건너뛰기</translation> <translation id="4250229828105606438">캡처화면</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1개월 전}other{#개월 전}}</translation> +<translation id="4289300219472526559">말하기 시작</translation> <translation id="4316910396681052118">모든 앱</translation> -<translation id="4320177379694898372">인터넷에 연결되지 않음</translation> <translation id="4588090240171750605">오른쪽 스크롤</translation> <translation id="4724120544754982507">알림 센터, 읽지 않은 알림 <ph name="UNREAD_NOTIFICATION_COUNT" />개</translation> <translation id="4730374152663651037">자주 사용하는 앱</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">앱 추천</translation> <translation id="6364916375976753737">왼쪽으로 스크롤</translation> <translation id="6394627529324717982">콤마</translation> +<translation id="6397363302884558537">말하기 중지</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1초 전}other{#초 전}}</translation> +<translation id="6430678249303439055">이 앱의 모든 알림 차단</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1초 전}other{#초 전}}</translation> <translation id="654149438358937226">모든 알림 차단</translation> <translation id="6567071839949112727">상위 개체 클릭</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1년 남음}other{#년 남음}}</translation> <translation id="6945221475159498467">선택</translation> <translation id="6965382102122355670">확인</translation> +<translation id="6974053822202609517">오른쪽에서 왼쪽으로</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">사용할 만한 앱</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">왼쪽 모서리</translation> <translation id="8331626408530291785">위로 스크롤</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1년}other{#년}}</translation> -<translation id="8371695176452482769">말하세요</translation> <translation id="838869780401515933">선택</translation> <translation id="8393700583063109961">메시지 보내기</translation> <translation id="8394908167088220973">미디어 재생/일시중지</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" />개</translation> <translation id="8730621377337864115">완료</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1시간}other{#시간}}</translation> +<translation id="8798099450830957504">기본값</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> 폴더</translation> <translation id="883911313571074303">이미지에 주석 달기</translation> <translation id="8901569739625249689"><ph name="QUANTITY" />KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_lt.xtb b/chromium/ui/strings/translations/ui_strings_lt.xtb index a25a968e5f5..fe75e98d64e 100644 --- a/chromium/ui/strings/translations/ui_strings_lt.xtb +++ b/chromium/ui/strings/translations/ui_strings_lt.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Įkelti</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">REKOMENDUOJAMOS PROGRAMOS</translation> +<translation id="1368832886055348810">Iš kairės į dešinę</translation> <translation id="1398853756734560583">Išskleisti</translation> <translation id="1413622004203049571">Išjungti pranešimus nuo <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minutė ir }one{# minutė ir }few{# minutės ir }many{# minutės ir }other{# minučių ir }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Įvertinimas žvaigždutėmis <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 valanda ir }one{# valanda ir }few{# valandos ir }many{# valandos ir }other{# valandų ir }}</translation> <translation id="1842960171412779397">pasirinkti</translation> +<translation id="1859234291848436338">Rašymo nurodymas</translation> <translation id="1860796786778352021">Uždaryti pranešimus</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Puslapį į viršų</translation> <translation id="2190355936436201913">(tuščias)</translation> <translation id="219905428774326614">Paleidimo priemonė, visos programos</translation> +<translation id="2267918077332197517">Blokuoti visus šios svetainės pranešimus</translation> <translation id="2289052229480071835">Palieskite jutiklines sritis ekrane.</translation> <translation id="2295140143284145483">Apklausa</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Slinkti iki čia</translation> <translation id="3234408098842461169">Rodyklė „Žemyn“</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 diena}one{# diena}few{# dienos}many{# dienos}other{# dienų}}</translation> +<translation id="335581015389089642">Kalba</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Liko 1 diena}one{Liko # diena}few{Liko # dienos}many{Liko # dienos}other{Liko # dienų}}</translation> +<translation id="3618849550573277856">Ieškoti „<ph name="LOOKUP_STRING" />“</translation> <translation id="364720409959344976">Pasirinkite norimą įkelti aplanką</translation> <translation id="3660179305079774227">Rodyklė „Aukštyn“</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">peršokti</translation> <translation id="4250229828105606438">Ekrano kopija</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Prieš 1 mėnesį}one{Prieš # mėnesį}few{Prieš # mėnesius}many{Prieš # mėnesio}other{Prieš # mėnesių}}</translation> +<translation id="4289300219472526559">Pradėti kalbėti</translation> <translation id="4316910396681052118">VISOS PROGRAMOS</translation> -<translation id="4320177379694898372">Nėra interneto ryšio</translation> <translation id="4588090240171750605">Slinkti į dešinę</translation> <translation id="4724120544754982507">Pranešimų centras, neskaitytų pranešimų: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">DAŽNAI NAUDOJAMOS PROGRAMOS</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">PROGRAMŲ PASIŪLYMAI</translation> <translation id="6364916375976753737">Slinkti į kairę</translation> <translation id="6394627529324717982">Kablelis</translation> +<translation id="6397363302884558537">Baigti kalbėti</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Prieš 1 sek.}one{Prieš # sek.}few{Prieš # sek.}many{Prieš # sek.}other{Prieš # sek.}}</translation> +<translation id="6430678249303439055">Blokuoti visus šios programos pranešimus</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Prieš 1 sekundę}one{Prieš # sekundę}few{Prieš # sekundes}many{Prieš # sekundės}other{Prieš # sekundžių}}</translation> <translation id="654149438358937226">Blokuoti visus pranešimus</translation> <translation id="6567071839949112727">spustelėti aukštesnio lygmens elementą</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Liko 1 metai}one{Liko # metai}few{Liko # metai}many{Liko # metų}other{Liko # metų}}</translation> <translation id="6945221475159498467">Pasirinkti</translation> <translation id="6965382102122355670">Gerai</translation> +<translation id="6974053822202609517">Iš dešinės į kairę</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">TIKRIAUSIAI SPUSTELĖJAMOS PROGRAMOS</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Kairysis kraštas</translation> <translation id="8331626408530291785">Slinkti į viršų</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 metai}one{# metai}few{# metai}many{# metų}other{# metų}}</translation> -<translation id="8371695176452482769">Kalbėti dabar</translation> <translation id="838869780401515933">tikrinti</translation> <translation id="8393700583063109961">Siųsti pranešimą</translation> <translation id="8394908167088220973">Leisti / pristabdyti mediją</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">Dar <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Atlikta</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 val.}one{# val.}few{# val.}many{# val.}other{# val.}}</translation> +<translation id="8798099450830957504">Numatytasis</translation> <translation id="8806053966018712535">Aplankas „<ph name="FOLDER_NAME" />“</translation> <translation id="883911313571074303">Komentuoti vaizdą</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_lv.xtb b/chromium/ui/strings/translations/ui_strings_lv.xtb index b375e7fe370..66b620dbcc7 100644 --- a/chromium/ui/strings/translations/ui_strings_lv.xtb +++ b/chromium/ui/strings/translations/ui_strings_lv.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Augšupielādēt</translation> <translation id="1293699935367580298">Atsolis</translation> <translation id="1306549533752902673">IETEIKTĀS LIETOTNES</translation> +<translation id="1368832886055348810">No kreisās uz labo pusi</translation> <translation id="1398853756734560583">Maksimizēt</translation> <translation id="1413622004203049571">Atspējot paziņojumu saņemšanu no: <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minūte un }zero{# minūtes un }one{# minūte un }other{# minūtes un }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Sākt vērtēt <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 stunda un }zero{# stundas un }one{# stunda un }other{# stundas un }}</translation> <translation id="1842960171412779397">Atlasiet</translation> +<translation id="1859234291848436338">Rakstīšanas virziens</translation> <translation id="1860796786778352021">Paziņojuma aizvēršana</translation> <translation id="1871244248791675517">Iespraušana</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Augšup</translation> <translation id="2190355936436201913">(tukšs)</translation> <translation id="219905428774326614">Palaišanas programma, visas lietotnes</translation> +<translation id="2267918077332197517">Bloķēt visus paziņojumus no šīs vietnes</translation> <translation id="2289052229480071835">Pieskarieties ekrānā redzamajiem pieskāriena mērķiem.</translation> <translation id="2295140143284145483">Aptauja</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Ritināt šeit</translation> <translation id="3234408098842461169">Bulta Lejup</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 diena}zero{# dienas}one{# diena}other{# dienas}}</translation> +<translation id="335581015389089642">Runa</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Atlikusi 1 diena}zero{Atlikušas # dienas}one{Atlikusi # diena}other{Atlikušas # dienas}}</translation> +<translation id="3618849550573277856">Meklēt “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Augšupielādējamās mapes atlase</translation> <translation id="3660179305079774227">Bulta augšup</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">lekt</translation> <translation id="4250229828105606438">Ekrānuzņēmums</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Pirms 1 mēneša}zero{Pirms # mēnešiem}one{Pirms # mēneša}other{Pirms # mēnešiem}}</translation> +<translation id="4289300219472526559">Sākt runāt</translation> <translation id="4316910396681052118">VISAS LIETOTNES</translation> -<translation id="4320177379694898372">Nav interneta savienojuma.</translation> <translation id="4588090240171750605">Ritināt pa labi</translation> <translation id="4724120544754982507">Paziņojumu centrs, <ph name="UNREAD_NOTIFICATION_COUNT" /> nelasīts(-i) paziņojums(-i)</translation> <translation id="4730374152663651037">BIEŽI IZMANTOTĀS</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">LIETOTŅU IETEIKUMI</translation> <translation id="6364916375976753737">Ritināt pa kreisi</translation> <translation id="6394627529324717982">Komats</translation> +<translation id="6397363302884558537">Pārtraukt runāt</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Pirms 1 s}zero{Pirms # s}one{Pirms # s}other{Pirms # s}}</translation> +<translation id="6430678249303439055">Bloķēt visus paziņojumus no šīs lietotnes</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Pirms 1 sekundes}zero{Pirms # sekundēm}one{Pirms # sekundes}other{Pirms # sekundēm}}</translation> <translation id="654149438358937226">Bloķēt visus paziņojumus</translation> <translation id="6567071839949112727">noklikšķināt uz priekšteča</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Atlicis 1 gads}zero{Atlikuši # gadi}one{Atlicis # gads}other{Atlikuši # gadi}}</translation> <translation id="6945221475159498467">Atlasīt</translation> <translation id="6965382102122355670">Labi</translation> +<translation id="6974053822202609517">No labās uz kreiso pusi</translation> <translation id="7052633198403197513">taustiņš F1</translation> <translation id="7130207228079676353">VISTICAMĀK</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Kreisā mala</translation> <translation id="8331626408530291785">Ritināt augšup</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 gads}zero{# gadu}one{# gads}other{# gadi}}</translation> -<translation id="8371695176452482769">Runājiet tūlīt</translation> <translation id="838869780401515933">prbaudt</translation> <translation id="8393700583063109961">Sūtīt ziņojumu</translation> <translation id="8394908167088220973">Multivide — atskaņot/apturēt</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">vēl <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Gatavs</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}zero{# h}one{# h}other{# h}}</translation> +<translation id="8798099450830957504">Noklusējums</translation> <translation id="8806053966018712535">Mape <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Anotēt attēlu</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ml.xtb b/chromium/ui/strings/translations/ui_strings_ml.xtb index af6b8fc8961..e70bb0a838f 100644 --- a/chromium/ui/strings/translations/ui_strings_ml.xtb +++ b/chromium/ui/strings/translations/ui_strings_ml.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">അപ്ലോഡുചെയ്യുക</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ശുപാർശിത ആപ്പുകൾ</translation> +<translation id="1368832886055348810">ഇടതുനിന്ന് വലത്തേക്ക്</translation> <translation id="1398853756734560583">വലുതാക്കുക</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> എന്നതിൽ നിന്നുള്ള അറിയിപ്പുകൾ പ്രവർത്തനരഹിതമാക്കുക</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{ഒരു മിനിറ്റും }other{# മിനിറ്റും }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">നക്ഷത്ര റേറ്റിംഗ് <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{ഒരു മണിക്കൂറും }other{# മണിക്കൂറും }}</translation> <translation id="1842960171412779397">തിരഞ്ഞെടുക്കൂ</translation> +<translation id="1859234291848436338">എഴുതേണ്ട ദിശ</translation> <translation id="1860796786778352021">അറിയിപ്പ് അടയ്ക്കൽ</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">പേജ് മുകളിലേയ്ക്ക്</translation> <translation id="2190355936436201913">(ശൂന്യം)</translation> <translation id="219905428774326614">ലോഞ്ചർ, എല്ലാ ആപ്പുകളും</translation> +<translation id="2267918077332197517">ഈ സൈറ്റിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളും ബ്ലോക്ക് ചെയ്യുക</translation> <translation id="2289052229480071835">സ്ക്രീനിലുള്ള 'ടാർഗെറ്റുകൾ സ്പർശിക്കുക' ടാപ്പുചെയ്യുക.</translation> <translation id="2295140143284145483">സർവ്വേ</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">ഇവിടെ സ്ക്രോള് ചെയ്യുക</translation> <translation id="3234408098842461169">താഴേക്കുള്ള ആരോ അടയാളം</translation> <translation id="3291688615589870984">{DAYS,plural, =1{ഒരു ദിവസം}other{# ദിവസം}}</translation> +<translation id="335581015389089642">സംഭാഷണം</translation> <translation id="3600566671520689681">{DAYS,plural, =1{ഒരു ദിവസം ശേഷിക്കുന്നു}other{# ദിവസം ശേഷിക്കുന്നു}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” തിരയുക</translation> <translation id="364720409959344976">അപ്ലോഡുചെയ്യുന്നതിന് ഫോൾഡർ തിരഞ്ഞെടുക്കുക</translation> <translation id="3660179305079774227">മുകളിലേക്കുള്ള അമ്പടയാളം</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">jump</translation> <translation id="4250229828105606438">സ്ക്രീൻഷോട്ട്</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{ഒരു മാസം മുമ്പ്}other{# മാസം മുമ്പ്}}</translation> +<translation id="4289300219472526559">സംഭാഷണം ആരംഭിക്കുക</translation> <translation id="4316910396681052118">എല്ലാ ആപ്പുകളും</translation> -<translation id="4320177379694898372">ഇന്റർനെറ്റ് കണക്ഷനൊന്നുമില്ല</translation> <translation id="4588090240171750605">വലത്തോട്ട് സ്ക്രോള് ചെയ്യുക</translation> <translation id="4724120544754982507">അറിയിപ്പ് കേന്ദ്രം, <ph name="UNREAD_NOTIFICATION_COUNT" /> വായിക്കാത്ത അറിയിപ്പുകൾ</translation> <translation id="4730374152663651037">പതിവായി ഉപയോഗിക്കുന്നത്</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ആപ്പ് നിർദ്ദേശങ്ങൾ</translation> <translation id="6364916375976753737">ഇടത്തേക്ക് സ്ക്രോള് ചെയ്യുക</translation> <translation id="6394627529324717982">കോമ</translation> +<translation id="6397363302884558537">സംഭാഷണം നിർത്തുക</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{ഒരു സെക്കൻഡ് മുമ്പ്}other{# സെക്കൻഡ് മുമ്പ്}}</translation> +<translation id="6430678249303439055">ഈ ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളും ബ്ലോക്ക് ചെയ്യുക</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 സെക്കൻഡ് മുമ്പ്}other{# സെക്കൻഡ് മുമ്പ്}}</translation> <translation id="654149438358937226">എല്ലാ അറിയിപ്പുകളും ബ്ലോക്ക് ചെയ്യുക</translation> <translation id="6567071839949112727">ആൻസിസ്റ്ററിൽ ക്ലിക്ക് ചെയ്യുക</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{ഒരു വർഷം ശേഷിക്കുന്നു}other{# വർഷം ശേഷിക്കുന്നു}}</translation> <translation id="6945221475159498467">തിരഞ്ഞെടുക്കുക</translation> <translation id="6965382102122355670">ശരി</translation> +<translation id="6974053822202609517">വലത്ത് നിന്ന് ഇടത്തേക്ക്</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">ഏറ്റവും കൂടുതൽ പേർ ലൈക്കുചെയ്തത്</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">ഇടത് അഗ്രം</translation> <translation id="8331626408530291785">മുകളിലേക്ക് സ്ക്രോള് ചെയ്യൂ</translation> <translation id="8352146631962686268">{YEARS,plural, =1{ഒരു വര്ഷം}other{# വർഷം}}</translation> -<translation id="8371695176452482769">ഇപ്പോള് സംസാരിക്കുക</translation> <translation id="838869780401515933">പരിശോധിക്കൂ</translation> <translation id="8393700583063109961">സന്ദേശം അയയ്ക്കുക</translation> <translation id="8394908167088220973">മീഡിയ പ്ലേ ചെയ്യുക/താൽക്കാലികമായി നിർത്തുക</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204"><ph name="NUMBER" /> എണ്ണം കൂടി</translation> <translation id="8730621377337864115">പൂർത്തിയാക്കി</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 മണിക്കൂർ}other{# മണിക്കൂർ}}</translation> +<translation id="8798099450830957504">സ്ഥിരസ്ഥിതി</translation> <translation id="8806053966018712535">ഫോൾഡർ <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">ചിത്രം വ്യാഖ്യാനിക്കുക</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_mr.xtb b/chromium/ui/strings/translations/ui_strings_mr.xtb index 82a9e213f86..7ae05d047ca 100644 --- a/chromium/ui/strings/translations/ui_strings_mr.xtb +++ b/chromium/ui/strings/translations/ui_strings_mr.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">अपलोड करा</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">शिफारस केलेले अॅप्स</translation> +<translation id="1368832886055348810">डावीकडून उजवीकडे</translation> <translation id="1398853756734560583">वाढवा</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> वरील सूचना अक्षम करा</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 मिनिट आणि }one{# मिनिट आणि }other{# मिनिटे आणि }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144"><ph name="RATING_SCORE" /> तारे रेटिंग</translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 तास आणि }one{# तास आणि }other{# तास आणि }}</translation> <translation id="1842960171412779397">निवडा</translation> +<translation id="1859234291848436338">लिहिण्याची दिशा</translation> <translation id="1860796786778352021">सूचना बंद</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">पृष्ठ वर</translation> <translation id="2190355936436201913">(रिक्त)</translation> <translation id="219905428774326614">लाँचर, सर्व अॅप्स</translation> +<translation id="2267918077332197517">या साइटच्या सर्व सूचना ब्लॉक करा</translation> <translation id="2289052229480071835">आपल्या स्क्रीनवरील लक्ष्यांना स्पर्श करा टॅप करा.</translation> <translation id="2295140143284145483">सर्वेक्षण</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">येथे स्क्रोल करा</translation> <translation id="3234408098842461169">Down Arrow</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 दिवस}one{# दिवस}other{# दिवस}}</translation> +<translation id="335581015389089642">भाषण</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 दिवस शिल्लक}one{# दिवस शिल्लक}other{# दिवस शिल्लक}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” पहा</translation> <translation id="364720409959344976">अपलोड करण्यासाठी फोल्डर निवडा</translation> <translation id="3660179305079774227">Up Arrow</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">जंप करा</translation> <translation id="4250229828105606438">स्क्रीनशॉट</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 महिन्यापूर्वी}one{# महिन्यापूर्वी}other{# महिन्यांपूर्वी}}</translation> +<translation id="4289300219472526559">बोलणे प्रारंभ करा</translation> <translation id="4316910396681052118">सर्व अॅप्स</translation> -<translation id="4320177379694898372">कोणतेही इंटरनेट कनेक्शन नाही</translation> <translation id="4588090240171750605">उजवे स्क्रोल करा</translation> <translation id="4724120544754982507">सूचना केंद्र, <ph name="UNREAD_NOTIFICATION_COUNT" /> न वाचलेल्या सूचना</translation> <translation id="4730374152663651037">वारंवार वापरलेले</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">अॅप सूचना</translation> <translation id="6364916375976753737">डावीकडे स्क्रोल करा</translation> <translation id="6394627529324717982">स्वल्पविराम</translation> +<translation id="6397363302884558537">बोलणे थांबवा</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 सेकंदापूर्वी}one{# सेकंदापूर्वी}other{# सेकंदांपूर्वी}}</translation> +<translation id="6430678249303439055">या अॅपच्या सर्व सूचना ब्लॉक करा</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 सेकंदापूर्वी}one{# सेकंदापूर्वी}other{# सेकंदांपूर्वी}}</translation> <translation id="654149438358937226">सर्व सूचना ब्लॉक करा</translation> <translation id="6567071839949112727">पूर्वजवर क्लिक करा</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 वर्ष राहिले}one{# वर्ष राहिले}other{# वर्षे राहिली}}</translation> <translation id="6945221475159498467">निवडा</translation> <translation id="6965382102122355670">ठीक आहे</translation> +<translation id="6974053822202609517">उजवीकडून डावीकडे</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">सर्वाधिक शक्यता</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">डावे काठ</translation> <translation id="8331626408530291785">वर स्क्रोल करा</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 वर्ष}one{# वर्ष}other{# वर्षे}}</translation> -<translation id="8371695176452482769">आता बोला</translation> <translation id="838869780401515933">तपासा</translation> <translation id="8393700583063109961">संदेश पाठवा</translation> <translation id="8394908167088220973">मीडिया प्ले करा/विराम द्या</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+आणखी <ph name="NUMBER" /></translation> <translation id="8730621377337864115">पूर्ण झाले</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1ता}one{#ता}other{#ता}}</translation> +<translation id="8798099450830957504">डीफॉल्ट</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> फोल्डर</translation> <translation id="883911313571074303">प्रतिमेवर भाष्य करा</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ms.xtb b/chromium/ui/strings/translations/ui_strings_ms.xtb index f93e134d165..de467150e5a 100644 --- a/chromium/ui/strings/translations/ui_strings_ms.xtb +++ b/chromium/ui/strings/translations/ui_strings_ms.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Muat naik</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APL YANG DISYORKAN</translation> +<translation id="1368832886055348810">Kiri ke Kanan</translation> <translation id="1398853756734560583">Maksimumkan</translation> <translation id="1413622004203049571">Lumpuhkan pemberitahuan daripada <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minit dan }other{# minit dan }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Penilaian <ph name="RATING_SCORE" /> bintang</translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 jam dan }other{# jam dan }}</translation> <translation id="1842960171412779397">pilih</translation> +<translation id="1859234291848436338">Arah Penulisan</translation> <translation id="1860796786778352021">Tutup Pemberitahuan</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Halaman Ke Atas</translation> <translation id="2190355936436201913">(kosong)</translation> <translation id="219905428774326614">Pelancar, semua apl</translation> +<translation id="2267918077332197517">Sekat semua pemberitahuan daripada tapak ini</translation> <translation id="2289052229480071835">Ketik sasaran sentuhan pada skrin anda.</translation> <translation id="2295140143284145483">Tinjauan</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Tatal ke Sini</translation> <translation id="3234408098842461169">Anak Panah Bawah</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 hari}other{# hari}}</translation> +<translation id="335581015389089642">Pertuturan</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation> +<translation id="3618849550573277856">Cari “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Pilih Folder untuk Dimuat Naik</translation> <translation id="3660179305079774227">Anak Panah Atas</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">lompat</translation> <translation id="4250229828105606438">Tangkapan skrin</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 bulan yang lalu}other{# bulan yang lalu}}</translation> +<translation id="4289300219472526559">Mula Bercakap</translation> <translation id="4316910396681052118">SEMUA APL</translation> -<translation id="4320177379694898372">Tiada sambungan Internet</translation> <translation id="4588090240171750605">Tatal ke Kanan</translation> <translation id="4724120544754982507">Pusat Pemberitahuan, <ph name="UNREAD_NOTIFICATION_COUNT" /> pemberitahuan belum dibaca</translation> <translation id="4730374152663651037">KERAP DIGUNAKAN</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">CADANGAN APL</translation> <translation id="6364916375976753737">Tatal Ke Kiri</translation> <translation id="6394627529324717982">Koma</translation> +<translation id="6397363302884558537">Berhenti Bercakap</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 saat yang lalu}other{# saat yang lalu}}</translation> +<translation id="6430678249303439055">Sekat semua pemberitahuan daripada apl ini</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Sesaat yang lalu}other{# saat yang lalu}}</translation> <translation id="654149438358937226">Sekat semua pemberitahuan</translation> <translation id="6567071839949112727">klik pewaris</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Berbaki 1 tahun}other{Berbaki # tahun}}</translation> <translation id="6945221475159498467">Pilih</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Kanan ke Kiri</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">KEMUNGKINAN BESAR</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Tepi Kiri</translation> <translation id="8331626408530291785">Tatal Ke Atas</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 tahun}other{# tahun}}</translation> -<translation id="8371695176452482769">Cakap sekarang</translation> <translation id="838869780401515933">periksa</translation> <translation id="8393700583063109961">Hantar mesej</translation> <translation id="8394908167088220973">Main/Jeda Media</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> lagi</translation> <translation id="8730621377337864115">Selesai</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1j}other{#j}}</translation> +<translation id="8798099450830957504">Lalai</translation> <translation id="8806053966018712535">Folder <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Anotasikan imej</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_nl.xtb b/chromium/ui/strings/translations/ui_strings_nl.xtb index 45b7b8b044b..8d248d1be85 100644 --- a/chromium/ui/strings/translations/ui_strings_nl.xtb +++ b/chromium/ui/strings/translations/ui_strings_nl.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Uploaden</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">AANBEVOLEN APPS</translation> +<translation id="1368832886055348810">Links naar rechts</translation> <translation id="1398853756734560583">Maximaliseren</translation> <translation id="1413622004203049571">Meldingen van <ph name="NOTIFIER_NAME" /> uitschakelen</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuut en }other{# minuten en }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Sterbeoordeling <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 uur en }other{# uur en }}</translation> <translation id="1842960171412779397">Selecteren</translation> +<translation id="1859234291848436338">Schrijfrichting</translation> <translation id="1860796786778352021">Melding sluiten</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Pagina omhoog</translation> <translation id="2190355936436201913">(leeg)</translation> <translation id="219905428774326614">Launcher, alle apps</translation> +<translation id="2267918077332197517">Alle meldingen van deze site blokkeren</translation> <translation id="2289052229480071835">Tik op de tikdoelen op je scherm.</translation> <translation id="2295140143284145483">Enquête</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Hiernaartoe bladeren</translation> <translation id="3234408098842461169">Pijl-omlaag</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dagen}}</translation> +<translation id="335581015389089642">Spraak</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 dag resterend}other{# dagen resterend}}</translation> +<translation id="3618849550573277856">'<ph name="LOOKUP_STRING" />' opzoeken</translation> <translation id="364720409959344976">Map voor uploaden selecteren</translation> <translation id="3660179305079774227">Pijl-omhoog</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">Gaan naar</translation> <translation id="4250229828105606438">Screenshot</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 maand geleden}other{# maanden geleden}}</translation> +<translation id="4289300219472526559">Inspreken starten</translation> <translation id="4316910396681052118">ALLE APPS</translation> -<translation id="4320177379694898372">Geen internetverbinding</translation> <translation id="4588090240171750605">Naar rechts bladeren</translation> <translation id="4724120544754982507">Meldingscentrum, <ph name="UNREAD_NOTIFICATION_COUNT" /> ongelezen meldingen</translation> <translation id="4730374152663651037">VEELGEBRUIKT</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">APP-SUGGESTIES</translation> <translation id="6364916375976753737">Naar links bladeren</translation> <translation id="6394627529324717982">Komma</translation> +<translation id="6397363302884558537">Inspreken stoppen</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 sec. geleden}other{# sec. geleden}}</translation> +<translation id="6430678249303439055">Alle meldingen van deze app blokkeren</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 seconde geleden}other{# seconden geleden}}</translation> <translation id="654149438358937226">Alle meldingen blokkeren</translation> <translation id="6567071839949112727">klik via bovenliggende entiteit</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Nog 1 jaar}other{Nog # jaar}}</translation> <translation id="6945221475159498467">Selecteren</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Rechts naar links</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MEEST WAARSCHIJNLIJK</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Linkerzijde</translation> <translation id="8331626408530291785">Omhoog bladeren</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 jaar}other{# jaar}}</translation> -<translation id="8371695176452482769">Begin nu te spreken</translation> <translation id="838869780401515933">Selecteren</translation> <translation id="8393700583063109961">Bericht verzenden</translation> <translation id="8394908167088220973">Media afspelen/onderbreken</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+ nog <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Gereed</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 u}other{# u}}</translation> +<translation id="8798099450830957504">Standaard</translation> <translation id="8806053966018712535">Map <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Afbeelding annoteren</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_no.xtb b/chromium/ui/strings/translations/ui_strings_no.xtb index 335b9ce37a3..75a5e61eab4 100644 --- a/chromium/ui/strings/translations/ui_strings_no.xtb +++ b/chromium/ui/strings/translations/ui_strings_no.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Last opp</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ANBEFALTE APPER</translation> +<translation id="1368832886055348810">Venstre til høyre</translation> <translation id="1398853756734560583">Maksimer</translation> <translation id="1413622004203049571">Deaktiver varsler fra <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minutt og }other{# minutter og }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Stjernerangering <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 time og }other{# timer og }}</translation> <translation id="1842960171412779397">velg</translation> +<translation id="1859234291848436338">Skriveretning</translation> <translation id="1860796786778352021">Lukk varsel</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Opp 1 s.</translation> <translation id="2190355936436201913">(tom)</translation> <translation id="219905428774326614">Appoversikt, alle apper</translation> +<translation id="2267918077332197517">Blokkér alle varsler fra dette nettstedet</translation> <translation id="2289052229480071835">Trykk på berøringsmålene på skjermen.</translation> <translation id="2295140143284145483">Undersøkelse</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB per sek</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Rull hit</translation> <translation id="3234408098842461169">Pil ned</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dager}}</translation> +<translation id="335581015389089642">Tale</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 dag igjen}other{# dager igjen}}</translation> +<translation id="3618849550573277856">Slå opp «<ph name="LOOKUP_STRING" />»</translation> <translation id="364720409959344976">Velg mappen du vil laste opp</translation> <translation id="3660179305079774227">Pil opp</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB per sek</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">hopp</translation> <translation id="4250229828105606438">Skjermdump</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{for 1 måned siden}other{for # måneder siden}}</translation> +<translation id="4289300219472526559">Begynn å snakke</translation> <translation id="4316910396681052118">ALLE APPER</translation> -<translation id="4320177379694898372">Ingen Internett-tilkobling</translation> <translation id="4588090240171750605">Rull mot høyre</translation> <translation id="4724120544754982507">Varselsenter, <ph name="UNREAD_NOTIFICATION_COUNT" /> uleste varsler</translation> <translation id="4730374152663651037">OFTE BRUKT</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">APPFORSLAG</translation> <translation id="6364916375976753737">Rull mot venstre</translation> <translation id="6394627529324717982">Komma</translation> +<translation id="6397363302884558537">Stopp å snakke</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{For 1 sekund siden}other{For # sekunder siden}}</translation> +<translation id="6430678249303439055">Blokkér alle varsler fra denne appen</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{for 1 sekund siden}other{for # sekunder siden}}</translation> <translation id="654149438358937226">Blokkér alle varsler</translation> <translation id="6567071839949112727">klikk på et overordnet element</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 år igjen}other{# år igjen}}</translation> <translation id="6945221475159498467">Velg</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Høyre til venstre</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MEST SANNSYNLIG</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Venstre kant</translation> <translation id="8331626408530291785">Rull opp</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 år}other{# år}}</translation> -<translation id="8371695176452482769">Snakk nå</translation> <translation id="838869780401515933">merk av</translation> <translation id="8393700583063109961">Send melding</translation> <translation id="8394908167088220973">Media – spill av / pause</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+ <ph name="NUMBER" /> til</translation> <translation id="8730621377337864115">Ferdig</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 t}other{# t}}</translation> +<translation id="8798099450830957504">Standard</translation> <translation id="8806053966018712535">Mappen <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Kommenter bildet</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_pl.xtb b/chromium/ui/strings/translations/ui_strings_pl.xtb index 0a1002e79a7..122dabf9eaa 100644 --- a/chromium/ui/strings/translations/ui_strings_pl.xtb +++ b/chromium/ui/strings/translations/ui_strings_pl.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Prześlij</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">POLECANE APLIKACJE</translation> +<translation id="1368832886055348810">Od lewej do prawej</translation> <translation id="1398853756734560583">Maksymalizuj</translation> <translation id="1413622004203049571">Wyłącz powiadomienia z <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuta i }few{# minuty i }many{# minut i }other{# minuty i }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Ocena w gwiazdkach: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 godzina i }few{# godziny i }many{# godzin i }other{# godziny i }}</translation> <translation id="1842960171412779397">wybierz</translation> +<translation id="1859234291848436338">Kierunek pisania</translation> <translation id="1860796786778352021">Zamknięcie powiadomienia</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Strona do góry</translation> <translation id="2190355936436201913">(puste)</translation> <translation id="219905428774326614">Menu ze wszystkimi aplikacjami</translation> +<translation id="2267918077332197517">Blokuj wszystkie powiadomienia z tej strony internetowej</translation> <translation id="2289052229480071835">Kliknij docelowe obszary kliknięcia na ekranie.</translation> <translation id="2295140143284145483">Ankieta</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Przewiń tutaj</translation> <translation id="3234408098842461169">Strzałka w dół</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dzień}few{# dni}many{# dni}other{# dnia}}</translation> +<translation id="335581015389089642">Mowa</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Pozostał 1 dzień}few{Pozostały # dni}many{Pozostało # dni}other{Pozostało # dnia}}</translation> +<translation id="3618849550573277856">Sprawdź słowo „<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Wybierz folder do przesłania</translation> <translation id="3660179305079774227">Strzałka w górę</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">przejdź</translation> <translation id="4250229828105606438">Zrzut ekranu</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{miesiąc temu}few{# miesiące temu}many{# miesięcy temu}other{# miesiąca temu}}</translation> +<translation id="4289300219472526559">Zacznij mówić</translation> <translation id="4316910396681052118">WSZYSTKIE APLIKACJE</translation> -<translation id="4320177379694898372">Brak połączenia z internetem</translation> <translation id="4588090240171750605">Przewiń w prawo</translation> <translation id="4724120544754982507">Centrum powiadomień, liczba nieprzeczytanych powiadomień: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">CZĘSTO UŻYWANE</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGEROWANE APLIKACJE</translation> <translation id="6364916375976753737">Przewiń w lewo</translation> <translation id="6394627529324717982">Przecinek</translation> +<translation id="6397363302884558537">Przestań mówić</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 s temu}few{# s temu}many{# s temu}other{# s temu}}</translation> +<translation id="6430678249303439055">Blokuj wszystkie powiadomienia z tej aplikacji</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{sekundę temu}few{# sekundy temu}many{# sekund temu}other{# sekundy temu}}</translation> <translation id="654149438358937226">Blokuj wszystkie powiadomienia</translation> <translation id="6567071839949112727">kliknij element nadrzędny</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Pozostał rok}few{Pozostały # lata}many{Pozostało # lat}other{Pozostało # roku}}</translation> <translation id="6945221475159498467">Wybierz</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Od prawej do lewej</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">NAJBARDZIEJ PRAWDOPODOBNE</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Krawędź po lewej</translation> <translation id="8331626408530291785">Przewiń w górę</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 rok}few{# lata}many{# lat}other{# roku}}</translation> -<translation id="8371695176452482769">Mów teraz</translation> <translation id="838869780401515933">zaznacz</translation> <translation id="8393700583063109961">Wyślij wiadomość</translation> <translation id="8394908167088220973">Odtwórz/wstrzymaj multimedia</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">i jeszcze <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Gotowe</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 godz.}few{# godz.}many{# godz.}other{# godz.}}</translation> +<translation id="8798099450830957504">Domyślny</translation> <translation id="8806053966018712535">Folder <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Dodaj notatkę na grafice</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb index 30cc147fc77..b6921f06ef2 100644 --- a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb +++ b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Fazer upload</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APPS RECOMENDADOS</translation> +<translation id="1368832886055348810">Da esquerda para a direita</translation> <translation id="1398853756734560583">Maximizar</translation> <translation id="1413622004203049571">Desativar notificações de <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{Um minuto e }one{# minutos e }other{# minutos e }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Avaliação com <ph name="RATING_SCORE" /> estrelas</translation> <translation id="1830179671306812954">{HOURS,plural, =1{Uma hora e }one{# horas e }other{# horas e }}</translation> <translation id="1842960171412779397">selecione</translation> +<translation id="1859234291848436338">Direção de Gravação</translation> <translation id="1860796786778352021">Fechar notificação</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Página para cima</translation> <translation id="2190355936436201913">(vazio)</translation> <translation id="219905428774326614">Tela de início, todos os apps</translation> +<translation id="2267918077332197517">Bloquear todas as notificações emitidas por este site</translation> <translation id="2289052229480071835">Toque nas áreas de toque da tela.</translation> <translation id="2295140143284145483">Pesquisa</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Percorrer até aqui</translation> <translation id="3234408098842461169">Seta para baixo</translation> <translation id="3291688615589870984">{DAYS,plural, =1{Um dia}one{# dias}other{# dias}}</translation> +<translation id="335581015389089642">Voz</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Um dia restante}one{# dias restantes}other{# dias restantes}}</translation> +<translation id="3618849550573277856">Pesquisar “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Selecionar pasta para upload</translation> <translation id="3660179305079774227">Seta para cima</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">pular</translation> <translation id="4250229828105606438">Captura de tela</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 mês atrás}one{# mês atrás}other{# meses atrás}}</translation> +<translation id="4289300219472526559">Comece a falar</translation> <translation id="4316910396681052118">TODOS OS APPS</translation> -<translation id="4320177379694898372">Sem conexão com a Internet</translation> <translation id="4588090240171750605">Percorrer à direita</translation> <translation id="4724120544754982507">Central de Notificações: <ph name="UNREAD_NOTIFICATION_COUNT" /> notificações não lidas</translation> <translation id="4730374152663651037">USADOS FREQUENTEMENTE</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGESTÕES DE APPS</translation> <translation id="6364916375976753737">Percorrer à esquerda</translation> <translation id="6394627529324717982">Vírgula</translation> +<translation id="6397363302884558537">Pare de falar</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Um segundo atrás}one{# segundos atrás}other{# segundos atrás}}</translation> +<translation id="6430678249303439055">Bloquear todas as notificações emitidas por este app</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 segundo atrás}one{# segundo atrás}other{# segundos atrás}}</translation> <translation id="654149438358937226">Bloquear todas as notificações</translation> <translation id="6567071839949112727">clicar no predecessor</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 ano restante}one{# ano restante}other{# anos restantes}}</translation> <translation id="6945221475159498467">Selecionar</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Da direita para a esquerda</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MUITO PROVAVELMENTE</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Borda esquerda</translation> <translation id="8331626408530291785">Percorrer para cima</translation> <translation id="8352146631962686268">{YEARS,plural, =1{ ano}one{# ano}other{# anos}}</translation> -<translation id="8371695176452482769">Fale agora</translation> <translation id="838869780401515933">marcar</translation> <translation id="8393700583063109961">Enviar mensagem</translation> <translation id="8394908167088220973">Reproduzir/pausar mídia</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">mais <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Concluído</translation> <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="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb index 3c8d2030360..161d2155cf8 100644 --- a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb +++ b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Carregar</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APLICAÇÕES RECOMENDADAS</translation> +<translation id="1368832886055348810">Da esquerda para a direita</translation> <translation id="1398853756734560583">Maximizar</translation> <translation id="1413622004203049571">Desativar notificações de <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minuto e }other{# minutos e }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Classificação de <ph name="RATING_SCORE" /> estrelas</translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 hora e }other{# horas e }}</translation> <translation id="1842960171412779397">seleccionar</translation> +<translation id="1859234291848436338">Direcção da escrita</translation> <translation id="1860796786778352021">Fechar notificação</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Página para cima</translation> <translation id="2190355936436201913">(vazio)</translation> <translation id="219905428774326614">Iniciador, todas as aplicações</translation> +<translation id="2267918077332197517">Bloquear todas as notificações deste site</translation> <translation id="2289052229480071835">Toque nos alvos de toque no ecrã.</translation> <translation id="2295140143284145483">Inquérito</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Deslocar-se para aqui</translation> <translation id="3234408098842461169">Seta para baixo</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dia}other{# dias}}</translation> +<translation id="335581015389089642">Voz</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 dia}other{Faltam # dias}}</translation> +<translation id="3618849550573277856">Procurar "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Selecionar Pasta a Carregar</translation> <translation id="3660179305079774227">Seta para cima</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">ir para</translation> <translation id="4250229828105606438">Captura de ecrã</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Há 1 mês}other{Há # meses}}</translation> +<translation id="4289300219472526559">Comece a Falar</translation> <translation id="4316910396681052118">TODAS AS APLICAÇÕES</translation> -<translation id="4320177379694898372">Sem ligação à Internet</translation> <translation id="4588090240171750605">Deslocar-se para a direita</translation> <translation id="4724120544754982507">Centro de notificações, <ph name="UNREAD_NOTIFICATION_COUNT" /> notificações não lidas</translation> <translation id="4730374152663651037">UTILIZADAS FREQUENTEMENTE</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGESTÕES DE APLICAÇÕES</translation> <translation id="6364916375976753737">Deslocar-se para a esquerda</translation> <translation id="6394627529324717982">Vírgula</translation> +<translation id="6397363302884558537">Pare de Falar</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Há 1 seg}other{Há # seg}}</translation> +<translation id="6430678249303439055">Bloquear todas as notificações desta aplicação</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Há 1 segundo}other{Há # segundos}}</translation> <translation id="654149438358937226">Bloquear todas as notificações</translation> <translation id="6567071839949112727">clicar no predecessor</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Falta 1 ano}other{Faltam # anos}}</translation> <translation id="6945221475159498467">Selecionar</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Da direita para a esquerda</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MUITO PROVAVELMENTE</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Margem esquerda</translation> <translation id="8331626408530291785">Deslocar-se para cima</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 ano}other{# anos}}</translation> -<translation id="8371695176452482769">Falar agora</translation> <translation id="838869780401515933">verificar</translation> <translation id="8393700583063109961">Enviar mensagem</translation> <translation id="8394908167088220973">Reproduzir/interromper multimédia</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /></translation> <translation id="8730621377337864115">Concluído</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}other{# h}}</translation> +<translation id="8798099450830957504">Predefinição</translation> <translation id="8806053966018712535">Pasta <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Anotar imagem</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ro.xtb b/chromium/ui/strings/translations/ui_strings_ro.xtb index 59c00398037..15f275f6fef 100644 --- a/chromium/ui/strings/translations/ui_strings_ro.xtb +++ b/chromium/ui/strings/translations/ui_strings_ro.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Încărcați</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">APLICAȚII RECOMANDATE</translation> +<translation id="1368832886055348810">De la stânga la dreapta</translation> <translation id="1398853756734560583">Maximizează</translation> <translation id="1413622004203049571">Dezactivați notificările de la <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{Un minut și }few{# minute și }other{# de minute și }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Evaluare cu stele: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{O oră și }few{# ore și }other{# de ore și }}</translation> <translation id="1842960171412779397">selectează</translation> +<translation id="1859234291848436338">Direcție de scriere</translation> <translation id="1860796786778352021">Buton de închidere a notificării</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">O pagină mai sus</translation> <translation id="2190355936436201913">(gol)</translation> <translation id="219905428774326614">Lansator, toate aplicațiile</translation> +<translation id="2267918077332197517">Blochează toate notificările de la acest site</translation> <translation id="2289052229480071835">Atinge țintele de atingere de pe ecran.</translation> <translation id="2295140143284145483">Sondaj</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Derulează până aici</translation> <translation id="3234408098842461169">Săgeată în jos</translation> <translation id="3291688615589870984">{DAYS,plural, =1{O zi}few{# zile}other{# de zile}}</translation> +<translation id="335581015389089642">Voce</translation> <translation id="3600566671520689681">{DAYS,plural, =1{O zi rămasă}few{# zile rămase}other{# de zile rămase}}</translation> +<translation id="3618849550573277856">Caută „<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Selectați un dosar de încărcat</translation> <translation id="3660179305079774227">Săgeată în sus</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">accesează</translation> <translation id="4250229828105606438">Captură de ecran</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Acum 1 lună}few{Acum # luni}other{Acum # de luni}}</translation> +<translation id="4289300219472526559">Începeți să vorbiți</translation> <translation id="4316910396681052118">TOATE APLICAȚIILE</translation> -<translation id="4320177379694898372">Fără conexiune la internet</translation> <translation id="4588090240171750605">Derulează spre dreapta</translation> <translation id="4724120544754982507">Centrul de notificări, <ph name="UNREAD_NOTIFICATION_COUNT" /> notificări necitite</translation> <translation id="4730374152663651037">FOLOSITE FRECVENT</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">SUGESTII DE APLICAȚII</translation> <translation id="6364916375976753737">Derulează spre stânga</translation> <translation id="6394627529324717982">Virgulă</translation> +<translation id="6397363302884558537">Opriți-vă din vorbit</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Acum o sec.}few{Acum # sec}other{Acum # sec}}</translation> +<translation id="6430678249303439055">Blochează toate notificările de la această aplicație</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Acum 1 secundă}few{Acum # secunde}other{Acum # de secunde}}</translation> <translation id="654149438358937226">Blochează toate notificările</translation> <translation id="6567071839949112727">dă clic pe predecesor</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 an rămas}few{# ani rămași}other{# de ani rămași}}</translation> <translation id="6945221475159498467">Selectează</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">De la dreapta la stânga</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">CEL MAI PROBABIL DE ACCESAT</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Marginea stângă</translation> <translation id="8331626408530291785">Derulează în sus</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 an}few{# ani}other{# de ani}}</translation> -<translation id="8371695176452482769">Rostește acum</translation> <translation id="838869780401515933">bifează</translation> <translation id="8393700583063109961">Trimite un mesaj</translation> <translation id="8394908167088220973">Redați/întrerupeți conținutul media</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">Peste <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Terminat</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}few{# h}other{# h}}</translation> +<translation id="8798099450830957504">Prestabilit</translation> <translation id="8806053966018712535">Dosarul <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Adnotează imaginea</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KO</translation> diff --git a/chromium/ui/strings/translations/ui_strings_ru.xtb b/chromium/ui/strings/translations/ui_strings_ru.xtb index 78fb522ae7e..b15eefc26da 100644 --- a/chromium/ui/strings/translations/ui_strings_ru.xtb +++ b/chromium/ui/strings/translations/ui_strings_ru.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Загрузить</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">РЕКОМЕНДУЕМЫЕ ПРИЛОЖЕНИЯ</translation> +<translation id="1368832886055348810">Слева направо</translation> <translation id="1398853756734560583">Развернуть</translation> <translation id="1413622004203049571">Отключить уведомления от <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 минута }one{# минута }few{# минуты }many{# минут }other{# минуты }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Оценка: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 час }one{# час }few{# часа }many{# часов }other{# часа }}</translation> <translation id="1842960171412779397">выбрать</translation> +<translation id="1859234291848436338">Направление письма</translation> <translation id="1860796786778352021">Закрыть уведомление</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Вверх</translation> <translation id="2190355936436201913">(пусто)</translation> <translation id="219905428774326614">Панель запуска, все приложения</translation> +<translation id="2267918077332197517">Блокировать все уведомления этого сайта</translation> <translation id="2289052229480071835">Коснитесь интерактивных элементов на экране.</translation> <translation id="2295140143284145483">Опрос</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> ТБ/с</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Прокрутить до этого места</translation> <translation id="3234408098842461169">Стрелка вниз</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 день}one{# день}few{# дня}many{# дней}other{# дня}}</translation> +<translation id="335581015389089642">Озвучить</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Остался 1 день}one{Остался # день}few{Осталось # дня}many{Осталось # дней}other{Осталось # дня}}</translation> +<translation id="3618849550573277856">Найти "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Выберите папку для загрузки</translation> <translation id="3660179305079774227">Стрелка вверх</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/с</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">перейти</translation> <translation id="4250229828105606438">Скриншот</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{месяц назад}one{# месяц назад}few{# месяца назад}many{# месяцев назад}other{# месяца назад}}</translation> +<translation id="4289300219472526559">Начать голосовой ввод</translation> <translation id="4316910396681052118">ВСЕ ПРИЛОЖЕНИЯ</translation> -<translation id="4320177379694898372">Нет подключения к Интернету</translation> <translation id="4588090240171750605">Прокрутка вправо</translation> <translation id="4724120544754982507">Центр уведомлений. Непрочитанных: <ph name="UNREAD_NOTIFICATION_COUNT" />.</translation> <translation id="4730374152663651037">ЧАСТО ИСПОЛЬЗУЕМЫЕ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ПРЕДЛАГАЕМЫЕ ПРИЛОЖЕНИЯ</translation> <translation id="6364916375976753737">Прокрутка влево</translation> <translation id="6394627529324717982">Запятая</translation> +<translation id="6397363302884558537">Прекратить голосовой ввод</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 сек. назад}one{# сек. назад}few{# сек. назад}many{# сек. назад}other{# сек. назад}}</translation> +<translation id="6430678249303439055">Блокировать все уведомления этого приложения</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{только что}one{# секунду назад}few{# секунды назад}many{# секунд назад}other{# секунды назад}}</translation> <translation id="654149438358937226">Блокировать все уведомления</translation> <translation id="6567071839949112727">нажмите на родительский элемент</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{остался 1 год}one{остался # год}few{осталось # года}many{осталось # лет}other{осталось # года}}</translation> <translation id="6945221475159498467">Выбрать</translation> <translation id="6965382102122355670">ОК</translation> +<translation id="6974053822202609517">Справа налево</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">САМЫЕ ПОДХОДЯЩИЕ</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Левый край</translation> <translation id="8331626408530291785">Прокрутка вверх</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 год}one{# год}few{# года}many{# лет}other{# года}}</translation> -<translation id="8371695176452482769">Говорите</translation> <translation id="838869780401515933">поставить галочку</translation> <translation id="8393700583063109961">Отправить сообщение</translation> <translation id="8394908167088220973">Воспроизведение/пауза</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">Ещё <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Готово</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 ч.}one{# ч.}few{# ч.}many{# ч.}other{# ч.}}</translation> +<translation id="8798099450830957504">По умолчанию</translation> <translation id="8806053966018712535">Папка <ph name="FOLDER_NAME" />.</translation> <translation id="883911313571074303">Добавить примечание к изображению</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> КБ</translation> diff --git a/chromium/ui/strings/translations/ui_strings_sk.xtb b/chromium/ui/strings/translations/ui_strings_sk.xtb index 200d6e56298..52a378f444e 100644 --- a/chromium/ui/strings/translations/ui_strings_sk.xtb +++ b/chromium/ui/strings/translations/ui_strings_sk.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Nahrať</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ODPORÚČANÉ APLIKÁCIE</translation> +<translation id="1368832886055348810">Zľava doprava</translation> <translation id="1398853756734560583">Maximalizovať</translation> <translation id="1413622004203049571">Zakázať upozornenia od <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minúta a }few{# minúty a }many{# minúty a }other{# minút a }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Hodnotenie: <ph name="RATING_SCORE" /> hviezd.</translation> <translation id="1830179671306812954">{HOURS,plural, =1{Pred 1 hodinou a }few{Pred # hodinami a }many{Pred # hodinou a }other{Pred # hodinami a }}</translation> <translation id="1842960171412779397">vybrať</translation> +<translation id="1859234291848436338">Smer písania</translation> <translation id="1860796786778352021">Zavrieť upozornenie</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Page Up</translation> <translation id="2190355936436201913">(prázdne)</translation> <translation id="219905428774326614">Spúšťač, všetky aplikácie</translation> +<translation id="2267918077332197517">Blokovať všetky upozornenia z tohto webu</translation> <translation id="2289052229480071835">Klepnite na dotykové ciele na obrazovke.</translation> <translation id="2295140143284145483">Prieskum</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Rolovať na toto miesto</translation> <translation id="3234408098842461169">Šípka nadol</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 deň}few{# dni}many{# dňa}other{# dní}}</translation> +<translation id="335581015389089642">Reč</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Zostáva 1 deň}few{Zostávajú # dni}many{Zostáva # dňa}other{Zostáva # dní}}</translation> +<translation id="3618849550573277856">Vyhľadať „<ph name="LOOKUP_STRING" />“</translation> <translation id="364720409959344976">Výber priečinka na nahranie</translation> <translation id="3660179305079774227">Šípka nahor</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">skok</translation> <translation id="4250229828105606438">Snímka obrazovky</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{pred mesiacom}few{pred # mesiacmi}many{pred # mesiacom}other{pred # mesiacmi}}</translation> +<translation id="4289300219472526559">Začať hovoriť</translation> <translation id="4316910396681052118">VŠETKY APLIKÁCIE</translation> -<translation id="4320177379694898372">Žiadne internetové pripojenie</translation> <translation id="4588090240171750605">Rolovať doprava</translation> <translation id="4724120544754982507">Centrum upozornení – počet neprečítaných upozornení: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">ČASTO POUŽÍVANÉ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">NÁVRHY APLIKÁCIÍ</translation> <translation id="6364916375976753737">Rolovať doľava</translation> <translation id="6394627529324717982">Čiarka</translation> +<translation id="6397363302884558537">Prestať hovoriť</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Pred 1 s}few{Pred # s}many{Pred # s}other{Pred # s}}</translation> +<translation id="6430678249303439055">Blokovať všetky upozornenia z tejto aplikácie</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{pred sekundou}few{pred # sekundami}many{pred # sekundami}other{pred # sekundami}}</translation> <translation id="654149438358937226">Blokovať všetky upozornenia</translation> <translation id="6567071839949112727">kliknúť na nadradený objekt</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{zostáva 1 rok}few{zostávajú # roky}many{zostáva # roka}other{zostáva # rokov}}</translation> <translation id="6945221475159498467">Vybrať</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Sprava doľava</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">S NAJVÄČŠOU PRAVDEPODOBNOSŤOU</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Ľavý okraj</translation> <translation id="8331626408530291785">Rolovať nahor</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 rok}few{# roky}many{# roka}other{# rokov}}</translation> -<translation id="8371695176452482769">Hovorte…</translation> <translation id="838869780401515933">označiť</translation> <translation id="8393700583063109961">Odoslať správu</translation> <translation id="8394908167088220973">Média – prehrať / pozastaviť</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">ďalšie (<ph name="NUMBER" />)</translation> <translation id="8730621377337864115">Hotovo</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 h}few{# h}many{# h}other{# h}}</translation> +<translation id="8798099450830957504">Predvolené</translation> <translation id="8806053966018712535">Priečinok <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Pridať k obrázku poznámku</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_sl.xtb b/chromium/ui/strings/translations/ui_strings_sl.xtb index d3718284bf4..9b23c7aee33 100644 --- a/chromium/ui/strings/translations/ui_strings_sl.xtb +++ b/chromium/ui/strings/translations/ui_strings_sl.xtb @@ -7,6 +7,7 @@ <translation id="1243314992276662751">Prenesi</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">PRIPOROČENE APLIKACIJE</translation> +<translation id="1368832886055348810">Od leve proti desni</translation> <translation id="1398853756734560583">Povečaj</translation> <translation id="1413622004203049571">Izklop obvestil za <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 min in }one{# min in }two{# min in }few{# min in }other{# min in }}</translation> @@ -19,6 +20,7 @@ <translation id="1812519734428420144">Ocena z zvezdicami (<ph name="RATING_SCORE" />)</translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 h in }one{# h in }two{# h in }few{# h in }other{# h in }}</translation> <translation id="1842960171412779397">izberi</translation> +<translation id="1859234291848436338">Smer pisanja</translation> <translation id="1860796786778352021">Zapri obvestilo</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1901303067676059328">Izberi &vse</translation> @@ -26,6 +28,7 @@ <translation id="2168039046890040389">Stran gor</translation> <translation id="2190355936436201913">(prazno)</translation> <translation id="219905428774326614">Zaganjalnik, vse aplikacije</translation> +<translation id="2267918077332197517">Blokiraj vsa obvestila s tega spletnega mesta</translation> <translation id="2289052229480071835">Dotaknite se ciljev za dotik na zaslonu.</translation> <translation id="2295140143284145483">Anketa</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -46,7 +49,9 @@ <translation id="3183922693828471536">Pomik do sem</translation> <translation id="3234408098842461169">Puščica dol</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dan}one{# dan}two{# dneva}few{# dni}other{# dni}}</translation> +<translation id="335581015389089642">Speech</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Še 1 dan}one{Še # dan}two{Še # dneva}few{Še # dni}other{Še # dni}}</translation> +<translation id="3618849550573277856">Poišči »<ph name="LOOKUP_STRING" />«</translation> <translation id="364720409959344976">Izberite mapo, ki jo želite prenesti</translation> <translation id="3660179305079774227">Puščica gor</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -59,8 +64,8 @@ <translation id="4202807286478387388">skoči</translation> <translation id="4250229828105606438">Posnetek zaslona</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Pred 1 mesecem}one{Pred # mesecem}two{Pred # mesecema}few{Pred # meseci}other{Pred # meseci}}</translation> +<translation id="4289300219472526559">Start Speaking</translation> <translation id="4316910396681052118">VSE APLIKACIJE</translation> -<translation id="4320177379694898372">Ni internetne povezave</translation> <translation id="4588090240171750605">Pomik desno</translation> <translation id="4724120544754982507">Središče za obvestila, št. neprebranih sporočil: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">POGOSTO UPORABLJENE</translation> @@ -96,7 +101,9 @@ <translation id="6351032674660237738">PREDLOGI ZA APLIKACIJE</translation> <translation id="6364916375976753737">Pomik levo</translation> <translation id="6394627529324717982">Vejica</translation> +<translation id="6397363302884558537">Stop Speaking</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Pred 1 s}one{Pred # s}two{Pred # s}few{Pred # s}other{Pred # s}}</translation> +<translation id="6430678249303439055">Blokiraj vsa obvestila iz te aplikacije</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Pred 1 sekundo}one{Pred # sekundo}two{Pred # sekundama}few{Pred # sekundami}other{Pred # sekundami}}</translation> <translation id="654149438358937226">Blokiraj vsa obvestila</translation> <translation id="6567071839949112727">kliknite prednika</translation> @@ -113,6 +120,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Še 1 leto}one{Še # leto}two{Še # leti}few{Še # leta}other{Še # let}}</translation> <translation id="6945221475159498467">Izberi</translation> <translation id="6965382102122355670">V redu</translation> +<translation id="6974053822202609517">Od desne proti levi</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">NAJVERJETNEJŠE</translation> <translation id="7222373446505536781">F11</translation> @@ -135,7 +143,6 @@ <translation id="8328145009876646418">Levi rob</translation> <translation id="8331626408530291785">Pomik gor</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 leto}one{# leto}two{# leti}few{# leta}other{# let}}</translation> -<translation id="8371695176452482769">Začnite govoriti</translation> <translation id="838869780401515933">potrdi</translation> <translation id="8393700583063109961">Pošlji sporočilo</translation> <translation id="8394908167088220973">Ustavitev/začasna ustavitev</translation> @@ -143,6 +150,7 @@ <translation id="8602707065186045623">Datoteka <ph name="SAVEAS_EXTENSION_TYPE" /> (.<ph name="SAVEAS_EXTENSION_NAME" />)</translation> <translation id="8677655579646609597"><ph name="QUANTITY" /> KB/s</translation> <translation id="8730621377337864115">Končano</translation> +<translation id="8798099450830957504">Privzeto</translation> <translation id="8806053966018712535">Mapa <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Dodaj pripis sliki</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_sr.xtb b/chromium/ui/strings/translations/ui_strings_sr.xtb index c07a2f2a253..bee93c7b1a1 100644 --- a/chromium/ui/strings/translations/ui_strings_sr.xtb +++ b/chromium/ui/strings/translations/ui_strings_sr.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Отпреми</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ПРЕПОРУЧЕНЕ АПЛИКАЦИЈЕ</translation> +<translation id="1368832886055348810">Слева надесно</translation> <translation id="1398853756734560583">Увећај</translation> <translation id="1413622004203049571">Онемогући обавештења од <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 минут и }one{# минут и }few{# минута и }other{# минута и }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Оцена у звездицама: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 сат и }one{# сат и }few{# сата и }other{# сати и }}</translation> <translation id="1842960171412779397">изабери</translation> +<translation id="1859234291848436338">Writing Direction (Смер писања)</translation> <translation id="1860796786778352021">Затвори обавештење</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Страница нагоре</translation> <translation id="2190355936436201913">(празно)</translation> <translation id="219905428774326614">Покретач, све апликације</translation> +<translation id="2267918077332197517">Блокирај сва обавештења са овог сајта</translation> <translation id="2289052229480071835">Додирните циљна поља за додир на екрану.</translation> <translation id="2295140143284145483">Анкета</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Помери се овде</translation> <translation id="3234408098842461169">Стрелица надоле</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 дан}one{# дан}few{# дана}other{# дана}}</translation> +<translation id="335581015389089642">Говор</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Још 1 дан}one{Још # дан}few{Још # дана}other{Још # дана}}</translation> +<translation id="3618849550573277856">Потражи „<ph name="LOOKUP_STRING" />“</translation> <translation id="364720409959344976">Избор директоријума за отпремање</translation> <translation id="3660179305079774227">Стрелица нагоре</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">прескочи</translation> <translation id="4250229828105606438">Снимак екрана</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Пре месец дана}one{Пре # месец}few{Пре # месеца}other{Пре # месеци}}</translation> +<translation id="4289300219472526559">Почните да говорите</translation> <translation id="4316910396681052118">СВЕ АПЛИКАЦИЈЕ</translation> -<translation id="4320177379694898372">Нема интернет везе</translation> <translation id="4588090240171750605">Помери надесно</translation> <translation id="4724120544754982507">Центар за обавештења, непрочитаних обавештења: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">ЧЕСТО КОРИШЋЕНЕ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ПРЕДЛОЗИ АПЛИКАЦИЈА</translation> <translation id="6364916375976753737">Помери налево</translation> <translation id="6394627529324717982">Зарез</translation> +<translation id="6397363302884558537">Престаните да говорите</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Пре 1 сек}one{Пре # сек}few{Пре # сек}other{Пре # сек}}</translation> +<translation id="6430678249303439055">Блокирај сва обавештења из ове апликације</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Пре 1 секунду}one{Пре # секунду}few{Пре # секунде}other{Пре # секунди}}</translation> <translation id="654149438358937226">Блокирај сва обавештења</translation> <translation id="6567071839949112727">кликните на претходни елемент</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Још 1 година}one{Још # година}few{Још # године}other{Још # година}}</translation> <translation id="6945221475159498467">Изабери</translation> <translation id="6965382102122355670">Потврди</translation> +<translation id="6974053822202609517">Здесна налево</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">НАЈВЕРОВАТНИЈЕ</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Лева ивица</translation> <translation id="8331626408530291785">Помери нагоре</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 година}one{# година}few{# године}other{# година}}</translation> -<translation id="8371695176452482769">Почните да говорите</translation> <translation id="838869780401515933">изабери</translation> <translation id="8393700583063109961">Пошаљите поруку</translation> <translation id="8394908167088220973">Пуштање/паузирање медија</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">и још <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Готово</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 с}one{# с}few{# с}other{# с}}</translation> +<translation id="8798099450830957504">Подразумевано</translation> <translation id="8806053966018712535">Директоријум <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Додај напомену у слику</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_sv.xtb b/chromium/ui/strings/translations/ui_strings_sv.xtb index 3d83c0af843..2dcdbb2375c 100644 --- a/chromium/ui/strings/translations/ui_strings_sv.xtb +++ b/chromium/ui/strings/translations/ui_strings_sv.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Ladda upp</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">REKOMMENDERADE APPAR</translation> +<translation id="1368832886055348810">Vänster till höger</translation> <translation id="1398853756734560583">Maximera</translation> <translation id="1413622004203049571">Inaktivera aviseringar från <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 minut och }other{# minuter och }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Betyg <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 timme och }other{# timmar och }}</translation> <translation id="1842960171412779397">välj</translation> +<translation id="1859234291848436338">Skrivriktning</translation> <translation id="1860796786778352021">Meddelande om stängning</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Page Up</translation> <translation id="2190355936436201913">(tom)</translation> <translation id="219905428774326614">Startprogram, alla appar</translation> +<translation id="2267918077332197517">Blockera alla aviseringar från den här webbplatsen</translation> <translation id="2289052229480071835">Tryck på tryckområdena på skärmen.</translation> <translation id="2295140143284145483">Enkät</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/sek</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Rulla hit</translation> <translation id="3234408098842461169">Nedpil</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dagar}}</translation> +<translation id="335581015389089642">Tal</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 dag kvar}other{# dagar kvar}}</translation> +<translation id="3618849550573277856">Sök efter ”<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Välj en mapp för uppladdning</translation> <translation id="3660179305079774227">Uppil</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/sek</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">fortsätta</translation> <translation id="4250229828105606438">Skärmdump</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 månad sedan}other{# månader sedan}}</translation> +<translation id="4289300219472526559">Börja tala</translation> <translation id="4316910396681052118">ALLA APPAR</translation> -<translation id="4320177379694898372">Ingen internetanslutning</translation> <translation id="4588090240171750605">Rulla åt höger</translation> <translation id="4724120544754982507"><ph name="UNREAD_NOTIFICATION_COUNT" /> olästa aviseringar i meddelandecentret</translation> <translation id="4730374152663651037">OFTA ANVÄNDA</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">APPFÖRSLAG</translation> <translation id="6364916375976753737">Rulla åt vänster</translation> <translation id="6394627529324717982">Komma</translation> +<translation id="6397363302884558537">Sluta tala</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{för 1 sek sedan}other{för # sek sedan}}</translation> +<translation id="6430678249303439055">Blockera alla aviseringar från den här appen</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 sekund sedan}other{# sekunder sedan}}</translation> <translation id="654149438358937226">Blockera alla aviseringar</translation> <translation id="6567071839949112727">klicka på det överordnade objektet</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 år kvar}other{# år kvar}}</translation> <translation id="6945221475159498467">Välj</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Höger till vänster</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">MEST TROLIGA</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Vänsterkant</translation> <translation id="8331626408530291785">Rulla uppåt</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 år}other{# år}}</translation> -<translation id="8371695176452482769">Prata nu</translation> <translation id="838869780401515933">kryssa för</translation> <translation id="8393700583063109961">Skicka meddelande</translation> <translation id="8394908167088220973">Spela upp/Pausa</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">och <ph name="NUMBER" /> till</translation> <translation id="8730621377337864115">Klart</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 tim}other{# tim}}</translation> +<translation id="8798099450830957504">Standard</translation> <translation id="8806053966018712535">Mappen <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Kommentera bild</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> kB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_sw.xtb b/chromium/ui/strings/translations/ui_strings_sw.xtb index 7d1ba36ef60..5cfc38c89f7 100644 --- a/chromium/ui/strings/translations/ui_strings_sw.xtb +++ b/chromium/ui/strings/translations/ui_strings_sw.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Pakia</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">PROGRAMU ZINAZOPENDEKEZWA</translation> +<translation id="1368832886055348810">Kushoto hadi Kulia</translation> <translation id="1398853756734560583">Tanua</translation> <translation id="1413622004203049571">Zima arifa kutoka <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{Dakika 1 na }other{Dakika # na }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Ukadiriaji wa nyota <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{Saa 1 na }other{Saa # na }}</translation> <translation id="1842960171412779397">chagua</translation> +<translation id="1859234291848436338">Mwelekeo wa Maandishi</translation> <translation id="1860796786778352021">Funga arifa</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Ukurasa mmoja juu</translation> <translation id="2190355936436201913">(tupu)</translation> <translation id="219905428774326614">Kifungua Programu, programu zote</translation> +<translation id="2267918077332197517">Zuia arifa zote kutoka tovuti hii</translation> <translation id="2289052229480071835">Gusa viashirio vya kugusa kwenye skrini yako.</translation> <translation id="2295140143284145483">Utafiti</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Sogeza Hadi Hapa</translation> <translation id="3234408098842461169">Mshale Chini</translation> <translation id="3291688615589870984">{DAYS,plural, =1{Siku 1}other{Siku #}}</translation> +<translation id="335581015389089642">Usemi</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Imesalia siku 1}other{Zimesalia siku #}}</translation> +<translation id="3618849550573277856">Angalia “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Chagua Folda ya Kupakia</translation> <translation id="3660179305079774227">Mshale Juu</translation> <translation id="3740362395218339114">GB/s <ph name="QUANTITY" /></translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">ruka</translation> <translation id="4250229828105606438">Picha ya skrini</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{Mwezi 1 uliopita}other{Miezi # iliyopita}}</translation> +<translation id="4289300219472526559">Anza Kuzungumza</translation> <translation id="4316910396681052118">PROGRAMU ZOTE</translation> -<translation id="4320177379694898372">Hakuna muunganisho wa intaneti</translation> <translation id="4588090240171750605">Sogeza Kulia</translation> <translation id="4724120544754982507">Kituo cha Arifa, arifa <ph name="UNREAD_NOTIFICATION_COUNT" /> ambazo hujasoma</translation> <translation id="4730374152663651037">ZINAZOTUMIKA SANA</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">MAPENDEKEZO YA PROGRAMU</translation> <translation id="6364916375976753737">Sogeza Kushoto</translation> <translation id="6394627529324717982">Koma</translation> +<translation id="6397363302884558537">Koma Kuongea</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{Sekunde 1 iliyopita}other{Sekunde # zilizopita}}</translation> +<translation id="6430678249303439055">Zuia arifa zote kutoka programu hii</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{Sekunde 1 iliyopita}other{Sekunde # zilizopita}}</translation> <translation id="654149438358937226">Zuia arifa zote</translation> <translation id="6567071839949112727">bofya kipengee</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Umesalia mwaka 1}other{Imesalia miaka #}}</translation> <translation id="6945221475159498467">Chagua</translation> <translation id="6965382102122355670">Sawa</translation> +<translation id="6974053822202609517">Kulia hadi Kushoto</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">UNAZOWEZA KUBOFYA SANA</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Ncha ya Kushoto</translation> <translation id="8331626408530291785">Sogeza Juu</translation> <translation id="8352146631962686268">{YEARS,plural, =1{Mwaka 1}other{Miaka #}}</translation> -<translation id="8371695176452482769">Ongea sasa</translation> <translation id="838869780401515933">chunguza</translation> <translation id="8393700583063109961">Tuma ujumbe</translation> <translation id="8394908167088220973">Cheza Media/Sitisha</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> zaidi</translation> <translation id="8730621377337864115">Nimemaliza</translation> <translation id="8772073294905169192">{HOURS,plural, =1{Saa 1}other{Saa #}}</translation> +<translation id="8798099450830957504">Chaguo Msingi</translation> <translation id="8806053966018712535">Folda ya <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Eleza kuhusu picha</translation> <translation id="8901569739625249689">KB <ph name="QUANTITY" /></translation> diff --git a/chromium/ui/strings/translations/ui_strings_ta.xtb b/chromium/ui/strings/translations/ui_strings_ta.xtb index 711a614e82a..66df98a941f 100644 --- a/chromium/ui/strings/translations/ui_strings_ta.xtb +++ b/chromium/ui/strings/translations/ui_strings_ta.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">பதிவேற்று</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">பரிந்துரைக்கப்படும் பயன்பாடுகள்</translation> +<translation id="1368832886055348810">இடமிருந்து வலம்</translation> <translation id="1398853756734560583">பெரிதாக்கு</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> இடமிருந்து வரும் அறிவிப்புகளை முடக்கு</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 நிமிடம், }other{# நிமிடங்கள், }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">நட்சத்திர மதிப்பீடு <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 மணிநேரம், }other{# மணிநேரம், }}</translation> <translation id="1842960171412779397">தேர்ந்தெடு</translation> +<translation id="1859234291848436338">எழுதும் திசை</translation> <translation id="1860796786778352021">அறிவிப்பை மூடு</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">பக்கத்தின் மேலே</translation> <translation id="2190355936436201913">(காலி)</translation> <translation id="219905428774326614">துவக்கி, எல்லாப் பயன்பாடுகளும்</translation> +<translation id="2267918077332197517">இந்தத் தளத்திலிருந்து எல்லா அறிவிப்புகளையும் தடு</translation> <translation id="2289052229480071835">உங்கள் திரையில் இருக்கும் தொடுவதற்கான இலக்கிடங்களைத் தட்டவும்.</translation> <translation id="2295140143284145483">கருத்துக்கணிப்பு</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> டெ.பை/வி</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">இங்கே உருட்டு</translation> <translation id="3234408098842461169">கீழ்நோக்கிய அம்பு</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 நாள்}other{# நாட்கள்}}</translation> +<translation id="335581015389089642">பேச்சு</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 நாள் உள்ளது}other{# நாட்கள் உள்ளன}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” எனத் தேடு</translation> <translation id="364720409959344976">பதிவேற்றுவதற்குக் கோப்புறையைத் தேர்ந்தெடு</translation> <translation id="3660179305079774227">மேல்நோக்கிய அம்பு</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> ஜி.பை/வி</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">தாவு</translation> <translation id="4250229828105606438">ஸ்கிரீன் ஷாட்</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 மாதத்திற்கு முன்}other{# மாதங்களுக்கு முன்}}</translation> +<translation id="4289300219472526559">பேச்சைத் தொடங்கு</translation> <translation id="4316910396681052118">எல்லாப் பயன்பாடுகளும்</translation> -<translation id="4320177379694898372">இணைய இணைப்பு இல்லை</translation> <translation id="4588090240171750605">வலப்புறம் உருட்டு</translation> <translation id="4724120544754982507">அறிவிப்பு மையம், <ph name="UNREAD_NOTIFICATION_COUNT" /> படிக்காத அறிவிப்புகள்</translation> <translation id="4730374152663651037">அடிக்கடிப் பயன்படுத்தியவை</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">பயன்பாட்டுப் பரிந்துரைகள்</translation> <translation id="6364916375976753737">இடப்புறம் உருட்டு</translation> <translation id="6394627529324717982">கமா</translation> +<translation id="6397363302884558537">பேச்சை நிறுத்து</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 நிமிடம் முன்பு}other{# நிமிடங்கள் முன்பு}}</translation> +<translation id="6430678249303439055">இந்தப் பயன்பாட்டிலிருந்து எல்லா அறிவிப்புகளையும் தடு</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 வினாடிக்கு முன்பு}other{# வினாடிகளுக்கு முன்பு}}</translation> <translation id="654149438358937226">எல்லா அறிவிப்புகளையும் தடு</translation> <translation id="6567071839949112727">ஆன்செஸ்டரைக் கிளிக் செய்</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 ஆண்டு உள்ளது}other{# ஆண்டுகள் உள்ளன}}</translation> <translation id="6945221475159498467">தேர்ந்தெடு</translation> <translation id="6965382102122355670">சரி</translation> +<translation id="6974053822202609517">வலமிருந்து இடம்</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">அதிகச் சாத்தியமுள்ளவை</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">இடதுபுற முனை</translation> <translation id="8331626408530291785">மேலே உருட்டு</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 ஆண்டு}other{# ஆண்டுகள்}}</translation> -<translation id="8371695176452482769">இப்போது பேசுக</translation> <translation id="838869780401515933">சரிபார்</translation> <translation id="8393700583063109961">செய்தி அனுப்பு</translation> <translation id="8394908167088220973">ஊடகத்தை இயக்கு/இடைநிறுத்து</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">மேலும் <ph name="NUMBER" /></translation> <translation id="8730621377337864115">முடிந்தது</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1ம}other{#ம}}</translation> +<translation id="8798099450830957504">இயல்புநிலை</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> கோப்புறை</translation> <translation id="883911313571074303">படத்தைக் குறிப்பிடு</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> கி.பை.</translation> diff --git a/chromium/ui/strings/translations/ui_strings_te.xtb b/chromium/ui/strings/translations/ui_strings_te.xtb index 0dfea8a7858..4e84a0122b2 100644 --- a/chromium/ui/strings/translations/ui_strings_te.xtb +++ b/chromium/ui/strings/translations/ui_strings_te.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">అప్లోడ్ చేయి</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">సిఫార్సు చేసిన యాప్లు</translation> +<translation id="1368832886055348810">ఎడమ నుండి కుడికి</translation> <translation id="1398853756734560583">గరిష్ఠీకరించు</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> నుండి వచ్చే నోటిఫికేషన్లను నిలిపివేయి</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 నిమిషం మరియు }other{# నిమిషాలు మరియు }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">నక్షత్ర రేటింగ్ <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 గంట మరియు }other{# గంటలు మరియు }}</translation> <translation id="1842960171412779397">ఎంచుకోండి</translation> +<translation id="1859234291848436338">వ్రాసే దిశ</translation> <translation id="1860796786778352021">నోటిఫికేషన్ను మూసివేయి</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">పేజీ పైకి</translation> <translation id="2190355936436201913">(ఖాళీ)</translation> <translation id="219905428774326614">లాంచర్, అన్ని యాప్లు</translation> +<translation id="2267918077332197517">ఈ సైట్ నుండి నోటిఫికేషన్లు అన్ని బ్లాక్ చేయండి</translation> <translation id="2289052229480071835">మీ స్క్రీన్పై ఉన్న స్పర్శ లక్ష్యాలను నొక్కండి.</translation> <translation id="2295140143284145483">సర్వే</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">ఇక్కడ స్క్రోల్ చెయ్యండి</translation> <translation id="3234408098842461169">క్రింది బాణం</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 రోజు}other{# రోజులు}}</translation> +<translation id="335581015389089642">ప్రసంగం</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 రోజు మిగిలి ఉంది}other{# రోజులు మిగిలి ఉన్నాయి}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />”ని వెతకండి</translation> <translation id="364720409959344976">అప్లోడ్ చేయడానికి ఫోల్డర్ని ఎంచుకోండి</translation> <translation id="3660179305079774227">ఎగువ బాణం</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">వెళ్ళు</translation> <translation id="4250229828105606438">స్క్రీన్షాట్</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 నెల క్రితం}other{# నెలల క్రితం}}</translation> +<translation id="4289300219472526559">మాట్లాడటాన్ని ప్రారంభించు</translation> <translation id="4316910396681052118">అన్ని అనువర్తనాలు</translation> -<translation id="4320177379694898372">ఇంటర్నెట్ కనెక్షన్ లేదు</translation> <translation id="4588090240171750605">కుడికి స్క్రోల్ చెయ్యి</translation> <translation id="4724120544754982507">నోటిఫికేషన్ కేంద్రం, <ph name="UNREAD_NOTIFICATION_COUNT" /> చదవని నోటిఫికేషన్లు</translation> <translation id="4730374152663651037">తరచుగా ఉపయోగించేవి</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">యాప్ సూచనలు</translation> <translation id="6364916375976753737">ఎడమకి స్క్రోల్ చేయి</translation> <translation id="6394627529324717982">కామా</translation> +<translation id="6397363302884558537">మాట్లాడటాన్ని ఆపివేయి</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 సెక. క్రితం}other{# సెక. క్రితం}}</translation> +<translation id="6430678249303439055">ఈ యాప్ నుండి నోటిఫికేషన్లు అన్ని బ్లాక్ చేయండి</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 సెకను క్రితం}other{# సెకన్ల క్రితం}}</translation> <translation id="654149438358937226">అన్ని నోటిఫికేషన్లను బ్లాక్ చేయి</translation> <translation id="6567071839949112727">క్లిక్ మూలకం</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 సంవత్సరం మిగిలి ఉంది}other{# సంవత్సరాలు మిగిలి ఉన్నాయి}}</translation> <translation id="6945221475159498467">ఎంచుకోండి</translation> <translation id="6965382102122355670">సరే</translation> +<translation id="6974053822202609517">కుడి నుండి ఎడమకు</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">అత్యంత ఇష్టపడేవి</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">ఎడమ హద్దు</translation> <translation id="8331626408530291785">పైకి స్క్రోల్ చెయ్యి</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 సంవత్సరం}other{# సంవత్సరాలు}}</translation> -<translation id="8371695176452482769">ఇప్పుడు మాట్లాడండి</translation> <translation id="838869780401515933">తనిఖీ చెయ్యి</translation> <translation id="8393700583063109961">సందేశాన్ని పంపండి</translation> <translation id="8394908167088220973">మీడియా ప్లే/పాజ్</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+ మరో <ph name="NUMBER" /></translation> <translation id="8730621377337864115">పూర్తయింది</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1గం}other{#గం}}</translation> +<translation id="8798099450830957504">డిఫాల్ట్</translation> <translation id="8806053966018712535">ఫోల్డర్ <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">చిత్రాన్ని అనులేఖించు</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_th.xtb b/chromium/ui/strings/translations/ui_strings_th.xtb index 484e557264f..7aa7da8ca72 100644 --- a/chromium/ui/strings/translations/ui_strings_th.xtb +++ b/chromium/ui/strings/translations/ui_strings_th.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">อัปโหลด</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">แอปแนะนำ</translation> +<translation id="1368832886055348810">ซ้ายไปขวา</translation> <translation id="1398853756734560583">ย่อ</translation> <translation id="1413622004203049571">ปิดการแจ้งเตือนจาก <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 นาทีกับอีก }other{# นาทีกับอีก }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">เริ่มให้คะแนน <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 ชั่วโมงกับอีก }other{# ชั่วโมงกับอีก }}</translation> <translation id="1842960171412779397">เลือก</translation> +<translation id="1859234291848436338">การเขียนเส้นทาง</translation> <translation id="1860796786778352021">ปิดการแจ้งเตือน</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">เลื่อนหน้าขึ้น</translation> <translation id="2190355936436201913">(ว่างเปล่า)</translation> <translation id="219905428774326614">Launcher, แอปทั้งหมด</translation> +<translation id="2267918077332197517">บล็อกการแจ้งเตือนทั้งหมดจากเว็บไซต์นี้</translation> <translation id="2289052229480071835">แตะเป้าหมายการสัมผัสในหน้าจอ</translation> <translation id="2295140143284145483">แบบสำรวจ</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/วินาที</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">เลื่อนมาที่นี่</translation> <translation id="3234408098842461169">ลูกศรลง</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 วัน}other{# วัน}}</translation> +<translation id="335581015389089642">คำพูด</translation> <translation id="3600566671520689681">{DAYS,plural, =1{เหลือ 1 วัน}other{เหลือ # วัน}}</translation> +<translation id="3618849550573277856">ค้นหา “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">เลือกโฟลเดอร์เพื่ออัปโหลด</translation> <translation id="3660179305079774227">ลูกศรขึ้น</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/วินาที</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">ข้าม</translation> <translation id="4250229828105606438">ภาพหน้าจอ</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 เดือนที่ผ่านมา}other{# เดือนที่ผ่านมา}}</translation> +<translation id="4289300219472526559">เริ่มพูด</translation> <translation id="4316910396681052118">แอปทั้งหมด</translation> -<translation id="4320177379694898372">ไม่มีการเชื่อมต่ออินเทอร์เน็ต</translation> <translation id="4588090240171750605">เลื่อนทางขวา</translation> <translation id="4724120544754982507">ศูนย์การแจ้งเตือนมีการแจ้งเตือนที่ยังไม่อ่าน <ph name="UNREAD_NOTIFICATION_COUNT" /> รายการ</translation> <translation id="4730374152663651037">แอปที่ใช้บ่อย</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">คำแนะนำเกี่ยวกับแอป</translation> <translation id="6364916375976753737">เลื่อนทางซ้าย</translation> <translation id="6394627529324717982">จุลภาค</translation> +<translation id="6397363302884558537">หยุดพูด</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 วินาทีที่ผ่านมา}other{# วินาทีที่ผ่านมา}}</translation> +<translation id="6430678249303439055">บล็อกการแจ้งเตือนทั้งหมดจากแอปนี้</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{ 1 วินาทีที่ผ่านมา}other{# วินาทีที่ผ่านมา}}</translation> <translation id="654149438358937226">บล็อกการแจ้งเตือนทั้งหมด</translation> <translation id="6567071839949112727">คลิกต้นตระกูล</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{เหลือ 1 ปี}other{เหลือ # ปี}}</translation> <translation id="6945221475159498467">เลือก</translation> <translation id="6965382102122355670">ตกลง</translation> +<translation id="6974053822202609517">ขวาไปซ้าย</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">น่าจะใช้มากที่สุด</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">ขอบซ้าย</translation> <translation id="8331626408530291785">เลื่อนขึ้น</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 ปี}other{# ปี}}</translation> -<translation id="8371695176452482769">เชิญพูดเลย</translation> <translation id="838869780401515933">ทำเครื่องหมาย</translation> <translation id="8393700583063109961">ส่งข้อความ</translation> <translation id="8394908167088220973">เล่น/หยุดสื่อชั่วคราว</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">และอีก <ph name="NUMBER" /> รายการ</translation> <translation id="8730621377337864115">เสร็จสิ้น</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 ชม.}other{# ชม.}}</translation> +<translation id="8798099450830957504">ค่าเริ่มต้น</translation> <translation id="8806053966018712535">โฟลเดอร์ <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">ใส่หมายเหตุในรูปภาพ</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_tr.xtb b/chromium/ui/strings/translations/ui_strings_tr.xtb index 6a12de1ae44..ff48f705d6d 100644 --- a/chromium/ui/strings/translations/ui_strings_tr.xtb +++ b/chromium/ui/strings/translations/ui_strings_tr.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Yükle</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">ÖNERİLEN UYGULAMALAR</translation> +<translation id="1368832886055348810">Soldan Sağa</translation> <translation id="1398853756734560583">Büyüt</translation> <translation id="1413622004203049571"><ph name="NOTIFIER_NAME" /> bildirimlerini devre dışı bırak</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 dakika ve }other{# dakika ve }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Yıldız puanı <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 saat }other{# saat ve }}</translation> <translation id="1842960171412779397">seç</translation> +<translation id="1859234291848436338">Yazma Yönü</translation> <translation id="1860796786778352021">Bildirimi kapat</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652">%<ph name="NUMBER" /></translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Page Up</translation> <translation id="2190355936436201913">(boş)</translation> <translation id="219905428774326614">Launcher, tüm uygulamalar</translation> +<translation id="2267918077332197517">Bu siteden gelen tüm bildirimleri engelle</translation> <translation id="2289052229480071835">Ekranınızda dokunma hedeflerine dokunun.</translation> <translation id="2295140143284145483">Anket</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/sn</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Buraya Kaydır</translation> <translation id="3234408098842461169">Aşağı Ok</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 gün}other{# gün}}</translation> +<translation id="335581015389089642">Konuşma</translation> <translation id="3600566671520689681">{DAYS,plural, =1{1 gün kaldı}other{# gün kaldı}}</translation> +<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” Araması Yap</translation> <translation id="364720409959344976">Yüklenecek Klasörü Seçin</translation> <translation id="3660179305079774227">Yukarı Ok</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/sn</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">git</translation> <translation id="4250229828105606438">Ekran görüntüsü</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 ay önce}other{# ay önce}}</translation> +<translation id="4289300219472526559">Konuşmaya Başla</translation> <translation id="4316910396681052118">TÜM UYGULAMALAR</translation> -<translation id="4320177379694898372">İnternet bağlantısı yok</translation> <translation id="4588090240171750605">Sağa Kaydır</translation> <translation id="4724120544754982507">Bildirim Merkezi, <ph name="UNREAD_NOTIFICATION_COUNT" /> okunmamış bildirim</translation> <translation id="4730374152663651037">SIK KULLANILANLAR</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">UYGULAMA ÖNERİLERİ</translation> <translation id="6364916375976753737">Sola Kaydır</translation> <translation id="6394627529324717982">Virgül</translation> +<translation id="6397363302884558537">Konuşmayı Durdur</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 sn. önce}other{# sn. önce}}</translation> +<translation id="6430678249303439055">Bu uygulamadan gelen tüm bildirimleri engelle</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 saniye önce}other{# saniye önce}}</translation> <translation id="654149438358937226">Tüm bildirimleri engelle</translation> <translation id="6567071839949112727">üst öğeyi tıkla</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{1 yıl kaldı}other{# yıl kaldı}}</translation> <translation id="6945221475159498467">Seç</translation> <translation id="6965382102122355670">Tamam</translation> +<translation id="6974053822202609517">Sağdan Sola</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">BÜYÜK İHTİMALLE</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Sol Kenar</translation> <translation id="8331626408530291785">Yukarı Kaydır</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 yıl}other{# yıl}}</translation> -<translation id="8371695176452482769">Şimdi konuşun</translation> <translation id="838869780401515933">işaretle</translation> <translation id="8393700583063109961">İleti gönder</translation> <translation id="8394908167088220973">Medyayı Oynat/Duraklat</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204"><ph name="NUMBER" /> öğe daha</translation> <translation id="8730621377337864115">Bitti</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 sa.}other{# sa.}}</translation> +<translation id="8798099450830957504">Varsayılan</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" /> klasörü</translation> <translation id="883911313571074303">Resme açıklama ekle</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_uk.xtb b/chromium/ui/strings/translations/ui_strings_uk.xtb index 21b70f1d44e..e470d44a019 100644 --- a/chromium/ui/strings/translations/ui_strings_uk.xtb +++ b/chromium/ui/strings/translations/ui_strings_uk.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">Завантажити</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">РЕКОМЕНДОВАНІ ПРОГРАМИ</translation> +<translation id="1368832886055348810">Зліва направо</translation> <translation id="1398853756734560583">Збільшити</translation> <translation id="1413622004203049571">Вимкнути сповіщення від <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 хвилина та }one{# хвилина та }few{# хвилини та }many{# хвилин і }other{# хвилини та }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Рейтинг у зірочках: <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 година та }one{# година та }few{# години та }many{# годин і }other{# години та }}</translation> <translation id="1842960171412779397">вибрати</translation> +<translation id="1859234291848436338">Напрямок письма</translation> <translation id="1860796786778352021">Закрити сповіщення</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" />%</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Сторінка вгору</translation> <translation id="2190355936436201913">(пусто)</translation> <translation id="219905428774326614">Панель запуску, усі додатки</translation> +<translation id="2267918077332197517">Блокувати всі сповіщення від цього сайту</translation> <translation id="2289052229480071835">Торкніться елементів для дотику на екрані.</translation> <translation id="2295140143284145483">Опитування</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> ТБ/сек.</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Прокрутка до цього місця</translation> <translation id="3234408098842461169">Курсор униз</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 день}one{# день}few{# дні}many{# днів}other{# дня}}</translation> +<translation id="335581015389089642">Speech</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Залишився 1 день}one{Залишився # день}few{Залишилося # дні}many{Залишилося # днів}other{Залишилося # дня}}</translation> +<translation id="3618849550573277856">Шукати "<ph name="LOOKUP_STRING" />"</translation> <translation id="364720409959344976">Виберіть папку для завантаження</translation> <translation id="3660179305079774227">Курсор угору</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> ГБ/сек.</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">перейти</translation> <translation id="4250229828105606438">Знімок екрана</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 місяць тому}one{# місяць тому}few{# місяці тому}many{# місяців тому}other{# місяця тому}}</translation> +<translation id="4289300219472526559">Start Speaking</translation> <translation id="4316910396681052118">УСІ ДОДАТКИ</translation> -<translation id="4320177379694898372">Немає з’єднання з Інтернетом</translation> <translation id="4588090240171750605">Прокрутка вправо</translation> <translation id="4724120544754982507">Центр сповіщень, непрочитаних сповіщень: <ph name="UNREAD_NOTIFICATION_COUNT" /></translation> <translation id="4730374152663651037">ЧАСТО ВИКОРИСТОВУЮТЬСЯ</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ПРОПОЗИЦІЇ ДОДАТКІВ</translation> <translation id="6364916375976753737">Прокрутка вліво</translation> <translation id="6394627529324717982">Кома</translation> +<translation id="6397363302884558537">Stop Speaking</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 с тому}one{# с тому}few{# с тому}many{# с тому}other{# с тому}}</translation> +<translation id="6430678249303439055">Блокувати всі сповіщення від цього додатка</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 секунду тому}one{# секунду тому}few{# секунди тому}many{# секунд тому}other{# секунди тому}}</translation> <translation id="654149438358937226">Блокувати всі сповіщення</translation> <translation id="6567071839949112727">натиснути предок</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Залишився 1 рік}one{Залишився # рік}few{Залишилося # роки}many{Залишилося # років}other{Залишилося # року}}</translation> <translation id="6945221475159498467">Вибрати</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Справа наліво</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">НАЙІМОВІРНІШЕ</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Лівий край</translation> <translation id="8331626408530291785">Прокрутка вгору</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 рік}one{# рік}few{# роки}many{# років}other{# року}}</translation> -<translation id="8371695176452482769">Диктуйте</translation> <translation id="838869780401515933">установити прапорець</translation> <translation id="8393700583063109961">Надіслати повідомлення</translation> <translation id="8394908167088220973">Відтворити чи призупинити</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">і ще <ph name="NUMBER" /></translation> <translation id="8730621377337864115">Готово</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 год}one{# год}few{# год}many{# год}other{# год}}</translation> +<translation id="8798099450830957504">За умовчанням</translation> <translation id="8806053966018712535">Папка <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Додати нотатку до зображення</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> КБ</translation> diff --git a/chromium/ui/strings/translations/ui_strings_vi.xtb b/chromium/ui/strings/translations/ui_strings_vi.xtb index c28f846e344..0278c309ae6 100644 --- a/chromium/ui/strings/translations/ui_strings_vi.xtb +++ b/chromium/ui/strings/translations/ui_strings_vi.xtb @@ -7,7 +7,8 @@ <translation id="1169783199079129864">{MINUTES,plural, =1{1 phút}other{# phút}}</translation> <translation id="1243314992276662751">Tải lên</translation> <translation id="1293699935367580298">Thoát</translation> -<translation id="1306549533752902673">ỨNG DỤNG ĐƯỢC ĐỀ XUẤT</translation> +<translation id="1306549533752902673">ỨNG DỤNG ĐỀ XUẤT</translation> +<translation id="1368832886055348810">Trái sang Phải</translation> <translation id="1398853756734560583">Phóng to</translation> <translation id="1413622004203049571">Tắt thông báo từ <ph name="NOTIFIER_NAME" /></translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 phút và }other{# phút và }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">Xếp hạng theo sao <ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 giờ và }other{# giờ và }}</translation> <translation id="1842960171412779397">chọn</translation> +<translation id="1859234291848436338">Hướng Ghi</translation> <translation id="1860796786778352021">Đóng thông báo</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">Page Up</translation> <translation id="2190355936436201913">(trống)</translation> <translation id="219905428774326614">Trình khởi chạy, tất cả ứng dụng</translation> +<translation id="2267918077332197517">Chặn tất cả thông báo từ trang web này</translation> <translation id="2289052229480071835">Nhấn vào các mục tiêu cảm ứng trên màn hình của bạn.</translation> <translation id="2295140143284145483">Khảo sát</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/giây</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">Cuộn tới Đây</translation> <translation id="3234408098842461169">Phím mũi tên Xuống</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 ngày}other{# ngày}}</translation> +<translation id="335581015389089642">Giọng nói</translation> <translation id="3600566671520689681">{DAYS,plural, =1{Còn 1 ngày}other{Còn # ngày}}</translation> +<translation id="3618849550573277856">Tra cứu “<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">Chọn thư mục để tải lên</translation> <translation id="3660179305079774227">Phím mũi tên Lên</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/giây</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">chuyển</translation> <translation id="4250229828105606438">Ảnh chụp màn hình</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 tháng trước}other{# tháng trước}}</translation> +<translation id="4289300219472526559">Bắt đầu nói</translation> <translation id="4316910396681052118">TẤT CẢ ỨNG DỤNG</translation> -<translation id="4320177379694898372">Không có kết nối Internet</translation> <translation id="4588090240171750605">Cuộn qua Phải</translation> <translation id="4724120544754982507">Trung tâm thông báo, <ph name="UNREAD_NOTIFICATION_COUNT" /> thông báo chưa đọc</translation> <translation id="4730374152663651037">SỬ DỤNG THƯỜNG XUYÊN</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">ĐỀ XUẤT ỨNG DỤNG</translation> <translation id="6364916375976753737">Cuộn qua Trái</translation> <translation id="6394627529324717982">Dấu phẩy</translation> +<translation id="6397363302884558537">Dừng nói</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 giây trước}other{# giây trước}}</translation> +<translation id="6430678249303439055">Chặn tất cả thông báo từ ứng dụng này</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 giây trước}other{# giây trước}}</translation> <translation id="654149438358937226">Chặn tất cả thông báo</translation> <translation id="6567071839949112727">nhấp vào đối tượng cấp trên</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{Còn 1 năm}other{Còn # năm}}</translation> <translation id="6945221475159498467">Chọn</translation> <translation id="6965382102122355670">OK</translation> +<translation id="6974053822202609517">Phải sang Trái</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">RẤT CÓ THỂ</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">Cạnh Bên trái</translation> <translation id="8331626408530291785">Cuộn Lên</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 năm}other{# năm}}</translation> -<translation id="8371695176452482769">Nói ngay bây giờ</translation> <translation id="838869780401515933">chọn</translation> <translation id="8393700583063109961">Gửi tin nhắn</translation> <translation id="8394908167088220973">Phát/Tạm dừng trình phát phương tiện</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+<ph name="NUMBER" /> mục khác</translation> <translation id="8730621377337864115">Hoàn tất</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 giờ}other{# giờ}}</translation> +<translation id="8798099450830957504">Mặc định</translation> <translation id="8806053966018712535">Thư mục <ph name="FOLDER_NAME" /></translation> <translation id="883911313571074303">Chú thích hình ảnh</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> @@ -161,7 +169,7 @@ <translation id="9044832324875206639">{SECONDS,plural, =1{1 giây}other{# giây}}</translation> <translation id="9059834730836941392">Thu gọn thông báo</translation> <translation id="9150735707954472829">Tab</translation> -<translation id="9161053988251441839">ỨNG DỤNG ĐƯỢC ĐỀ XUẤT</translation> +<translation id="9161053988251441839">ỨNG DỤNG ĐỀ XUẤT</translation> <translation id="9170848237812810038">H&oàn tác</translation> <translation id="932327136139879170">Trang chủ</translation> </translationbundle>
\ No newline at end of file diff --git a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb index 1a9de3d2d67..1dc0dbb27d5 100644 --- a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb +++ b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">上传</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">推荐的应用</translation> +<translation id="1368832886055348810">从左向右</translation> <translation id="1398853756734560583">最大化</translation> <translation id="1413622004203049571">停用来自“<ph name="NOTIFIER_NAME" />”的通知</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 分钟 }other{# 分钟 }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">星级:<ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 小时 }other{# 小时 }}</translation> <translation id="1842960171412779397">选中</translation> +<translation id="1859234291848436338">书写方向</translation> <translation id="1860796786778352021">关闭通知</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">向上翻页</translation> <translation id="2190355936436201913">(空)</translation> <translation id="219905428774326614">启动器,所有应用</translation> +<translation id="2267918077332197517">屏蔽来自此网站的所有通知</translation> <translation id="2289052229480071835">点按您屏幕上的触摸目标。</translation> <translation id="2295140143284145483">调查问卷</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation> @@ -50,7 +53,9 @@ <translation id="3183922693828471536">滚动到此处</translation> <translation id="3234408098842461169">向下箭头</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 天}other{# 天}}</translation> +<translation id="335581015389089642">语音</translation> <translation id="3600566671520689681">{DAYS,plural, =1{还剩 1 天}other{还剩 # 天}}</translation> +<translation id="3618849550573277856">查询“<ph name="LOOKUP_STRING" />”</translation> <translation id="364720409959344976">选择要上传的文件夹</translation> <translation id="3660179305079774227">向上箭头</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation> @@ -63,8 +68,8 @@ <translation id="4202807286478387388">略过</translation> <translation id="4250229828105606438">屏幕截图</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 个月前}other{# 个月前}}</translation> +<translation id="4289300219472526559">开始讲话</translation> <translation id="4316910396681052118">所有应用</translation> -<translation id="4320177379694898372">未连接到互联网</translation> <translation id="4588090240171750605">向右滚动</translation> <translation id="4724120544754982507">通知中心,<ph name="UNREAD_NOTIFICATION_COUNT" /> 条未读通知</translation> <translation id="4730374152663651037">常用应用</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">应用推荐</translation> <translation id="6364916375976753737">向左滚动</translation> <translation id="6394627529324717982">逗号</translation> +<translation id="6397363302884558537">停止讲话</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation> +<translation id="6430678249303439055">屏蔽来自此应用的所有通知</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation> <translation id="654149438358937226">屏蔽所有通知</translation> <translation id="6567071839949112727">点击祖先实体</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{还有 1 年的时间}other{还有 # 年的时间}}</translation> <translation id="6945221475159498467">选择</translation> <translation id="6965382102122355670">确定</translation> +<translation id="6974053822202609517">从右向左</translation> <translation id="7052633198403197513">F1</translation> <translation id="7130207228079676353">很可能会点击的应用</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">左边缘</translation> <translation id="8331626408530291785">向上滚动</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 年}other{# 年}}</translation> -<translation id="8371695176452482769">请开始说话</translation> <translation id="838869780401515933">选中</translation> <translation id="8393700583063109961">发送消息</translation> <translation id="8394908167088220973">媒体播放/暂停</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">+ 另外 <ph name="NUMBER" /> 项</translation> <translation id="8730621377337864115">完成</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 小时}other{# 小时}}</translation> +<translation id="8798099450830957504">默认</translation> <translation id="8806053966018712535">文件夹“<ph name="FOLDER_NAME" />”</translation> <translation id="883911313571074303">为图片添加注释</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb index 381cb4a5685..ad478c47f7b 100644 --- a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb +++ b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb @@ -8,6 +8,7 @@ <translation id="1243314992276662751">上傳</translation> <translation id="1293699935367580298">Esc</translation> <translation id="1306549533752902673">推薦應用程式</translation> +<translation id="1368832886055348810">由左至右</translation> <translation id="1398853756734560583">放到最大</translation> <translation id="1413622004203049571">停用「<ph name="NOTIFIER_NAME" />」的通知</translation> <translation id="1591184457164800433">{MINUTES,plural, =1{1 分鐘 }other{# 分鐘 }}</translation> @@ -21,6 +22,7 @@ <translation id="1812519734428420144">星級評等:<ph name="RATING_SCORE" /></translation> <translation id="1830179671306812954">{HOURS,plural, =1{1 小時 }other{# 小時 }}</translation> <translation id="1842960171412779397">選取</translation> +<translation id="1859234291848436338">文字方向</translation> <translation id="1860796786778352021">通知關閉</translation> <translation id="1871244248791675517">Ins</translation> <translation id="1884435127456172652"><ph name="NUMBER" /> %</translation> @@ -30,6 +32,7 @@ <translation id="2168039046890040389">向上翻頁</translation> <translation id="2190355936436201913">(空白)</translation> <translation id="219905428774326614">啟動器,所有應用程式</translation> +<translation id="2267918077332197517">一律封鎖來自這個網站的通知</translation> <translation id="2289052229480071835">輕觸畫面上的觸控目標。</translation> <translation id="2295140143284145483">問卷調查</translation> <translation id="2297836609126180313"><ph name="QUANTITY" /> TB/秒</translation> @@ -50,21 +53,23 @@ <translation id="3183922693828471536">捲動至此</translation> <translation id="3234408098842461169">向下鍵</translation> <translation id="3291688615589870984">{DAYS,plural, =1{1 天}other{# 天}}</translation> +<translation id="335581015389089642">語音</translation> <translation id="3600566671520689681">{DAYS,plural, =1{還剩 1 天}other{還剩 # 天}}</translation> +<translation id="3618849550573277856">查詢「<ph name="LOOKUP_STRING" />」</translation> <translation id="364720409959344976">選取要上傳的資料夾</translation> <translation id="3660179305079774227">向上鍵</translation> <translation id="3740362395218339114"><ph name="QUANTITY" /> GB/秒</translation> <translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation> <translation id="385051799172605136">返回</translation> <translation id="3889424535448813030">向右鍵</translation> -<translation id="3892641579809465218">内建顯示器</translation> +<translation id="3892641579809465218">內建顯示器</translation> <translation id="3909791450649380159">剪下(&T)</translation> <translation id="3990502903496589789">右邊緣</translation> <translation id="4202807286478387388">跳至另一頁</translation> <translation id="4250229828105606438">螢幕擷取畫面</translation> <translation id="4266252015790371705">{MONTHS,plural, =1{1 個月前}other{# 個月前}}</translation> +<translation id="4289300219472526559">Start Speaking</translation> <translation id="4316910396681052118">所有應用程式</translation> -<translation id="4320177379694898372">沒有網際網路連線</translation> <translation id="4588090240171750605">向右捲動</translation> <translation id="4724120544754982507">通知中心,<ph name="UNREAD_NOTIFICATION_COUNT" /> 則未讀通知</translation> <translation id="4730374152663651037">常用的應用程式</translation> @@ -102,7 +107,9 @@ <translation id="6351032674660237738">應用程式建議</translation> <translation id="6364916375976753737">向左捲動</translation> <translation id="6394627529324717982">逗號</translation> +<translation id="6397363302884558537">Stop Speaking</translation> <translation id="6404817160109697034">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation> +<translation id="6430678249303439055">一律封鎖來自這個應用程式的通知</translation> <translation id="6483402905448010557">{SECONDS,plural, =1{1 秒前}other{# 秒前}}</translation> <translation id="654149438358937226">封鎖所有通知</translation> <translation id="6567071839949112727">點選上層項目</translation> @@ -119,6 +126,7 @@ <translation id="6917971086528278418">{YEARS,plural, =1{還剩 1 年}other{還剩 # 年}}</translation> <translation id="6945221475159498467">選取</translation> <translation id="6965382102122355670">確定</translation> +<translation id="6974053822202609517">由右至左</translation> <translation id="7052633198403197513">F1 鍵</translation> <translation id="7130207228079676353">最有可能選擇的應用程式</translation> <translation id="7222373446505536781">F11</translation> @@ -142,7 +150,6 @@ <translation id="8328145009876646418">左邊緣</translation> <translation id="8331626408530291785">向上捲動</translation> <translation id="8352146631962686268">{YEARS,plural, =1{1 年}other{# 年}}</translation> -<translation id="8371695176452482769">請說話</translation> <translation id="838869780401515933">選取</translation> <translation id="8393700583063109961">傳送訊息</translation> <translation id="8394908167088220973">媒體播放/暫停</translation> @@ -153,6 +160,7 @@ <translation id="8725488761726303204">還有另外 <ph name="NUMBER" /> 個清單項目</translation> <translation id="8730621377337864115">完成</translation> <translation id="8772073294905169192">{HOURS,plural, =1{1 小時}other{# 小時}}</translation> +<translation id="8798099450830957504">預設</translation> <translation id="8806053966018712535"><ph name="FOLDER_NAME" />資料夾</translation> <translation id="883911313571074303">為圖片加註</translation> <translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation> diff --git a/chromium/ui/strings/ui_strings.grd b/chromium/ui/strings/ui_strings.grd index a58dd606522..3e0b41a4055 100644 --- a/chromium/ui/strings/ui_strings.grd +++ b/chromium/ui/strings/ui_strings.grd @@ -334,8 +334,37 @@ need to be translated for each locale.--> <message name="IDS_SELECT_UPLOAD_FOLDER_BUTTON_TITLE" desc="The name of the Select button in the folder selection dialog for uploading."> Upload </message> + + <!-- Edit::Speech submenu --> + <message name="IDS_SPEECH_MAC" desc="The Mac menu item for the 'Speech' submenu in the edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there."> + Speech + </message> + <message name="IDS_SPEECH_START_SPEAKING_MAC" desc="The Mac menu item for the 'Start Speaking' item from the 'Speech' submenu in edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there."> + Start Speaking + </message> + <message name="IDS_SPEECH_STOP_SPEAKING_MAC" desc="The Mac menu item for the 'Stop Speaking' item from the 'Speech' submenu in edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there."> + Stop Speaking + </message> + + <message name="IDS_CONTENT_CONTEXT_LOOK_UP" desc="The name of the 'Look Up “string”' item in the content area context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, right-click on the text entry area and use the translation from there."> + Look Up “<ph name="LOOKUP_STRING">$1<ex>orthogonal</ex></ph>” + </message> + </if> + <message name="IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU" desc="The name of the Writing Direction submenu in the content area context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, right-click on the text entry area and use the translation from there."> + Writing Direction + </message> + <message name="IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT" desc="The name of the 'default' item from the Writing Direction submenu in the content area context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, right-click on the text entry area and use the translation from there."> + Default + </message> + <message name="IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR" desc="The name of the 'Left to Right' item from the Writing Direction submenu in the content area context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, right-click on the text entry area and use the translation from there."> + Left to Right + </message> + <message name="IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL" desc="The name of the 'Right to Left' item from the Writing Direction submenu in the content area context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, right-click on the text entry area and use the translation from there."> + Right to Left + </message> + <!-- File chooser dialog default titles (only used on Linux) --> <message name="IDS_SELECT_FOLDER_DIALOG_TITLE" desc="The default title for the Select Folder file chooser dialog."> Select Folder @@ -652,7 +681,13 @@ need to be translated for each locale.--> <message name="IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST" desc="Phrase describing a time duration using years that is as short as possible, preferrably one character. Should be same as AndroidPlatform msgId 7848711145196397042. (frameworks/base/core/res/res/values/strings.xml:plurals:duration_years_shortest) [ICU Syntax]"> {YEARS, plural, =1 {1y} other {#y}} </message> - <message name="IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS" desc="The label for the radio button to block all the notifications from this notification origin."> + <message name="IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS_SITE" desc="The label for the radio button to block all the notifications from this notification origin."> + Block all notifications from this site + </message> + <message name="IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS_APP" desc="The label for the radio button to block all the notifications from this app."> + Block all notifications from this app + </message> + <message name="IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS" desc="The label for the radio button to block all the notifications."> Block all notifications </message> <message name="IDS_MESSAGE_CENTER_DONT_BLOCK_NOTIFICATIONS" desc="The label for the radio button to allow all the notifications from this notification origin."> @@ -719,12 +754,6 @@ need to be translated for each locale.--> <message name="IDS_APP_LIST_FOLDER_CLOSE_FOLDER_ACCESSIBILE_NAME" desc="The spoken feedback text for closing an app launcher folder"> Close folder </message> - <message name="IDS_APP_LIST_SPEECH_HINT_TEXT" desc="The text label in the speech recognition UI to ask the user to speak the search query"> - Speak now - </message> - <message name="IDS_APP_LIST_SPEECH_NETWORK_ERROR_HINT_TEXT" desc="The text label in the speech recognition UI to show the speech recognition can't start because of network error."> - No internet connection - </message> <message name="IDS_APP_LIST_EXPAND_BUTTON" desc="Tooltip for the button that expands the app list from suggested apps to a fullscreen view which shows all apps."> Expand to all apps </message> diff --git a/chromium/ui/touch_selection/longpress_drag_selector.cc b/chromium/ui/touch_selection/longpress_drag_selector.cc index fdc3221118a..df96825cf43 100644 --- a/chromium/ui/touch_selection/longpress_drag_selector.cc +++ b/chromium/ui/touch_selection/longpress_drag_selector.cc @@ -28,19 +28,19 @@ LongPressDragSelector::~LongPressDragSelector() { bool LongPressDragSelector::WillHandleTouchEvent(const MotionEvent& event) { switch (event.GetAction()) { - case MotionEvent::ACTION_DOWN: + case MotionEvent::Action::DOWN: touch_down_position_.SetPoint(event.GetX(), event.GetY()); touch_down_time_ = event.GetEventTime(); has_longpress_drag_start_anchor_ = false; SetState(LONGPRESS_PENDING); return false; - case MotionEvent::ACTION_UP: - case MotionEvent::ACTION_CANCEL: + case MotionEvent::Action::UP: + case MotionEvent::Action::CANCEL: SetState(INACTIVE); return false; - case MotionEvent::ACTION_MOVE: + case MotionEvent::Action::MOVE: break; default: diff --git a/chromium/ui/touch_selection/touch_handle.cc b/chromium/ui/touch_selection/touch_handle.cc index ee1c765d17e..65b1dba8e82 100644 --- a/chromium/ui/touch_selection/touch_handle.cc +++ b/chromium/ui/touch_selection/touch_handle.cc @@ -165,11 +165,11 @@ bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { if (!enabled_) return false; - if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) + if (!is_dragging_ && event.GetAction() != MotionEvent::Action::DOWN) return false; switch (event.GetAction()) { - case MotionEvent::ACTION_DOWN: { + case MotionEvent::Action::DOWN: { if (!is_visible_) return false; const gfx::PointF touch_point(event.GetX(), event.GetY()); @@ -191,7 +191,7 @@ bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { BeginDrag(); } break; - case MotionEvent::ACTION_MOVE: { + case MotionEvent::Action::MOVE: { gfx::PointF touch_move_position(event.GetX(), event.GetY()); is_drag_within_tap_region_ &= client_->IsWithinTapSlop(touch_down_position_ - touch_move_position); @@ -201,7 +201,7 @@ bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { client_->OnDragUpdate(*this, touch_move_position + touch_drag_offset_); } break; - case MotionEvent::ACTION_UP: { + case MotionEvent::Action::UP: { if (is_drag_within_tap_region_ && (event.GetEventTime() - touch_down_time_) < client_->GetMaxTapDuration()) { @@ -211,7 +211,7 @@ bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { EndDrag(); } break; - case MotionEvent::ACTION_CANCEL: + case MotionEvent::Action::CANCEL: EndDrag(); break; diff --git a/chromium/ui/touch_selection/touch_handle_unittest.cc b/chromium/ui/touch_selection/touch_handle_unittest.cc index 84c9db22b20..c723009d0f3 100644 --- a/chromium/ui/touch_selection/touch_handle_unittest.cc +++ b/chromium/ui/touch_selection/touch_handle_unittest.cc @@ -331,8 +331,8 @@ TEST_F(TouchHandleTest, Enabled) { // Dragging should not be allowed while the handle is disabled. base::TimeTicks event_time = base::TimeTicks::Now(); const float kOffset = kDefaultDrawableSize / 2.f; - MockMotionEvent event( - MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, kOffset, + kOffset); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); // Disabling mid-animation should cancel the animation. @@ -366,50 +366,51 @@ TEST_F(TouchHandleTest, Drag) { const float kOffset = kDefaultDrawableSize / 2.f; // The handle must be visible to trigger drag. - MockMotionEvent event( - MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, kOffset, + kOffset); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(IsDragging()); UpdateHandleVisibility(handle, true, TouchHandle::ANIMATION_NONE); - // ACTION_DOWN must fall within the drawable region to trigger drag. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 50, 50); + // Action::DOWN must fall within the drawable region to trigger drag. + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 50, 50); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(IsDragging()); - // Only ACTION_DOWN will trigger drag. - event = MockMotionEvent( - MockMotionEvent::ACTION_MOVE, event_time, kOffset, kOffset); + // Only Action::DOWN will trigger drag. + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, kOffset, + kOffset); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(IsDragging()); // Start the drag. - event = MockMotionEvent( - MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, kOffset, + kOffset); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(IsDragging()); - event = MockMotionEvent( - MockMotionEvent::ACTION_MOVE, event_time, kOffset + 10, kOffset + 15); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, + kOffset + 10, kOffset + 15); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetHandleDragged()); EXPECT_TRUE(IsDragging()); EXPECT_EQ(gfx::PointF(10, 15), DragPosition()); - event = MockMotionEvent( - MockMotionEvent::ACTION_MOVE, event_time, kOffset - 10, kOffset - 15); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, + kOffset - 10, kOffset - 15); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetHandleDragged()); EXPECT_TRUE(IsDragging()); EXPECT_EQ(gfx::PointF(-10, -15), DragPosition()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP); + event = MockMotionEvent(MockMotionEvent::Action::UP); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetHandleDragged()); EXPECT_FALSE(IsDragging()); - // Non-ACTION_DOWN events after the drag has terminated should not be handled. - event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL); + // Non-Action::DOWN events after the drag has terminated should not be + // handled. + event = MockMotionEvent(MockMotionEvent::Action::CANCEL); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); } @@ -418,7 +419,7 @@ TEST_F(TouchHandleTest, DragDefersOrientationChange) { ASSERT_EQ(drawable().orientation, TouchHandleOrientation::RIGHT); UpdateHandleVisibility(handle, true, TouchHandle::ANIMATION_NONE); - MockMotionEvent event(MockMotionEvent::ACTION_DOWN); + MockMotionEvent event(MockMotionEvent::Action::DOWN); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(IsDragging()); @@ -426,13 +427,13 @@ TEST_F(TouchHandleTest, DragDefersOrientationChange) { UpdateHandleOrientation(handle, TouchHandleOrientation::LEFT); EXPECT_EQ(TouchHandleOrientation::RIGHT, drawable().orientation); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE); + event = MockMotionEvent(MockMotionEvent::Action::MOVE); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetHandleDragged()); EXPECT_TRUE(IsDragging()); EXPECT_EQ(TouchHandleOrientation::RIGHT, drawable().orientation); - event = MockMotionEvent(MockMotionEvent::ACTION_UP); + event = MockMotionEvent(MockMotionEvent::Action::UP); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetHandleDragged()); EXPECT_FALSE(IsDragging()); @@ -444,7 +445,7 @@ TEST_F(TouchHandleTest, DragDefersFade) { kDefaultViewportRect); UpdateHandleVisibility(handle, true, TouchHandle::ANIMATION_NONE); - MockMotionEvent event(MockMotionEvent::ACTION_DOWN); + MockMotionEvent event(MockMotionEvent::Action::DOWN); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(IsDragging()); @@ -454,12 +455,12 @@ TEST_F(TouchHandleTest, DragDefersFade) { EXPECT_TRUE(drawable().visible); EXPECT_EQ(1.f, drawable().alpha); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE); + event = MockMotionEvent(MockMotionEvent::Action::MOVE); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(NeedsAnimate()); EXPECT_TRUE(drawable().visible); - event = MockMotionEvent(MockMotionEvent::ACTION_UP); + event = MockMotionEvent(MockMotionEvent::Action::UP); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(IsDragging()); EXPECT_TRUE(NeedsAnimate()); @@ -481,8 +482,7 @@ TEST_F(TouchHandleTest, DragTargettingUsesTouchSize) { const float kTouchSize = 24.f; const float kOffset = kDefaultDrawableSize + kTouchSize / 2.001f; - MockMotionEvent event( - MockMotionEvent::ACTION_DOWN, event_time, kOffset, 0); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, kOffset, 0); event.SetTouchMajor(0.f); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(IsDragging()); @@ -500,8 +500,8 @@ TEST_F(TouchHandleTest, DragTargettingUsesTouchSize) { EXPECT_TRUE(IsDragging()); // The touch hit test region should be circular. - event = MockMotionEvent( - MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, kOffset, + kOffset); event.SetTouchMajor(kTouchSize); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(IsDragging()); @@ -515,17 +515,16 @@ TEST_F(TouchHandleTest, DragTargettingUsesTouchSize) { EXPECT_TRUE(IsDragging()); // Ensure a touch size of 0 can still register a hit. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, - event_time, - kDefaultDrawableSize / 2.f, - kDefaultDrawableSize / 2.f); + event = + MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, + kDefaultDrawableSize / 2.f, kDefaultDrawableSize / 2.f); event.SetTouchMajor(0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(IsDragging()); // Touches centered above the handle region should never register a hit, even // if the touch region intersects the handle region. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, kDefaultDrawableSize / 2.f, -kTouchSize / 3.f); event.SetTouchMajor(kTouchSize); EXPECT_FALSE(handle.WillHandleTouchEvent(event)); @@ -539,43 +538,43 @@ TEST_F(TouchHandleTest, Tap) { base::TimeTicks event_time = base::TimeTicks::Now(); - // ACTION_CANCEL shouldn't trigger a tap. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + // Action::CANCEL shouldn't trigger a tap. + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); event_time += base::TimeDelta::FromMilliseconds(50); - event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::CANCEL, event_time, 0, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetHandleTapped()); // Long press shouldn't trigger a tap. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); event_time += 2 * GetMaxTapDuration(); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 0, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetHandleTapped()); // Only a brief tap within the slop region should trigger a tap. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); event_time += GetMaxTapDuration() / 2; - event = MockMotionEvent( - MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop / 2.f, 0); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, + kDefaultTapSlop / 2.f, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); - event = MockMotionEvent( - MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop / 2.f, 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, + kDefaultTapSlop / 2.f, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetHandleTapped()); // Moving beyond the slop region shouldn't trigger a tap. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); event_time += GetMaxTapDuration() / 2; - event = MockMotionEvent( - MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop * 2.f, 0); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, + kDefaultTapSlop * 2.f, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); - event = MockMotionEvent( - MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop * 2.f, 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, + kDefaultTapSlop * 2.f, 0); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetHandleTapped()); } @@ -639,7 +638,7 @@ TEST_F(TouchHandleTest, DragDefersMirrorChange) { const float kOffset = kDefaultDrawableSize / 2.f; // Start the drag. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, kOffset, + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, kOffset, kOffset); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_TRUE(IsDragging()); @@ -652,7 +651,7 @@ TEST_F(TouchHandleTest, DragDefersMirrorChange) { EXPECT_FALSE(drawable().mirror_horizontal); // Mirror flag changes will be deferred until the drag ends. - event = MockMotionEvent(MockMotionEvent::ACTION_UP); + event = MockMotionEvent(MockMotionEvent::Action::UP); EXPECT_TRUE(handle.WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetHandleDragged()); EXPECT_FALSE(IsDragging()); diff --git a/chromium/ui/touch_selection/touch_selection_controller.cc b/chromium/ui/touch_selection/touch_selection_controller.cc index 884ea9072bb..8ea5e0b5cac 100644 --- a/chromium/ui/touch_selection/touch_selection_controller.cc +++ b/chromium/ui/touch_selection/touch_selection_controller.cc @@ -88,12 +88,31 @@ void TouchSelectionController::OnSelectionBoundsChanged( // Swap the Handles when the start and end selection points cross each other. if (active_status_ == SELECTION_ACTIVE) { - if ((start_selection_handle_->IsActive() && - end_.edge_bottom() == start.edge_bottom()) || - (end_selection_handle_->IsActive() && - end.edge_bottom() == start_.edge_bottom())) { + // Bounds have the same orientation. + bool need_swap = (start_selection_handle_->IsActive() && + end_.edge_bottom() == start.edge_bottom()) || + (end_selection_handle_->IsActive() && + end.edge_bottom() == start_.edge_bottom()); + + // Bounds have different orientation. + // Specifically, for writing-mode: vertical-*, selection bounds are + // horizontal. + // When vertical-lr: + // - start bound is from right to left, + // - end bound is from left to right. + // When vertical-rl: + // - start bound is from left to right, + // - end bound is from right to left. + // So when previous start/end bound become current end/start bound, + // edge_top() and edge_bottom() are swapped. Therefore, we are comparing + // edge_bottom() with edge_top() here. + need_swap |= (start_selection_handle_->IsActive() && + end_.edge_bottom() == start.edge_top()) || + (end_selection_handle_->IsActive() && + end.edge_bottom() == start_.edge_top()); + + if (need_swap) start_selection_handle_.swap(end_selection_handle_); - } } start_ = start; @@ -153,13 +172,13 @@ void TouchSelectionController::OnViewportChanged( bool TouchSelectionController::WillHandleTouchEvent(const MotionEvent& event) { bool handled = WillHandleTouchEventImpl(event); - // If ACTION_DOWN is consumed, the rest of touch sequence should be consumed, + // If Action::DOWN is consumed, the rest of touch sequence should be consumed, // too, regardless of value of |handled|. - // TODO(mohsen): This will consume touch events until the next ACTION_DOWN. - // Ideally we should consume until the final ACTION_UP/ACTION_CANCEL. - // But, apparently, we can't reliably determine the final ACTION_CANCEL in a + // TODO(mohsen): This will consume touch events until the next Action::DOWN. + // Ideally we should consume until the final Action::UP/Action::CANCEL. + // But, apparently, we can't reliably determine the final Action::CANCEL in a // multi-touch scenario. See https://crbug.com/653212. - if (event.GetAction() == MotionEvent::ACTION_DOWN) + if (event.GetAction() == MotionEvent::Action::DOWN) consume_touch_sequence_ = handled; return handled || consume_touch_sequence_; } @@ -260,7 +279,7 @@ gfx::RectF TouchSelectionController::GetEndHandleRect() const { return gfx::RectF(); } -gfx::PointF TouchSelectionController::GetActiveHandleBoundPoint() const { +float TouchSelectionController::GetActiveHandleMiddleY() const { const gfx::SelectionBound* bound = nullptr; if (active_status_ == INSERTION_ACTIVE && insertion_handle_->IsActive()) bound = &start_; @@ -272,11 +291,8 @@ gfx::PointF TouchSelectionController::GetActiveHandleBoundPoint() const { } if (!bound) - return gfx::PointF(0.f, 0.f); - - float x = (bound->edge_top().x() + bound->edge_bottom().x()) / 2.f; - float y = (bound->edge_top().y() + bound->edge_bottom().y()) / 2.f; - return gfx::PointF(x, y); + return 0.f; + return (bound->edge_top().y() + bound->edge_bottom().y()) / 2.f; } const gfx::PointF& TouchSelectionController::GetStartPosition() const { @@ -372,6 +388,13 @@ void TouchSelectionController::OnDragUpdate( client_->MoveCaret(line_position); else client_->MoveRangeSelectionExtent(line_position); + + // We use the bound middle point to restrict the ability to move up and down, + // but let user move it more freely in horizontal direction. + if (&draggable != &longpress_drag_selector_) { + float y = GetActiveHandleMiddleY(); + client_->OnDragUpdate(gfx::PointF(drag_position.x(), y)); + } } void TouchSelectionController::OnDragEnd( diff --git a/chromium/ui/touch_selection/touch_selection_controller.h b/chromium/ui/touch_selection/touch_selection_controller.h index 6ec985cee00..2214024f7ef 100644 --- a/chromium/ui/touch_selection/touch_selection_controller.h +++ b/chromium/ui/touch_selection/touch_selection_controller.h @@ -33,6 +33,7 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionControllerClient { virtual void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) = 0; virtual void OnSelectionEvent(SelectionEventType event) = 0; + virtual void OnDragUpdate(const gfx::PointF& position) = 0; virtual std::unique_ptr<TouchHandleDrawable> CreateDrawable() = 0; virtual void DidScroll() = 0; }; @@ -120,10 +121,6 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionController gfx::RectF GetStartHandleRect() const; gfx::RectF GetEndHandleRect() const; - // Returns the middle point of selection bound corresponding to the active - // selection or insertion handle. If there is no active handle, returns (0,0). - gfx::PointF GetActiveHandleBoundPoint() const; - // Returns the focal point of the start and end bounds, as defined by // their bottom coordinate. const gfx::PointF& GetStartPosition() const; @@ -174,6 +171,11 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionController void SetTemporarilyHiddenForLongPressDrag(bool hidden); void RefreshHandleVisibility(); + // Returns the y-coordinate of middle point of selection bound corresponding + // to the active selection or insertion handle. If there is no active handle, + // returns 0.0. + float GetActiveHandleMiddleY() const; + void HideHandles(); gfx::Vector2dF GetStartLineOffset() const; diff --git a/chromium/ui/touch_selection/touch_selection_controller_unittest.cc b/chromium/ui/touch_selection/touch_selection_controller_unittest.cc index 0056940cdf0..d0bf65b32bc 100644 --- a/chromium/ui/touch_selection/touch_selection_controller_unittest.cc +++ b/chromium/ui/touch_selection/touch_selection_controller_unittest.cc @@ -100,7 +100,10 @@ class TouchSelectionControllerTest : public testing::Test, last_event_start_ = controller_->GetStartPosition(); last_event_end_ = controller_->GetEndPosition(); last_event_bounds_rect_ = controller_->GetRectBetweenBounds(); - last_event_handle_bound_middle_ = controller_->GetActiveHandleBoundPoint(); + } + + void OnDragUpdate(const gfx::PointF& position) override { + last_drag_update_position_ = position; } std::unique_ptr<TouchHandleDrawable> CreateDrawable() override { @@ -147,6 +150,20 @@ class TouchSelectionControllerTest : public testing::Test, controller_->OnSelectionBoundsChanged(start_bound, end_bound); } + void ChangeVerticalSelection(const gfx::RectF& start_rect, + bool start_visible, + const gfx::RectF& end_rect, + bool end_visible) { + gfx::SelectionBound start_bound, end_bound; + start_bound.set_type(gfx::SelectionBound::RIGHT); + end_bound.set_type(gfx::SelectionBound::LEFT); + start_bound.SetEdge(start_rect.origin(), start_rect.bottom_right()); + end_bound.SetEdge(end_rect.bottom_right(), end_rect.origin()); + start_bound.set_visible(start_visible); + end_bound.set_visible(end_visible); + controller_->OnSelectionBoundsChanged(start_bound, end_bound); + } + void OnLongPressEvent() { controller().HandleLongPressEvent(base::TimeTicks(), kIgnoredPoint); @@ -202,8 +219,8 @@ class TouchSelectionControllerTest : public testing::Test, const gfx::RectF& GetLastEventBoundsRect() const { return last_event_bounds_rect_; } - const gfx::PointF& GetLastEventHandleBoundMiddle() const { - return last_event_handle_bound_middle_; + const gfx::PointF& GetLastDragUpdatePosition() const { + return last_drag_update_position_; } std::vector<SelectionEventType> GetAndResetEvents() { @@ -232,7 +249,7 @@ class TouchSelectionControllerTest : public testing::Test, gfx::PointF selection_start_; gfx::PointF selection_end_; gfx::RectF last_event_bounds_rect_; - gfx::PointF last_event_handle_bound_middle_; + gfx::PointF last_drag_update_position_; std::vector<SelectionEventType> events_; bool caret_moved_; bool selection_moved_; @@ -311,7 +328,7 @@ TEST_F(TouchSelectionControllerTest, InsertionDragged) { OnTapEvent(); // The touch sequence should not be handled if insertion is not active. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_FALSE(controller().WillHandleTouchEvent(event)); float line_height = 10.f; @@ -332,30 +349,30 @@ TEST_F(TouchSelectionControllerTest, InsertionDragged) { // The MoveCaret() result should reflect the movement. // The reported position is offset from the center of |start_rect|. gfx::PointF start_offset = start_rect.CenterPoint(); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 0, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetCaretMoved()); EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition()); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 5, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetCaretMoved()); EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition()); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 10, 10); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetCaretMoved()); EXPECT_EQ(start_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetCaretMoved()); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STOPPED)); - // Following ACTION_DOWN should not be consumed if it does not start handle + // Following Action::DOWN should not be consumed if it does not start handle // dragging. SetDraggingEnabled(false); - event = MockMotionEvent(MotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_FALSE(controller().WillHandleTouchEvent(event)); } @@ -371,18 +388,18 @@ TEST_F(TouchSelectionControllerTest, InsertionDeactivatedWhileDragging) { ElementsAre(INSERTION_HANDLE_SHOWN)); EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart()); - // Enable dragging so that the following ACTION_DOWN starts handle dragging. + // Enable dragging so that the following Action::DOWN starts handle dragging. SetDraggingEnabled(true); // Touch down to start dragging. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetCaretMoved()); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED)); // Move the handle. gfx::PointF start_offset = start_rect.CenterPoint(); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 0, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetCaretMoved()); EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition()); @@ -395,21 +412,21 @@ TEST_F(TouchSelectionControllerTest, InsertionDeactivatedWhileDragging) { // Move the finger. There is no handle to move, so the cursor is not moved; // but, the event is still consumed because the touch down that started the // touch sequence was consumed. - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 5, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetCaretMoved()); EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition()); // Lift the finger to end the touch sequence. - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 5, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 5, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetCaretMoved()); EXPECT_THAT(GetAndResetEvents(), IsEmpty()); - // Following ACTION_DOWN should not be consumed if it does not start handle + // Following Action::DOWN should not be consumed if it does not start handle // dragging. SetDraggingEnabled(false); - event = MockMotionEvent(MotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_FALSE(controller().WillHandleTouchEvent(event)); } @@ -424,11 +441,11 @@ TEST_F(TouchSelectionControllerTest, InsertionTapped) { EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN)); - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED)); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_TAPPED, INSERTION_HANDLE_DRAG_STOPPED)); @@ -441,12 +458,10 @@ TEST_F(TouchSelectionControllerTest, InsertionTapped) { ElementsAre(INSERTION_HANDLE_CLEARED, INSERTION_HANDLE_SHOWN)); // No tap should be signalled if the time between DOWN and UP was too long. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, - event_time + base::TimeDelta::FromSeconds(1), - 0, - 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, + event_time + base::TimeDelta::FromSeconds(1), 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED, INSERTION_HANDLE_DRAG_STOPPED)); @@ -459,11 +474,11 @@ TEST_F(TouchSelectionControllerTest, InsertionTapped) { ElementsAre(INSERTION_HANDLE_CLEARED, INSERTION_HANDLE_SHOWN)); // No tap should be signalled if the drag was too long. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 100, 0); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 100, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 100, 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 100, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED, INSERTION_HANDLE_DRAG_STOPPED)); @@ -476,9 +491,9 @@ TEST_F(TouchSelectionControllerTest, InsertionTapped) { ElementsAre(INSERTION_HANDLE_CLEARED, INSERTION_HANDLE_SHOWN)); // No tap should be signalled if the touch sequence is cancelled. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); - event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::CANCEL, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED, INSERTION_HANDLE_DRAG_STOPPED)); @@ -614,7 +629,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDragged) { OnLongPressEvent(); // The touch sequence should not be handled if selection is not active. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_FALSE(controller().WillHandleTouchEvent(event)); float line_height = 10.f; @@ -639,34 +654,34 @@ TEST_F(TouchSelectionControllerTest, SelectionDragged) { // input rects (i.e., the middle of the corresponding text line). gfx::PointF fixed_offset = end_rect.CenterPoint(); gfx::PointF start_offset = start_rect.CenterPoint(); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 0, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); EXPECT_TRUE(GetAndResetSelectionMoved()); EXPECT_EQ(fixed_offset, GetLastSelectionStart()); EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 5, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetSelectionMoved()); EXPECT_EQ(fixed_offset, GetLastSelectionStart()); EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetSelectionMoved()); EXPECT_EQ(fixed_offset, GetLastSelectionStart()); EXPECT_EQ(start_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); EXPECT_FALSE(GetAndResetSelectionMoved()); - // Following ACTION_DOWN should not be consumed if it does not start handle + // Following Action::DOWN should not be consumed if it does not start handle // dragging. SetDraggingEnabled(false); - event = MockMotionEvent(MotionEvent::ACTION_DOWN, event_time, 0, 0); + event = MockMotionEvent(MotionEvent::Action::DOWN, event_time, 0, 0); EXPECT_FALSE(controller().WillHandleTouchEvent(event)); } @@ -683,27 +698,27 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) { ElementsAre(SELECTION_HANDLES_SHOWN)); EXPECT_EQ(start_rect.bottom_left(), GetLastEventStart()); - // The ACTION_DOWN should lock to the closest handle. + // The Action::DOWN should lock to the closest handle. gfx::PointF end_offset = end_rect.CenterPoint(); gfx::PointF fixed_offset = start_rect.CenterPoint(); float touch_down_x = (end_offset.x() + fixed_offset.x()) / 2 + 1.f; - MockMotionEvent event( - MockMotionEvent::ACTION_DOWN, event_time, touch_down_x, 0); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, touch_down_x, + 0); SetDraggingEnabled(true); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); EXPECT_FALSE(GetAndResetSelectionMoved()); - // Even though the ACTION_MOVE is over the start handle, it should continue - // targetting the end handle that consumed the ACTION_DOWN. - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 0); + // Even though the Action::MOVE is over the start handle, it should continue + // targetting the end handle that consumed the Action::DOWN. + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetSelectionMoved()); EXPECT_EQ(fixed_offset, GetLastSelectionStart()); EXPECT_EQ(end_offset - gfx::Vector2dF(touch_down_x, 0), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -725,15 +740,15 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { SetDraggingEnabled(true); // Move the extent, not triggering a swap of points. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, - end_rect.x(), end_rect.bottom()); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, end_rect.x(), + end_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetSelectionMoved()); EXPECT_FALSE(GetAndResetSelectionPointsSwapped()); gfx::PointF base_offset = start_rect.CenterPoint(); gfx::PointF extent_offset = end_rect.CenterPoint(); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, end_rect.x(), end_rect.bottom() + 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -742,7 +757,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { EXPECT_EQ(base_offset, GetLastSelectionStart()); EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -752,7 +767,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED)); // Move the base, triggering a swap of points. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, start_rect.x(), start_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -760,7 +775,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { base_offset = end_rect.CenterPoint(); extent_offset = start_rect.CenterPoint(); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, start_rect.x(), start_rect.bottom() + 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -769,7 +784,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { EXPECT_EQ(base_offset, GetLastSelectionStart()); EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -779,7 +794,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED)); // Move the same point again, not triggering a swap of points. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, start_rect.x(), start_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -787,7 +802,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { base_offset = end_rect.CenterPoint(); extent_offset = start_rect.CenterPoint(); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, start_rect.x(), start_rect.bottom() + 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -796,7 +811,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { EXPECT_EQ(base_offset, GetLastSelectionStart()); EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -806,7 +821,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED)); // Move the base, triggering a swap of points. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, end_rect.x(), end_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -814,7 +829,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { base_offset = start_rect.CenterPoint(); extent_offset = end_rect.CenterPoint(); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, end_rect.x(), end_rect.bottom() + 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -823,7 +838,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) { EXPECT_EQ(base_offset, GetLastSelectionStart()); EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd()); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); EXPECT_FALSE(GetAndResetSelectionMoved()); @@ -844,7 +859,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDragExtremeLineSize) { EXPECT_EQ(small_line_rect.bottom_left(), GetLastEventStart()); // Start dragging the handle on the small line. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, small_line_rect.x(), small_line_rect.y()); SetDraggingEnabled(true); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); @@ -858,7 +873,7 @@ TEST_F(TouchSelectionControllerTest, SelectionDragExtremeLineSize) { EXPECT_EQ(small_line_rect.CenterPoint(), GetLastSelectionEnd()); small_line_rect += gfx::Vector2dF(25.f, 0); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, small_line_rect.x(), small_line_rect.y()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_TRUE(GetAndResetSelectionMoved()); @@ -1169,7 +1184,7 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { SetDraggingEnabled(true); // Simulate moving the base, not triggering a swap of points. - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, start_rect.x(), start_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -1184,7 +1199,7 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { TouchHandleOrientation::RIGHT); event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, offset_rect.x(), offset_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); @@ -1194,7 +1209,7 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { TouchHandleOrientation::RIGHT); // Simulate moving the base, triggering a swap of points. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, offset_rect.x(), offset_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -1208,7 +1223,7 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { TouchHandleOrientation::LEFT); event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, offset_rect.x(), offset_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); @@ -1218,7 +1233,7 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { TouchHandleOrientation::RIGHT); // Simulate moving the anchor, not triggering a swap of points. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, offset_rect.x(), offset_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -1232,7 +1247,7 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { TouchHandleOrientation::RIGHT); event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, offset_rect.x(), offset_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); @@ -1242,7 +1257,7 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { TouchHandleOrientation::RIGHT); // Simulate moving the anchor, triggering a swap of points. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, offset_rect.x(), offset_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); @@ -1256,17 +1271,93 @@ TEST_F(TouchSelectionControllerTest, SelectionNoOrientationChangeWhenSwapped) { TouchHandleOrientation::RIGHT); event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, + offset_rect.x(), offset_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); + EXPECT_EQ(test_controller.GetStartHandleOrientation(), + TouchHandleOrientation::LEFT); + EXPECT_EQ(test_controller.GetEndHandleOrientation(), + TouchHandleOrientation::RIGHT); +} + +TEST_F(TouchSelectionControllerTest, VerticalTextSelectionHandleSwap) { + TouchSelectionControllerTestApi test_controller(&controller()); + base::TimeTicks event_time = base::TimeTicks::Now(); + OnLongPressEvent(); + + // Horizontal bounds. + gfx::RectF start_rect(0, 50, 16, 0); + gfx::RectF end_rect(0, 100, 16, 0); + + bool visible = true; + ChangeVerticalSelection(start_rect, visible, end_rect, visible); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN)); + EXPECT_EQ(start_rect.bottom_right(), GetLastEventStart()); + EXPECT_EQ(test_controller.GetStartHandleOrientation(), + TouchHandleOrientation::RIGHT); + EXPECT_EQ(test_controller.GetEndHandleOrientation(), + TouchHandleOrientation::LEFT); + + SetDraggingEnabled(true); + + // Simulate moving the base, triggering a swap of points. + // Start to drag start handle. + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, + start_rect.right(), start_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); + + // Move start handle down below end handle. + gfx::RectF offset_rect = end_rect; + offset_rect.Offset(gfx::Vector2dF(0, 20)); + ChangeVerticalSelection(end_rect, visible, offset_rect, visible); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED)); + EXPECT_EQ(test_controller.GetStartHandleOrientation(), + TouchHandleOrientation::RIGHT); + EXPECT_EQ(test_controller.GetEndHandleOrientation(), + TouchHandleOrientation::RIGHT); + + // Release. + event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, offset_rect.x(), offset_rect.bottom()); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); EXPECT_EQ(test_controller.GetStartHandleOrientation(), + TouchHandleOrientation::RIGHT); + EXPECT_EQ(test_controller.GetEndHandleOrientation(), + TouchHandleOrientation::LEFT); + + // Move end handle up. + // Start to drag end handle. + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, + offset_rect.x(), offset_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); + + // Move up end handle up above the start handle. + offset_rect = start_rect; + ChangeVerticalSelection(offset_rect, visible, end_rect, visible); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED)); + EXPECT_EQ(test_controller.GetStartHandleOrientation(), TouchHandleOrientation::LEFT); EXPECT_EQ(test_controller.GetEndHandleOrientation(), + TouchHandleOrientation::LEFT); + + // Release. + event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, + offset_rect.x(), offset_rect.bottom()); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); + EXPECT_EQ(test_controller.GetStartHandleOrientation(), TouchHandleOrientation::RIGHT); + EXPECT_EQ(test_controller.GetEndHandleOrientation(), + TouchHandleOrientation::LEFT); } -TEST_F(TouchSelectionControllerTest, InsertionActiveBoundMiddlePoint) { +TEST_F(TouchSelectionControllerTest, InsertionUpdateDragPosition) { base::TimeTicks event_time = base::TimeTicks::Now(); float line_height = 10.f; gfx::RectF insertion_rect(10, 0, 0, line_height); @@ -1275,38 +1366,43 @@ TEST_F(TouchSelectionControllerTest, InsertionActiveBoundMiddlePoint) { OnTapEvent(); ChangeInsertion(insertion_rect, visible); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_SHOWN)); - EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastEventHandleBoundMiddle()); + EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastDragUpdatePosition()); SetDraggingEnabled(true); - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 10, 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STARTED)); - EXPECT_EQ(gfx::PointF(10.f, 5.f), GetLastEventHandleBoundMiddle()); + EXPECT_EQ(gfx::PointF(10.f, 5.f), GetLastDragUpdatePosition()); insertion_rect.Offset(1, 0); ChangeInsertion(insertion_rect, visible); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 1, 0); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 12, 6); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED)); - EXPECT_EQ(gfx::PointF(11.f, 5.f), GetLastEventHandleBoundMiddle()); + // Don't follow the y-coordinate change but only x-coordinate change. + EXPECT_EQ(gfx::PointF(12.f, 5.f), GetLastDragUpdatePosition()); insertion_rect.Offset(0, 1); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 11, 6); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); ChangeInsertion(insertion_rect, visible); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 1); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 11, 7); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_MOVED)); - EXPECT_EQ(gfx::PointF(11.f, 6.f), GetLastEventHandleBoundMiddle()); + // Don't follow the y-coordinate change. + EXPECT_EQ(gfx::PointF(11.f, 6.f), GetLastDragUpdatePosition()); event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 0, 0); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(INSERTION_HANDLE_DRAG_STOPPED)); - EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastEventHandleBoundMiddle()); SetDraggingEnabled(false); } -TEST_F(TouchSelectionControllerTest, SelectionActiveBoundMiddlePoint) { +TEST_F(TouchSelectionControllerTest, SelectionUpdateDragPosition) { base::TimeTicks event_time = base::TimeTicks::Now(); float line_height = 10.f; gfx::RectF start_rect(10, 0, 0, line_height); @@ -1316,46 +1412,49 @@ TEST_F(TouchSelectionControllerTest, SelectionActiveBoundMiddlePoint) { ChangeSelection(start_rect, visible, end_rect, visible); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_SHOWN)); - EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastEventHandleBoundMiddle()); + EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastDragUpdatePosition()); // Left handle. SetDraggingEnabled(true); - MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 10, 5); + MockMotionEvent event(MockMotionEvent::Action::DOWN, event_time, 10, 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 10, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); - EXPECT_EQ(gfx::PointF(10.f, 5.f), GetLastEventHandleBoundMiddle()); + EXPECT_EQ(gfx::PointF(10.f, 5.f), GetLastDragUpdatePosition()); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 15, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 16, 6); start_rect.Offset(5, 0); ChangeSelection(start_rect, visible, end_rect, visible); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED)); - EXPECT_EQ(gfx::PointF(15.f, 5.f), GetLastEventHandleBoundMiddle()); + // Don't follow the y-coordinate change but only x-coordinate change. + EXPECT_EQ(gfx::PointF(16.f, 5.f), GetLastDragUpdatePosition()); event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 15, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 15, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); - EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastEventHandleBoundMiddle()); // Right handle. - event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 50, 5); + event = MockMotionEvent(MockMotionEvent::Action::DOWN, event_time, 50, 5); + EXPECT_TRUE(controller().WillHandleTouchEvent(event)); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 50, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STARTED)); - EXPECT_EQ(gfx::PointF(50.f, 5.f), GetLastEventHandleBoundMiddle()); + EXPECT_EQ(gfx::PointF(50.f, 5.f), GetLastDragUpdatePosition()); - event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 45, 5); + event = MockMotionEvent(MockMotionEvent::Action::MOVE, event_time, 45, 5); end_rect.Offset(-5, 0); ChangeSelection(start_rect, visible, end_rect, visible); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLES_MOVED)); - EXPECT_EQ(gfx::PointF(45.f, 5.f), GetLastEventHandleBoundMiddle()); + EXPECT_EQ(gfx::PointF(45.f, 5.f), GetLastDragUpdatePosition()); event_time += base::TimeDelta::FromMilliseconds(2 * kDefaultTapTimeoutMs); - event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 45, 5); + event = MockMotionEvent(MockMotionEvent::Action::UP, event_time, 45, 5); EXPECT_TRUE(controller().WillHandleTouchEvent(event)); EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_HANDLE_DRAG_STOPPED)); - EXPECT_EQ(gfx::PointF(0.f, 0.f), GetLastEventHandleBoundMiddle()); } } // namespace ui diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn index a845514bf92..8d72c2a2b31 100644 --- a/chromium/ui/views/BUILD.gn +++ b/chromium/ui/views/BUILD.gn @@ -167,6 +167,7 @@ jumbo_component("views") { "controls/tree/tree_view.h", "controls/tree/tree_view_controller.h", "controls/tree/tree_view_drawing_provider.h", + "controls/views_text_services_context_menu.h", "debug_utils.h", "drag_controller.h", "drag_utils.h", @@ -355,6 +356,8 @@ jumbo_component("views") { "controls/tree/tree_view.cc", "controls/tree/tree_view_controller.cc", "controls/tree/tree_view_drawing_provider.cc", + "controls/views_text_services_context_menu.cc", + "controls/views_text_services_context_menu_mac.mm", "debug_utils.cc", "drag_utils.cc", "drag_utils_mac.mm", @@ -464,7 +467,7 @@ jumbo_component("views") { ":views_vector_icons", "//base", "//components/vector_icons", - "//ui/accessibility:ax_gen", + "//ui/accessibility:ax_enums_mojo", "//ui/base", "//ui/base/ime", "//ui/compositor", @@ -683,7 +686,9 @@ jumbo_component("views") { } if (is_mac) { + sources -= [ "controls/views_text_services_context_menu.cc" ] deps += [ + "//components/crash/core/common", "//ui/accelerated_widget_mac", "//ui/events:dom_keycode_converter", ] @@ -918,6 +923,7 @@ source_set("views_unittests_sources") { "controls/button/radio_button_unittest.cc", "controls/button/toggle_button_unittest.cc", "controls/combobox/combobox_unittest.cc", + "controls/image_view_unittest.cc", "controls/label_unittest.cc", "controls/menu/menu_controller_unittest.cc", "controls/menu/menu_item_view_unittest.cc", @@ -1188,7 +1194,13 @@ test("views_perftests") { ":test_support", "//base/test:test_support", "//cc/base:base", + "//mojo/edk/system", "//testing/perf", "//ui/resources:ui_test_pak", ] + + data_deps = [ + "//ui/resources:ui_test_pak_data", + "//testing:run_gtest_perf_test", + ] } diff --git a/chromium/ui/views/DEPS b/chromium/ui/views/DEPS index 83326226e10..41eaa521433 100644 --- a/chromium/ui/views/DEPS +++ b/chromium/ui/views/DEPS @@ -1,5 +1,6 @@ include_rules = [ "+cc/paint", + "+components/crash/core/common/crash_key.h", "+components/vector_icons", "+services/ui/public/interfaces", "+skia/ext", diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc index 1372dd28de5..3fc1975935b 100644 --- a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc +++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc @@ -118,11 +118,11 @@ AXAuraObjWrapper* AXAuraObjCache::GetFocus() { void AXAuraObjCache::OnFocusedViewChanged() { View* view = GetFocusedView(); if (view) - view->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); + view->NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true); } void AXAuraObjCache::FireEvent(AXAuraObjWrapper* aura_obj, - ui::AXEvent event_type) { + ax::mojom::Event event_type) { if (delegate_) delegate_->OnEvent(aura_obj, event_type); } diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.h b/chromium/ui/views/accessibility/ax_aura_obj_cache.h index 69958c3d048..48be286a40c 100644 --- a/chromium/ui/views/accessibility/ax_aura_obj_cache.h +++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.h @@ -13,7 +13,7 @@ #include <vector> #include "base/macros.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/aura/client/focus_change_observer.h" #include "ui/views/views_export.h" @@ -40,7 +40,7 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver { public: virtual void OnChildWindowRemoved(AXAuraObjWrapper* parent) = 0; virtual void OnEvent(AXAuraObjWrapper* aura_obj, - ui::AXEvent event_type) = 0; + ax::mojom::Event event_type) = 0; }; // Get or create an entry in the cache based on an Aura view. @@ -80,7 +80,7 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver { void OnFocusedViewChanged(); // Tell our delegate to fire an event on a given object. - void FireEvent(AXAuraObjWrapper* aura_obj, ui::AXEvent event_type); + void FireEvent(AXAuraObjWrapper* aura_obj, ax::mojom::Event event_type); // Indicates if this object's currently being destroyed. bool is_destroying() { return is_destroying_; } diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc index 2c0cb81523b..2645da529ef 100644 --- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc +++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc @@ -35,6 +35,9 @@ AXAuraObjWrapper* AXViewObjWrapper::GetParent() { void AXViewObjWrapper::GetChildren( std::vector<AXAuraObjWrapper*>* out_children) { + if (view_->GetViewAccessibility().IsLeaf()) + return; + // TODO(dtseng): Need to handle |Widget| child of |View|. for (int i = 0; i < view_->child_count(); ++i) { if (!view_->child_at(i)->visible()) diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc index bfb5725e752..43eb649aa24 100644 --- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc +++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc @@ -46,7 +46,7 @@ void AXWidgetObjWrapper::Serialize(ui::AXNodeData* out_node_data) { out_node_data->id = GetUniqueId().Get(); out_node_data->role = widget_->widget_delegate()->GetAccessibleWindowRole(); out_node_data->AddStringAttribute( - ui::AX_ATTR_NAME, + ax::mojom::StringAttribute::kName, base::UTF16ToUTF8( widget_->widget_delegate()->GetAccessibleWindowTitle())); out_node_data->location = gfx::RectF(widget_->GetWindowBoundsInScreen()); diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc index ab604049070..68aaca376d8 100644 --- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc +++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc @@ -7,7 +7,7 @@ #include <stddef.h> #include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/platform/aura_window_properties.h" #include "ui/accessibility/platform/ax_unique_id.h" @@ -18,6 +18,28 @@ namespace views { +void FireLocationChanges(aura::Window* window) { + AXAuraObjCache::GetInstance()->FireEvent( + AXAuraObjCache::GetInstance()->GetOrCreate(window), + ax::mojom::Event::kLocationChanged); + + Widget* widget = Widget::GetWidgetForNativeView(window); + if (widget) { + AXAuraObjCache::GetInstance()->FireEvent( + AXAuraObjCache::GetInstance()->GetOrCreate(widget), + ax::mojom::Event::kLocationChanged); + + views::View* root_view = widget->GetRootView(); + if (root_view) + root_view->NotifyAccessibilityEvent(ax::mojom::Event::kLocationChanged, + true); + } + + aura::Window::Windows children = window->children(); + for (size_t i = 0; i < children.size(); ++i) + FireLocationChanges(children[i]); +} + AXWindowObjWrapper::AXWindowObjWrapper(aura::Window* window) : window_(window), is_alert_(false), @@ -59,22 +81,17 @@ void AXWindowObjWrapper::GetChildren( void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) { out_node_data->id = GetUniqueId().Get(); - ui::AXRole role = window_->GetProperty(ui::kAXRoleOverride); - if (role != ui::AX_ROLE_NONE) + ax::mojom::Role role = window_->GetProperty(ui::kAXRoleOverride); + if (role != ax::mojom::Role::kNone) out_node_data->role = role; else - out_node_data->role = is_alert_ ? ui::AX_ROLE_ALERT : ui::AX_ROLE_WINDOW; - out_node_data->AddStringAttribute(ui::AX_ATTR_NAME, + out_node_data->role = + is_alert_ ? ax::mojom::Role::kAlert : ax::mojom::Role::kWindow; + out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kName, base::UTF16ToUTF8(window_->GetTitle())); if (!window_->IsVisible()) - out_node_data->AddState(ui::AX_STATE_INVISIBLE); - - out_node_data->location = gfx::RectF(window_->bounds()); - if (window_->parent()) { - out_node_data->offset_container_id = - AXAuraObjCache::GetInstance()->GetID(window_->parent()); - } - + out_node_data->AddState(ax::mojom::State::kInvisible); + out_node_data->location = gfx::RectF(window_->GetBoundsInScreen()); ui::AXTreeIDRegistry::AXTreeID child_ax_tree_id = window_->GetProperty(ui::kChildAXTreeID); if (child_ax_tree_id != ui::AXTreeIDRegistry::kNoAXTreeID) { @@ -89,7 +106,8 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) { return; } - out_node_data->AddIntAttribute(ui::AX_ATTR_CHILD_TREE_ID, child_ax_tree_id); + out_node_data->AddIntAttribute(ax::mojom::IntAttribute::kChildTreeId, + child_ax_tree_id); } } @@ -121,26 +139,15 @@ void AXWindowObjWrapper::OnWindowBoundsChanged( if (window != window_) return; - AXAuraObjCache::GetInstance()->FireEvent(this, ui::AX_EVENT_LOCATION_CHANGED); - - Widget* widget = Widget::GetWidgetForNativeView(window); - if (widget) { - AXAuraObjCache::GetInstance()->FireEvent( - AXAuraObjCache::GetInstance()->GetOrCreate(widget), - ui::AX_EVENT_LOCATION_CHANGED); - - views::View* root_view = widget->GetRootView(); - if (root_view) - root_view->NotifyAccessibilityEvent(ui::AX_EVENT_LOCATION_CHANGED, true); - } + FireLocationChanges(window_); } void AXWindowObjWrapper::OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) { if (window == window_ && key == ui::kChildAXTreeID) { - AXAuraObjCache::GetInstance()->FireEvent(this, - ui::AX_EVENT_CHILDREN_CHANGED); + AXAuraObjCache::GetInstance()->FireEvent( + this, ax::mojom::Event::kChildrenChanged); } } diff --git a/chromium/ui/views/accessibility/native_view_accessibility.h b/chromium/ui/views/accessibility/native_view_accessibility.h index 803db433932..d2ed8c176f9 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility.h +++ b/chromium/ui/views/accessibility/native_view_accessibility.h @@ -8,7 +8,7 @@ #include <memory> #include "base/macros.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/views_export.h" @@ -25,7 +25,7 @@ class VIEWS_EXPORT NativeViewAccessibility { virtual ~NativeViewAccessibility() {} virtual gfx::NativeViewAccessible GetNativeObject() = 0; - virtual void NotifyAccessibilityEvent(ui::AXEvent event_type) = 0; + virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type) = 0; protected: NativeViewAccessibility() {} diff --git a/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc b/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc index 7fbbca936cf..0be9b7cfd75 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc +++ b/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc @@ -13,7 +13,7 @@ #include "base/memory/singleton.h" #include "base/stl_util.h" #include "ui/accessibility/ax_action_data.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/platform/ax_platform_node_auralinux.h" #include "ui/accessibility/platform/ax_platform_node_delegate.h" @@ -98,7 +98,10 @@ class AuraLinuxApplication return widget->GetRootView()->GetNativeViewAccessible(); } - gfx::Rect GetScreenBoundsRect() const override { return gfx::Rect(); } + gfx::Rect GetClippedScreenBoundsRect() const override { return gfx::Rect(); } + gfx::Rect GetUnclippedScreenBoundsRect() const override { + return gfx::Rect(); + } gfx::NativeViewAccessible HitTestSync(int x, int y) override { return nullptr; @@ -127,12 +130,12 @@ class AuraLinuxApplication bool ShouldIgnoreHoveredStateForTesting() override { return false; } - std::set<int32_t> GetReverseRelations(ui::AXIntAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) override { return std::set<int32_t>(); } - std::set<int32_t> GetReverseRelations(ui::AXIntListAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) override { return std::set<int32_t>(); } @@ -141,11 +144,11 @@ class AuraLinuxApplication friend struct base::DefaultSingletonTraits<AuraLinuxApplication>; AuraLinuxApplication() { - data_.role = ui::AX_ROLE_APPLICATION; + data_.role = ax::mojom::Role::kApplication; platform_node_ = ui::AXPlatformNode::Create(this); if (ViewsDelegate::GetInstance()) { data_.AddStringAttribute( - ui::AX_ATTR_NAME, + ax::mojom::StringAttribute::kName, ViewsDelegate::GetInstance()->GetApplicationName()); } ui::AXPlatformNodeAuraLinux::SetApplication(platform_node_); diff --git a/chromium/ui/views/accessibility/native_view_accessibility_base.cc b/chromium/ui/views/accessibility/native_view_accessibility_base.cc index d26a9ec8cee..9997f88dd95 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_base.cc +++ b/chromium/ui/views/accessibility/native_view_accessibility_base.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <map> +#include <memory> + #include "ui/views/accessibility/native_view_accessibility_base.h" #include "base/memory/ptr_util.h" @@ -16,6 +19,9 @@ namespace views { namespace { +base::LazyInstance<std::map<int32_t, ui::AXPlatformNode*>>::Leaky + g_unique_id_to_ax_platform_node = LAZY_INSTANCE_INITIALIZER; + bool IsAccessibilityFocusableWhenEnabled(View* view) { return view->focus_behavior() != View::FocusBehavior::NEVER && view->IsDrawn(); @@ -24,7 +30,7 @@ bool IsAccessibilityFocusableWhenEnabled(View* view) { // Used to determine if a View should be ignored by accessibility clients by // being a non-keyboard-focusable child of a keyboard-focusable ancestor. E.g., // LabelButtons contain Labels, but a11y should just show that there's a button. -bool IsViewUnfocusableChildOfFocusableAncestor(View* view) { +bool IsViewUnfocusableDescendantOfFocusableAncestor(View* view) { if (IsAccessibilityFocusableWhenEnabled(view)) return false; @@ -66,9 +72,12 @@ NativeViewAccessibilityBase::NativeViewAccessibilityBase(View* view) base::BindRepeating(&FromNativeWindow)); first_time = false; } + + g_unique_id_to_ax_platform_node.Get()[GetUniqueId().Get()] = ax_node_; } NativeViewAccessibilityBase::~NativeViewAccessibilityBase() { + g_unique_id_to_ax_platform_node.Get().erase(GetUniqueId().Get()); ax_node_->Destroy(); } @@ -77,7 +86,7 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::GetNativeObject() { } void NativeViewAccessibilityBase::NotifyAccessibilityEvent( - ui::AXEvent event_type) { + ax::mojom::Event event_type) { ax_node_->NotifyAccessibilityEvent(event_type); } @@ -95,7 +104,7 @@ const ui::AXNodeData& NativeViewAccessibilityBase::GetData() const { // This will require ensuring that Chrome OS invalidates the whole // subtree when a View changes its visibility state. if (!view()->IsDrawn()) - data_.AddState(ui::AX_STATE_INVISIBLE); + data_.AddState(ax::mojom::State::kInvisible); // Make sure this element is excluded from the a11y tree if there's a // focusable parent. All keyboard focusable elements should be leaf nodes. @@ -105,8 +114,8 @@ const ui::AXNodeData& NativeViewAccessibilityBase::GetData() const { // because we needed a way to mark a View as a leaf node in the // accessibility tree. We need to replace this with a cross-platform // solution that works for ChromeVox, too, and move it to ViewAccessibility. - if (IsViewUnfocusableChildOfFocusableAncestor(view())) - data_.role = ui::AX_ROLE_IGNORED; + if (IsViewUnfocusableDescendantOfFocusableAncestor(view())) + data_.role = ax::mojom::Role::kIgnored; return data_; } @@ -117,6 +126,8 @@ const ui::AXTreeData& NativeViewAccessibilityBase::GetTreeData() const { } int NativeViewAccessibilityBase::GetChildCount() { + if (IsLeaf()) + return 0; int child_count = view()->child_count(); std::vector<Widget*> child_widgets; @@ -127,6 +138,9 @@ int NativeViewAccessibilityBase::GetChildCount() { } gfx::NativeViewAccessible NativeViewAccessibilityBase::ChildAtIndex(int index) { + if (IsLeaf()) + return nullptr; + // If this is a root view, our widget might have child widgets. Include std::vector<Widget*> child_widgets; PopulateChildWidgetVector(&child_widgets); @@ -161,7 +175,12 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::GetParent() { return nullptr; } -gfx::Rect NativeViewAccessibilityBase::GetScreenBoundsRect() const { +gfx::Rect NativeViewAccessibilityBase::GetClippedScreenBoundsRect() const { + // We could optionally add clipping here if ever needed. + return view()->GetBoundsInScreen(); +} + +gfx::Rect NativeViewAccessibilityBase::GetUnclippedScreenBoundsRect() const { return view()->GetBoundsInScreen(); } @@ -170,6 +189,9 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::HitTestSync(int x, if (!view() || !view()->GetWidget()) return nullptr; + if (IsLeaf()) + return GetNativeObject(); + // Search child widgets first, since they're on top in the z-order. std::vector<Widget*> child_widgets; PopulateChildWidgetVector(&child_widgets); @@ -212,7 +234,14 @@ gfx::NativeViewAccessible NativeViewAccessibilityBase::GetFocus() { } ui::AXPlatformNode* NativeViewAccessibilityBase::GetFromNodeID(int32_t id) { - return nullptr; + // Note: For Views, node IDs and unique IDs are the same - but that isn't + // necessarily true for all AXPlatformNodes. + auto it = g_unique_id_to_ax_platform_node.Get().find(id); + + if (it == g_unique_id_to_ax_platform_node.Get().end()) + return nullptr; + + return it->second; } int NativeViewAccessibilityBase::GetIndexInParent() const { @@ -239,13 +268,13 @@ bool NativeViewAccessibilityBase::IsOffscreen() const { } std::set<int32_t> NativeViewAccessibilityBase::GetReverseRelations( - ui::AXIntAttribute attr, + ax::mojom::IntAttribute attr, int32_t dst_id) { return std::set<int32_t>(); } std::set<int32_t> NativeViewAccessibilityBase::GetReverseRelations( - ui::AXIntListAttribute attr, + ax::mojom::IntListAttribute attr, int32_t dst_id) { return std::set<int32_t>(); } @@ -254,10 +283,6 @@ const ui::AXUniqueId& NativeViewAccessibilityBase::GetUniqueId() const { return ViewAccessibility::GetUniqueId(); } -gfx::RectF NativeViewAccessibilityBase::GetBoundsInScreen() const { - return gfx::RectF(view()->GetBoundsInScreen()); -} - void NativeViewAccessibilityBase::PopulateChildWidgetVector( std::vector<Widget*>* result_child_widgets) { // Only attach child widgets to the root view. diff --git a/chromium/ui/views/accessibility/native_view_accessibility_base.h b/chromium/ui/views/accessibility/native_view_accessibility_base.h index 413a3a32af9..18fe003a7fc 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_base.h +++ b/chromium/ui/views/accessibility/native_view_accessibility_base.h @@ -36,7 +36,7 @@ class VIEWS_EXPORT NativeViewAccessibilityBase // ViewAccessibility: gfx::NativeViewAccessible GetNativeObject() override; - void NotifyAccessibilityEvent(ui::AXEvent event_type) override; + void NotifyAccessibilityEvent(ax::mojom::Event event_type) override; // ui::AXPlatformNodeDelegate const ui::AXNodeData& GetData() const override; @@ -45,7 +45,8 @@ class VIEWS_EXPORT NativeViewAccessibilityBase gfx::NativeViewAccessible ChildAtIndex(int index) override; gfx::NativeWindow GetTopLevelWidget() override; gfx::NativeViewAccessible GetParent() override; - gfx::Rect GetScreenBoundsRect() const override; + gfx::Rect GetClippedScreenBoundsRect() const override; + gfx::Rect GetUnclippedScreenBoundsRect() const override; gfx::NativeViewAccessible HitTestSync(int x, int y) override; gfx::NativeViewAccessible GetFocus() override; ui::AXPlatformNode* GetFromNodeID(int32_t id) override; @@ -56,17 +57,14 @@ class VIEWS_EXPORT NativeViewAccessibilityBase bool IsOffscreen() const override; const ui::AXUniqueId& GetUniqueId() const override; // Also in ViewAccessibility - std::set<int32_t> GetReverseRelations(ui::AXIntAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) override; - std::set<int32_t> GetReverseRelations(ui::AXIntListAttribute attr, + std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) override; protected: explicit NativeViewAccessibilityBase(View* view); - protected: - virtual gfx::RectF GetBoundsInScreen() const; - private: void PopulateChildWidgetVector(std::vector<Widget*>* result_child_widgets); diff --git a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc index 5bf1eaaf746..d146b33705f 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc +++ b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc @@ -71,7 +71,8 @@ class NativeViewAccessibilityTest : public ViewsTestBase { bool SetFocused(NativeViewAccessibilityBase* view_accessibility, bool focused) { ui::AXActionData data; - data.action = focused ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; + data.action = + focused ? ax::mojom::Action::kFocus : ax::mojom::Action::kBlur; return view_accessibility->AccessibilityPerformAction(data); } @@ -84,22 +85,24 @@ class NativeViewAccessibilityTest : public ViewsTestBase { }; TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) { - EXPECT_EQ(ui::AX_ROLE_BUTTON, button_accessibility()->GetData().role); + EXPECT_EQ(ax::mojom::Role::kButton, button_accessibility()->GetData().role); // Since the label is a subview of |button_|, and the button is keyboard // focusable, the label is assumed to form part of the button and not have a // role of its own. - EXPECT_EQ(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); + EXPECT_EQ(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role); // This will happen for all potentially keyboard-focusable Views with // non-keyboard-focusable children, so if we make the button unfocusable, the // label will be allowed to have its own role again. button_->SetFocusBehavior(View::FocusBehavior::NEVER); - EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, label_accessibility()->GetData().role); + EXPECT_EQ(ax::mojom::Role::kStaticText, + label_accessibility()->GetData().role); } TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) { gfx::Rect bounds = gfx::ToEnclosingRect(button_accessibility()->GetData().location); - gfx::Rect screen_bounds = button_accessibility()->GetScreenBoundsRect(); + gfx::Rect screen_bounds = + button_accessibility()->GetUnclippedScreenBoundsRect(); EXPECT_EQ(button_->GetBoundsInScreen(), bounds); EXPECT_EQ(screen_bounds, bounds); @@ -111,7 +114,7 @@ TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { EXPECT_EQ(1, button_accessibility()->GetChildCount()); EXPECT_EQ(button_->GetNativeViewAccessible(), label_accessibility()->GetParent()); - EXPECT_EQ(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); + EXPECT_EQ(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role); // If |button_| is no longer focusable, |label_| should show up again. button_->SetFocusBehavior(View::FocusBehavior::NEVER); @@ -120,21 +123,21 @@ TEST_F(NativeViewAccessibilityTest, LabelIsChildOfButton) { button_accessibility()->ChildAtIndex(0)); EXPECT_EQ(button_->GetNativeViewAccessible(), label_accessibility()->GetParent()); - EXPECT_NE(ui::AX_ROLE_IGNORED, label_accessibility()->GetData().role); + EXPECT_NE(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role); } -// Verify Views with invisible ancestors have AX_STATE_INVISIBLE. +// Verify Views with invisible ancestors have ax::mojom::State::kInvisible. TEST_F(NativeViewAccessibilityTest, InvisibleViews) { EXPECT_TRUE(widget_->IsVisible()); EXPECT_FALSE( - button_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); + button_accessibility()->GetData().HasState(ax::mojom::State::kInvisible)); EXPECT_FALSE( - label_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); + label_accessibility()->GetData().HasState(ax::mojom::State::kInvisible)); button_->SetVisible(false); EXPECT_TRUE( - button_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); + button_accessibility()->GetData().HasState(ax::mojom::State::kInvisible)); EXPECT_TRUE( - label_accessibility()->GetData().HasState(ui::AX_STATE_INVISIBLE)); + label_accessibility()->GetData().HasState(ax::mojom::State::kInvisible)); } TEST_F(NativeViewAccessibilityTest, WritableFocus) { @@ -178,7 +181,8 @@ class AxTestViewsDelegate : public TestViewsDelegate { AxTestViewsDelegate() {} ~AxTestViewsDelegate() override {} - void NotifyAccessibilityEvent(View* view, ui::AXEvent event_type) override { + void NotifyAccessibilityEvent(View* view, + ax::mojom::Event event_type) override { AXAuraObjCache* ax = AXAuraObjCache::GetInstance(); std::vector<AXAuraObjWrapper*> out_children; AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget()); diff --git a/chromium/ui/views/accessibility/native_view_accessibility_win.cc b/chromium/ui/views/accessibility/native_view_accessibility_win.cc index 9fe2082cc0d..bc1ef854510 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_win.cc +++ b/chromium/ui/views/accessibility/native_view_accessibility_win.cc @@ -15,7 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/windows_version.h" #include "third_party/iaccessible2/ia2_api_all.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/aura/window.h" @@ -23,6 +23,7 @@ #include "ui/base/layout.h" #include "ui/base/win/accessibility_misc_utils.h" #include "ui/base/win/atl_module.h" +#include "ui/display/win/screen_win.h" #include "ui/views/controls/button/button.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/widget/widget.h" @@ -101,12 +102,14 @@ NativeViewAccessibilityWin::GetTargetForNativeAccessibilityEvent() { return HWNDForView(view()); } -gfx::RectF NativeViewAccessibilityWin::GetBoundsInScreen() const { - gfx::RectF bounds = gfx::RectF(view()->GetBoundsInScreen()); - gfx::NativeView native_view = view()->GetWidget()->GetNativeView(); - float device_scale = ui::GetScaleFactorForNativeView(native_view); - bounds.Scale(device_scale); - return bounds; +gfx::Rect NativeViewAccessibilityWin::GetClippedScreenBoundsRect() const { + // We could optionally add clipping here if ever needed. + return GetUnclippedScreenBoundsRect(); +} + +gfx::Rect NativeViewAccessibilityWin::GetUnclippedScreenBoundsRect() const { + gfx::Rect bounds = view()->GetBoundsInScreen(); + return display::win::ScreenWin::DIPToScreenRect(HWNDForView(view()), bounds); } } // namespace views diff --git a/chromium/ui/views/accessibility/native_view_accessibility_win.h b/chromium/ui/views/accessibility/native_view_accessibility_win.h index dde0c906e23..8f64f68877a 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_win.h +++ b/chromium/ui/views/accessibility/native_view_accessibility_win.h @@ -19,7 +19,8 @@ class NativeViewAccessibilityWin : public NativeViewAccessibilityBase { // NativeViewAccessibilityBase: gfx::NativeViewAccessible GetParent() override; gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override; - gfx::RectF GetBoundsInScreen() const override; + gfx::Rect GetClippedScreenBoundsRect() const override; + gfx::Rect GetUnclippedScreenBoundsRect() const override; DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityWin); }; diff --git a/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc b/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc index 9a4d5647ec1..0b1c5dc7b55 100644 --- a/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc +++ b/chromium/ui/views/accessibility/native_view_accessibility_win_unittest.cc @@ -9,6 +9,8 @@ #include "base/win/scoped_variant.h" #include "third_party/iaccessible2/ia2_api_all.h" #include "ui/views/accessibility/native_view_accessibility_base.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/views_test_base.h" @@ -101,6 +103,56 @@ TEST_F(NativeViewAccessibilityWinTest, TextfieldAccessibility) { ASSERT_STREQ(L"New value", textfield->text().c_str()); } +TEST_F(NativeViewAccessibilityWinTest, TextfieldAssociatedLabel) { + Widget widget; + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(init_params); + + View* content = new View; + widget.SetContentsView(content); + + Label* label = new Label(L"Label"); + content->AddChildView(label); + Textfield* textfield = new Textfield; + textfield->SetAssociatedLabel(label); + content->AddChildView(textfield); + + ComPtr<IAccessible> content_accessible(content->GetNativeViewAccessible()); + LONG child_count = 0; + ASSERT_EQ(S_OK, content_accessible->get_accChildCount(&child_count)); + ASSERT_EQ(2L, child_count); + + ComPtr<IDispatch> textfield_dispatch; + ComPtr<IAccessible> textfield_accessible; + ScopedVariant child_index(2); + ASSERT_EQ(S_OK, content_accessible->get_accChild( + child_index, textfield_dispatch.GetAddressOf())); + ASSERT_EQ(S_OK, + textfield_dispatch.CopyTo(textfield_accessible.GetAddressOf())); + + ScopedBstr name; + ScopedVariant childid_self(CHILDID_SELF); + ASSERT_EQ(S_OK, + textfield_accessible->get_accName(childid_self, name.Receive())); + ASSERT_STREQ(L"Label", name); + + ComPtr<IAccessible2_2> textfield_ia2; + EXPECT_EQ(S_OK, textfield_accessible.CopyTo(textfield_ia2.GetAddressOf())); + ScopedBstr type(IA2_RELATION_LABELLED_BY); + IUnknown** targets; + LONG n_targets; + EXPECT_EQ(S_OK, textfield_ia2->get_relationTargetsOfType(type, 0, &targets, + &n_targets)); + ASSERT_EQ(1, n_targets); + ComPtr<IUnknown> label_unknown(targets[0]); + ComPtr<IAccessible> label_accessible; + ASSERT_EQ(S_OK, label_unknown.CopyTo(label_accessible.GetAddressOf())); + ScopedVariant role; + EXPECT_EQ(S_OK, label_accessible->get_accRole(childid_self, role.Receive())); + EXPECT_EQ(ROLE_SYSTEM_STATICTEXT, V_I4(role.ptr())); +} + // A subclass of NativeViewAccessibilityWinTest that we run twice, // first where we create an transient child widget (child = false), the second // time where we create a child widget (child = true). @@ -237,8 +289,8 @@ TEST_F(NativeViewAccessibilityWinTest, DISABLED_RetrieveAllAlerts) { ASSERT_EQ(0, n_targets); // Fire alert events on the infobars. - infobar->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); - infobar2->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + infobar->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); + infobar2->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); // Now calling get_relationTargetsOfType should retrieve the alerts. ASSERT_EQ(S_OK, root_view_accessible->get_relationTargetsOfType( @@ -282,7 +334,7 @@ TEST_F(NativeViewAccessibilityWinTest, GetAllOwnedWidgetsCrash) { TEST_F(NativeViewAccessibilityWinTest, WindowHasRoleApplication) { // We expect that our internal window object does not expose - // ROLE_SYSTEM_WINDOW, but ROLE_SYSTEM_APPLICATION instead. + // ROLE_SYSTEM_WINDOW, but ROLE_SYSTEM_PANE instead. Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW); @@ -294,8 +346,69 @@ TEST_F(NativeViewAccessibilityWinTest, WindowHasRoleApplication) { ScopedVariant childid_self(CHILDID_SELF); ScopedVariant role; EXPECT_EQ(S_OK, accessible->get_accRole(childid_self, role.Receive())); - EXPECT_EQ(role.type(), VT_I4); - EXPECT_EQ(V_I4(role.ptr()), ROLE_SYSTEM_APPLICATION); + EXPECT_EQ(VT_I4, role.type()); + EXPECT_EQ(ROLE_SYSTEM_PANE, V_I4(role.ptr())); +} + +TEST_F(NativeViewAccessibilityWinTest, Overrides) { + // We expect that our internal window object does not expose + // ROLE_SYSTEM_WINDOW, but ROLE_SYSTEM_PANE instead. + Widget widget; + Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_POPUP); + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget.Init(init_params); + + View* contents_view = new View; + widget.SetContentsView(contents_view); + + View* alert_view = new ScrollView; + alert_view->GetViewAccessibility().OverrideRole(ax::mojom::Role::kAlert); + alert_view->GetViewAccessibility().OverrideName(L"Name"); + alert_view->GetViewAccessibility().OverrideDescription("Description"); + alert_view->GetViewAccessibility().OverrideIsLeaf(); + contents_view->AddChildView(alert_view); + + // Descendant should be ignored because the parent uses OverrideIsLeaf(). + View* ignored_descendant = new View; + alert_view->AddChildView(ignored_descendant); + + ComPtr<IAccessible> content_accessible( + contents_view->GetNativeViewAccessible()); + ScopedVariant child_index(1); + + // Role. + ScopedVariant role; + EXPECT_EQ(S_OK, content_accessible->get_accRole(child_index, role.Receive())); + EXPECT_EQ(VT_I4, role.type()); + EXPECT_EQ(ROLE_SYSTEM_ALERT, V_I4(role.ptr())); + + // Name. + ScopedBstr name; + ASSERT_EQ(S_OK, content_accessible->get_accName(child_index, name.Receive())); + ASSERT_STREQ(L"Name", name); + + // Description. + ScopedBstr description; + ASSERT_EQ(S_OK, content_accessible->get_accDescription( + child_index, description.Receive())); + ASSERT_STREQ(L"Description", description); + + // Get the child accessible. + ComPtr<IDispatch> alert_dispatch; + ComPtr<IAccessible> alert_accessible; + ASSERT_EQ(S_OK, content_accessible->get_accChild( + child_index, alert_dispatch.GetAddressOf())); + ASSERT_EQ(S_OK, alert_dispatch.CopyTo(alert_accessible.GetAddressOf())); + + // Child accessible is a leaf. + LONG child_count = 0; + ASSERT_EQ(S_OK, alert_accessible->get_accChildCount(&child_count)); + ASSERT_EQ(0, child_count); + + ComPtr<IDispatch> child_dispatch; + ASSERT_EQ(E_INVALIDARG, alert_accessible->get_accChild( + child_index, child_dispatch.GetAddressOf())); + ASSERT_EQ(child_dispatch.Get(), nullptr); } } // namespace test } // namespace views diff --git a/chromium/ui/views/accessibility/view_accessibility.cc b/chromium/ui/views/accessibility/view_accessibility.cc index 577872cb4e7..133b4d4368d 100644 --- a/chromium/ui/views/accessibility/view_accessibility.cc +++ b/chromium/ui/views/accessibility/view_accessibility.cc @@ -13,16 +13,16 @@ namespace views { namespace { -bool IsValidRoleForViews(ui::AXRole role) { +bool IsValidRoleForViews(ax::mojom::Role role) { switch (role) { // These roles all have special meaning and shouldn't ever be // set on a View. - case ui::AX_ROLE_DESKTOP: - case ui::AX_ROLE_NONE: - case ui::AX_ROLE_ROOT_WEB_AREA: - case ui::AX_ROLE_SVG_ROOT: - case ui::AX_ROLE_UNKNOWN: - case ui::AX_ROLE_WEB_AREA: + case ax::mojom::Role::kDesktop: + case ax::mojom::Role::kNone: + case ax::mojom::Role::kRootWebArea: + case ax::mojom::Role::kSvgRoot: + case ax::mojom::Role::kUnknown: + case ax::mojom::Role::kWebArea: return false; default: @@ -39,7 +39,8 @@ std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) { } #endif -ViewAccessibility::ViewAccessibility(View* view) : owner_view_(view) {} +ViewAccessibility::ViewAccessibility(View* view) + : owner_view_(view), is_leaf_(false) {} ViewAccessibility::~ViewAccessibility() {} @@ -50,42 +51,64 @@ const ui::AXUniqueId& ViewAccessibility::GetUniqueId() const { void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const { // Views may misbehave if their widget is closed; return an unknown role // rather than possibly crashing. - if (!owner_view_->GetWidget() || owner_view_->GetWidget()->IsClosed()) { - data->role = ui::AX_ROLE_UNKNOWN; - data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, ui::AX_RESTRICTION_DISABLED); + views::Widget* widget = owner_view_->GetWidget(); + if (!widget || !widget->widget_delegate() || widget->IsClosed()) { + data->role = ax::mojom::Role::kUnknown; + data->SetRestriction(ax::mojom::Restriction::kDisabled); return; } owner_view_->GetAccessibleNodeData(data); - if (custom_data_.role != ui::AX_ROLE_UNKNOWN) + if (custom_data_.role != ax::mojom::Role::kUnknown) data->role = custom_data_.role; - if (custom_data_.HasStringAttribute(ui::AX_ATTR_NAME)) - data->SetName(custom_data_.GetStringAttribute(ui::AX_ATTR_NAME)); - data->location = gfx::RectF(owner_view_->GetBoundsInScreen()); - if (!data->HasStringAttribute(ui::AX_ATTR_DESCRIPTION)) { - base::string16 description; - owner_view_->GetTooltipText(gfx::Point(), &description); - data->AddStringAttribute(ui::AX_ATTR_DESCRIPTION, - base::UTF16ToUTF8(description)); + if (custom_data_.HasStringAttribute(ax::mojom::StringAttribute::kName)) { + data->SetName( + custom_data_.GetStringAttribute(ax::mojom::StringAttribute::kName)); + } + + if (custom_data_.HasStringAttribute( + ax::mojom::StringAttribute::kDescription)) { + data->SetDescription(custom_data_.GetStringAttribute( + ax::mojom::StringAttribute::kDescription)); } - data->AddStringAttribute(ui::AX_ATTR_CLASS_NAME, owner_view_->GetClassName()); + if (!data->HasStringAttribute(ax::mojom::StringAttribute::kDescription)) { + base::string16 tooltip; + owner_view_->GetTooltipText(gfx::Point(), &tooltip); + // Some screen readers announce the accessible description right after the + // accessible name. Only use the tooltip as the accessible description if + // it's different from the name, otherwise users might be puzzled as to why + // their screen reader is announcing the same thing twice. + if (tooltip != + data->GetString16Attribute(ax::mojom::StringAttribute::kName)) { + data->AddStringAttribute(ax::mojom::StringAttribute::kDescription, + base::UTF16ToUTF8(tooltip)); + } + } + + data->location = gfx::RectF(owner_view_->GetBoundsInScreen()); + data->AddStringAttribute(ax::mojom::StringAttribute::kClassName, + owner_view_->GetClassName()); if (owner_view_->IsAccessibilityFocusable()) - data->AddState(ui::AX_STATE_FOCUSABLE); + data->AddState(ax::mojom::State::kFocusable); if (!owner_view_->enabled()) - data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, ui::AX_RESTRICTION_DISABLED); + data->SetRestriction(ax::mojom::Restriction::kDisabled); if (!owner_view_->visible()) - data->AddState(ui::AX_STATE_INVISIBLE); + data->AddState(ax::mojom::State::kInvisible); if (owner_view_->context_menu_controller()) - data->AddAction(ui::AX_ACTION_SHOW_CONTEXT_MENU); + data->AddAction(ax::mojom::Action::kShowContextMenu); +} + +bool ViewAccessibility::IsLeaf() const { + return is_leaf_; } -void ViewAccessibility::OverrideRole(ui::AXRole role) { +void ViewAccessibility::OverrideRole(ax::mojom::Role role) { DCHECK(IsValidRoleForViews(role)); custom_data_.role = role; @@ -95,6 +118,21 @@ void ViewAccessibility::OverrideName(const std::string& name) { custom_data_.SetName(name); } +void ViewAccessibility::OverrideName(const base::string16& name) { + custom_data_.SetName(base::UTF16ToUTF8(name)); +} + +void ViewAccessibility::OverrideDescription(const std::string& description) { + DCHECK(!custom_data_.HasStringAttribute( + ax::mojom::StringAttribute::kDescription)); + custom_data_.AddStringAttribute(ax::mojom::StringAttribute::kDescription, + description); +} + +void ViewAccessibility::OverrideIsLeaf() { + is_leaf_ = true; +} + gfx::NativeViewAccessible ViewAccessibility::GetNativeObject() { return nullptr; } diff --git a/chromium/ui/views/accessibility/view_accessibility.h b/chromium/ui/views/accessibility/view_accessibility.h index b9c02c4fe3f..8dc947bd63a 100644 --- a/chromium/ui/views/accessibility/view_accessibility.h +++ b/chromium/ui/views/accessibility/view_accessibility.h @@ -8,7 +8,7 @@ #include <memory> #include "base/macros.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/platform/ax_unique_id.h" #include "ui/gfx/native_widget_types.h" @@ -40,18 +40,24 @@ class VIEWS_EXPORT ViewAccessibility { virtual void GetAccessibleNodeData(ui::AXNodeData* node_data) const; // - // These override anything returned from View::GetAccessibleNodeData(). + // These override accessibility information, including properties returned + // from View::GetAccessibleNodeData(). // Note that string attributes are only used if non-empty, so you can't // override a string with the empty string. // - void OverrideRole(ui::AXRole role); + void OverrideRole(ax::mojom::Role role); void OverrideName(const std::string& name); + void OverrideName(const base::string16& name); + void OverrideDescription(const std::string& description); + void OverrideIsLeaf(); // Force this node to be treated as a leaf node. virtual gfx::NativeViewAccessible GetNativeObject(); - virtual void NotifyAccessibilityEvent(ui::AXEvent event_type) {} + virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type) {} virtual const ui::AXUniqueId& GetUniqueId() const; + bool IsLeaf() const; + protected: explicit ViewAccessibility(View* view); @@ -67,6 +73,8 @@ class VIEWS_EXPORT ViewAccessibility { // anything provided by GetAccessibleNodeData(). ui::AXNodeData custom_data_; + bool is_leaf_; + DISALLOW_COPY_AND_ASSIGN(ViewAccessibility); }; diff --git a/chromium/ui/views/accessible_pane_view.cc b/chromium/ui/views/accessible_pane_view.cc index 2be372d5355..a22b6967a34 100644 --- a/chromium/ui/views/accessible_pane_view.cc +++ b/chromium/ui/views/accessible_pane_view.cc @@ -205,7 +205,7 @@ void AccessiblePaneView::SetVisible(bool flag) { } void AccessiblePaneView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_PANE; + node_data->role = ax::mojom::Role::kPane; } void AccessiblePaneView::RequestFocus() { diff --git a/chromium/ui/views/animation/bounds_animator.cc b/chromium/ui/views/animation/bounds_animator.cc index 78c22580454..13180c3f2e2 100644 --- a/chromium/ui/views/animation/bounds_animator.cc +++ b/chromium/ui/views/animation/bounds_animator.cc @@ -32,7 +32,7 @@ BoundsAnimator::BoundsAnimator(View* parent) BoundsAnimator::~BoundsAnimator() { // Reset the delegate so that we don't attempt to notify our observer from // the destructor. - container_->set_observer(NULL); + container_->set_observer(nullptr); // Delete all the animations, but don't remove any child views. We assume the // view owns us and is going to be deleted anyway. @@ -49,9 +49,7 @@ void BoundsAnimator::AnimateViewTo(View* view, const gfx::Rect& target) { if (IsAnimating(view)) { // Don't immediatly delete the animation, that might trigger a callback from // the animationcontainer. - existing_data = data_[view]; - - RemoveFromMaps(view); + existing_data = RemoveFromMaps(view); } // NOTE: we don't check if the view is already at the target location. Doing @@ -64,11 +62,11 @@ void BoundsAnimator::AnimateViewTo(View* view, const gfx::Rect& target) { data.target_bounds = target; data.animation = CreateAnimation(); - animation_to_view_[data.animation] = view; + animation_to_view_[data.animation.get()] = view; data.animation->Show(); - CleanupData(true, &existing_data, NULL); + CleanupData(true, &existing_data, nullptr); } void BoundsAnimator::SetTargetBounds(View* view, const gfx::Rect& target) { @@ -86,29 +84,29 @@ gfx::Rect BoundsAnimator::GetTargetBounds(View* view) { return data_[view].target_bounds; } -void BoundsAnimator::SetAnimationForView(View* view, - SlideAnimation* animation) { +void BoundsAnimator::SetAnimationForView( + View* view, + std::unique_ptr<SlideAnimation> animation) { DCHECK(animation); - std::unique_ptr<SlideAnimation> animation_wrapper(animation); - if (!IsAnimating(view)) return; // We delay deleting the animation until the end so that we don't prematurely // send out notification that we're done. - std::unique_ptr<Animation> old_animation(ResetAnimationForView(view)); + std::unique_ptr<Animation> old_animation = ResetAnimationForView(view); - data_[view].animation = animation_wrapper.release(); - animation_to_view_[animation] = view; + SlideAnimation* animation_ptr = animation.get(); + data_[view].animation = std::move(animation); + animation_to_view_[animation_ptr] = view; - animation->set_delegate(this); - animation->SetContainer(container_.get()); - animation->Show(); + animation_ptr->set_delegate(this); + animation_ptr->SetContainer(container_.get()); + animation_ptr->Show(); } const SlideAnimation* BoundsAnimator::GetAnimationForView(View* view) { - return !IsAnimating(view) ? NULL : data_[view].animation; + return !IsAnimating(view) ? nullptr : data_[view].animation.get(); } void BoundsAnimator::SetAnimationDelegate( @@ -116,7 +114,7 @@ void BoundsAnimator::SetAnimationDelegate( std::unique_ptr<AnimationDelegate> delegate) { DCHECK(IsAnimating(view)); - data_[view].delegate = delegate.release(); + data_[view].delegate = std::move(delegate); } void BoundsAnimator::StopAnimatingView(View* view) { @@ -157,46 +155,51 @@ void BoundsAnimator::RemoveObserver(BoundsAnimatorObserver* observer) { observers_.RemoveObserver(observer); } -SlideAnimation* BoundsAnimator::CreateAnimation() { - SlideAnimation* animation = new SlideAnimation(this); +std::unique_ptr<gfx::SlideAnimation> BoundsAnimator::CreateAnimation() { + std::unique_ptr<gfx::SlideAnimation> animation = + std::make_unique<SlideAnimation>(this); animation->SetContainer(container_.get()); animation->SetSlideDuration(animation_duration_ms_); animation->SetTweenType(tween_type_); return animation; } -void BoundsAnimator::RemoveFromMaps(View* view) { +BoundsAnimator::Data::Data() = default; +BoundsAnimator::Data::Data(Data&&) = default; +BoundsAnimator::Data& BoundsAnimator::Data::operator=(Data&&) = default; +BoundsAnimator::Data::~Data() = default; + +BoundsAnimator::Data BoundsAnimator::RemoveFromMaps(View* view) { DCHECK(data_.count(view) > 0); - DCHECK(animation_to_view_.count(data_[view].animation) > 0); + DCHECK(animation_to_view_.count(data_[view].animation.get()) > 0); - animation_to_view_.erase(data_[view].animation); + Data old_data = std::move(data_[view]); data_.erase(view); + animation_to_view_.erase(old_data.animation.get()); + return old_data; } void BoundsAnimator::CleanupData(bool send_cancel, Data* data, View* view) { if (send_cancel && data->delegate) - data->delegate->AnimationCanceled(data->animation); + data->delegate->AnimationCanceled(data->animation.get()); - delete data->delegate; - data->delegate = NULL; + data->delegate.reset(); if (data->animation) { - data->animation->set_delegate(NULL); - delete data->animation; - data->animation = NULL; + data->animation->set_delegate(nullptr); + data->animation.reset(); } } -Animation* BoundsAnimator::ResetAnimationForView(View* view) { +std::unique_ptr<Animation> BoundsAnimator::ResetAnimationForView(View* view) { if (!IsAnimating(view)) - return NULL; + return nullptr; - Animation* old_animation = data_[view].animation; - animation_to_view_.erase(old_animation); - data_[view].animation = NULL; + std::unique_ptr<Animation> old_animation = std::move(data_[view].animation); + animation_to_view_.erase(old_animation.get()); // Reset the delegate so that we don't attempt any processing when the // animation calls us back. - old_animation->set_delegate(NULL); + old_animation->set_delegate(nullptr); return old_animation; } @@ -207,10 +210,8 @@ void BoundsAnimator::AnimationEndedOrCanceled(const Animation* animation, View* view = animation_to_view_[animation]; DCHECK(view); - // Make a copy of the data as Remove empties out the maps. - Data data = data_[view]; - - RemoveFromMaps(view); + // Save the data for later clean up. + Data data = RemoveFromMaps(view); if (data.delegate) { if (type == ANIMATION_ENDED) { diff --git a/chromium/ui/views/animation/bounds_animator.h b/chromium/ui/views/animation/bounds_animator.h index 7f4208985b2..5fdb04dd713 100644 --- a/chromium/ui/views/animation/bounds_animator.h +++ b/chromium/ui/views/animation/bounds_animator.h @@ -58,9 +58,9 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate, // animating its current bounds is returned. gfx::Rect GetTargetBounds(View* view); - // Sets the animation for the specified view. BoundsAnimator takes ownership - // of the specified animation. - void SetAnimationForView(View* view, gfx::SlideAnimation* animation); + // Sets the animation for the specified view. + void SetAnimationForView(View* view, + std::unique_ptr<gfx::SlideAnimation> animation); // Returns the animation for the specified view. BoundsAnimator owns the // returned Animation. @@ -98,12 +98,15 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate, protected: // Creates the animation to use for animating views. - virtual gfx::SlideAnimation* CreateAnimation(); + virtual std::unique_ptr<gfx::SlideAnimation> CreateAnimation(); private: // Tracks data about the view being animated. struct Data { - Data() : animation(NULL), delegate(NULL) {} + Data(); + Data(Data&&); + Data& operator=(Data&&); + ~Data(); // The initial bounds. gfx::Rect start_bounds; @@ -111,11 +114,11 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate, // Target bounds. gfx::Rect target_bounds; - // The animation. We own this. - gfx::SlideAnimation* animation; + // The animation. + std::unique_ptr<gfx::SlideAnimation> animation; - // Delegate for the animation, may be null. We own this. - gfx::AnimationDelegate* delegate; + // Delegate for the animation, may be nullptr. + std::unique_ptr<gfx::AnimationDelegate> delegate; }; // Used by AnimationEndedOrCanceled. @@ -128,9 +131,9 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate, typedef std::map<const gfx::Animation*, View*> AnimationToViewMap; - // Removes references to |view| and its animation. This does NOT delete the - // animation or delegate. - void RemoveFromMaps(View* view); + // Removes references to |view| and its animation. Returns the data for the + // caller to handle cleanup. + Data RemoveFromMaps(View* view); // Does the necessary cleanup for |data|. If |send_cancel| is true and a // delegate has been installed on |data| AnimationCanceled is invoked on it. @@ -139,7 +142,7 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate, // Used when changing the animation for a view. This resets the maps for // the animation used by view and returns the current animation. Ownership // of the returned animation passes to the caller. - gfx::Animation* ResetAnimationForView(View* view); + std::unique_ptr<gfx::Animation> ResetAnimationForView(View* view); // Invoked from AnimationEnded and AnimationCanceled. void AnimationEndedOrCanceled(const gfx::Animation* animation, diff --git a/chromium/ui/views/animation/bounds_animator_unittest.cc b/chromium/ui/views/animation/bounds_animator_unittest.cc index 000c0c3efbc..489f72392b1 100644 --- a/chromium/ui/views/animation/bounds_animator_unittest.cc +++ b/chromium/ui/views/animation/bounds_animator_unittest.cc @@ -19,22 +19,6 @@ using gfx::TestAnimationDelegate; namespace views { namespace { -class TestBoundsAnimator : public BoundsAnimator { - public: - explicit TestBoundsAnimator(View* view) : BoundsAnimator(view) { - } - - protected: - SlideAnimation* CreateAnimation() override { - SlideAnimation* animation = BoundsAnimator::CreateAnimation(); - animation->SetSlideDuration(10); - return animation; - } - - private: - DISALLOW_COPY_AND_ASSIGN(TestBoundsAnimator); -}; - class OwnedDelegate : public gfx::AnimationDelegate { public: OwnedDelegate() {} @@ -98,17 +82,18 @@ class BoundsAnimatorTest : public testing::Test { child_(new TestView()), animator_(&parent_) { parent_.AddChildView(child_); + animator_.SetAnimationDuration(10); } TestView* parent() { return &parent_; } TestView* child() { return child_; } - TestBoundsAnimator* animator() { return &animator_; } + BoundsAnimator* animator() { return &animator_; } private: base::test::ScopedTaskEnvironment scoped_task_environment_; TestView parent_; TestView* child_; // Owned by |parent_|. - TestBoundsAnimator animator_; + BoundsAnimator animator_; DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorTest); }; diff --git a/chromium/ui/views/animation/ink_drop.h b/chromium/ui/views/animation/ink_drop.h index 0664440b4de..3569e01f261 100644 --- a/chromium/ui/views/animation/ink_drop.h +++ b/chromium/ui/views/animation/ink_drop.h @@ -36,11 +36,12 @@ class VIEWS_EXPORT InkDrop { // Animates from the current InkDropState to |ink_drop_state|. virtual void AnimateToState(InkDropState ink_drop_state) = 0; - // Immediately snaps the InkDropState to ACTIVATED. This more specific - // implementation of the non-existent SnapToState(InkDropState) function is - // the only one available because it was the only InkDropState that clients - // needed to skip animations for. + // Immediately snaps the InkDropState to ACTIVATED and HIDDEN specifically. + // These are more specific implementations of the non-existent + // SnapToState(InkDropState) function are the only ones available because they + // were the only InkDropState that clients needed to skip animations for. virtual void SnapToActivated() = 0; + virtual void SnapToHidden() = 0; // Enables or disables the hover state. virtual void SetHovered(bool is_hovered) = 0; diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc index 31f307b75e4..5a769f05902 100644 --- a/chromium/ui/views/animation/ink_drop_host_view.cc +++ b/chromium/ui/views/animation/ink_drop_host_view.cc @@ -221,11 +221,21 @@ void InkDropHostView::AnimateInkDrop(InkDropState state, GetInkDrop()->AnimateToState(state); } +void InkDropHostView::ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) { + // If we're being removed hide the ink-drop so if we're highlighted now the + // highlight won't be active if we're added back again. + if (!details.is_add && details.child == this && ink_drop_) { + GetInkDrop()->SnapToHidden(); + GetInkDrop()->SetHovered(false); + } + View::ViewHierarchyChanged(details); +} + void InkDropHostView::OnBoundsChanged(const gfx::Rect& previous_bounds) { if (ink_drop_) ink_drop_->HostSizeChanged(size()); - if (ink_drop_mask_) - ink_drop_mask_->UpdateLayerSize(size()); + UpdateInkDropMaskLayerSize(size()); } void InkDropHostView::VisibilityChanged(View* starting_from, bool is_visible) { @@ -300,11 +310,19 @@ void InkDropHostView::ResetInkDropMask() { ink_drop_mask_.reset(); } +void InkDropHostView::UpdateInkDropMaskLayerSize(const gfx::Size& new_size) { + if (ink_drop_mask_) + ink_drop_mask_->UpdateLayerSize(new_size); +} + std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() { std::unique_ptr<InkDropImpl> ink_drop = std::make_unique<InkDropImpl>(this, size()); - ink_drop->SetAutoHighlightMode( - views::InkDropImpl::AutoHighlightMode::HIDE_ON_RIPPLE); + views::InkDropImpl::AutoHighlightMode mode = + PlatformStyle::kUseRipples + ? views::InkDropImpl::AutoHighlightMode::HIDE_ON_RIPPLE + : views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE; + ink_drop->SetAutoHighlightMode(mode); return ink_drop; } diff --git a/chromium/ui/views/animation/ink_drop_host_view.h b/chromium/ui/views/animation/ink_drop_host_view.h index 8ac475fa752..34ea050d06a 100644 --- a/chromium/ui/views/animation/ink_drop_host_view.h +++ b/chromium/ui/views/animation/ink_drop_host_view.h @@ -95,6 +95,8 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost { gfx::Point GetInkDropCenterBasedOnLastEvent() const; // View: + void ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void VisibilityChanged(View* starting_from, bool is_visible) override; void OnFocus() override; @@ -128,6 +130,10 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost { void ResetInkDropMask(); + // Updates the ink drop mask layer size to |new_size|. It does nothing if + // |ink_drop_mask_| is null. + void UpdateInkDropMaskLayerSize(const gfx::Size& new_size); + // Returns an InkDropImpl configured to work well with a // flood-fill ink drop ripple. std::unique_ptr<InkDropImpl> CreateDefaultFloodFillInkDropImpl(); diff --git a/chromium/ui/views/animation/ink_drop_impl.cc b/chromium/ui/views/animation/ink_drop_impl.cc index 5841c7889fe..f052e387114 100644 --- a/chromium/ui/views/animation/ink_drop_impl.cc +++ b/chromium/ui/views/animation/ink_drop_impl.cc @@ -343,7 +343,7 @@ void InkDropImpl::HideHighlightOnRippleHiddenState::AnimationStarted( // TODO(bruthig): Investigate if the animation framework can address this // issue instead. See https://crbug.com/663335. if (GetInkDrop()->ink_drop_ripple_) - GetInkDrop()->ink_drop_ripple_->HideImmediately(); + GetInkDrop()->ink_drop_ripple_->SnapToHidden(); GetInkDrop()->SetHighlightState( state_factory()->CreateVisibleState(base::TimeDelta(), false)); } @@ -647,6 +647,13 @@ void InkDropImpl::SnapToActivated() { ink_drop_ripple_->SnapToActivated(); } +void InkDropImpl::SnapToHidden() { + DestroyHiddenTargetedAnimations(); + if (!ink_drop_ripple_) + return; + ink_drop_ripple_->SnapToHidden(); +} + void InkDropImpl::SetHovered(bool is_hovered) { is_hovered_ = is_hovered; highlight_state_->OnHoverChanged(); diff --git a/chromium/ui/views/animation/ink_drop_impl.h b/chromium/ui/views/animation/ink_drop_impl.h index 47dd80aa23d..98ec237e3f7 100644 --- a/chromium/ui/views/animation/ink_drop_impl.h +++ b/chromium/ui/views/animation/ink_drop_impl.h @@ -66,6 +66,7 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop, InkDropState GetTargetInkDropState() const override; void AnimateToState(InkDropState ink_drop_state) override; void SnapToActivated() override; + void SnapToHidden() override; void SetHovered(bool is_hovered) override; void SetFocused(bool is_focused) override; bool IsHighlightFadingInOrVisible() const override; diff --git a/chromium/ui/views/animation/ink_drop_mask.cc b/chromium/ui/views/animation/ink_drop_mask.cc index 05bd983cf1a..a2d2adb366e 100644 --- a/chromium/ui/views/animation/ink_drop_mask.cc +++ b/chromium/ui/views/animation/ink_drop_mask.cc @@ -35,7 +35,7 @@ void InkDropMask::OnDeviceScaleFactorChanged(float old_device_scale_factor, RoundRectInkDropMask::RoundRectInkDropMask(const gfx::Size& layer_size, const gfx::InsetsF& mask_insets, - int corner_radius) + float corner_radius) : InkDropMask(layer_size), mask_insets_(mask_insets), corner_radius_(corner_radius) {} @@ -52,10 +52,8 @@ void RoundRectInkDropMask::OnPaintLayer(const ui::PaintContext& context) { gfx::RectF masking_bound(layer()->bounds()); masking_bound.Inset(mask_insets_); - const gfx::Rect masking_bound_scaled = - gfx::ScaleToRoundedRect(gfx::ToNearestRect(masking_bound), dsf); - recorder.canvas()->DrawRoundRect(masking_bound_scaled, corner_radius_ * dsf, - flags); + recorder.canvas()->DrawRoundRect(gfx::ScaleRect(masking_bound, dsf), + corner_radius_ * dsf, flags); } // CircleInkDropMask diff --git a/chromium/ui/views/animation/ink_drop_mask.h b/chromium/ui/views/animation/ink_drop_mask.h index 8899e5bf389..debfb1604e2 100644 --- a/chromium/ui/views/animation/ink_drop_mask.h +++ b/chromium/ui/views/animation/ink_drop_mask.h @@ -47,14 +47,14 @@ class VIEWS_EXPORT RoundRectInkDropMask : public InkDropMask { public: RoundRectInkDropMask(const gfx::Size& layer_size, const gfx::InsetsF& mask_insets, - int corner_radius); + float corner_radius); private: // Overriden from InkDropMask: void OnPaintLayer(const ui::PaintContext& context) override; gfx::InsetsF mask_insets_; - int corner_radius_; + float corner_radius_; DISALLOW_COPY_AND_ASSIGN(RoundRectInkDropMask); }; diff --git a/chromium/ui/views/animation/ink_drop_ripple.cc b/chromium/ui/views/animation/ink_drop_ripple.cc index f6360a80947..ea16770dd00 100644 --- a/chromium/ui/views/animation/ink_drop_ripple.cc +++ b/chromium/ui/views/animation/ink_drop_ripple.cc @@ -91,7 +91,7 @@ bool InkDropRipple::IsVisible() { return GetRootLayer()->visible(); } -void InkDropRipple::HideImmediately() { +void InkDropRipple::SnapToHidden() { AbortAllAnimations(); SetStateToHidden(); target_ink_drop_state_ = InkDropState::HIDDEN; diff --git a/chromium/ui/views/animation/ink_drop_ripple.h b/chromium/ui/views/animation/ink_drop_ripple.h index 6f05f7f6c0a..645abff0204 100644 --- a/chromium/ui/views/animation/ink_drop_ripple.h +++ b/chromium/ui/views/animation/ink_drop_ripple.h @@ -70,7 +70,7 @@ class VIEWS_EXPORT InkDropRipple { // // NOTE: This will NOT raise Animation(Started|Ended) events for the state // transition to HIDDEN! - void HideImmediately(); + void SnapToHidden(); // Immediately snaps the ink drop to the ACTIVATED target state. All pending // animations are aborted. Events will be raised for the pending animations diff --git a/chromium/ui/views/animation/ink_drop_ripple_unittest.cc b/chromium/ui/views/animation/ink_drop_ripple_unittest.cc index 2bb50772568..0184bc4c84b 100644 --- a/chromium/ui/views/animation/ink_drop_ripple_unittest.cc +++ b/chromium/ui/views/animation/ink_drop_ripple_unittest.cc @@ -250,7 +250,7 @@ TEST_P(InkDropRippleTest, InkDropStatesPersistWhenCallingAnimateToState) { ink_drop_ripple_->target_ink_drop_state()); } -TEST_P(InkDropRippleTest, HideImmediatelyWithoutActiveAnimations) { +TEST_P(InkDropRippleTest, SnapToHiddenWithoutActiveAnimations) { ink_drop_ripple_->AnimateToState(views::InkDropState::ACTION_PENDING); test_api_->CompleteAnimations(); EXPECT_EQ(1, observer_.last_animation_started_ordinal()); @@ -259,7 +259,7 @@ TEST_P(InkDropRippleTest, HideImmediatelyWithoutActiveAnimations) { EXPECT_FALSE(test_api_->HasActiveAnimations()); EXPECT_NE(InkDropState::HIDDEN, ink_drop_ripple_->target_ink_drop_state()); - ink_drop_ripple_->HideImmediately(); + ink_drop_ripple_->SnapToHidden(); EXPECT_FALSE(test_api_->HasActiveAnimations()); EXPECT_EQ(views::InkDropState::HIDDEN, @@ -272,8 +272,8 @@ TEST_P(InkDropRippleTest, HideImmediatelyWithoutActiveAnimations) { } // Verifies all active animations are aborted and the InkDropState is set to -// HIDDEN after invoking HideImmediately(). -TEST_P(InkDropRippleTest, HideImmediatelyWithActiveAnimations) { +// HIDDEN after invoking SnapToHidden(). +TEST_P(InkDropRippleTest, SnapToHiddenWithActiveAnimations) { // TODO(bruthig): Re-enable! For some reason these tests fail on some win // trunk builds. See crbug.com/731811. if (!gfx::Animation::ShouldRenderRichAnimation()) @@ -284,7 +284,7 @@ TEST_P(InkDropRippleTest, HideImmediatelyWithActiveAnimations) { EXPECT_NE(InkDropState::HIDDEN, ink_drop_ripple_->target_ink_drop_state()); EXPECT_EQ(1, observer_.last_animation_started_ordinal()); - ink_drop_ripple_->HideImmediately(); + ink_drop_ripple_->SnapToHidden(); EXPECT_FALSE(test_api_->HasActiveAnimations()); EXPECT_EQ(views::InkDropState::HIDDEN, diff --git a/chromium/ui/views/animation/ink_drop_stub.cc b/chromium/ui/views/animation/ink_drop_stub.cc index 2883d89db82..9a8237b3c11 100644 --- a/chromium/ui/views/animation/ink_drop_stub.cc +++ b/chromium/ui/views/animation/ink_drop_stub.cc @@ -20,6 +20,8 @@ void InkDropStub::AnimateToState(InkDropState state) {} void InkDropStub::SnapToActivated() {} +void InkDropStub::SnapToHidden() {} + void InkDropStub::SetHovered(bool is_hovered) {} void InkDropStub::SetFocused(bool is_hovered) {} diff --git a/chromium/ui/views/animation/ink_drop_stub.h b/chromium/ui/views/animation/ink_drop_stub.h index f9f6e728b56..86ed8829824 100644 --- a/chromium/ui/views/animation/ink_drop_stub.h +++ b/chromium/ui/views/animation/ink_drop_stub.h @@ -23,6 +23,7 @@ class VIEWS_EXPORT InkDropStub : public InkDrop { InkDropState GetTargetInkDropState() const override; void AnimateToState(InkDropState state) override; void SnapToActivated() override; + void SnapToHidden() override; void SetHovered(bool is_hovered) override; void SetFocused(bool is_hovered) override; bool IsHighlightFadingInOrVisible() const override; diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc index 797fb98889c..e2292a8f620 100644 --- a/chromium/ui/views/bubble/bubble_border.cc +++ b/chromium/ui/views/bubble/bubble_border.cc @@ -8,12 +8,12 @@ #include <vector> #include "base/logging.h" +#include "base/no_destructor.h" #include "cc/paint/paint_flags.h" #include "third_party/skia/include/core/SkDrawLooper.h" #include "third_party/skia/include/core/SkPath.h" #include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/path.h" #include "ui/gfx/scoped_canvas.h" @@ -65,17 +65,6 @@ namespace { // The border is stroked at 1px, but for the purposes of reserving space we have // to deal in dip coordinates, so round up to 1dip. const int kBorderThicknessDip = 1; -const int kBorderStrokeThicknessPx = 1; - -// Blur and offset values for the two shadows drawn around each dialog. The -// values are all in dip. -const int kSmallShadowVerticalOffset = 2; -const int kSmallShadowBlur = 4; -const SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33); - -const int kLargeShadowVerticalOffset = 2; -const int kLargeShadowBlur = 6; -const SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A); bool UseMaterialDesign() { return ui::MaterialDesignController::IsSecondaryUiMaterial(); @@ -199,6 +188,14 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color) BubbleBorder::~BubbleBorder() {} +// static +gfx::Insets BubbleBorder::GetBorderAndShadowInsets() { + constexpr gfx::Insets blur(kShadowBlur + kBorderThicknessDip); + constexpr gfx::Insets offset(-kShadowVerticalOffset, 0, kShadowVerticalOffset, + 0); + return blur + offset; +} + void BubbleBorder::set_paint_arrow(ArrowPaintType value) { if (UseMaterialDesign()) return; @@ -368,15 +365,8 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) { } gfx::Insets BubbleBorder::GetInsets() const { - if (UseMaterialDesign()) { - if (shadow_ == NO_ASSETS) - return gfx::Insets(); - - gfx::Insets blur(kLargeShadowBlur); - gfx::Insets offset(-kLargeShadowVerticalOffset, 0, - kLargeShadowVerticalOffset, 0); - return blur + offset; - } + if (UseMaterialDesign()) + return (shadow_ == NO_ASSETS) ? gfx::Insets() : GetBorderAndShadowInsets(); // The insets contain the stroke and shadow pixels outside the bubble fill. const int inset = GetBorderThickness(); @@ -397,6 +387,33 @@ gfx::Size BubbleBorder::GetMinimumSize() const { return GetSizeForContentsSize(gfx::Size()); } +// static +const cc::PaintFlags& BubbleBorder::GetBorderAndShadowFlags() { + // This object is always the same, so construct it once and cache. + static const base::NoDestructor<cc::PaintFlags> flags([] { + cc::PaintFlags f; + constexpr SkColor kBorderColor = SkColorSetA(SK_ColorBLACK, 0x26); + f.setColor(kBorderColor); + f.setAntiAlias(true); + + constexpr int kSmallShadowVerticalOffset = 2; + constexpr int kSmallShadowBlur = 4; + constexpr SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33); + constexpr SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A); + // gfx::ShadowValue counts blur pixels both inside and outside the shape, + // whereas these blur values only describe the outside portion, hence they + // must be doubled. + f.setLooper(gfx::CreateShadowDrawLooper({ + {gfx::Vector2d(0, kSmallShadowVerticalOffset), 2 * kSmallShadowBlur, + kSmallShadowColor}, + {gfx::Vector2d(0, kShadowVerticalOffset), 2 * kShadowBlur, + kLargeShadowColor}, + })); + return f; + }()); + return *flags; +} + gfx::Size BubbleBorder::GetSizeForContentsSize( const gfx::Size& contents_size) const { // Enlarge the contents size by the thickness of the border images. @@ -526,28 +543,11 @@ void BubbleBorder::PaintMd(const View& view, gfx::Canvas* canvas) { gfx::ScopedCanvas scoped(canvas); - cc::PaintFlags flags; - std::vector<gfx::ShadowValue> shadows; - // gfx::ShadowValue counts blur pixels both inside and outside the shape, - // whereas these blur values only describe the outside portion, hence they - // must be doubled. - shadows.emplace_back(gfx::Vector2d(0, kSmallShadowVerticalOffset), - 2 * kSmallShadowBlur, kSmallShadowColor); - shadows.emplace_back(gfx::Vector2d(0, kLargeShadowVerticalOffset), - 2 * kLargeShadowBlur, kLargeShadowColor); - flags.setLooper(gfx::CreateShadowDrawLooper(shadows)); - flags.setColor(SkColorSetA(SK_ColorBLACK, 0x26)); - flags.setAntiAlias(true); - SkRRect r_rect = GetClientRect(view); canvas->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference, true /*doAntiAlias*/); - // The border is drawn outside the content area. - const SkScalar one_pixel = - SkFloatToScalar(kBorderStrokeThicknessPx / canvas->image_scale()); - r_rect.inset(-one_pixel, -one_pixel); - canvas->sk_canvas()->drawRRect(r_rect, flags); + DrawBorderAndShadow(std::move(r_rect), &cc::PaintCanvas::drawRRect, canvas); } void BubbleBorder::PaintNoAssets(const View& view, gfx::Canvas* canvas) { diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h index fdf0c3604b8..46531ed02f6 100644 --- a/chromium/ui/views/bubble/bubble_border.h +++ b/chromium/ui/views/bubble/bubble_border.h @@ -11,6 +11,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "build/build_config.h" +#include "ui/gfx/canvas.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/background.h" #include "ui/views/border.h" @@ -135,6 +136,11 @@ class VIEWS_EXPORT BubbleBorder : public Border { PAINT_NONE, }; + // Specific to MD bubbles: size of shadow blur (outside the bubble) and + // vertical offset, both in DIP. + static constexpr int kShadowBlur = 6; + static constexpr int kShadowVerticalOffset = 2; + BubbleBorder(Arrow arrow, Shadow shadow, SkColor color); ~BubbleBorder() override; @@ -166,6 +172,26 @@ class VIEWS_EXPORT BubbleBorder : public Border { a : static_cast<Arrow>(a ^ BOTTOM); } + // Returns the insets required by a border and shadow. This is only used for + // MD bubbles. + static gfx::Insets GetBorderAndShadowInsets(); + + // Draws a border and shadow outside the |rect| on |canvas|, using |draw| as + // the draw function. Templated so as to accept either SkRect or SkRRect. + template <typename T> + static void DrawBorderAndShadow( + T rect, + void (cc::PaintCanvas::*draw)(const T&, const cc::PaintFlags&), + gfx::Canvas* canvas) { + // Provide a 1 px border outside the bounds. + const int kBorderStrokeThicknessPx = 1; + const SkScalar one_pixel = + SkFloatToScalar(kBorderStrokeThicknessPx / canvas->image_scale()); + rect.outset(one_pixel, one_pixel); + + (canvas->sk_canvas()->*draw)(rect, GetBorderAndShadowFlags()); + } + // Get or set the arrow type. void set_arrow(Arrow arrow) { arrow_ = arrow; } Arrow arrow() const { return arrow_; } @@ -233,6 +259,10 @@ class VIEWS_EXPORT BubbleBorder : public Border { FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetBoundsOriginTest); FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, ShadowTypes); + // Returns the paint flags to use for painting the border and shadow. This is + // only used for MD bubbles. + static const cc::PaintFlags& GetBorderAndShadowFlags(); + // The border and arrow stroke size used in image assets, in pixels. static const int kStroke; diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.cc b/chromium/ui/views/bubble/bubble_dialog_delegate.cc index aa98ca418f7..9f766e72100 100644 --- a/chromium/ui/views/bubble/bubble_dialog_delegate.cc +++ b/chromium/ui/views/bubble/bubble_dialog_delegate.cc @@ -320,13 +320,14 @@ void BubbleDialogDelegateView::HandleVisibilityChanged(Widget* widget, anchor_widget()->GetTopLevelWidget()->SetAlwaysRenderAsActive(visible); } - // Fire AX_EVENT_ALERT for bubbles marked as AX_ROLE_ALERT_DIALOG; this - // instructs accessibility tools to read the bubble in its entirety rather - // than just its title and initially focused view. See - // http://crbug.com/474622 for details. + // Fire ax::mojom::Event::kAlert for bubbles marked as + // ax::mojom::Role::kAlertDialog; this instructs accessibility tools to read + // the bubble in its entirety rather than just its title and initially focused + // view. See http://crbug.com/474622 for details. if (widget == GetWidget() && visible) { - if (GetAccessibleWindowRole() == ui::AX_ROLE_ALERT_DIALOG) - widget->GetRootView()->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + if (GetAccessibleWindowRole() == ax::mojom::Role::kAlertDialog) + widget->GetRootView()->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, + true); } } diff --git a/chromium/ui/views/bubble/tooltip_icon.cc b/chromium/ui/views/bubble/tooltip_icon.cc index b3a5ca6e8f7..de30b6dcc62 100644 --- a/chromium/ui/views/bubble/tooltip_icon.cc +++ b/chromium/ui/views/bubble/tooltip_icon.cc @@ -55,7 +55,7 @@ void TooltipIcon::OnGestureEvent(ui::GestureEvent* event) { } void TooltipIcon::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_TOOLTIP; + node_data->role = ax::mojom::Role::kTooltip; node_data->SetName(tooltip_); } diff --git a/chromium/ui/views/bubble/tray_bubble_view.cc b/chromium/ui/views/bubble/tray_bubble_view.cc index 392cbd14a30..fe4ba9727f6 100644 --- a/chromium/ui/views/bubble/tray_bubble_view.cc +++ b/chromium/ui/views/bubble/tray_bubble_view.cc @@ -322,7 +322,7 @@ void TrayBubbleView::OnBeforeBubbleWidgetInit(Widget::InitParams* params, Widget* bubble_widget) const { // Apply a WM-provided shadow (see ui/wm/core/). params->shadow_type = Widget::InitParams::SHADOW_TYPE_DROP; - params->shadow_elevation = wm::ShadowElevation::LARGE; + params->shadow_elevation = wm::kShadowElevationActiveWindow; } void TrayBubbleView::OnWidgetClosing(Widget* widget) { @@ -332,7 +332,8 @@ void TrayBubbleView::OnWidgetClosing(Widget* widget) { BubbleDialogDelegateView::OnWidgetClosing(widget); --g_current_tray_bubble_showing_count_; - DCHECK_GE(g_current_tray_bubble_showing_count_, 0); + DCHECK_GE(g_current_tray_bubble_showing_count_, 0) + << "Closing " << widget->GetName(); } void TrayBubbleView::OnWidgetActivationChanged(Widget* widget, bool active) { @@ -360,7 +361,10 @@ void TrayBubbleView::GetWidgetHitTestMask(gfx::Path* mask) const { } base::string16 TrayBubbleView::GetAccessibleWindowTitle() const { - return delegate_->GetAccessibleNameForBubble(); + if (delegate_) + return delegate_->GetAccessibleNameForBubble(); + else + return base::string16(); } gfx::Size TrayBubbleView::CalculatePreferredSize() const { @@ -421,7 +425,7 @@ void TrayBubbleView::OnMouseExited(const ui::MouseEvent& event) { void TrayBubbleView::GetAccessibleNodeData(ui::AXNodeData* node_data) { if (delegate_ && CanActivate()) { - node_data->role = ui::AX_ROLE_WINDOW; + node_data->role = ax::mojom::Role::kWindow; node_data->SetName(delegate_->GetAccessibleNameForBubble()); } } @@ -438,7 +442,8 @@ void TrayBubbleView::MouseMovedOutOfHost() { // The mouse was accidentally over the bubble when it opened and the AutoClose // logic was not activated. Now that the user did move the mouse we tell the // delegate to disable AutoClose. - delegate_->OnMouseEnteredView(); + if (delegate_) + delegate_->OnMouseEnteredView(); mouse_actively_entered_ = true; mouse_watcher_->Stop(); } diff --git a/chromium/ui/views/cocoa/bridged_native_widget.h b/chromium/ui/views/cocoa/bridged_native_widget.h index 67a0d56ee63..64be7882515 100644 --- a/chromium/ui/views/cocoa/bridged_native_widget.h +++ b/chromium/ui/views/cocoa/bridged_native_widget.h @@ -12,6 +12,7 @@ #import "base/mac/scoped_nsobject.h" #include "base/macros.h" +#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #import "ui/accelerated_widget_mac/accelerated_widget_mac.h" #include "ui/base/ime/input_method_delegate.h" #include "ui/compositor/layer_owner.h" @@ -138,7 +139,7 @@ class VIEWS_EXPORT BridgedNativeWidget // Transition the window into or out of fullscreen. This will immediately // invert the value of target_fullscreen_state(). - void ToggleDesiredFullscreenState(); + void ToggleDesiredFullscreenState(bool async = false); // Called by the NSWindowDelegate when the size of the window changes. void OnSizeChanged(); @@ -324,6 +325,7 @@ class VIEWS_EXPORT BridgedNativeWidget base::scoped_nsobject<NSView> compositor_superview_; std::unique_ptr<ui::AcceleratedWidgetMac> compositor_widget_; std::unique_ptr<ui::Compositor> compositor_; + viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_; // Tracks the bounds when the window last started entering fullscreen. Used to // provide an answer for GetRestoredBounds(), but not ever sent to Cocoa (it diff --git a/chromium/ui/views/cocoa/bridged_native_widget.mm b/chromium/ui/views/cocoa/bridged_native_widget.mm index 7c5c25f2ce0..3c6e9903d7d 100644 --- a/chromium/ui/views/cocoa/bridged_native_widget.mm +++ b/chromium/ui/views/cocoa/bridged_native_widget.mm @@ -836,21 +836,15 @@ void BridgedNativeWidget::OnFullscreenTransitionComplete( return; } + // The transition completed, but into the wrong state. This can happen when + // there are calls to change the fullscreen state whilst mid-transition. // First update to reflect reality so that OnTargetFullscreenStateChanged() // expects the change. target_fullscreen_state_ = actual_fullscreen_state; - ToggleDesiredFullscreenState(); - - // Usually ToggleDesiredFullscreenState() sets |in_fullscreen_transition_| via - // OnFullscreenTransitionStart(). When it does not, it means Cocoa ignored the - // toggleFullScreen: request. This can occur when the fullscreen transition - // fails and Cocoa is *about* to send windowDidFailToEnterFullScreen:. - // Annoyingly, for this case, Cocoa first sends windowDidExitFullScreen:. - if (in_fullscreen_transition_) - DCHECK_NE(target_fullscreen_state_, actual_fullscreen_state); + ToggleDesiredFullscreenState(true /* async */); } -void BridgedNativeWidget::ToggleDesiredFullscreenState() { +void BridgedNativeWidget::ToggleDesiredFullscreenState(bool async) { // If there is currently an animation into or out of fullscreen, then AppKit // emits the string "not in fullscreen state" to stdio and does nothing. For // this case, schedule a transition back into the desired state when the @@ -878,7 +872,18 @@ void BridgedNativeWidget::ToggleDesiredFullscreenState() { // This will be reset when a transition out of fullscreen completes. gfx::SetNSWindowCanFullscreen(window_, true); - [window_ toggleFullScreen:nil]; + // Until 10.13, AppKit would obey a call to -toggleFullScreen: made inside + // OnFullscreenTransitionComplete(). Starting in 10.13, it behaves as though + // the transition is still in progress and just emits "not in a fullscreen + // state" when trying to exit fullscreen in the same runloop that entered it. + // To handle this case, invoke -toggleFullScreen: asynchronously. + if (async) { + [window_ performSelector:@selector(toggleFullScreen:) + withObject:nil + afterDelay:0]; + } else { + [window_ toggleFullScreen:nil]; + } } void BridgedNativeWidget::OnSizeChanged() { @@ -1414,11 +1419,9 @@ void BridgedNativeWidget::InitCompositor() { DCHECK(layer()); float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); gfx::Size size_in_dip = GetClientAreaSize(); - // TODO(fsamuel): A valid viz::LocalSurfaceId() likely needs to be plumbed - // here to properly enable surface synchronization. compositor_->SetScaleAndSize(scale_factor, ConvertSizeToPixel(scale_factor, size_in_dip), - viz::LocalSurfaceId()); + parent_local_surface_id_allocator_.GenerateId()); compositor_->SetRootLayer(layer()); } @@ -1491,15 +1494,18 @@ void BridgedNativeWidget::AddCompositorSuperview() { void BridgedNativeWidget::UpdateLayerProperties() { DCHECK(layer()); DCHECK(compositor_superview_); + float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); gfx::Size size_in_dip = GetClientAreaSize(); + gfx::Size size_in_pixel = ConvertSizeToPixel(scale_factor, size_in_dip); + layer()->SetBounds(gfx::Rect(size_in_dip)); - float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); - // TODO(fsamuel): A valid viz::LocalSurfaceId() likely needs to be plumbed - // here to properly enable surface synchronization. - compositor_->SetScaleAndSize(scale_factor, - ConvertSizeToPixel(scale_factor, size_in_dip), - viz::LocalSurfaceId()); + if (compositor_->size() != size_in_pixel || + compositor_->device_scale_factor() != scale_factor) { + compositor_->SetScaleAndSize( + scale_factor, size_in_pixel, + parent_local_surface_id_allocator_.GenerateId()); + } // For a translucent window, the shadow calculation needs to be carried out // after the frame from the compositor arrives. diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm index 4a7157d0bd6..282a17b231e 100644 --- a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm @@ -214,6 +214,18 @@ bool IsRTLSelectBuggy(SEL sel) { @synthesize ignoredToggleFullScreenCount = ignoredToggleFullScreenCount_; +- (void)performSelector:(SEL)aSelector + withObject:(id)anArgument + afterDelay:(NSTimeInterval)delay { + // This is used in simulations without a message loop. Don't start a message + // loop since that would expose the tests to system notifications and + // potential flakes. Instead, just pretend the message loop is flushed here. + if (aSelector == @selector(toggleFullScreen:)) + [self toggleFullScreen:anArgument]; + else + [super performSelector:aSelector withObject:anArgument afterDelay:delay]; +} + - (void)toggleFullScreen:(id)sender { ++ignoredToggleFullScreenCount_; } diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc index e8b9a13207d..77c453f79d0 100644 --- a/chromium/ui/views/controls/button/button.cc +++ b/chromium/ui/views/controls/button/button.cc @@ -6,8 +6,6 @@ #include "base/strings/utf_string_conversions.h" #include "ui/accessibility/ax_node_data.h" - -#include "ui/accessibility/ax_node_data.h" #include "ui/base/class_property.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" @@ -97,7 +95,7 @@ void Button::SetTooltipText(const base::string16& tooltip_text) { void Button::SetAccessibleName(const base::string16& name) { accessible_name_ = name; - NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true); } void Button::SetState(ButtonState state) { @@ -152,7 +150,7 @@ void Button::SetHotTracked(bool is_hot_tracked) { SetState(is_hot_tracked ? STATE_HOVERED : STATE_NORMAL); if (is_hot_tracked) - NotifyAccessibilityEvent(ui::AX_EVENT_HOVER, true); + NotifyAccessibilityEvent(ax::mojom::Event::kHover, true); } bool Button::IsHotTracked() const { @@ -385,34 +383,28 @@ void Button::OnPaint(gfx::Canvas* canvas) { } void Button::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_BUTTON; + node_data->role = ax::mojom::Role::kButton; node_data->SetName(accessible_name_); - if (!enabled()) { - node_data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, - ui::AX_RESTRICTION_DISABLED); - } + if (!enabled()) + node_data->SetRestriction(ax::mojom::Restriction::kDisabled); switch (state_) { case STATE_HOVERED: - node_data->AddState(ui::AX_STATE_HOVERED); + node_data->AddState(ax::mojom::State::kHovered); break; case STATE_PRESSED: - node_data->AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, - ui::AX_CHECKED_STATE_TRUE); + node_data->SetCheckedState(ax::mojom::CheckedState::kTrue); break; case STATE_DISABLED: - node_data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, - ui::AX_RESTRICTION_DISABLED); + node_data->SetRestriction(ax::mojom::Restriction::kDisabled); break; case STATE_NORMAL: case STATE_COUNT: // No additional accessibility node_data set for this button node_data. break; } - if (enabled()) { - node_data->AddIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, - ui::AX_DEFAULT_ACTION_VERB_PRESS); - } + if (enabled()) + node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kPress); } void Button::VisibilityChanged(View* starting_from, bool visible) { @@ -425,6 +417,7 @@ void Button::VisibilityChanged(View* starting_from, bool visible) { void Button::ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) { if (!details.is_add && state_ != STATE_DISABLED && details.child == this) SetState(STATE_NORMAL); + InkDropHostView::ViewHierarchyChanged(details); } void Button::OnFocus() { diff --git a/chromium/ui/views/controls/button/button_unittest.cc b/chromium/ui/views/controls/button/button_unittest.cc index 20f610f96a6..067653b4945 100644 --- a/chromium/ui/views/controls/button/button_unittest.cc +++ b/chromium/ui/views/controls/button/button_unittest.cc @@ -510,6 +510,58 @@ TEST_F(ButtonTest, InkDropAfterTryingToShowContextMenu) { EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop->GetTargetInkDropState()); } +TEST_F(ButtonTest, HideInkDropHighlightWhenRemoved) { + views::View test_container; + test_container.set_owned_by_client(); + TestInkDrop* ink_drop = new TestInkDrop(); + CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false); + // Mark the button as owned by client so we can remove it from widget() + // without it being deleted. + button()->set_owned_by_client(); + + // Make sure that the button ink drop is hidden after the button gets removed. + widget()->SetContentsView(&test_container); + test_container.AddChildView(button()); + ui::test::EventGenerator generator(widget()->GetNativeWindow()); + generator.MoveMouseToInHost(2, 2); + EXPECT_TRUE(ink_drop->is_hovered()); + // Set ink-drop state to ACTIVATED to make sure that removing the container + // sets it back to HIDDEN. + ink_drop->AnimateToState(InkDropState::ACTIVATED); + test_container.RemoveAllChildViews(false); + EXPECT_FALSE(ink_drop->is_hovered()); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop->GetTargetInkDropState()); + + // Make sure hiding the ink drop happens even if the button is indirectly + // being removed. + views::View parent_test_container; + parent_test_container.set_owned_by_client(); + parent_test_container.AddChildView(&test_container); + test_container.AddChildView(button()); + widget()->SetContentsView(&parent_test_container); + + // Trigger hovering and then remove from the indirect parent. This should + // propagate down to Button which should remove the highlight effect. + EXPECT_FALSE(ink_drop->is_hovered()); + generator.MoveMouseToInHost(10, 10); + EXPECT_TRUE(ink_drop->is_hovered()); + // Set ink-drop state to ACTIVATED to make sure that removing the container + // sets it back to HIDDEN. + ink_drop->AnimateToState(InkDropState::ACTIVATED); + parent_test_container.RemoveAllChildViews(false); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop->GetTargetInkDropState()); + EXPECT_FALSE(ink_drop->is_hovered()); + + // Remove references to and delete button() which cannot be removed by owned + // containers as it's permanently set as owned by client. + test_container.RemoveAllChildViews(false); + delete button(); + + // Set the widget contents view to a new View so widget() doesn't contain a + // stale reference to the test containers that are about to go out of scope. + widget()->SetContentsView(new View()); +} + // Tests that when button is set to notify on release, dragging mouse out and // back transitions ink drop states correctly. TEST_F(ButtonTest, InkDropShowHideOnMouseDraggedNotifyOnRelease) { diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc index 968aaf469eb..8468460448f 100644 --- a/chromium/ui/views/controls/button/checkbox.cc +++ b/chromium/ui/views/controls/button/checkbox.cc @@ -12,6 +12,7 @@ #include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/native_theme/native_theme.h" @@ -163,17 +164,16 @@ const char* Checkbox::GetClassName() const { void Checkbox::GetAccessibleNodeData(ui::AXNodeData* node_data) { LabelButton::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_CHECK_BOX; - const ui::AXCheckedState checked_state = - checked() ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE; - node_data->AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, checked_state); + node_data->role = ax::mojom::Role::kCheckBox; + const ax::mojom::CheckedState checked_state = + checked() ? ax::mojom::CheckedState::kTrue + : ax::mojom::CheckedState::kFalse; + node_data->SetCheckedState(checked_state); if (enabled()) { if (checked()) { - node_data->AddIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, - ui::AX_DEFAULT_ACTION_VERB_UNCHECK); + node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kUncheck); } else { - node_data->AddIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, - ui::AX_DEFAULT_ACTION_VERB_CHECK); + node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kCheck); } } } @@ -216,14 +216,16 @@ std::unique_ptr<InkDropRipple> Checkbox::CreateInkDropRipple() const { SkColor Checkbox::GetInkDropBaseColor() const { // Usually ink drop ripples match the text color. Checkboxes use the color of - // the unchecked icon. - return GetIconImageColor(false); + // the unchecked, enabled icon. + return GetIconImageColor(IconState::ENABLED); } gfx::ImageSkia Checkbox::GetImage(ButtonState for_state) const { if (UseMd()) { + const int checked = checked_ ? IconState::CHECKED : 0; + const int enabled = for_state != STATE_DISABLED ? IconState::ENABLED : 0; return gfx::CreateVectorIcon(GetVectorIcon(), 16, - GetIconImageColor(checked_)); + GetIconImageColor(checked | enabled)); } const size_t checked_index = checked_ ? 1 : 0; @@ -264,14 +266,19 @@ const gfx::VectorIcon& Checkbox::GetVectorIcon() const { return checked() ? kCheckboxActiveIcon : kCheckboxNormalIcon; } -SkColor Checkbox::GetIconImageColor(bool checked) const { +SkColor Checkbox::GetIconImageColor(int icon_state) const { DCHECK(UseMd()); - return checked - ? GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_FocusedBorderColor) - // When unchecked, the icon color matches push button text color. - : style::GetColor(*this, style::CONTEXT_BUTTON_MD, - style::STYLE_PRIMARY); + const SkColor active_color = + (icon_state & IconState::CHECKED) + ? GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_FocusedBorderColor) + // When unchecked, the icon color matches push button text color. + : style::GetColor(*this, style::CONTEXT_BUTTON_MD, + style::STYLE_PRIMARY); + return (icon_state & IconState::ENABLED) + ? active_color + : color_utils::BlendTowardOppositeLuma(active_color, + gfx::kDisabledControlAlpha); } void Checkbox::NotifyClick(const ui::Event& event) { diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h index 7fc27353a01..f6605e8dd4c 100644 --- a/chromium/ui/views/controls/button/checkbox.h +++ b/chromium/ui/views/controls/button/checkbox.h @@ -74,7 +74,11 @@ class VIEWS_EXPORT Checkbox : public LabelButton { private: friend class IconFocusRing; - SkColor GetIconImageColor(bool checked) const; + // Bitmask constants for GetIconImageColor. + enum IconState { CHECKED = 0b1, ENABLED = 0b10 }; + + // |icon_state| is a bitmask using the IconState enum. + SkColor GetIconImageColor(int icon_state) const; // Button: void NotifyClick(const ui::Event& event) override; diff --git a/chromium/ui/views/controls/button/image_button.cc b/chromium/ui/views/controls/button/image_button.cc index 86da89c1729..6d945e4579c 100644 --- a/chromium/ui/views/controls/button/image_button.cc +++ b/chromium/ui/views/controls/button/image_button.cc @@ -217,7 +217,7 @@ void ToggleImageButton::SetToggled(bool toggled) { toggled_ = toggled; SchedulePaint(); - NotifyAccessibilityEvent(ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kAriaAttributeChanged, true); } void ToggleImageButton::SetToggledImage(ButtonState image_state, @@ -279,10 +279,9 @@ void ToggleImageButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { // accessible toggle button. if ((toggled_ && !images_[ButtonState::STATE_NORMAL].isNull()) || (!toggled_ && !alternate_images_[ButtonState::STATE_NORMAL].isNull())) { - node_data->role = ui::AX_ROLE_TOGGLE_BUTTON; - node_data->AddIntAttribute( - ui::AX_ATTR_CHECKED_STATE, - toggled_ ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE); + node_data->role = ax::mojom::Role::kToggleButton; + node_data->SetCheckedState(toggled_ ? ax::mojom::CheckedState::kTrue + : ax::mojom::CheckedState::kFalse); } } diff --git a/chromium/ui/views/controls/button/image_button.h b/chromium/ui/views/controls/button/image_button.h index 61c0ca338c1..fb73e6c1e06 100644 --- a/chromium/ui/views/controls/button/image_button.h +++ b/chromium/ui/views/controls/button/image_button.h @@ -23,12 +23,14 @@ class VIEWS_EXPORT ImageButton : public Button { public: static const char kViewClassName[]; + // An enum describing the horizontal alignment of images on Buttons. enum HorizontalAlignment { ALIGN_LEFT = 0, ALIGN_CENTER, ALIGN_RIGHT }; + // An enum describing the vertical alignment of images on Buttons. enum VerticalAlignment { ALIGN_TOP = 0, ALIGN_MIDDLE, diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc index 6fc12bbc6f9..7cf98686b71 100644 --- a/chromium/ui/views/controls/button/label_button.cc +++ b/chromium/ui/views/controls/button/label_button.cc @@ -273,7 +273,15 @@ void LabelButton::Layout() { label_area.height()); gfx::Point image_origin(child_area.origin()); - image_origin.Offset(0, (child_area.height() - image_size.height()) / 2); + if (label_->multi_line()) { + // Right now this code currently only works for CheckBox and RadioButton + // descendants that have multi-line enabled for their label. + image_origin.Offset( + 0, std::max( + 0, (label_->font_list().GetHeight() - image_size.height()) / 2)); + } else { + image_origin.Offset(0, (child_area.height() - image_size.height()) / 2); + } if (horizontal_alignment_ == gfx::ALIGN_CENTER) { const int spacing = (image_size.width() > 0 && label_size.width() > 0) ? image_label_spacing_ : 0; diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc index 466b9ccc543..4a1ac7683d6 100644 --- a/chromium/ui/views/controls/button/label_button_unittest.cc +++ b/chromium/ui/views/controls/button/label_button_unittest.cc @@ -24,6 +24,7 @@ #include "ui/native_theme/native_theme.h" #include "ui/views/animation/test/ink_drop_host_view_test_api.h" #include "ui/views/animation/test/test_ink_drop.h" +#include "ui/views/layout/layout_provider.h" #include "ui/views/style/platform_style.h" #include "ui/views/test/views_test_base.h" #include "ui/views/test/widget_test.h" @@ -134,8 +135,9 @@ TEST_F(LabelButtonTest, Init) { ui::AXNodeData accessible_node_data; button.GetAccessibleNodeData(&accessible_node_data); - EXPECT_EQ(ui::AX_ROLE_BUTTON, accessible_node_data.role); - EXPECT_EQ(text, accessible_node_data.GetString16Attribute(ui::AX_ATTR_NAME)); + EXPECT_EQ(ax::mojom::Role::kButton, accessible_node_data.role); + EXPECT_EQ(text, accessible_node_data.GetString16Attribute( + ax::mojom::StringAttribute::kName)); EXPECT_FALSE(button.is_default()); EXPECT_EQ(button.style(), Button::STYLE_TEXTBUTTON); @@ -184,25 +186,25 @@ TEST_F(LabelButtonTest, AccessibleState) { ui::AXNodeData accessible_node_data; button_->GetAccessibleNodeData(&accessible_node_data); - EXPECT_EQ(ui::AX_ROLE_BUTTON, accessible_node_data.role); - EXPECT_EQ(base::string16(), - accessible_node_data.GetString16Attribute(ui::AX_ATTR_NAME)); + EXPECT_EQ(ax::mojom::Role::kButton, accessible_node_data.role); + EXPECT_EQ(base::string16(), accessible_node_data.GetString16Attribute( + ax::mojom::StringAttribute::kName)); // Without a label (e.g. image-only), the accessible name should automatically // be set from the tooltip. const base::string16 tooltip_text = ASCIIToUTF16("abc"); button_->SetTooltipText(tooltip_text); button_->GetAccessibleNodeData(&accessible_node_data); - EXPECT_EQ(tooltip_text, - accessible_node_data.GetString16Attribute(ui::AX_ATTR_NAME)); + EXPECT_EQ(tooltip_text, accessible_node_data.GetString16Attribute( + ax::mojom::StringAttribute::kName)); EXPECT_EQ(base::string16(), button_->GetText()); // Setting a label overrides the tooltip text. const base::string16 label_text = ASCIIToUTF16("def"); button_->SetText(label_text); button_->GetAccessibleNodeData(&accessible_node_data); - EXPECT_EQ(label_text, - accessible_node_data.GetString16Attribute(ui::AX_ATTR_NAME)); + EXPECT_EQ(label_text, accessible_node_data.GetString16Attribute( + ax::mojom::StringAttribute::kName)); EXPECT_EQ(label_text, button_->GetText()); base::string16 tooltip; @@ -304,6 +306,42 @@ TEST_F(LabelButtonTest, LabelAndImage) { EXPECT_EQ(button_->GetPreferredSize(), gfx::Size(1, 1)); } +TEST_F(LabelButtonTest, LabelWrapAndImageAlignment) { + LayoutProvider* provider = LayoutProvider::Get(); + const gfx::FontList font_list = button_->label()->font_list(); + const base::string16 text(ASCIIToUTF16("abcdefghijklm abcdefghijklm")); + const int text_wrap_width = gfx::GetStringWidth(text, font_list) / 2; + const int image_spacing = + provider->GetDistanceMetric(DISTANCE_RELATED_LABEL_HORIZONTAL); + + button_->SetText(text); + button_->label()->SetMultiLine(true); + + const int image_size = font_list.GetHeight(); + const gfx::ImageSkia image = CreateTestImage(image_size, image_size); + ASSERT_EQ(font_list.GetHeight(), image.width()); + + button_->SetImage(Button::STATE_NORMAL, image); + button_->SetMaxSize( + gfx::Size(image.width() + image_spacing + text_wrap_width, 0)); + + gfx::Insets button_insets = button_->GetInsets(); + gfx::Size preferred_size = button_->GetPreferredSize(); + preferred_size.set_height(button_->GetHeightForWidth(preferred_size.width())); + button_->SetSize(preferred_size); + button_->Layout(); + + EXPECT_EQ(preferred_size.width(), + image.width() + image_spacing + text_wrap_width); + EXPECT_EQ(preferred_size.height(), + font_list.GetHeight() * 2 + button_insets.height()); + + // The image should be centered on the first line of the multi-line label. + EXPECT_EQ(button_->image()->y(), + (font_list.GetHeight() - button_->image()->height()) / 2 + + button_insets.top()); +} + // This test was added because GetHeightForWidth and GetPreferredSize were // inconsistent. GetPreferredSize would account for image size + insets whereas // GetHeightForWidth wouldn't. As of writing they share a large chunk of diff --git a/chromium/ui/views/controls/button/md_text_button.h b/chromium/ui/views/controls/button/md_text_button.h index 8d0d6e35b73..27ba3c0cb97 100644 --- a/chromium/ui/views/controls/button/md_text_button.h +++ b/chromium/ui/views/controls/button/md_text_button.h @@ -51,9 +51,10 @@ class VIEWS_EXPORT MdTextButton : public LabelButton { void UpdateStyleToIndicateDefaultStatus() override; void StateChanged(ButtonState old_state) override; - private: + protected: MdTextButton(ButtonListener* listener, int button_context); + private: void UpdatePadding(); void UpdateColors(); diff --git a/chromium/ui/views/controls/button/menu_button.cc b/chromium/ui/views/controls/button/menu_button.cc index 536fd0159e2..b6996aab742 100644 --- a/chromium/ui/views/controls/button/menu_button.cc +++ b/chromium/ui/views/controls/button/menu_button.cc @@ -259,6 +259,7 @@ bool MenuButton::OnKeyPressed(const ui::KeyEvent& event) { // Alt-space on windows should show the window menu. if (event.IsAltDown()) break; + FALLTHROUGH; case ui::VKEY_RETURN: case ui::VKEY_UP: case ui::VKEY_DOWN: { @@ -285,12 +286,10 @@ bool MenuButton::OnKeyReleased(const ui::KeyEvent& event) { void MenuButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { Button::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_POP_UP_BUTTON; - node_data->AddState(ui::AX_STATE_HASPOPUP); - if (enabled()) { - node_data->AddIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, - ui::AX_DEFAULT_ACTION_VERB_OPEN); - } + node_data->role = ax::mojom::Role::kPopUpButton; + node_data->AddState(ax::mojom::State::kHaspopup); + if (enabled()) + node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kOpen); } void MenuButton::PaintMenuMarker(gfx::Canvas* canvas) { diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc index bfe433636f3..e8499db3311 100644 --- a/chromium/ui/views/controls/button/radio_button.cc +++ b/chromium/ui/views/controls/button/radio_button.cc @@ -75,7 +75,7 @@ const char* RadioButton::GetClassName() const { void RadioButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { Checkbox::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_RADIO_BUTTON; + node_data->role = ax::mojom::Role::kRadioButton; } View* RadioButton::GetSelectedViewForGroup(int group) { diff --git a/chromium/ui/views/controls/button/toggle_button.cc b/chromium/ui/views/controls/button/toggle_button.cc index b62c2de33e0..650d85b8c34 100644 --- a/chromium/ui/views/controls/button/toggle_button.cc +++ b/chromium/ui/views/controls/button/toggle_button.cc @@ -23,13 +23,13 @@ namespace views { namespace { // Constants are measured in dip. -const int kTrackHeight = 12; -const int kTrackWidth = 28; +constexpr int kTrackHeight = 12; +constexpr int kTrackWidth = 28; // Margins from edge of track to edge of view. -const int kTrackVerticalMargin = 5; -const int kTrackHorizontalMargin = 6; +constexpr int kTrackVerticalMargin = 5; +constexpr int kTrackHorizontalMargin = 6; // Inset from the rounded edge of the thumb to the rounded edge of the track. -const int kThumbInset = 2; +constexpr int kThumbInset = 2; } // namespace @@ -60,9 +60,9 @@ class ToggleButton::ThumbView : public InkDropHostView { } private: - static const int kShadowOffsetX = 0; - static const int kShadowOffsetY = 1; - static const int kShadowBlur = 2; + static constexpr int kShadowOffsetX = 0; + static constexpr int kShadowOffsetY = 1; + static constexpr int kShadowBlur = 2; // views::View: const char* GetClassName() const override { @@ -197,10 +197,9 @@ void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) { void ToggleButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { Button::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_SWITCH; - const ui::AXCheckedState checked_state = - is_on_ ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE; - node_data->AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, checked_state); + node_data->role = ax::mojom::Role::kSwitch; + node_data->SetCheckedState(is_on_ ? ax::mojom::CheckedState::kTrue + : ax::mojom::CheckedState::kFalse); } void ToggleButton::OnFocus() { diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc index 295fbbaf5ed..67f9af2eaee 100644 --- a/chromium/ui/views/controls/combobox/combobox.cc +++ b/chromium/ui/views/controls/combobox/combobox.cc @@ -766,29 +766,31 @@ void Combobox::OnBlur() { } void Combobox::GetAccessibleNodeData(ui::AXNodeData* node_data) { - // AX_ROLE_COMBO_BOX is for UI elements with a dropdown and an editable text - // field, which views::Combobox does not have. Use AX_ROLE_POP_UP_BUTTON to - // match an HTML <select> element. - node_data->role = ui::AX_ROLE_POP_UP_BUTTON; + // ax::mojom::Role::kComboBox is for UI elements with a dropdown and + // an editable text field, which views::Combobox does not have. Use + // ax::mojom::Role::kPopUpButton to match an HTML <select> element. + node_data->role = ax::mojom::Role::kPopUpButton; node_data->SetName(accessible_name_); node_data->SetValue(model_->GetItemAt(selected_index_)); if (enabled()) { - node_data->AddIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, - ui::AX_DEFAULT_ACTION_VERB_OPEN); + node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kOpen); } - node_data->AddIntAttribute(ui::AX_ATTR_POS_IN_SET, selected_index_); - node_data->AddIntAttribute(ui::AX_ATTR_SET_SIZE, model_->GetItemCount()); + node_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, + selected_index_); + node_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize, + model_->GetItemCount()); } bool Combobox::HandleAccessibleAction(const ui::AXActionData& action_data) { // The action handling in View would generate a mouse event and send it to // |this|. However, mouse events for Combobox are handled by |arrow_button_|, // which is hidden from the a11y tree (so can't expose actions). Rather than - // forwarding AX_ACTION_DO_DEFAULT to View and then forwarding the mouse event - // it generates to |arrow_button_| to have it forward back to |this| (as its - // ButtonListener), just handle the action explicitly here and bypass View. - if (enabled() && action_data.action == ui::AX_ACTION_DO_DEFAULT) { + // forwarding ax::mojom::Action::kDoDefault to View and then forwarding the + // mouse event it generates to |arrow_button_| to have it forward back to + // |this| (as its ButtonListener), just handle the action explicitly here and + // bypass View. + if (enabled() && action_data.action == ax::mojom::Action::kDoDefault) { ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD); return true; } @@ -996,7 +998,7 @@ void Combobox::OnMenuClosed(Button::ButtonState original_button_state) { } void Combobox::OnPerformAction() { - NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); SchedulePaint(); // This combobox may be deleted by the listener. diff --git a/chromium/ui/views/controls/combobox/combobox_unittest.cc b/chromium/ui/views/controls/combobox/combobox_unittest.cc index 4134a21e34b..5c32debbaf9 100644 --- a/chromium/ui/views/controls/combobox/combobox_unittest.cc +++ b/chromium/ui/views/controls/combobox/combobox_unittest.cc @@ -648,19 +648,19 @@ TEST_F(ComboboxTest, ShowViaAccessibleAction) { InitCombobox(nullptr, Combobox::STYLE_NORMAL); ui::AXActionData data; - data.action = ui::AX_ACTION_DO_DEFAULT; + data.action = ax::mojom::Action::kDoDefault; EXPECT_EQ(0, menu_show_count_); combobox_->HandleAccessibleAction(data); EXPECT_EQ(1, menu_show_count_); - // AX_ACTION_SHOW_CONTEXT_MENU is specifically for a context menu (e.g. right- - // click). Combobox should ignore it. - data.action = ui::AX_ACTION_SHOW_CONTEXT_MENU; + // ax::mojom::Action::kShowContextMenu is specifically for a context menu + // (e.g. right- click). Combobox should ignore it. + data.action = ax::mojom::Action::kShowContextMenu; combobox_->HandleAccessibleAction(data); EXPECT_EQ(1, menu_show_count_); // No change. - data.action = ui::AX_ACTION_BLUR; + data.action = ax::mojom::Action::kBlur; combobox_->HandleAccessibleAction(data); EXPECT_EQ(1, menu_show_count_); // No change. @@ -668,7 +668,7 @@ TEST_F(ComboboxTest, ShowViaAccessibleAction) { combobox_->HandleAccessibleAction(data); EXPECT_EQ(1, menu_show_count_); // No change. - data.action = ui::AX_ACTION_SHOW_CONTEXT_MENU; + data.action = ax::mojom::Action::kShowContextMenu; combobox_->HandleAccessibleAction(data); EXPECT_EQ(1, menu_show_count_); // No change. } diff --git a/chromium/ui/views/controls/image_view.cc b/chromium/ui/views/controls/image_view.cc index bc748e3552d..badae559e96 100644 --- a/chromium/ui/views/controls/image_view.cc +++ b/chromium/ui/views/controls/image_view.cc @@ -106,7 +106,9 @@ gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const { switch (actual_horiz_alignment) { case LEADING: x = insets.left(); break; case TRAILING: x = width() - insets.right() - image_size.width(); break; - case CENTER: x = (width() - image_size.width()) / 2; break; + case CENTER: + x = (width() - insets.width() - image_size.width()) / 2 + insets.left(); + break; default: NOTREACHED(); x = 0; break; } @@ -114,7 +116,9 @@ gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const { switch (vert_alignment_) { case LEADING: y = insets.top(); break; case TRAILING: y = height() - insets.bottom() - image_size.height(); break; - case CENTER: y = (height() - image_size.height()) / 2; break; + case CENTER: + y = (height() - insets.height() - image_size.height()) / 2 + insets.top(); + break; default: NOTREACHED(); y = 0; break; } @@ -127,7 +131,7 @@ void ImageView::OnPaint(gfx::Canvas* canvas) { } void ImageView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_IMAGE; + node_data->role = ax::mojom::Role::kImage; node_data->SetName(tooltip_text_); } diff --git a/chromium/ui/views/controls/image_view.h b/chromium/ui/views/controls/image_view.h index e850c033cb2..751bee97277 100644 --- a/chromium/ui/views/controls/image_view.h +++ b/chromium/ui/views/controls/image_view.h @@ -82,6 +82,8 @@ class VIEWS_EXPORT ImageView : public View { views::PaintInfo::ScaleType GetPaintScaleType() const override; private: + friend class ImageViewTest; + void OnPaintImage(gfx::Canvas* canvas); // Returns true if |img| is the same as the last image we painted. This is diff --git a/chromium/ui/views/controls/image_view_unittest.cc b/chromium/ui/views/controls/image_view_unittest.cc new file mode 100644 index 00000000000..417d342d445 --- /dev/null +++ b/chromium/ui/views/controls/image_view_unittest.cc @@ -0,0 +1,134 @@ +// Copyright 2018 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/views/controls/image_view.h" + +#include "base/i18n/rtl.h" +#include "base/memory/ptr_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/border.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/test/views_test_base.h" +#include "ui/views/widget/widget.h" + +namespace { + +enum class Axis { + kHorizontal, + kVertical, +}; + +// A test utility function to set the application default text direction. +void SetRTL(bool rtl) { + // Override the current locale/direction. + base::i18n::SetICUDefaultLocale(rtl ? "he" : "en"); + EXPECT_EQ(rtl, base::i18n::IsRTL()); +} + +} // namespace + +namespace views { + +class ImageViewTest : public ViewsTestBase, + public ::testing::WithParamInterface<Axis> { + public: + ImageViewTest() {} + + // ViewsTestBase: + void SetUp() override { + ViewsTestBase::SetUp(); + + Widget::InitParams params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.bounds = gfx::Rect(200, 200); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget_.Init(params); + View* container = new View(); + // Make sure children can take up exactly as much space as they require. + BoxLayout::Orientation orientation = GetParam() == Axis::kHorizontal + ? BoxLayout::kHorizontal + : BoxLayout::kVertical; + container->SetLayoutManager(std::make_unique<BoxLayout>(orientation)); + widget_.SetContentsView(container); + + image_view_ = new ImageView(); + container->AddChildView(image_view_); + + widget_.Show(); + } + + void TearDown() override { + widget_.Close(); + ViewsTestBase::TearDown(); + } + + int CurrentImageOriginForParam() { + gfx::Point origin = + image_view()->ComputeImageOrigin(image_view()->GetImageSize()); + return GetParam() == Axis::kHorizontal ? origin.x() : origin.y(); + } + + protected: + ImageView* image_view() { return image_view_; } + Widget* widget() { return &widget_; } + + private: + ImageView* image_view_ = nullptr; + Widget widget_; + + DISALLOW_COPY_AND_ASSIGN(ImageViewTest); +}; + +// Test the image origin of the internal ImageSkia is correct when it is +// center-aligned (both horizontally and vertically). +TEST_P(ImageViewTest, CenterAlignment) { + image_view()->SetHorizontalAlignment(ImageView::CENTER); + + constexpr int kImageSkiaSize = 4; + SkBitmap bitmap; + bitmap.allocN32Pixels(kImageSkiaSize, kImageSkiaSize); + gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + image_view()->SetImage(image_skia); + widget()->GetContentsView()->Layout(); + EXPECT_NE(gfx::Size(), image_skia.size()); + + // With no changes to the size / padding of |image_view|, the origin of + // |image_skia| is the same as the origin of |image_view|. + EXPECT_EQ(0, CurrentImageOriginForParam()); + + // Test insets are always respected in LTR and RTL. + constexpr int kInset = 5; + image_view()->SetBorder(CreateEmptyBorder(gfx::Insets(kInset))); + widget()->GetContentsView()->Layout(); + EXPECT_EQ(kInset, CurrentImageOriginForParam()); + + SetRTL(true); + widget()->GetContentsView()->Layout(); + EXPECT_EQ(kInset, CurrentImageOriginForParam()); + + // Check this still holds true when the insets are asymmetrical. + constexpr int kLeadingInset = 4; + constexpr int kTrailingInset = 6; + image_view()->SetBorder(CreateEmptyBorder( + gfx::Insets(/*top=*/kLeadingInset, /*left=*/kLeadingInset, + /*bottom=*/kTrailingInset, /*right=*/kTrailingInset))); + widget()->GetContentsView()->Layout(); + EXPECT_EQ(kLeadingInset, CurrentImageOriginForParam()); + + SetRTL(false); + widget()->GetContentsView()->Layout(); + EXPECT_EQ(kLeadingInset, CurrentImageOriginForParam()); +} + +INSTANTIATE_TEST_CASE_P(, + ImageViewTest, + ::testing::Values(Axis::kHorizontal, Axis::kVertical)); + +} // namespace views diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc index 5fb2a8667c8..6b6d5f02b8a 100644 --- a/chromium/ui/views/controls/label.cc +++ b/chromium/ui/views/controls/label.cc @@ -25,6 +25,7 @@ #include "ui/gfx/color_utils.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/text_elider.h" +#include "ui/gfx/text_utils.h" #include "ui/native_theme/native_theme.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/background.h" @@ -75,7 +76,6 @@ const gfx::FontList& Label::GetDefaultFontList() { } void Label::SetFontList(const gfx::FontList& font_list) { - is_first_paint_text_ = true; full_text_->SetFontList(font_list); ResetLayout(); } @@ -83,7 +83,6 @@ void Label::SetFontList(const gfx::FontList& font_list) { void Label::SetText(const base::string16& new_text) { if (new_text == text()) return; - is_first_paint_text_ = true; full_text_->SetText(new_text); ResetLayout(); stored_selection_range_ = gfx::Range::InvalidRange(); @@ -92,7 +91,6 @@ void Label::SetText(const base::string16& new_text) { void Label::SetAutoColorReadabilityEnabled(bool enabled) { if (auto_color_readability_ == enabled) return; - is_first_paint_text_ = true; auto_color_readability_ = enabled; RecalculateColors(); } @@ -100,7 +98,6 @@ void Label::SetAutoColorReadabilityEnabled(bool enabled) { void Label::SetEnabledColor(SkColor color) { if (enabled_color_set_ && requested_enabled_color_ == color) return; - is_first_paint_text_ = true; requested_enabled_color_ = color; enabled_color_set_ = true; RecalculateColors(); @@ -109,7 +106,6 @@ void Label::SetEnabledColor(SkColor color) { void Label::SetBackgroundColor(SkColor color) { if (background_color_set_ && background_color_ == color) return; - is_first_paint_text_ = true; background_color_ = color; background_color_set_ = true; RecalculateColors(); @@ -118,7 +114,6 @@ void Label::SetBackgroundColor(SkColor color) { void Label::SetSelectionTextColor(SkColor color) { if (selection_text_color_set_ && requested_selection_text_color_ == color) return; - is_first_paint_text_ = true; requested_selection_text_color_ = color; selection_text_color_set_ = true; RecalculateColors(); @@ -127,7 +122,6 @@ void Label::SetSelectionTextColor(SkColor color) { void Label::SetSelectionBackgroundColor(SkColor color) { if (selection_background_color_set_ && selection_background_color_ == color) return; - is_first_paint_text_ = true; selection_background_color_ = color; selection_background_color_set_ = true; RecalculateColors(); @@ -136,7 +130,6 @@ void Label::SetSelectionBackgroundColor(SkColor color) { void Label::SetShadows(const gfx::ShadowValues& shadows) { if (full_text_->shadows() == shadows) return; - is_first_paint_text_ = true; full_text_->set_shadows(shadows); ResetLayout(); } @@ -144,21 +137,14 @@ void Label::SetShadows(const gfx::ShadowValues& shadows) { void Label::SetSubpixelRenderingEnabled(bool subpixel_rendering_enabled) { if (subpixel_rendering_enabled_ == subpixel_rendering_enabled) return; - is_first_paint_text_ = true; subpixel_rendering_enabled_ = subpixel_rendering_enabled; RecalculateColors(); } void Label::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) { - // If the UI layout is right-to-left, flip the alignment direction. - if (base::i18n::IsRTL() && - (alignment == gfx::ALIGN_LEFT || alignment == gfx::ALIGN_RIGHT)) { - alignment = (alignment == gfx::ALIGN_LEFT) ? - gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT; - } + alignment = gfx::MaybeFlipForRTL(alignment); if (horizontal_alignment() == alignment) return; - is_first_paint_text_ = true; full_text_->SetHorizontalAlignment(alignment); ResetLayout(); } @@ -166,7 +152,6 @@ void Label::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) { void Label::SetLineHeight(int height) { if (line_height() == height) return; - is_first_paint_text_ = true; full_text_->SetMinLineHeight(height); ResetLayout(); } @@ -176,7 +161,6 @@ void Label::SetMultiLine(bool multi_line) { elide_behavior_ == gfx::NO_ELIDE)); if (this->multi_line() == multi_line) return; - is_first_paint_text_ = true; multi_line_ = multi_line; full_text_->SetMultiline(multi_line); full_text_->SetReplaceNewlineCharsWithSymbols(!multi_line); @@ -186,7 +170,6 @@ void Label::SetMultiLine(bool multi_line) { void Label::SetMaxLines(int max_lines) { if (max_lines_ == max_lines) return; - is_first_paint_text_ = true; max_lines_ = max_lines; ResetLayout(); } @@ -194,7 +177,6 @@ void Label::SetMaxLines(int max_lines) { void Label::SetObscured(bool obscured) { if (this->obscured() == obscured) return; - is_first_paint_text_ = true; full_text_->SetObscured(obscured); if (obscured) SetSelectable(false); @@ -208,7 +190,6 @@ void Label::SetAllowCharacterBreak(bool allow_character_break) { return; full_text_->SetWordWrapBehavior(behavior); if (multi_line()) { - is_first_paint_text_ = true; ResetLayout(); } } @@ -218,7 +199,6 @@ void Label::SetElideBehavior(gfx::ElideBehavior elide_behavior) { elide_behavior_ == gfx::NO_ELIDE)); if (elide_behavior_ == elide_behavior) return; - is_first_paint_text_ = true; elide_behavior_ = elide_behavior; ResetLayout(); } @@ -396,9 +376,9 @@ const char* Label::GetClassName() const { View* Label::GetTooltipHandlerForPoint(const gfx::Point& point) { if (!handles_tooltips_ || (tooltip_text_.empty() && !ShouldShowDefaultTooltip())) - return NULL; + return nullptr; - return HitTestPoint(point) ? this : NULL; + return HitTestPoint(point) ? this : nullptr; } bool Label::CanProcessEventsWithinSubtree() const { @@ -410,7 +390,11 @@ WordLookupClient* Label::GetWordLookupClient() { } void Label::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_STATIC_TEXT; + if (text_context_ == style::CONTEXT_DIALOG_TITLE) + node_data->role = ax::mojom::Role::kTitleBar; + else + node_data->role = ax::mojom::Role::kStaticText; + node_data->SetName(full_text_->GetDisplayText()); } @@ -516,13 +500,7 @@ void Label::OnBoundsChanged(const gfx::Rect& previous_bounds) { void Label::OnPaint(gfx::Canvas* canvas) { View::OnPaint(canvas); - if (is_first_paint_text_) { - is_first_paint_text_ = false; - PaintText(canvas); - } else { - PaintText(canvas); - } - + PaintText(canvas); if (HasFocus()) PaintFocusRing(canvas); } @@ -836,7 +814,6 @@ void Label::Init(const base::string16& text, const gfx::FontList& font_list) { collapse_when_hidden_ = false; fixed_width_ = 0; max_width_ = 0; - is_first_paint_text_ = true; SetText(text); // Only selectable labels will get requests to show the context menu, due to diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h index 1cee7279272..635025a8250 100644 --- a/chromium/ui/views/controls/label.h +++ b/chromium/ui/views/controls/label.h @@ -5,6 +5,8 @@ #ifndef UI_VIEWS_CONTROLS_LABEL_H_ #define UI_VIEWS_CONTROLS_LABEL_H_ +#include <memory> + #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -366,10 +368,6 @@ class VIEWS_EXPORT Label : public View, int fixed_width_; int max_width_; - // TODO(ckocagil): Remove is_first_paint_text_ before crbug.com/441028 is - // closed. - bool is_first_paint_text_; - std::unique_ptr<SelectionController> selection_controller_; // Context menu related members. diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc index 7e70ba3be24..54654acf866 100644 --- a/chromium/ui/views/controls/label_unittest.cc +++ b/chromium/ui/views/controls/label_unittest.cc @@ -227,7 +227,7 @@ class LabelSelectionTest : public LabelTest { label()->GetRenderTextForSelectionController(); const gfx::Range range(index, index + 1); const std::vector<gfx::Rect> bounds = - render_text->GetSubstringBoundsForTesting(range); + render_text->GetSubstringBounds(range); DCHECK_EQ(1u, bounds.size()); const int mid_y = bounds[0].y() + bounds[0].height() / 2; @@ -567,9 +567,11 @@ TEST_F(LabelTest, Accessibility) { ui::AXNodeData node_data; label()->GetAccessibleNodeData(&node_data); - EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, node_data.role); - EXPECT_EQ(label()->text(), node_data.GetString16Attribute(ui::AX_ATTR_NAME)); - EXPECT_FALSE(node_data.HasIntAttribute(ui::AX_ATTR_RESTRICTION)); + EXPECT_EQ(ax::mojom::Role::kStaticText, node_data.role); + EXPECT_EQ(label()->text(), + node_data.GetString16Attribute(ax::mojom::StringAttribute::kName)); + EXPECT_FALSE( + node_data.HasIntAttribute(ax::mojom::IntAttribute::kRestriction)); } TEST_F(LabelTest, TextChangeWithoutLayout) { diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc index 1cc2e1faf5e..f4e605aaedb 100644 --- a/chromium/ui/views/controls/link.cc +++ b/chromium/ui/views/controls/link.cc @@ -163,7 +163,7 @@ bool Link::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) { void Link::GetAccessibleNodeData(ui::AXNodeData* node_data) { Label::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_LINK; + node_data->role = ax::mojom::Role::kLink; } void Link::OnEnabledChanged() { diff --git a/chromium/ui/views/controls/menu/menu_config_win.cc b/chromium/ui/views/controls/menu/menu_config_win.cc index 34d29d7bef1..6048ee062fd 100644 --- a/chromium/ui/views/controls/menu/menu_config_win.cc +++ b/chromium/ui/views/controls/menu/menu_config_win.cc @@ -10,7 +10,7 @@ #include "base/logging.h" #include "base/win/scoped_gdi_object.h" -#include "base/win/win_util.h" +#include "base/win/win_client_metrics.h" #include "ui/base/l10n/l10n_util_win.h" #include "ui/gfx/color_utils.h" #include "ui/native_theme/native_theme_win.h" diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc index 9389f25f034..4feb2cd4b2e 100644 --- a/chromium/ui/views/controls/menu/menu_controller.cc +++ b/chromium/ui/views/controls/menu/menu_controller.cc @@ -1200,8 +1200,7 @@ void MenuController::SetSelection(MenuItemView* menu_item, if (menu_item && (MenuDepth(menu_item) != 1 || menu_item->GetType() != MenuItemView::SUBMENU)) { - menu_item->NotifyAccessibilityEvent( - ui::AX_EVENT_SELECTION, true); + menu_item->NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true); } } @@ -1328,7 +1327,8 @@ void MenuController::OnKeyDown(ui::KeyboardCode key_code) { case ui::VKEY_F4: if (!is_combobox_) break; - // Fallthrough to accept or dismiss combobox menus on F4, like windows. + // Fallthrough to accept or dismiss combobox menus on F4, like windows. + FALLTHROUGH; case ui::VKEY_RETURN: #if defined(OS_MACOSX) case ui::VKEY_SPACE: @@ -2697,7 +2697,7 @@ void MenuController::SetHotTrackedButton(Button* hot_button) { // Hot-tracked state may change outside of the MenuController. Correct it. if (hot_button && !hot_button->IsHotTracked()) { hot_button->SetHotTracked(true); - hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); + hot_button->NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true); } return; } @@ -2706,7 +2706,7 @@ void MenuController::SetHotTrackedButton(Button* hot_button) { hot_button_ = hot_button; if (hot_button) { hot_button->SetHotTracked(true); - hot_button->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); + hot_button->NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true); } } diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc index d90a8ec45fc..4cf7d61f7ef 100644 --- a/chromium/ui/views/controls/menu/menu_item_view.cc +++ b/chromium/ui/views/controls/menu/menu_item_view.cc @@ -17,6 +17,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/text_utils.h" #include "ui/native_theme/common_theme.h" #include "ui/strings/grit/ui_strings.h" @@ -152,7 +153,7 @@ bool MenuItemView::GetTooltipText(const gfx::Point& p, } void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_MENU_ITEM; + node_data->role = ax::mojom::Role::kMenuItem; base::string16 item_text; if (IsContainer()) { @@ -161,7 +162,8 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) { View* child = child_at(0); ui::AXNodeData node_data; child->GetAccessibleNodeData(&node_data); - item_text = node_data.GetString16Attribute(ui::AX_ATTR_NAME); + item_text = + node_data.GetString16Attribute(ax::mojom::StringAttribute::kName); } else { item_text = title_; } @@ -169,14 +171,13 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) { switch (GetType()) { case SUBMENU: - node_data->AddState(ui::AX_STATE_HASPOPUP); + node_data->AddState(ax::mojom::State::kHaspopup); break; case CHECKBOX: case RADIO: { const bool is_checked = GetDelegate()->IsItemChecked(GetCommand()); - const ui::AXCheckedState checked_state = - is_checked ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE; - node_data->AddIntAttribute(ui::AX_ATTR_CHECKED_STATE, checked_state); + node_data->SetCheckedState(is_checked ? ax::mojom::CheckedState::kTrue + : ax::mojom::CheckedState::kFalse); } break; case NORMAL: case SEPARATOR: @@ -188,7 +189,7 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) { base::char16 mnemonic = GetMnemonic(); if (mnemonic != '\0') { node_data->AddStringAttribute( - ui::AX_ATTR_KEY_SHORTCUTS, + ax::mojom::StringAttribute::kKeyShortcuts, base::UTF16ToUTF8(base::string16(1, mnemonic))); } } @@ -241,6 +242,7 @@ MenuItemView* MenuItemView::AddMenuItemAt( const base::string16& label, const base::string16& sublabel, const base::string16& minor_text, + const gfx::VectorIcon* minor_icon, const gfx::ImageSkia& icon, Type type, ui::MenuSeparatorType separator_style) { @@ -260,6 +262,7 @@ MenuItemView* MenuItemView::AddMenuItemAt( item->SetTitle(label); item->SetSubtitle(sublabel); item->SetMinorText(minor_text); + item->SetMinorIcon(minor_icon); if (!icon.isNull()) item->SetIcon(icon); if (type == SUBMENU) @@ -289,20 +292,22 @@ MenuItemView* MenuItemView::AppendMenuItem(int item_id, const base::string16& label, Type type) { return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(), - gfx::ImageSkia(), type, ui::NORMAL_SEPARATOR); + nullptr, gfx::ImageSkia(), type, + ui::NORMAL_SEPARATOR); } MenuItemView* MenuItemView::AppendSubMenu(int item_id, const base::string16& label) { return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(), - gfx::ImageSkia(), SUBMENU, ui::NORMAL_SEPARATOR); + nullptr, gfx::ImageSkia(), SUBMENU, + ui::NORMAL_SEPARATOR); } MenuItemView* MenuItemView::AppendSubMenuWithIcon(int item_id, const base::string16& label, const gfx::ImageSkia& icon) { return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(), - icon, SUBMENU, ui::NORMAL_SEPARATOR); + nullptr, icon, SUBMENU, ui::NORMAL_SEPARATOR); } MenuItemView* MenuItemView::AppendMenuItemWithLabel( @@ -317,14 +322,15 @@ MenuItemView* MenuItemView::AppendDelegateMenuItem(int item_id) { void MenuItemView::AppendSeparator() { AppendMenuItemImpl(0, base::string16(), base::string16(), base::string16(), - gfx::ImageSkia(), SEPARATOR, ui::NORMAL_SEPARATOR); + nullptr, gfx::ImageSkia(), SEPARATOR, + ui::NORMAL_SEPARATOR); } MenuItemView* MenuItemView::AppendMenuItemWithIcon(int item_id, const base::string16& label, const gfx::ImageSkia& icon) { return AppendMenuItemImpl(item_id, label, base::string16(), base::string16(), - icon, NORMAL, ui::NORMAL_SEPARATOR); + nullptr, icon, NORMAL, ui::NORMAL_SEPARATOR); } MenuItemView* MenuItemView::AppendMenuItemImpl( @@ -332,12 +338,13 @@ MenuItemView* MenuItemView::AppendMenuItemImpl( const base::string16& label, const base::string16& sublabel, const base::string16& minor_text, + const gfx::VectorIcon* minor_icon, const gfx::ImageSkia& icon, Type type, ui::MenuSeparatorType separator_style) { const int index = submenu_ ? submenu_->child_count() : 0; - return AddMenuItemAt(index, item_id, label, sublabel, minor_text, icon, type, - separator_style); + return AddMenuItemAt(index, item_id, label, sublabel, minor_text, minor_icon, + icon, type, separator_style); } SubmenuView* MenuItemView::CreateSubmenu() { @@ -379,6 +386,11 @@ void MenuItemView::SetMinorText(const base::string16& minor_text) { invalidate_dimensions(); // Triggers preferred size recalculation. } +void MenuItemView::SetMinorIcon(const gfx::VectorIcon* minor_icon) { + minor_icon_ = minor_icon; + invalidate_dimensions(); // Triggers preferred size recalculation. +} + void MenuItemView::SetSelected(bool selected) { selected_ = selected; SchedulePaint(); @@ -866,35 +878,56 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) { flags); } - PaintMinorText(canvas, GetTextColor(true, render_selection, emphasized)); + PaintMinorIconAndText(canvas, + GetTextColor(true, render_selection, emphasized)); // Set the submenu indicator (arrow) image and color. if (HasSubmenu()) submenu_arrow_image_view_->SetImage(GetSubmenuArrowImage(icon_color)); } -void MenuItemView::PaintMinorText(gfx::Canvas* canvas, SkColor color) { +void MenuItemView::PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color) { base::string16 minor_text = GetMinorText(); - if (minor_text.empty()) + const gfx::VectorIcon* minor_icon = GetMinorIcon(); + if (minor_text.empty() && !minor_icon) return; int available_height = height() - GetTopMargin() - GetBottomMargin(); - int max_accel_width = + int max_minor_text_width = parent_menu_item_->GetSubmenu()->max_minor_text_width(); const MenuConfig& config = MenuConfig::instance(); - int accel_right_margin = config.align_arrow_and_shortcut ? - config.arrow_to_edge_padding : item_right_margin_; - gfx::Rect accel_bounds(width() - accel_right_margin - max_accel_width, - GetTopMargin(), max_accel_width, available_height); - accel_bounds.set_x(GetMirroredXForRect(accel_bounds)); - int flags = GetDrawStringFlags(); - flags &= ~(gfx::Canvas::TEXT_ALIGN_RIGHT | gfx::Canvas::TEXT_ALIGN_LEFT); - if (base::i18n::IsRTL()) - flags |= gfx::Canvas::TEXT_ALIGN_LEFT; - else - flags |= gfx::Canvas::TEXT_ALIGN_RIGHT; - canvas->DrawStringRectWithFlags(minor_text, GetFontList(), color, - accel_bounds, flags); + int minor_text_right_margin = config.align_arrow_and_shortcut + ? config.arrow_to_edge_padding + : item_right_margin_; + gfx::Rect minor_text_bounds( + width() - minor_text_right_margin - max_minor_text_width, GetTopMargin(), + max_minor_text_width, available_height); + minor_text_bounds.set_x(GetMirroredXForRect(minor_text_bounds)); + + auto render_text = gfx::RenderText::CreateHarfBuzzInstance(); + if (!minor_text.empty()) { + render_text->SetText(minor_text); + render_text->SetFontList(GetFontList()); + render_text->SetColor(color); + render_text->SetDisplayRect(minor_text_bounds); + render_text->SetHorizontalAlignment(base::i18n::IsRTL() ? gfx::ALIGN_LEFT + : gfx::ALIGN_RIGHT); + render_text->Draw(canvas); + } + + if (minor_icon) { + gfx::ImageSkia image = CreateVectorIcon(*minor_icon, color); + + int image_x = GetMirroredRect(minor_text_bounds).right() - + render_text->GetContentWidth() - + (minor_text.empty() ? 0 : config.icon_to_label_padding) - + image.width(); + int minor_text_center_y = + minor_text_bounds.y() + minor_text_bounds.height() / 2; + int image_y = minor_text_center_y - image.height() / 2; + canvas->DrawImageInt( + image, GetMirroredXWithWidthInView(image_x, image.width()), image_y); + } } SkColor MenuItemView::GetTextColor(bool minor, @@ -1057,6 +1090,10 @@ base::string16 MenuItemView::GetMinorText() const { return minor_text_; } +const gfx::VectorIcon* MenuItemView::GetMinorIcon() const { + return minor_icon_; +} + bool MenuItemView::IsContainer() const { // Let the first child take over |this| when we only have one child and no // title. diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h index f474f6f9dac..ab487377b9e 100644 --- a/chromium/ui/views/controls/menu/menu_item_view.h +++ b/chromium/ui/views/controls/menu/menu_item_view.h @@ -29,6 +29,7 @@ namespace gfx { class FontList; +struct VectorIcon; } namespace views { @@ -154,6 +155,7 @@ class VIEWS_EXPORT MenuItemView : public View { const base::string16& label, const base::string16& sublabel, const base::string16& minor_text, + const gfx::VectorIcon* minor_icon, const gfx::ImageSkia& icon, Type type, ui::MenuSeparatorType separator_style); @@ -209,6 +211,7 @@ class VIEWS_EXPORT MenuItemView : public View { const base::string16& label, const base::string16& sublabel, const base::string16& minor_text, + const gfx::VectorIcon* minor_icon, const gfx::ImageSkia& icon, Type type, ui::MenuSeparatorType separator_style); @@ -240,6 +243,9 @@ class VIEWS_EXPORT MenuItemView : public View { // Sets the minor text. void SetMinorText(const base::string16& minor_text); + // Sets the minor icon. + void SetMinorIcon(const gfx::VectorIcon* minor_icon); + // Returns the type of this menu. const Type& GetType() const { return type_; } @@ -395,8 +401,8 @@ class VIEWS_EXPORT MenuItemView : public View { // are not rendered. void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode); - // Paints the right-side text. - void PaintMinorText(gfx::Canvas* canvas, SkColor color); + // Paints the right-side icon and text. + void PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color); // Destroys the window used to display this menu and recursively destroys // the windows used to display all descendants. @@ -406,6 +412,9 @@ class VIEWS_EXPORT MenuItemView : public View { // item. This will be the accelerator (if one exists), otherwise |subtitle_|. base::string16 GetMinorText() const; + // Returns the icon that should be displayed to the left of the minor text. + const gfx::VectorIcon* GetMinorIcon() const; + // Returns the text color for the current state. |minor| specifies if the // minor text or the normal text is desired. SkColor GetTextColor(bool minor, @@ -484,6 +493,9 @@ class VIEWS_EXPORT MenuItemView : public View { // Minor text. base::string16 minor_text_; + // Minor icon. + const gfx::VectorIcon* minor_icon_ = nullptr; + // Does the title have a mnemonic? Only useful on the root menu item. bool has_mnemonics_; diff --git a/chromium/ui/views/controls/menu/menu_item_view_unittest.cc b/chromium/ui/views/controls/menu/menu_item_view_unittest.cc index ab5f10ec455..bdc22a6b784 100644 --- a/chromium/ui/views/controls/menu/menu_item_view_unittest.cc +++ b/chromium/ui/views/controls/menu/menu_item_view_unittest.cc @@ -8,8 +8,12 @@ #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/compositor/canvas_painter.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/controls/menu/submenu_view.h" +#include "ui/views/test/menu_test_utils.h" +#include "ui/views/test/views_test_base.h" +#include "ui/views/vector_icons.h" namespace views { @@ -143,4 +147,69 @@ TEST(MenuItemViewUnitTest, TestEmptySubmenuWhenAllChildItemsAreHidden) { empty_item->title()); } +class MenuItemViewPaintUnitTest : public ViewsTestBase { + public: + MenuItemViewPaintUnitTest() {} + ~MenuItemViewPaintUnitTest() override {} + + MenuItemView* menu_item_view() { return menu_item_view_; } + MenuRunner* menu_runner() { return menu_runner_.get(); } + Widget* widget() { return widget_.get(); } + + // ViewsTestBase implementation. + void SetUp() override { + ViewsTestBase::SetUp(); + menu_delegate_.reset(new test::TestMenuDelegate); + menu_item_view_ = new MenuItemView(menu_delegate_.get()); + + widget_.reset(new Widget); + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget_->Init(params); + widget_->Show(); + + menu_runner_.reset(new MenuRunner(menu_item_view_, 0)); + } + + void TearDown() override { + widget_->CloseNow(); + ViewsTestBase::TearDown(); + } + + private: + // Owned by MenuRunner. + MenuItemView* menu_item_view_; + + std::unique_ptr<test::TestMenuDelegate> menu_delegate_; + std::unique_ptr<MenuRunner> menu_runner_; + std::unique_ptr<Widget> widget_; + + DISALLOW_COPY_AND_ASSIGN(MenuItemViewPaintUnitTest); +}; + +// Provides assertion coverage for painting minor text and icons. +TEST_F(MenuItemViewPaintUnitTest, MinorTextAndIconAssertionCoverage) { + auto AddItem = [this](auto label, auto minor_label, auto minor_icon) { + menu_item_view()->AddMenuItemAt( + 0, 1000, base::ASCIIToUTF16(label), base::string16(), minor_label, + minor_icon, gfx::ImageSkia(), views::MenuItemView::NORMAL, + ui::NORMAL_SEPARATOR); + }; + AddItem("No minor content", base::string16(), nullptr); + AddItem("Minor text only", base::ASCIIToUTF16("minor text"), nullptr); + AddItem("Minor icon only", base::string16(), &views::kMenuCheckIcon); + AddItem("Minor text and icon", base::ASCIIToUTF16("minor text"), + &views::kMenuCheckIcon); + + menu_runner()->RunMenuAt(widget(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT, + ui::MENU_SOURCE_KEYBOARD); + + SkBitmap bitmap; + gfx::Size size = menu_item_view()->GetMirroredBounds().size(); + ui::CanvasPainter canvas_painter(&bitmap, size, 1.f, SK_ColorTRANSPARENT, + false); + menu_item_view()->GetSubmenu()->Paint( + PaintInfo::CreateRootPaintInfo(canvas_painter.context(), size)); +} + } // namespace views diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc index 06a9d3cfda9..2a540157090 100644 --- a/chromium/ui/views/controls/menu/menu_model_adapter.cc +++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc @@ -64,6 +64,7 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model, gfx::Image icon; model->GetIconAt(model_index, &icon); base::string16 label, sublabel, minor_text; + const gfx::VectorIcon* minor_icon = nullptr; ui::MenuSeparatorType separator_style = ui::NORMAL_SEPARATOR; MenuItemView::Type type; ui::MenuModel::ItemType menu_type = model->GetTypeAt(model_index); @@ -75,18 +76,21 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model, label = model->GetLabelAt(model_index); sublabel = model->GetSublabelAt(model_index); minor_text = model->GetMinorTextAt(model_index); + minor_icon = model->GetMinorIconAt(model_index); break; case ui::MenuModel::TYPE_CHECK: type = MenuItemView::CHECKBOX; label = model->GetLabelAt(model_index); sublabel = model->GetSublabelAt(model_index); minor_text = model->GetMinorTextAt(model_index); + minor_icon = model->GetMinorIconAt(model_index); break; case ui::MenuModel::TYPE_RADIO: type = MenuItemView::RADIO; label = model->GetLabelAt(model_index); sublabel = model->GetSublabelAt(model_index); minor_text = model->GetMinorTextAt(model_index); + minor_icon = model->GetMinorIconAt(model_index); break; case ui::MenuModel::TYPE_SEPARATOR: icon = gfx::Image(); @@ -98,6 +102,7 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model, label = model->GetLabelAt(model_index); sublabel = model->GetSublabelAt(model_index); minor_text = model->GetMinorTextAt(model_index); + minor_icon = model->GetMinorIconAt(model_index); break; default: NOTREACHED(); @@ -106,13 +111,8 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model, } return menu->AddMenuItemAt( - menu_index, - item_id, - label, - sublabel, - minor_text, - icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(), - type, + menu_index, item_id, label, sublabel, minor_text, minor_icon, + icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(), type, separator_style); } diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc index fc9e3426f7c..01069fe8680 100644 --- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc +++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc @@ -259,7 +259,7 @@ void MenuScrollViewContainer::OnPaintBackground(gfx::Canvas* canvas) { void MenuScrollViewContainer::GetAccessibleNodeData(ui::AXNodeData* node_data) { // Get the name from the submenu view. content_view_->GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_MENU_BAR; + node_data->role = ax::mojom::Role::kMenuBar; } void MenuScrollViewContainer::OnBoundsChanged( diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc index f7a75314ec4..b8926dedbdc 100644 --- a/chromium/ui/views/controls/menu/submenu_view.cc +++ b/chromium/ui/views/controls/menu/submenu_view.cc @@ -194,9 +194,9 @@ void SubmenuView::GetAccessibleNodeData(ui::AXNodeData* node_data) { // the orientation. if (GetMenuItem()) GetMenuItem()->GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_MENU_LIST_POPUP; + node_data->role = ax::mojom::Role::kMenuListPopup; // Menus in Chrome are always traversed in a vertical direction. - node_data->AddState(ui::AX_STATE_VERTICAL); + node_data->AddState(ax::mojom::State::kVertical); } void SubmenuView::PaintChildren(const PaintInfo& paint_info) { @@ -389,11 +389,8 @@ void SubmenuView::ShowAt(Widget* parent, } GetScrollViewContainer()->NotifyAccessibilityEvent( - ui::AX_EVENT_MENU_START, - true); - NotifyAccessibilityEvent( - ui::AX_EVENT_MENU_POPUP_START, - true); + ax::mojom::Event::kMenuStart, true); + NotifyAccessibilityEvent(ax::mojom::Event::kMenuPopupStart, true); } void SubmenuView::Reposition(const gfx::Rect& bounds) { @@ -403,9 +400,9 @@ void SubmenuView::Reposition(const gfx::Rect& bounds) { void SubmenuView::Close() { if (host_) { - NotifyAccessibilityEvent(ui::AX_EVENT_MENU_POPUP_END, true); + NotifyAccessibilityEvent(ax::mojom::Event::kMenuPopupEnd, true); GetScrollViewContainer()->NotifyAccessibilityEvent( - ui::AX_EVENT_MENU_END, true); + ax::mojom::Event::kMenuEnd, true); host_->DestroyMenuHost(); host_ = NULL; diff --git a/chromium/ui/views/controls/message_box_view.cc b/chromium/ui/views/controls/message_box_view.cc index 087c94001c5..27dc783cf4f 100644 --- a/chromium/ui/views/controls/message_box_view.cc +++ b/chromium/ui/views/controls/message_box_view.cc @@ -136,7 +136,7 @@ void MessageBoxView::SetLink(const base::string16& text, } void MessageBoxView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_ALERT; + node_data->role = ax::mojom::Role::kAlert; } /////////////////////////////////////////////////////////////////////////////// @@ -148,7 +148,7 @@ void MessageBoxView::ViewHierarchyChanged( if (prompt_field_) prompt_field_->SelectAll(true); - NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); } } @@ -207,8 +207,9 @@ void MessageBoxView::Init(const InitParams& params) { message_labels_[0]->SetSelectable(true); if (params.options & HAS_PROMPT_FIELD) { - prompt_field_ = new Textfield; + prompt_field_ = new Textfield(); prompt_field_->SetText(params.default_prompt); + prompt_field_->SetAccessibleName(params.message); } inter_row_vertical_spacing_ = params.inter_row_vertical_spacing; diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc index 2c5016d5d5d..df116d35b8a 100644 --- a/chromium/ui/views/controls/native/native_view_host.cc +++ b/chromium/ui/views/controls/native/native_view_host.cc @@ -185,7 +185,7 @@ const char* NativeViewHost::GetClassName() const { void NativeViewHost::OnFocus() { if (native_view_) native_wrapper_->SetFocus(); - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); + NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true); } gfx::NativeViewAccessible NativeViewHost::GetNativeViewAccessible() { diff --git a/chromium/ui/views/controls/progress_bar.cc b/chromium/ui/views/controls/progress_bar.cc index f0b0ade79da..2a5bbfd9a64 100644 --- a/chromium/ui/views/controls/progress_bar.cc +++ b/chromium/ui/views/controls/progress_bar.cc @@ -54,7 +54,7 @@ ProgressBar::~ProgressBar() { } void ProgressBar::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_PROGRESS_INDICATOR; + node_data->role = ax::mojom::Role::kProgressIndicator; } gfx::Size ProgressBar::CalculatePreferredSize() const { diff --git a/chromium/ui/views/controls/progress_bar_unittest.cc b/chromium/ui/views/controls/progress_bar_unittest.cc index 2fe8ba943b2..6eddafe318b 100644 --- a/chromium/ui/views/controls/progress_bar_unittest.cc +++ b/chromium/ui/views/controls/progress_bar_unittest.cc @@ -18,9 +18,11 @@ TEST(ProgressBarTest, Accessibility) { ui::AXNodeData node_data; bar.GetAccessibleNodeData(&node_data); - EXPECT_EQ(ui::AX_ROLE_PROGRESS_INDICATOR, node_data.role); - EXPECT_EQ(base::string16(), node_data.GetString16Attribute(ui::AX_ATTR_NAME)); - EXPECT_FALSE(node_data.HasIntAttribute(ui::AX_ATTR_RESTRICTION)); + EXPECT_EQ(ax::mojom::Role::kProgressIndicator, node_data.role); + EXPECT_EQ(base::string16(), + node_data.GetString16Attribute(ax::mojom::StringAttribute::kName)); + EXPECT_FALSE( + node_data.HasIntAttribute(ax::mojom::IntAttribute::kRestriction)); } // Test that default colors can be overridden. Used by Chromecast. diff --git a/chromium/ui/views/controls/resize_area.cc b/chromium/ui/views/controls/resize_area.cc index 06c0325fea3..6601ad28224 100644 --- a/chromium/ui/views/controls/resize_area.cc +++ b/chromium/ui/views/controls/resize_area.cc @@ -70,7 +70,7 @@ void ResizeArea::OnMouseCaptureLost() { } void ResizeArea::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_SPLITTER; + node_data->role = ax::mojom::Role::kSplitter; } void ResizeArea::ReportResizeAmount(int resize_amount, bool last_update) { diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc index 12eeb9af696..9add6bb5776 100644 --- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc +++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc @@ -268,20 +268,37 @@ void BaseScrollBar::ShowContextMenuForView(View* source, View::ConvertPointFromWidget(this, &temp_pt); context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y(); - views::MenuItemView* menu = new views::MenuItemView(this); - // MenuRunner takes ownership of |menu|. - menu_runner_.reset(new MenuRunner( - menu, MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU)); - menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere); - menu->AppendSeparator(); - menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart); - menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollEnd); - menu->AppendSeparator(); - menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageUp); - menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageDown); - menu->AppendSeparator(); - menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev); - menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext); + if (!menu_model_) { + menu_model_ = std::make_unique<ui::SimpleMenuModel>(this); + menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollHere, + IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE); + menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); + menu_model_->AddItemWithStringId( + ScrollBarContextMenuCommand_ScrollStart, + IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE + : IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME); + menu_model_->AddItemWithStringId( + ScrollBarContextMenuCommand_ScrollEnd, + IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE + : IDS_APP_SCROLLBAR_CXMENU_SCROLLEND); + menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); + menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPageUp, + IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP); + menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPageDown, + IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN); + menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); + menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollPrev, + IsHorizontal() + ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT + : IDS_APP_SCROLLBAR_CXMENU_SCROLLUP); + menu_model_->AddItemWithStringId(ScrollBarContextMenuCommand_ScrollNext, + IsHorizontal() + ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT + : IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN); + } + menu_runner_ = std::make_unique<MenuRunner>( + menu_model_.get(), + MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU); menu_runner_->RunMenuAt(GetWidget(), nullptr, gfx::Rect(p, gfx::Size()), MENU_ANCHOR_TOPLEFT, source_type); } @@ -289,42 +306,7 @@ void BaseScrollBar::ShowContextMenuForView(View* source, /////////////////////////////////////////////////////////////////////////////// // BaseScrollBar, Menu::Delegate implementation: -base::string16 BaseScrollBar::GetLabel(int id) const { - int ids_value = 0; - switch (id) { - case ScrollBarContextMenuCommand_ScrollHere: - ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE; - break; - case ScrollBarContextMenuCommand_ScrollStart: - ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE - : IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME; - break; - case ScrollBarContextMenuCommand_ScrollEnd: - ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE - : IDS_APP_SCROLLBAR_CXMENU_SCROLLEND; - break; - case ScrollBarContextMenuCommand_ScrollPageUp: - ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP; - break; - case ScrollBarContextMenuCommand_ScrollPageDown: - ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN; - break; - case ScrollBarContextMenuCommand_ScrollPrev: - ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT - : IDS_APP_SCROLLBAR_CXMENU_SCROLLUP; - break; - case ScrollBarContextMenuCommand_ScrollNext: - ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT - : IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN; - break; - default: - NOTREACHED() << "Invalid BaseScrollBar Context Menu command!"; - } - - return ids_value ? l10n_util::GetStringUTF16(ids_value) : base::string16(); -} - -bool BaseScrollBar::IsCommandEnabled(int id) const { +bool BaseScrollBar::IsCommandIdEnabled(int id) const { switch (id) { case ScrollBarContextMenuCommand_ScrollPageUp: case ScrollBarContextMenuCommand_ScrollPageDown: @@ -333,7 +315,11 @@ bool BaseScrollBar::IsCommandEnabled(int id) const { return true; } -void BaseScrollBar::ExecuteCommand(int id) { +bool BaseScrollBar::IsCommandIdChecked(int id) const { + return false; +} + +void BaseScrollBar::ExecuteCommand(int id, int event_flags) { switch (id) { case ScrollBarContextMenuCommand_ScrollHere: ScrollToThumbPosition(context_menu_mouse_position_, true); diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h index 7c89c6f2580..07ae5b04111 100644 --- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h +++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h @@ -7,10 +7,10 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "ui/base/models/simple_menu_model.h" #include "ui/views/animation/scroll_animator.h" #include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/image_button.h" -#include "ui/views/controls/menu/menu_delegate.h" #include "ui/views/controls/scrollbar/scroll_bar.h" #include "ui/views/repeat_controller.h" @@ -30,7 +30,7 @@ class MenuRunner; class VIEWS_EXPORT BaseScrollBar : public ScrollBar, public ScrollDelegate, public ContextMenuController, - public MenuDelegate { + public ui::SimpleMenuModel::Delegate { public: explicit BaseScrollBar(bool horizontal); ~BaseScrollBar() override; @@ -90,10 +90,10 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar, const gfx::Point& point, ui::MenuSourceType source_type) override; - // Menu::Delegate overrides: - base::string16 GetLabel(int id) const override; - bool IsCommandEnabled(int id) const override; - void ExecuteCommand(int id) override; + // ui::SimpleMenuModel::Delegate overrides: + bool IsCommandIdChecked(int id) const override; + bool IsCommandIdEnabled(int id) const override; + void ExecuteCommand(int id, int event_flags) override; protected: BaseScrollBarThumb* GetThumb() const; @@ -166,6 +166,7 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar, // was invoked. int context_menu_mouse_position_; + std::unique_ptr<ui::SimpleMenuModel> menu_model_; std::unique_ptr<MenuRunner> menu_runner_; std::unique_ptr<ScrollAnimator> scroll_animator_; diff --git a/chromium/ui/views/controls/scrollbar/scroll_bar.cc b/chromium/ui/views/controls/scrollbar/scroll_bar.cc index 67146933197..be7c83eec68 100644 --- a/chromium/ui/views/controls/scrollbar/scroll_bar.cc +++ b/chromium/ui/views/controls/scrollbar/scroll_bar.cc @@ -12,7 +12,7 @@ ScrollBar::~ScrollBar() { } void ScrollBar::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_SCROLL_BAR; + node_data->role = ax::mojom::Role::kScrollBar; } bool ScrollBar::IsHorizontal() const { diff --git a/chromium/ui/views/controls/separator.cc b/chromium/ui/views/controls/separator.cc index 82a6cabbd71..8be91e790d2 100644 --- a/chromium/ui/views/controls/separator.cc +++ b/chromium/ui/views/controls/separator.cc @@ -41,7 +41,7 @@ gfx::Size Separator::CalculatePreferredSize() const { } void Separator::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_SPLITTER; + node_data->role = ax::mojom::Role::kSplitter; } void Separator::OnPaint(gfx::Canvas* canvas) { diff --git a/chromium/ui/views/controls/slider.cc b/chromium/ui/views/controls/slider.cc index c52218fa2a6..015c695e102 100644 --- a/chromium/ui/views/controls/slider.cc +++ b/chromium/ui/views/controls/slider.cc @@ -87,10 +87,6 @@ void Slider::SetValue(float value) { SetValueInternal(value, VALUE_CHANGED_BY_API); } -void Slider::SetAccessibleName(const base::string16& name) { - accessible_name_ = name; -} - void Slider::UpdateState(bool control_on) { is_active_ = control_on; SchedulePaint(); @@ -158,7 +154,7 @@ void Slider::SetValueInternal(float value, SliderChangeReason reason) { if (accessibility_events_enabled_) { if (GetWidget() && GetWidget()->IsVisible()) { DCHECK(!pending_accessibility_value_change_); - NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); } else { pending_accessibility_value_change_ = true; } @@ -258,8 +254,7 @@ bool Slider::OnKeyPressed(const ui::KeyEvent& event) { } void Slider::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_SLIDER; - node_data->SetName(accessible_name_); + node_data->role = ax::mojom::Role::kSlider; node_data->SetValue(base::UTF8ToUTF16( base::StringPrintf("%d%%", static_cast<int>(value_ * 100 + 0.5)))); } @@ -341,7 +336,7 @@ void Slider::NotifyPendingAccessibilityValueChanged() { if (!pending_accessibility_value_change_) return; - NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); pending_accessibility_value_change_ = false; } @@ -352,7 +347,7 @@ void Slider::OnGestureEvent(ui::GestureEvent* event) { case ui::ET_GESTURE_TAP_DOWN: OnSliderDragStarted(); PrepareForMove(event->location().x()); - // Intentional fall through to next case. + FALLTHROUGH; case ui::ET_GESTURE_SCROLL_BEGIN: case ui::ET_GESTURE_SCROLL_UPDATE: MoveButtonTo(event->location()); diff --git a/chromium/ui/views/controls/slider.h b/chromium/ui/views/controls/slider.h index db8d7e1ea77..66121a2ffb9 100644 --- a/chromium/ui/views/controls/slider.h +++ b/chromium/ui/views/controls/slider.h @@ -53,8 +53,6 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate { float value() const { return value_; } void SetValue(float value); - void SetAccessibleName(const base::string16& name); - void set_enable_accessibility_events(bool enabled) { accessibility_events_enabled_ = enabled; } @@ -124,7 +122,6 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate { float keyboard_increment_ = 0.1f; float initial_animating_value_ = 0.f; bool value_is_valid_ = false; - base::string16 accessible_name_; bool accessibility_events_enabled_ = true; // Relative position of the mouse cursor (or the touch point) on the slider's diff --git a/chromium/ui/views/controls/slider_unittest.cc b/chromium/ui/views/controls/slider_unittest.cc index 46ee5fd2aca..5ce176bd113 100644 --- a/chromium/ui/views/controls/slider_unittest.cc +++ b/chromium/ui/views/controls/slider_unittest.cc @@ -129,8 +129,9 @@ class SliderTest : public views::ViewsTestBase { bool has_value_changed() { return has_value_changed_; } private: - void NotifyAccessibilityEvent(View* view, ui::AXEvent event_type) override { - if (event_type == ui::AX_EVENT_VALUE_CHANGED) + void NotifyAccessibilityEvent(View* view, + ax::mojom::Event event_type) override { + if (event_type == ax::mojom::Event::kValueChanged) has_value_changed_ = true; } diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc index 95b60d61197..1515c68c296 100644 --- a/chromium/ui/views/controls/styled_label.cc +++ b/chromium/ui/views/controls/styled_label.cc @@ -6,12 +6,16 @@ #include <stddef.h> +#include <algorithm> #include <limits> +#include <memory> #include <vector> +#include "base/i18n/rtl.h" #include "base/strings/string_util.h" #include "ui/gfx/font_list.h" #include "ui/gfx/text_elider.h" +#include "ui/gfx/text_utils.h" #include "ui/native_theme/native_theme.h" #include "ui/views/controls/label.h" #include "ui/views/controls/link.h" @@ -65,6 +69,16 @@ std::unique_ptr<Label> CreateLabelRange( return result; } +// Returns the horizontal offset to align views in a line. +int HorizontalAdjustment(int used_width, + int width, + gfx::HorizontalAlignment alignment) { + const int space = width - used_width; + return alignment == gfx::ALIGN_LEFT + ? 0 + : alignment == gfx::ALIGN_CENTER ? space / 2 : space; +} + } // namespace // StyledLabel::RangeStyleInfo ------------------------------------------------ @@ -108,7 +122,9 @@ StyledLabel::StyledLabel(const base::string16& text, width_at_last_layout_(0), displayed_on_background_color_(SkColorSetRGB(0xFF, 0xFF, 0xFF)), displayed_on_background_color_set_(false), - auto_color_readability_enabled_(true) { + auto_color_readability_enabled_(true), + horizontal_alignment_(base::i18n::IsRTL() ? gfx::ALIGN_RIGHT + : gfx::ALIGN_LEFT) { base::TrimWhitespace(text, base::TRIM_TRAILING, &text_); } @@ -139,6 +155,11 @@ void StyledLabel::AddStyleRange(const gfx::Range& range, PreferredSizeChanged(); } +void StyledLabel::AddCustomView(std::unique_ptr<View> custom_view) { + DCHECK(custom_view->owned_by_client()); + custom_views_.insert(std::move(custom_view)); +} + void StyledLabel::SetTextContext(int text_context) { if (text_context_ == text_context) return; @@ -232,6 +253,22 @@ void StyledLabel::LinkClicked(Link* source, int event_flags) { listener_->StyledLabelLinkClicked(this, link_targets_[source], event_flags); } +// TODO(wutao): support gfx::ALIGN_TO_HEAD alignment. +void StyledLabel::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) { + DCHECK_NE(gfx::ALIGN_TO_HEAD, alignment); + alignment = gfx::MaybeFlipForRTL(alignment); + + if (horizontal_alignment_ == alignment) + return; + horizontal_alignment_ = alignment; + SchedulePaint(); +} + +void StyledLabel::ClearStyleRanges() { + style_ranges_.clear(); + PreferredSizeChanged(); +} + int StyledLabel::GetDefaultLineHeight() const { return specified_line_height_ > 0 ? specified_line_height_ @@ -271,13 +308,13 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { if (width <= 0 || text_.empty()) return gfx::Size(); - const int line_height = GetDefaultLineHeight(); + const int default_line_height = GetDefaultLineHeight(); // The index of the line we're on. int line = 0; - // The x position (in pixels) of the line we're on, relative to content - // bounds. - int x = 0; + const gfx::Insets insets = GetInsets(); + // The current child view's position, relative to content bounds, in pixels. + gfx::Point offset(0, insets.top()); int total_height = 0; // The width that was actually used. Guaranteed to be no larger than |width|. int used_width = 0; @@ -290,10 +327,16 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { bool first_loop_iteration = true; + // Max height of the views in a line. + int max_line_height = default_line_height; + + // Temporary references to the views in a line, used for alignment. + std::vector<View*> views_in_a_line; + // Iterate over the text, creating a bunch of labels and links and laying them // out in the appropriate positions. while (!remaining_string.empty()) { - if (x == 0 && !first_loop_iteration) { + if (offset.x() == 0 && !first_loop_iteration) { if (remaining_string.front() == L'\n') { // Wrapped to the next line on \n, remove it. Other whitespace, // eg, spaces to indent next line, are preserved. @@ -312,75 +355,104 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { range = current_range->range; const size_t position = text_.size() - remaining_string.size(); - - const gfx::Rect chunk_bounds(x, 0, width - x, 2 * line_height); std::vector<base::string16> substrings; - // If the start of the remaining text is inside a styled range, the font - // style may differ from the base font. The font specified by the range - // should be used when eliding text. - gfx::FontList text_font_list = position >= range.start() - ? GetFontListForRange(current_range) - : GetDefaultFontList(); - int elide_result = gfx::ElideRectangleText( - remaining_string, text_font_list, chunk_bounds.width(), - chunk_bounds.height(), gfx::WRAP_LONG_WORDS, &substrings); - - if (substrings.empty()) { - // There is no room for anything; abort. Since wrapping is enabled, this - // should only occur if there is insufficient vertical space remaining. - // ElideRectangleText always adds a single character, even if there is no - // room horizontally. - DCHECK_NE(0, elide_result & gfx::INSUFFICIENT_SPACE_VERTICAL); - break; - } + // If the current range is not a custom_view, then we use ElideRectangleText + // to determine the line wrapping. Note: if it is a custom_view, then the + // |position| should equal |range.start()| because the custom_view is + // treated as one unit. + if (position != range.start() || (current_range != style_ranges_.end() && + !current_range->style_info.custom_view)) { + const gfx::Rect chunk_bounds(offset.x(), 0, width - offset.x(), + default_line_height); + // If the start of the remaining text is inside a styled range, the font + // style may differ from the base font. The font specified by the range + // should be used when eliding text. + gfx::FontList text_font_list = position >= range.start() + ? GetFontListForRange(current_range) + : GetDefaultFontList(); + int elide_result = gfx::ElideRectangleText( + remaining_string, text_font_list, chunk_bounds.width(), + chunk_bounds.height(), gfx::WRAP_LONG_WORDS, &substrings); + + if (substrings.empty()) { + // There is no room for anything; abort. Since wrapping is enabled, this + // should only occur if there is insufficient vertical space remaining. + // ElideRectangleText always adds a single character, even if there is + // no room horizontally. + DCHECK_NE(0, elide_result & gfx::INSUFFICIENT_SPACE_VERTICAL); + break; + } - // Views are aligned to integer coordinates, but typesetting is not. This - // means that it's possible for an ElideRectangleText on a prior iteration - // to fit a word on the current line, which does not fit after that word is - // wrapped in a View for its chunk at the end of the line. In most cases, - // this will just wrap more words on to the next line. However, if the - // remaining chunk width is insufficient for the very _first_ word, that - // word will be incorrectly split. In this case, start a new line instead. - bool truncated_chunk = - x != 0 && (elide_result & gfx::INSUFFICIENT_SPACE_FOR_FIRST_WORD) != 0; - if (substrings[0].empty() || truncated_chunk) { - // The entire line is \n, or nothing fits on this line. Start a new line. - // As for the first line, don't advance line number so that it will be - // handled again at the beginning of the loop. - if (x != 0 || line > 0) { - ++line; + // Views are aligned to integer coordinates, but typesetting is not. This + // means that it's possible for an ElideRectangleText on a prior iteration + // to fit a word on the current line, which does not fit after that word + // is wrapped in a View for its chunk at the end of the line. In most + // cases, this will just wrap more words on to the next line. However, if + // the remaining chunk width is insufficient for the very _first_ word, + // that word will be incorrectly split. In this case, start a new line + // instead. + bool truncated_chunk = + offset.x() != 0 && + (elide_result & gfx::INSUFFICIENT_SPACE_FOR_FIRST_WORD) != 0; + if (substrings[0].empty() || truncated_chunk) { + // The entire line is \n, or nothing fits on this line. Start a new + // line. As for the first line, don't advance line number so that it + // will be handled again at the beginning of the loop. + AdvanceOneLine(&line, &offset, &max_line_height, width, + &views_in_a_line, + offset.x() != 0 || line > 0 /* new_line */); + continue; } - x = 0; - continue; } - base::string16 chunk = substrings[0]; - + base::string16 chunk; + View* custom_view = nullptr; std::unique_ptr<Label> label; if (position >= range.start()) { const RangeStyleInfo& style_info = current_range->style_info; - if (style_info.disable_line_wrapping && chunk.size() < range.length() && - position == range.start() && x != 0) { + if (style_info.custom_view) { + custom_view = style_info.custom_view; + // Ownership of the custom view must be passed to StyledLabel. + DCHECK( + std::find_if(custom_views_.cbegin(), custom_views_.cend(), + [custom_view](const std::unique_ptr<View>& view_ptr) { + return view_ptr.get() == custom_view; + }) != custom_views_.cend()); + // Do not allow wrap in custom view. + DCHECK_EQ(position, range.start()); + chunk = remaining_string.substr(0, range.end() - position); + } else { + chunk = substrings[0]; + } + + if (((custom_view && + offset.x() + custom_view->GetPreferredSize().width() > width) || + (style_info.disable_line_wrapping && + chunk.size() < range.length())) && + position == range.start() && offset.x() != 0) { // If the chunk should not be wrapped, try to fit it entirely on the // next line. - x = 0; - ++line; + AdvanceOneLine(&line, &offset, &max_line_height, width, + &views_in_a_line); continue; } if (chunk.size() > range.end() - position) chunk = chunk.substr(0, range.end() - position); - label = CreateLabelRange(chunk, text_context_, default_text_style_, - style_info, this); - - if (style_info.IsLink() && !dry_run) - link_targets_[label.get()] = range; + if (!custom_view) { + label = CreateLabelRange(chunk, text_context_, default_text_style_, + style_info, this); + if (style_info.IsLink() && !dry_run) + link_targets_[label.get()] = range; + } if (position + chunk.size() >= range.end()) ++current_range; } else { + chunk = substrings[0]; + // This chunk is normal text. if (position + chunk.size() > range.start()) chunk = chunk.substr(0, range.start() - position); @@ -388,53 +460,86 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) { default_style, this); } - if (displayed_on_background_color_set_) - label->SetBackgroundColor(displayed_on_background_color_); - label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_); + if (label) { + if (displayed_on_background_color_set_) + label->SetBackgroundColor(displayed_on_background_color_); + label->SetAutoColorReadabilityEnabled(auto_color_readability_enabled_); + } - const gfx::Size view_size = label->GetPreferredSize(); - const gfx::Insets insets = GetInsets(); - gfx::Point view_origin(insets.left() + x, - insets.top() + line * line_height); - if (Link::GetDefaultFocusStyle() == Link::FocusStyle::RING) { + View* child_view = custom_view ? custom_view : label.get(); + gfx::Size view_size = child_view->GetPreferredSize(); + // |offset.y()| already contains |insets.top()|. + gfx::Point view_origin(insets.left() + offset.x(), offset.y()); + gfx::Insets focus_border_insets; + if (Link::GetDefaultFocusStyle() == Link::FocusStyle::RING && label) { // Calculate the size of the optional focus border, and overlap by that // amount. Otherwise, "<a>link</a>," will render as "link ,". - const gfx::Insets focus_border_insets = FocusBorderInsets(*label); - view_origin.Offset(-focus_border_insets.left(), - -focus_border_insets.top()); - label->SetBoundsRect(gfx::Rect(view_origin, view_size)); - x += view_size.width() - focus_border_insets.width(); - used_width = std::max(used_width, x); - total_height = - std::max(total_height, label->bounds().bottom() + insets.bottom() - - focus_border_insets.bottom()); - } else { - label->SetBoundsRect(gfx::Rect(view_origin, view_size)); - x += view_size.width(); - total_height = - std::max(total_height, label->bounds().bottom() + insets.bottom()); + focus_border_insets = FocusBorderInsets(*label); + } + view_origin.Offset(-focus_border_insets.left(), -focus_border_insets.top()); + // The custom view could be wider than the available width; clamp as needed. + if (custom_view) { + view_size.set_width(std::min( + view_size.width(), width - offset.x() + focus_border_insets.width())); + } + child_view->SetBoundsRect(gfx::Rect(view_origin, view_size)); + offset.set_x(offset.x() + view_size.width() - focus_border_insets.width()); + total_height = + std::max(total_height, child_view->bounds().bottom() + insets.bottom() - + focus_border_insets.bottom()); + used_width = std::max(used_width, offset.x()); + max_line_height = std::max( + max_line_height, view_size.height() - focus_border_insets.height()); + + if (!dry_run) { + views_in_a_line.push_back(child_view); + if (label) + AddChildView(label.release()); + else + AddChildView(child_view); } - used_width = std::max(used_width, x); - - if (!dry_run) - AddChildView(label.release()); // If |gfx::ElideRectangleText| returned more than one substring, that // means the whole text did not fit into remaining line width, with text // after |susbtring[0]| spilling into next line. If whole |substring[0]| // was added to the current line (this may not be the case if part of the // substring has different style), proceed to the next line. - if (substrings.size() > 1 && chunk.size() == substrings[0].size()) { - x = 0; - ++line; + if (!custom_view && substrings.size() > 1 && + chunk.size() == substrings[0].size()) { + AdvanceOneLine(&line, &offset, &max_line_height, width, &views_in_a_line); } remaining_string = remaining_string.substr(chunk.size()); } - + AdvanceOneLine(&line, &offset, &max_line_height, width, &views_in_a_line, + false); DCHECK_LE(used_width, width); calculated_size_ = gfx::Size(used_width + GetInsets().width(), total_height); return calculated_size_; } +void StyledLabel::AdvanceOneLine(int* line_number, + gfx::Point* offset, + int* max_line_height, + int width, + std::vector<View*>* views_in_a_line, + bool new_line) { + const int x_delta = + HorizontalAdjustment(offset->x(), width, horizontal_alignment_); + for (auto* view : *views_in_a_line) { + gfx::Rect bounds = view->bounds(); + bounds.set_x(bounds.x() + x_delta); + bounds.set_y(offset->y() + (*max_line_height - bounds.height()) / 2.0f); + view->SetBoundsRect(bounds); + } + views_in_a_line->clear(); + + if (new_line) { + ++(*line_number); + offset->set_y(offset->y() + *max_line_height); + *max_line_height = GetDefaultLineHeight(); + } + offset->set_x(0); +} + } // namespace views diff --git a/chromium/ui/views/controls/styled_label.h b/chromium/ui/views/controls/styled_label.h index 5b25f40ba21..6dc8e734bdc 100644 --- a/chromium/ui/views/controls/styled_label.h +++ b/chromium/ui/views/controls/styled_label.h @@ -7,6 +7,8 @@ #include <list> #include <map> +#include <memory> +#include <set> #include "base/macros.h" #include "base/optional.h" @@ -15,6 +17,7 @@ #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/range/range.h" +#include "ui/gfx/text_constants.h" #include "ui/views/controls/link_listener.h" #include "ui/views/style/typography.h" #include "ui/views/view.h" @@ -62,6 +65,10 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener { // If set, the whole range will be put on a single line. bool disable_line_wrapping = false; + + // A custom view shown instead of the underlying text. Ownership of custom + // views must be passed to StyledLabel via AddCustomView(). + View* custom_view = nullptr; }; // Note that any trailing whitespace in |text| will be trimmed. @@ -81,6 +88,9 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener { // |range| must be contained in |text_|. void AddStyleRange(const gfx::Range& range, const RangeStyleInfo& style_info); + // Passes ownership of a custom view for use by RangeStyleInfo structs. + void AddCustomView(std::unique_ptr<View> custom_view); + // Set the context of this text. All ranges have the same context. // |text_context| must be a value from views::style::TextContext. void SetTextContext(int text_context); @@ -125,6 +135,12 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener { // LinkListener implementation: void LinkClicked(Link* source, int event_flags) override; + // Sets the horizontal alignment; the argument value is mirrored in RTL UI. + void SetHorizontalAlignment(gfx::HorizontalAlignment alignment); + + // Clears all the styles applied to the label. + void ClearStyleRanges(); + private: struct StyleRange { StyleRange(const gfx::Range& range, @@ -155,6 +171,15 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener { // |width_at_last_size_calculation_|. Returns the needed size. gfx::Size CalculateAndDoLayout(int width, bool dry_run); + // Adjusts the offsets of the views in a line for alignment and other line + // parameters. + void AdvanceOneLine(int* line_number, + gfx::Point* offset, + int* max_line_height, + int width, + std::vector<View*>* views_in_a_line, + bool new_line = true); + // The text to display. base::string16 text_; @@ -174,6 +199,9 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener { // that correspond to ranges with is_link style set will be added to the map. std::map<View*, gfx::Range> link_targets_; + // Owns the custom views used to replace ranges of text with icons, etc. + std::set<std::unique_ptr<View>> custom_views_; + // This variable saves the result of the last GetHeightForWidth call in order // to avoid repeated calculation. mutable gfx::Size calculated_size_; @@ -188,6 +216,10 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener { // background. bool auto_color_readability_enabled_; + // The horizontal alignment. This value is flipped for RTL. The default + // behavior is to align left in LTR UI and right in RTL UI. + gfx::HorizontalAlignment horizontal_alignment_; + DISALLOW_COPY_AND_ASSIGN(StyledLabel); }; diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc index e7226092de1..7aa780d2c8f 100644 --- a/chromium/ui/views/controls/styled_label_unittest.cc +++ b/chromium/ui/views/controls/styled_label_unittest.cc @@ -22,6 +22,7 @@ #include "ui/views/controls/styled_label_listener.h" #include "ui/views/style/typography.h" #include "ui/views/test/test_layout_provider.h" +#include "ui/views/test/test_views.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget.h" @@ -282,8 +283,7 @@ TEST_P(MDStyledLabelTest, DontBreakLinks) { const std::string link_text("and this should be a link"); InitStyledLabel(text + link_text); styled()->AddStyleRange( - gfx::Range(static_cast<uint32_t>(text.size()), - static_cast<uint32_t>(text.size() + link_text.size())), + gfx::Range(text.size(), text.size() + link_text.size()), StyledLabel::RangeStyleInfo::CreateForLink()); Label label(ASCIIToUTF16(text + link_text.substr(0, link_text.size() / 2))); @@ -316,8 +316,7 @@ TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) { StyledLabel::RangeStyleInfo style_info; style_info.disable_line_wrapping = true; styled()->AddStyleRange( - gfx::Range(static_cast<uint32_t>(text.size()), - static_cast<uint32_t>(text.size() + unbreakable_text.size())), + gfx::Range(text.size(), text.size() + unbreakable_text.size()), style_info); Label label(ASCIIToUTF16( @@ -343,8 +342,7 @@ TEST_F(StyledLabelTest, StyledRangeCustomFontUnderlined) { style_info.custom_font = styled()->GetDefaultFontList().DeriveWithStyle(gfx::Font::UNDERLINE); styled()->AddStyleRange( - gfx::Range(static_cast<uint32_t>(text.size()), - static_cast<uint32_t>(text.size() + underlined_text.size())), + gfx::Range(text.size(), text.size() + underlined_text.size()), style_info); styled()->SetBounds(0, 0, 1000, 1000); @@ -372,8 +370,7 @@ TEST_F(StyledLabelTest, StyledRangeTextStyleBold) { StyledLabel::RangeStyleInfo style_info; style_info.text_style = style::STYLE_DISABLED; - styled()->AddStyleRange( - gfx::Range(0u, static_cast<uint32_t>(bold_text.size())), style_info); + styled()->AddStyleRange(gfx::Range(0u, bold_text.size()), style_info); // Calculate the bold text width if it were a pure label view, both with bold // and normal style. @@ -434,14 +431,12 @@ TEST_F(StyledLabelTest, Color) { StyledLabel::RangeStyleInfo style_info_red; style_info_red.override_color = SK_ColorRED; - styled()->AddStyleRange( - gfx::Range(0u, static_cast<uint32_t>(text_red.size())), style_info_red); + styled()->AddStyleRange(gfx::Range(0u, text_red.size()), style_info_red); StyledLabel::RangeStyleInfo style_info_link = StyledLabel::RangeStyleInfo::CreateForLink(); styled()->AddStyleRange( - gfx::Range(static_cast<uint32_t>(text_red.size()), - static_cast<uint32_t>(text_red.size() + text_link.size())), + gfx::Range(text_red.size(), text_red.size() + text_link.size()), style_info_link); styled()->SetBounds(0, 0, 1000, 1000); @@ -498,13 +493,10 @@ TEST_P(MDStyledLabelTest, StyledRangeWithTooltip) { StyledLabel::RangeStyleInfo tooltip_style; tooltip_style.tooltip = ASCIIToUTF16("tooltip"); styled()->AddStyleRange( - gfx::Range(static_cast<uint32_t>(tooltip_start), - static_cast<uint32_t>(tooltip_start + tooltip_text.size())), + gfx::Range(tooltip_start, tooltip_start + tooltip_text.size()), tooltip_style); - styled()->AddStyleRange( - gfx::Range(static_cast<uint32_t>(link_start), - static_cast<uint32_t>(link_start + link_text.size())), - StyledLabel::RangeStyleInfo::CreateForLink()); + styled()->AddStyleRange(gfx::Range(link_start, link_start + link_text.size()), + StyledLabel::RangeStyleInfo::CreateForLink()); // Break line inside the range with the tooltip. Label label(ASCIIToUTF16( @@ -652,6 +644,147 @@ TEST_F(StyledLabelTest, Border) { styled()->GetPreferredSize().width()); } +TEST_F(StyledLabelTest, LineHeightWithShorterCustomView) { + const std::string text("one "); + InitStyledLabel(text); + int default_height = styled()->GetHeightForWidth(1000); + + const std::string custom_view_text("with custom view"); + const int less_height = 10; + std::unique_ptr<View> custom_view = std::make_unique<StaticSizedView>( + gfx::Size(20, default_height - less_height)); + custom_view->set_owned_by_client(); + StyledLabel::RangeStyleInfo style_info; + style_info.custom_view = custom_view.get(); + InitStyledLabel(text + custom_view_text); + styled()->AddStyleRange( + gfx::Range(text.size(), text.size() + custom_view_text.size()), + style_info); + styled()->AddCustomView(std::move(custom_view)); + EXPECT_EQ(default_height, styled()->GetHeightForWidth(100)); +} + +TEST_F(StyledLabelTest, LineHeightWithTallerCustomView) { + const std::string text("one "); + InitStyledLabel(text); + int default_height = styled()->GetHeightForWidth(100); + + const std::string custom_view_text("with custom view"); + const int more_height = 10; + std::unique_ptr<View> custom_view = std::make_unique<StaticSizedView>( + gfx::Size(20, default_height + more_height)); + custom_view->set_owned_by_client(); + StyledLabel::RangeStyleInfo style_info; + style_info.custom_view = custom_view.get(); + InitStyledLabel(text + custom_view_text); + styled()->AddStyleRange( + gfx::Range(text.size(), text.size() + custom_view_text.size()), + style_info); + styled()->AddCustomView(std::move(custom_view)); + EXPECT_EQ(default_height + more_height, styled()->GetHeightForWidth(100)); +} + +TEST_F(StyledLabelTest, LineWrapperWithCustomView) { + const std::string text_before("one "); + InitStyledLabel(text_before); + int default_height = styled()->GetHeightForWidth(100); + const std::string custom_view_text("two with custom view "); + const std::string text_after("three"); + + int custom_view_height = 25; + std::unique_ptr<View> custom_view = + std::make_unique<StaticSizedView>(gfx::Size(200, custom_view_height)); + custom_view->set_owned_by_client(); + StyledLabel::RangeStyleInfo style_info; + style_info.custom_view = custom_view.get(); + InitStyledLabel(text_before + custom_view_text + text_after); + styled()->AddStyleRange( + gfx::Range(text_before.size(), + text_before.size() + custom_view_text.size()), + style_info); + styled()->AddCustomView(std::move(custom_view)); + EXPECT_EQ(default_height * 2 + custom_view_height, + styled()->GetHeightForWidth(100)); +} + +TEST_F(StyledLabelTest, LeftAlignment) { + const std::string multiline_text("one\ntwo\nthree"); + InitStyledLabel(multiline_text); + styled()->SetHorizontalAlignment(gfx::ALIGN_LEFT); + styled()->SetBounds(0, 0, 1000, 1000); + styled()->Layout(); + ASSERT_EQ(3, styled()->child_count()); + EXPECT_EQ(0, styled()->child_at(0)->bounds().x()); + EXPECT_EQ(0, styled()->child_at(1)->bounds().x()); + EXPECT_EQ(0, styled()->child_at(2)->bounds().x()); +} + +TEST_F(StyledLabelTest, RightAlignment) { + const std::string multiline_text("one\ntwo\nthree"); + InitStyledLabel(multiline_text); + styled()->SetHorizontalAlignment(gfx::ALIGN_RIGHT); + styled()->SetBounds(0, 0, 1000, 1000); + styled()->Layout(); + ASSERT_EQ(3, styled()->child_count()); + EXPECT_EQ(1000, styled()->child_at(0)->bounds().right()); + EXPECT_EQ(1000, styled()->child_at(1)->bounds().right()); + EXPECT_EQ(1000, styled()->child_at(2)->bounds().right()); +} + +TEST_F(StyledLabelTest, CenterAlignment) { + const std::string multiline_text("one\ntwo\nthree"); + InitStyledLabel(multiline_text); + styled()->SetHorizontalAlignment(gfx::ALIGN_CENTER); + styled()->SetBounds(0, 0, 1000, 1000); + styled()->Layout(); + + Label label_one(ASCIIToUTF16("one")); + Label label_two(ASCIIToUTF16("two")); + Label label_three(ASCIIToUTF16("three")); + + ASSERT_EQ(3, styled()->child_count()); + EXPECT_EQ((1000 - label_one.GetPreferredSize().width()) / 2, + styled()->child_at(0)->bounds().x()); + EXPECT_EQ((1000 - label_two.GetPreferredSize().width()) / 2, + styled()->child_at(1)->bounds().x()); + EXPECT_EQ((1000 - label_three.GetPreferredSize().width()) / 2, + styled()->child_at(2)->bounds().x()); +} + +TEST_P(MDStyledLabelTest, ViewsCenteredWithLinkAndCustomView) { + const std::string text("This is a test block of text, "); + const std::string link_text("and this should be a link"); + const std::string custom_view_text("And this is a custom view"); + InitStyledLabel(text + link_text + custom_view_text); + styled()->AddStyleRange( + gfx::Range(text.size(), text.size() + link_text.size()), + StyledLabel::RangeStyleInfo::CreateForLink()); + + int custom_view_height = 25; + std::unique_ptr<View> custom_view = + std::make_unique<StaticSizedView>(gfx::Size(20, custom_view_height)); + custom_view->set_owned_by_client(); + StyledLabel::RangeStyleInfo style_info; + style_info.custom_view = custom_view.get(); + styled()->AddStyleRange( + gfx::Range(text.size() + link_text.size(), + text.size() + link_text.size() + custom_view_text.size()), + style_info); + styled()->AddCustomView(std::move(custom_view)); + + styled()->SetBounds(0, 0, 1000, 500); + styled()->Layout(); + int height = styled()->GetPreferredSize().height(); + + ASSERT_EQ(3, styled()->child_count()); + EXPECT_EQ((height - styled()->child_at(0)->bounds().height()) / 2, + styled()->child_at(0)->bounds().y()); + EXPECT_EQ((height - styled()->child_at(1)->bounds().height()) / 2, + styled()->child_at(1)->bounds().y()); + EXPECT_EQ((height - styled()->child_at(2)->bounds().height()) / 2, + styled()->child_at(2)->bounds().y()); +} + INSTANTIATE_TEST_CASE_P(, MDStyledLabelTest, ::testing::Values(SecondaryUiMode::MD, diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc index bff1a9c4807..7c44a024a40 100644 --- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc +++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc @@ -21,6 +21,7 @@ #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/insets.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h" @@ -34,35 +35,32 @@ namespace views { namespace { // TODO(markusheintz|msw): Use NativeTheme colors. -const SkColor kTabTitleColor_Inactive = SkColorSetRGB(0x64, 0x64, 0x64); -const SkColor kTabTitleColor_Active = SK_ColorBLACK; +constexpr SkColor kTabTitleColor_InactiveBorder = + SkColorSetARGBMacro(0xFF, 0x64, 0x64, 0x64); +constexpr SkColor kTabTitleColor_InactiveHighlight = + SkColorSetARGBMacro(0xFF, 0x80, 0x86, 0x8B); +constexpr SkColor kTabTitleColor_ActiveBorder = SK_ColorBLACK; +constexpr SkColor kTabTitleColor_ActiveHighlight = + SkColorSetARGBMacro(0xFF, 0x42, 0x85, 0xF4); const SkColor kTabTitleColor_Hovered = SK_ColorBLACK; const SkColor kTabBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8); const SkScalar kTabBorderThickness = 1.0f; - -const gfx::Font::Weight kHoverWeight = gfx::Font::Weight::NORMAL; +constexpr SkColor kTabHighlightBackgroundColor = + SkColorSetARGBMacro(0xFF, 0xE8, 0xF0, 0xFE); +constexpr int kTabHighlightBorderRadius = 32; +constexpr int kTabHighlightPreferredHeight = 32; +constexpr int kTabHighlightPreferredWidth = 208; + +const gfx::Font::Weight kHoverWeightBorder = gfx::Font::Weight::NORMAL; +const gfx::Font::Weight kHoverWeightHighlight = gfx::Font::Weight::MEDIUM; const gfx::Font::Weight kActiveWeight = gfx::Font::Weight::BOLD; -const gfx::Font::Weight kInactiveWeight = gfx::Font::Weight::NORMAL; +const gfx::Font::Weight kInactiveWeightBorder = gfx::Font::Weight::NORMAL; +const gfx::Font::Weight kInactiveWeightHighlight = gfx::Font::Weight::MEDIUM; -const int kHarmonyTabStripTabHeight = 32; +constexpr int kLabelFontSizeDeltaHighlight = 1; -// The View containing the text for each tab in the tab strip. -class TabLabel : public Label { - public: - explicit TabLabel(const base::string16& tab_title) - : Label(tab_title, style::CONTEXT_LABEL, style::STYLE_TAB_ACTIVE) {} - - // Label: - void GetAccessibleNodeData(ui::AXNodeData* data) override { - // views::Tab shouldn't expose any of its children in the a11y tree. - // Instead, it should provide the a11y information itself. Normally, - // non-keyboard-focusable children of keyboard-focusable parents are - // ignored, but Tabs only mark the currently selected tab as - // keyboard-focusable. This means all unselected Tabs expose their children - // to the a11y tree. To fix, manually ignore the children. - data->role = ui::AX_ROLE_IGNORED; - } -}; +const int kHarmonyTabStripTabHeight = 32; +constexpr int kBorderThickness = 2; } // namespace @@ -91,7 +89,8 @@ class MdTab : public Tab { // class uses a BoxLayout to position tabs. class MdTabStrip : public TabStrip, public gfx::AnimationDelegate { public: - MdTabStrip(); + MdTabStrip(TabbedPane::Orientation orientation, + TabbedPane::TabStripStyle style); ~MdTabStrip() override; // Overridden from TabStrip: @@ -125,21 +124,41 @@ const char Tab::kViewClassName[] = "Tab"; Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents) : tabbed_pane_(tabbed_pane), - title_(new TabLabel(title)), + title_(new Label(title, style::CONTEXT_LABEL, style::STYLE_TAB_ACTIVE)), tab_state_(TAB_ACTIVE), contents_(contents) { - // Calculate this now while the font list is guaranteed to be bold. + // Calculate the size while the font list is bold. preferred_title_size_ = title_->GetPreferredSize(); + const bool is_vertical = + tabbed_pane_->GetOrientation() == TabbedPane::Orientation::kVertical; + const bool is_highlight_style = + tabbed_pane_->GetStyle() == TabbedPane::TabStripStyle::kHighlight; + + if (is_vertical) { + title_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); + title_->SetElideBehavior(gfx::ElideBehavior::NO_ELIDE); + } - const int kTabVerticalPadding = 5; - const int kTabHorizontalPadding = 10; - - SetBorder(CreateEmptyBorder( - gfx::Insets(kTabVerticalPadding, kTabHorizontalPadding))); + if (is_highlight_style && is_vertical) { + const int kTabVerticalPadding = 8; + const int kTabHorizontalPadding = 32; + SetBorder(CreateEmptyBorder(gfx::Insets( + kTabVerticalPadding, kTabHorizontalPadding, kTabVerticalPadding, 0))); + } else { + const int kTabVerticalPadding = 5; + const int kTabHorizontalPadding = 10; + SetBorder(CreateEmptyBorder( + gfx::Insets(kTabVerticalPadding, kTabHorizontalPadding))); + } SetLayoutManager(std::make_unique<FillLayout>()); - SetState(TAB_INACTIVE); + // Calculate the size while the font list is normal and set the max size. + preferred_title_size_.SetToMax(title_->GetPreferredSize()); AddChildView(title_); + + // Use leaf so that name is spoken by screen reader without exposing the + // children. + GetViewAccessibility().OverrideIsLeaf(); } Tab::~Tab() {} @@ -157,28 +176,41 @@ void Tab::SetSelected(bool selected) { void Tab::OnStateChanged() { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + const bool is_highlight_mode = + tabbed_pane_->GetStyle() == TabbedPane::TabStripStyle::kHighlight; + const int font_size_delta = is_highlight_mode ? kLabelFontSizeDeltaHighlight + : ui::kLabelFontSizeDelta; switch (tab_state_) { case TAB_INACTIVE: - title_->SetEnabledColor(kTabTitleColor_Inactive); - title_->SetFontList(rb.GetFontListWithDelta( - ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kInactiveWeight)); + // Notify assistive tools to update this tab's selected status. + // The way Chrome OS accessibility is implemented right now, firing almost + // any event will work, we just need to trigger its state to be refreshed. + NotifyAccessibilityEvent(ax::mojom::Event::kCheckedStateChanged, true); + title_->SetEnabledColor(is_highlight_mode + ? kTabTitleColor_InactiveHighlight + : kTabTitleColor_InactiveBorder); + title_->SetFontList( + rb.GetFontListWithDelta(font_size_delta, gfx::Font::NORMAL, + is_highlight_mode ? kInactiveWeightHighlight + : kInactiveWeightBorder)); break; case TAB_ACTIVE: - title_->SetEnabledColor(kTabTitleColor_Active); + title_->SetEnabledColor(is_highlight_mode ? kTabTitleColor_ActiveHighlight + : kTabTitleColor_ActiveBorder); title_->SetFontList(rb.GetFontListWithDelta( - ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kActiveWeight)); + font_size_delta, gfx::Font::NORMAL, kActiveWeight)); break; case TAB_HOVERED: title_->SetEnabledColor(kTabTitleColor_Hovered); title_->SetFontList(rb.GetFontListWithDelta( - ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kHoverWeight)); + font_size_delta, gfx::Font::NORMAL, + is_highlight_mode ? kHoverWeightHighlight : kHoverWeightBorder)); break; } } bool Tab::OnMousePressed(const ui::MouseEvent& event) { - if (event.IsOnlyLeftMouseButton() && - GetLocalBounds().Contains(event.location())) + if (enabled() && event.IsOnlyLeftMouseButton()) tabbed_pane_->SelectTab(this); return true; } @@ -211,6 +243,11 @@ void Tab::OnGestureEvent(ui::GestureEvent* event) { gfx::Size Tab::CalculatePreferredSize() const { gfx::Size size(preferred_title_size_); size.Enlarge(GetInsets().width(), GetInsets().height()); + if (tabbed_pane_->GetStyle() == TabbedPane::TabStripStyle::kHighlight && + tabbed_pane_->GetOrientation() == TabbedPane::Orientation::kVertical) { + size.SetToMax( + gfx::Size(kTabHighlightPreferredWidth, kTabHighlightPreferredHeight)); + } return size; } @@ -226,32 +263,51 @@ void Tab::SetState(TabState tab_state) { SchedulePaint(); } +void Tab::OnPaint(gfx::Canvas* canvas) { + View::OnPaint(canvas); + if (!selected()) + return; + if (tabbed_pane_->GetOrientation() != TabbedPane::Orientation::kVertical || + tabbed_pane_->GetStyle() != TabbedPane::TabStripStyle::kHighlight) { + return; + } + + SkScalar radius = SkIntToScalar(kTabHighlightBorderRadius); + const SkScalar kRadius[8] = {0, 0, radius, radius, radius, radius, 0, 0}; + SkPath path; + gfx::Rect bounds(size()); + path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); + cc::PaintFlags fill_flags; + fill_flags.setAntiAlias(true); + fill_flags.setColor(kTabHighlightBackgroundColor); + canvas->DrawPath(path, fill_flags); +} + void Tab::GetAccessibleNodeData(ui::AXNodeData* data) { - data->role = ui::AX_ROLE_TAB; + data->role = ax::mojom::Role::kTab; data->SetName(title()->text()); - data->AddState(ui::AX_STATE_SELECTABLE); + data->AddState(ax::mojom::State::kSelectable); if (selected()) - data->AddState(ui::AX_STATE_SELECTED); + data->AddState(ax::mojom::State::kSelected); } bool Tab::HandleAccessibleAction(const ui::AXActionData& action_data) { - if (action_data.action != ui::AX_ACTION_SET_SELECTION || !enabled()) - return false; - - // It's not clear what should happen if a tab is 'deselected', so the - // AX_ACTION_SET_SELECTION action will always select the tab. - tabbed_pane_->SelectTab(this); - return true; + // If the assistive tool sends kSetSelection, handle it like kDoDefault. + // These generate a click event handled in Tab::OnMousePressed. + ui::AXActionData action_data_copy(action_data); + if (action_data.action == ax::mojom::Action::kSetSelection) + action_data_copy.action = ax::mojom::Action::kDoDefault; + return View::HandleAccessibleAction(action_data_copy); } void Tab::OnFocus() { OnStateChanged(); // When the tab gains focus, send an accessibility event indicating that the // contents are focused. When the tab loses focus, whichever new View ends up - // with focus will send an AX_EVENT_FOCUS of its own, so there's no need to - // send one in OnBlur(). + // with focus will send an ax::mojom::Event::kFocus of its own, so there's no + // need to send one in OnBlur(). if (contents()) - contents()->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); + contents()->NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true); SchedulePaint(); } @@ -262,17 +318,25 @@ void Tab::OnBlur() { bool Tab::OnKeyPressed(const ui::KeyEvent& event) { ui::KeyboardCode key = event.key_code(); - if (key != ui::VKEY_LEFT && key != ui::VKEY_RIGHT) - return false; - return tabbed_pane_->MoveSelectionBy(key == ui::VKEY_RIGHT ? 1 : -1); + const bool is_horizontal = + tabbed_pane_->GetOrientation() == TabbedPane::Orientation::kHorizontal; + // Use left and right arrows to navigate tabs in horizontal orientation. + if (is_horizontal) { + return (key == ui::VKEY_LEFT || key == ui::VKEY_RIGHT) && + tabbed_pane_->MoveSelectionBy(key == ui::VKEY_RIGHT ? 1 : -1); + } + // Use up and down arrows to navigate tabs in vertical orientation. + return (key == ui::VKEY_UP || key == ui::VKEY_DOWN) && + tabbed_pane_->MoveSelectionBy(key == ui::VKEY_DOWN ? 1 : -1); } MdTab::MdTab(TabbedPane* tabbed_pane, const base::string16& title, View* contents) : Tab(tabbed_pane, title, contents) { - const int kBorderThickness = 2; - SetBorder(CreateEmptyBorder(gfx::Insets(kBorderThickness))); + if (tabbed_pane->GetOrientation() == TabbedPane::Orientation::kHorizontal) { + SetBorder(CreateEmptyBorder(gfx::Insets(kBorderThickness))); + } OnStateChanged(); } @@ -321,12 +385,24 @@ void MdTab::OnBlur() { // static const char TabStrip::kViewClassName[] = "TabStrip"; -TabStrip::TabStrip() { - const int kTabStripLeadingEdgePadding = 9; - auto layout = std::make_unique<BoxLayout>( - BoxLayout::kHorizontal, gfx::Insets(0, kTabStripLeadingEdgePadding)); +TabStrip::TabStrip(TabbedPane::Orientation orientation, + TabbedPane::TabStripStyle style) + : orientation_(orientation), style_(style) { + std::unique_ptr<BoxLayout> layout; + if (orientation == TabbedPane::Orientation::kHorizontal) { + const int kTabStripLeadingEdgePadding = 9; + layout = std::make_unique<BoxLayout>( + BoxLayout::kHorizontal, gfx::Insets(0, kTabStripLeadingEdgePadding)); + layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END); + } else { + const int kTabStripEdgePadding = 8; + const int kTabSpacing = 16; + layout = std::make_unique<BoxLayout>( + BoxLayout::kVertical, gfx::Insets(kTabStripEdgePadding, 0, 0, 0), + kTabSpacing); + layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_START); + } layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START); - layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END); layout->SetDefaultFlex(0); SetLayoutManager(std::move(layout)); } @@ -340,34 +416,69 @@ const char* TabStrip::GetClassName() const { } void TabStrip::OnPaintBorder(gfx::Canvas* canvas) { + // Do not draw border line in kHighlight mode. + if (style_ == TabbedPane::TabStripStyle::kHighlight) + return; + cc::PaintFlags fill_flags; fill_flags.setColor(kTabBorderColor); fill_flags.setStrokeWidth(kTabBorderThickness); - SkScalar line_y = SkIntToScalar(height()) - (kTabBorderThickness / 2); - SkScalar line_end = SkIntToScalar(width()); + SkScalar line_center_cross_axis; + SkScalar line_end_main_axis; + + const bool is_horizontal = + orientation_ == TabbedPane::Orientation::kHorizontal; + if (is_horizontal) { + line_center_cross_axis = + SkIntToScalar(height()) - (kTabBorderThickness / 2); + line_end_main_axis = SkIntToScalar(width()); + } else { + line_center_cross_axis = SkIntToScalar(width()) - (kTabBorderThickness / 2); + line_end_main_axis = SkIntToScalar(height()); + } + int selected_tab_index = GetSelectedTabIndex(); if (selected_tab_index >= 0) { Tab* selected_tab = GetTabAtIndex(selected_tab_index); SkPath path; SkScalar tab_height = SkIntToScalar(selected_tab->height()) - kTabBorderThickness; - SkScalar tab_width = - SkIntToScalar(selected_tab->width()) - kTabBorderThickness; - SkScalar tab_start = SkIntToScalar(selected_tab->GetMirroredX()); - path.moveTo(0, line_y); - path.rLineTo(tab_start, 0); - path.rLineTo(0, -tab_height); - path.rLineTo(tab_width, 0); - path.rLineTo(0, tab_height); - path.lineTo(line_end, line_y); - - cc::PaintFlags fill_flags; + SkScalar tab_width; + + SkScalar tab_start_x = SkIntToScalar(selected_tab->GetMirroredX()); + SkScalar tab_start_y = SkIntToScalar(selected_tab->bounds().y()); + if (is_horizontal) { + tab_width = SkIntToScalar(selected_tab->width()) - kTabBorderThickness; + path.moveTo(0, line_center_cross_axis); + path.rLineTo(tab_start_x, 0); + path.rLineTo(0, -tab_height); + path.rLineTo(tab_width, 0); + path.rLineTo(0, tab_height); + path.lineTo(line_end_main_axis, line_center_cross_axis); + } else { + tab_width = + SkIntToScalar(width() - selected_tab->GetInsets().left() / 2) - + kTabBorderThickness; + path.moveTo(line_center_cross_axis, 0); + path.rLineTo(0, tab_start_y); + path.rLineTo(-tab_width, 0); + path.rLineTo(0, tab_height); + path.rLineTo(tab_width, 0); + path.lineTo(line_center_cross_axis, line_end_main_axis); + } + fill_flags.setStyle(cc::PaintFlags::kStroke_Style); - fill_flags.setColor(kTabBorderColor); - fill_flags.setStrokeWidth(kTabBorderThickness); canvas->DrawPath(path, fill_flags); } else { - canvas->sk_canvas()->drawLine(0, line_y, line_end, line_y, fill_flags); + if (is_horizontal) { + canvas->sk_canvas()->drawLine(0, line_center_cross_axis, + line_end_main_axis, line_center_cross_axis, + fill_flags); + } else { + canvas->sk_canvas()->drawLine(line_center_cross_axis, 0, + line_center_cross_axis, line_end_main_axis, + fill_flags); + } } } @@ -394,12 +505,16 @@ Tab* TabStrip::GetTabAtDeltaFromSelected(int delta) const { return GetTabAtIndex(index); } -MdTabStrip::MdTabStrip() { - auto layout = std::make_unique<BoxLayout>(BoxLayout::kHorizontal); - layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); - layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); - layout->SetDefaultFlex(1); - SetLayoutManager(std::move(layout)); +MdTabStrip::MdTabStrip(TabbedPane::Orientation orientation, + TabbedPane::TabStripStyle style) + : TabStrip(orientation, style) { + if (orientation == TabbedPane::Orientation::kHorizontal) { + auto layout = std::make_unique<BoxLayout>(BoxLayout::kHorizontal); + layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); + layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); + layout->SetDefaultFlex(1); + SetLayoutManager(std::move(layout)); + } // These durations are taken from the Paper Tabs source: // https://github.com/PolymerElements/paper-tabs/blob/master/paper-tabs.html @@ -417,29 +532,52 @@ void MdTabStrip::OnSelectedTabChanged(Tab* from_tab, Tab* to_tab) { DCHECK(!from_tab->selected()); DCHECK(to_tab->selected()); - animating_from_ = gfx::Range(from_tab->GetMirroredX(), - from_tab->GetMirroredX() + from_tab->width()); - animating_to_ = gfx::Range(to_tab->GetMirroredX(), - to_tab->GetMirroredX() + to_tab->width()); + if (orientation() == TabbedPane::Orientation::kHorizontal) { + animating_from_ = gfx::Range(from_tab->GetMirroredX(), + from_tab->GetMirroredX() + from_tab->width()); + animating_to_ = gfx::Range(to_tab->GetMirroredX(), + to_tab->GetMirroredX() + to_tab->width()); + } else { + animating_from_ = gfx::Range(from_tab->bounds().y(), + from_tab->bounds().y() + from_tab->height()); + animating_to_ = gfx::Range(to_tab->bounds().y(), + to_tab->bounds().y() + to_tab->height()); + } contract_animation_->Stop(); expand_animation_->Start(); } void MdTabStrip::OnPaintBorder(gfx::Canvas* canvas) { - int max_y = child_at(0)->y() + child_at(0)->height(); + // Do not draw border line in kHighlight mode. + if (style() == TabbedPane::TabStripStyle::kHighlight) + return; + const int kUnselectedBorderThickness = 1; const int kSelectedBorderThickness = 2; + const bool is_horizontal = + orientation() == TabbedPane::Orientation::kHorizontal; + + int max_cross_axis; + + // First, draw the unselected border across the TabStrip's entire width or + // height, depending on the orientation of the tab alignment. The area + // underneath or on the right of the selected tab will be overdrawn later. + gfx::Rect rect; + if (is_horizontal) { + max_cross_axis = child_at(0)->y() + child_at(0)->height(); + rect = gfx::Rect(0, max_cross_axis - kUnselectedBorderThickness, width(), + kUnselectedBorderThickness); + } else { + max_cross_axis = width(); + rect = gfx::Rect(max_cross_axis - kUnselectedBorderThickness, 0, + kUnselectedBorderThickness, height()); + } + canvas->FillRect(rect, GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_TabBottomBorder)); - // First, draw the unselected border across the TabStrip's entire width. The - // area underneath the selected tab will be overdrawn later. - canvas->FillRect(gfx::Rect(0, max_y - kUnselectedBorderThickness, width(), - kUnselectedBorderThickness), - GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_TabBottomBorder)); - - int min_x = 0; - int max_x = 0; + int min_main_axis = 0; + int max_main_axis = 0; // Now, figure out the range to draw the selection marker underneath. There // are three states here: @@ -454,43 +592,53 @@ void MdTabStrip::OnPaintBorder(gfx::Canvas* canvas) { if (!tab) return; if (expand_animation_->is_animating()) { - bool animating_left = animating_to_.start() < animating_from_.start(); + bool animating_leading = animating_to_.start() < animating_from_.start(); double anim_value = gfx::Tween::CalculateValue( gfx::Tween::FAST_OUT_LINEAR_IN, expand_animation_->GetCurrentValue()); - if (animating_left) { - min_x = gfx::Tween::IntValueBetween(anim_value, animating_from_.start(), - animating_to_.start()); - max_x = animating_from_.end(); + if (animating_leading) { + min_main_axis = gfx::Tween::IntValueBetween( + anim_value, animating_from_.start(), animating_to_.start()); + max_main_axis = animating_from_.end(); } else { - min_x = animating_from_.start(); - max_x = gfx::Tween::IntValueBetween(anim_value, animating_from_.end(), - animating_to_.end()); + min_main_axis = animating_from_.start(); + max_main_axis = gfx::Tween::IntValueBetween( + anim_value, animating_from_.end(), animating_to_.end()); } } else if (contract_animation_->is_animating()) { - bool animating_left = animating_to_.start() < animating_from_.start(); + bool animating_leading = animating_to_.start() < animating_from_.start(); double anim_value = gfx::Tween::CalculateValue( gfx::Tween::LINEAR_OUT_SLOW_IN, contract_animation_->GetCurrentValue()); - if (animating_left) { - min_x = animating_to_.start(); - max_x = gfx::Tween::IntValueBetween(anim_value, animating_from_.end(), - animating_to_.end()); + if (animating_leading) { + min_main_axis = animating_to_.start(); + max_main_axis = gfx::Tween::IntValueBetween( + anim_value, animating_from_.end(), animating_to_.end()); } else { - min_x = gfx::Tween::IntValueBetween(anim_value, animating_from_.start(), - animating_to_.start()); - max_x = animating_to_.end(); + min_main_axis = gfx::Tween::IntValueBetween( + anim_value, animating_from_.start(), animating_to_.start()); + max_main_axis = animating_to_.end(); } } else if (tab) { - min_x = tab->GetMirroredX(); - max_x = tab->GetMirroredX() + tab->width(); + if (is_horizontal) { + min_main_axis = tab->GetMirroredX(); + max_main_axis = tab->GetMirroredX() + tab->width(); + } else { + min_main_axis = tab->bounds().y(); + max_main_axis = tab->bounds().y() + tab->height(); + } } - DCHECK(min_x != max_x); + DCHECK(min_main_axis != max_main_axis); // Draw over the unselected border from above. - canvas->FillRect(gfx::Rect(min_x, max_y - kSelectedBorderThickness, - max_x - min_x, kSelectedBorderThickness), - GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_FocusedBorderColor)); + if (is_horizontal) { + rect = gfx::Rect(min_main_axis, max_cross_axis - kSelectedBorderThickness, + max_main_axis - min_main_axis, kSelectedBorderThickness); + } else { + rect = gfx::Rect(max_cross_axis - kSelectedBorderThickness, min_main_axis, + kSelectedBorderThickness, max_main_axis - min_main_axis); + } + canvas->FillRect(rect, GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_FocusedBorderColor)); } void MdTabStrip::AnimationProgressed(const gfx::Animation* animation) { @@ -502,12 +650,14 @@ void MdTabStrip::AnimationEnded(const gfx::Animation* animation) { contract_animation_->Start(); } -TabbedPane::TabbedPane() - : listener_(NULL), - tab_strip_(ui::MaterialDesignController::IsSecondaryUiMaterial() - ? new MdTabStrip - : new TabStrip), - contents_(new View()) { +TabbedPane::TabbedPane(TabbedPane::Orientation orientation, + TabbedPane::TabStripStyle style) + : listener_(NULL), contents_(new View()) { + DCHECK(orientation != TabbedPane::Orientation::kHorizontal || + style != TabbedPane::TabStripStyle::kHighlight); + tab_strip_ = ui::MaterialDesignController::IsSecondaryUiMaterial() + ? new MdTabStrip(orientation, style) + : new TabStrip(orientation, style); AddChildView(tab_strip_); AddChildView(contents_); } @@ -581,14 +731,29 @@ gfx::Size TabbedPane::CalculatePreferredSize() const { gfx::Size size; for (int i = 0; i < contents_->child_count(); ++i) size.SetToMax(contents_->child_at(i)->GetPreferredSize()); - size.Enlarge(0, tab_strip_->GetPreferredSize().height()); + if (GetOrientation() == Orientation::kHorizontal) + size.Enlarge(0, tab_strip_->GetPreferredSize().height()); + else + size.Enlarge(tab_strip_->GetPreferredSize().width(), 0); return size; } +TabbedPane::Orientation TabbedPane::GetOrientation() const { + return tab_strip_->orientation(); +} + +TabbedPane::TabStripStyle TabbedPane::GetStyle() const { + return tab_strip_->style(); +} + Tab* TabbedPane::GetSelectedTab() { return tab_strip_->GetSelectedTab(); } +View* TabbedPane::GetSelectedTabContentView() { + return GetSelectedTab() ? GetSelectedTab()->contents() : nullptr; +} + bool TabbedPane::MoveSelectionBy(int delta) { if (contents_->child_count() <= 1) return false; @@ -598,9 +763,15 @@ bool TabbedPane::MoveSelectionBy(int delta) { void TabbedPane::Layout() { const gfx::Size size = tab_strip_->GetPreferredSize(); - tab_strip_->SetBounds(0, 0, width(), size.height()); - contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(), - std::max(0, height() - size.height())); + if (GetOrientation() == Orientation::kHorizontal) { + tab_strip_->SetBounds(0, 0, width(), size.height()); + contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(), + std::max(0, height() - size.height())); + } else { + tab_strip_->SetBounds(0, 0, size.width(), height()); + contents_->SetBounds(tab_strip_->bounds().width(), 0, + std::max(0, width() - size.width()), height()); + } for (int i = 0; i < contents_->child_count(); ++i) contents_->child_at(i)->SetSize(contents_->size()); } @@ -625,12 +796,8 @@ const char* TabbedPane::GetClassName() const { return kViewClassName; } -View* TabbedPane::GetSelectedTabContentView() { - return GetSelectedTab() ? GetSelectedTab()->contents() : nullptr; -} - void TabbedPane::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_TAB_LIST; + node_data->role = ax::mojom::Role::kTabList; } } // namespace views diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h index 2397828d847..0d3cec8d493 100644 --- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h +++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h @@ -24,12 +24,27 @@ class TabbedPaneTest; // TabbedPane is a view that shows tabs. When the user clicks on a tab, the // associated view is displayed. +// Support for horizontal-highlight and vertical-border modes is limited and +// may require additional polish. class VIEWS_EXPORT TabbedPane : public View { public: // Internal class name. static const char kViewClassName[]; - TabbedPane(); + // The orientation of the tab alignment. + enum class Orientation { + kHorizontal, + kVertical, + }; + + // The style of the tab strip. + enum class TabStripStyle { + kBorder, // Draw border around the selected tab. + kHighlight, // Highlight background and text of the selected tab. + }; + + TabbedPane(Orientation orientation = Orientation::kHorizontal, + TabStripStyle style = TabStripStyle::kBorder); ~TabbedPane() override; TabbedPaneListener* listener() const { return listener_; } @@ -62,6 +77,12 @@ class VIEWS_EXPORT TabbedPane : public View { gfx::Size CalculatePreferredSize() const override; const char* GetClassName() const override; + // Gets the orientation of the tab alignment. + Orientation GetOrientation() const; + + // Gets the style of the tab strip. + TabStripStyle GetStyle() const; + private: friend class FocusTraversalTest; friend class Tab; @@ -144,6 +165,9 @@ class Tab : public View { void SetState(TabState tab_state); + // views::View: + void OnPaint(gfx::Canvas* canvas) override; + TabbedPane* tabbed_pane_; Label* title_; gfx::Size preferred_title_size_; @@ -154,13 +178,14 @@ class Tab : public View { DISALLOW_COPY_AND_ASSIGN(Tab); }; -// The tab strip shown above the tab contents. +// The tab strip shown above/left of the tab contents. class TabStrip : public View { public: // Internal class name. static const char kViewClassName[]; - TabStrip(); + TabStrip(TabbedPane::Orientation orientation, + TabbedPane::TabStripStyle style); ~TabStrip() override; // Called by TabStrip when the selected tab changes. This function is only @@ -177,7 +202,17 @@ class TabStrip : public View { Tab* GetTabAtIndex(int index) const; int GetSelectedTabIndex() const; + TabbedPane::Orientation orientation() const { return orientation_; } + + TabbedPane::TabStripStyle style() const { return style_; } + private: + // The orientation of the tab alignment. + const TabbedPane::Orientation orientation_; + + // The style of the tab strip. + const TabbedPane::TabStripStyle style_; + DISALLOW_COPY_AND_ASSIGN(TabStrip); }; diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc index c6b243d1965..02bb3cf82c8 100644 --- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc +++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc @@ -11,7 +11,7 @@ #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/accessibility/ax_action_data.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/events/keycodes/keyboard_code_conversion.h" #include "ui/views/test/test_views.h" @@ -38,6 +38,12 @@ class TabbedPaneTest : public ViewsTestBase { } protected: + void MakeTabbedPane(TabbedPane::Orientation orientation, + TabbedPane::TabStripStyle style) { + tabbed_pane_ = std::make_unique<TabbedPane>(orientation, style); + tabbed_pane_->set_owned_by_client(); + } + Tab* GetTabAt(int index) { return static_cast<Tab*>(tabbed_pane_->tab_strip_->child_at(index)); } @@ -58,36 +64,92 @@ class TabbedPaneTest : public ViewsTestBase { DISALLOW_COPY_AND_ASSIGN(TabbedPaneTest); }; -// Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout(). +// Tests tab orientation. +TEST_F(TabbedPaneTest, HorizontalOrientation) { + EXPECT_EQ(tabbed_pane_->GetOrientation(), + TabbedPane::Orientation::kHorizontal); +} + +// Tests tab orientation. +TEST_F(TabbedPaneTest, VerticalOrientation) { + MakeTabbedPane(TabbedPane::Orientation::kVertical, + TabbedPane::TabStripStyle::kBorder); + EXPECT_EQ(tabbed_pane_->GetOrientation(), TabbedPane::Orientation::kVertical); +} + +// Tests tab strip style. +TEST_F(TabbedPaneTest, TabStripBorderStyle) { + EXPECT_EQ(tabbed_pane_->GetStyle(), TabbedPane::TabStripStyle::kBorder); +} + +// Tests tab strip style. +TEST_F(TabbedPaneTest, TabStripHighlightStyle) { + MakeTabbedPane(TabbedPane::Orientation::kVertical, + TabbedPane::TabStripStyle::kHighlight); + EXPECT_EQ(tabbed_pane_->GetStyle(), TabbedPane::TabStripStyle::kHighlight); +} + +// Tests the preferred size and layout when tabs are aligned horizontally. +// TabbedPane requests a size that fits its largest tab, and disregards the +// width of horizontal tab strips for preferred size calculations. Tab titles +// are elided to fit the actual width. TEST_F(TabbedPaneTest, SizeAndLayout) { View* child1 = new StaticSizedView(gfx::Size(20, 10)); + tabbed_pane_->AddTab(ASCIIToUTF16("tab1 with very long text"), child1); + View* child2 = new StaticSizedView(gfx::Size(5, 5)); + tabbed_pane_->AddTab(ASCIIToUTF16("tab2 with very long text"), child2); + tabbed_pane_->SelectTabAt(0); + + // |tabbed_pane_| width should match the largest child in horizontal mode. + EXPECT_EQ(tabbed_pane_->GetPreferredSize().width(), 20); + // |tabbed_pane_| reserves extra height for the tab strip in horizontal mode. + EXPECT_GT(tabbed_pane_->GetPreferredSize().height(), 10); + + // The child views should resize to fit in larger tabbed panes. + tabbed_pane_->SetBounds(0, 0, 100, 200); + RunPendingMessages(); + // |tabbed_pane_| has no border. Therefore the children should be as wide as + // the |tabbed_pane_|. + EXPECT_EQ(child1->bounds().width(), 100); + EXPECT_GT(child1->bounds().height(), 0); + // |tabbed_pane_| reserves extra height for the tab strip. Therefore the + // children's height should be smaller than the |tabbed_pane_|'s height. + EXPECT_LT(child1->bounds().height(), 200); + + // If we switch to the other tab, it should get assigned the same bounds. + tabbed_pane_->SelectTabAt(1); + EXPECT_EQ(child1->bounds(), child2->bounds()); +} + +// Tests the preferred size and layout when tabs are aligned vertically.. +TEST_F(TabbedPaneTest, SizeAndLayoutInVerticalOrientation) { + MakeTabbedPane(TabbedPane::Orientation::kVertical, + TabbedPane::TabStripStyle::kBorder); + View* child1 = new StaticSizedView(gfx::Size(20, 10)); tabbed_pane_->AddTab(ASCIIToUTF16("tab1"), child1); View* child2 = new StaticSizedView(gfx::Size(5, 5)); tabbed_pane_->AddTab(ASCIIToUTF16("tab2"), child2); tabbed_pane_->SelectTabAt(0); - // The |tabbed_pane_| implementation of Views has no border by default. - // Therefore it should be as wide as the widest tab. The native Windows - // tabbed pane has a border that used up extra space. Therefore the preferred - // width is larger than the largest child. - gfx::Size pref(tabbed_pane_->GetPreferredSize()); - EXPECT_GE(pref.width(), 20); - EXPECT_GT(pref.height(), 10); + // |tabbed_pane_| reserves extra width for the tab strip in vertical mode. + EXPECT_GT(tabbed_pane_->GetPreferredSize().width(), 20); + // |tabbed_pane_| height should match the largest child in vertical mode. + EXPECT_EQ(tabbed_pane_->GetPreferredSize().height(), 10); - // The bounds of our children should be smaller than the tabbed pane's bounds. + // The child views should resize to fit in larger tabbed panes. tabbed_pane_->SetBounds(0, 0, 100, 200); RunPendingMessages(); - gfx::Rect bounds(child1->bounds()); - EXPECT_GT(bounds.width(), 0); - // The |tabbed_pane_| has no border. Therefore the children should be as wide - // as the |tabbed_pane_|. - EXPECT_LE(bounds.width(), 100); - EXPECT_GT(bounds.height(), 0); - EXPECT_LT(bounds.height(), 200); + EXPECT_GT(child1->bounds().width(), 0); + // |tabbed_pane_| reserves extra width for the tab strip. Therefore the + // children's width should be smaller than the |tabbed_pane_|'s width. + EXPECT_LT(child1->bounds().width(), 100); + // |tabbed_pane_| has no border. Therefore the children should be as high as + // the |tabbed_pane_|. + EXPECT_EQ(child1->bounds().height(), 200); // If we switch to the other tab, it should get assigned the same bounds. tabbed_pane_->SelectTabAt(1); - EXPECT_EQ(bounds, child2->bounds()); + EXPECT_EQ(child1->bounds(), child2->bounds()); } TEST_F(TabbedPaneTest, AddAndSelect) { @@ -161,14 +223,15 @@ TEST_F(TabbedPaneTest, SelectTabWithAccessibleAction) { ui::AXNodeData data; GetTabAt(i)->GetAccessibleNodeData(&data); SCOPED_TRACE(testing::Message() << "Tab at index: " << i); - EXPECT_EQ(ui::AX_ROLE_TAB, data.role); - EXPECT_EQ(DefaultTabTitle(), data.GetString16Attribute(ui::AX_ATTR_NAME)); - EXPECT_TRUE(data.HasState(ui::AX_STATE_SELECTABLE)); - EXPECT_EQ(i == 0, data.HasState(ui::AX_STATE_SELECTED)); + EXPECT_EQ(ax::mojom::Role::kTab, data.role); + EXPECT_EQ(DefaultTabTitle(), + data.GetString16Attribute(ax::mojom::StringAttribute::kName)); + EXPECT_TRUE(data.HasState(ax::mojom::State::kSelectable)); + EXPECT_EQ(i == 0, data.HasState(ax::mojom::State::kSelected)); } ui::AXActionData action; - action.action = ui::AX_ACTION_SET_SELECTION; + action.action = ax::mojom::Action::kSetSelection; // Select the first tab. GetTabAt(0)->HandleAccessibleAction(action); diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc index e2082961b4f..a6c8234c5cb 100644 --- a/chromium/ui/views/controls/table/table_view.cc +++ b/chromium/ui/views/controls/table/table_view.cc @@ -447,21 +447,22 @@ bool TableView::GetTooltipTextOrigin(const gfx::Point& p, } void TableView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_TABLE; - node_data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, - ui::AX_RESTRICTION_READ_ONLY); - node_data->AddIntAttribute(ui::AX_ATTR_SET_SIZE, RowCount()); + // TODO(aleventhal) Needs work, see https://crbug.com/811277. + node_data->role = ax::mojom::Role::kTable; + node_data->SetRestriction(ax::mojom::Restriction::kReadOnly); + node_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize, RowCount()); if (selection_model_.active() != ui::ListSelectionModel::kUnselectedIndex) { // Get information about the active item, this is not the same as the set // of selected items (of which there could be more than one). - node_data->role = ui::AX_ROLE_ROW; - node_data->AddIntAttribute(ui::AX_ATTR_POS_IN_SET, + node_data->role = ax::mojom::Role::kRow; + node_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, selection_model_.active()); if (selection_model_.IsSelected(selection_model_.active())) { - node_data->AddState(ui::AX_STATE_SELECTED); + node_data->AddState(ax::mojom::State::kSelected); } + // Generate accessible name from column headers and selected cell text. std::vector<base::string16> name_parts; for (const VisibleColumn& visible_column : visible_columns_) { base::string16 value = model_->GetText( @@ -472,6 +473,9 @@ void TableView::GetAccessibleNodeData(ui::AXNodeData* node_data) { } } node_data->SetName(base::JoinString(name_parts, base::ASCIIToUTF16(", "))); + } else { + // Name requires a selection. + node_data->SetNameExplicitlyEmpty(); } } @@ -648,7 +652,7 @@ void TableView::OnFocus() { scroll_view->SetHasFocusIndicator(true); SchedulePaintForSelection(); - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); + NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true); } void TableView::OnBlur() { @@ -873,7 +877,7 @@ void TableView::SetSelectionModel(ui::ListSelectionModel new_selection) { if (observer_) observer_->OnSelectionChanged(); - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); + NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true); } void TableView::AdvanceSelection(AdvanceDirection direction) { diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc index 7be7cbfa1a6..d02b648714c 100644 --- a/chromium/ui/views/controls/textfield/textfield.cc +++ b/chromium/ui/views/controls/textfield/textfield.cc @@ -38,6 +38,7 @@ #include "ui/gfx/selection_bound.h" #include "ui/native_theme/native_theme.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/background.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/focusable_border.h" @@ -45,6 +46,7 @@ #include "ui/views/controls/menu/menu_runner.h" #include "ui/views/controls/native/native_view_host.h" #include "ui/views/controls/textfield/textfield_controller.h" +#include "ui/views/controls/views_text_services_context_menu.h" #include "ui/views/drag_utils.h" #include "ui/views/layout/layout_provider.h" #include "ui/views/native_cursor.h" @@ -268,9 +270,9 @@ Textfield::Textfield() background_color_(SK_ColorWHITE), selection_text_color_(SK_ColorWHITE), selection_background_color_(SK_ColorBLUE), - placeholder_text_color_(kDefaultPlaceholderTextColor), placeholder_text_draw_flags_(gfx::Canvas::DefaultCanvasTextAlignment()), invalid_(false), + label_ax_id_(0), text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), text_input_flags_(0), performing_user_action_(false), @@ -317,6 +319,11 @@ Textfield::~Textfield() { } } +void Textfield::SetAssociatedLabel(Label* label) { + label_ax_id_ = label->GetViewAccessibility().GetUniqueId().Get(); + accessible_name_ = label->text(); +} + void Textfield::SetReadOnly(bool read_only) { // Update read-only without changing the focusable state (or active, etc.). read_only_ = read_only; @@ -345,7 +352,7 @@ void Textfield::SetText(const base::string16& new_text) { UpdateCursorViewPosition(); UpdateCursorVisibility(); SchedulePaint(); - NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); } void Textfield::AppendText(const base::string16& new_text) { @@ -354,7 +361,7 @@ void Textfield::AppendText(const base::string16& new_text) { model_->Append(new_text); OnCaretBoundsChanged(); SchedulePaint(); - NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true); } void Textfield::InsertOrReplaceText(const base::string16& new_text) { @@ -614,9 +621,11 @@ void Textfield::SetBorder(std::unique_ptr<Border> b) { } gfx::NativeCursor Textfield::GetCursor(const ui::MouseEvent& event) { + bool platform_arrow = PlatformStyle::kTextfieldUsesDragCursorWhenDraggable; bool in_selection = GetRenderText()->IsPointInSelection(event.location()); bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED; - bool text_cursor = !initiating_drag_ && (drag_event || !in_selection); + bool text_cursor = + !initiating_drag_ && (drag_event || !in_selection || !platform_arrow); return text_cursor ? GetNativeIBeamCursor() : gfx::kNullCursor; } @@ -935,37 +944,40 @@ void Textfield::OnDragDone() { } void Textfield::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_TEXT_FIELD; + node_data->role = ax::mojom::Role::kTextField; + if (label_ax_id_) { + node_data->AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds, + {label_ax_id_}); + } + node_data->SetName(accessible_name_); // Editable state indicates support of editable interface, and is always set // for a textfield, even if disabled or readonly. - node_data->AddState(ui::AX_STATE_EDITABLE); + node_data->AddState(ax::mojom::State::kEditable); if (enabled()) { - node_data->AddIntAttribute(ui::AX_ATTR_DEFAULT_ACTION_VERB, - ui::AX_DEFAULT_ACTION_VERB_ACTIVATE); + node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kActivate); // Only readonly if enabled. Don't overwrite the disabled restriction. - if (read_only()) { - node_data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, - ui::AX_RESTRICTION_READ_ONLY); - } + if (read_only()) + node_data->SetRestriction(ax::mojom::Restriction::kReadOnly); } if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD) { - node_data->AddState(ui::AX_STATE_PROTECTED); + node_data->AddState(ax::mojom::State::kProtected); node_data->SetValue(base::string16( text().size(), gfx::RenderText::kPasswordReplacementChar)); } else { node_data->SetValue(text()); } - node_data->AddStringAttribute(ui::AX_ATTR_PLACEHOLDER, + node_data->AddStringAttribute(ax::mojom::StringAttribute::kPlaceholder, base::UTF16ToUTF8(GetPlaceholderText())); const gfx::Range range = GetSelectedRange(); - node_data->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, range.start()); - node_data->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, range.end()); + node_data->AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart, + range.start()); + node_data->AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, range.end()); } bool Textfield::HandleAccessibleAction(const ui::AXActionData& action_data) { - if (action_data.action == ui::AX_ACTION_SET_SELECTION) { + if (action_data.action == ax::mojom::Action::kSetSelection) { if (action_data.anchor_node_id != action_data.focus_node_id) return false; // TODO(nektar): Check that the focus_node_id matches the ID of this node. @@ -977,11 +989,11 @@ bool Textfield::HandleAccessibleAction(const ui::AXActionData& action_data) { if (read_only()) return View::HandleAccessibleAction(action_data); - if (action_data.action == ui::AX_ACTION_SET_VALUE) { + if (action_data.action == ax::mojom::Action::kSetValue) { SetText(action_data.value); ClearSelection(); return true; - } else if (action_data.action == ui::AX_ACTION_REPLACE_SELECTED_TEXT) { + } else if (action_data.action == ax::mojom::Action::kReplaceSelectedText) { InsertOrReplaceText(action_data.value); ClearSelection(); return true; @@ -1688,7 +1700,7 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) { case ui::TextEditCommand::DELETE_TO_END_OF_LINE: case ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH: add_to_kill_buffer = text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD; - // Fall through. + FALLTHROUGH; case ui::TextEditCommand::DELETE_WORD_BACKWARD: case ui::TextEditCommand::DELETE_WORD_FORWARD: if (HasSelection()) @@ -1872,6 +1884,10 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) { OnAfterUserAction(); } +void Textfield::OffsetDoubleClickWord(int offset) { + selection_controller_.OffsetDoubleClickWord(offset); +} + //////////////////////////////////////////////////////////////////////////////// // Textfield, private: @@ -1984,7 +2000,7 @@ void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) { if (text_changed) { if (controller_) controller_->ContentsChanged(this, text()); - NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true); } if (cursor_changed) { UpdateCursorViewPosition(); @@ -2036,9 +2052,10 @@ void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) { GetPlaceholderText(), placeholder_font_list_.has_value() ? placeholder_font_list_.value() : GetFontList(), - ui::MaterialDesignController::IsSecondaryUiMaterial() - ? SkColorSetA(GetTextColor(), 0x83) - : placeholder_text_color_, + placeholder_text_color_.value_or( + ui::MaterialDesignController::IsSecondaryUiMaterial() + ? SkColorSetA(GetTextColor(), 0x83) + : kDefaultPlaceholderTextColor), render_text->display_rect(), placeholder_text_draw_flags); } @@ -2063,7 +2080,7 @@ void Textfield::OnCaretBoundsChanged() { GetInputMethod()->OnCaretBoundsChanged(this); if (touch_selection_controller_) touch_selection_controller_->SelectionChanged(); - NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_SELECTION_CHANGED, true); + NotifyAccessibilityEvent(ax::mojom::Event::kTextSelectionChanged, true); } void Textfield::OnBeforeUserAction() { @@ -2125,7 +2142,11 @@ void Textfield::UpdateContextMenu() { // IsCommandIdEnabled() as appropriate, for the commands added. if (controller_) controller_->UpdateContextMenu(context_menu_contents_.get()); + + text_services_context_menu_ = ViewsTextServicesContextMenu::Create( + context_menu_contents_.get(), this); } + context_menu_runner_.reset( new MenuRunner(context_menu_contents_.get(), MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU)); diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h index 1c36080fcf6..db30abdd006 100644 --- a/chromium/ui/views/controls/textfield/textfield.h +++ b/chromium/ui/views/controls/textfield/textfield.h @@ -40,8 +40,10 @@ class TimeDelta; namespace views { +class Label; class MenuRunner; class TextfieldController; +class ViewsTextServicesContextMenu; // A views/skia textfield implementation. No platform-specific code is used. class VIEWS_EXPORT Textfield : public View, @@ -218,9 +220,15 @@ class VIEWS_EXPORT Textfield : public View, // Clears Edit history. void ClearEditHistory(); - // Set the accessible name of the text field. + // Set the accessible name of the text field. If the textfield has a visible + // label, use SetAssociatedLabel() instead. void SetAccessibleName(const base::string16& name); + // If the accessible name should be the same as the label text, use this. It + // will set both the accessible label relationship and the accessible name + // from the contents of the label. + void SetAssociatedLabel(Label* label); + // Set extra spacing placed between glyphs; used for obscured text styling. void SetGlyphSpacing(int spacing); @@ -352,6 +360,11 @@ class VIEWS_EXPORT Textfield : public View, // Executes the given |command|. virtual void ExecuteTextEditCommand(ui::TextEditCommand command); + // Offsets the double-clicked word's range. This is only used in the unusual + // case where the text changes on the second mousedown of a double-click. + // This is harmless if there is not a currently double-clicked word. + void OffsetDoubleClickWord(int offset); + private: friend class TextfieldTestApi; @@ -488,8 +501,10 @@ class VIEWS_EXPORT Textfield : public View, base::string16 placeholder_text_; // Placeholder text color. - // TODO(estade): remove this when Harmony/MD is default. - SkColor placeholder_text_color_; + // TODO(newcomer): Use NativeTheme to define different default placeholder + // text colors for chrome/CrOS when harmony is enabled by default + // (https://crbug.com/803279). + base::Optional<SkColor> placeholder_text_color_; // The draw flags specified for |placeholder_text_|. int placeholder_text_draw_flags_; @@ -502,6 +517,9 @@ class VIEWS_EXPORT Textfield : public View, // such. bool invalid_; + // The unique id for the associated label's accessible object. + int32_t label_ax_id_; + // The accessible name of the text field. base::string16 accessible_name_; @@ -551,6 +569,7 @@ class VIEWS_EXPORT Textfield : public View, // Context menu related members. std::unique_ptr<ui::SimpleMenuModel> context_menu_contents_; + std::unique_ptr<ViewsTextServicesContextMenu> text_services_context_menu_; std::unique_ptr<views::MenuRunner> context_menu_runner_; // View containing the text cursor. diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.cc b/chromium/ui/views/controls/textfield/textfield_test_api.cc index bef918aea45..3f756dfaad7 100644 --- a/chromium/ui/views/controls/textfield/textfield_test_api.cc +++ b/chromium/ui/views/controls/textfield/textfield_test_api.cc @@ -5,6 +5,7 @@ #include "ui/views/controls/textfield/textfield_test_api.h" #include "ui/gfx/geometry/rect.h" +#include "ui/views/controls/views_text_services_context_menu.h" namespace views { @@ -33,4 +34,10 @@ void TextfieldTestApi::SetCursorViewRect(gfx::Rect bounds) { textfield_->cursor_view_.SetBoundsRect(bounds); } +bool TextfieldTestApi::IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection direction) const { + return ViewsTextServicesContextMenu::IsTextDirectionCheckedForTesting( + textfield_->text_services_context_menu_.get(), direction); +} + } // namespace views diff --git a/chromium/ui/views/controls/textfield/textfield_test_api.h b/chromium/ui/views/controls/textfield/textfield_test_api.h index 8b898715afd..c111175ea47 100644 --- a/chromium/ui/views/controls/textfield/textfield_test_api.h +++ b/chromium/ui/views/controls/textfield/textfield_test_api.h @@ -5,6 +5,7 @@ #ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_ #define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_TEST_API_H_ +#include "base/i18n/rtl.h" #include "base/macros.h" #include "ui/views/controls/textfield/textfield.h" @@ -50,6 +51,9 @@ class TextfieldTestApi { bool IsCursorVisible() const { return textfield_->cursor_view_.visible(); } + bool IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection direction) const; + private: Textfield* textfield_; diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc index 4ee16e76284..5cfb980672f 100644 --- a/chromium/ui/views/controls/textfield/textfield_unittest.cc +++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc @@ -890,9 +890,11 @@ TEST_F(TextfieldTest, ControlAndSelectTest) { // Test word select. SendWordEvent(ui::VKEY_RIGHT, true); -#if defined(OS_WIN) // Select word right includes space/punctuation. +#if defined(OS_WIN) // Windows breaks on word starts and includes spaces. + EXPECT_STR_EQ("one ", textfield_->GetSelectedText()); + SendWordEvent(ui::VKEY_RIGHT, true); EXPECT_STR_EQ("one two ", textfield_->GetSelectedText()); -#else // Non-Windows: select word right does NOT include space/punctuation. +#else // Non-Windows breaks on word ends and does NOT include spaces. EXPECT_STR_EQ("one two", textfield_->GetSelectedText()); #endif SendWordEvent(ui::VKEY_RIGHT, true); @@ -1441,6 +1443,9 @@ TEST_F(TextfieldTest, CursorMovement) { // Ctrl+Right, then Ctrl+Left should move the cursor to the beginning of the // first word. SendWordEvent(ui::VKEY_RIGHT, shift); +#if defined(OS_WIN) // Windows breaks on word start, move further to pass "ne". + SendWordEvent(ui::VKEY_RIGHT, shift); +#endif SendWordEvent(ui::VKEY_LEFT, shift); SendKeyEvent(ui::VKEY_O); EXPECT_STR_EQ(" one two", textfield_->text()); @@ -3214,18 +3219,18 @@ TEST_F(TextfieldTest, AccessiblePasswordTest) { ui::AXNodeData node_data_regular; textfield_->GetAccessibleNodeData(&node_data_regular); - EXPECT_EQ(ui::AX_ROLE_TEXT_FIELD, node_data_regular.role); - EXPECT_EQ(ASCIIToUTF16("password"), - node_data_regular.GetString16Attribute(ui::AX_ATTR_VALUE)); - EXPECT_FALSE(node_data_regular.HasState(ui::AX_STATE_PROTECTED)); + EXPECT_EQ(ax::mojom::Role::kTextField, node_data_regular.role); + EXPECT_EQ(ASCIIToUTF16("password"), node_data_regular.GetString16Attribute( + ax::mojom::StringAttribute::kValue)); + EXPECT_FALSE(node_data_regular.HasState(ax::mojom::State::kProtected)); textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); ui::AXNodeData node_data_protected; textfield_->GetAccessibleNodeData(&node_data_protected); - EXPECT_EQ(ui::AX_ROLE_TEXT_FIELD, node_data_protected.role); - EXPECT_EQ(UTF8ToUTF16("••••••••"), - node_data_protected.GetString16Attribute(ui::AX_ATTR_VALUE)); - EXPECT_TRUE(node_data_protected.HasState(ui::AX_STATE_PROTECTED)); + EXPECT_EQ(ax::mojom::Role::kTextField, node_data_protected.role); + EXPECT_EQ(UTF8ToUTF16("••••••••"), node_data_protected.GetString16Attribute( + ax::mojom::StringAttribute::kValue)); + EXPECT_TRUE(node_data_protected.HasState(ax::mojom::State::kProtected)); } // Verify that cursor visibility is controlled by SetCursorEnabled. @@ -3400,4 +3405,37 @@ TEST_F(TextfieldTest, SendingDeletePreservesShiftFlag) { EXPECT_EQ(ui::EF_SHIFT_DOWN, textfield_->event_flags()); } +#if defined(OS_MACOSX) +// Tests to see if the BiDi submenu items are updated correctly when the +// textfield's text direction is changed. +TEST_F(TextfieldTest, TextServicesContextMenuTextDirectionTest) { + InitTextfield(); + EXPECT_TRUE(textfield_->context_menu_controller()); + + EXPECT_TRUE(GetContextMenuModel()); + + textfield_->ChangeTextDirectionAndLayoutAlignment( + base::i18n::TextDirection::LEFT_TO_RIGHT); + test_api_->UpdateContextMenu(); + + EXPECT_FALSE(test_api_->IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection::UNKNOWN_DIRECTION)); + EXPECT_TRUE(test_api_->IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection::LEFT_TO_RIGHT)); + EXPECT_FALSE(test_api_->IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection::RIGHT_TO_LEFT)); + + textfield_->ChangeTextDirectionAndLayoutAlignment( + base::i18n::TextDirection::RIGHT_TO_LEFT); + test_api_->UpdateContextMenu(); + + EXPECT_FALSE(test_api_->IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection::UNKNOWN_DIRECTION)); + EXPECT_FALSE(test_api_->IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection::LEFT_TO_RIGHT)); + EXPECT_TRUE(test_api_->IsTextDirectionCheckedInContextMenu( + base::i18n::TextDirection::RIGHT_TO_LEFT)); +} +#endif // defined(OS_MACOSX) + } // namespace views diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc index d8382aa975f..f5709270c99 100644 --- a/chromium/ui/views/controls/tree/tree_view.cc +++ b/chromium/ui/views/controls/tree/tree_view.cc @@ -272,8 +272,8 @@ void TreeView::SetSelectedNode(TreeModelNode* model_node) { controller_->OnTreeViewSelectionChanged(this); if (changed) { - NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); - NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); + NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true); + NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true); } } @@ -425,14 +425,13 @@ void TreeView::ShowContextMenu(const gfx::Point& p, } void TreeView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_TREE; - node_data->AddIntAttribute(ui::AX_ATTR_RESTRICTION, - ui::AX_RESTRICTION_READ_ONLY); + node_data->role = ax::mojom::Role::kTree; + node_data->SetRestriction(ax::mojom::Restriction::kReadOnly); if (!selected_node_) return; // Get selected item info. - node_data->role = ui::AX_ROLE_TREE_ITEM; + node_data->role = ax::mojom::Role::kTreeItem; node_data->SetName(selected_node_->model_node()->GetTitle()); } diff --git a/chromium/ui/views/controls/views_text_services_context_menu.cc b/chromium/ui/views/controls/views_text_services_context_menu.cc new file mode 100644 index 00000000000..ec5975312cc --- /dev/null +++ b/chromium/ui/views/controls/views_text_services_context_menu.cc @@ -0,0 +1,25 @@ +// Copyright 2018 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/views/controls/views_text_services_context_menu.h" + +#include "base/logging.h" + +namespace views { + +// static +std::unique_ptr<ViewsTextServicesContextMenu> +ViewsTextServicesContextMenu::Create(ui::SimpleMenuModel* menu, + Textfield* client) { + return nullptr; +} + +bool ViewsTextServicesContextMenu::IsTextDirectionCheckedForTesting( + ViewsTextServicesContextMenu* menu, + base::i18n::TextDirection direction) { + NOTREACHED(); + return false; +} + +} // namespace views
\ No newline at end of file diff --git a/chromium/ui/views/controls/views_text_services_context_menu.h b/chromium/ui/views/controls/views_text_services_context_menu.h new file mode 100644 index 00000000000..2388b27653b --- /dev/null +++ b/chromium/ui/views/controls/views_text_services_context_menu.h @@ -0,0 +1,41 @@ +// Copyright 2018 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_VIEWS_CONTROLS_TEXTFIELD_VIEWS_TEXT_SERVICES_CONTEXT_MENU_H_ +#define UI_VIEWS_CONTROLS_TEXTFIELD_VIEWS_TEXT_SERVICES_CONTEXT_MENU_H_ + +#include <memory> + +#include "base/i18n/rtl.h" +#include "ui/views/views_export.h" + +namespace ui { +class SimpleMenuModel; +} + +namespace views { + +class Textfield; + +// This class is used to add and handle text service items in the text context +// menu. +class ViewsTextServicesContextMenu { + public: + virtual ~ViewsTextServicesContextMenu() {} + + // Creates a platform-specific ViewsTextServicesContextMenu object. + static std::unique_ptr<ViewsTextServicesContextMenu> Create( + ui::SimpleMenuModel* menu, + Textfield* textfield); + + // Method for testing. Returns true if the text direction BiDi submenu item + // in |menu| should be checked. + VIEWS_EXPORT static bool IsTextDirectionCheckedForTesting( + ViewsTextServicesContextMenu* menu, + base::i18n::TextDirection direction); +}; + +} // namespace views + +#endif // UI_VIEWS_CONTROLS_TEXTFIELD_VIEWS_TEXT_SERVICES_CONTEXT_MENU_H_ diff --git a/chromium/ui/views/controls/views_text_services_context_menu_mac.mm b/chromium/ui/views/controls/views_text_services_context_menu_mac.mm new file mode 100644 index 00000000000..be96d8ac4ee --- /dev/null +++ b/chromium/ui/views/controls/views_text_services_context_menu_mac.mm @@ -0,0 +1,83 @@ +// Copyright 2018 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/views/controls/views_text_services_context_menu.h" + +#include "base/memory/ptr_util.h" +#include "ui/base/cocoa/text_services_context_menu.h" +#include "ui/base/models/simple_menu_model.h" +#include "ui/views/controls/textfield/textfield.h" + +namespace views { + +namespace { + +// This class serves as a bridge to TextServicesContextMenu to add and handle +// text service items in the context menu. The items include Speech, Look Up +// and BiDi. +// TODO (spqchan): Add Look Up and BiDi. +class ViewsTextServicesContextMenuMac + : public ViewsTextServicesContextMenu, + public ui::TextServicesContextMenu::Delegate { + public: + ViewsTextServicesContextMenuMac(ui::SimpleMenuModel* menu, Textfield* client) + : text_services_menu_(this), client_(client) { + text_services_menu_.AppendToContextMenu(menu); + text_services_menu_.AppendEditableItems(menu); + } + + ~ViewsTextServicesContextMenuMac() override {} + + // TextServicesContextMenu::Delegate: + base::string16 GetSelectedText() const override { + return client_->GetSelectedText(); + } + + bool IsTextDirectionEnabled( + base::i18n::TextDirection direction) const override { + return direction != base::i18n::UNKNOWN_DIRECTION; + } + + bool IsTextDirectionChecked( + base::i18n::TextDirection direction) const override { + return direction != base::i18n::UNKNOWN_DIRECTION && + client_->GetTextDirection() == direction; + } + + void UpdateTextDirection(base::i18n::TextDirection direction) override { + DCHECK_NE(direction, base::i18n::UNKNOWN_DIRECTION); + + base::i18n::TextDirection text_direction = + direction == base::i18n::LEFT_TO_RIGHT ? base::i18n::LEFT_TO_RIGHT + : base::i18n::RIGHT_TO_LEFT; + client_->ChangeTextDirectionAndLayoutAlignment(text_direction); + } + + private: + // Appends and handles the text service menu. + ui::TextServicesContextMenu text_services_menu_; + + // The view associated with the menu. Weak. Owns |this|. + Textfield* client_; + + DISALLOW_COPY_AND_ASSIGN(ViewsTextServicesContextMenuMac); +}; + +} // namespace + +// static +std::unique_ptr<ViewsTextServicesContextMenu> +ViewsTextServicesContextMenu::Create(ui::SimpleMenuModel* menu, + Textfield* client) { + return std::make_unique<ViewsTextServicesContextMenuMac>(menu, client); +} + +// static +bool ViewsTextServicesContextMenu::IsTextDirectionCheckedForTesting( + ViewsTextServicesContextMenu* menu, + base::i18n::TextDirection direction) { + return static_cast<views::ViewsTextServicesContextMenuMac*>(menu) + ->IsTextDirectionChecked(direction); +} +} // namespace views
\ No newline at end of file diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc index b65a9e4cbbe..5144b14e415 100644 --- a/chromium/ui/views/controls/webview/webview.cc +++ b/chromium/ui/views/controls/webview/webview.cc @@ -14,7 +14,7 @@ #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "ipc/ipc_message.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/events/event.h" #include "ui/views/controls/native/native_view_host.h" @@ -54,11 +54,11 @@ content::WebContents* WebView::GetWebContents() { void WebView::SetWebContents(content::WebContents* replacement) { if (replacement == web_contents()) return; + SetCrashedOverlayView(nullptr); DetachWebContents(); WebContentsObserver::Observe(replacement); // web_contents() now returns |replacement| from here onwards. - SetFocusBehavior(web_contents() ? FocusBehavior::ALWAYS - : FocusBehavior::NEVER); + UpdateCrashedOverlayView(); if (wc_owner_.get() != replacement) wc_owner_.reset(); if (embed_fullscreen_widget_mode_enabled_) { @@ -91,6 +91,25 @@ void WebView::SetResizeBackgroundColor(SkColor resize_background_color) { holder_->set_resize_background_color(resize_background_color); } +void WebView::SetCrashedOverlayView(View* crashed_overlay_view) { + if (crashed_overlay_view_ == crashed_overlay_view) + return; + + if (crashed_overlay_view_) { + RemoveChildView(crashed_overlay_view_); + if (!crashed_overlay_view_->owned_by_client()) + delete crashed_overlay_view_; + } + + crashed_overlay_view_ = crashed_overlay_view; + if (crashed_overlay_view_) { + AddChildView(crashed_overlay_view_); + crashed_overlay_view_->SetBoundsRect(gfx::Rect(size())); + } + + UpdateCrashedOverlayView(); +} + //////////////////////////////////////////////////////////////////////////////// // WebView, View overrides: @@ -111,6 +130,9 @@ std::unique_ptr<content::WebContents> WebView::SwapWebContents( } void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) { + if (crashed_overlay_view_) + crashed_overlay_view_->SetBoundsRect(gfx::Rect(size())); + // In most cases, the holder is simply sized to fill this WebView's bounds. // Only WebContentses that are in fullscreen mode and being screen-captured // will engage the special layout/sizing behavior. @@ -181,21 +203,25 @@ bool WebView::OnMousePressed(const ui::MouseEvent& event) { } void WebView::OnFocus() { - if (web_contents()) + if (web_contents() && !web_contents()->IsCrashed()) web_contents()->Focus(); } void WebView::AboutToRequestFocusFromTabTraversal(bool reverse) { - if (web_contents()) + if (web_contents() && !web_contents()->IsCrashed()) web_contents()->FocusThroughTabTraversal(reverse); } void WebView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_WEB_VIEW; + node_data->role = ax::mojom::Role::kWebView; + // A webview does not need an accessible name as the document title is + // provided via other means. Providing it here would be redundant. + // Mark the name as explicitly empty so that accessibility_checks pass. + node_data->SetNameExplicitlyEmpty(); } gfx::NativeViewAccessible WebView::GetNativeViewAccessible() { - if (web_contents()) { + if (web_contents() && !web_contents()->IsCrashed()) { content::RenderWidgetHostView* host_view = web_contents()->GetRenderWidgetHostView(); if (host_view) @@ -216,10 +242,12 @@ bool WebView::EmbedsFullscreenWidget() const { // WebView, content::WebContentsObserver implementation: void WebView::RenderViewReady() { + UpdateCrashedOverlayView(); NotifyAccessibilityWebContentsChanged(); } void WebView::RenderViewDeleted(content::RenderViewHost* render_view_host) { + UpdateCrashedOverlayView(); NotifyAccessibilityWebContentsChanged(); } @@ -264,6 +292,7 @@ void WebView::OnWebContentsFocused( } void WebView::RenderProcessGone(base::TerminationStatus status) { + UpdateCrashedOverlayView(); NotifyAccessibilityWebContentsChanged(); } @@ -317,9 +346,32 @@ void WebView::ReattachForFullscreenChange(bool enter_fullscreen) { NotifyAccessibilityWebContentsChanged(); } +void WebView::UpdateCrashedOverlayView() { + // TODO(dmazzoni): Fix WebContents::IsCrashed() so we can call that + // instead of checking termination status codes. + if (web_contents() && + web_contents()->GetCrashedStatus() != + base::TERMINATION_STATUS_NORMAL_TERMINATION && + web_contents()->GetCrashedStatus() != + base::TERMINATION_STATUS_STILL_RUNNING && + crashed_overlay_view_) { + SetFocusBehavior(FocusBehavior::NEVER); + holder_->SetVisible(false); + crashed_overlay_view_->SetVisible(true); + return; + } + + SetFocusBehavior(web_contents() ? FocusBehavior::ALWAYS + : FocusBehavior::NEVER); + + if (crashed_overlay_view_) + crashed_overlay_view_->SetVisible(false); + holder_->SetVisible(true); +} + void WebView::NotifyAccessibilityWebContentsChanged() { if (web_contents()) - NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, false); + NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false); } content::WebContents* WebView::CreateWebContents( diff --git a/chromium/ui/views/controls/webview/webview.h b/chromium/ui/views/controls/webview/webview.h index 73ad929c699..afdd0a03938 100644 --- a/chromium/ui/views/controls/webview/webview.h +++ b/chromium/ui/views/controls/webview/webview.h @@ -79,6 +79,11 @@ class WEBVIEW_EXPORT WebView : public View, // by default. void SetResizeBackgroundColor(SkColor resize_background_color); + // If provided, this View will be shown in place of the web contents + // when the web contents is in a crashed state. This is cleared automatically + // if the web contents is changed. + void SetCrashedOverlayView(View* crashed_overlay_view); + // When used to host UI, we need to explicitly allow accelerators to be // processed. Default is false. void set_allow_accelerators(bool allow_accelerators) { @@ -140,6 +145,7 @@ class WEBVIEW_EXPORT WebView : public View, void AttachWebContents(); void DetachWebContents(); void ReattachForFullscreenChange(bool enter_fullscreen); + void UpdateCrashedOverlayView(); void NotifyAccessibilityWebContentsChanged(); // Create a regular or test web contents (based on whether we're running @@ -158,6 +164,7 @@ class WEBVIEW_EXPORT WebView : public View, bool is_embedding_fullscreen_widget_; content::BrowserContext* browser_context_; bool allow_accelerators_; + View* crashed_overlay_view_ = nullptr; DISALLOW_COPY_AND_ASSIGN(WebView); }; diff --git a/chromium/ui/views/controls/webview/webview_unittest.cc b/chromium/ui/views/controls/webview/webview_unittest.cc index 2ca7683f8d8..b3c86732c50 100644 --- a/chromium/ui/views/controls/webview/webview_unittest.cc +++ b/chromium/ui/views/controls/webview/webview_unittest.cc @@ -48,8 +48,8 @@ class WebViewTestViewsDelegate : public views::TestViewsDelegate { DISALLOW_COPY_AND_ASSIGN(WebViewTestViewsDelegate); }; -// Provides functionality to observe events on a WebContents like WasShown/ -// WasHidden/WebContentsDestroyed. +// Provides functionality to observe events on a WebContents like +// OnVisibilityChanged/WebContentsDestroyed. class WebViewTestWebContentsObserver : public content::WebContentsObserver { public: WebViewTestWebContentsObserver(content::WebContents* web_contents) @@ -72,18 +72,27 @@ class WebViewTestWebContentsObserver : public content::WebContentsObserver { web_contents_ = NULL; } - void WasShown() override { + void OnVisibilityChanged(content::Visibility visibility) override { + switch (visibility) { + case content::Visibility::VISIBLE: { #if defined(USE_AURA) - valid_root_while_shown_ = - web_contents()->GetNativeView()->GetRootWindow() != NULL; + valid_root_while_shown_ = + web_contents()->GetNativeView()->GetRootWindow() != NULL; #endif - was_shown_ = true; - ++shown_count_; - } - - void WasHidden() override { - was_shown_ = false; - ++hidden_count_; + was_shown_ = true; + ++shown_count_; + break; + } + case content::Visibility::HIDDEN: { + was_shown_ = false; + ++hidden_count_; + break; + } + default: { + ADD_FAILURE() << "Unexpected call to OnVisibilityChanged."; + break; + } + } } bool was_shown() const { return was_shown_; } @@ -485,4 +494,58 @@ TEST_F(WebViewUnitTest, DetachedWebViewDestructor) { webview.reset(); } +// Test that the specified crashed overlay view is shown when a WebContents +// is in a crashed state. +TEST_F(WebViewUnitTest, CrashedOverlayView) { + const std::unique_ptr<content::WebContents> web_contents(CreateWebContents()); + std::unique_ptr<WebView> web_view( + new WebView(web_contents->GetBrowserContext())); + View* contents_view = top_level_widget()->GetContentsView(); + contents_view->AddChildView(web_view.get()); + web_view->SetWebContents(web_contents.get()); + + View* crashed_overlay_view = new View(); + web_view->SetCrashedOverlayView(crashed_overlay_view); + EXPECT_FALSE(crashed_overlay_view->IsDrawn()); + + // Normally when a renderer crashes, the WebView will learn about it + // automatically via WebContentsObserver. Since this is a test + // WebContents, simulate that by calling SetIsCrashed and then + // explicitly calling RenderViewDeleted on the WebView to trigger it + // to swap in the crashed overlay view. + web_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + EXPECT_TRUE(web_contents->IsCrashed()); + static_cast<content::WebContentsObserver*>(web_view.get()) + ->RenderViewDeleted(nullptr); + EXPECT_TRUE(crashed_overlay_view->IsDrawn()); +} + +// Test that a crashed overlay view isn't deleted if it's owned by client. +TEST_F(WebViewUnitTest, CrashedOverlayViewOwnedbyClient) { + const std::unique_ptr<content::WebContents> web_contents(CreateWebContents()); + std::unique_ptr<WebView> web_view( + new WebView(web_contents->GetBrowserContext())); + View* contents_view = top_level_widget()->GetContentsView(); + contents_view->AddChildView(web_view.get()); + web_view->SetWebContents(web_contents.get()); + + View* crashed_overlay_view = new View(); + crashed_overlay_view->set_owned_by_client(); + web_view->SetCrashedOverlayView(crashed_overlay_view); + EXPECT_FALSE(crashed_overlay_view->IsDrawn()); + + // Simulate a renderer crash (see above). + web_contents->SetIsCrashed(base::TERMINATION_STATUS_PROCESS_CRASHED, -1); + EXPECT_TRUE(web_contents->IsCrashed()); + static_cast<content::WebContentsObserver*>(web_view.get()) + ->RenderViewDeleted(nullptr); + EXPECT_TRUE(crashed_overlay_view->IsDrawn()); + + web_view->SetCrashedOverlayView(nullptr); + web_view.reset(); + + // This shouldn't crash, we still own this. + delete crashed_overlay_view; +} + } // namespace views diff --git a/chromium/ui/views/examples/label_example.cc b/chromium/ui/views/examples/label_example.cc index 05e30aa2e12..4af92326d72 100644 --- a/chromium/ui/views/examples/label_example.cc +++ b/chromium/ui/views/examples/label_example.cc @@ -101,7 +101,7 @@ void LabelExample::CreateExampleView(View* container) { label->SetFontList(gfx::FontList("Courier, 18px")); gfx::ShadowValues shadows(1, gfx::ShadowValue(gfx::Vector2d(), 1, SK_ColorRED)); - gfx::ShadowValue shadow(gfx::Vector2d(2, 2), 0, SK_ColorGRAY); + constexpr gfx::ShadowValue shadow(gfx::Vector2d(2, 2), 0, SK_ColorGRAY); shadows.push_back(shadow); label->SetShadows(shadows); container->AddChildView(label); diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn index dc46a047be4..a8e4c997153 100644 --- a/chromium/ui/views/mus/BUILD.gn +++ b/chromium/ui/views/mus/BUILD.gn @@ -53,9 +53,9 @@ jumbo_component("mus") { "//mojo/public/cpp/bindings", "//net", "//services/catalog/public/cpp", - "//services/catalog/public/interfaces:constants", + "//services/catalog/public/mojom:constants", "//services/service_manager/public/cpp", - "//services/service_manager/public/interfaces", + "//services/service_manager/public/mojom", "//services/ui/public/cpp", "//services/ui/public/interfaces", "//skia", @@ -250,6 +250,7 @@ test("views_mus_interactive_ui_tests") { "//ui/aura", "//ui/aura:test_support", "//ui/base", + "//ui/base:test_support", "//ui/base/ime", "//ui/events:events_base", "//ui/events:test_support", diff --git a/chromium/ui/views/mus/aura_init.cc b/chromium/ui/views/mus/aura_init.cc index 60773f241f9..7631ab57b0e 100644 --- a/chromium/ui/views/mus/aura_init.cc +++ b/chromium/ui/views/mus/aura_init.cc @@ -12,7 +12,7 @@ #include "base/path_service.h" #include "build/build_config.h" #include "services/catalog/public/cpp/resource_loader.h" -#include "services/catalog/public/interfaces/constants.mojom.h" +#include "services/catalog/public/mojom/constants.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "ui/aura/env.h" #include "ui/base/ime/input_method_initializer.h" @@ -133,7 +133,7 @@ bool AuraInit::InitializeResources(service_manager::Connector* connector, const std::string& resource_file, const std::string& resource_file_200, bool register_path_provider) { - // Resources may have already been initialized (e.g. when 'chrome --mash' is + // Resources may have already been initialized (e.g. when chrome with mash is // used to launch the current app). if (ui::ResourceBundle::HasSharedInstance()) return true; diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc index 683a0520ade..34a105de7de 100644 --- a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc +++ b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc @@ -328,10 +328,10 @@ TEST_F(DesktopWindowTreeHostMusTest, ShadowDefaults) { widget.Init(params); // |DesktopNativeWidgetAura::content_window_| should have no shadow; the wm // should provide it if it so desires. - EXPECT_EQ(wm::ShadowElevation::NONE, + EXPECT_EQ(wm::kShadowElevationNone, widget.GetNativeView()->GetProperty(wm::kShadowElevationKey)); // The wm honors the shadow property from the WindowTreeHost's window. - EXPECT_EQ(wm::ShadowElevation::DEFAULT, + EXPECT_EQ(wm::kShadowElevationDefault, widget.GetNativeView()->GetHost()->window()->GetProperty( wm::kShadowElevationKey)); } @@ -342,9 +342,9 @@ TEST_F(DesktopWindowTreeHostMusTest, NoShadow) { params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE; widget.Init(params); - EXPECT_EQ(wm::ShadowElevation::NONE, + EXPECT_EQ(wm::kShadowElevationNone, widget.GetNativeView()->GetProperty(wm::kShadowElevationKey)); - EXPECT_EQ(wm::ShadowElevation::NONE, + EXPECT_EQ(wm::kShadowElevationNone, widget.GetNativeView()->GetHost()->window()->GetProperty( wm::kShadowElevationKey)); } diff --git a/chromium/ui/views/mus/mus_client.cc b/chromium/ui/views/mus/mus_client.cc index 30a7651135d..9399f8228d7 100644 --- a/chromium/ui/views/mus/mus_client.cc +++ b/chromium/ui/views/mus/mus_client.cc @@ -95,9 +95,9 @@ MusClient::MusClient(service_manager::Connector* connector, // TODO(msw): Avoid this... use some default value? Allow clients to extend? property_converter_ = std::make_unique<aura::PropertyConverter>(); property_converter_->RegisterPrimitiveProperty( - wm::kShadowElevationKey, + ::wm::kShadowElevationKey, ui::mojom::WindowManager::kShadowElevation_Property, - base::Bind(&wm::IsValidShadowElevation)); + aura::PropertyConverter::CreateAcceptAnyValueCallback()); if (create_wm_state) wm_state_ = std::make_unique<wm::WMState>(); @@ -195,6 +195,12 @@ MusClient::ConfigurePropertiesFromParams( properties[WindowManager::kRemoveStandardFrame_InitProperty] = mojo::ConvertTo<TransportType>(init_params.remove_standard_frame); + if (init_params.corner_radius) { + properties[WindowManager::kWindowCornerRadius_Property] = + mojo::ConvertTo<TransportType>( + static_cast<PrimitiveType>(*init_params.corner_radius)); + } + if (!Widget::RequiresNonClientView(init_params.type)) return properties; diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc index 202bd8c986c..0008b8eeaf4 100644 --- a/chromium/ui/views/mus/views_mus_test_suite.cc +++ b/chromium/ui/views/mus/views_mus_test_suite.cc @@ -7,6 +7,7 @@ #include <memory> #include <string> +#include "base/base_switches.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/memory/ptr_util.h" @@ -28,6 +29,7 @@ #include "ui/aura/mus/window_tree_host_mus.h" #include "ui/aura/test/mus/input_method_mus_test_api.h" #include "ui/aura/window.h" +#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_switches.h" #include "ui/compositor/test/fake_context_factory.h" #include "ui/gl/gl_switches.h" @@ -240,12 +242,15 @@ void ViewsMusTestSuite::Initialize() { EnsureCommandLineSwitch(ui::switches::kUseTestConfig); EnsureCommandLineSwitch(switches::kOverrideUseSoftwareGLForTests); - base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMus); - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kMusHostingViz); ViewsTestSuite::Initialize(); + // NOTE: this has to be after ViewsTestSuite::Initialize() as + // TestSuite::Initialize() resets kEnableFeatures and the command line. + feature_list_.InitAndEnableFeature(features::kMash); + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kEnableFeatures, features::kMash.name); + PlatformTestHelper::set_factory(base::Bind(&CreatePlatformTestHelper)); } diff --git a/chromium/ui/views/mus/views_mus_test_suite.h b/chromium/ui/views/mus/views_mus_test_suite.h index d8184d0ee6e..4dc9d09dc07 100644 --- a/chromium/ui/views/mus/views_mus_test_suite.h +++ b/chromium/ui/views/mus/views_mus_test_suite.h @@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/test/scoped_feature_list.h" #include "ui/views/views_test_suite.h" namespace views { @@ -23,6 +24,8 @@ class ViewsMusTestSuite : public ViewsTestSuite { void InitializeEnv() override; void DestroyEnv() override; + base::test::ScopedFeatureList feature_list_; + std::unique_ptr<aura::Env> env_; DISALLOW_COPY_AND_ASSIGN(ViewsMusTestSuite); diff --git a/chromium/ui/views/selection_controller.cc b/chromium/ui/views/selection_controller.cc index 1169936be56..aa400d8bf22 100644 --- a/chromium/ui/views/selection_controller.cc +++ b/chromium/ui/views/selection_controller.cc @@ -154,6 +154,11 @@ void SelectionController::OnMouseCaptureLost() { delegate_->UpdateSelectionClipboard(); } +void SelectionController::OffsetDoubleClickWord(int offset) { + double_click_word_.set_start(double_click_word_.start() + offset); + double_click_word_.set_end(double_click_word_.end() + offset); +} + void SelectionController::TrackMouseClicks(const ui::MouseEvent& event) { if (event.IsOnlyLeftMouseButton()) { base::TimeDelta time_delta = event.time_stamp() - last_click_time_; diff --git a/chromium/ui/views/selection_controller.h b/chromium/ui/views/selection_controller.h index 3a2279bef55..cb929fdd621 100644 --- a/chromium/ui/views/selection_controller.h +++ b/chromium/ui/views/selection_controller.h @@ -58,6 +58,11 @@ class VIEWS_EXPORT SelectionController { handles_selection_clipboard_ = value; } + // Offsets the double-clicked word's range. This is only used in the unusual + // case where the text changes on the second mousedown of a double-click. + // This is harmless if there is not a currently double-clicked word. + void OffsetDoubleClickWord(int offset); + private: // Tracks the mouse clicks for single/double/triple clicks. void TrackMouseClicks(const ui::MouseEvent& event); diff --git a/chromium/ui/views/style/platform_style.cc b/chromium/ui/views/style/platform_style.cc index 42b006117aa..b12430178e9 100644 --- a/chromium/ui/views/style/platform_style.cc +++ b/chromium/ui/views/style/platform_style.cc @@ -33,6 +33,12 @@ const SkColor kStyleButtonShadowColor = SK_ColorWHITE; } // namespace +#if defined(OS_WIN) || defined(OS_CHROMEOS) +const bool PlatformStyle::kIsOkButtonLeading = true; +#else +const bool PlatformStyle::kIsOkButtonLeading = false; +#endif + #if !defined(OS_MACOSX) const int PlatformStyle::kMinLabelButtonWidth = 70; @@ -48,6 +54,7 @@ const bool PlatformStyle::kReturnClicksFocusedControl = true; const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = false; const bool PlatformStyle::kUseRipples = true; const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = false; +const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = true; // static std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) { diff --git a/chromium/ui/views/style/platform_style.h b/chromium/ui/views/style/platform_style.h index 246293d97c0..d5b7e3bf951 100644 --- a/chromium/ui/views/style/platform_style.h +++ b/chromium/ui/views/style/platform_style.h @@ -24,6 +24,10 @@ class VIEWS_EXPORT PlatformStyle { // Type used by LabelButton to map button states to text colors. using ButtonColorByState = SkColor[Button::STATE_COUNT]; + // Whether the ok button is in the leading position (left in LTR) in a + // typical Cancel/OK button group. + static const bool kIsOkButtonLeading; + // Minimum size for platform-styled buttons (Button::STYLE_BUTTON). static const int kMinLabelButtonWidth; static const int kMinLabelButtonHeight; @@ -58,6 +62,10 @@ class VIEWS_EXPORT PlatformStyle { // focus. static const bool kTextfieldScrollsToStartOnFocusChange; + // Whether text fields should use a "drag" cursor when not actually + // dragging but available to do so. + static const bool kTextfieldUsesDragCursorWhenDraggable; + // Creates the default scrollbar for the given orientation. static std::unique_ptr<ScrollBar> CreateScrollBar(bool is_horizontal); diff --git a/chromium/ui/views/style/platform_style_mac.mm b/chromium/ui/views/style/platform_style_mac.mm index 3a4a52537e6..5d14515be15 100644 --- a/chromium/ui/views/style/platform_style_mac.mm +++ b/chromium/ui/views/style/platform_style_mac.mm @@ -20,6 +20,7 @@ const bool PlatformStyle::kDialogDefaultButtonCanBeCancel = false; const bool PlatformStyle::kSelectWordOnRightClick = true; const bool PlatformStyle::kSelectAllOnRightClickWhenUnfocused = true; const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = true; +const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = false; const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = true; const bool PlatformStyle::kUseRipples = false; diff --git a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc index 75ab64c985b..3b283a149a9 100644 --- a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc +++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc @@ -10,6 +10,8 @@ #include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" @@ -120,7 +122,16 @@ TouchSelectionMenuRunnerViews::Menu::Menu(TouchSelectionMenuRunnerViews* owner, SetAnchorRect(adjusted_anchor_rect); BubbleDialogDelegateView::CreateBubble(this); - GetWidget()->Show(); + Widget* widget = GetWidget(); + gfx::Rect bounds = widget->GetWindowBoundsInScreen(); + gfx::Rect work_area = display::Screen::GetScreen() + ->GetDisplayNearestPoint(bounds.origin()) + .work_area(); + if (!work_area.IsEmpty()) { + bounds.AdjustToFit(work_area); + widget->SetBounds(bounds); + } + widget->Show(); } bool TouchSelectionMenuRunnerViews::Menu::IsMenuAvailable( diff --git a/chromium/ui/views/vector_icons/OWNERS b/chromium/ui/views/vector_icons/OWNERS new file mode 100644 index 00000000000..d7ec991d34a --- /dev/null +++ b/chromium/ui/views/vector_icons/OWNERS @@ -0,0 +1 @@ +file://components/vector_icons/OWNERS diff --git a/chromium/ui/views/vector_icons/vector_icons.cc.template b/chromium/ui/views/vector_icons/vector_icons.cc.template index 9411587ff5b..c0e98199d90 100644 --- a/chromium/ui/views/vector_icons/vector_icons.cc.template +++ b/chromium/ui/views/vector_icons/vector_icons.cc.template @@ -10,11 +10,7 @@ #include "base/logging.h" #include "ui/gfx/vector_icon_types.h" -#define PATH_ELEMENT_TEMPLATE(path_name, ...) \ -static constexpr gfx::PathElement path_name[] = {__VA_ARGS__}; - -#define VECTOR_ICON_TEMPLATE(icon_name, path_name, path_name_1x) \ -const gfx::VectorIcon icon_name = { path_name , path_name_1x }; +#include "components/vector_icons/cc_macros.h" namespace views { diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc index e114a6f37be..8568fae0fc1 100644 --- a/chromium/ui/views/view.cc +++ b/chromium/ui/views/view.cc @@ -21,7 +21,7 @@ #include "build/build_config.h" #include "third_party/skia/include/core/SkRect.h" #include "ui/accessibility/ax_action_data.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/cursor/cursor.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/ime/input_method.h" @@ -96,21 +96,22 @@ const View* GetHierarchyRoot(const View* view) { namespace internal { #if DCHECK_IS_ON() - class ScopedChildrenLock { - public: - explicit ScopedChildrenLock(const View* view) - : reset_(&view->iterating_, true) {} - ~ScopedChildrenLock() {} - private: - base::AutoReset<bool> reset_; - DISALLOW_COPY_AND_ASSIGN(ScopedChildrenLock); - }; +class ScopedChildrenLock { + public: + explicit ScopedChildrenLock(const View* view) + : reset_(&view->iterating_, true) {} + ~ScopedChildrenLock() {} + + private: + base::AutoReset<bool> reset_; + DISALLOW_COPY_AND_ASSIGN(ScopedChildrenLock); +}; #else - class ScopedChildrenLock { - public: - explicit ScopedChildrenLock(const View* view) {} - ~ScopedChildrenLock() {} - }; +class ScopedChildrenLock { + public: + explicit ScopedChildrenLock(const View* view) {} + ~ScopedChildrenLock() {} +}; #endif } // namespace internal @@ -127,7 +128,7 @@ View::View() : owned_by_client_(false), id_(0), group_(-1), - parent_(NULL), + parent_(nullptr), #if DCHECK_IS_ON() iterating_(false), #endif @@ -140,13 +141,13 @@ View::View() snap_layer_to_pixel_boundary_(false), flip_canvas_on_paint_for_rtl_ui_(false), paint_to_layer_(false), - accelerator_focus_manager_(NULL), + accelerator_focus_manager_(nullptr), registered_accelerator_count_(0), - next_focusable_view_(NULL), - previous_focusable_view_(NULL), + next_focusable_view_(nullptr), + previous_focusable_view_(nullptr), focus_behavior_(FocusBehavior::NEVER), - context_menu_controller_(NULL), - drag_controller_(NULL) { + context_menu_controller_(nullptr), + drag_controller_(nullptr) { SetTargetHandler(this); } @@ -157,7 +158,7 @@ View::~View() { { internal::ScopedChildrenLock lock(this); for (auto* child : children_) { - child->parent_ = NULL; + child->parent_ = nullptr; if (!child->owned_by_client_) delete child; } @@ -171,7 +172,7 @@ View::~View() { const Widget* View::GetWidget() const { // The root view holds a reference to this view hierarchy's Widget. - return parent_ ? parent_->GetWidget() : NULL; + return parent_ ? parent_->GetWidget() : nullptr; } Widget* View::GetWidget() { @@ -292,12 +293,13 @@ void View::ReorderChildView(View* view, int index) { } void View::RemoveChildView(View* view) { - DoRemoveChildView(view, true, true, false, NULL); + DoRemoveChildView(view, true, true, false, nullptr); } void View::RemoveAllChildViews(bool delete_children) { while (!children_.empty()) - DoRemoveChildView(children_.front(), false, false, delete_children, NULL); + DoRemoveChildView(children_.front(), false, false, delete_children, + nullptr); UpdateTooltip(); } @@ -383,7 +385,7 @@ gfx::Rect View::GetVisibleBounds() const { const View* view = this; gfx::Transform transform; - while (view != NULL && !vis_bounds.IsEmpty()) { + while (view != nullptr && !vis_bounds.IsEmpty()) { transform.ConcatTransform(view->GetTransform()); gfx::Transform translation; translation.Translate(static_cast<float>(view->GetMirroredX()), @@ -392,7 +394,7 @@ gfx::Rect View::GetVisibleBounds() const { vis_bounds = view->ConvertRectToParent(vis_bounds); const View* ancestor = view->parent_; - if (ancestor != NULL) { + if (ancestor != nullptr) { ancestor_bounds.SetRect(0, 0, ancestor->width(), ancestor->height()); vis_bounds.Intersect(ancestor_bounds); } else if (!view->GetWidget()) { @@ -435,9 +437,9 @@ void View::SetPreferredSize(const gfx::Size& size) { } void View::SizeToPreferredSize() { - gfx::Size prefsize = GetPreferredSize(); - if ((prefsize.width() != width()) || (prefsize.height() != height())) - SetBounds(x(), y(), prefsize.width(), prefsize.height()); + gfx::Size pref_size = GetPreferredSize(); + if ((pref_size.width() != width()) || (pref_size.height() != height())) + SetBounds(x(), y(), pref_size.width(), pref_size.height()); } gfx::Size View::GetMinimumSize() const { @@ -467,7 +469,8 @@ void View::SetVisible(bool visible) { // Notify the parent. if (parent_) { parent_->ChildVisibilityChanged(this); - parent_->NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, false); + parent_->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, + false); } for (ViewObserver& observer : observers_) @@ -646,7 +649,7 @@ const View* View::GetAncestorWithClassName(const std::string& name) const { if (!strcmp(view->GetClassName(), name.c_str())) return view; } - return NULL; + return nullptr; } View* View::GetAncestorWithClassName(const std::string& name) { @@ -664,7 +667,7 @@ const View* View::GetViewByID(int id) const { if (view) return view; } - return NULL; + return nullptr; } View* View::GetViewByID(int id) { @@ -697,7 +700,7 @@ void View::GetViewsInGroup(int group, Views* views) { View* View::GetSelectedViewForGroup(int group) { Views views; GetWidget()->GetRootView()->GetViewsInGroup(group, &views); - return views.empty() ? NULL : views[0]; + return views.empty() ? nullptr : views[0]; } // Coordinate conversion ------------------------------------------------------- @@ -745,7 +748,7 @@ void View::ConvertPointToWidget(const View* src, gfx::Point* p) { DCHECK(src); DCHECK(p); - src->ConvertPointForAncestor(NULL, p); + src->ConvertPointForAncestor(nullptr, p); } // static @@ -753,7 +756,7 @@ void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) { DCHECK(dest); DCHECK(p); - dest->ConvertPointFromAncestor(NULL, p); + dest->ConvertPointFromAncestor(nullptr, p); } // static @@ -898,7 +901,7 @@ void View::Paint(const PaintInfo& parent_paint_info) { } ui::TransformRecorder transform_recorder(context); - SetupTransformRecorderForPainting(paint_info.offset_from_parent(), + SetUpTransformRecorderForPainting(paint_info.offset_from_parent(), &transform_recorder); // Note that the cache is not aware of the offset of the view @@ -979,7 +982,7 @@ bool View::CanProcessEventsWithinSubtree() const { View* View::GetTooltipHandlerForPoint(const gfx::Point& point) { // TODO(tdanderson): Move this implementation into ViewTargetDelegate. if (!HitTestPoint(point) || !CanProcessEventsWithinSubtree()) - return NULL; + return nullptr; // Walk the child Views recursively looking for the View that most // tightly encloses the specified point. @@ -1002,7 +1005,7 @@ gfx::NativeCursor View::GetCursor(const ui::MouseEvent& event) { #if defined(OS_WIN) static ui::Cursor arrow; if (!arrow.platform()) - arrow.SetPlatformCursor(LoadCursor(NULL, IDC_ARROW)); + arrow.SetPlatformCursor(LoadCursor(nullptr, IDC_ARROW)); return arrow; #else return gfx::kNullCursor; @@ -1057,7 +1060,7 @@ void View::OnMouseExited(const ui::MouseEvent& event) { } void View::SetMouseHandler(View* new_mouse_handler) { - // |new_mouse_handler| may be NULL. + // |new_mouse_handler| may be nullptr. if (parent_) parent_->SetMouseHandler(new_mouse_handler); } @@ -1095,7 +1098,7 @@ void View::OnMouseEvent(ui::MouseEvent* event) { OnMouseMoved(*event); return; } - // FALL-THROUGH + FALLTHROUGH; case ui::ET_MOUSE_DRAGGED: if (ProcessMouseDragged(*event)) event->SetHandled(); @@ -1112,7 +1115,7 @@ void View::OnMouseEvent(ui::MouseEvent* event) { case ui::ET_MOUSE_ENTERED: if (event->flags() & ui::EF_TOUCH_ACCESSIBILITY) - NotifyAccessibilityEvent(ui::AX_EVENT_HOVER, true); + NotifyAccessibilityEvent(ax::mojom::Event::kHover, true); OnMouseEntered(*event); break; @@ -1295,12 +1298,12 @@ bool View::IsAccessibilityFocusable() const { FocusManager* View::GetFocusManager() { Widget* widget = GetWidget(); - return widget ? widget->GetFocusManager() : NULL; + return widget ? widget->GetFocusManager() : nullptr; } const FocusManager* View::GetFocusManager() const { const Widget* widget = GetWidget(); - return widget ? widget->GetFocusManager() : NULL; + return widget ? widget->GetFocusManager() : nullptr; } void View::RequestFocus() { @@ -1319,11 +1322,11 @@ bool View::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) { } FocusTraversable* View::GetFocusTraversable() { - return NULL; + return nullptr; } FocusTraversable* View::GetPaneFocusTraversable() { - return NULL; + return nullptr; } // Tooltips -------------------------------------------------------------------- @@ -1408,13 +1411,13 @@ ViewAccessibility& View::GetViewAccessibility() { bool View::HandleAccessibleAction(const ui::AXActionData& action_data) { switch (action_data.action) { - case ui::AX_ACTION_BLUR: + case ax::mojom::Action::kBlur: if (HasFocus()) { GetFocusManager()->ClearFocus(); return true; } break; - case ui::AX_ACTION_DO_DEFAULT: { + case ax::mojom::Action::kDoDefault: { const gfx::Point center = GetLocalBounds().CenterPoint(); OnMousePressed(ui::MouseEvent( ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(), @@ -1424,16 +1427,16 @@ bool View::HandleAccessibleAction(const ui::AXActionData& action_data) { ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); return true; } - case ui::AX_ACTION_FOCUS: + case ax::mojom::Action::kFocus: if (IsAccessibilityFocusable()) { RequestFocus(); return true; } break; - case ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE: + case ax::mojom::Action::kScrollToMakeVisible: ScrollRectToVisible(GetLocalBounds()); return true; - case ui::AX_ACTION_SHOW_CONTEXT_MENU: + case ax::mojom::Action::kShowContextMenu: ShowContextMenu(GetBoundsInScreen().CenterPoint(), ui::MENU_SOURCE_KEYBOARD); return true; @@ -1449,9 +1452,8 @@ gfx::NativeViewAccessible View::GetNativeViewAccessible() { return GetViewAccessibility().GetNativeObject(); } -void View::NotifyAccessibilityEvent( - ui::AXEvent event_type, - bool send_native_event) { +void View::NotifyAccessibilityEvent(ax::mojom::Event event_type, + bool send_native_event) { if (ViewsDelegate::GetInstance()) ViewsDelegate::GetInstance()->NotifyAccessibilityEvent(this, event_type); @@ -1461,7 +1463,7 @@ void View::NotifyAccessibilityEvent( OnAccessibilityEvent(event_type); } -void View::OnAccessibilityEvent(ui::AXEvent event_type) {} +void View::OnAccessibilityEvent(ax::mojom::Event event_type) {} // Scrolling ------------------------------------------------------------------- @@ -1602,7 +1604,7 @@ void View::UpdateParentLayer() { if (!layer()) return; - ui::Layer* parent_layer = NULL; + ui::Layer* parent_layer = nullptr; gfx::Vector2d offset(GetMirroredX(), y()); if (parent_) { @@ -1668,7 +1670,7 @@ void View::DestroyLayerImpl(LayerChangeNotifyBehavior notify_parents) { if (new_parent) ReorderLayers(); - UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(NULL)); + UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(nullptr)); SchedulePaint(); @@ -1747,7 +1749,7 @@ void View::ReorderLayers() { if (widget) { // Reorder the widget's child NativeViews in case a child NativeView is - // associated with a view (eg via a NativeViewHost). Always do the + // associated with a view (e.g. via a NativeViewHost). Always do the // reordering because the associated NativeView's layer (if it has one) // is parented to the widget's layer regardless of whether the host view has // an ancestor with a layer. @@ -1775,7 +1777,7 @@ void View::OnChildLayerChanged(View* child) {} // Input ----------------------------------------------------------------------- View::DragInfo* View::GetDragInfo() { - return parent_ ? parent_->GetDragInfo() : NULL; + return parent_ ? parent_->GetDragInfo() : nullptr; } // Focus ----------------------------------------------------------------------- @@ -1792,7 +1794,7 @@ void View::OnFocus() { // TODO(beng): Investigate whether it's possible for us to move this to // Focus(). // Notify assistive technologies of the focus change. - NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); + NotifyAccessibilityEvent(ax::mojom::Event::kFocus, true); } void View::OnBlur() { @@ -2002,7 +2004,7 @@ bool View::ShouldPaint() const { return visible_ && !size().IsEmpty(); } -void View::SetupTransformRecorderForPainting( +void View::SetUpTransformRecorderForPainting( const gfx::Vector2d& offset_from_parent, ui::TransformRecorder* recorder) const { // If the view is backed by a layer, it should paint with itself as the origin @@ -2051,7 +2053,7 @@ void View::PaintDebugRects(const PaintInfo& parent_paint_info) { const ui::PaintContext& context = paint_info.context(); ui::TransformRecorder transform_recorder(context); - SetupTransformRecorderForPainting(paint_info.offset_from_parent(), + SetUpTransformRecorderForPainting(paint_info.offset_from_parent(), &transform_recorder); RecursivePaintHelper(&View::PaintDebugRects, paint_info); @@ -2276,12 +2278,12 @@ void View::BoundsChanged(const gfx::Rect& previous_bounds) { } else { // If our bounds have changed, then any descendant layer bounds may have // changed. Update them accordingly. - UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(NULL)); + UpdateChildLayerBounds(CalculateOffsetToAncestorWithLayer(nullptr)); } OnBoundsChanged(previous_bounds); if (bounds_ != previous_bounds) - NotifyAccessibilityEvent(ui::AX_EVENT_LOCATION_CHANGED, false); + NotifyAccessibilityEvent(ax::mojom::Event::kLocationChanged, false); if (needs_layout_ || previous_bounds.size() != size()) { needs_layout_ = false; @@ -2356,7 +2358,7 @@ void View::SetLayoutManagerImpl(std::unique_ptr<LayoutManager> layout_manager) { // Some code keeps a bare pointer to the layout manager for calling // derived-class-specific-functions. It's an easy mistake to create a new // unique_ptr and re-set the layout manager with a new unique_ptr, which - // will cause a crash. Re-setting to null is OK. + // will cause a crash. Re-setting to nullptr is OK. CHECK(!layout_manager.get() || layout_manager_.get() != layout_manager.get()); layout_manager_ = std::move(layout_manager); @@ -2562,7 +2564,7 @@ bool View::ProcessMouseDragged(const ui::MouseEvent& event) { // Fall through to return value based on context menu controller. } // WARNING: we may have been deleted. - return (context_menu_controller != NULL) || possible_drag; + return (context_menu_controller != nullptr) || possible_drag; } void View::ProcessMouseReleased(const ui::MouseEvent& event) { @@ -2620,7 +2622,7 @@ void View::UnregisterAccelerators(bool leave_data_intact) { if (GetWidget()) { if (accelerator_focus_manager_) { accelerator_focus_manager_->UnregisterAccelerators(this); - accelerator_focus_manager_ = NULL; + accelerator_focus_manager_ = nullptr; } if (!leave_data_intact) { accelerators_->clear(); @@ -2636,14 +2638,14 @@ void View::InitFocusSiblings(View* v, int index) { int count = child_count(); if (count == 0) { - v->next_focusable_view_ = NULL; - v->previous_focusable_view_ = NULL; + v->next_focusable_view_ = nullptr; + v->previous_focusable_view_ = nullptr; } else { if (index == count) { // We are inserting at the end, but the end of the child list may not be // the last focusable element. Let's try to find an element with no next // focusable element to link to. - View* last_focusable_view = NULL; + View* last_focusable_view = nullptr; { internal::ScopedChildrenLock lock(this); for (auto* child : children_) { @@ -2653,7 +2655,7 @@ void View::InitFocusSiblings(View* v, int index) { } } } - if (last_focusable_view == NULL) { + if (last_focusable_view == nullptr) { // Hum... there is a cycle in the focus list. Let's just insert ourself // after the last child. View* prev = children_[index - 1]; @@ -2663,7 +2665,7 @@ void View::InitFocusSiblings(View* v, int index) { prev->next_focusable_view_ = v; } else { last_focusable_view->next_focusable_view_ = v; - v->next_focusable_view_ = NULL; + v->next_focusable_view_ = nullptr; v->previous_focusable_view_ = last_focusable_view; } } else { @@ -2680,7 +2682,7 @@ void View::InitFocusSiblings(View* v, int index) { void View::AdvanceFocusIfNecessary() { // Focus should only be advanced if this is the focused view and has become // unfocusable. If the view is still focusable or is not focused, we can - // return early avoiding furthur unnecessary checks. Focusability check is + // return early avoiding further unnecessary checks. Focusability check is // performed first as it tends to be faster. if (IsAccessibilityFocusable() || !HasFocus()) return; @@ -2722,7 +2724,7 @@ void View::PropagateDeviceScaleFactorChanged(float old_device_scale_factor, void View::UpdateTooltip() { Widget* widget = GetWidget(); - // TODO(beng): The TooltipManager NULL check can be removed when we + // TODO(beng): The TooltipManager nullptr check can be removed when we // consolidate Init() methods and make views_unittests Init() all // Widgets that it uses. if (widget && widget->GetTooltipManager()) diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h index f3075731dd6..8b874876b89 100644 --- a/chromium/ui/views/view.h +++ b/chromium/ui/views/view.h @@ -12,6 +12,7 @@ #include <memory> #include <set> #include <string> +#include <utility> #include <vector> #include "base/compiler_specific.h" @@ -19,7 +20,7 @@ #include "base/logging.h" #include "base/macros.h" #include "build/build_config.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/class_property.h" #include "ui/base/dragdrop/drag_drop_types.h" @@ -52,7 +53,7 @@ class Canvas; class Insets; class Path; class Transform; -} +} // namespace gfx namespace ui { struct AXActionData; @@ -64,7 +65,7 @@ class NativeTheme; class PaintContext; class ThemeProvider; class TransformRecorder; -} +} // namespace ui namespace views { @@ -86,7 +87,7 @@ class PreEventDispatchHandler; class PostEventDispatchHandler; class RootView; class ScopedChildrenLock; -} +} // namespace internal ///////////////////////////////////////////////////////////////////////////// // @@ -263,6 +264,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // By default a View is owned by its parent unless specified otherwise here. void set_owned_by_client() { owned_by_client_ = true; } + bool owned_by_client() const { return owned_by_client_; } // Tree operations ----------------------------------------------------------- @@ -318,7 +320,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // position accessors. // Transformations are not applied on the size/position. For example, if // bounds is (0, 0, 100, 100) and it is scaled by 0.5 along the X axis, the - // width will still be 100 (although when painted, it will be 50x50, painted + // width will still be 100 (although when painted, it will be 50x100, painted // at location (0, 0)). void SetBounds(int x, int y, int width, int height); @@ -539,7 +541,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Return the receiving view's class name. A view class is a string which // uniquely identifies the view class. It is intended to be used as a way to - // find out during run time if a view can be safely casted to a specific view + // find out during run time if a view can be safely cast to a specific view // subclass. The default implementation returns kViewClassName. virtual const char* GetClassName() const; @@ -750,7 +752,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // The provided event is in the receiver's coordinate system. // // Return true if you processed the event and want to receive subsequent - // MouseDraggged and MouseReleased events. This also stops the event from + // MouseDragged and MouseReleased events. This also stops the event from // bubbling. If you return false, the event will bubble through parent // views. // @@ -825,7 +827,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, virtual void SetMouseHandler(View* new_mouse_handler); // Invoked when a key is pressed or released. - // Subclasser should return true if the event has been processed and false + // Subclasses should return true if the event has been processed and false // otherwise. If the event has not been processed, the parent will be given a // chance. virtual bool OnKeyPressed(const ui::KeyEvent& event); @@ -1004,7 +1006,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // Provides default implementation for context menu handling. The default // implementation calls the ShowContextMenu of the current // ContextMenuController (if it is not NULL). Overridden in subclassed views - // to provide right-click menu display triggerd by the keyboard (i.e. for the + // to provide right-click menu display triggered by the keyboard (i.e. for the // Chrome toolbar Back and Forward buttons). No source needs to be specified, // as it is always equal to the current View. virtual void ShowContextMenu(const gfx::Point& p, @@ -1115,12 +1117,12 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // cases where the view is a native control that's already sending a // native accessibility event and the duplicate event would cause // problems. - void NotifyAccessibilityEvent(ui::AXEvent event_type, + void NotifyAccessibilityEvent(ax::mojom::Event event_type, bool send_native_event); // Views may override this function to know when an accessibility // event is fired. This will be called by NotifyAccessibilityEvent. - virtual void OnAccessibilityEvent(ui::AXEvent event_type); + virtual void OnAccessibilityEvent(ax::mojom::Event event_type); // Scrolling ----------------------------------------------------------------- // TODO(beng): Figure out if this can live somewhere other than View, i.e. @@ -1138,7 +1140,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, // The following methods are used by ScrollView to determine the amount // to scroll relative to the visible bounds of the view. For example, a - // return value of 10 indicates the scrollview should scroll 10 pixels in + // return value of 10 indicates the scroll_view should scroll 10 pixels in // the appropriate direction. // // Each method takes the following parameters: @@ -1442,7 +1444,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, bool ShouldPaint() const; // Adjusts the transform of |recorder| in advance of painting. - void SetupTransformRecorderForPainting( + void SetUpTransformRecorderForPainting( const gfx::Vector2d& offset_from_parent, ui::TransformRecorder* recorder) const; diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc index 38a0c05b4cf..82631bbd6ce 100644 --- a/chromium/ui/views/view_unittest.cc +++ b/chromium/ui/views/view_unittest.cc @@ -12,7 +12,6 @@ #include "base/command_line.h" #include "base/i18n/rtl.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/rand_util.h" #include "base/run_loop.h" #include "base/strings/string_util.h" @@ -262,7 +261,7 @@ class TestView : public View { void OnNativeThemeChanged(const ui::NativeTheme* native_theme) override; - void OnAccessibilityEvent(ui::AXEvent event_type) override; + void OnAccessibilityEvent(ax::mojom::Event event_type) override; // OnBoundsChanged. bool did_change_bounds_; @@ -292,7 +291,7 @@ class TestView : public View { bool can_process_events_within_subtree_; // Accessibility events - ui::AXEvent last_a11y_event_; + ax::mojom::Event last_a11y_event_; }; //////////////////////////////////////////////////////////////////////////////// @@ -328,7 +327,7 @@ TEST_F(ViewTest, LayoutCalledInvalidateAndOriginChanges) { // OnBoundsChanged //////////////////////////////////////////////////////////////////////////////// -void TestView::OnAccessibilityEvent(ui::AXEvent event_type) { +void TestView::OnAccessibilityEvent(ax::mojom::Event event_type) { last_a11y_event_ = event_type; } @@ -340,17 +339,17 @@ TEST_F(ViewTest, OnBoundsChangedFiresA11yEvent) { gfx::Rect scaled(0, 0, 250, 250); gfx::Rect moved(100, 100, 250, 250); - v.last_a11y_event_ = ui::AX_EVENT_NONE; + v.last_a11y_event_ = ax::mojom::Event::kNone; v.SetBoundsRect(initial); - EXPECT_EQ(v.last_a11y_event_, ui::AX_EVENT_LOCATION_CHANGED); + EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged); - v.last_a11y_event_ = ui::AX_EVENT_NONE; + v.last_a11y_event_ = ax::mojom::Event::kNone; v.SetBoundsRect(scaled); - EXPECT_EQ(v.last_a11y_event_, ui::AX_EVENT_LOCATION_CHANGED); + EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged); - v.last_a11y_event_ = ui::AX_EVENT_NONE; + v.last_a11y_event_ = ax::mojom::Event::kNone; v.SetBoundsRect(moved); - EXPECT_EQ(v.last_a11y_event_, ui::AX_EVENT_LOCATION_CHANGED); + EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged); } void TestView::OnBoundsChanged(const gfx::Rect& previous_bounds) { @@ -4516,7 +4515,7 @@ class PaintLayerView : public View { PaintLayerView() = default; void PaintChildren(const PaintInfo& info) override { - last_paint_info_ = base::MakeUnique<PaintInfo>(info); + last_paint_info_ = std::make_unique<PaintInfo>(info); View::PaintChildren(info); } diff --git a/chromium/ui/views/views_delegate.cc b/chromium/ui/views/views_delegate.cc index 1f7068795ff..964f1390be0 100644 --- a/chromium/ui/views/views_delegate.cc +++ b/chromium/ui/views/views_delegate.cc @@ -61,8 +61,7 @@ bool ViewsDelegate::GetSavedWindowPlacement( } void ViewsDelegate::NotifyAccessibilityEvent(View* view, - ui::AXEvent event_type) { -} + ax::mojom::Event event_type) {} void ViewsDelegate::NotifyMenuItemFocused(const base::string16& menu_name, const base::string16& menu_item_name, diff --git a/chromium/ui/views/views_delegate.h b/chromium/ui/views/views_delegate.h index aed6c6eeff0..cfaf7b0dd8a 100644 --- a/chromium/ui/views/views_delegate.h +++ b/chromium/ui/views/views_delegate.h @@ -17,7 +17,7 @@ #include "base/macros.h" #include "base/strings/string16.h" #include "build/build_config.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/ui_base_types.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/views_export.h" @@ -135,7 +135,8 @@ class VIEWS_EXPORT ViewsDelegate { gfx::Rect* bounds, ui::WindowShowState* show_state) const; - virtual void NotifyAccessibilityEvent(View* view, ui::AXEvent event_type); + virtual void NotifyAccessibilityEvent(View* view, + ax::mojom::Event event_type); // For accessibility, notify the delegate that a menu item was focused // so that alternate feedback (speech / magnified text) can be provided. diff --git a/chromium/ui/views/views_perftests.cc b/chromium/ui/views/views_perftests.cc index c7ace58ab5c..65a61183415 100644 --- a/chromium/ui/views/views_perftests.cc +++ b/chromium/ui/views/views_perftests.cc @@ -3,10 +3,12 @@ // found in the LICENSE file. #include "base/test/launcher/unit_test_launcher.h" +#include "mojo/edk/embedder/embedder.h" #include "ui/views/views_test_suite.h" int main(int argc, char** argv) { views::ViewsTestSuite test_suite(argc, argv); + mojo::edk::Init(); return base::LaunchUnitTestsSerially( argc, argv, base::Bind(&views::ViewsTestSuite::Run, base::Unretained(&test_suite))); diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index da27f6dd704..cde45a41be5 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -362,7 +362,7 @@ void DesktopNativeWidgetAura::HandleActivationChanged(bool active) { View* view_for_activation = focus_manager->GetFocusedView() ? focus_manager->GetFocusedView() : focus_manager->GetStoredFocusView(); - if (!view_for_activation) { + if (!view_for_activation || !view_for_activation->GetWidget()) { view_for_activation = GetWidget()->GetRootView(); } else if (view_for_activation == focus_manager->GetStoredFocusView()) { // When desktop native widget has modal transient child, we don't @@ -413,7 +413,7 @@ void DesktopNativeWidgetAura::InitNativeWidget( NativeWidgetAura::RegisterNativeWidgetForWindow(this, content_window_); content_window_->SetType(GetAuraWindowTypeForWidgetType(params.type)); content_window_->Init(params.layer_type); - wm::SetShadowElevation(content_window_, wm::ShadowElevation::NONE); + wm::SetShadowElevation(content_window_, wm::kShadowElevationNone); if (!desktop_window_tree_host_) { if (params.desktop_window_tree_host) { diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index 1bf5a5e2ca5..19f103c0385 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc @@ -4,6 +4,7 @@ #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" +#include "base/containers/flat_set.h" #include "base/memory/ptr_util.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRegion.h" @@ -18,6 +19,7 @@ #include "ui/compositor/paint_context.h" #include "ui/display/win/dpi.h" #include "ui/display/win/screen_win.h" +#include "ui/events/keyboard_hook.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/native_widget_types.h" @@ -558,6 +560,23 @@ void DesktopWindowTreeHostWin::ReleaseCapture() { message_handler_->ReleaseCapture(); } +bool DesktopWindowTreeHostWin::CaptureSystemKeyEventsImpl( + base::Optional<base::flat_set<int>> key_codes) { + // Only one KeyboardHook should be active at a time, otherwise there will be + // problems with event routing (i.e. which Hook takes precedence) and + // destruction ordering. + DCHECK(!keyboard_hook_); + keyboard_hook_ = ui::KeyboardHook::Create( + std::move(key_codes), + base::BindRepeating(&DesktopWindowTreeHostWin::HandleKeyEvent, + base::Unretained(this))); + return keyboard_hook_ != nullptr; +} + +void DesktopWindowTreeHostWin::ReleaseSystemKeyEventCapture() { + keyboard_hook_.reset(); +} + void DesktopWindowTreeHostWin::SetCursorNative(gfx::NativeCursor cursor) { ui::CursorLoaderWin cursor_loader; cursor_loader.SetPlatformCursor(&cursor); @@ -718,10 +737,6 @@ gfx::NativeViewAccessible DesktopWindowTreeHostWin::GetNativeViewAccessible() { : nullptr; } -bool DesktopWindowTreeHostWin::ShouldHandleSystemCommands() const { - return GetWidget()->widget_delegate()->ShouldHandleSystemCommands(); -} - void DesktopWindowTreeHostWin::HandleAppDeactivated() { native_widget_delegate_->SetAlwaysRenderAsActive(false); } diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h index db66147f0e9..732f492c102 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h @@ -5,6 +5,9 @@ #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_WIN_H_ #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_WIN_H_ +#include <memory> +#include <string> + #include "base/macros.h" #include "ui/aura/window_tree_host.h" #include "ui/views/views_export.h" @@ -21,6 +24,7 @@ class FocusClient; namespace ui { class InputMethod; +class KeyboardHook; } // namespace ui namespace wm { @@ -127,6 +131,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin gfx::Point GetLocationOnScreenInPixels() const override; void SetCapture() override; void ReleaseCapture() override; + bool CaptureSystemKeyEventsImpl( + base::Optional<base::flat_set<int>> keys_codes) override; + void ReleaseSystemKeyEventCapture() override; void SetCursorNative(gfx::NativeCursor cursor) override; void OnCursorVisibilityChangedNative(bool show) override; void MoveCursorToScreenLocationInPixels( @@ -163,7 +170,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin gfx::Size DIPToScreenSize(const gfx::Size& dip_size) const override; void ResetWindowControls() override; gfx::NativeViewAccessible GetNativeViewAccessible() override; - bool ShouldHandleSystemCommands() const override; void HandleAppDeactivated() override; void HandleActivationChanged(bool active) override; bool HandleAppCommand(short command) override; @@ -281,6 +287,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin // whenever the cursor visibility state changes. static bool is_cursor_visible_; + // Captures system key events when keyboard lock is requested. + std::unique_ptr<ui::KeyboardHook> keyboard_hook_; + std::unique_ptr<wm::ScopedTooltipDisabler> tooltip_disabler_; // Indicates if current window will receive mouse events when should not diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc index deaf9cbc13c..f8550833ee6 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc @@ -7,6 +7,7 @@ #include <utility> #include "base/command_line.h" +#include "base/containers/flat_set.h" #include "base/location.h" #include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" @@ -35,6 +36,7 @@ #include "ui/events/devices/x11/device_list_cache_x11.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/event_utils.h" +#include "ui/events/keyboard_hook.h" #include "ui/events/null_event_targeter.h" #include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/x11/x11_event_source.h" @@ -337,6 +339,7 @@ void DesktopWindowTreeHostX11::OnFocusEvent(bool focus_in, // (FocusOut with NotifyNonlinearVirtual) // |has_pointer_focus_| should be false before and after this event. has_pointer_focus_ = false; + break; default: break; } @@ -1290,6 +1293,23 @@ void DesktopWindowTreeHostX11::ReleaseCapture() { } } +bool DesktopWindowTreeHostX11::CaptureSystemKeyEventsImpl( + base::Optional<base::flat_set<int>> key_codes) { + // Only one KeyboardHook should be active at a time, otherwise there will be + // problems with event routing (i.e. which Hook takes precedence) and + // destruction ordering. + DCHECK(!keyboard_hook_); + keyboard_hook_ = ui::KeyboardHook::Create( + std::move(key_codes), + base::BindRepeating(&DesktopWindowTreeHostX11::DispatchKeyEvent, + base::Unretained(this))); + return keyboard_hook_ != nullptr; +} + +void DesktopWindowTreeHostX11::ReleaseSystemKeyEventCapture() { + keyboard_hook_.reset(); +} + void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) { XDefineCursor(xdisplay_, xwindow_, cursor.platform()); } @@ -1758,7 +1778,11 @@ void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) { } else { // Another DesktopWindowTreeHostX11 has installed itself as // capture. Translate the event's location and dispatch to the other. - ConvertEventToDifferentHost(event, g_current_capture); + DCHECK_EQ(ui::GetScaleFactorForNativeView(window()), + ui::GetScaleFactorForNativeView(g_current_capture->window())); + ConvertEventLocationToTargetWindowLocation( + g_current_capture->GetLocationOnScreenInPixels(), + GetLocationOnScreenInPixels(), event->AsLocatedEvent()); g_current_capture->SendEventToSink(event); } } @@ -1766,7 +1790,11 @@ void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) { void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) { if (g_current_capture && g_current_capture != this && event->type() == ui::ET_TOUCH_PRESSED) { - ConvertEventToDifferentHost(event, g_current_capture); + DCHECK_EQ(ui::GetScaleFactorForNativeView(window()), + ui::GetScaleFactorForNativeView(g_current_capture->window())); + ConvertEventLocationToTargetWindowLocation( + g_current_capture->GetLocationOnScreenInPixels(), + GetLocationOnScreenInPixels(), event->AsLocatedEvent()); g_current_capture->SendEventToSink(event); } else { SendEventToSink(event); @@ -1778,20 +1806,6 @@ void DesktopWindowTreeHostX11::DispatchKeyEvent(ui::KeyEvent* event) { SendEventToSink(event); } -void DesktopWindowTreeHostX11::ConvertEventToDifferentHost( - ui::LocatedEvent* located_event, - DesktopWindowTreeHostX11* host) { - DCHECK_NE(this, host); - DCHECK_EQ(ui::GetScaleFactorForNativeView(window()), - ui::GetScaleFactorForNativeView(host->window())); - gfx::Vector2d offset = - GetLocationOnScreenInPixels() - host->GetLocationOnScreenInPixels(); - gfx::PointF location_in_pixel_in_host = - located_event->location_f() + gfx::Vector2dF(offset); - located_event->set_location_f(location_in_pixel_in_host); - located_event->set_root_location_f(location_in_pixel_in_host); -} - void DesktopWindowTreeHostX11::ResetWindowRegion() { // If a custom window shape was supplied then apply it. if (custom_window_shape_) { @@ -2006,9 +2020,9 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( } break; } - case FocusIn: - case FocusOut: - OnFocusEvent(xev->type == FocusIn, event->xfocus.mode, + case x11::FocusIn: + case x11::FocusOut: + OnFocusEvent(xev->type == x11::FocusIn, event->xfocus.mode, event->xfocus.detail); break; case ConfigureNotify: { @@ -2071,7 +2085,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); if (num_coalesced > 0) xev = &last_event; - // fallthrough + FALLTHROUGH; case ui::ET_TOUCH_PRESSED: case ui::ET_TOUCH_RELEASED: { ui::TouchEvent touchev(xev); @@ -2092,7 +2106,15 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( xev = &last_event; } ui::MouseEvent mouseev(xev); - DispatchMouseEvent(&mouseev); + // If after CoalescePendingMotionEvents the type of xev is resolved to + // UNKNOWN, don't dispatch the event. + // TODO(804418): investigate why ColescePendingMotionEvents can + // include mouse wheel events as well. Investigation showed that + // events on Linux are checked with cmt-device path, and can include + // DT_CMT_SCROLL_ data. See more discussion in + // https://crrev.com/c/853953 + if (mouseev.type() != ui::ET_UNKNOWN) + DispatchMouseEvent(&mouseev); break; } case ui::ET_MOUSEWHEEL: { diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h index 674951e1c90..021a1d9ad2b 100644 --- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h +++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h @@ -31,6 +31,7 @@ class ImageSkiaRep; namespace ui { class EventHandler; +class KeyboardHook; class XScopedEventSelector; } @@ -163,6 +164,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 gfx::Point GetLocationOnScreenInPixels() const override; void SetCapture() override; void ReleaseCapture() override; + bool CaptureSystemKeyEventsImpl( + base::Optional<base::flat_set<int>> keys_codes) override; + void ReleaseSystemKeyEventCapture() override; void SetCursorNative(gfx::NativeCursor cursor) override; void MoveCursorToScreenLocationInPixels( const gfx::Point& location_in_pixels) override; @@ -242,11 +246,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 // Dispatches a key event. void DispatchKeyEvent(ui::KeyEvent* event); - // Updates the location of |located_event| to be in |host|'s coordinate system - // so that it can be dispatched to |host|. - void ConvertEventToDifferentHost(ui::LocatedEvent* located_event, - DesktopWindowTreeHostX11* host); - // Resets the window region for the current widget bounds if necessary. void ResetWindowRegion(); @@ -423,6 +422,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11 bool had_pointer_grab_; bool had_window_focus_; + // Captures system key events when keyboard lock is requested. + std::unique_ptr<ui::KeyboardHook> keyboard_hook_; + base::CancelableCallback<void()> delayed_resize_task_; std::unique_ptr<aura::ScopedWindowTargeter> targeter_for_modal_; diff --git a/chromium/ui/views/widget/desktop_aura/window_event_filter.cc b/chromium/ui/views/widget/desktop_aura/window_event_filter.cc index 05ab5af4eaf..2d3170ca5cd 100644 --- a/chromium/ui/views/widget/desktop_aura/window_event_filter.cc +++ b/chromium/ui/views/widget/desktop_aura/window_event_filter.cc @@ -89,28 +89,31 @@ void WindowEventFilter::OnClickedCaption(ui::MouseEvent* event, break; case LinuxUI::WINDOW_FRAME_ACTION_LOWER: LowerWindow(); + event->SetHandled(); break; case LinuxUI::WINDOW_FRAME_ACTION_MINIMIZE: window_tree_host_->Minimize(); + event->SetHandled(); break; case LinuxUI::WINDOW_FRAME_ACTION_TOGGLE_MAXIMIZE: if (target->GetProperty(aura::client::kResizeBehaviorKey) & ui::mojom::kResizeBehaviorCanMaximize) ToggleMaximizedState(); + event->SetHandled(); break; case LinuxUI::WINDOW_FRAME_ACTION_MENU: views::Widget* widget = views::Widget::GetWidgetForNativeView(target); if (!widget) break; views::View* view = widget->GetContentsView(); - if (!view) + if (!view || !view->context_menu_controller()) break; gfx::Point location(event->location()); views::View::ConvertPointToScreen(view, &location); view->ShowContextMenu(location, ui::MENU_SOURCE_MOUSE); + event->SetHandled(); break; } - event->SetHandled(); } void WindowEventFilter::OnClickedMaximizeButton(ui::MouseEvent* event) { diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc index 8797bf889fb..a9be3abbd01 100644 --- a/chromium/ui/views/widget/native_widget_aura.cc +++ b/chromium/ui/views/widget/native_widget_aura.cc @@ -57,7 +57,7 @@ #if defined(OS_WIN) #include "base/win/scoped_gdi_object.h" -#include "base/win/win_util.h" +#include "base/win/win_client_metrics.h" #include "ui/base/l10n/l10n_util_win.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" #endif @@ -136,10 +136,10 @@ void NativeWidgetAura::SetShadowElevationFromInitParams( aura::Window* window, const Widget::InitParams& params) { if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_NONE) { - SetShadowElevation(window, wm::ShadowElevation::NONE); + wm::SetShadowElevation(window, wm::kShadowElevationNone); } else if (params.shadow_type == Widget::InitParams::SHADOW_TYPE_DROP && params.shadow_elevation) { - SetShadowElevation(window, *params.shadow_elevation); + wm::SetShadowElevation(window, *params.shadow_elevation); } } @@ -157,15 +157,23 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { // MusClient has assertions that ui::mojom::WindowType matches // views::Widget::InitParams::Type. aura::SetWindowType(window_, static_cast<ui::mojom::WindowType>(params.type)); + if (params.corner_radius) { + window_->SetProperty(aura::client::kWindowCornerRadiusKey, + *params.corner_radius); + } window_->SetProperty(aura::client::kShowStateKey, params.show_state); if (params.type == Widget::InitParams::TYPE_BUBBLE) wm::SetHideOnDeactivate(window_, true); window_->SetTransparent( params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW); + + // Check for SHADOW_TYPE_NONE before aura::Window::Init() to ensure observers + // do not add useless shadow layers by deriving one from the window type. + SetShadowElevationFromInitParams(window_, params); + window_->Init(params.layer_type); // Set name after layer init so it propagates to layer. window_->SetName(params.name); - SetShadowElevationFromInitParams(window_, params); if (params.type == Widget::InitParams::TYPE_CONTROL) window_->Show(); diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm index 28040b162fa..f5db821551e 100644 --- a/chromium/ui/views/widget/native_widget_mac.mm +++ b/chromium/ui/views/widget/native_widget_mac.mm @@ -13,6 +13,7 @@ #include "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" +#include "components/crash/core/common/crash_key.h" #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" #import "ui/base/cocoa/window_size_constants.h" #include "ui/gfx/font_list.h" @@ -635,11 +636,25 @@ NativeWidgetMacNSWindow* NativeWidgetMac::CreateNSWindow( // static void Widget::CloseAllSecondaryWidgets() { - // Create a copy of [NSApp windows] to increase every window's retain count. - // -[NSWindow dealloc] won't be invoked on any windows until this array goes - // out of scope. - base::scoped_nsobject<NSArray> starting_windows([[NSApp windows] copy]); - for (NSWindow* window in starting_windows.get()) { + NSArray* starting_windows = [NSApp windows]; // Creates an autoreleased copy. + for (NSWindow* window in starting_windows) { + // Ignore any windows that couldn't have been created by NativeWidgetMac or + // a subclass. GetNativeWidgetForNativeWindow() will later interrogate the + // NSWindow delegate, but we can't trust that delegate to be a valid object. + if (![window isKindOfClass:[NativeWidgetMacNSWindow class]]) + continue; + + // Record a crash key to detect when client code may destroy a + // WidgetObserver without removing it (possibly leaking the Widget). + // A crash can occur in generic Widget teardown paths when trying to notify. + // See http://crbug.com/808318. + static crash_reporter::CrashKeyString<256> window_info_key("windowInfo"); + std::string value = base::SysNSStringToUTF8( + [NSString stringWithFormat:@"Closing %@ (%@)", [window title], + [window className]]); + crash_reporter::ScopedCrashKeyString scopedWindowKey(&window_info_key, + value); + Widget* widget = GetWidgetForNativeWindow(window); if (widget && widget->is_secondary_widget()) [window close]; diff --git a/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm b/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm index 23ab9fb0eb2..a6baee39626 100644 --- a/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm +++ b/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm @@ -12,7 +12,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #import "testing/gtest_mac.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #import "ui/accessibility/platform/ax_platform_node_mac.h" #include "ui/base/ime/text_input_type.h" @@ -36,8 +36,8 @@ NSString* const kTestTitle = @"Test textfield"; class FlexibleRoleTestView : public View { public: - explicit FlexibleRoleTestView(ui::AXRole role) : role_(role) {} - void set_role(ui::AXRole role) { role_ = role; } + explicit FlexibleRoleTestView(ax::mojom::Role role) : role_(role) {} + void set_role(ax::mojom::Role role) { role_ = role; } // Add a child view and resize to fit the child. void FitBoundsToNewChild(View* view) { @@ -60,7 +60,7 @@ class FlexibleRoleTestView : public View { } private: - ui::AXRole role_; + ax::mojom::Role role_; bool mouse_was_pressed_ = false; DISALLOW_COPY_AND_ASSIGN(FlexibleRoleTestView); @@ -133,7 +133,7 @@ class NativeWidgetMacAccessibilityTest : public test::WidgetTest { } // Shorthand helpers to get a11y properties from A11yElementAtMidpoint(). - NSString* AXRole() { + NSString* AXRoleString() { return AttributeValueAtMidpoint(NSAccessibilityRoleAttribute); } id AXParent() { @@ -292,7 +292,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, FocusableElementsAreLeafNodes) { TestLabelButton* button = new TestLabelButton(); button->SetSize(widget()->GetContentsView()->size()); widget()->GetContentsView()->AddChildView(button); - EXPECT_NSEQ(NSAccessibilityButtonRole, AXRole()); + EXPECT_NSEQ(NSAccessibilityButtonRole, AXRoleString()); EXPECT_EQ( 0u, [[button->GetNativeViewAccessible() @@ -339,7 +339,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, ChildrenAttribute) { // Check ignored children don't show up in the accessibility tree. widget()->GetContentsView()->AddChildView( - new FlexibleRoleTestView(ui::AX_ROLE_IGNORED)); + new FlexibleRoleTestView(ax::mojom::Role::kIgnored)); EXPECT_EQ(kNumChildren, [AttributeValueAtMidpoint(NSAccessibilityChildrenAttribute) count]); } @@ -356,7 +356,8 @@ TEST_F(NativeWidgetMacAccessibilityTest, ParentAttribute) { // Views with non-Widget parents will have the role of the parent view. widget()->GetContentsView()->RemoveChildView(child); - FlexibleRoleTestView* parent = new FlexibleRoleTestView(ui::AX_ROLE_GROUP); + FlexibleRoleTestView* parent = + new FlexibleRoleTestView(ax::mojom::Role::kGroup); parent->FitBoundsToNewChild(child); widget()->GetContentsView()->AddChildView(parent); EXPECT_NSEQ( @@ -364,7 +365,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, ParentAttribute) { [AXParent() accessibilityAttributeValue:NSAccessibilityRoleAttribute]); // Test an ignored role parent is skipped in favor of the grandparent. - parent->set_role(ui::AX_ROLE_IGNORED); + parent->set_role(ax::mojom::Role::kIgnored); EXPECT_NSEQ( NSAccessibilityWindowRole, [AXParent() accessibilityAttributeValue:NSAccessibilityRoleAttribute]); @@ -390,7 +391,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, PositionAttribute) { // Test for NSAccessibilityHelpAttribute. TEST_F(NativeWidgetMacAccessibilityTest, HelpAttribute) { - Label* label = new Label(base::SysNSStringToUTF16(kTestPlaceholderText)); + Label* label = new Label(base::SysNSStringToUTF16(kTestStringValue)); label->SetSize(GetWidgetBounds().size()); EXPECT_NSEQ(@"", AttributeValueAtMidpoint(NSAccessibilityHelpAttribute)); label->SetTooltipText(base::SysNSStringToUTF16(kTestPlaceholderText)); @@ -402,11 +403,12 @@ TEST_F(NativeWidgetMacAccessibilityTest, HelpAttribute) { // Test view properties that should report the native NSWindow, and test // specific properties on that NSWindow. TEST_F(NativeWidgetMacAccessibilityTest, NativeWindowProperties) { - FlexibleRoleTestView* view = new FlexibleRoleTestView(ui::AX_ROLE_GROUP); + FlexibleRoleTestView* view = + new FlexibleRoleTestView(ax::mojom::Role::kGroup); view->SetSize(GetWidgetBounds().size()); widget()->GetContentsView()->AddChildView(view); // Make sure it's |view| in the hit test by checking its accessibility role. - EXPECT_EQ(NSAccessibilityGroupRole, AXRole()); + EXPECT_EQ(NSAccessibilityGroupRole, AXRoleString()); NSWindow* window = widget()->GetNativeWindow(); EXPECT_NSEQ(window, AttributeValueAtMidpoint(NSAccessibilityWindowAttribute)); @@ -439,7 +441,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, TextfieldGenericAttributes) { boolValue]); // NSAccessibilityTitleAttribute. - EXPECT_NSEQ(NSAccessibilityTextFieldRole, AXRole()); + EXPECT_NSEQ(NSAccessibilityTextFieldRole, AXRoleString()); EXPECT_NSEQ(kTestTitle, AXTitle()); EXPECT_NSEQ(kTestStringValue, AXValue()); @@ -538,14 +540,15 @@ TEST_F(NativeWidgetMacAccessibilityTest, TextfieldEditableAttributes) { // Test writing accessibility attributes via an accessibility client for normal // Views. TEST_F(NativeWidgetMacAccessibilityTest, ViewWritableAttributes) { - FlexibleRoleTestView* view = new FlexibleRoleTestView(ui::AX_ROLE_GROUP); + FlexibleRoleTestView* view = + new FlexibleRoleTestView(ax::mojom::Role::kGroup); view->SetSize(GetWidgetBounds().size()); widget()->GetContentsView()->AddChildView(view); // Make sure the accessibility object tested is the correct one. id ax_node = A11yElementAtMidpoint(); EXPECT_TRUE(ax_node); - EXPECT_NSEQ(NSAccessibilityGroupRole, AXRole()); + EXPECT_NSEQ(NSAccessibilityGroupRole, AXRoleString()); // Make sure |view| is focusable, then focus/unfocus it. view->SetFocusBehavior(View::FocusBehavior::ALWAYS); @@ -721,12 +724,13 @@ TEST_F(NativeWidgetMacAccessibilityTest, TextParameterizedAttributes) { // Test performing a 'click' on Views with clickable roles work. TEST_F(NativeWidgetMacAccessibilityTest, PressAction) { - FlexibleRoleTestView* view = new FlexibleRoleTestView(ui::AX_ROLE_BUTTON); + FlexibleRoleTestView* view = + new FlexibleRoleTestView(ax::mojom::Role::kButton); widget()->GetContentsView()->AddChildView(view); view->SetSize(GetWidgetBounds().size()); id ax_node = A11yElementAtMidpoint(); - EXPECT_NSEQ(NSAccessibilityButtonRole, AXRole()); + EXPECT_NSEQ(NSAccessibilityButtonRole, AXRoleString()); EXPECT_TRUE([[ax_node accessibilityActionNames] containsObject:NSAccessibilityPressAction]); @@ -789,7 +793,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, ProtectedTextfields) { // Explicit checks done without comparing to NSTextField. EXPECT_TRUE( [ax_node accessibilityIsAttributeSettable:NSAccessibilityValueAttribute]); - EXPECT_NSEQ(NSAccessibilityTextFieldRole, AXRole()); + EXPECT_NSEQ(NSAccessibilityTextFieldRole, AXRoleString()); NSString* kShownValue = @"•" @"••••••••••••••••"; @@ -831,7 +835,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, Label) { id ax_node = A11yElementAtMidpoint(); EXPECT_TRUE(ax_node); - EXPECT_NSEQ(NSAccessibilityStaticTextRole, AXRole()); + EXPECT_NSEQ(NSAccessibilityStaticTextRole, AXRoleString()); EXPECT_NSEQ(kTestStringValue, AXValue()); // Title and description for StaticTextRole should always be empty. @@ -867,6 +871,21 @@ TEST_F(NativeWidgetMacAccessibilityTest, Label) { // TODO(tapted): Add a test for multiline Labels (currently not supported). } +// Labels used as title bars should be exposed as normal static text on Mac. +TEST_F(NativeWidgetMacAccessibilityTest, LabelUsedAsTitleBar) { + Label* label = new Label(base::SysNSStringToUTF16(kTestStringValue), + style::CONTEXT_DIALOG_TITLE, style::STYLE_PRIMARY); + label->SetSize(GetWidgetBounds().size()); + widget()->GetContentsView()->AddChildView(label); + + // Get the Label's accessibility object. + id ax_node = A11yElementAtMidpoint(); + EXPECT_TRUE(ax_node); + + EXPECT_NSEQ(NSAccessibilityStaticTextRole, AXRoleString()); + EXPECT_NSEQ(kTestStringValue, AXValue()); +} + class TestComboboxModel : public ui::ComboboxModel { public: TestComboboxModel() = default; @@ -891,7 +910,7 @@ TEST_F(NativeWidgetMacAccessibilityTest, Combobox) { id ax_node = A11yElementAtMidpoint(); EXPECT_TRUE(ax_node); - EXPECT_NSEQ(NSAccessibilityPopUpButtonRole, AXRole()); + EXPECT_NSEQ(NSAccessibilityPopUpButtonRole, AXRoleString()); // The initial value should be the first item in the menu. EXPECT_NSEQ(kTestStringValue, AXValue()); diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm index b8e66d1533e..6555f7ddd0f 100644 --- a/chromium/ui/views/widget/native_widget_mac_unittest.mm +++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm @@ -760,6 +760,76 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) { EXPECT_EQ(0u, [[native_parent childWindows] count]); } +// Tests that CloseAllSecondaryWidgets behaves in various configurations. +TEST_F(NativeWidgetMacTest, CloseAllSecondaryWidgetsValidState) { + NSWindow* last_window = nil; + { + // First verify the behavior of CloseAllSecondaryWidgets in the normal case, + // and how [NSApp windows] changes in response to Widget closure. + base::mac::ScopedNSAutoreleasePool pool; + Widget* widget = CreateTopLevelPlatformWidget(); + widget->Show(); + TestWidgetObserver observer(widget); + last_window = widget->GetNativeWindow(); + EXPECT_TRUE([[NSApp windows] containsObject:last_window]); + Widget::CloseAllSecondaryWidgets(); + EXPECT_TRUE(observer.widget_closed()); + } + + { + // Calls to [NSApp windows] do autorelease, so ensure the pool empties. + base::mac::ScopedNSAutoreleasePool pool; + + // [NSApp windows] updates inside dealloc, so the window should be gone. + EXPECT_FALSE([[NSApp windows] containsObject:last_window]); + } + + { + // Repeat, but now retain a reference and close the window before + // CloseAllSecondaryWidgets(). + base::mac::ScopedNSAutoreleasePool pool; + Widget* widget = CreateTopLevelPlatformWidget(); + widget->Show(); + TestWidgetObserver observer(widget); + last_window = [widget->GetNativeWindow() retain]; + EXPECT_TRUE([[NSApp windows] containsObject:last_window]); + widget->CloseNow(); + EXPECT_TRUE(observer.widget_closed()); + } + { + base::mac::ScopedNSAutoreleasePool pool; + // Reference retained, so the window should still be present. + EXPECT_TRUE([[NSApp windows] containsObject:last_window]); + } + + { + base::mac::ScopedNSAutoreleasePool pool; + Widget::CloseAllSecondaryWidgets(); + [last_window release]; + } + { + base::mac::ScopedNSAutoreleasePool pool; + EXPECT_FALSE([[NSApp windows] containsObject:last_window]); + } + + // Repeat, with two Widgets. We can't control the order of window closure. + // If the parent is closed first, it should tear down the child while + // iterating over the windows. -[NSWindow close] will be sent to the child + // twice, but that should be fine. + Widget* parent = CreateTopLevelPlatformWidget(); + Widget* child = CreateChildPlatformWidget(parent->GetNativeView()); + parent->Show(); + child->Show(); + TestWidgetObserver parent_observer(parent); + TestWidgetObserver child_observer(child); + + EXPECT_TRUE([[NSApp windows] containsObject:parent->GetNativeWindow()]); + EXPECT_TRUE([[NSApp windows] containsObject:child->GetNativeWindow()]); + Widget::CloseAllSecondaryWidgets(); + EXPECT_TRUE(parent_observer.widget_closed()); + EXPECT_TRUE(child_observer.widget_closed()); +} + // Tests closing the last remaining NSWindow reference via -windowWillClose:. // This is a regression test for http://crbug.com/616701. TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) { diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc index d685bf4f40e..926519dfa33 100644 --- a/chromium/ui/views/widget/widget.cc +++ b/chromium/ui/views/widget/widget.cc @@ -525,6 +525,8 @@ void Widget::SetBoundsConstrained(const gfx::Rect& bounds) { if (work_area.IsEmpty()) { SetBounds(bounds); } else { + // TODO(https://crbug.com/806936): The following code doesn't actually do + // what the comment describing this function says it should. // Inset the work area slightly. work_area.Inset(10, 10, 10, 10); work_area.AdjustToFit(bounds); diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h index 242c9496b29..6c0c60807a2 100644 --- a/chromium/ui/views/widget/widget.h +++ b/chromium/ui/views/widget/widget.h @@ -59,10 +59,6 @@ class OSExchangeData; class ThemeProvider; } // namespace ui -namespace wm { -enum class ShadowElevation; -} - namespace views { class DesktopWindowTreeHost; @@ -243,7 +239,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, ShadowType shadow_type; // A hint about the size of the shadow if the type is SHADOW_TYPE_DROP. May // be ignored on some platforms. No value indicates no preference. - base::Optional<wm::ShadowElevation> shadow_elevation; + base::Optional<int> shadow_elevation; + // The window corner radius. May be ignored on some platforms. + base::Optional<int> corner_radius; // Specifies that the system default caption and icon should not be // rendered, and that the client area should be equivalent to the window // area. Only used on some platforms (Windows and Linux). diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc index a7696103df3..294113b8996 100644 --- a/chromium/ui/views/widget/widget_delegate.cc +++ b/chromium/ui/views/widget/widget_delegate.cc @@ -74,8 +74,8 @@ ui::ModalType WidgetDelegate::GetModalType() const { return ui::MODAL_TYPE_NONE; } -ui::AXRole WidgetDelegate::GetAccessibleWindowRole() const { - return ui::AX_ROLE_WINDOW; +ax::mojom::Role WidgetDelegate::GetAccessibleWindowRole() const { + return ax::mojom::Role::kWindow; } base::string16 WidgetDelegate::GetAccessibleWindowTitle() const { @@ -94,14 +94,6 @@ bool WidgetDelegate::ShouldShowCloseButton() const { return true; } -bool WidgetDelegate::ShouldHandleSystemCommands() const { - const Widget* widget = GetWidget(); - if (!widget) - return false; - - return widget->non_client_view() != NULL; -} - gfx::ImageSkia WidgetDelegate::GetWindowAppIcon() { // Use the window icon as app icon by default. return GetWindowIcon(); diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h index bd4d8a7a1de..8ae82197483 100644 --- a/chromium/ui/views/widget/widget_delegate.h +++ b/chromium/ui/views/widget/widget_delegate.h @@ -9,7 +9,7 @@ #include <vector> #include "base/macros.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/ui_base_types.h" #include "ui/views/view.h" @@ -72,7 +72,7 @@ class VIEWS_EXPORT WidgetDelegate { // ui::MODAL_TYPE_NONE (not modal). virtual ui::ModalType GetModalType() const; - virtual ui::AXRole GetAccessibleWindowRole() const; + virtual ax::mojom::Role GetAccessibleWindowRole() const; // Returns the title to be read with screen readers. virtual base::string16 GetAccessibleWindowTitle() const; @@ -86,10 +86,6 @@ class VIEWS_EXPORT WidgetDelegate { // Returns true if the window should show a close button in the title bar. virtual bool ShouldShowCloseButton() const; - // Returns true if the window should handle standard system commands, such as - // close, minimize, maximize. - virtual bool ShouldHandleSystemCommands() const; - // Returns the app icon for the window. On Windows, this is the ICON_BIG used // in Alt-Tab list and Win7's taskbar. virtual gfx::ImageSkia GetWindowAppIcon(); diff --git a/chromium/ui/views/widget/widget_hwnd_utils.cc b/chromium/ui/views/widget/widget_hwnd_utils.cc index 163e4b54b03..c7296fed234 100644 --- a/chromium/ui/views/widget/widget_hwnd_utils.cc +++ b/chromium/ui/views/widget/widget_hwnd_utils.cc @@ -60,7 +60,7 @@ void CalculateWindowStylesFromInitParams( *style |= WS_POPUP; break; } - // Else, no break. Fall through to TYPE_WINDOW. + FALLTHROUGH; case Widget::InitParams::TYPE_WINDOW: { // WS_OVERLAPPEDWINDOW is equivalent to: // WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc index 7bc23806118..1cad461f7dd 100644 --- a/chromium/ui/views/widget/widget_interactive_uitest.cc +++ b/chromium/ui/views/widget/widget_interactive_uitest.cc @@ -14,11 +14,13 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/win/windows_version.h" #include "build/build_config.h" #include "mojo/edk/embedder/embedder.h" #include "ui/base/ime/input_method.h" #include "ui/base/ime/text_input_client.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/base/test/ui_controls.h" #include "ui/base/ui_base_paths.h" #include "ui/base/ui_base_switches.h" #include "ui/events/event_processor.h" @@ -362,6 +364,75 @@ TEST_F(WidgetTestInteractive, DesktopNativeWidgetAuraActivationAndFocusTest) { widget2->CloseNow(); widget1->CloseNow(); } + +class TouchEventHandler : public ui::EventHandler { + public: + TouchEventHandler(Widget* widget) : widget_(widget) { + widget_->GetNativeWindow()->GetHost()->window()->AddPreTargetHandler(this); + } + + ~TouchEventHandler() override { + widget_->GetNativeWindow()->GetHost()->window()->RemovePreTargetHandler( + this); + } + + void WaitForEvents() { + base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); + base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop); + base::RunLoop run_loop; + quit_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + } + + static void __stdcall AsyncActivateMouse(HWND hwnd, + UINT msg, + ULONG_PTR data, + LRESULT result) { + EXPECT_EQ(MA_NOACTIVATE, result); + std::move(reinterpret_cast<TouchEventHandler*>(data)->quit_closure_).Run(); + } + + void ActivateViaMouse() { + SendMessageCallback( + widget_->GetNativeWindow()->GetHost()->GetAcceleratedWidget(), + WM_MOUSEACTIVATE, 0, 0, AsyncActivateMouse, + reinterpret_cast<ULONG_PTR>(this)); + } + + private: + // ui::EventHandler: + void OnTouchEvent(ui::TouchEvent* event) override { + if (event->type() == ui::ET_TOUCH_PRESSED) + ActivateViaMouse(); + } + + Widget* widget_; + base::OnceClosure quit_closure_; + DISALLOW_COPY_AND_ASSIGN(TouchEventHandler); +}; + +// TODO(dtapuska): Disabled due to it being flaky crbug.com/817531 +TEST_F(WidgetTestInteractive, DISABLED_TouchNoActivateWindow) { + // ui_controls::SendTouchEvents which uses InjectTouchInput API only works + // on Windows 8 and up. + if (base::win::GetVersion() <= base::win::VERSION_WIN7) + return; + + View* focusable_view = new View; + focusable_view->SetFocusBehavior(View::FocusBehavior::ALWAYS); + Widget* widget = CreateWidget(); + widget->GetContentsView()->AddChildView(focusable_view); + widget->Show(); + + { + TouchEventHandler touch_event_handler(widget); + ASSERT_TRUE(ui_controls::SendTouchEvents(ui_controls::PRESS, 1, 100, 100)); + touch_event_handler.WaitForEvents(); + } + + widget->CloseNow(); +} + #endif // defined(OS_WIN) TEST_F(WidgetTestInteractive, CaptureAutoReset) { @@ -641,6 +712,82 @@ TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) { widget2->CloseNow(); } +// Test z-order of child widgets relative to their parent. +TEST_F(WidgetTestInteractive, ChildStackedRelativeToParent) { + WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget()); + Widget* child = CreateChildPlatformWidget(parent->GetNativeView()); + + parent->SetBounds(gfx::Rect(160, 100, 320, 200)); + child->SetBounds(gfx::Rect(50, 50, 30, 20)); + + // Child shown first. Initially not visible, but on top of parent when shown. + // Use ShowInactive whenever showing the child, otherwise the usual activation + // logic will just put it on top anyway. Here, we want to ensure it is on top + // of its parent regardless. + child->ShowInactive(); + EXPECT_FALSE(child->IsVisible()); + + ShowSync(parent.get()); + EXPECT_TRUE(child->IsVisible()); + EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); + EXPECT_FALSE(IsWindowStackedAbove(parent.get(), child)); // Sanity check. + + WidgetAutoclosePtr popover(CreateTopLevelPlatformWidget()); + popover->SetBounds(gfx::Rect(150, 90, 340, 240)); + ShowSync(popover.get()); + + // NOTE: for aura-mus-client stacking of top-levels is not maintained in the + // client, so z-order of top-levels can't be determined. + const bool check_toplevel_z_order = !IsMus(); + if (check_toplevel_z_order) + EXPECT_TRUE(IsWindowStackedAbove(popover.get(), child)); + EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); + + // Showing the parent again should raise it and its child above the popover. + ShowSync(parent.get()); + EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); + if (check_toplevel_z_order) + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); + + // Test grandchildren. + Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView()); + grandchild->SetBounds(gfx::Rect(5, 5, 15, 10)); + grandchild->ShowInactive(); + EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); + EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); + if (check_toplevel_z_order) + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); + + ShowSync(popover.get()); + if (check_toplevel_z_order) + EXPECT_TRUE(IsWindowStackedAbove(popover.get(), grandchild)); + EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); + + ShowSync(parent.get()); + EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); + if (check_toplevel_z_order) + EXPECT_TRUE(IsWindowStackedAbove(child, popover.get())); + + // Test hiding and reshowing. + parent->Hide(); + EXPECT_FALSE(grandchild->IsVisible()); + ShowSync(parent.get()); + + EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); + EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); + if (check_toplevel_z_order) + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); + + grandchild->Hide(); + EXPECT_FALSE(grandchild->IsVisible()); + grandchild->ShowInactive(); + + EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); + EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); + if (check_toplevel_z_order) + EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); +} + #if defined(OS_WIN) // Test view focus retention when a widget's HWND is disabled and re-enabled. diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc index 9bee0337d55..76a9b283676 100644 --- a/chromium/ui/views/widget/widget_unittest.cc +++ b/chromium/ui/views/widget/widget_unittest.cc @@ -47,6 +47,12 @@ #include "base/mac/mac_util.h" #endif +#if defined(OS_CHROMEOS) +#include "ui/wm/core/base_focus_rules.h" +#include "ui/wm/core/focus_controller.h" +#include "ui/wm/core/shadow_controller.h" +#endif + namespace views { namespace test { @@ -61,12 +67,6 @@ gfx::Point ConvertPointFromWidgetToView(View* view, const gfx::Point& p) { return tmp; } -// This class can be used as a deleter for std::unique_ptr<Widget> -// to call function Widget::CloseNow automatically. -struct WidgetCloser { - inline void operator()(Widget* widget) const { widget->CloseNow(); } -}; - class TestBubbleDialogDelegateView : public BubbleDialogDelegateView { public: TestBubbleDialogDelegateView(View* anchor) @@ -82,8 +82,6 @@ class TestBubbleDialogDelegateView : public BubbleDialogDelegateView { mutable bool reset_controls_called_; }; -using WidgetAutoclosePtr = std::unique_ptr<Widget, WidgetCloser>; - } // namespace // A view that keeps track of the events it receives, and consumes all scroll @@ -286,82 +284,6 @@ TEST_F(WidgetTest, ChildBoundsRelativeToParent) { EXPECT_EQ(toplevel_bounds, child->GetWindowBoundsInScreen()); } -// Test z-order of child widgets relative to their parent. -TEST_F(WidgetTest, ChildStackedRelativeToParent) { - WidgetAutoclosePtr parent(CreateTopLevelPlatformWidget()); - Widget* child = CreateChildPlatformWidget(parent->GetNativeView()); - - parent->SetBounds(gfx::Rect(160, 100, 320, 200)); - child->SetBounds(gfx::Rect(50, 50, 30, 20)); - - // Child shown first. Initially not visible, but on top of parent when shown. - // Use ShowInactive whenever showing the child, otherwise the usual activation - // logic will just put it on top anyway. Here, we want to ensure it is on top - // of its parent regardless. - child->ShowInactive(); - EXPECT_FALSE(child->IsVisible()); - - parent->Show(); - EXPECT_TRUE(child->IsVisible()); - EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - EXPECT_FALSE(IsWindowStackedAbove(parent.get(), child)); // Sanity check. - - WidgetAutoclosePtr popover(CreateTopLevelPlatformWidget()); - popover->SetBounds(gfx::Rect(150, 90, 340, 240)); - popover->Show(); - - // NOTE: for aura-mus-client stacking of top-levels is not maintained in the - // client, so z-order of top-levels can't be determined. - const bool check_toplevel_z_order = !IsMus(); - if (check_toplevel_z_order) - EXPECT_TRUE(IsWindowStackedAbove(popover.get(), child)); - EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - - // Showing the parent again should raise it and its child above the popover. - parent->Show(); - EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - if (check_toplevel_z_order) - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); - - // Test grandchildren. - Widget* grandchild = CreateChildPlatformWidget(child->GetNativeView()); - grandchild->SetBounds(gfx::Rect(5, 5, 15, 10)); - grandchild->ShowInactive(); - EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); - EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - if (check_toplevel_z_order) - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); - - popover->Show(); - if (check_toplevel_z_order) - EXPECT_TRUE(IsWindowStackedAbove(popover.get(), grandchild)); - EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); - - parent->Show(); - EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); - if (check_toplevel_z_order) - EXPECT_TRUE(IsWindowStackedAbove(child, popover.get())); - - // Test hiding and reshowing. - parent->Hide(); - EXPECT_FALSE(grandchild->IsVisible()); - parent->Show(); - - EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); - EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - if (check_toplevel_z_order) - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); - - grandchild->Hide(); - EXPECT_FALSE(grandchild->IsVisible()); - grandchild->ShowInactive(); - - EXPECT_TRUE(IsWindowStackedAbove(grandchild, child)); - EXPECT_TRUE(IsWindowStackedAbove(child, parent.get())); - if (check_toplevel_z_order) - EXPECT_TRUE(IsWindowStackedAbove(parent.get(), popover.get())); -} - //////////////////////////////////////////////////////////////////////////////// // Widget ownership tests. // @@ -2116,7 +2038,7 @@ bool RunGetNativeThemeFromDestructor(const Widget::InitParams& in_params, bool is_first_run) { bool needs_second_run = false; // Destroyed by CloseNow() below. - WidgetAutoclosePtr widget(new Widget); + WidgetTest::WidgetAutoclosePtr widget(new Widget); Widget::InitParams params(in_params); // Deletes itself when the Widget is destroyed. params.delegate = new GetNativeThemeFromDestructorView; @@ -3815,6 +3737,142 @@ TEST_F(WidgetTest, MouseWheelEvent) { EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSEWHEEL)); } +class WidgetShadowTest : public WidgetTest { + public: + WidgetShadowTest() { InitControllers(); } + + // WidgetTest: + Widget::InitParams CreateParams(Widget::InitParams::Type type) override { + Widget::InitParams params = + WidgetTest::CreateParams(override_type_.value_or(type)); + params.shadow_type = Widget::InitParams::SHADOW_TYPE_DROP; + params.shadow_elevation = 10; + params.name = name_; + params.child = force_child_; + return params; + } + + protected: + base::Optional<Widget::InitParams::Type> override_type_; + std::string name_; + bool force_child_ = false; + + private: +#if !defined(OS_CHROMEOS) + void InitControllers() {} +#else + class TestFocusRules : public wm::BaseFocusRules { + public: + TestFocusRules() = default; + + bool SupportsChildActivation(aura::Window* window) const override { + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TestFocusRules); + }; + + void InitControllers() { + // Add bits usually managed by the ash::Shell. Under Mus, + // DesktopNativeWidgetAura provides these in-process instead. + if (IsMus()) + return; + + focus_controller_ = + std::make_unique<wm::FocusController>(new TestFocusRules); + shadow_controller_ = + std::make_unique<wm::ShadowController>(focus_controller_.get()); + } + + std::unique_ptr<wm::FocusController> focus_controller_; + std::unique_ptr<wm::ShadowController> shadow_controller_; +#endif // OS_CHROMEOS + + DISALLOW_COPY_AND_ASSIGN(WidgetShadowTest); +}; + +// Disabled on Mac: All drop shadows are managed out of process for now. +#if defined(OS_MACOSX) && !defined(USE_AURA) +#define MAYBE_ShadowsInRootWindow DISABLED_ShadowsInRootWindow +#else +#define MAYBE_ShadowsInRootWindow ShadowsInRootWindow +#endif + +// Test that shadows are not added to root windows when created or upon +// activation. Test that shadows are added to non-root windows even if not +// activated. +TEST_F(WidgetShadowTest, MAYBE_ShadowsInRootWindow) { + // A desktop window clips to its bounds, so it shouldn't have a shadow. + bool top_level_window_should_have_shadow = false; + +#if defined(OS_CHROMEOS) + // In Mus, the shadow should be in the WindowServer process only. In non-mus + // CreateNativeDesktopWidget() creates a non-root window, so it should have + // a shadow. + top_level_window_should_have_shadow = !IsMus(); +#endif + + // To start, just create a Widget. This constructs the first ShadowController + // which will start observing the environment for additional aura::Window + // initialization. The very first ShadowController in DesktopNativeWidgetAura + // is created after the call to aura::Window::Init(), so the ShadowController + // Impl class won't ever see this first Window being initialized. + name_ = "other_top_level"; + Widget* other_top_level = CreateNativeDesktopWidget(); + + name_ = "top_level"; + Widget* top_level = CreateNativeDesktopWidget(); + top_level->SetBounds(gfx::Rect(100, 100, 320, 200)); + + EXPECT_FALSE(WidgetHasInProcessShadow(top_level)); + EXPECT_FALSE(top_level->IsVisible()); + top_level->ShowInactive(); + EXPECT_EQ(top_level_window_should_have_shadow, + WidgetHasInProcessShadow(top_level)); + top_level->Show(); + EXPECT_EQ(top_level_window_should_have_shadow, + WidgetHasInProcessShadow(top_level)); + + name_ = "control"; + Widget* control = CreateChildNativeWidgetWithParent(top_level); + control->SetBounds(gfx::Rect(20, 20, 160, 100)); + + // Widgets of TYPE_CONTROL become visible during Init, so start with a shadow. + EXPECT_TRUE(WidgetHasInProcessShadow(control)); + control->ShowInactive(); + EXPECT_TRUE(WidgetHasInProcessShadow(control)); + control->Show(); + EXPECT_TRUE(WidgetHasInProcessShadow(control)); + + name_ = "child"; + override_type_ = Widget::InitParams::TYPE_POPUP; + force_child_ = true; + Widget* child = CreateChildNativeWidgetWithParent(top_level); + child->SetBounds(gfx::Rect(20, 20, 160, 100)); + + // Now false: the Widget hasn't been shown yet. + EXPECT_FALSE(WidgetHasInProcessShadow(child)); + child->ShowInactive(); + EXPECT_TRUE(WidgetHasInProcessShadow(child)); + child->Show(); + EXPECT_TRUE(WidgetHasInProcessShadow(child)); + + other_top_level->Show(); + + // Re-activate the top level window. This handles a hypothetical case where + // a shadow is added via the ActivationChangeObserver rather than by the + // aura::WindowObserver. Activation changes only modify an existing shadow + // (if there is one), but should never install a Shadow, even if the Window + // properties otherwise say it should have one. + top_level->Show(); + EXPECT_EQ(top_level_window_should_have_shadow, + WidgetHasInProcessShadow(top_level)); + + top_level->Close(); + other_top_level->Close(); +} + #if defined(OS_WIN) namespace { diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc index 5906900d721..c8fb7eecb9c 100644 --- a/chromium/ui/views/win/hwnd_message_handler.cc +++ b/chromium/ui/views/win/hwnd_message_handler.cc @@ -31,6 +31,7 @@ #include "ui/base/ime/text_input_type.h" #include "ui/base/ui_base_features.h" #include "ui/base/view_prop.h" +#include "ui/base/win/direct_manipulation.h" #include "ui/base/win/internal_constants.h" #include "ui/base/win/lock_state.h" #include "ui/base/win/mouse_wheel_util.h" @@ -48,7 +49,6 @@ #include "ui/gfx/icon_util.h" #include "ui/gfx/path.h" #include "ui/gfx/path_win.h" -#include "ui/gfx/win/direct_manipulation.h" #include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/win/rendering_window_manager.h" #include "ui/native_theme/native_theme_win.h" @@ -249,9 +249,6 @@ const int kTouchDownContextResetTimeout = 500; // same location as the cursor. const int kSynthesizedMouseMessagesTimeDifference = 500; -// Currently this flag is always false - see http://crbug.com/763223 -const bool kUsePointerEventsForTouch = false; - } // namespace // A scoping class that prevents a window from being able to redraw in response @@ -371,6 +368,7 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate) sent_window_size_changing_(false), left_button_down_on_caption_(false), background_fullscreen_hack_(false), + pointer_events_for_touch_(features::IsUsingWMPointerForTouch()), autohide_factory_(this), weak_factory_(this) {} @@ -416,7 +414,7 @@ void HWNDMessageHandler::Init(HWND parent, const gfx::Rect& bounds) { // Direct Manipulation is enabled on Windows 10+. The CreateInstance function // returns NULL if Direct Manipulation is not available. direct_manipulation_helper_ = - gfx::win::DirectManipulationHelper::CreateInstance(); + ui::win::DirectManipulationHelper::CreateInstance(); if (direct_manipulation_helper_) direct_manipulation_helper_->Initialize(hwnd()); @@ -1429,7 +1427,8 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) { // Get access to a modifiable copy of the system menu. GetSystemMenu(hwnd(), false); - RegisterTouchWindow(hwnd(), TWF_WANTPALM); + if (!pointer_events_for_touch_) + RegisterTouchWindow(hwnd(), TWF_WANTPALM); // We need to allow the delegate to size its contents since the window may not // receive a size notification when its initial bounds are specified at window @@ -1748,9 +1747,9 @@ LRESULT HWNDMessageHandler::OnPointerEvent(UINT message, case PT_PEN: return HandlePointerEventTypePen(message, w_param, l_param); case PT_TOUCH: - if (kUsePointerEventsForTouch) + if (pointer_events_for_touch_) return HandlePointerEventTypeTouch(message, w_param, l_param); - // FALLTHROUGH_INTENDED + FALLTHROUGH; default: SetMsgHandled(FALSE); return -1; @@ -2223,9 +2222,6 @@ void HWNDMessageHandler::OnSize(UINT param, const gfx::Size& size) { void HWNDMessageHandler::OnSysCommand(UINT notification_code, const gfx::Point& point) { - if (!delegate_->ShouldHandleSystemCommands()) - return; - // Windows uses the 4 lower order bits of |notification_code| for type- // specific information so we must exclude this when comparing. static const int sc_mask = 0xFFF0; @@ -2299,6 +2295,16 @@ void HWNDMessageHandler::OnTimeChange() { LRESULT HWNDMessageHandler::OnTouchEvent(UINT message, WPARAM w_param, LPARAM l_param) { + if (pointer_events_for_touch_) { + // Release any associated memory with this event. + CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(l_param)); + + // Claim the event is handled. This shouldn't ever happen + // because we don't register touch windows when we are using + // pointer events. + return 0; + } + // Handle touch events only on Aura for now. int num_points = LOWORD(w_param); std::unique_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]); @@ -2309,7 +2315,10 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message, // so use base::TimeTicks::Now(). const base::TimeTicks event_time = base::TimeTicks::Now(); TouchEvents touch_events; + TouchIDs stale_touches(touch_ids_); + for (int i = 0; i < num_points; ++i) { + stale_touches.erase(input[i].dwID); POINT point; point.x = TOUCH_COORD_TO_PIXEL(input[i].x); point.y = TOUCH_COORD_TO_PIXEL(input[i].y); @@ -2330,7 +2339,7 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message, last_touch_or_pen_message_time_ = ::GetMessageTime(); gfx::Point touch_point(point.x, point.y); - unsigned int touch_id = id_generator_.GetGeneratedID(input[i].dwID); + size_t touch_id = id_generator_.GetGeneratedID(input[i].dwID); if (input[i].dwFlags & TOUCHEVENTF_DOWN) { touch_ids_.insert(input[i].dwID); @@ -2355,6 +2364,19 @@ LRESULT HWNDMessageHandler::OnTouchEvent(UINT message, } } } + // If a touch has been dropped from the list (without a TOUCH_EVENTF_UP) + // we generate a simulated TOUCHEVENTF_UP event. + for (auto touch_number : stale_touches) { + // Log that we've hit this code. When usage drops off, we can remove + // this "workaround". See https://crbug.com/811273 + UMA_HISTOGRAM_BOOLEAN("TouchScreen.MissedTOUCHEVENTF_UP", true); + size_t touch_id = id_generator_.GetGeneratedID(touch_number); + touch_ids_.erase(touch_number); + GenerateTouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(0, 0), touch_id, + event_time, &touch_events); + id_generator_.ReleaseNumber(touch_number); + } + // Handle the touch events asynchronously. We need this because touch // events on windows don't fire if we enter a modal loop in the context of // a touch event. @@ -2720,6 +2742,7 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message, return -1; } + last_touch_or_pen_message_time_ = ::GetMessageTime(); // Ignore enter/leave events, otherwise they will be converted in // |GetTouchEventType| to ET_TOUCH_PRESSED/ET_TOUCH_RELEASED events, which // is not correct. @@ -2728,7 +2751,18 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message, return 0; } - unsigned int mapped_pointer_id = id_generator_.GetGeneratedID(pointer_id); + // Increment |touch_down_contexts_| on a pointer down. This variable + // is used to debounce the WM_MOUSEACTIVATE events. + if (message == WM_POINTERDOWN) { + touch_down_contexts_++; + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&HWNDMessageHandler::ResetTouchDownContext, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kTouchDownContextResetTimeout)); + } + + size_t mapped_pointer_id = id_generator_.GetGeneratedID(pointer_id); POINTER_INFO pointer_info = pointer_touch_info.pointerInfo; POINT client_point = pointer_info.ptPixelLocationRaw; ScreenToClient(hwnd(), &client_point); @@ -2763,14 +2797,14 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message, ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, event_time, 1); // There are cases where the code handling the message destroys the - // window, so use the weak ptr to check if destruction occured or not. + // window, so use the weak ptr to check if destruction occurred or not. base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr()); delegate_->HandleTouchEvent(event); if (event_type == ui::ET_TOUCH_RELEASED) id_generator_.ReleaseNumber(pointer_id); if (ref) - SetMsgHandled(TRUE); + SetMsgHandled(event.handled()); return 0; } @@ -2869,7 +2903,7 @@ void HWNDMessageHandler::PerformDwmTransition() { void HWNDMessageHandler::GenerateTouchEvent(ui::EventType event_type, const gfx::Point& point, - unsigned int id, + size_t id, base::TimeTicks time_stamp, TouchEvents* touch_events) { ui::TouchEvent event( diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h index ad432b4d9ac..5d5765c1928 100644 --- a/chromium/ui/views/win/hwnd_message_handler.h +++ b/chromium/ui/views/win/hwnd_message_handler.h @@ -20,7 +20,7 @@ #include "base/strings/string16.h" #include "base/win/scoped_gdi_object.h" #include "base/win/win_util.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/ime/input_method_observer.h" #include "ui/base/ui_base_types.h" #include "ui/base/win/window_event_target.h" @@ -34,9 +34,6 @@ namespace gfx { class ImageSkia; class Insets; -namespace win { -class DirectManipulationHelper; -} // namespace win } // namespace gfx namespace ui { @@ -44,7 +41,10 @@ class AXSystemCaretWin; class InputMethod; class TextInputClient; class ViewProp; -} +namespace win { +class DirectManipulationHelper; +} // namespace win +} // namespace ui namespace views { @@ -550,12 +550,6 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl, const POINTER_INFO& pointer_info, const gfx::Point& point, const ui::PointerDetails& pointer_details); - LRESULT GenerateTouchEventFromPointerEvent( - UINT message, - UINT32 pointer_id, - const POINTER_INFO& pointer_info, - const gfx::Point& point, - const ui::PointerDetails& pointer_details); // Returns true if the mouse message passed in is an OS synthesized mouse // message. @@ -575,7 +569,7 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl, // |time_stamp| is the time stamp associated with the message. void GenerateTouchEvent(ui::EventType event_type, const gfx::Point& point, - unsigned int id, + size_t id, base::TimeTicks time_stamp, TouchEvents* touch_events); @@ -737,7 +731,7 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl, // This class provides functionality to register the legacy window as a // Direct Manipulation consumer. This allows us to support smooth scroll // in Chrome on Windows 10. - std::unique_ptr<gfx::win::DirectManipulationHelper> + std::unique_ptr<ui::win::DirectManipulationHelper> direct_manipulation_helper_; // The location where the user clicked on the caption. We cache this when we @@ -759,6 +753,10 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl, // partially or fully transparent. bool is_translucent_ = false; + // True if the window should process WM_POINTER for touch events and + // not WM_TOUCH events. + bool pointer_events_for_touch_; + // This is a map of the HMONITOR to full screeen window instance. It is safe // to keep a raw pointer to the HWNDMessageHandler instance as we track the // window destruction and ensure that the map is cleaned up. diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h index 2168aedea4b..d13f807e4a7 100644 --- a/chromium/ui/views/win/hwnd_message_handler_delegate.h +++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h @@ -5,12 +5,16 @@ #ifndef UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_DELEGATE_H_ #define UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_DELEGATE_H_ +#include "base/win/windows_types.h" +#include "ui/base/ui_base_types.h" +#include "ui/gfx/native_widget_types.h" #include "ui/views/views_export.h" namespace gfx { class Insets; class Path; class Point; +class Rect; class Size; } @@ -19,6 +23,8 @@ class Accelerator; class InputMethod; class KeyEvent; class MouseEvent; +class PointerEvent; +class ScrollEvent; class TouchEvent; } @@ -98,12 +104,6 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate { virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0; - // Returns true if the window should handle standard system commands, such as - // close, minimize, maximize. - // TODO(benwells): Remove this once bubbles don't have two widgets - // implementing them on non-aura windows. http://crbug.com/189112. - virtual bool ShouldHandleSystemCommands() const = 0; - // TODO(beng): Investigate migrating these methods to On* prefixes once // HWNDMessageHandler is the WindowImpl. diff --git a/chromium/ui/views/win/pen_event_processor.cc b/chromium/ui/views/win/pen_event_processor.cc index dd15a85140f..17f51705029 100644 --- a/chromium/ui/views/win/pen_event_processor.cc +++ b/chromium/ui/views/win/pen_event_processor.cc @@ -187,9 +187,10 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateTouchEvent( int rotation_angle = static_cast<int>(pointer_details.twist) % 180; if (rotation_angle < 0) rotation_angle += 180; - std::unique_ptr<ui::Event> event = std::make_unique<ui::TouchEvent>( + std::unique_ptr<ui::TouchEvent> event = std::make_unique<ui::TouchEvent>( event_type, point, event_time, pointer_details, flags | ui::GetModifiersFromKeyState(), rotation_angle); + event->set_hovering(event_type == ui::ET_TOUCH_RELEASED); event->latency()->AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, event_time, 1); return event; diff --git a/chromium/ui/views/window/client_view.cc b/chromium/ui/views/window/client_view.cc index 2f080badef5..2b6a99a020c 100644 --- a/chromium/ui/views/window/client_view.cc +++ b/chromium/ui/views/window/client_view.cc @@ -75,7 +75,7 @@ const char* ClientView::GetClassName() const { } void ClientView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_CLIENT; + node_data->role = ax::mojom::Role::kClient; } void ClientView::OnBoundsChanged(const gfx::Rect& previous_bounds) { diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc index 6b673090242..40cc9f35cfa 100644 --- a/chromium/ui/views/window/dialog_client_view.cc +++ b/chromium/ui/views/window/dialog_client_view.cc @@ -33,12 +33,6 @@ namespace { // conflict with other groups that could be in the dialog content. const int kButtonGroup = 6666; -#if defined(OS_WIN) || defined(OS_CHROMEOS) -const bool kIsOkButtonOnLeftSide = true; -#else -const bool kIsOkButtonOnLeftSide = false; -#endif - // Returns true if the given view should be shown (i.e. exists and is // visible). bool ShouldShow(View* view) { @@ -330,7 +324,7 @@ DialogClientView::GetButtonRowViews() { View* first = ShouldShow(extra_view_) ? extra_view_ : nullptr; View* second = cancel_button_; View* third = ok_button_; - if (kIsOkButtonOnLeftSide) + if (PlatformStyle::kIsOkButtonLeading) std::swap(second, third); return {{first, second, third}}; } diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc index a741a22ad42..3e88b8db4c8 100644 --- a/chromium/ui/views/window/dialog_delegate.cc +++ b/chromium/ui/views/window/dialog_delegate.cc @@ -249,8 +249,8 @@ void DialogDelegate::DialogModelChanged() { observer.OnDialogModelChanged(); } -ui::AXRole DialogDelegate::GetAccessibleWindowRole() const { - return ui::AX_ROLE_DIALOG; +ax::mojom::Role DialogDelegate::GetAccessibleWindowRole() const { + return ax::mojom::Role::kDialog; } //////////////////////////////////////////////////////////////////////////////// @@ -283,7 +283,7 @@ View* DialogDelegateView::GetContentsView() { void DialogDelegateView::ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) { if (details.is_add && details.child == this && GetWidget()) - NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); } } // namespace views diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h index 8061f680220..69add25e1a0 100644 --- a/chromium/ui/views/window/dialog_delegate.h +++ b/chromium/ui/views/window/dialog_delegate.h @@ -9,7 +9,7 @@ #include "base/macros.h" #include "base/strings/string16.h" #include "base/time/time.h" -#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/models/dialog_model.h" #include "ui/base/ui_base_types.h" #include "ui/views/widget/widget.h" @@ -130,7 +130,7 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel, protected: // Overridden from WidgetDelegate: - ui::AXRole GetAccessibleWindowRole() const override; + ax::mojom::Role GetAccessibleWindowRole() const override; private: // A flag indicating whether this dialog is able to use the custom frame diff --git a/chromium/ui/views/window/non_client_view.cc b/chromium/ui/views/window/non_client_view.cc index 2d20a34cae2..1dbbeb4f839 100644 --- a/chromium/ui/views/window/non_client_view.cc +++ b/chromium/ui/views/window/non_client_view.cc @@ -201,7 +201,7 @@ void NonClientView::ViewHierarchyChanged( } void NonClientView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_CLIENT; + node_data->role = ax::mojom::Role::kClient; node_data->SetName(accessible_name_); } @@ -319,7 +319,7 @@ void NonClientFrameView::ActivationChanged(bool active) { } void NonClientFrameView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_CLIENT; + node_data->role = ax::mojom::Role::kClient; } const char* NonClientFrameView::GetClassName() const { diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html index 691625fb095..423a18a8e50 100644 --- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html +++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_subentry.html @@ -36,21 +36,21 @@ title="[[i18n('moreActions')]]" on-tap="onDotsTap_"></button> <template is="cr-lazy-render" id="menu"> <dialog is="cr-action-menu"> - <button class="dropdown-item" id="view" + <button slot="item" class="dropdown-item" id="view" on-tap="onViewTap_"> [[i18n('certificateManagerView')]] </button> - <button class="dropdown-item" id="edit" + <button slot="item" class="dropdown-item" id="edit" hidden$="[[!canEdit_(certificateType, model)]]" on-tap="onEditTap_"> [[i18n('edit')]] </button> - <button class="dropdown-item" id="export" + <button slot="item" class="dropdown-item" id="export" hidden$="[[!canExport_(certificateType, model)]]" on-tap="onExportTap_"> [[i18n('certificateManagerExport')]] </button> - <button class="dropdown-item" id="delete" + <button slot="item" class="dropdown-item" id="delete" hidden$="[[!canDelete_(model)]]" on-tap="onDeleteTap_"> [[i18n('certificateManagerDelete')]] diff --git a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html index dc8592fc98c..a71d029f68a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth_dialog.html @@ -13,7 +13,7 @@ <template> <style include="cr-hidden-style iron-flex"> dialog { - @apply(--bluetooth-dialog-style); + @apply --bluetooth-dialog-style; } #pairing { diff --git a/chromium/ui/webui/resources/cr_components/chromeos/compiled_resources2.gyp b/chromium/ui/webui/resources/cr_components/chromeos/compiled_resources2.gyp index 1e6afe0491a..02bc35a7bbe 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/compiled_resources2.gyp +++ b/chromium/ui/webui/resources/cr_components/chromeos/compiled_resources2.gyp @@ -11,6 +11,13 @@ ], }, { + 'target_name': 'quick_unlock_resources', + 'type': 'none', + 'dependencies': [ + 'quick_unlock/compiled_resources2.gyp:*', + ], + }, + { 'target_name': 'bluetooth_dialog', 'dependencies': [ '<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog', diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html index a2ba57be7c2..32c5b74d9e7 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html @@ -15,14 +15,14 @@ </style> <!-- SSID (WiFi) --> - <template is="dom-if" if="[[isType_(NetworkType_.WI_FI, type)]]"> + <template is="dom-if" if="[[isType_(NetworkType_.WI_FI, type)]]" restamp> <network-config-input id="ssid" label="[[i18n('OncWiFi-SSID')]]" value="{{configProperties_.WiFi.SSID}}" disabled="[[hasGuid_(guid)]]"> </network-config-input> </template> <!-- Security (WiFi and Ethernet) --> - <template is="dom-if" if="[[securityIsVisible_(type)]]"> + <template is="dom-if" if="[[securityIsVisible_(type)]]" restamp> <network-config-select id="security" label="[[i18n('OncWiFi-Security')]]" value="{{security_}}" disabled="[[!securityIsEnabled_(guid, type)]]" @@ -32,7 +32,8 @@ </template> <!-- Passphrase (WiFi) --> - <template is="dom-if" if="[[configRequiresPassphrase_(type, security_)]]"> + <template is="dom-if" if="[[configRequiresPassphrase_(type, security_)]]" + restamp> <network-config-input label="[[i18n('OncWiFi-Passphrase')]]" value="{{configProperties_.WiFi.Passphrase}}" password> <iron-a11y-keys keys="enter" on-keys-pressed="connectIfConfigured_"> @@ -41,7 +42,7 @@ </template> <!-- VPN --> - <template is="dom-if" if="[[showVpn_]]"> + <template is="dom-if" if="[[showVpn_]]" restamp> <network-config-input label="[[i18n('OncVPN-Host')]]" value="{{configProperties_.VPN.Host}}"> </network-config-input> @@ -102,7 +103,7 @@ </template> <!-- EAP (WiFi, WiMAX, Ethernet) --> - <template is="dom-if" if="[[showEap_]]"> + <template is="dom-if" if="[[showEap_]]" restamp> <network-config-select id="outer" label="[[i18n('OncEAP-Outer')]]" value="{{eapProperties_.Outer}}" items="[[eapOuterItems_]]" onc-prefix="EAP.Outer" hidden="[[!showEap_.Outer]]"> @@ -147,7 +148,7 @@ <!-- Share (WiFi and WiMAX) --> <template is="dom-if" - if="[[shareIsVisible_(guid, type, networkProperties)]]"> + if="[[shareIsVisible_(guid, type, networkProperties)]]" restamp> <div class="property-box"> <div id="shareLabel" class="start">[[i18n('networkConfigShare')]]</div> <paper-toggle-button id="share" checked="{{shareNetwork_}}" diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js index 74cdc9b049f..0b6ada22d5a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js @@ -9,7 +9,7 @@ */ /** - * Combinaiton of CrOnc.VPNType + AuthenticationType for IPsec. + * Combination of CrOnc.VPNType + AuthenticationType for IPsec. * Note: closure does not always recognize this if inside function() {}. * @enum {string} */ @@ -24,6 +24,7 @@ var VPNConfigType = { /** @const */ var DEFAULT_HASH = 'default'; /** @const */ var DO_NOT_CHECK_HASH = 'do-not-check'; +/** @const */ var NO_CERTS_HASH = 'no-certs'; Polymer({ is: 'network-config', @@ -53,9 +54,6 @@ Polymer({ */ type: String, - /** Set by embedder if saveOrConnect should always connect. */ - connectOnSave: Boolean, - /** True if the user configuring the network can toggle the shared state. */ shareAllowEnable: Boolean, @@ -129,7 +127,7 @@ Polymer({ }, }, - /** @private */ + /** @private {string|undefined} */ selectedServerCaHash_: String, /** @@ -143,7 +141,7 @@ Polymer({ }, }, - /** @private */ + /** @private {string|undefined} */ selectedUserCertHash_: String, /** @@ -280,7 +278,7 @@ Polymer({ /** * Array of values for the VPN Type dropdown. For L2TP-IPSec, the - * IPsec AuthenticationType ('PSK' or 'Cert') is incuded in the type. + * IPsec AuthenticationType ('PSK' or 'Cert') is included in the type. * Note: closure does not recognize Array<VPNConfigType> here. * @private {!Array<string>} * @const @@ -313,6 +311,7 @@ Polymer({ 'updateIsConfigured_(configProperties_, eapProperties_.*)', 'updateIsConfigured_(configProperties_.WiFi.*)', 'updateIsConfigured_(configProperties_.VPN.*, vpnType_)', + 'updateIsConfigured_(selectedUserCertHash_)', ], /** @const */ @@ -343,6 +342,8 @@ Polymer({ init: function() { this.propertiesSent_ = false; + this.selectedServerCaHash_ = undefined; + this.selectedUserCertHash_ = undefined; this.guid = this.networkProperties.GUID; this.type = this.networkProperties.Type; if (this.guid) { @@ -360,7 +361,19 @@ Polymer({ this.setShareNetwork_(); }, - saveOrConnect: function() { + save: function() { + this.saveAndConnect_(false /* connect */); + }, + + connect: function() { + this.saveAndConnect_(true /* connect */); + }, + + /** + * @param {boolean} connect If true, connect after save. + * @private + */ + saveAndConnect_: function(connect) { if (this.propertiesSent_) return; this.propertiesSent_ = true; @@ -376,14 +389,14 @@ Polymer({ this.globalPolicy.AllowOnlyPolicyNetworksToConnect)) { CrOnc.setTypeProperty(propertiesToSet, 'AutoConnect', false); } - // Create the configuration, then connect to it in the callback. this.networkingPrivate.createNetwork( - this.shareNetwork_, propertiesToSet, - this.createNetworkCallback_.bind(this)); + this.shareNetwork_, propertiesToSet, (guid) => { + this.createNetworkCallback_(connect, guid); + }); } else { - propertiesToSet.GUID = this.guid; - this.networkingPrivate.setProperties( - this.guid, propertiesToSet, this.setPropertiesCallback_.bind(this)); + this.networkingPrivate.setProperties(this.guid, propertiesToSet, () => { + this.setPropertiesCallback_(connect); + }); } }, @@ -401,7 +414,7 @@ Polymer({ connectIfConfigured_: function() { if (!this.isConfigured_) return; - this.saveOrConnect(); + this.connect(); }, /** @private */ @@ -438,13 +451,30 @@ Polymer({ caCerts.push(this.getDefaultCert_( this.i18n('networkCADoNotCheck'), DO_NOT_CHECK_HASH)); this.set('serverCaCerts_', caCerts); + if (this.selectedServerCaHash_ && !caCerts.find((cert) => { + return cert.hash == this.selectedServerCaHash_; + })) { + this.selectedServerCaHash_ = undefined; + } var userCerts = certificateLists.userCertificates.slice(); if (!userCerts.length) { userCerts = [this.getDefaultCert_( - this.i18n('networkCertificateNoneInstalled'), '')]; + this.i18n('networkCertificateNoneInstalled'), NO_CERTS_HASH)]; + } else { + // Only hardware backed user certs are supported. + userCerts.forEach(function(cert) { + if (!cert.hardwareBacked) + cert.hash = ''; // Clear the hash to invalidate the certificate. + }); } this.set('userCerts_', userCerts); + if (this.selectedUserCertHash_ && !userCerts.find((cert) => { + return cert.hash == this.selectedUserCertHash_; + })) { + this.selectedUserCertHash_ = undefined; + } + this.updateCertError_(); }.bind(this)); }, @@ -501,8 +531,9 @@ Polymer({ this.propertiesReceived_ = true; this.networkProperties = properties; this.setError_(properties.ErrorState); + this.updateCertError_(); - // Set the current shareNetwork_ value when porperties are received. + // Set the current shareNetwork_ value when properties are received. this.setShareNetwork_(); }, @@ -727,7 +758,7 @@ Polymer({ } else { this.set('eapProperties_.Inner', undefined); } - // Set the share vaule to its default when the EAP.Outer value changes. + // Set the share value to its default when the EAP.Outer value changes. this.setShareNetwork_(); }, @@ -904,16 +935,39 @@ Polymer({ /** @private */ updateCertError_: function() { - /** @const */ var certError = 'networkErrorNoUserCertificate'; - if (this.error && this.error != certError) + // If |this.error| was set to something other than a cert error, do not + // change it. + /** @const */ var noCertsError = 'networkErrorNoUserCertificate'; + /** @const */ var noValidCertsError = 'networkErrorNotHardwareBacked'; + if (this.error && this.error != noCertsError && + this.error != noValidCertsError) { return; + } var requireCerts = (this.showEap_ && this.showEap_.UserCert) || (this.showVpn_ && this.showVpn_.UserCert); - this.setError_(requireCerts && !this.userCerts_.length ? certError : ''); + if (!requireCerts) { + this.setError_(''); + return; + } + if (!this.userCerts_.length || this.userCerts_[0].hash == NO_CERTS_HASH) { + this.setError_(noCertsError); + return; + } + var validUserCert = this.userCerts_.find(function(cert) { + return !!cert.hash; + }); + if (!validUserCert) { + this.setError_(noValidCertsError); + return; + } + this.setError_(''); + return; }, /** + * Sets the selected cert if |pem| (serverCa) or |certId| (user) is specified. + * Otherwise sets a default value if no certificate is selected. * @param {string|undefined} pem * @param {string|undefined} certId * @private @@ -936,8 +990,15 @@ Polymer({ if (userCert) this.selectedUserCertHash_ = userCert.hash; } - if (!this.selectedUserCertHash_ && this.userCerts_[0]) - this.selectedUserCertHash_ = this.userCerts_[0].hash; + if (!this.selectedUserCertHash_) { + // Find either the first valid entry or the 'no-certs' entry. + var selectUserCert = this.userCerts_.find(function(cert) { + return !!cert.hash; + }); + if (selectUserCert) + this.selectedUserCertHash_ = selectUserCert.hash; + } + this.updateIsConfigured_(); }, /** @@ -945,6 +1006,9 @@ Polymer({ * @private */ getIsConfigured_: function() { + if (!this.configProperties_) + return false; + if (this.configProperties_.Type == CrOnc.Type.VPN) return this.vpnIsConfigured_(); @@ -1063,13 +1127,22 @@ Polymer({ * @return {boolean} * @private */ + selectedUserCertHashIsValid_: function() { + return !!this.selectedUserCertHash_ && + this.selectedUserCertHash_ != NO_CERTS_HASH; + }, + + /** + * @return {boolean} + * @private + */ eapIsConfigured_: function() { var eap = this.getEap_(this.configProperties_); if (!eap) return false; if (eap.Outer != CrOnc.EAPType.EAP_TLS) return true; - return !!this.selectedUserCertHash_; + return this.selectedUserCertHashIsValid_(); }, /** @@ -1085,10 +1158,11 @@ Polymer({ case VPNConfigType.L2TP_IPSEC_PSK: return !!this.get('L2TP.Username', vpn) && !!this.get('IPsec.PSK', vpn); case VPNConfigType.L2TP_IPSEC_CERT: - return !!this.get('L2TP.Username', vpn) && !!this.selectedUserCertHash_; + return !!this.get('L2TP.Username', vpn) && + this.selectedUserCertHashIsValid_(); case VPNConfigType.OPEN_VPN: return !!this.get('OpenVPN.Username', vpn) && - !!this.selectedUserCertHash_; + this.selectedUserCertHashIsValid_(); } return false; }, @@ -1096,6 +1170,11 @@ Polymer({ /** @private */ getPropertiesToSet_: function() { var propertiesToSet = Object.assign({}, this.configProperties_); + // Do not set AutoConnect by default, the connection manager will set + // it to true on a successful connection. + CrOnc.setTypeProperty(propertiesToSet, 'AutoConnect', undefined); + if (this.guid) + propertiesToSet.GUID = this.guid; var eap = this.getEap_(propertiesToSet); if (eap) this.setEapProperties_(eap); @@ -1127,11 +1206,10 @@ Polymer({ * @private */ getUserCertPkcs11Id_: function() { - var userHash = this.selectedUserCertHash_; - if (!userHash) + if (!this.selectedUserCertHashIsValid_()) return ''; - var userCert = this.userCerts_.find(function(cert) { - return cert.hash == userHash; + var userCert = this.userCerts_.find((cert) => { + return cert.hash == this.selectedUserCertHash_; }); return (userCert && userCert.PKCS11Id) || ''; }, @@ -1203,8 +1281,11 @@ Polymer({ return (chrome.runtime.lastError && chrome.runtime.lastError.message) || ''; }, - /** @private */ - setPropertiesCallback_: function() { + /** + * @param {boolean} connect If true, connect after save. + * @private + */ + setPropertiesCallback_: function(connect) { this.setError_(this.getRuntimeError_()); if (this.error) { console.error('setProperties error: ' + this.guid + ': ' + this.error); @@ -1212,7 +1293,7 @@ Polymer({ return; } var connectState = this.networkProperties.ConnectionState; - if (this.connectOnSave && + if (connect && (!connectState || connectState == CrOnc.ConnectionState.NOT_CONNECTED)) { this.startConnect_(this.guid); @@ -1222,10 +1303,11 @@ Polymer({ }, /** + * @param {boolean} connect If true, connect after save. * @param {string} guid * @private */ - createNetworkCallback_: function(guid) { + createNetworkCallback_: function(connect, guid) { this.setError_(this.getRuntimeError_()); if (this.error) { console.error( @@ -1234,7 +1316,8 @@ Polymer({ this.propertiesSent_ = false; return; } - this.startConnect_(guid); + if (connect) + this.startConnect_(guid); }, /** diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html index 12784fd7a51..d23f9ec5c4b 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html @@ -29,8 +29,8 @@ <div class="control-box"> <paper-input-container always-float-label> - <label id="label">[[label]]</label> - <input is="iron-input" value="{{value::input}}" + <label id="label" slot="label">[[label]]</label> + <input is="iron-input" value="{{value::input}}" slot="input" tabindex="1" disabled="[[disabled]]" aria-label$="[[label]]" type="[[getInputType_(password, showPassword)]]"> </paper-input-container> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html index 31ccb502f47..66dcf2537e8 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.html @@ -14,6 +14,7 @@ [[i18n('networkIPConfigAuto')]] </div> <paper-toggle-button checked="{{automatic_}}" disabled="[[!editable]]" + on-change="onAutomaticChange_" aria-labelledby="autoIPConfigLabel"> </paper-toggle-button> </div> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js index de442adbaf3..4260815ca7f 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js @@ -38,7 +38,6 @@ Polymer({ automatic_: { type: Boolean, value: true, - observer: 'automaticChanged_', }, /** @@ -113,7 +112,7 @@ Polymer({ }, /** @private */ - automaticChanged_: function() { + onAutomaticChange_: function() { if (!this.automatic_) { var defaultIpv4 = { Gateway: '192.168.1.1', diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html index 0f8bc18aa14..4caf352d6bc 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html @@ -90,7 +90,7 @@ <paper-input-container no-label-float> <input id="nameserver[[index]]" is="iron-input" value="[[item]]" disabled="[[!canEdit_(editable, nameserversType_)]]" - on-change="onValueChange_"> + on-change="onValueChange_" slot="input"> </paper-input-container> </template> </div> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html index 3ea4c64f27e..534ce962de2 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.html @@ -44,7 +44,7 @@ <template is="dom-if" if="[[isEditable_( item, 'String', propertyDict, editFieldTypes)]]"> <paper-input-container no-label-float> - <input id="[[item]]" is="iron-input" + <input id="[[item]]" is="iron-input" slot="input" value="[[getPropertyValue_(item, prefix, propertyDict)]]" on-change="onValueChange_"> </paper-input-container> @@ -53,7 +53,7 @@ <template is="dom-if" if="[[isEditable_( item, 'Password', propertyDict, editFieldTypes)]]"> <paper-input-container no-label-float> - <input id="[[item]]" is="iron-input" type="password" + <input id="[[item]]" is="iron-input" type="password" slot="input" value="[[getPropertyValue_(item, prefix, propertyDict)]]" on-change="onValueChange_"> </paper-input-container> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html index 4b328f9145b..1834e1db0f0 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.html @@ -53,10 +53,10 @@ <div class="property-box indented" hidden$="[[!matches_(proxy_.Type, ProxySettingsType_.PAC)]]"> <div>[[i18n('networkProxyAutoConfig')]]</div> - <paper-input no-label-float class="middle" value="{{proxy_.PAC}}" + <paper-input id="pacInput" no-label-float class="middle" + value="{{proxy_.PAC}}" on-change="onPACChange_" disabled="[[!isEditable_('PAC', networkProperties, editable, - useSharedProxies)]]" - on-change="onPACChange_"> + useSharedProxies)]]"> </paper-input> </div> @@ -130,8 +130,8 @@ </network-proxy-exclusions> <div class="layout horizontal"> <paper-input-container no-label-float class="flex"> - <input id="proxyExclusion" is="iron-input"> - <iron-a11y-keys keys="enter" + <input id="proxyExclusion" is="iron-input" slot="input"> + <iron-a11y-keys keys="enter" slot="add-on" on-keys-pressed="onAddProxyExclusionTap_"> </iron-a11y-keys> </paper-input-container> @@ -144,7 +144,7 @@ <paper-button id="saveManualProxy" on-tap="onSaveProxyTap_" class="action-button" disabled="[[!isSaveManualProxyEnabled_(networkProperties, - proxyModified_, proxy_.*)]]"> + proxyIsUserModified_, proxy_.*)]]"> [[i18n('save')]] </paper-button> </div> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js index a1f2056eba8..7dd7aeb8fe8 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js @@ -120,7 +120,7 @@ Polymer({ * override the edited values. * @private {boolean} */ - proxyModified_: false, + proxyIsUserModified_: false, /** @override */ attached: function() { @@ -132,14 +132,14 @@ Polymer({ * is updated correctly. */ reset: function() { - this.proxyModified_ = false; + this.proxyIsUserModified_ = false; this.proxy_ = this.createDefaultProxySettings_(); this.updateProxy_(); }, /** @private */ networkPropertiesChanged_: function() { - if (this.proxyModified_) + if (this.proxyIsUserModified_) return; // Ignore update. this.updateProxy_(); }, @@ -221,13 +221,13 @@ Polymer({ // Set this.proxy_ after dom-repeat has been stamped. this.async(() => { this.proxy_ = proxy; - this.proxyModified_ = false; + this.proxyIsUserModified_ = false; }); }, /** @private */ useSameProxyChanged_: function() { - this.proxyModified_ = true; + this.proxyIsUserModified_ = true; }, /** @@ -283,7 +283,7 @@ Polymer({ return; } this.fire('proxy-change', {field: 'ProxySettings', value: proxy}); - this.proxyModified_ = false; + this.proxyIsUserModified_ = false; }, /** @@ -296,10 +296,41 @@ Polymer({ var type = /** @type {chrome.networkingPrivate.ProxySettingsType} */ ( target.value); this.set('proxy_.Type', type); - if (type == CrOnc.ProxySettingsType.MANUAL) - this.proxyModified_ = true; - else + var proxyTypeChangeIsReady; + var elementToFocus; + switch (type) { + case CrOnc.ProxySettingsType.DIRECT: + case CrOnc.ProxySettingsType.WPAD: + // No addtional values are required, send the type change. + proxyTypeChangeIsReady = true; + break; + case CrOnc.ProxySettingsType.PAC: + elementToFocus = this.$$('#pacInput'); + // If a PAC is already defined, send the type change now, otherwise wait + // until the user provides a PAC value. + proxyTypeChangeIsReady = !!this.proxy_.PAC; + break; + case CrOnc.ProxySettingsType.MANUAL: + // Manual proxy configuration includes multiple input fields, so wait + // until the 'send' button is clicked. + proxyTypeChangeIsReady = false; + elementToFocus = this.$$('#manualProxy network-proxy-input'); + break; + } + + // If the new proxy type is fully configured, send it, otherwise set + // |proxyIsUserModified_| to true so that property updates do not + // overwrite user changes. + if (proxyTypeChangeIsReady) this.sendProxyChange_(); + else + this.proxyIsUserModified_ = true; + + if (elementToFocus) { + this.async(() => { + elementToFocus.focus(); + }); + } }, /** @private */ @@ -309,7 +340,7 @@ Polymer({ /** @private */ onProxyInputChange_: function() { - this.proxyModified_ = true; + this.proxyIsUserModified_ = true; }, /** @@ -324,7 +355,7 @@ Polymer({ this.push('proxy_.ExcludeDomains', value); // Clear input. this.$.proxyExclusion.value = ''; - this.proxyModified_ = true; + this.proxyIsUserModified_ = true; }, /** @@ -333,7 +364,7 @@ Polymer({ * @private */ onProxyExclusionsChange_: function(event) { - this.proxyModified_ = true; + this.proxyIsUserModified_ = true; }, /** @private */ @@ -406,7 +437,7 @@ Polymer({ * @private */ isSaveManualProxyEnabled_: function() { - if (!this.proxyModified_) + if (!this.proxyIsUserModified_) return false; var manual = this.proxy_.Manual; var httpHost = this.get('HTTPProxy.Host', manual); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.html index f574252c285..4438899755c 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.html @@ -9,7 +9,7 @@ <template> <style include="network-shared cr-hidden-style iron-flex"> iron-icon { - @apply(--cr-actionable); + @apply --cr-actionable; margin: 5px; } diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.html index a1104bde59f..940a9433450 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.html @@ -36,12 +36,12 @@ <div id="container"> <div id="label">[[label]]</div> <paper-input-container id="host" no-label-float> - <input is="iron-input" bind-value="{{value.Host}}" + <input is="iron-input" bind-value="{{value.Host}}" slot="input" disabled="[[!editable]]" on-change="onValueChange_"> </paper-input-container> <div>[[i18n('networkProxyPort')]]</div> <paper-input-container id="port" no-label-float> - <input is="iron-input" bind-value="{{value.Port}}" + <input is="iron-input" bind-value="{{value.Port}}" slot="input" disabled="[[!editable]]" on-change="onValueChange_"> </paper-input-container> </div> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js index 63609b074ce..cb22d24ed38 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js @@ -43,6 +43,10 @@ Polymer({ }, }, + focus: function() { + this.$$('input').focus(); + }, + /** * Event triggered when an input value changes. * @private diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_shared_css.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_shared_css.html index 3d6b9eee8d8..7c2deb92100 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_shared_css.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_shared_css.html @@ -19,7 +19,7 @@ } .property-box { - @apply(--cr-section); + @apply --cr-section; border-top: none; min-height: var(--cr-section-min-height); padding: 0; @@ -59,7 +59,7 @@ } .secondary { - @apply(--cr-secondary-text); + @apply --cr-secondary-text; } paper-input-container { diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/compiled_resources2.gyp b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/compiled_resources2.gyp new file mode 100644 index 00000000000..eff59d15d7c --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/compiled_resources2.gyp @@ -0,0 +1,16 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'targets': [ + { + 'target_name': 'pin_keyboard', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', + '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-button/compiled_resources2.gyp:paper-button-extracted', + '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted', + ], + 'includes': ['../../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + ], +} diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html new file mode 100644 index 00000000000..ad554340880 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html @@ -0,0 +1,266 @@ +<!-- TODO(crbug.com/603217): Use i18n instead of string literals. Figure out + what i18n to use for keypad, ie, does 1 ABC make + sense in every scenario? --> + +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html"> + +<iron-iconset-svg name="pin-keyboard" size="24"> + <svg> + <defs> + <!-- + Inlined from Polymer's iron-icons to avoid importing everything. + See http://goo.gl/Y1OdAq for instructions on adding additional icons. + --> + <g id="arrow-forward"> + <path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"> + </path> + </g> + <g id="backspace"> + <path d="M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53.9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z"> + </g> + </defs> + </svg> +</iron-iconset-svg> + +<dom-module id="pin-keyboard"> + <template> + <style include="cr-shared-style"> + :host { + outline: none; + } + + #root { + direction: ltr; + display: block; + } + + .row { + display: flex; + } + + :host([enable-password]) #pinInputDiv { + display: none; + } + + .bottom-row { + margin-bottom: 6px; + } + + .backspace-button-container { + position: relative; + } + + .backspace-button-container paper-ripple { + left: var(--pin-keyboard-backspace-paper-ripple-offset, 0); + top: var(--pin-keyboard-backspace-paper-ripple-offset, 0); + } + + .digit-button { + align-items: center; + background: none; + border-radius: 0; + box-sizing: border-box; + color: #000; + display: flex; + flex-direction: column; + height: 48px; + justify-content: center; + margin: 0; + min-height: 48px; + min-width: 48px; + opacity: 0.87px; + width: 60px; + + @apply --pin-keyboard-digit-button; + } + + .digit-button.backspace-button { + color: var(--pin-keyboard-backspace-color, #000); + left: 0; + opacity: var(--pin-keyboard-backspace-opacity, --dark-primary-opacity); + padding: 14px; + position: absolute; + top: 0; + } + + .digit-button.backspace-button:not([has-content]) { + opacity: 0.34; + } + + .digit-button inner-text { + display: flex; + flex-direction: column; + font-family: 'Roboto'; + } + + .letter { + color: var(--pin-keyboard-letter-color, --paper-blue-grey-700); + font-size: 9px; + margin-top: 4px; + } + + .number { + color: var(--pin-keyboard-number-color, --paper-blue-grey-700); + font-size: 20px; + height: 52px; + } + + paper-ripple { + border-radius: 100px; + color: #000; + height: 48px; + left: 6px; + width: 48px; + + @apply --pin-keyboard-paper-ripple; + } + + #pinInput { + background-color: white; + border: 0; + box-sizing: border-box; + font-face: Roboto-Regular; + font-size: 13px; + height: 43px; + left: 0; + opacity: var(--dark-secondary-opacity); + outline: 0; + position: relative; + text-align: center; + width: 180px; + + --paper-input-container-input: { + caret-color: var(--paper-input-container-focus-color); + } + } + + #pinInput[has-content] { + opacity: var(--dark-primary-opacity); + } + + #pinInput[is-input-rtl] { + direction: rtl; + } + + #pinInput[type=number]::-webkit-inner-spin-button, + #pinInput[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + + :host([has-error]) #pinInput { + --paper-input-container-focus-color: var(--paper-red-500); + } + + /* Ensure that all children of paper-button do not consume events. This + * simplifies the event handler code. */ + paper-button * { + pointer-events: none; + } + </style> + + <div id="root" on-contextmenu="onContextMenu_"> + <div id="pinInputDiv" class="row"> + <paper-input id="pinInput" type="password" no-label-float + value="[[value]]" + is-input-rtl$="[[isInputRtl_(value)]]" + has-content$="[[hasInput_(value)]]" + label="[[getInputPlaceholder_(enablePassword)]]" + on-keydown="onInputKeyDown_"> + </paper-input> + </div> + <slot select="[problem]"></slot> + <div class="row"> + <paper-button class="digit-button" on-tap="onNumberTap_" value="1" + noink> + <inner-text class="number">[[i18n('pinKeyboard1')]]</inner-text> + <paper-ripple> + </paper-button> + <paper-button class="digit-button" on-tap="onNumberTap_" value="2" + noink> + <inner-text class="number">[[i18n('pinKeyboard2')]]</inner-text> + <inner-text class="letter">ABC</inner-text> + <paper-ripple> + </paper-button> + <paper-button class="digit-button" on-tap="onNumberTap_" value="3" + noink> + <inner-text class="number">[[i18n('pinKeyboard3')]]</inner-text> + <inner-text class="letter">DEF</inner-text> + <paper-ripple> + </paper-button> + </div> + <div class="row"> + <paper-button class="digit-button" on-tap="onNumberTap_" value="4" + noink> + <inner-text class="number">[[i18n('pinKeyboard4')]]</inner-text> + <inner-text class="letter">GHI</inner-text> + <paper-ripple> + </paper-button> + <paper-button class="digit-button" on-tap="onNumberTap_" value="5" + noink> + <inner-text class="number">[[i18n('pinKeyboard5')]]</inner-text> + <inner-text class="letter">JKL</inner-text> + <paper-ripple> + </paper-button> + <paper-button class="digit-button" on-tap="onNumberTap_" value="6" + noink> + <inner-text class="number">[[i18n('pinKeyboard6')]]</inner-text> + <inner-text class="letter">MNO</inner-text> + <paper-ripple> + </paper-button> + </div> + <div class="row"> + <paper-button class="digit-button" on-tap="onNumberTap_" value="7" + noink> + <inner-text class="number">[[i18n('pinKeyboard7')]]</inner-text> + <inner-text class="letter">PQRS</inner-text> + <paper-ripple> + </paper-button> + <paper-button class="digit-button" on-tap="onNumberTap_" value="8" + noink> + <inner-text class="number">[[i18n('pinKeyboard8')]]</inner-text> + <inner-text class="letter">TUV</inner-text> + <paper-ripple> + </paper-button> + <paper-button class="digit-button" on-tap="onNumberTap_" value="9" + noink> + <inner-text class="number">[[i18n('pinKeyboard9')]]</inner-text> + <inner-text class="letter">WXYZ</inner-text> + <paper-ripple> + </paper-button> + </div> + <div class="row bottom-row"> + <div class="digit-button"></div> + <paper-button class="digit-button" on-tap="onNumberTap_" value="0" + noink> + <inner-text class="number">[[i18n('pinKeyboard0')]]</inner-text> + <inner-text class="letter">+</inner-text> + <paper-ripple> + </paper-button> + <div class="backspace-button-container"> + <paper-icon-button class="digit-button backspace-button" + has-content$="[[hasInput_(value)]]" + icon="pin-keyboard:backspace" + on-pointerdown="onBackspacePointerDown_" + on-pointerout="clearAndReset_" + on-pointerup="onBackspacePointerUp_" + aria-label="[[i18n('pinKeyboardDeleteAccessibleName')]]" + noink> + </paper-icon-button> + <paper-ripple> + </div> + </div> + </div> + </template> + <script src="pin_keyboard.js"></script> +</dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js new file mode 100644 index 00000000000..2ebcaaf4724 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js @@ -0,0 +1,416 @@ +// 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. + +/** + * @fileoverview + * 'pin-keyboard' is a keyboard that can be used to enter PINs or more generally + * numeric values. + * + * Properties: + * value: The value of the PIN keyboard. Writing to this property will adjust + * the PIN keyboard's value. + * + * Events: + * pin-change: Fired when the PIN value has changed. The PIN is available at + * event.detail.pin. + * submit: Fired when the PIN is submitted. The PIN is available at + * event.detail.pin. + * + * Example: + * <pin-keyboard on-pin-change="onPinChange" on-submit="onPinSubmit"> + * </pin-keyboard> + */ + +(function() { + +/** + * Once auto backspace starts, the time between individual backspaces. + * @type {number} + * @const + */ +var REPEAT_BACKSPACE_DELAY_MS = 150; + +/** + * How long the backspace button must be held down before auto backspace + * starts. + * @type {number} + * @const + */ +var INITIAL_BACKSPACE_DELAY_MS = 500; + +/** + * The key codes of the keys allowed to be used on the pin input, in addition to + * number keys. Currently we allow backspace(8), tab(9), left(37) and right(39). + * @type {Array<number>} + * @const + */ +var PIN_INPUT_ALLOWED_NON_NUMBER_KEY_CODES = [8, 9, 37, 39]; + +Polymer({ + is: 'pin-keyboard', + + behaviors: [ + I18nBehavior, + ], + + properties: { + /** + * Whether or not the keyboard's input element should be numerical + * or password. + * @private + */ + enablePassword: { + type: Boolean, + value: false, + }, + + /** + * The password element the pin keyboard is associated with. If this is not + * set, then a default input element is shown and used. + * @type {?Element} + * @private + */ + passwordElement: { + type: Object, + value: function() { + return this.$.pinInput.inputElement; + }, + observer: 'onPasswordElementAttached_', + }, + + /** + * The intervalID used for the backspace button set/clear interval. + * @private + */ + repeatBackspaceIntervalId_: { + type: Number, + value: 0, + }, + + /** + * The timeoutID used for the auto backspace. + * @private + */ + startAutoBackspaceId_: { + type: Number, + value: 0, + }, + + /** + * Whether or not to show the default pin input. + * @private + */ + showPinInput_: { + type: Boolean, + value: false, + }, + + /** + * The value stored in the keyboard's input element. + * @private + */ + value: { + type: String, + notify: true, + value: '', + observer: 'onPinValueChange_', + }, + }, + + /** + * Called when a password element is attached to the pin keyboard. + * @param {HTMLInputElement} inputElement The PIN keyboard's input element. + * @private + */ + onPasswordElementAttached_: function(inputElement) { + this.showPinInput_ = inputElement == this.$.pinInput.inputElement; + inputElement.addEventListener('input', this.handleInputChanged_.bind(this)); + }, + + /** + * Called when the user uses the keyboard to enter a value into the input + * element. + * @param {Event} event The event object. + * @private + */ + handleInputChanged_: function(event) { + this.value = event.target.value; + }, + + /** + * Gets the selection start of the input field. + * @type {number} + * @private + */ + get selectionStart_() { + return this.passwordElement.selectionStart; + }, + + /** + * Gets the selection end of the input field. + * @type {number} + * @private + */ + get selectionEnd_() { + return this.passwordElement.selectionEnd; + }, + + /** + * Sets the selection start of the input field. + * @param {number} start The new selection start of the input element. + * @private + */ + set selectionStart_(start) { + this.passwordElement.selectionStart = start; + }, + + /** + * Sets the selection end of the input field. + * @param {number} end The new selection end of the input element. + * @private + */ + set selectionEnd_(end) { + this.passwordElement.selectionEnd = end; + }, + + /** + * Transfers blur to the input element. + */ + blur: function() { + this.passwordElement.blur(); + }, + + /** + * Transfers focus to the input element. This should not bring up the virtual + * keyboard, if it is enabled. After focus, moves the caret to the correct + * location if specified. + * @param {number=} opt_selectionStart + * @param {number=} opt_selectionEnd + */ + focus: function(opt_selectionStart, opt_selectionEnd) { + setTimeout(function() { + this.passwordElement.focus(); + this.selectionStart_ = opt_selectionStart || 0; + this.selectionEnd_ = opt_selectionEnd || 0; + }.bind(this), 0); + }, + + /** + * Called when a keypad number has been tapped. + * @param {Event} event The event object. + * @private + */ + onNumberTap_: function(event) { + var numberValue = event.target.getAttribute('value'); + + // Add the number where the caret is, then update the selection range of the + // input element. + var selectionStart = this.selectionStart_; + this.value = this.value.substring(0, this.selectionStart_) + numberValue + + this.value.substring(this.selectionEnd_); + + // If a number button is clicked, we do not want to switch focus to the + // button, therefore we transfer focus back to the input, but if a number + // button is tabbed into, it should keep focus, so users can use tab and + // spacebar/return to enter their PIN. + if (!event.target.receivedFocusFromKeyboard) + this.focus(selectionStart + 1, selectionStart + 1); + event.stopImmediatePropagation(); + }, + + /** Fires a submit event with the current PIN value. */ + firePinSubmitEvent_: function() { + this.fire('submit', {pin: this.value}); + }, + + /** + * Fires an update event with the current PIN value. The event will only be + * fired if the PIN value has actually changed. + * @param {string} value + * @param {string} previous + */ + onPinValueChange_: function(value, previous) { + if (value != previous) { + this.passwordElement.value = this.value; + this.fire('pin-change', {pin: value}); + } + }, + + /** + * Called when the user wants to erase the last character of the entered + * PIN value. + * @private + */ + onPinClear_: function() { + // If the input is shown, clear the text based on the caret location or + // selected region of the input element. If it is just a caret, remove the + // character in front of the caret. + var selectionStart = this.selectionStart_; + var selectionEnd = this.selectionEnd_; + if (selectionStart == selectionEnd && selectionStart) + selectionStart--; + + this.value = this.value.substring(0, selectionStart) + + this.value.substring(selectionEnd); + + // Move the caret or selected region to the correct new place. + this.selectionStart_ = selectionStart; + this.selectionEnd_ = selectionStart; + }, + + /** + * Called when the user presses or touches the backspace button. Starts a + * timer which starts an interval to repeatedly backspace the pin value until + * the interval is cleared. + * @param {Event} event The event object. + * @private + */ + onBackspacePointerDown_: function(event) { + this.startAutoBackspaceId_ = setTimeout(function() { + this.repeatBackspaceIntervalId_ = + setInterval(this.onPinClear_.bind(this), REPEAT_BACKSPACE_DELAY_MS); + }.bind(this), INITIAL_BACKSPACE_DELAY_MS); + + if (!event.target.receivedFocusFromKeyboard) + this.focus(this.selectionStart_, this.selectionEnd_); + event.stopImmediatePropagation(); + }, + + /** + * Helper function which clears the timer / interval ids and resets them. + * @private + */ + clearAndReset_: function() { + clearInterval(this.repeatBackspaceIntervalId_); + this.repeatBackspaceIntervalId_ = 0; + clearTimeout(this.startAutoBackspaceId_); + this.startAutoBackspaceId_ = 0; + }, + + /** + * Called when the user unpresses or untouches the backspace button. Stops the + * interval callback and fires a backspace event if there is no interval + * running. + * @param {Event} event The event object. + * @private + */ + onBackspacePointerUp_: function(event) { + // If an interval has started, do not fire event on pointer up. + if (!this.repeatBackspaceIntervalId_) + this.onPinClear_(); + this.clearAndReset_(); + + // Since on-down gives the input element focus, the input element will + // already have focus when on-up is called. This will actually bring up the + // virtual keyboard, even if focus() is wrapped in a setTimeout. Blur the + // input element first to workaround this. + this.blur(); + if (!event.target.receivedFocusFromKeyboard) + this.focus(this.selectionStart_, this.selectionEnd_); + event.stopImmediatePropagation(); + }, + + /** + * Helper function to check whether a given |event| should be processed by + * the numeric only input. + * @param {Event} event The event object. + * @private + */ + isValidEventForInput_: function(event) { + // Valid if the key is a number, and shift is not pressed. + if ((event.keyCode >= 48 && event.keyCode <= 57) && !event.shiftKey) + return true; + + // Valid if the key is one of the selected special keys defined in + // |PIN_INPUT_ALLOWED_NON_NUMBER_KEY_CODES|. + if (PIN_INPUT_ALLOWED_NON_NUMBER_KEY_CODES.indexOf(event.keyCode) > -1) + return true; + + // Valid if the key is CTRL+A to allow users to quickly select the entire + // PIN. + if (event.keyCode == 65 && event.ctrlKey) + return true; + + // The rest of the keys are invalid. + return false; + }, + + /** + * Called when a key event is pressed while the input element has focus. + * @param {Event} event The event object. + * @private + */ + onInputKeyDown_: function(event) { + // Up/down pressed, swallow the event to prevent the input value from + // being incremented or decremented. + if (event.keyCode == 38 || event.keyCode == 40) { + event.preventDefault(); + return; + } + + // Enter pressed. + if (event.keyCode == 13) { + this.firePinSubmitEvent_(); + event.preventDefault(); + return; + } + + // Do not pass events that are not numbers or special keys we care about. We + // use this instead of input type number because there are several issues + // with input type number, such as no selectionStart/selectionEnd and + // entered non numbers causes the caret to jump to the left. + if (!this.isValidEventForInput_(event)) { + event.preventDefault(); + return; + } + }, + + /** + * Disables the backspace button if nothing is entered. + * @param {string} value + * @private + */ + hasInput_: function(value) { + return value.length > 0; + }, + + /** + * Computes the value of the pin input placeholder. + * @param {boolean} enablePassword + * @private + */ + getInputPlaceholder_: function(enablePassword) { + return enablePassword ? this.i18n('pinKeyboardPlaceholderPinPassword') : + this.i18n('pinKeyboardPlaceholderPin'); + }, + + /** + * Computes the direction of the pin input. + * @param {string} password + * @private + */ + isInputRtl_: function(password) { + // +password will convert a string to a number or to NaN if that's not + // possible. Number.isInteger will verify the value is not a NaN and that it + // does not contain decimals. + // This heuristic will fail for inputs like '1.0'. + // + // Since we still support users entering their passwords through the PIN + // keyboard, we swap the input box to rtl when we think it is a password + // (just numbers), if the document direction is rtl. + return (document.dir == 'rtl') && !Number.isInteger(+password); + }, + + /** + * Catch and stop propagation of context menu events since we the backspace + * button can be held down on touch. + * @param {!Event} e + * @private + */ + onContextMenu_: function(e) { + e.preventDefault(); + e.stopPropagation(); + }, +}); +})(); diff --git a/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp b/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp index 1e198676684..46a47e79eac 100644 --- a/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp +++ b/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp @@ -208,4 +208,15 @@ type="chrome_html" compress="gzip" /> </if> + <if expr="chromeos"> + <!-- Shared between settings and OOBE, which is not vulcanized. --> + <structure name="IDR_WEBUI_CHROMEOS_QUICK_UNLOCK_PIN_KEYBOARD_HTML" + file="cr_components/chromeos/quick_unlock/pin_keyboard.html" + type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_CHROMEOS_QUICK_UNLOCK_PIN_KEYBOARD_JS" + file="cr_components/chromeos/quick_unlock/pin_keyboard.js" + type="chrome_html" + compress="gzip" /> + </if> </grit-part> diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js index 67e7b727be0..3e6255cccb1 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js +++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js @@ -77,6 +77,7 @@ Polymer({ this.$.cameraVideo.addEventListener('canplay', function() { this.$.userImageStreamCrop.classList.add('preview'); this.cameraOnline_ = true; + this.focusTakePhotoButton(); }.bind(this)); this.startCamera(); }, diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js index e604c76d55e..2b878fd620d 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js +++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js @@ -78,8 +78,7 @@ Polymer({ if (connectionState == this.connectionState_) return; this.connectionState_ = connectionState; - if (connectionState == CrOnc.ConnectionState.CONNECTED) - this.fire('network-connected', this.networkState); + this.fire('network-connect-changed', this.networkState); }, /** @@ -104,9 +103,7 @@ Polymer({ * @private */ isStateTextVisible_: function() { - return !!this.networkState && - (this.networkState.ConnectionState != - CrOnc.ConnectionState.NOT_CONNECTED); + return !!this.networkState && !!this.getNetworkStateText_(); }, /** @@ -115,16 +112,20 @@ Polymer({ * @private */ getNetworkStateText_: function() { - if (!this.isStateTextVisible_()) + if (!this.networkState) return ''; - var state = this.networkState.ConnectionState; - // For Cellular, an empty ConnectionState indicates that the device is - // still initializing. - if (!state && this.networkState.Type == CrOnc.Type.CELLULAR) - return CrOncStrings.networkListItemInitializing; - if (state == CrOnc.ConnectionState.CONNECTED) + var connectionState = this.networkState.ConnectionState; + if (this.networkState.Type == CrOnc.Type.CELLULAR) { + // For Cellular, an empty ConnectionState indicates that the device is + // still initializing. + if (!connectionState) + return CrOncStrings.networkListItemInitializing; + if (this.networkState.Cellular && this.networkState.Cellular.Scanning) + return CrOncStrings.networkListItemScanning; + } + if (connectionState == CrOnc.ConnectionState.CONNECTED) return CrOncStrings.networkListItemConnected; - if (state == CrOnc.ConnectionState.CONNECTING) + if (connectionState == CrOnc.ConnectionState.CONNECTING) return CrOncStrings.networkListItemConnecting; return ''; }, diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.html b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.html index 8fea14ce971..def03d72acb 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.html +++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.html @@ -15,7 +15,6 @@ </style> <cr-network-list id="networkList" on-selected="onNetworkListItemSelected_" - on-network-connected="onNetworkConnected_" networks="[[networkStateList_]]" custom-items="[[customItems]]" show-buttons="[[showButtons]]" no-bottom-scroll-border="[[noBottomScrollBorder]]"> diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js index 2a3afa75347..26a37dc478f 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js +++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js @@ -54,10 +54,16 @@ Polymer({ return []; }, }, + + /** + * Cached Cellular Device state or undefined if there is no Cellular device. + * @private {!CrOnc.DeviceStateProperties|undefined} deviceState + */ + cellularDeviceState_: Object, }, - /** @type {string} */ - defaultStateGuid_: '', + /** @type {!CrOnc.NetworkStateProperties|undefined} */ + defaultNetworkState_: undefined, focus: function() { this.$.networkList.focus(); @@ -124,60 +130,76 @@ Polymer({ * @private */ getDeviceStatesCallback_: function(deviceStates) { - var uninitializedCellular = deviceStates.find(function(device) { - return device.Type == CrOnc.Type.CELLULAR && - device.State == CrOnc.DeviceState.UNINITIALIZED; - }); - this.getNetworkStates_(uninitializedCellular); - }, - - /** - * @param {!CrOnc.DeviceStateProperties|undefined} uninitializedCellular - * A cellular device state to pass to |getNetworksCallback_| or undefined. - */ - getNetworkStates_: function(uninitializedCellular) { var filter = { networkType: chrome.networkingPrivate.NetworkType.ALL, visible: true, configured: false }; - chrome.networkingPrivate.getNetworks(filter, function(states) { - this.getNetworksCallback_(uninitializedCellular, states); + chrome.networkingPrivate.getNetworks(filter, function(networkStates) { + this.getNetworksCallback_(deviceStates, networkStates); }.bind(this)); }, /** - * @param {!CrOnc.DeviceStateProperties|undefined} uninitializedCellular - * If defined, prepends a Cellular state with no ConnectionState to - * represent an uninitialized Cellular device. - * @param {!Array<!CrOnc.NetworkStateProperties>} states + * @param {!Array<!CrOnc.DeviceStateProperties>} deviceStates + * @param {!Array<!CrOnc.NetworkStateProperties>} networkStates * @private */ - getNetworksCallback_: function(uninitializedCellular, states) { - if (uninitializedCellular) { - states.unshift({ - GUID: '', - Type: uninitializedCellular.Type, - }); + getNetworksCallback_: function(deviceStates, networkStates) { + this.cellularDeviceState_ = deviceStates.find(function(device) { + return device.Type == CrOnc.Type.CELLULAR; + }); + if (this.cellularDeviceState_) + this.ensureCellularNetwork_(networkStates); + this.networkStateList_ = networkStates; + var defaultNetwork; + if (networkStates.length > 0) { + // Handle an edge case where Ethernet is connecting. + if (networkStates.length > 1 && + networkStates[0].ConnectionState == + CrOnc.ConnectionState.CONNECTING && + networkStates[1].ConnectionState == CrOnc.ConnectionState.CONNECTED) { + defaultNetwork = networkStates[1]; + } else { + defaultNetwork = networkStates[0]; + } + } else if (!this.defaultNetworkState_) { + return; // No change } - this.networkStateList_ = states; - var defaultState = (this.networkStateList_.length > 0 && - this.networkStateList_[0].ConnectionState == - CrOnc.ConnectionState.CONNECTED) ? - this.networkStateList_[0] : - null; - - if (!defaultState && !this.defaultStateGuid_) - return; - - // defaultState.GUID must never be empty. - assert(!defaultState || defaultState.GUID); + if (defaultNetwork && this.defaultNetworkState_ && + defaultNetwork.GUID == this.defaultNetworkState_.GUID && + defaultNetwork.ConnectionState == + this.defaultNetworkState_.ConnectionState) { + return; // No change to network or ConnectionState + } + this.defaultNetworkState_ = + /** @type {!CrOnc.NetworkStateProperties|undefined} */ ( + Object.assign({}, defaultNetwork)); + this.fire('default-network-changed', defaultNetwork); + }, - if (defaultState && defaultState.GUID == this.defaultStateGuid_) + /** + * Modifies |networkStates| to include a cellular network if none exists. + * @param {!Array<!CrOnc.NetworkStateProperties>} networkStates + * @private + */ + ensureCellularNetwork_: function(networkStates) { + if (networkStates.find(function(network) { + return network.Type == CrOnc.Type.CELLULAR; + })) { return; - - this.defaultStateGuid_ = defaultState ? defaultState.GUID : ''; - this.fire('default-network-changed', defaultState); + } + // Add a Cellular network after the Ethernet network if it exists. + var idx = networkStates.length > 0 && + networkStates[0].Type == CrOnc.Type.ETHERNET ? + 1 : + 0; + var cellular = { + GUID: '', + Type: CrOnc.Type.CELLULAR, + Cellular: {Scanning: this.cellularDeviceState_.Scanning} + }; + networkStates.splice(idx, 0, cellular); }, /** @@ -194,6 +216,18 @@ Polymer({ return; } + // NOTE: This isn't used by OOBE (no handle-network-item-selected). + // TODO(stevenjb): Remove custom OOBE handling. + if (state.Type == CrOnc.Type.CELLULAR && this.cellularDeviceState_) { + var cellularDevice = this.cellularDeviceState_; + // If Cellular is not enabled and not SIM locked, enable Cellular. + if (cellularDevice.State != CrOnc.DeviceState.ENABLED && + (!cellularDevice.SIMLockStatus || + !cellularDevice.SIMLockStatus.LockType)) { + chrome.networkingPrivate.enableNetworkType(CrOnc.Type.CELLULAR); + } + } + if (state.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED) return; @@ -203,14 +237,4 @@ Polymer({ console.error('networkingPrivate.startConnect error: ' + lastError); }); }, - - /** - * Event triggered when a cr-network-list-item becomes connected. - * @param {!{target: HTMLElement, detail: !CrOnc.NetworkStateProperties}} e - * @private - */ - onNetworkConnected_: function(e) { - if (e.detail && e.detail.GUID != this.defaultStateGuid_) - this.refreshNetworks(); - }, }); diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js index 5a7ed921c7b..b6671b12291 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js +++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js @@ -30,6 +30,7 @@ * networkListItemConnecting: string, * networkListItemConnectingTo: string, * networkListItemInitializing: string, + * networkListItemScanning: string, * networkListItemNotConnected: string, * networkListItemNoNetwork: string, * vpnNameTemplate: string, @@ -498,7 +499,8 @@ CrOnc.setValidStaticIPConfig = function(config, properties) { * @param {!chrome.networkingPrivate.NetworkConfigProperties} properties * The ONC property dictionary to modify. * @param {string} key The property key which may be nested, e.g. 'Foo.Bar'. - * @param {!CrOnc.NetworkPropertyType} value The property value to set. + * @param {!CrOnc.NetworkPropertyType|undefined} value The property value to + * set. If undefined the property will be removed. */ CrOnc.setProperty = function(properties, key, value) { while (true) { @@ -511,7 +513,10 @@ CrOnc.setProperty = function(properties, key, value) { properties = properties[keyComponent]; key = key.substr(index + 1); } - properties[key] = value; + if (value === undefined) + delete properties[key]; + else + properties[key] = value; }; /** @@ -519,7 +524,8 @@ CrOnc.setProperty = function(properties, key, value) { * @param {!chrome.networkingPrivate.NetworkConfigProperties} properties The * ONC properties to set. properties.Type must be set already. * @param {string} key The type property key, e.g. 'AutoConnect'. - * @param {!CrOnc.NetworkPropertyType} value The property value to set. + * @param {!CrOnc.NetworkPropertyType|undefined} value The property value to + * set. If undefined the property will be removed. */ CrOnc.setTypeProperty = function(properties, key, value) { if (properties.Type == undefined) { diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp b/chromium/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp index c3698cf0147..5b542f023a5 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp +++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp @@ -9,6 +9,7 @@ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util', '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:focus_without_ink', + '<(EXTERNS_GYP):pending', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html index 05ca3cc16ce..70acc097ff2 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html +++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html @@ -21,7 +21,7 @@ background-color: transparent; } - :host ::content .dropdown-item { + :host ::slotted(.dropdown-item) { background: none; border: none; border-radius: 0; @@ -35,20 +35,20 @@ width: 100%; } - :host ::content .dropdown-item:not([hidden]) { + :host ::slotted(.dropdown-item:not([hidden])) { align-items: center; display: flex; } - :host ::content .dropdown-item[disabled] { + :host ::slotted(.dropdown-item[disabled]) { opacity: 0.65; } - :host ::content .dropdown-item:not([disabled]) { - @apply(--cr-actionable); + :host ::slotted(.dropdown-item:not([disabled])) { + @apply --cr-actionable; } - :host ::content .dropdown-item:focus { + :host ::slotted(.dropdown-item:focus) { background-color: var(--paper-grey-300); outline: none; } @@ -58,7 +58,7 @@ } </style> <div class="item-wrapper" tabindex="-1" role="menu"> - <content select=".dropdown-item,hr" id="contentNode"></content> + <slot name="item" id="contentNode"></slot> </div> </template> <script src="cr_action_menu.js"></script> diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js index d524c5433cf..31613726bcc 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js +++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js @@ -4,6 +4,22 @@ /** * @typedef {{ + * top: (number|undefined), + * left: (number|undefined), + * width: (number|undefined), + * height: (number|undefined), + * anchorAlignmentX: (number|undefined), + * anchorAlignmentY: (number|undefined), + * minX: (number|undefined), + * minY: (number|undefined), + * maxX: (number|undefined), + * maxY: (number|undefined), + * }} + */ +var ShowAtConfig; + +/** + * @typedef {{ * top: number, * left: number, * width: (number|undefined), @@ -16,7 +32,7 @@ * maxY: (number|undefined), * }} */ -var ShowConfig; +var ShowAtPositionConfig; /** * @enum {number} @@ -81,7 +97,7 @@ function getStartPointWithAnchor( /** * @private - * @return {!ShowConfig} + * @return {!ShowAtPositionConfig} */ function getDefaultShowConfig() { var doc = document.scrollingElement; @@ -124,10 +140,25 @@ Polymer({ /** @private {?PolymerDomApi.ObserveHandle} */ contentObserver_: null, + /** @private {?ResizeObserver} */ + resizeObserver_: null, + + /** @private {?ShowAtPositionConfig} */ + lastConfig_: null, + hostAttributes: { tabindex: 0, }, + properties: { + // Setting this flag will make the menu listen for content size changes and + // reposition to its anchor accordingly. + autoReposition: { + type: Boolean, + value: false, + }, + }, + listeners: { 'keydown': 'onKeyDown_', 'mouseover': 'onMouseover_', @@ -147,6 +178,11 @@ Polymer({ Polymer.dom(this.$.contentNode).unobserveNodes(this.contentObserver_); this.contentObserver_ = null; } + + if (this.resizeObserver_) { + this.resizeObserver_.disconnect(); + this.resizeObserver_ = null; + } }, /** @@ -251,12 +287,15 @@ Polymer({ cr.ui.focusWithoutInk(assert(this.anchorElement_)); this.anchorElement_ = null; } + if (this.lastConfig_) { + this.lastConfig_ = null; + } }, /** * Shows the menu anchored to the given element. * @param {!Element} anchorElement - * @param {ShowConfig=} opt_config + * @param {ShowAtConfig=} opt_config */ showAt: function(anchorElement, opt_config) { this.anchorElement_ = anchorElement; @@ -265,7 +304,7 @@ Polymer({ this.anchorElement_.scrollIntoViewIfNeeded(); var rect = this.anchorElement_.getBoundingClientRect(); - this.showAtPosition(/** @type {ShowConfig} */ (Object.assign( + this.showAtPosition(/** @type {ShowAtPositionConfig} */ (Object.assign( { top: rect.top, left: rect.left, @@ -302,7 +341,7 @@ Polymer({ * (BEFORE_END, AFTER_START), whereas centering the menu below the bottom * edge of the anchor would use (CENTER, AFTER_END). * - * @param {!ShowConfig} config + * @param {!ShowAtPositionConfig} config */ showAtPosition: function(config) { // Save the scroll position of the viewport. @@ -319,7 +358,7 @@ Polymer({ config.top += scrollTop; config.left += scrollLeft; - this.positionDialog_(/** @type {ShowConfig} */ (Object.assign( + this.positionDialog_(/** @type {ShowAtPositionConfig} */ (Object.assign( { minX: scrollLeft, minY: scrollTop, @@ -344,10 +383,11 @@ Polymer({ /** * Position the dialog using the coordinates in config. Coordinates are * relative to the top-left of the viewport when scrolled to (0, 0). - * @param {!ShowConfig} config + * @param {!ShowAtPositionConfig} config * @private */ positionDialog_: function(config) { + this.lastConfig_ = config; var c = Object.assign(getDefaultShowConfig(), config); var top = c.top; @@ -397,6 +437,17 @@ Polymer({ } }); }); + + if (this.autoReposition) { + this.resizeObserver_ = new ResizeObserver(() => { + if (this.lastConfig_) { + this.positionDialog_(this.lastConfig_); + this.fire('cr-action-menu-repositioned'); // For easier testing. + } + }); + + this.resizeObserver_.observe(this); + } }, }); })(); diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html index 759fcf8b6de..68cb78ff83f 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html +++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html @@ -29,6 +29,7 @@ flex-direction: column; max-height: 100vh; overflow: auto; + @apply --cr-dialog-wrapper; } /* When needing to flex, force .body-container alone to shrink. */ @@ -49,7 +50,7 @@ :host ::slotted([slot=body]) { padding: 12px 16px; - @apply(--cr-dialog-body); + @apply --cr-dialog-body; } :host ::slotted([slot=title]) { @@ -57,7 +58,7 @@ font-size: calc(15 / 13 * 100%); line-height: 1; padding: 16px 16px; - @apply(--cr-dialog-title); + @apply --cr-dialog-title; } :host ::slotted([slot=button-container]) { @@ -84,7 +85,7 @@ min-height: 60px; /* Minimum reasonably usable height. */ overflow: auto; - @apply(--cr-dialog-body-container); + @apply --cr-dialog-body-container; } .body-container.bottom-scrollable { @@ -116,6 +117,16 @@ align-self: flex-start; margin-top: 4px; padding: 10px; /* Makes the actual icon 16x16. */ + + @apply --cr-dialog-close-image; + } + + #close:hover { + @apply --cr-dialog-close-image-hover; + } + + #close:active { + @apply --cr-dialog-close-image-active; } </style> <!-- This wrapper is necessary, such that the "pulse" animation is not diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html index 2753d98bb65..e31345821ed 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html +++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html @@ -11,7 +11,7 @@ } button[is=paper-icon-button-light] { - @apply(--cr-paper-icon-button-margin); + @apply --cr-paper-icon-button-margin; } #outer { @@ -26,8 +26,8 @@ <div id="outer" on-tap="toggleExpand_"> <div id="label" on-tap="toggleExpand_"><slot></slot></div> <button is="paper-icon-button-light" class$="[[iconName_(expanded)]]" - toggles active="{{expanded}}" disabled="[[disabled]]" alt="[[alt]]" - aria-active-attribute="aria-expanded" + toggles active="{{expanded}}" disabled="[[disabled]]" + aria-label$="[[alt]]" aria-pressed$="[[getAriaPressed_(expanded)]]" tabindex$="[[tabIndex]]"> </button> </div> diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js index 6cc2d178740..65a019c9e11 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js +++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js @@ -44,4 +44,9 @@ Polymer({ this.expanded = !this.expanded; event.stopPropagation(); }, + + /** @private */ + getAriaPressed_: function(expanded) { + return expanded ? 'true' : 'false'; + }, }); diff --git a/chromium/ui/webui/resources/cr_elements/cr_icons_css.html b/chromium/ui/webui/resources/cr_elements/cr_icons_css.html index f207914c7da..f8dc56c8a7f 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_icons_css.html +++ b/chromium/ui/webui/resources/cr_elements/cr_icons_css.html @@ -11,7 +11,7 @@ button[is='paper-icon-button-light'], .cr-icon { - @apply(--cr-paper-icon-button-margin); + @apply --cr-paper-icon-button-margin; background-position: center; background-repeat: no-repeat; background-size: var(--cr-icon-size); diff --git a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html index 4f6115b4b82..97bb3cc66a7 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html +++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html @@ -65,7 +65,7 @@ } #subLabel { - /* TODO(dschuyler): replace with: @apply(--cr-secondary-text); */ + /* TODO(dschuyler): replace with: @apply --cr-secondary-text; */ color: var(--paper-grey-600); font-weight: 400; } diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html index 29b9923b515..bc13ad1d5d6 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html +++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html @@ -12,7 +12,7 @@ --avatar-spacing: 24px; display: inline-flex; - @apply(--avatar-selector); + @apply --avatar-selector; } #avatar-grid .avatar { @@ -33,7 +33,7 @@ padding: 0; width: var(--avatar-size); - @apply(--avatar-selector-avatar); + @apply --avatar-selector-avatar; } #avatar-grid .avatar.iron-selected { diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html index 24ca91153a1..063e1fd2902 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html +++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html @@ -40,7 +40,7 @@ } paper-spinner-lite { - @apply(--cr-icon-height-width); + @apply --cr-icon-height-width; --paper-spinner-color: white; margin: 0 6px; opacity: 0; diff --git a/chromium/ui/webui/resources/cr_elements/paper_toggle_style_css.html b/chromium/ui/webui/resources/cr_elements/paper_toggle_style_css.html index 95581fd1707..44260f5541d 100644 --- a/chromium/ui/webui/resources/cr_elements/paper_toggle_style_css.html +++ b/chromium/ui/webui/resources/cr_elements/paper_toggle_style_css.html @@ -28,7 +28,7 @@ --paper-toggle-button-checked-bar: var(--cr-toggle-bar-size); --paper-toggle-button-checked-bar-color: var(--cr-toggle-color); --paper-toggle-button-checked-button: { - @apply(--cr-toggle-button-size); + @apply --cr-toggle-button-size; transform: translate(18px, 0); }; --paper-toggle-button-checked-button-color: var(--cr-toggle-color); diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js index 2ad60591ab2..e8b2bba0d98 100644 --- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js +++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js @@ -120,7 +120,7 @@ var CrPolicyIndicatorBehavior = { return ''; // Tooltips may not be defined, e.g. in OOBE. switch (type) { case CrPolicyIndicatorType.EXTENSION: - return CrPolicyStrings.controlledSettingExtension; + return CrPolicyStrings.controlledSettingExtension.replace('$1', name); case CrPolicyIndicatorType.PRIMARY_USER: return CrPolicyStrings.controlledSettingShared.replace('$1', name); case CrPolicyIndicatorType.OWNER: diff --git a/chromium/ui/webui/resources/cr_elements/search_highlight_style_css.html b/chromium/ui/webui/resources/cr_elements/search_highlight_style_css.html new file mode 100644 index 00000000000..451f86dd950 --- /dev/null +++ b/chromium/ui/webui/resources/cr_elements/search_highlight_style_css.html @@ -0,0 +1,48 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="shared_vars_css.html"> + +<dom-module id="search-highlight-style"> + <template> + <style> + .search-bubble { + /* RGB value matches var(--paper-yellow-500). */ + --search-bubble-color: rgba(255, 235, 59, 0.9); + position: absolute; + z-index: 1; + } + + .search-bubble-innards { + align-items: center; + background-color: var(--search-bubble-color); + border-radius: 2px; + max-width: 100px; + min-width: 64px; + padding: 4px 10px; + text-align: center; + @apply --cr-text-elide; + } + + /* Provides the arrow which points at the anchor element. */ + .search-bubble-innards::after { + background-color: var(--search-bubble-color); + content: ''; + height: 10px; + left: calc(50% - 5px); + position: absolute; + top: -5px; + transform: rotate(-45deg); + width: 10px; + z-index: -1; + } + + /* Turns the arrow direction downwards, when the bubble is placed above + * the anchor element */ + .search-bubble-innards.above::after { + bottom: -5px; + top: auto; + transform: rotate(-135deg); + } + </style> + </template> +</dom-module> diff --git a/chromium/ui/webui/resources/cr_elements/shared_style_css.html b/chromium/ui/webui/resources/cr_elements/shared_style_css.html index f3bcb9eb1ff..090a611be97 100644 --- a/chromium/ui/webui/resources/cr_elements/shared_style_css.html +++ b/chromium/ui/webui/resources/cr_elements/shared_style_css.html @@ -36,7 +36,7 @@ } [actionable] { - @apply(--cr-actionable); + @apply --cr-actionable; } .subpage-arrow, @@ -71,8 +71,8 @@ border-bottom-color: var(--google-grey-300); } [scrollable] iron-list > :not(.no-outline):focus { - @apply(--cr-list-item-focus); - @apply(--cr-selectable-focus); + @apply --cr-list-item-focus; + @apply --cr-selectable-focus; } .scroll-container { @@ -83,15 +83,15 @@ [selectable]:focus, [selectable] > :focus { - @apply(--cr-selectable-focus); + @apply --cr-selectable-focus; } [selectable] > * { - @apply(--cr-actionable); + @apply --cr-actionable; } /** Styles for elements that implement the CrContainerShadowBehavior */ #cr-container-shadow { - @apply(--cr-container-shadow); + @apply --cr-container-shadow; } #cr-container-shadow.has-shadow { diff --git a/chromium/ui/webui/resources/cr_elements/shared_vars_css.html b/chromium/ui/webui/resources/cr_elements/shared_vars_css.html index 83d28f66dfd..f7eeb885181 100644 --- a/chromium/ui/webui/resources/cr_elements/shared_vars_css.html +++ b/chromium/ui/webui/resources/cr_elements/shared_vars_css.html @@ -67,6 +67,12 @@ padding: 0 var(--cr-section-padding); }; + --cr-text-elide: { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + }; + --cr-title-text: { color: rgb(90, 90, 90); font-size: 107.6923%; /* Go to 14px from 13px. */ diff --git a/chromium/ui/webui/resources/cr_elements_resources.grdp b/chromium/ui/webui/resources/cr_elements_resources.grdp index c5c61226a49..c348d34f2f6 100644 --- a/chromium/ui/webui/resources/cr_elements_resources.grdp +++ b/chromium/ui/webui/resources/cr_elements_resources.grdp @@ -284,6 +284,10 @@ file="../../webui/resources/cr_elements/paper_toggle_style_css.html" type="chrome_html" compress="gzip" /> + <structure name="IDR_CR_ELEMENTS_SEARCH_HIGHLIGHT_STYLE_CSS_HTML" + file="../../webui/resources/cr_elements/search_highlight_style_css.html" + type="chrome_html" + compress="gzip" /> <structure name="IDR_CR_ELEMENTS_CR_SHARED_VARS_CSS_HTML" file="../../webui/resources/cr_elements/shared_vars_css.html" type="chrome_html" diff --git a/chromium/ui/webui/resources/cr_polymer_resources.grdp b/chromium/ui/webui/resources/cr_polymer_resources.grdp new file mode 100644 index 00000000000..96e7fecc19f --- /dev/null +++ b/chromium/ui/webui/resources/cr_polymer_resources.grdp @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Holds various resources under ui/webui/resources/{js,html}, that depend on + Polymer or are Polymer related. --> +<grit-part> + <!-- HTML resources --> + <structure name="IDR_WEBUI_HTML_ACTION_LINK_CSS" + file="html/action_link_css.html" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_WITHOUT_INK" + file="html/cr/ui/focus_without_ink.html" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_HTML_I18N_BEHAVIOR" + file="html/i18n_behavior.html" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_HTML_MD_SELECT_CSS_HTML" + file="html/md_select_css.html" type="chrome_html" + compress="gzip" flattenhtml="true" /> + <structure name="IDR_WEBUI_HTML_POLYMER" + file="html/polymer.html" type="chrome_html" compress="gzip" /> + <structure name="IDR_WEBUI_HTML_WEBUI_LISTENER_BEHAVIOR" + file="html/web_ui_listener_behavior.html" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_HTML_SEARCH_HIGHLIGHT_UTILS" + file="html/search_highlight_utils.html" type="chrome_html" + compress="gzip" /> + + <!-- CSS resources --> + <structure name="IDR_WEBUI_CSS_MD_COLORS" + file="css/md_colors.css" type="chrome_html" compress="gzip" /> + + <!-- JS resources --> + <structure name="IDR_WEBUI_JS_I18N_BEHAVIOR" + file="js/i18n_behavior.js" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_WITHOUT_INK" + file="js/cr/ui/focus_without_ink.js" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_JS_POLYMER_CONFIG" + file="js/polymer_config.js" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_JS_WEBUI_LISTENER_BEHAVIOR" + file="js/web_ui_listener_behavior.js" type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_JS_SEARCH_HIGHLIGHT_UTILS" + file="js/search_highlight_utils.js" type="chrome_html" + compress="gzip" /> +</grit-part> diff --git a/chromium/ui/webui/resources/html/action_link_css.html b/chromium/ui/webui/resources/html/action_link_css.html index 9ece1d5701f..904395b8046 100644 --- a/chromium/ui/webui/resources/html/action_link_css.html +++ b/chromium/ui/webui/resources/html/action_link_css.html @@ -6,7 +6,7 @@ <template> <style> [is='action-link'] { - @apply(--cr-actionable); + @apply --cr-actionable; display: inline-block; text-decoration: none; } diff --git a/chromium/ui/webui/resources/html/search_highlight_utils.html b/chromium/ui/webui/resources/html/search_highlight_utils.html new file mode 100644 index 00000000000..5f7a8836bcc --- /dev/null +++ b/chromium/ui/webui/resources/html/search_highlight_utils.html @@ -0,0 +1 @@ +<script src="chrome://resources/js/search_highlight_utils.js"></script> diff --git a/chromium/ui/webui/resources/images/200-logo_chrome.png b/chromium/ui/webui/resources/images/200-logo_chrome.png Binary files differindex c283720758c..44f808efaf6 100644 --- a/chromium/ui/webui/resources/images/200-logo_chrome.png +++ b/chromium/ui/webui/resources/images/200-logo_chrome.png diff --git a/chromium/ui/webui/resources/images/200-logo_googleg.png b/chromium/ui/webui/resources/images/200-logo_googleg.png Binary files differindex 85f92c09ca9..9ace71c2a9c 100644 --- a/chromium/ui/webui/resources/images/200-logo_googleg.png +++ b/chromium/ui/webui/resources/images/200-logo_googleg.png diff --git a/chromium/ui/webui/resources/images/2x/apps/topbar_button_maximize.png b/chromium/ui/webui/resources/images/2x/apps/topbar_button_maximize.png Binary files differindex 59377a4dc41..96cecc99da1 100644 --- a/chromium/ui/webui/resources/images/2x/apps/topbar_button_maximize.png +++ b/chromium/ui/webui/resources/images/2x/apps/topbar_button_maximize.png diff --git a/chromium/ui/webui/resources/images/2x/apps/topbar_button_minimize.png b/chromium/ui/webui/resources/images/2x/apps/topbar_button_minimize.png Binary files differindex 2c0afdb3eba..437c6f700dd 100644 --- a/chromium/ui/webui/resources/images/2x/apps/topbar_button_minimize.png +++ b/chromium/ui/webui/resources/images/2x/apps/topbar_button_minimize.png diff --git a/chromium/ui/webui/resources/images/apps/button_butter_bar_close.png b/chromium/ui/webui/resources/images/apps/button_butter_bar_close.png Binary files differindex 75edfba33bd..001f22742c3 100644 --- a/chromium/ui/webui/resources/images/apps/button_butter_bar_close.png +++ b/chromium/ui/webui/resources/images/apps/button_butter_bar_close.png diff --git a/chromium/ui/webui/resources/images/apps/topbar_button_maximize.png b/chromium/ui/webui/resources/images/apps/topbar_button_maximize.png Binary files differindex 3bd557fa5a4..7d452702c13 100644 --- a/chromium/ui/webui/resources/images/apps/topbar_button_maximize.png +++ b/chromium/ui/webui/resources/images/apps/topbar_button_maximize.png diff --git a/chromium/ui/webui/resources/images/apps/topbar_button_minimize.png b/chromium/ui/webui/resources/images/apps/topbar_button_minimize.png Binary files differindex 484079d5bdb..33b892dfe3d 100644 --- a/chromium/ui/webui/resources/images/apps/topbar_button_minimize.png +++ b/chromium/ui/webui/resources/images/apps/topbar_button_minimize.png diff --git a/chromium/ui/webui/resources/images/check.png b/chromium/ui/webui/resources/images/check.png Binary files differindex 94c58b78c43..0321d1b45d9 100644 --- a/chromium/ui/webui/resources/images/check.png +++ b/chromium/ui/webui/resources/images/check.png diff --git a/chromium/ui/webui/resources/images/checkbox_black.png b/chromium/ui/webui/resources/images/checkbox_black.png Binary files differindex 3609119e41a..16e82cb2a63 100644 --- a/chromium/ui/webui/resources/images/checkbox_black.png +++ b/chromium/ui/webui/resources/images/checkbox_black.png diff --git a/chromium/ui/webui/resources/images/disabled_select.png b/chromium/ui/webui/resources/images/disabled_select.png Binary files differindex 0aa20000d74..9bce7a30523 100644 --- a/chromium/ui/webui/resources/images/disabled_select.png +++ b/chromium/ui/webui/resources/images/disabled_select.png diff --git a/chromium/ui/webui/resources/images/select.png b/chromium/ui/webui/resources/images/select.png Binary files differindex 2af6f675864..3cb71fb514c 100644 --- a/chromium/ui/webui/resources/images/select.png +++ b/chromium/ui/webui/resources/images/select.png diff --git a/chromium/ui/webui/resources/js/compiled_resources2.gyp b/chromium/ui/webui/resources/js/compiled_resources2.gyp index 25f388bebeb..3b759c04f4b 100644 --- a/chromium/ui/webui/resources/js/compiled_resources2.gyp +++ b/chromium/ui/webui/resources/js/compiled_resources2.gyp @@ -32,6 +32,13 @@ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'search_highlight_utils', + 'dependencies': [ + 'cr', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'icon', 'dependencies': [ 'cr', diff --git a/chromium/ui/webui/resources/js/cr/ui/tree.js b/chromium/ui/webui/resources/js/cr/ui/tree.js index 89940b6b66a..87ffb019a71 100644 --- a/chromium/ui/webui/resources/js/cr/ui/tree.js +++ b/chromium/ui/webui/resources/js/cr/ui/tree.js @@ -465,7 +465,7 @@ cr.define('cr.ui', function() { return getComputedStyle(this.labelElement).backgroundImage.slice(4, -1); }, set icon(icon) { - return this.labelElement.style.backgroundImage = url(icon); + return this.labelElement.style.backgroundImage = getUrlForCss(icon); }, /** diff --git a/chromium/ui/webui/resources/js/icon.js b/chromium/ui/webui/resources/js/icon.js index ee8c445f11c..ef025e7133d 100644 --- a/chromium/ui/webui/resources/js/icon.js +++ b/chromium/ui/webui/resources/js/icon.js @@ -45,7 +45,7 @@ cr.define('cr.icon', function() { var replaceStartIndex = path.indexOf('scalefactor'); if (replaceStartIndex < 0) - return url(path); + return getUrlForCss(path); var s = ''; for (var i = 0; i < supportedScaleFactors.length; ++i) { @@ -53,7 +53,7 @@ cr.define('cr.icon', function() { var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length); - s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x'; + s += getUrlForCss(pathWithScaleFactor) + ' ' + scaleFactor + 'x'; if (i != supportedScaleFactors.length - 1) s += ', '; @@ -72,7 +72,8 @@ cr.define('cr.icon', function() { var chromeThemePath = 'chrome://theme'; var isChromeThemeUrl = (path.slice(0, chromeThemePath.length) == chromeThemePath); - return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : url(path); + return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : + getUrlForCss(path); } /** diff --git a/chromium/ui/webui/resources/js/search_highlight_utils.js b/chromium/ui/webui/resources/js/search_highlight_utils.js new file mode 100644 index 00000000000..d7bf3c8acb0 --- /dev/null +++ b/chromium/ui/webui/resources/js/search_highlight_utils.js @@ -0,0 +1,130 @@ +// Copyright 2018 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. + +cr.define('cr.search_highlight_utils', function() { + /** @type {string} */ + const WRAPPER_CSS_CLASS = 'search-highlight-wrapper'; + + /** @type {string} */ + const ORIGINAL_CONTENT_CSS_CLASS = 'search-highlight-original-content'; + + /** @type {string} */ + const HIT_CSS_CLASS = 'search-highlight-hit'; + + /** @type {string} */ + const SEARCH_BUBBLE_CSS_CLASS = 'search-bubble'; + + /** + * Applies the highlight UI (yellow rectangle) around all matches in |node|. + * @param {!Node} node The text node to be highlighted. |node| ends up + * being hidden. + * @param {!Array<string>} tokens The string tokens after splitting on the + * relevant regExp. Even indices hold text that doesn't need highlighting, + * odd indices hold the text to be highlighted. For example: + * const r = new RegExp('(foo)', 'i'); + * 'barfoobar foo bar'.split(r) => ['bar', 'foo', 'bar ', 'foo', ' bar'] + */ + function highlight(node, tokens) { + const wrapper = document.createElement('span'); + wrapper.classList.add(WRAPPER_CSS_CLASS); + // Use existing node as placeholder to determine where to insert the + // replacement content. + node.parentNode.replaceChild(wrapper, node); + + // Keep the existing node around for when the highlights are removed. The + // existing text node might be involved in data-binding and therefore should + // not be discarded. + const span = document.createElement('span'); + span.classList.add(ORIGINAL_CONTENT_CSS_CLASS); + span.style.display = 'none'; + span.appendChild(node); + wrapper.appendChild(span); + + for (let i = 0; i < tokens.length; ++i) { + if (i % 2 == 0) { + wrapper.appendChild(document.createTextNode(tokens[i])); + } else { + const hitSpan = document.createElement('span'); + hitSpan.classList.add(HIT_CSS_CLASS); + hitSpan.style.backgroundColor = '#ffeb3b'; // --var(--paper-yellow-500) + hitSpan.textContent = tokens[i]; + wrapper.appendChild(hitSpan); + } + } + } + + /** + * Finds all previous highlighted nodes under |node| (both within self and + * children's Shadow DOM) and replaces the highlights (yellow rectangles) + * with the original search node. + * @param {!Node} node + * @private + */ + function findAndRemoveHighlights(node) { + const wrappers = node.querySelectorAll(`* /deep/ .${WRAPPER_CSS_CLASS}`); + + for (let i = 0; i < wrappers.length; i++) { + const wrapper = wrappers[i]; + const originalNode = + wrapper.querySelector(`.${ORIGINAL_CONTENT_CSS_CLASS}`); + wrapper.parentElement.replaceChild(originalNode.firstChild, wrapper); + } + } + + /** + * Finds and removes all previously created yellow search bubbles under + * |node| (both within self and children's Shadow DOM). + * @param {!Node} node + * @private + */ + function findAndRemoveBubbles(node) { + const searchBubbles = + node.querySelectorAll(`* /deep/ .${SEARCH_BUBBLE_CSS_CLASS}`); + for (let bubble of searchBubbles) + bubble.remove(); + } + + /** + * Highlights an HTML element by displaying a search bubble. The element + * should already be visible or the bubble will render incorrectly. + * @param {!HTMLElement} element The element to be highlighted. + * @param {string} rawQuery The search query. + * @private + */ + function highlightControlWithBubble(element, rawQuery) { + let searchBubble = element.querySelector(`.${SEARCH_BUBBLE_CSS_CLASS}`); + // If the element has already been highlighted, there is no need to do + // anything. + if (searchBubble) + return; + + searchBubble = document.createElement('div'); + searchBubble.classList.add(SEARCH_BUBBLE_CSS_CLASS); + const innards = document.createElement('div'); + innards.classList.add('search-bubble-innards'); + innards.textContent = rawQuery; + searchBubble.appendChild(innards); + element.appendChild(searchBubble); + + const updatePosition = function() { + searchBubble.style.top = element.offsetTop + + (innards.classList.contains('above') ? -searchBubble.offsetHeight : + element.offsetHeight) + + 'px'; + }; + updatePosition(); + + searchBubble.addEventListener('mouseover', function() { + innards.classList.toggle('above'); + updatePosition(); + }); + } + + return { + highlight: highlight, + highlightControlWithBubble: highlightControlWithBubble, + findAndRemoveBubbles: findAndRemoveBubbles, + findAndRemoveHighlights: findAndRemoveHighlights, + }; +}); diff --git a/chromium/ui/webui/resources/js/util.js b/chromium/ui/webui/resources/js/util.js index 27faa1b60bf..a5099bf9b56 100644 --- a/chromium/ui/webui/resources/js/util.js +++ b/chromium/ui/webui/resources/js/util.js @@ -56,7 +56,7 @@ function announceAccessibleMessage(msg) { * @param {string} s The URL to generate the CSS url for. * @return {string} The CSS url string. */ -function url(s) { +function getUrlForCss(s) { // http://www.w3.org/TR/css3-values/#uris // Parentheses, commas, whitespace characters, single quotes (') and double // quotes (") appearing in a URI must be escaped with a backslash diff --git a/chromium/ui/webui/resources/polymer_resources.grdp b/chromium/ui/webui/resources/polymer_resources.grdp index 6e5f88e36b1..6f4a7f9d3f0 100644 --- a/chromium/ui/webui/resources/polymer_resources.grdp +++ b/chromium/ui/webui/resources/polymer_resources.grdp @@ -276,6 +276,14 @@ file="../../../third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-overlay-manager.html" type="chrome_html" compress="gzip" /> + <structure name="IDR_POLYMER_1_0_IRON_OVERLAY_BEHAVIOR_IRON_SCROLL_MANAGER_EXTRACTED_JS" + file="../../../third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-scroll-manager-extracted.js" + type="chrome_html" + compress="gzip" /> + <structure name="IDR_POLYMER_1_0_IRON_OVERLAY_BEHAVIOR_IRON_SCROLL_MANAGER_HTML" + file="../../../third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/iron-scroll-manager.html" + type="chrome_html" + compress="gzip" /> <structure name="IDR_POLYMER_1_0_IRON_PAGES_IRON_PAGES_EXTRACTED_JS" file="../../../third_party/polymer/v1_0/components-chromium/iron-pages/iron-pages-extracted.js" type="chrome_html" @@ -700,30 +708,6 @@ file="../../../third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_MATERIAL_PAPER_MATERIAL_SHARED_STYLES_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/paper-material/paper-material-shared-styles.html" - type="chrome_html" - compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_MENU_PAPER_MENU_EXTRACTED_JS" - file="../../../third_party/polymer/v1_0/components-chromium/paper-menu/paper-menu-extracted.js" - type="chrome_html" - compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_MENU_PAPER_MENU_SHARED_STYLES_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/paper-menu/paper-menu-shared-styles.html" - type="chrome_html" - compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_MENU_PAPER_MENU_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/paper-menu/paper-menu.html" - type="chrome_html" - compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_MENU_PAPER_SUBMENU_EXTRACTED_JS" - file="../../../third_party/polymer/v1_0/components-chromium/paper-menu/paper-submenu-extracted.js" - type="chrome_html" - compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_MENU_PAPER_SUBMENU_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/paper-menu/paper-submenu.html" - type="chrome_html" - compress="gzip" /> <structure name="IDR_POLYMER_1_0_PAPER_PROGRESS_PAPER_PROGRESS_EXTRACTED_JS" file="../../../third_party/polymer/v1_0/components-chromium/paper-progress/paper-progress-extracted.js" type="chrome_html" @@ -784,10 +768,6 @@ file="../../../third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-styles.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_STYLES_CLASSES_SHADOW_LAYOUT_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/classes/shadow-layout.html" - type="chrome_html" - compress="gzip" /> <structure name="IDR_POLYMER_1_0_PAPER_STYLES_CLASSES_SHADOW_HTML" file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/classes/shadow.html" type="chrome_html" @@ -804,6 +784,14 @@ file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/default-theme.html" type="chrome_html" compress="gzip" /> + <structure name="IDR_POLYMER_1_0_PAPER_STYLES_ELEMENT_STYLES_PAPER_ITEM_STYLES_HTML" + file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/element-styles/paper-item-styles.html" + type="chrome_html" + compress="gzip" /> + <structure name="IDR_POLYMER_1_0_PAPER_STYLES_ELEMENT_STYLES_PAPER_MATERIAL_STYLES_HTML" + file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/element-styles/paper-material-styles.html" + type="chrome_html" + compress="gzip" /> <structure name="IDR_POLYMER_1_0_PAPER_STYLES_PAPER_STYLES_CLASSES_HTML" file="../../../third_party/polymer/v1_0/components-chromium/paper-styles/paper-styles-classes.html" type="chrome_html" diff --git a/chromium/ui/webui/resources/webui_resources.grd b/chromium/ui/webui/resources/webui_resources.grd index 980b689ac1e..a704601c238 100644 --- a/chromium/ui/webui/resources/webui_resources.grd +++ b/chromium/ui/webui/resources/webui_resources.grd @@ -236,8 +236,6 @@ without changes to the corresponding grd file. --> compress="gzip" /> <structure name="IDR_WEBUI_CSS_LIST" file="css/list.css" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_CSS_MD_COLORS" - file="css/md_colors.css" type="chrome_html" compress="gzip" /> <structure name="IDR_WEBUI_CSS_MENU" file="css/menu.css" type="chrome_html" compress="gzip" flattenhtml="true" /> @@ -274,9 +272,6 @@ without changes to the corresponding grd file. --> <structure name="IDR_WEBUI_HTML_ACTION_LINK" file="html/action_link.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_HTML_ACTION_LINK_CSS" - file="html/action_link_css.html" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_HTML_ASSERT" file="html/assert.html" type="chrome_html" compress="gzip" /> <structure name="IDR_WEBUI_HTML_PROMISE_RESOLVER" @@ -319,9 +314,6 @@ without changes to the corresponding grd file. --> <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_ROW" file="html/cr/ui/focus_row.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_WITHOUT_INK" - file="html/cr/ui/focus_without_ink.html" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_HTML_CR_UI_LIST" file="html/cr/ui/list.html" type="chrome_html" compress="gzip" /> @@ -366,25 +358,14 @@ without changes to the corresponding grd file. --> <structure name="IDR_WEBUI_HTML_I18N_TEMPLATE" file="html/i18n_template.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_HTML_MD_SELECT_CSS_HTML" - file="html/md_select_css.html" type="chrome_html" - compress="gzip" flattenhtml="true" /> <structure name="IDR_WEBUI_HTML_LOAD_TIME_DATA" file="html/load_time_data.html" type="chrome_html" compress="gzip" /> <structure name="IDR_WEBUI_HTML_PARSE_HTML_SUBSET" file="html/parse_html_subset.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_HTML_POLYMER" - file="html/polymer.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_HTML_I18N_BEHAVIOR" - file="html/i18n_behavior.html" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_HTML_UTIL" file="html/util.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_HTML_WEBUI_LISTENER_BEHAVIOR" - file="html/web_ui_listener_behavior.html" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_HTML_WEBUI_LISTENER_TRACKER" file="html/webui_listener_tracker.html" type="chrome_html" compress="gzip" /> @@ -454,9 +435,6 @@ without changes to the corresponding grd file. --> <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_ROW" file="js/cr/ui/focus_row.js" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_WITHOUT_INK" - file="js/cr/ui/focus_without_ink.js" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_JS_CR_UI_LIST" file="js/cr/ui/list.js" type="chrome_html" compress="gzip" /> <structure name="IDR_WEBUI_JS_CR_UI_LIST_ITEM" @@ -546,24 +524,17 @@ without changes to the corresponding grd file. --> <structure name="IDR_WEBUI_JS_PARSE_HTML_SUBSET" file="js/parse_html_subset.js" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_JS_POLYMER_CONFIG" - file="js/polymer_config.js" type="chrome_html" - compress="gzip" /> - <structure name="IDR_WEBUI_JS_I18N_BEHAVIOR" - file="js/i18n_behavior.js" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_JS_UTIL" file="js/util.js" type="chrome_html" compress="gzip" flattenhtml="true" /> - <structure name="IDR_WEBUI_JS_WEBUI_LISTENER_BEHAVIOR" - file="js/web_ui_listener_behavior.js" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_JS_WEBUI_RESOURCE_TEST" file="js/webui_resource_test.js" type="chrome_html" compress="gzip" /> - <if expr="not is_android"> + + <if expr="not is_android and not is_ios"> <part file="cr_components/cr_components_resources.grdp" /> <part file="cr_elements_resources.grdp" /> + <part file="cr_polymer_resources.grdp" /> <part file="polymer_resources.grdp" /> </if> </structures> diff --git a/chromium/ui/wm/core/shadow.cc b/chromium/ui/wm/core/shadow.cc index 0fb91267c3a..20def6b8976 100644 --- a/chromium/ui/wm/core/shadow.cc +++ b/chromium/ui/wm/core/shadow.cc @@ -9,30 +9,22 @@ #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/shadow_util.h" -#include "ui/wm/core/shadow_types.h" namespace wm { namespace { // Duration for opacity animation in milliseconds. -const int kShadowAnimationDurationMs = 100; - -// Default rounded corner radius. Shadow::SetRoundedCornerRadius can -// be used to override this for elements with a different rounded -// corner radius. -const int kDefaultRoundedCornerRadius = 2; +constexpr int kShadowAnimationDurationMs = 100; } // namespace -Shadow::Shadow() - : desired_elevation_(ShadowElevation::NONE), - rounded_corner_radius_(kDefaultRoundedCornerRadius) {} +Shadow::Shadow() {} Shadow::~Shadow() {} -void Shadow::Init(ShadowElevation elevation) { - DCHECK_NE(ShadowElevation::DEFAULT, elevation); +void Shadow::Init(int elevation) { + DCHECK_GE(elevation, 0); desired_elevation_ = elevation; layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); RecreateShadowLayer(); @@ -48,8 +40,8 @@ void Shadow::SetContentBounds(const gfx::Rect& content_bounds) { UpdateLayerBounds(); } -void Shadow::SetElevation(ShadowElevation elevation) { - DCHECK_NE(ShadowElevation::DEFAULT, elevation); +void Shadow::SetElevation(int elevation) { + DCHECK_GE(elevation, 0); if (desired_elevation_ == elevation) return; diff --git a/chromium/ui/wm/core/shadow.h b/chromium/ui/wm/core/shadow.h index 03c65e7db0f..4c224a20b45 100644 --- a/chromium/ui/wm/core/shadow.h +++ b/chromium/ui/wm/core/shadow.h @@ -21,7 +21,6 @@ class Layer; } // namespace ui namespace wm { -enum class ShadowElevation; // Simple class that draws a drop shadow around content at given bounds. class WM_CORE_EXPORT Shadow : public ui::ImplicitAnimationObserver { @@ -29,7 +28,10 @@ class WM_CORE_EXPORT Shadow : public ui::ImplicitAnimationObserver { Shadow(); ~Shadow() override; - void Init(ShadowElevation elevation); + // Initialize for the the given shadow |elevation|. This is passed to + // gfx::ShadowValue::MakeMdShadowValues() and controls the y-offset and blur + // for the shadow style. + void Init(int elevation); // Returns |layer_.get()|. This is exposed so it can be added to the same // layer as the content and stacked below it. SetContentBounds() should be @@ -42,13 +44,13 @@ class WM_CORE_EXPORT Shadow : public ui::ImplicitAnimationObserver { ui::Layer* shadow_layer() const { return shadow_layer_.get(); } const gfx::Rect& content_bounds() const { return content_bounds_; } - ShadowElevation desired_elevation() const { return desired_elevation_; } + int desired_elevation() const { return desired_elevation_; } // Moves and resizes the shadow layer to frame |content_bounds|. void SetContentBounds(const gfx::Rect& content_bounds); // Sets the shadow's appearance, animating opacity as necessary. - void SetElevation(ShadowElevation elevation); + void SetElevation(int elevation); // Sets the radius for the rounded corners to take into account when // adjusting the shadow layer to frame |content_bounds|. 0 or greater. @@ -71,11 +73,11 @@ class WM_CORE_EXPORT Shadow : public ui::ImplicitAnimationObserver { // dictates the shadow's display characteristics and is proportional to the // size of the blur and its offset. This may not match reality if the window // isn't big enough to support it. - ShadowElevation desired_elevation_; + int desired_elevation_ = 0; // Rounded corners are drawn on top of the window's content layer, // we need to exclude them from the occlusion area. - int rounded_corner_radius_; + int rounded_corner_radius_ = 2; // The details of the shadow image that's currently set on |shadow_layer_|. // This will be null until a positive elevation has been set. Once set, it diff --git a/chromium/ui/wm/core/shadow_controller.cc b/chromium/ui/wm/core/shadow_controller.cc index 93552daa5c1..875ed5e9b14 100644 --- a/chromium/ui/wm/core/shadow_controller.cc +++ b/chromium/ui/wm/core/shadow_controller.cc @@ -20,6 +20,7 @@ #include "ui/base/ui_base_types.h" #include "ui/compositor/layer.h" #include "ui/wm/core/shadow.h" +#include "ui/wm/core/shadow_types.h" #include "ui/wm/core/window_util.h" #include "ui/wm/public/activation_client.h" @@ -32,41 +33,38 @@ namespace wm { namespace { -constexpr ShadowElevation kInactiveNormalShadowElevation = - ShadowElevation::MEDIUM; - -ShadowElevation GetDefaultShadowElevationForWindow(aura::Window* window) { +int GetDefaultShadowElevationForWindow(aura::Window* window) { switch (window->type()) { case aura::client::WINDOW_TYPE_NORMAL: case aura::client::WINDOW_TYPE_PANEL: - return kInactiveNormalShadowElevation; + return kShadowElevationInactiveWindow; case aura::client::WINDOW_TYPE_MENU: case aura::client::WINDOW_TYPE_TOOLTIP: - return ShadowElevation::SMALL; + return kShadowElevationMenuOrTooltip; default: break; } - return ShadowElevation::NONE; + return kShadowElevationNone; } -// Returns the ShadowElevation for |window|, converting |DEFAULT| to the -// appropriate ShadowElevation. -ShadowElevation GetShadowElevationConvertDefault(aura::Window* window) { - ShadowElevation elevation = window->GetProperty(kShadowElevationKey); - return elevation == ShadowElevation::DEFAULT +// Returns the shadow elevation for |window|, converting +// |kShadowElevationDefault| to the appropriate value. +int GetShadowElevationConvertDefault(aura::Window* window) { + int elevation = window->GetProperty(kShadowElevationKey); + return elevation == kShadowElevationDefault ? GetDefaultShadowElevationForWindow(window) : elevation; } -ShadowElevation GetShadowElevationForActiveState(aura::Window* window) { - ShadowElevation elevation = window->GetProperty(kShadowElevationKey); - if (elevation != ShadowElevation::DEFAULT) +int GetShadowElevationForActiveState(aura::Window* window) { + int elevation = window->GetProperty(kShadowElevationKey); + if (elevation != kShadowElevationDefault) return elevation; if (IsActiveWindow(window)) - return ShadowController::kActiveNormalShadowElevation; + return kShadowElevationActiveWindow; return GetDefaultShadowElevationForWindow(window); } @@ -74,15 +72,14 @@ ShadowElevation GetShadowElevationForActiveState(aura::Window* window) { // Returns the shadow style to be applied to |losing_active| when it is losing // active to |gaining_active|. |gaining_active| may be of a type that hides when // inactive, and as such we do not want to render |losing_active| as inactive. -ShadowElevation GetShadowElevationForWindowLosingActive( - aura::Window* losing_active, - aura::Window* gaining_active) { +int GetShadowElevationForWindowLosingActive(aura::Window* losing_active, + aura::Window* gaining_active) { if (gaining_active && GetHideOnDeactivate(gaining_active)) { if (base::ContainsValue(GetTransientChildren(losing_active), gaining_active)) - return ShadowController::kActiveNormalShadowElevation; + return kShadowElevationActiveWindow; } - return kInactiveNormalShadowElevation; + return kShadowElevationInactiveWindow; } } // namespace @@ -108,6 +105,7 @@ class ShadowController::Impl : void OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) override; + void OnWindowVisibilityChanging(aura::Window* window, bool visible) override; void OnWindowBoundsChanged(aura::Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds, @@ -160,25 +158,45 @@ ShadowController::Impl* ShadowController::Impl::GetInstance() { } void ShadowController::Impl::OnWindowInitialized(aura::Window* window) { + // During initialization, the window can't reliably tell whether it will be a + // root window. That must be checked in the first visibility change + DCHECK(!window->parent()); + DCHECK(!window->TargetVisibility()); observer_manager_.Add(window); - HandlePossibleShadowVisibilityChange(window); } void ShadowController::Impl::OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) { - if (key == kShadowElevationKey) { - if (window->GetProperty(kShadowElevationKey) == - static_cast<ShadowElevation>(old)) - return; - } else if (key == aura::client::kShowStateKey) { - if (window->GetProperty(aura::client::kShowStateKey) == - static_cast<ui::WindowShowState>(old)) { - return; - } - } else { + bool shadow_will_change = false; + if (key == kShadowElevationKey) + shadow_will_change = window->GetProperty(kShadowElevationKey) != old; + + if (key == aura::client::kShowStateKey) { + shadow_will_change = window->GetProperty(aura::client::kShowStateKey) != + static_cast<ui::WindowShowState>(old); + } + + // Check the target visibility. IsVisible() may return false if a parent layer + // is hidden, but |this| only observes calls to Show()/Hide() on |window|. + if (shadow_will_change && window->TargetVisibility()) + HandlePossibleShadowVisibilityChange(window); +} + +void ShadowController::Impl::OnWindowVisibilityChanging(aura::Window* window, + bool visible) { + // At the time of the first visibility change, |window| will give a correct + // answer for whether or not it is a root window. If it is, don't bother + // observing: a shadow should never be added. Root windows can only have + // shadows in the WindowServer (where a corresponding aura::Window may no + // longer be a root window). Without this check, a second shadow is added, + // which clips to the root window bounds; filling any rounded corners the + // window may have. + if (window->IsRootWindow()) { + observer_manager_.Remove(window); return; } + HandlePossibleShadowVisibilityChange(window); } @@ -207,9 +225,8 @@ void ShadowController::Impl::OnWindowActivated(ActivationReason reason, } if (lost_active) { Shadow* shadow = GetShadowForWindow(lost_active); - if (shadow && - GetShadowElevationConvertDefault(lost_active) == - kInactiveNormalShadowElevation) { + if (shadow && GetShadowElevationConvertDefault(lost_active) == + kShadowElevationInactiveWindow) { shadow->SetElevation( GetShadowElevationForWindowLosingActive(lost_active, gained_active)); } @@ -225,7 +242,7 @@ bool ShadowController::Impl::ShouldShowShadowForWindow( return false; } - return static_cast<int>(GetShadowElevationConvertDefault(window)) > 0; + return GetShadowElevationConvertDefault(window) > 0; } void ShadowController::Impl::HandlePossibleShadowVisibilityChange( @@ -241,12 +258,19 @@ void ShadowController::Impl::HandlePossibleShadowVisibilityChange( } void ShadowController::Impl::CreateShadowForWindow(aura::Window* window) { + DCHECK(!window->IsRootWindow()); Shadow* shadow = new Shadow(); window->SetProperty(kShadowLayerKey, shadow); + + int corner_radius = window->GetProperty(aura::client::kWindowCornerRadiusKey); + if (corner_radius >= 0) + shadow->SetRoundedCornerRadius(corner_radius); + shadow->Init(GetShadowElevationForActiveState(window)); shadow->SetContentBounds(gfx::Rect(window->bounds().size())); shadow->layer()->SetVisible(ShouldShowShadowForWindow(window)); window->layer()->Add(shadow->layer()); + window->layer()->StackAtBottom(shadow->layer()); } ShadowController::Impl::Impl() diff --git a/chromium/ui/wm/core/shadow_controller.h b/chromium/ui/wm/core/shadow_controller.h index 34ac15a3fea..f9c3bee5336 100644 --- a/chromium/ui/wm/core/shadow_controller.h +++ b/chromium/ui/wm/core/shadow_controller.h @@ -10,7 +10,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "ui/wm/core/shadow_types.h" #include "ui/wm/core/wm_core_export.h" #include "ui/wm/public/activation_change_observer.h" @@ -29,9 +28,6 @@ class Shadow; // which observes all window creation. class WM_CORE_EXPORT ShadowController : public ActivationChangeObserver { public: - static constexpr ShadowElevation kActiveNormalShadowElevation = - ShadowElevation::LARGE; - // Returns the shadow for the |window|, or NULL if no shadow exists. static Shadow* GetShadowForWindow(aura::Window* window); diff --git a/chromium/ui/wm/core/shadow_controller_unittest.cc b/chromium/ui/wm/core/shadow_controller_unittest.cc index b4a6269c4bc..c3af5692265 100644 --- a/chromium/ui/wm/core/shadow_controller_unittest.cc +++ b/chromium/ui/wm/core/shadow_controller_unittest.cc @@ -61,23 +61,24 @@ TEST_F(ShadowControllerTest, Shadow) { window->Init(ui::LAYER_TEXTURED); ParentWindow(window.get()); - // We should create the shadow before the window is visible (the shadow's - // layer won't get drawn yet since it's a child of the window's layer). + // The shadow is not created until the Window is shown (some Windows should + // never get shadows, which is checked when the window first becomes visible). + EXPECT_FALSE(ShadowController::GetShadowForWindow(window.get())); + window->Show(); + const Shadow* shadow = ShadowController::GetShadowForWindow(window.get()); ASSERT_TRUE(shadow != NULL); EXPECT_TRUE(shadow->layer()->visible()); // The shadow should remain visible after window visibility changes. - window->Show(); - EXPECT_TRUE(shadow->layer()->visible()); window->Hide(); EXPECT_TRUE(shadow->layer()->visible()); // If the shadow is disabled, it should be hidden. - SetShadowElevation(window.get(), ShadowElevation::NONE); + SetShadowElevation(window.get(), kShadowElevationNone); window->Show(); EXPECT_FALSE(shadow->layer()->visible()); - SetShadowElevation(window.get(), ShadowElevation::MEDIUM); + SetShadowElevation(window.get(), kShadowElevationInactiveWindow); EXPECT_TRUE(shadow->layer()->visible()); // The shadow's layer should be a child of the window's layer. @@ -97,7 +98,7 @@ TEST_F(ShadowControllerTest, ShadowBounds) { // When the shadow is first created, it should use the window's size (but // remain at the origin, since it's a child of the window's layer). - SetShadowElevation(window.get(), ShadowElevation::MEDIUM); + SetShadowElevation(window.get(), kShadowElevationInactiveWindow); const Shadow* shadow = ShadowController::GetShadowForWindow(window.get()); ASSERT_TRUE(shadow != NULL); EXPECT_EQ(gfx::Rect(kOldBounds.size()).ToString(), @@ -123,7 +124,7 @@ TEST_F(ShadowControllerTest, ShadowStyle) { // window1 is active, so style should have active appearance. Shadow* shadow1 = ShadowController::GetShadowForWindow(window1.get()); ASSERT_TRUE(shadow1 != NULL); - EXPECT_EQ(ShadowElevation::LARGE, shadow1->desired_elevation()); + EXPECT_EQ(kShadowElevationActiveWindow, shadow1->desired_elevation()); // Create another window and activate it. std::unique_ptr<aura::Window> window2(new aura::Window(NULL)); @@ -137,8 +138,8 @@ TEST_F(ShadowControllerTest, ShadowStyle) { // window1 is now inactive, so shadow should go inactive. Shadow* shadow2 = ShadowController::GetShadowForWindow(window2.get()); ASSERT_TRUE(shadow2 != NULL); - EXPECT_EQ(ShadowElevation::MEDIUM, shadow1->desired_elevation()); - EXPECT_EQ(ShadowElevation::LARGE, shadow2->desired_elevation()); + EXPECT_EQ(kShadowElevationInactiveWindow, shadow1->desired_elevation()); + EXPECT_EQ(kShadowElevationActiveWindow, shadow2->desired_elevation()); } // Tests that shadow gets updated when the window show state changes. @@ -151,7 +152,7 @@ TEST_F(ShadowControllerTest, ShowState) { Shadow* shadow = ShadowController::GetShadowForWindow(window.get()); ASSERT_TRUE(shadow != NULL); - EXPECT_EQ(ShadowElevation::MEDIUM, shadow->desired_elevation()); + EXPECT_EQ(kShadowElevationInactiveWindow, shadow->desired_elevation()); window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); EXPECT_FALSE(shadow->layer()->visible()); @@ -175,7 +176,7 @@ TEST_F(ShadowControllerTest, SmallShadowsForTooltipsAndMenus) { Shadow* tooltip_shadow = ShadowController::GetShadowForWindow(tooltip_window.get()); ASSERT_TRUE(tooltip_shadow != NULL); - EXPECT_EQ(ShadowElevation::SMALL, tooltip_shadow->desired_elevation()); + EXPECT_EQ(kShadowElevationMenuOrTooltip, tooltip_shadow->desired_elevation()); std::unique_ptr<aura::Window> menu_window(new aura::Window(NULL)); menu_window->SetType(aura::client::WINDOW_TYPE_MENU); @@ -187,7 +188,7 @@ TEST_F(ShadowControllerTest, SmallShadowsForTooltipsAndMenus) { Shadow* menu_shadow = ShadowController::GetShadowForWindow(tooltip_window.get()); ASSERT_TRUE(menu_shadow != NULL); - EXPECT_EQ(ShadowElevation::SMALL, menu_shadow->desired_elevation()); + EXPECT_EQ(kShadowElevationMenuOrTooltip, menu_shadow->desired_elevation()); } // http://crbug.com/120210 - transient parents of certain types of transients @@ -204,7 +205,7 @@ TEST_F(ShadowControllerTest, TransientParentKeepsActiveShadow) { // window1 is active, so style should have active appearance. Shadow* shadow1 = ShadowController::GetShadowForWindow(window1.get()); ASSERT_TRUE(shadow1 != NULL); - EXPECT_EQ(ShadowElevation::LARGE, shadow1->desired_elevation()); + EXPECT_EQ(kShadowElevationActiveWindow, shadow1->desired_elevation()); // Create a window that is transient to window1, and that has the 'hide on // deactivate' property set. Upon activation, window1 should still have an @@ -220,7 +221,7 @@ TEST_F(ShadowControllerTest, TransientParentKeepsActiveShadow) { ActivateWindow(window2.get()); // window1 is now inactive, but its shadow should still appear active. - EXPECT_EQ(ShadowElevation::LARGE, shadow1->desired_elevation()); + EXPECT_EQ(kShadowElevationActiveWindow, shadow1->desired_elevation()); } } // namespace wm diff --git a/chromium/ui/wm/core/shadow_types.cc b/chromium/ui/wm/core/shadow_types.cc index 431ab2e41cf..bc8679fc1a2 100644 --- a/chromium/ui/wm/core/shadow_types.cc +++ b/chromium/ui/wm/core/shadow_types.cc @@ -6,29 +6,12 @@ #include "ui/base/class_property.h" -DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(WM_CORE_EXPORT, ::wm::ShadowElevation); - namespace wm { -DEFINE_UI_CLASS_PROPERTY_KEY(ShadowElevation, - kShadowElevationKey, - ShadowElevation::DEFAULT); +DEFINE_UI_CLASS_PROPERTY_KEY(int, kShadowElevationKey, kShadowElevationDefault); -void SetShadowElevation(aura::Window* window, ShadowElevation elevation) { +void SetShadowElevation(aura::Window* window, int elevation) { window->SetProperty(kShadowElevationKey, elevation); } -bool IsValidShadowElevation(int64_t value) { - switch (static_cast<ShadowElevation>(value)) { - case ShadowElevation::DEFAULT: - case ShadowElevation::NONE: - case ShadowElevation::TINY: - case ShadowElevation::SMALL: - case ShadowElevation::MEDIUM: - case ShadowElevation::LARGE: - return true; - } - return false; -} - } // namespace wm diff --git a/chromium/ui/wm/core/shadow_types.h b/chromium/ui/wm/core/shadow_types.h index b61a325ac04..5cc02c20baf 100644 --- a/chromium/ui/wm/core/shadow_types.h +++ b/chromium/ui/wm/core/shadow_types.h @@ -10,39 +10,28 @@ namespace wm { +// Indicates an elevation should be chosen based on the window. This is used +// by wm::ShadowController, but is not a valid elevation to pass to wm::Shadow. +constexpr int kShadowElevationDefault = -1; + // Different types of drop shadows that can be drawn under a window by the -// shell. Used as a value for the kShadowTypeKey property. The integer value of -// each entry is directly used for determining the size of the shadow. -enum class ShadowElevation { - // Indicates an elevation should be chosen based on the window. This is the - // default. - DEFAULT = -1, - NONE = 0, - TINY = 2, - SMALL = 6, - MEDIUM = 8, - LARGE = 24, -}; - -WM_CORE_EXPORT void SetShadowElevation(aura::Window* window, - ShadowElevation elevation); - -// Returns true if |value| is a valid element of ShadowElevation elements. -WM_CORE_EXPORT bool IsValidShadowElevation(int64_t value); +// shell. Used as a value for the kShadowElevationKey property. +constexpr int kShadowElevationNone = 0; + +// Standard shadow elevations used by the the aura window manager. The value is +// used to initialize an instance of wm::Shadow and controls the offset and blur +// of the shadow style created by gfx::ShadowValue::MakeMdShadowValues(). +constexpr int kShadowElevationMenuOrTooltip = 6; +constexpr int kShadowElevationInactiveWindow = 8; +constexpr int kShadowElevationActiveWindow = 24; + +WM_CORE_EXPORT void SetShadowElevation(aura::Window* window, int elevation); // A property key describing the drop shadow that should be displayed under the // window. A null value is interpreted as using the default. -WM_CORE_EXPORT extern const aura::WindowProperty<ShadowElevation>* const +WM_CORE_EXPORT extern const aura::WindowProperty<int>* const kShadowElevationKey; } // namespace wm -// Declaring the template specialization here to make sure that the -// compiler in all builds, including jumbo builds, always knows about -// the specialization before the first template instance use (for -// instance in shadw_controller.cc). Using a template instance before -// its specialization is declared in a translation unit is a C++ -// error. -DECLARE_EXPORTED_UI_CLASS_PROPERTY_TYPE(WM_CORE_EXPORT, ::wm::ShadowElevation); - #endif // UI_WM_CORE_SHADOW_TYPES_H_ diff --git a/chromium/ui/wm/core/shadow_unittest.cc b/chromium/ui/wm/core/shadow_unittest.cc index 3e720a404f0..28cef9b62ac 100644 --- a/chromium/ui/wm/core/shadow_unittest.cc +++ b/chromium/ui/wm/core/shadow_unittest.cc @@ -8,11 +8,13 @@ #include "ui/aura/test/aura_test_base.h" #include "ui/gfx/shadow_util.h" #include "ui/gfx/shadow_value.h" -#include "ui/wm/core/shadow_types.h" namespace wm { namespace { +constexpr int kElevationLarge = 24; +constexpr int kElevationSmall = 6; + gfx::Insets InsetsForElevation(int elevation) { return -gfx::Insets(2 * elevation) + gfx::Insets(elevation, 0, -elevation, 0); } @@ -33,22 +35,22 @@ TEST_F(ShadowTest, SetContentBounds) { // Verify that layer bounds are outset from content bounds. Shadow shadow; { - shadow.Init(ShadowElevation::LARGE); + shadow.Init(kElevationLarge); gfx::Rect content_bounds(100, 100, 300, 300); shadow.SetContentBounds(content_bounds); EXPECT_EQ(content_bounds, shadow.content_bounds()); gfx::Rect shadow_bounds(content_bounds); - shadow_bounds.Inset(InsetsForElevation(24)); + shadow_bounds.Inset(InsetsForElevation(kElevationLarge)); EXPECT_EQ(shadow_bounds, shadow.layer()->bounds()); } { - shadow.SetElevation(ShadowElevation::SMALL); + shadow.SetElevation(kElevationSmall); gfx::Rect content_bounds(100, 100, 300, 300); shadow.SetContentBounds(content_bounds); EXPECT_EQ(content_bounds, shadow.content_bounds()); gfx::Rect shadow_bounds(content_bounds); - shadow_bounds.Inset(InsetsForElevation(6)); + shadow_bounds.Inset(InsetsForElevation(kElevationSmall)); EXPECT_EQ(shadow_bounds, shadow.layer()->bounds()); } } @@ -57,12 +59,12 @@ TEST_F(ShadowTest, SetContentBounds) { // the full elevation. TEST_F(ShadowTest, AdjustElevationForSmallContents) { Shadow shadow; - shadow.Init(ShadowElevation::LARGE); + shadow.Init(kElevationLarge); { gfx::Rect content_bounds(100, 100, 300, 300); shadow.SetContentBounds(content_bounds); gfx::Rect shadow_bounds(content_bounds); - shadow_bounds.Inset(InsetsForElevation(24)); + shadow_bounds.Inset(InsetsForElevation(kElevationLarge)); EXPECT_EQ(shadow_bounds, shadow.layer()->bounds()); } @@ -88,13 +90,13 @@ TEST_F(ShadowTest, AdjustElevationForSmallContents) { // Test that rounded corner radius is handled correctly. TEST_F(ShadowTest, AdjustRoundedCornerRadius) { Shadow shadow; - shadow.Init(ShadowElevation::SMALL); + shadow.Init(kElevationSmall); gfx::Rect content_bounds(100, 100, 300, 300); shadow.SetContentBounds(content_bounds); EXPECT_EQ(content_bounds, shadow.content_bounds()); shadow.SetRoundedCornerRadius(0); gfx::Rect shadow_bounds(content_bounds); - shadow_bounds.Inset(InsetsForElevation(6)); + shadow_bounds.Inset(InsetsForElevation(kElevationSmall)); EXPECT_EQ(shadow_bounds, shadow.layer()->bounds()); EXPECT_EQ(NineboxImageSizeForElevationAndCornerRadius(6, 0), shadow.details_for_testing()->ninebox_image.size()); diff --git a/chromium/ui/wm/core/window_util.cc b/chromium/ui/wm/core/window_util.cc index 264ea83ec1a..d8cbfdc9e6a 100644 --- a/chromium/ui/wm/core/window_util.cc +++ b/chromium/ui/wm/core/window_util.cc @@ -131,11 +131,6 @@ void Unminimize(aura::Window* window) { window->SetProperty( aura::client::kShowStateKey, window->GetProperty(aura::client::kPreMinimizedShowStateKey)); - // Clear the property only when the window is actually unminimized. - if (window->GetProperty(aura::client::kShowStateKey) != - ui::SHOW_STATE_MINIMIZED) { - window->ClearProperty(aura::client::kPreMinimizedShowStateKey); - } } aura::Window* GetActivatableWindow(aura::Window* window) { |