Commit 015d96fa authored by Bruce Long's avatar Bruce Long Committed by Commit Bot

Adding core caret browsing functionality (renderer side only)

This change implements native caret browsing. In caret
browsing, a moveable cursor is placed on a web page, allowing a user
to select and navigate through non-editable text with just a keyboard.

The changes on the renderer process side are those
needed to make the caret visible and moveable in non-editable
text when caret browsing is enabled, move the focus when the caret moves
into a focusable element such as an anchor, and move the caret to the
active element on initiating navigation if not already there.

For the initial landing of caret browsing, no UX is exposed to the user for
toggling caret browsing on and off (using F7 as in other browsers e.g.),
nor are there any means exposed on about:flags to enable the feature. Instead
caret browsing is enabled on browser launch via a command line parameter,
similar to the current behavior of the spatial navigation feature:

    chrome --enable-caret-browsing

All new tabs created during the browser session will have caret
browsing turned on.

To fully land the feature in a later CL would require implementing the
following UX elements as well:

1) Adding the F7 (or other appropriate key) as an accelerator to toggle
   caret browsing on and off.

2) Creating a caret browsing dialog confirming with the user that
   caret browsing should be toggled on or off.

3) Adding two new browser settings: one indicating if caret browsing is
   currently enabled, and another that indicates if pressing F7 should trigger
   a confirmation dialog or just enable/disable caret browsing without confirmation.

4) Plumbing a mechanism for passing the "caret browsing is enabled" setting from
   the browser process to renderer processes.

5) Adding a flag for this feature to "about:flags", exposing a means for
   the user to enable or disable the feature without a command line flag.

Note that these UX elements were already implemented in earlier patchsets
of this CL--see patchset 18 as the last patch before their removal. Separating
the feature implementation into multiple CLs allows early experimentation
of the renderer side changes and accounts for the possibility that
different browsers may opt for a different UX.

