From 62576bcb7832e08c6fd9f9482285882c37a2ece5 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 7 May 2018 17:43:08 -0700 Subject: [PATCH] Fabric/Text: attributedstring module, the second part Reviewed By: mdvacca Differential Revision: D7748711 fbshipit-source-id: 57b37cb2eaa20b85c6f6719b38eac2a2c0479485 --- .../attributedstring/AttributedString.cpp | 68 ++++++++++++++++ .../attributedstring/AttributedString.h | 75 ++++++++++++++++++ .../attributedstring/TextAttributes.cpp | 79 +++++++++++++++++++ .../fabric/attributedstring/TextAttributes.h | 79 +++++++++++++++++++ 4 files changed, 301 insertions(+) create mode 100644 ReactCommon/fabric/attributedstring/AttributedString.cpp create mode 100644 ReactCommon/fabric/attributedstring/AttributedString.h create mode 100644 ReactCommon/fabric/attributedstring/TextAttributes.cpp create mode 100644 ReactCommon/fabric/attributedstring/TextAttributes.h diff --git a/ReactCommon/fabric/attributedstring/AttributedString.cpp b/ReactCommon/fabric/attributedstring/AttributedString.cpp new file mode 100644 index 000000000..b5eb74af1 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/AttributedString.cpp @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "AttributedString.h" + +#include + +namespace facebook { +namespace react { + +using Fragment = AttributedString::Fragment; +using Fragments = AttributedString::Fragments; + +void AttributedString::appendFragment(const Fragment &fragment) { + ensureUnsealed(); + fragments_.push_back(fragment); +} + +void AttributedString::prependFragment(const Fragment &fragment) { + ensureUnsealed(); + fragments_.insert(fragments_.begin(), fragment); +} + +void AttributedString::appendAttributedString(const AttributedString &attributedString) { + ensureUnsealed(); + fragments_.insert(fragments_.end(), attributedString.fragments_.begin(), attributedString.fragments_.end()); +} + +void AttributedString::prependAttributedString(const AttributedString &attributedString) { + ensureUnsealed(); + fragments_.insert(fragments_.begin(), attributedString.fragments_.begin(), attributedString.fragments_.end()); +} + +const std::vector &AttributedString::getFragments() const { + return fragments_; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList AttributedString::getDebugChildren() const { + SharedDebugStringConvertibleList list = {}; + + for (auto &&fragment : fragments_) { + auto propsList = fragment.textAttributes.DebugStringConvertible::getDebugProps(); + + if (fragment.shadowNode) { + propsList.push_back(std::make_shared("shadowNode", fragment.shadowNode->getDebugDescription())); + } + + list.push_back( + std::make_shared( + "Fragment", + fragment.string, + SharedDebugStringConvertibleList(), + propsList + ) + ); + } + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/AttributedString.h b/ReactCommon/fabric/attributedstring/AttributedString.h new file mode 100644 index 000000000..07cc47603 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/AttributedString.h @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class AttributedString; + +using SharedAttributedString = std::shared_ptr; + +/* + * Simple, cross-platfrom, React-specific implementation of attributed string + * (aka spanned string). + * `AttributedString` is basically a list of `Fragments` which have `string` and + * `textAttributes` + `shadowNode` associated with the `string`. + */ +class AttributedString: + public Sealable, + public DebugStringConvertible { + +public: + + class Fragment { + public: + std::string string; + TextAttributes textAttributes; + SharedShadowNode shadowNode; + }; + + using Fragments = std::vector; + + /* + * Appends and prepends a `fragment` to the string. + */ + void appendFragment(const Fragment &fragment); + void prependFragment(const Fragment &fragment); + + /* + * Appends and prepends an `attributedString` (all its fragments) to + * the string. + */ + void appendAttributedString(const AttributedString &attributedString); + void prependAttributedString(const AttributedString &attributedString); + + /* + * Returns read-only reference to a list of fragments. + */ + const Fragments &getFragments() const; + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugChildren() const override; + +private: + + Fragments fragments_; +}; + +} // namespace react +} // namespace facebook + diff --git a/ReactCommon/fabric/attributedstring/TextAttributes.cpp b/ReactCommon/fabric/attributedstring/TextAttributes.cpp new file mode 100644 index 000000000..984aba5d3 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/TextAttributes.cpp @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TextAttributes.h" + +#include +#include + +namespace facebook { +namespace react { + +void TextAttributes::apply(TextAttributes textAttributes) { + // Color + foregroundColor = textAttributes.foregroundColor ? textAttributes.foregroundColor : foregroundColor; + backgroundColor = textAttributes.backgroundColor ? textAttributes.backgroundColor : backgroundColor; + opacity = !isnan(textAttributes.opacity) ? textAttributes.opacity : opacity; + + // Font + fontFamily = !textAttributes.fontFamily.empty() ? textAttributes.fontFamily : fontFamily; + fontSize = !isnan(textAttributes.fontSize) ? textAttributes.fontSize : fontSize; + fontSizeMultiplier = !isnan(textAttributes.fontSizeMultiplier) ? textAttributes.fontSizeMultiplier : fontSizeMultiplier; + fontWeight = textAttributes.fontWeight.has_value() ? textAttributes.fontWeight : fontWeight; + fontStyle = textAttributes.fontStyle.has_value() ? textAttributes.fontStyle : fontStyle; + fontVariant = textAttributes.fontVariant.has_value() ? textAttributes.fontVariant : fontVariant; + allowFontScaling = textAttributes.allowFontScaling.has_value() ? textAttributes.allowFontScaling : allowFontScaling; + letterSpacing = !isnan(textAttributes.letterSpacing) ? textAttributes.letterSpacing : letterSpacing; + + // Paragraph Styles + lineHeight = !isnan(textAttributes.lineHeight) ? textAttributes.lineHeight : lineHeight; + alignment = textAttributes.alignment.has_value() ? textAttributes.alignment : alignment; + baseWritingDirection = textAttributes.baseWritingDirection.has_value() ? textAttributes.baseWritingDirection : baseWritingDirection; + + // Decoration + textDecorationColor = textAttributes.textDecorationColor ? textAttributes.textDecorationColor : textDecorationColor; + textDecorationLineType = textAttributes.textDecorationLineType.has_value() ? textAttributes.textDecorationLineType : textDecorationLineType; + textDecorationLineStyle = textAttributes.textDecorationLineStyle.has_value() ? textAttributes.textDecorationLineStyle : textDecorationLineStyle; + textDecorationLinePattern = textAttributes.textDecorationLinePattern.has_value() ? textAttributes.textDecorationLinePattern : textDecorationLinePattern; + + // Shadow + textShadowOffset = textAttributes.textShadowOffset.has_value() ? textAttributes.textShadowOffset.value() : textShadowOffset; + textShadowRadius = !isnan(textAttributes.textShadowRadius) ? textAttributes.textShadowRadius : textShadowRadius; + textShadowColor = textAttributes.textShadowColor ? textAttributes.textShadowColor : textShadowColor; + + // Special + isHighlighted = textAttributes.isHighlighted.has_value() ? textAttributes.isHighlighted : isHighlighted; + layoutDirection = textAttributes.layoutDirection.has_value() ? textAttributes.layoutDirection : layoutDirection; +} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList TextAttributes::getDebugProps() const { + TextAttributes defaultAttributes = {}; + + SharedDebugStringConvertibleList list = {}; + +#define PROPS_ADD_TO_SET(propertyName, accessor, convertor) \ + if (propertyName != defaultAttributes.propertyName) { \ + list.push_back(std::make_shared(#propertyName, convertor(propertyName accessor))); \ + } + + PROPS_ADD_TO_SET(backgroundColor, , colorNameFromColor) + PROPS_ADD_TO_SET(foregroundColor, , colorNameFromColor) + PROPS_ADD_TO_SET(opacity, , std::to_string) + + PROPS_ADD_TO_SET(fontFamily, , ) + PROPS_ADD_TO_SET(fontSize, , std::to_string) + PROPS_ADD_TO_SET(fontSizeMultiplier, , std::to_string) + + // TODO: Implement all fields. + + return list; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/TextAttributes.h b/ReactCommon/fabric/attributedstring/TextAttributes.h new file mode 100644 index 000000000..30159eb5c --- /dev/null +++ b/ReactCommon/fabric/attributedstring/TextAttributes.h @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * 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 + +#include +#include +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class TextAttributes; + +using SharedTextAttributes = std::shared_ptr; + +class TextAttributes: + public DebugStringConvertible { +public: + +#pragma mark - Fields + + // Color + SharedColor foregroundColor {nullptr}; + SharedColor backgroundColor {nullptr}; + Float opacity {std::numeric_limits::quiet_NaN()}; + + // Font + std::string fontFamily {""}; + Float fontSize {std::numeric_limits::quiet_NaN()}; + Float fontSizeMultiplier {std::numeric_limits::quiet_NaN()}; + folly::Optional fontWeight {}; + folly::Optional fontStyle {}; + folly::Optional fontVariant {}; + folly::Optional allowFontScaling {}; + Float letterSpacing {std::numeric_limits::quiet_NaN()}; + + // Paragraph Styles + Float lineHeight {std::numeric_limits::quiet_NaN()}; + folly::Optional alignment {}; + folly::Optional baseWritingDirection {}; + + // Decoration + SharedColor textDecorationColor {nullptr}; + folly::Optional textDecorationLineType {}; + folly::Optional textDecorationLineStyle {}; + folly::Optional textDecorationLinePattern {}; + + // Shadow + folly::Optional textShadowOffset {}; + Float textShadowRadius {std::numeric_limits::quiet_NaN()}; + SharedColor textShadowColor {nullptr}; + + // Special + folly::Optional isHighlighted {}; + folly::Optional layoutDirection {}; + +#pragma mark - Operations + + void apply(TextAttributes textAttributes); + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; +}; + +} // namespace react +} // namespace facebook +