Files
react-native/ReactCommon/react/renderer/components/view/accessibilityPropsConversions.h
T
Joshua Gross cb37562f83 Remove abort in props parsing
Summary:
Goals are:

1. Catch errors in parsing during dev-mode in a way that is disruptive/grabs attention, but has enough information.
2. Use react_native_assert for hitting breakpoints (less useful for Android, more for iOS), and add LOGs for when this code is used in Android (more useful for Android, less useful for iOS).
3. Return sane defaults so that prod cases don't crash, and don't return totally garbage data.

I also found a couple cases where parsing was incorrect before; see WritingDirection and TextAlignment. This could impact some layouts and RTL/LTR potentially.

Changelog: [Internal]

Reviewed By: fkgozali

Differential Revision: D27540903

fbshipit-source-id: 99e6949d97e8ef5520d008c1df3cbe408b5a43a4
2021-04-02 16:31:13 -07:00

197 lines
5.4 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <folly/dynamic.h>
#include <glog/logging.h>
#include <react/debug/react_native_assert.h>
#include <react/renderer/components/view/AccessibilityPrimitives.h>
#include <react/renderer/core/propsConversions.h>
namespace facebook {
namespace react {
inline void fromString(const std::string &string, AccessibilityTraits &result) {
if (string == "none") {
result = AccessibilityTraits::None;
return;
}
if (string == "button") {
result = AccessibilityTraits::Button;
return;
}
if (string == "link") {
result = AccessibilityTraits::Link;
return;
}
if (string == "image") {
result = AccessibilityTraits::Image;
return;
}
if (string == "selected") {
result = AccessibilityTraits::Selected;
return;
}
if (string == "plays") {
result = AccessibilityTraits::PlaysSound;
return;
}
if (string == "keyboardkey" || string == "key") {
result = AccessibilityTraits::KeyboardKey;
return;
}
if (string == "text") {
result = AccessibilityTraits::StaticText;
return;
}
if (string == "disabled") {
result = AccessibilityTraits::NotEnabled;
return;
}
if (string == "frequentUpdates") {
result = AccessibilityTraits::UpdatesFrequently;
return;
}
if (string == "search") {
result = AccessibilityTraits::SearchField;
return;
}
if (string == "startsMedia") {
result = AccessibilityTraits::StartsMediaSession;
return;
}
if (string == "adjustable") {
result = AccessibilityTraits::Adjustable;
return;
}
if (string == "allowsDirectInteraction") {
result = AccessibilityTraits::AllowsDirectInteraction;
return;
}
if (string == "pageTurn") {
result = AccessibilityTraits::CausesPageTurn;
return;
}
if (string == "header") {
result = AccessibilityTraits::Header;
return;
}
if (string == "imagebutton") {
result = AccessibilityTraits::Image | AccessibilityTraits::Button;
return;
}
if (string == "summary") {
result = AccessibilityTraits::SummaryElement;
return;
}
if (string == "switch") {
result = AccessibilityTraits::Switch;
return;
}
result = AccessibilityTraits::None;
}
inline void fromRawValue(const RawValue &value, AccessibilityTraits &result) {
if (value.hasType<std::string>()) {
fromString((std::string)value, result);
return;
}
result = {};
react_native_assert(value.hasType<std::vector<std::string>>());
if (value.hasType<std::vector<std::string>>()) {
auto items = (std::vector<std::string>)value;
for (auto &item : items) {
AccessibilityTraits itemAccessibilityTraits;
fromString(item, itemAccessibilityTraits);
result = result | itemAccessibilityTraits;
}
} else {
LOG(ERROR) << "AccessibilityTraits parsing: unsupported type";
}
}
inline void fromRawValue(const RawValue &value, AccessibilityState &result) {
auto map = (better::map<std::string, RawValue>)value;
auto selected = map.find("selected");
if (selected != map.end()) {
fromRawValue(selected->second, result.selected);
}
auto disabled = map.find("disabled");
if (disabled != map.end()) {
fromRawValue(disabled->second, result.disabled);
}
auto checked = map.find("checked");
if (checked != map.end()) {
if (checked->second.hasType<std::string>()) {
if ((std::string)checked->second == "mixed") {
result.checked = AccessibilityState::Mixed;
} else {
result.checked = AccessibilityState::None;
}
} else if (checked->second.hasType<bool>()) {
if ((bool)checked->second == true) {
result.checked = AccessibilityState::Checked;
} else {
result.checked = AccessibilityState::Unchecked;
}
} else {
result.checked = AccessibilityState::None;
}
}
auto busy = map.find("busy");
if (busy != map.end()) {
fromRawValue(busy->second, result.busy);
}
auto expanded = map.find("expanded");
if (expanded != map.end()) {
fromRawValue(expanded->second, result.expanded);
}
}
inline std::string toString(
const ImportantForAccessibility &importantForAccessibility) {
switch (importantForAccessibility) {
case ImportantForAccessibility::Auto:
return "auto";
case ImportantForAccessibility::Yes:
return "yes";
case ImportantForAccessibility::No:
return "no";
case ImportantForAccessibility::NoHideDescendants:
return "no-hide-descendants";
}
}
inline void fromRawValue(
const RawValue &value,
ImportantForAccessibility &result) {
react_native_assert(value.hasType<std::string>());
if (value.hasType<std::string>()) {
auto string = (std::string)value;
if (string == "auto") {
result = ImportantForAccessibility::Auto;
} else if (string == "yes") {
result = ImportantForAccessibility::Yes;
} else if (string == "no") {
result = ImportantForAccessibility::No;
} else if (string == "no-hide-descendants") {
result = ImportantForAccessibility::NoHideDescendants;
} else {
LOG(ERROR) << "Unsupported ImportantForAccessiblity value: " << string;
react_native_assert(false);
}
} else {
LOG(ERROR) << "Unsupported ImportantForAccessiblity type";
}
}
} // namespace react
} // namespace facebook