Bug: 977390
Change-Id: I1906165037c96079d7bec70683f3cc446580f56e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1666567
Commit-Queue: Bruce Long <brlong@microsoft.com>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Reviewed-by: default avatarCharlie Reis <creis@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#677097}
parent 6a6f60ae
...@@ -562,6 +562,9 @@ const WebPreferences RenderViewHostImpl::ComputeWebPreferences() { ...@@ -562,6 +562,9 @@ const WebPreferences RenderViewHostImpl::ComputeWebPreferences() {
if (delegate_ && delegate_->IsSpatialNavigationDisabled()) if (delegate_ && delegate_->IsSpatialNavigationDisabled())
prefs.spatial_navigation_enabled = false; prefs.spatial_navigation_enabled = false;
prefs.caret_browsing_enabled =
command_line.HasSwitch(switches::kEnableCaretBrowsing);
prefs.disable_reading_from_canvas = command_line.HasSwitch( prefs.disable_reading_from_canvas = command_line.HasSwitch(
switches::kDisableReadingFromCanvas); switches::kDisableReadingFromCanvas);
......
...@@ -194,6 +194,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences) ...@@ -194,6 +194,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(cookie_enabled) IPC_STRUCT_TRAITS_MEMBER(cookie_enabled)
IPC_STRUCT_TRAITS_MEMBER(navigate_on_drag_drop) IPC_STRUCT_TRAITS_MEMBER(navigate_on_drag_drop)
IPC_STRUCT_TRAITS_MEMBER(spatial_navigation_enabled) IPC_STRUCT_TRAITS_MEMBER(spatial_navigation_enabled)
IPC_STRUCT_TRAITS_MEMBER(caret_browsing_enabled)
IPC_STRUCT_TRAITS_MEMBER(v8_cache_options) IPC_STRUCT_TRAITS_MEMBER(v8_cache_options)
IPC_STRUCT_TRAITS_MEMBER(accelerated_video_decode_enabled) IPC_STRUCT_TRAITS_MEMBER(accelerated_video_decode_enabled)
IPC_STRUCT_TRAITS_MEMBER(animation_policy) IPC_STRUCT_TRAITS_MEMBER(animation_policy)
......
...@@ -340,6 +340,11 @@ const char kEnablePreferCompositingToLCDText[] = ...@@ -340,6 +340,11 @@ const char kEnablePreferCompositingToLCDText[] =
// features. // features.
const char kEnableBlinkFeatures[] = "enable-blink-features"; const char kEnableBlinkFeatures[] = "enable-blink-features";
// Enable native caret browsing, in which a moveable cursor is placed on a web
// page, allowing a user to select and navigate through non-editable text using
// just a keyboard. See https://crbug.com/977390 for links to i2i.
const char kEnableCaretBrowsing[] = "enable-caret-browsing";
// Enable default SiteInstance to be used for all unisolated sites. // Enable default SiteInstance to be used for all unisolated sites.
const char kEnableDefaultSiteInstance[] = "enable-default-site-instance"; const char kEnableDefaultSiteInstance[] = "enable-default-site-instance";
......
...@@ -110,6 +110,7 @@ CONTENT_EXPORT extern const char kEnableAggressiveDOMStorageFlushing[]; ...@@ -110,6 +110,7 @@ CONTENT_EXPORT extern const char kEnableAggressiveDOMStorageFlushing[];
CONTENT_EXPORT extern const char kEnableAutomation[]; CONTENT_EXPORT extern const char kEnableAutomation[];
CONTENT_EXPORT extern const char kEnablePreferCompositingToLCDText[]; CONTENT_EXPORT extern const char kEnablePreferCompositingToLCDText[];
CONTENT_EXPORT extern const char kEnableBlinkFeatures[]; CONTENT_EXPORT extern const char kEnableBlinkFeatures[];
CONTENT_EXPORT extern const char kEnableCaretBrowsing[];
CONTENT_EXPORT extern const char kEnableDisplayList2dCanvas[]; CONTENT_EXPORT extern const char kEnableDisplayList2dCanvas[];
CONTENT_EXPORT extern const char kEnableDefaultSiteInstance[]; CONTENT_EXPORT extern const char kEnableDefaultSiteInstance[];
CONTENT_EXPORT extern const char kEnableExperimentalWebPlatformFeatures[]; CONTENT_EXPORT extern const char kEnableExperimentalWebPlatformFeatures[];
......
...@@ -166,6 +166,7 @@ WebPreferences::WebPreferences() ...@@ -166,6 +166,7 @@ WebPreferences::WebPreferences()
smart_insert_delete_enabled(false), smart_insert_delete_enabled(false),
#endif #endif
spatial_navigation_enabled(false), spatial_navigation_enabled(false),
caret_browsing_enabled(false),
use_solid_color_scrollbars(false), use_solid_color_scrollbars(false),
navigate_on_drag_drop(true), navigate_on_drag_drop(true),
v8_cache_options(blink::mojom::V8CacheOptions::kDefault), v8_cache_options(blink::mojom::V8CacheOptions::kDefault),
......
...@@ -183,6 +183,7 @@ struct CONTENT_EXPORT WebPreferences { ...@@ -183,6 +183,7 @@ struct CONTENT_EXPORT WebPreferences {
bool initialize_at_minimum_page_scale; bool initialize_at_minimum_page_scale;
bool smart_insert_delete_enabled; bool smart_insert_delete_enabled;
bool spatial_navigation_enabled; bool spatial_navigation_enabled;
bool caret_browsing_enabled;
bool use_solid_color_scrollbars; bool use_solid_color_scrollbars;
bool navigate_on_drag_drop; bool navigate_on_drag_drop;
blink::mojom::V8CacheOptions v8_cache_options; blink::mojom::V8CacheOptions v8_cache_options;
......
...@@ -787,6 +787,8 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs, ...@@ -787,6 +787,8 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
if (prefs.spatial_navigation_enabled) if (prefs.spatial_navigation_enabled)
WebRuntimeFeatures::EnableKeyboardFocusableScrollers(true); WebRuntimeFeatures::EnableKeyboardFocusableScrollers(true);
settings->SetCaretBrowsingEnabled(prefs.caret_browsing_enabled);
settings->SetSelectionIncludesAltImageText(true); settings->SetSelectionIncludesAltImageText(true);
settings->SetV8CacheOptions( settings->SetV8CacheOptions(
......
...@@ -135,6 +135,7 @@ class WebSettings { ...@@ -135,6 +135,7 @@ class WebSettings {
virtual void SetAntialiasedClips2dCanvasEnabled(bool) = 0; virtual void SetAntialiasedClips2dCanvasEnabled(bool) = 0;
virtual void SetAutoplayPolicy(AutoplayPolicy) = 0; virtual void SetAutoplayPolicy(AutoplayPolicy) = 0;
virtual void SetAutoZoomFocusedNodeToLegibleScale(bool) = 0; virtual void SetAutoZoomFocusedNodeToLegibleScale(bool) = 0;
virtual void SetCaretBrowsingEnabled(bool) = 0;
virtual void SetClobberUserAgentInitialScaleQuirk(bool) = 0; virtual void SetClobberUserAgentInitialScaleQuirk(bool) = 0;
virtual void SetCookieEnabled(bool) = 0; virtual void SetCookieEnabled(bool) = 0;
virtual void SetNavigateOnDragDrop(bool) = 0; virtual void SetNavigateOnDragDrop(bool) = 0;
......
...@@ -343,6 +343,7 @@ jumbo_source_set("unit_tests") { ...@@ -343,6 +343,7 @@ jumbo_source_set("unit_tests") {
"commands/insert_list_command_test.cc", "commands/insert_list_command_test.cc",
"commands/insert_paragraph_separator_command_test.cc", "commands/insert_paragraph_separator_command_test.cc",
"commands/insert_text_command_test.cc", "commands/insert_text_command_test.cc",
"commands/move_commands_test.cc",
"commands/replace_selection_command_test.cc", "commands/replace_selection_command_test.cc",
"commands/set_character_data_command_test.cc", "commands/set_character_data_command_test.cc",
"commands/split_text_node_command_test.cc", "commands/split_text_node_command_test.cc",
......
...@@ -7,8 +7,11 @@ ...@@ -7,8 +7,11 @@
#include "third_party/blink/renderer/core/editing/commands/editor_command.h" #include "third_party/blink/renderer/core/editing/commands/editor_command.h"
#include "third_party/blink/renderer/core/editing/commands/editor_command_names.h" #include "third_party/blink/renderer/core/editing/commands/editor_command_names.h"
#include "third_party/blink/renderer/core/editing/editor.h" #include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h" #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink { namespace blink {
...@@ -79,4 +82,64 @@ TEST_F(EditingCommandTest, CreateCommandFromInvalidString) { ...@@ -79,4 +82,64 @@ TEST_F(EditingCommandTest, CreateCommandFromInvalidString) {
} }
} }
TEST_F(EditingCommandTest, EnabledVisibleSelection) {
Editor& editor = GetDocument().GetFrame()->GetEditor();
const EditorCommand command =
editor.CreateCommand("MoveRightAndModifySelection");
Selection().SetSelection(
SetSelectionTextToBody("<div contenteditable>a|b<div>"),
SetSelectionOptions());
Element* div = GetDocument().QuerySelector("div");
GetDocument().SetFocusedElement(
div,
FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeNone, nullptr));
EXPECT_TRUE(command.IsEnabled());
div->removeAttribute("contenteditable");
EXPECT_FALSE(command.IsEnabled());
GetDocument().GetFrame()->GetSettings()->SetCaretBrowsingEnabled(true);
EXPECT_TRUE(command.IsEnabled());
}
TEST_F(EditingCommandTest, EnabledVisibleSelectionAndMark) {
Editor& editor = GetDocument().GetFrame()->GetEditor();
const EditorCommand command = editor.CreateCommand("SelectToMark");
Selection().SetSelection(
SetSelectionTextToBody("<div contenteditable>a|b<div>"),
SetSelectionOptions());
Element* div = GetDocument().QuerySelector("div");
GetDocument().SetFocusedElement(
div,
FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeNone, nullptr));
EXPECT_FALSE(command.IsEnabled());
editor.SetMark();
EXPECT_TRUE(command.IsEnabled());
div->removeAttribute("contenteditable");
EXPECT_FALSE(command.IsEnabled());
GetDocument().GetFrame()->GetSettings()->SetCaretBrowsingEnabled(true);
EXPECT_TRUE(command.IsEnabled());
}
TEST_F(EditingCommandTest, EnabledInEditableTextOrCaretBrowsing) {
Editor& editor = GetDocument().GetFrame()->GetEditor();
const EditorCommand command = editor.CreateCommand("MoveRight");
SetBodyContent("<div>abc</div>");
GetDocument().GetFrame()->GetSettings()->SetCaretBrowsingEnabled(false);
EXPECT_FALSE(command.IsEnabled());
GetDocument().GetFrame()->GetSettings()->SetCaretBrowsingEnabled(true);
EXPECT_TRUE(command.IsEnabled());
GetDocument().GetFrame()->GetSettings()->SetCaretBrowsingEnabled(false);
Selection().SetSelection(
SetSelectionTextToBody("<div contenteditable>a|b<div>"),
SetSelectionOptions());
Element* div = GetDocument().QuerySelector("div");
GetDocument().SetFocusedElement(
div,
FocusParams(SelectionBehaviorOnFocus::kNone, kWebFocusTypeNone, nullptr));
EXPECT_TRUE(command.IsEnabled());
div->removeAttribute("contenteditable");
EXPECT_FALSE(command.IsEnabled());
}
} // namespace blink } // namespace blink
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_COMMANDS_MOVE_COMMANDS_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_COMMANDS_MOVE_COMMANDS_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_COMMANDS_MOVE_COMMANDS_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_COMMANDS_MOVE_COMMANDS_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/forward.h"
...@@ -42,10 +43,12 @@ class LocalFrame; ...@@ -42,10 +43,12 @@ class LocalFrame;
enum class EditorCommandSource; enum class EditorCommandSource;
enum class SelectionModifyAlteration; enum class SelectionModifyAlteration;
enum class SelectionModifyDirection;
enum class SelectionModifyVerticalDirection; enum class SelectionModifyVerticalDirection;
enum class TextGranularity;
// This class provides static functions about commands related to move. // This class provides static functions about commands related to move.
class MoveCommands { class CORE_EXPORT MoveCommands {
STATIC_ONLY(MoveCommands); STATIC_ONLY(MoveCommands);
public: public:
...@@ -257,6 +260,26 @@ class MoveCommands { ...@@ -257,6 +260,26 @@ class MoveCommands {
SelectionModifyAlteration, SelectionModifyAlteration,
unsigned, unsigned,
SelectionModifyVerticalDirection); SelectionModifyVerticalDirection);
// Wraps FrameSelection::Modify for case where the selection is moved by the
// user. Returns false if the "selectstart" event is dispatched and canceled,
// otherwise returns true (return value does not indicate whether the
// selection was modified).
static bool MoveSelection(LocalFrame&,
SelectionModifyDirection,
TextGranularity);
// If caret browsing is enabled and the caret is in a non-editable region then
// UpdateFocusForCaretBrowsing moves focus to the nearest focusable ancestor
// of the caret, if there is one. This will, for example, move focus to anchor
// elements when the caret enters an anchor. If there is no focusable ancestor
// then focus will move to the body.
static void UpdateFocusForCaretBrowsing(LocalFrame&);
// If caret browsing is enabled and the caret/selection is not in focus then
// UpdateSelectionForCaretBrowsing moves the caret to the first position in
// the active element.
static void UpdateSelectionForCaretBrowsing(LocalFrame&);
}; };
} // namespace blink } // namespace blink
......
...@@ -150,8 +150,9 @@ void FrameCaret::UpdateStyleAndLayoutIfNeeded() { ...@@ -150,8 +150,9 @@ void FrameCaret::UpdateStyleAndLayoutIfNeeded() {
bool should_paint_caret = bool should_paint_caret =
should_paint_caret_ && IsActive() && should_paint_caret_ && IsActive() &&
caret_visibility_ == CaretVisibility::kVisible && caret_visibility_ == CaretVisibility::kVisible &&
IsEditablePosition( (IsEditablePosition(
selection_editor_->ComputeVisibleSelectionInDOMTree().Start()); selection_editor_->ComputeVisibleSelectionInDOMTree().Start()) ||
frame_->GetSettings()->GetCaretBrowsingEnabled());
display_item_client_->UpdateStyleAndLayoutIfNeeded( display_item_client_->UpdateStyleAndLayoutIfNeeded(
should_paint_caret ? CaretPosition() : PositionWithAffinity()); should_paint_caret ? CaretPosition() : PositionWithAffinity());
...@@ -187,17 +188,25 @@ void FrameCaret::PaintCaret(GraphicsContext& context, ...@@ -187,17 +188,25 @@ void FrameCaret::PaintCaret(GraphicsContext& context,
} }
bool FrameCaret::ShouldBlinkCaret() const { bool FrameCaret::ShouldBlinkCaret() const {
// Don't blink the caret if it isn't visible or positioned.
if (caret_visibility_ != CaretVisibility::kVisible || !IsActive()) if (caret_visibility_ != CaretVisibility::kVisible || !IsActive())
return false; return false;
Element* root = RootEditableElementOf(CaretPosition().GetPosition()); Element* root = RootEditableElementOf(CaretPosition().GetPosition());
if (!root) if (root) {
return false; // Caret is contained in editable content. If there is no focused element,
// don't blink the caret.
Element* focused_element = root->GetDocument().FocusedElement(); Element* focused_element = root->GetDocument().FocusedElement();
if (!focused_element) if (!focused_element)
return false; return false;
} else {
// Caret is not contained in editable content--see if caret browsing is
// enabled. If it isn't, don't blink the caret.
if (!frame_->GetSettings()->GetCaretBrowsingEnabled())
return false;
}
// Only blink the caret if the selection has focus.
return frame_->Selection().SelectionHasFocus(); return frame_->Selection().SelectionHasFocus();
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/editing/selection_template.h" #include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h" #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h" #include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h" #include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h"
...@@ -95,4 +96,14 @@ TEST_F(FrameCaretTest, ShouldNotBlinkWhenSelectionLooseFocus) { ...@@ -95,4 +96,14 @@ TEST_F(FrameCaretTest, ShouldNotBlinkWhenSelectionLooseFocus) {
EXPECT_FALSE(ShouldBlinkCaret(caret)); EXPECT_FALSE(ShouldBlinkCaret(caret));
} }
TEST_F(FrameCaretTest, ShouldBlinkCaretWhileCaretBrowsing) {
FrameCaret& caret = Selection().FrameCaretForTesting();
Selection().SetSelection(SetSelectionTextToBody("<div>a|b</div>"),
SetSelectionOptions());
Selection().SetCaretVisible(true);
EXPECT_FALSE(ShouldBlinkCaret(caret));
GetDocument().GetFrame()->GetSettings()->SetCaretBrowsingEnabled(true);
EXPECT_TRUE(ShouldBlinkCaret(caret));
}
} // namespace blink } // namespace blink
...@@ -521,7 +521,8 @@ bool FrameSelection::ShouldPaintCaret(const LayoutBlock& block) const { ...@@ -521,7 +521,8 @@ bool FrameSelection::ShouldPaintCaret(const LayoutBlock& block) const {
bool result = frame_caret_->ShouldPaintCaret(block); bool result = frame_caret_->ShouldPaintCaret(block);
DCHECK(!result || DCHECK(!result ||
(ComputeVisibleSelectionInDOMTree().IsCaret() && (ComputeVisibleSelectionInDOMTree().IsCaret() &&
IsEditablePosition(ComputeVisibleSelectionInDOMTree().Start()))); (IsEditablePosition(ComputeVisibleSelectionInDOMTree().Start()) ||
frame_->GetSettings()->GetCaretBrowsingEnabled())));
return result; return result;
} }
......
...@@ -636,6 +636,10 @@ void WebSettingsImpl::SetSyncXHRInDocumentsEnabled(bool enabled) { ...@@ -636,6 +636,10 @@ void WebSettingsImpl::SetSyncXHRInDocumentsEnabled(bool enabled) {
settings_->SetSyncXHRInDocumentsEnabled(enabled); settings_->SetSyncXHRInDocumentsEnabled(enabled);
} }
void WebSettingsImpl::SetCaretBrowsingEnabled(bool enabled) {
settings_->SetCaretBrowsingEnabled(enabled);
}
void WebSettingsImpl::SetCookieEnabled(bool enabled) { void WebSettingsImpl::SetCookieEnabled(bool enabled) {
dev_tools_emulator_->SetCookieEnabled(enabled); dev_tools_emulator_->SetCookieEnabled(enabled);
} }
......
...@@ -65,6 +65,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings { ...@@ -65,6 +65,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
void SetAutoZoomFocusedNodeToLegibleScale(bool) override; void SetAutoZoomFocusedNodeToLegibleScale(bool) override;
void SetClobberUserAgentInitialScaleQuirk(bool) override; void SetClobberUserAgentInitialScaleQuirk(bool) override;
void SetCookieEnabled(bool) override; void SetCookieEnabled(bool) override;
void SetCaretBrowsingEnabled(bool) override;
void SetNavigateOnDragDrop(bool) override; void SetNavigateOnDragDrop(bool) override;
void SetCursiveFontFamily(const WebString&, void SetCursiveFontFamily(const WebString&,
UScriptCode = USCRIPT_COMMON) override; UScriptCode = USCRIPT_COMMON) override;
......
...@@ -484,6 +484,12 @@ ...@@ -484,6 +484,12 @@
initial: false, initial: false,
}, },
// The current state of caret browsing mode.
{
name: "caretBrowsingEnabled",
initial: false,
},
// Font scale factor for accessibility, applied as part of text autosizing. // Font scale factor for accessibility, applied as part of text autosizing.
{ {
name: "accessibilityFontScaleFactor", name: "accessibilityFontScaleFactor",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment