Skip to content

Commit

Permalink
Fabric/Text: <Paragraph> is now supporting text attributes
Browse files Browse the repository at this point in the history
Summary:
I was shamed by Sebastian's sebmarkbage concerns (totally unrelated to this topic) about introducing another level of indirection into the system and decided to change my original plan not to support text attributes for the <Paragraph> component.

So, now <Paragraph> shares <View>, <Text> and <Paragraph> itself capabilities. That reduces the minimum amount of required components for trivial text fragment from three (Paragraph, Text, RawText) to two (Paragraph and RawText).

Special thanks for C++ for supporting multiple inheritance.

Reviewed By: mdvacca

Differential Revision: D7785889

fbshipit-source-id: dd9f2e2650bfbfd76d7d4b538adaf409f9429df3
  • Loading branch information
shergin authored and facebook-github-bot committed May 9, 2018
1 parent 9ea7957 commit d9ff176
Show file tree
Hide file tree
Showing 19 changed files with 268 additions and 147 deletions.
5 changes: 3 additions & 2 deletions ReactCommon/fabric/attributedstring/BUCK
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE")
load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE")

APPLE_COMPILER_FLAGS = []

Expand Down Expand Up @@ -37,6 +37,7 @@ rn_xplat_cxx_library(
],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
Expand Down
5 changes: 3 additions & 2 deletions ReactCommon/fabric/core/BUCK
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE")
load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE")

APPLE_COMPILER_FLAGS = []

Expand Down Expand Up @@ -40,6 +40,7 @@ rn_xplat_cxx_library(
],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
Expand Down
10 changes: 7 additions & 3 deletions ReactCommon/fabric/debug/BUCK
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE")
load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE")

APPLE_COMPILER_FLAGS = []

if not IS_OSS_BUILD:
load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags")
APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), "compiler_flags")
APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags')

rn_xplat_cxx_library(
name = "debug",
Expand Down Expand Up @@ -37,14 +37,18 @@ rn_xplat_cxx_library(
],
force_static = True,
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
tests = [],
visibility = ["PUBLIC"],
deps = [
"xplat//fbsystrace:fbsystrace",
"xplat//folly:headers_only",
"xplat//folly:memory",
"xplat//folly:molly",
],
)

Expand Down
14 changes: 10 additions & 4 deletions ReactCommon/fabric/graphics/BUCK
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "get_apple_inspector_flags", "APPLE")
load("//configurations/buck/apple:flag_defs.bzl", "get_application_ios_flags", "get_debug_preprocessor_flags", "OBJC_ARC_PREPROCESSOR_FLAGS")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "rn_xplat_cxx_library", "get_apple_inspector_flags", "react_native_xplat_target", "ANDROID", "APPLE")

APPLE_COMPILER_FLAGS = []

