160 lines
4.5 KiB
C++
160 lines
4.5 KiB
C++
#include <reanimated/CSS/utils/props.h>
|
|
|
|
namespace reanimated::css {
|
|
|
|
bool isDiscreteProperty(
|
|
const std::string &propName,
|
|
const std::string &componentName) {
|
|
const auto &interpolators = getComponentInterpolators(componentName);
|
|
const auto it = interpolators.find(propName);
|
|
if (it == interpolators.end()) {
|
|
return false;
|
|
}
|
|
return it->second->isDiscreteProperty();
|
|
}
|
|
|
|
bool areArraysDifferentRecursive(
|
|
const folly::dynamic &oldArray,
|
|
const folly::dynamic &newArray) {
|
|
if (oldArray.size() != newArray.size()) {
|
|
return true;
|
|
}
|
|
|
|
for (size_t i = 0; i < oldArray.size(); i++) {
|
|
const auto [oldChangedProp, newChangedProp] =
|
|
getChangedPropsRecursive(oldArray[i], newArray[i]);
|
|
|
|
if (!oldChangedProp.isNull() || !newChangedProp.isNull()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::pair<folly::dynamic, folly::dynamic> getChangedPropsRecursive(
|
|
const folly::dynamic &oldProp,
|
|
const folly::dynamic &newProp) {
|
|
if (!oldProp.isObject() || !newProp.isObject()) {
|
|
// Primitive values comparison
|
|
if (oldProp != newProp) {
|
|
return {oldProp, newProp};
|
|
}
|
|
return {folly::dynamic(), folly::dynamic()};
|
|
}
|
|
|
|
if (oldProp.isArray() && newProp.isArray()) {
|
|
// Arrays comparison
|
|
if (areArraysDifferentRecursive(oldProp, newProp)) {
|
|
return {oldProp, newProp};
|
|
}
|
|
return {folly::dynamic(), folly::dynamic()};
|
|
}
|
|
|
|
folly::dynamic oldResult = folly::dynamic::object;
|
|
folly::dynamic newResult = folly::dynamic::object;
|
|
bool oldHasChanges = false;
|
|
bool newHasChanges = false;
|
|
|
|
// Check for removed properties
|
|
for (const auto &item : oldProp.items()) {
|
|
const auto &propName = item.first.asString();
|
|
if (!newProp.count(propName)) {
|
|
const auto &oldValue = item.second;
|
|
oldResult[propName] = oldValue;
|
|
oldHasChanges = true;
|
|
}
|
|
}
|
|
|
|
// Check for new and changed properties
|
|
for (const auto &item : newProp.items()) {
|
|
const auto &propName = item.first.asString();
|
|
const auto &newValue = item.second;
|
|
|
|
if (oldProp.count(propName)) {
|
|
const auto &oldValue = oldProp[propName];
|
|
auto [oldChangedProp, newChangedProp] =
|
|
getChangedPropsRecursive(oldValue, newValue);
|
|
|
|
if (!oldChangedProp.isNull() && !newChangedProp.isNull()) {
|
|
oldResult[propName] = std::move(oldChangedProp);
|
|
newResult[propName] = std::move(newChangedProp);
|
|
oldHasChanges = true;
|
|
newHasChanges = true;
|
|
}
|
|
} else {
|
|
newResult[propName] = newValue;
|
|
newHasChanges = true;
|
|
}
|
|
}
|
|
|
|
return {
|
|
oldHasChanges ? std::move(oldResult) : folly::dynamic(),
|
|
newHasChanges ? std::move(newResult) : folly::dynamic()};
|
|
}
|
|
|
|
std::pair<folly::dynamic, folly::dynamic> getChangedValueForProp(
|
|
const folly::dynamic &oldObject,
|
|
const folly::dynamic &newObject,
|
|
const std::string &propName) {
|
|
const bool oldHasProperty = oldObject.count(propName);
|
|
const bool newHasProperty = newObject.count(propName);
|
|
|
|
if (oldHasProperty && newHasProperty) {
|
|
const auto &oldVal = oldObject[propName];
|
|
const auto &newVal = newObject[propName];
|
|
|
|
if (oldVal.isObject() && newVal.isObject()) {
|
|
return getChangedPropsRecursive(oldVal, newVal);
|
|
} else if (oldVal != newVal) {
|
|
return {oldVal, newVal};
|
|
}
|
|
|
|
return {folly::dynamic(), folly::dynamic()};
|
|
}
|
|
|
|
if (oldHasProperty) {
|
|
const auto &oldVal = oldObject[propName];
|
|
return {oldVal, folly::dynamic()};
|
|
} else if (newHasProperty) {
|
|
const auto &newVal = newObject[propName];
|
|
return {folly::dynamic(), newVal};
|
|
}
|
|
|
|
return {folly::dynamic(), folly::dynamic()};
|
|
}
|
|
|
|
ChangedProps getChangedProps(
|
|
const folly::dynamic &oldProps,
|
|
const folly::dynamic &newProps,
|
|
const PropertyNames &allowedProperties) {
|
|
folly::dynamic oldResult = folly::dynamic::object;
|
|
folly::dynamic newResult = folly::dynamic::object;
|
|
PropertyNames changedPropertyNames;
|
|
|
|
for (const auto &propName : allowedProperties) {
|
|
auto [oldChangedProp, newChangedProp] =
|
|
getChangedValueForProp(oldProps, newProps, propName);
|
|
|
|
const auto hasOldChangedProp = !oldChangedProp.isNull();
|
|
const auto hasNewChangedProp = !newChangedProp.isNull();
|
|
|
|
if (hasOldChangedProp) {
|
|
oldResult[propName] = std::move(oldChangedProp);
|
|
}
|
|
if (hasNewChangedProp) {
|
|
newResult[propName] = std::move(newChangedProp);
|
|
}
|
|
if (hasOldChangedProp || hasNewChangedProp) {
|
|
changedPropertyNames.push_back(propName);
|
|
}
|
|
}
|
|
|
|
return {
|
|
std::move(oldResult),
|
|
std::move(newResult),
|
|
std::move(changedPropertyNames)};
|
|
}
|
|
|
|
} // namespace reanimated::css
|