Expand All @@ -25,18 +25,24 @@ rn_xplat_cxx_library(
prefix = "fabric/graphics",
),
compiler_flags = [
"-std=c++14",
"-Wall",
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
fbobjc_tests = [
":tests",
],
force_static = True,
frameworks = [
"$SDKROOT/System/Library/Frameworks/CoreGraphics.framework",
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
],
macosx_tests_override = [],
platforms = (ANDROID, APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
Expand Down
1 change: 1 addition & 0 deletions ReactCommon/fabric/text/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ rn_xplat_cxx_library(
exported_headers = subdir_glob(
[
("", "*.h"),
("basetext", "*.h"),
("paragraph", "*.h"),
("text", "*.h"),
("rawtext", "*.h"),
Expand Down
73 changes: 73 additions & 0 deletions ReactCommon/fabric/text/basetext/BaseTextProps.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* 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 "BaseTextProps.h"

#include <fabric/attributedstring/textValuesConversions.h>
#include <fabric/core/propsConversions.h>
#include <fabric/debug/DebugStringConvertibleItem.h>
#include <fabric/graphics/graphicValuesConversions.h>
#include <fabric/text/propsConversions.h>

namespace facebook {
namespace react {

void BaseTextProps::apply(const RawProps &rawProps) {
// Color
applyRawProp(rawProps, "color", textAttributes_.foregroundColor);
applyRawProp(rawProps, "backgroundColor", textAttributes_.backgroundColor);
applyRawProp(rawProps, "opacity", textAttributes_.opacity);

// Font
applyRawProp(rawProps, "fontFamily", textAttributes_.fontFamily);
applyRawProp(rawProps, "fontSize", textAttributes_.fontSize);
applyRawProp(rawProps, "fontSizeMultiplier", textAttributes_.fontSizeMultiplier);
applyRawProp(rawProps, "fontWeight", textAttributes_.fontWeight);
applyRawProp(rawProps, "fontStyle", textAttributes_.fontStyle);
applyRawProp(rawProps, "fontVariant", textAttributes_.fontVariant);
applyRawProp(rawProps, "allowFontScaling", textAttributes_.allowFontScaling);
applyRawProp(rawProps, "letterSpacing", textAttributes_.letterSpacing);

// Paragraph
applyRawProp(rawProps, "lineHeight", textAttributes_.lineHeight);
applyRawProp(rawProps, "alignment", textAttributes_.alignment);
applyRawProp(rawProps, "baseWritingDirection", textAttributes_.baseWritingDirection);

// Decoration
applyRawProp(rawProps, "textDecorationColor", textAttributes_.textDecorationColor);
applyRawProp(rawProps, "textDecorationLineType", textAttributes_.textDecorationLineType);
applyRawProp(rawProps, "textDecorationLineStyle", textAttributes_.textDecorationLineStyle);
applyRawProp(rawProps, "textDecorationLinePattern", textAttributes_.textDecorationLinePattern);

// Shadow
applyRawProp(rawProps, "textShadowOffset", textAttributes_.textShadowOffset);
applyRawProp(rawProps, "textShadowRadius", textAttributes_.textShadowRadius);
applyRawProp(rawProps, "textShadowColor", textAttributes_.textShadowColor);

// Special
applyRawProp(rawProps, "isHighlighted", textAttributes_.isHighlighted);
}

#pragma mark - Getters

TextAttributes BaseTextProps::getTextAttributes() const {
return textAttributes_;
}

#pragma mark - DebugStringConvertible

SharedDebugStringConvertibleList BaseTextProps::getDebugProps() const {
SharedDebugStringConvertibleList list = {};

auto textAttributesPropsList = textAttributes_.getDebugProps();
std::move(textAttributesPropsList.begin(), textAttributesPropsList.end(), std::back_inserter(list));

return list;
}

} // namespace react
} // namespace facebook
48 changes: 48 additions & 0 deletions ReactCommon/fabric/text/basetext/BaseTextProps.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* 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 <fabric/attributedstring/TextAttributes.h>
#include <fabric/core/Props.h>
#include <fabric/graphics/Color.h>
#include <fabric/graphics/Geometry.h>

namespace facebook {
namespace react {

/*
* `Props`-like class which is used as a base class for all Props classes
* that can have text attributes (such as Text and Paragraph).
*/
class BaseTextProps {
public:

/*
* Same semantic as `Props::apply(...)`.
*/
void apply(const RawProps &rawProps);

#pragma mark - Getters

/*
* Returns all props values as `TextAttributes` object.
*/
TextAttributes getTextAttributes() const;

#pragma mark - DebugStringConvertible (partially)

SharedDebugStringConvertibleList getDebugProps() const;

private:

TextAttributes textAttributes_;
};

} // namespace react
} // namespace facebook

59 changes: 59 additions & 0 deletions ReactCommon/fabric/text/basetext/BaseTextShadowNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* 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 "BaseTextShadowNode.h"

#include <fabric/debug/DebugStringConvertibleItem.h>

#include "RawTextShadowNode.h"
#include "RawTextProps.h"
#include "TextShadowNode.h"
#include "TextProps.h"

namespace facebook {
namespace react {

AttributedString BaseTextShadowNode::getAttributedString(
const TextAttributes &textAttributes,
const SharedShadowNodeSharedList &childNodes
) const {
// TODO: Implement caching.

AttributedString attributedString;

for (auto &&childNode : *childNodes) {
// RawShadowNode
SharedRawTextShadowNode rawTextShadowNode = std::dynamic_pointer_cast<const RawTextShadowNode>(childNode);
if (rawTextShadowNode) {
AttributedString::Fragment fragment;
fragment.string = rawTextShadowNode->getProps()->getText();
fragment.textAttributes = textAttributes;
attributedString.appendFragment(fragment);
continue;
}

// TextShadowNode
SharedTextShadowNode textShadowNode = std::dynamic_pointer_cast<const TextShadowNode>(childNode);
if (textShadowNode) {
TextAttributes localTextAttributes = textAttributes;
localTextAttributes.apply(textShadowNode->getProps()->getTextAttributes());
attributedString.appendAttributedString(textShadowNode->getAttributedString(localTextAttributes, textShadowNode->getChildren()));
continue;
}

// Any other kind of ShadowNode
AttributedString::Fragment fragment;
fragment.shadowNode = childNode;
fragment.textAttributes = textAttributes;
attributedString.appendFragment(fragment);
}

return attributedString;
}

} // namespace react
} // namespace facebook
33 changes: 33 additions & 0 deletions ReactCommon/fabric/text/basetext/BaseTextShadowNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* 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 <fabric/attributedstring/AttributedString.h>
#include <fabric/attributedstring/TextAttributes.h>

namespace facebook {
namespace react {

/*
* Base class (one of) for shadow nodes that represents attributed text,
* such as Text and Paragraph (but not RawText).
*/
class BaseTextShadowNode {
public:

/*
* Returns a `AttributedString` which represents text content of the node.
*/
AttributedString getAttributedString(
const TextAttributes &baseTextAttributes,
const SharedShadowNodeSharedList &childNodes
) const;
};

} // namespace react
} // namespace facebook
11 changes: 8 additions & 3 deletions ReactCommon/fabric/text/paragraph/ParagraphProps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace react {

void ParagraphProps::apply(const RawProps &rawProps) {
ViewProps::apply(rawProps);
BaseTextProps::apply(rawProps);

// Paragraph Attributes
applyRawProp(rawProps, "numberOfLines", paragraphAttributes_.maximumNumberOfLines);
Expand Down Expand Up @@ -44,13 +45,17 @@ bool ParagraphProps::getIsSelectable() const {
SharedDebugStringConvertibleList ParagraphProps::getDebugProps() const {
SharedDebugStringConvertibleList list = {};

// View Props
auto &&viewPropsList = ViewProps::getDebugProps();
std::move(viewPropsList.begin(), viewPropsList.end(), std::back_inserter(list));

// Paragraph Props
auto &&paragraphAttributePropsList = paragraphAttributes_.getDebugProps();
std::move(paragraphAttributePropsList.begin(), paragraphAttributePropsList.end(), std::back_inserter(list));

// View Props
auto &&viewPropsList = ViewProps::getDebugProps();
std::move(viewPropsList.begin(), viewPropsList.end(), std::back_inserter(list));
// Base Text Props
auto &&baseTextPropsList = BaseTextProps::getDebugProps();
std::move(baseTextPropsList.begin(), baseTextPropsList.end(), std::back_inserter(list));

return list;
}
Expand Down
4 changes: 3 additions & 1 deletion ReactCommon/fabric/text/paragraph/ParagraphProps.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <fabric/attributedstring/ParagraphAttributes.h>
#include <fabric/core/Props.h>
#include <fabric/text/BaseTextProps.h>
#include <fabric/view/ViewProps.h>

namespace facebook {
Expand All @@ -27,7 +28,8 @@ using SharedParagraphProps = std::shared_ptr<const ParagraphProps>;
* object.
*/
class ParagraphProps:
public ViewProps {
public ViewProps,
public BaseTextProps {

public:

Expand Down
10 changes: 1 addition & 9 deletions ReactCommon/fabric/text/paragraph/ParagraphShadowNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,9 @@ namespace react {
ComponentName ParagraphShadowNode::getComponentName() const {
return ComponentName("Paragraph");
}

SharedTextShadowNode ParagraphShadowNode::getTextChildNode() const {
// <Paragraph> component must always have a single <Text> child component.
assert(getChildren()->size() == 1);
auto childNode = getChildren()->front();
assert(std::dynamic_pointer_cast<const TextShadowNode>(childNode));
return std::static_pointer_cast<const TextShadowNode>(childNode);
}

AttributedString ParagraphShadowNode::getAttributedString() const {
return getTextChildNode()->getAttributedString(TextAttributes());
return BaseTextShadowNode::getAttributedString(getProps()->getTextAttributes(), getChildren());
}

void ParagraphShadowNode::setTextLayoutManager(SharedTextLayoutManager textLayoutManager) {
Expand Down
Loading

0 comments on commit d9ff176

Please sign in to comment.