yeet
This commit is contained in:
157
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/BUCK
generated
vendored
Normal file
157
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/BUCK
generated
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_preprocessor_flags_for_build_mode")
|
||||
load(
|
||||
"//tools/build_defs/oss:rn_defs.bzl",
|
||||
"ANDROID",
|
||||
"APPLE",
|
||||
"CXX",
|
||||
"YOGA_CXX_TARGET",
|
||||
"fb_xplat_cxx_test",
|
||||
"get_apple_compiler_flags",
|
||||
"get_apple_inspector_flags",
|
||||
"react_native_target",
|
||||
"react_native_xplat_target",
|
||||
"rn_xplat_cxx_library",
|
||||
"subdir_glob",
|
||||
)
|
||||
|
||||
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
|
||||
|
||||
rn_xplat_cxx_library(
|
||||
name = "textlayoutmanager",
|
||||
srcs = glob(
|
||||
[
|
||||
"*.cpp",
|
||||
],
|
||||
),
|
||||
headers = subdir_glob(
|
||||
[
|
||||
("", "*.h"),
|
||||
],
|
||||
prefix = "",
|
||||
),
|
||||
header_namespace = "",
|
||||
exported_headers = subdir_glob(
|
||||
[
|
||||
("", "*.h"),
|
||||
],
|
||||
prefix = "react/textlayoutmanager",
|
||||
),
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
cxx_exported_headers = subdir_glob(
|
||||
[
|
||||
("platform/cxx", "*.h"),
|
||||
],
|
||||
prefix = "react/textlayoutmanager",
|
||||
),
|
||||
cxx_headers = subdir_glob(
|
||||
[
|
||||
("platform/cxx", "**/*.h"),
|
||||
],
|
||||
prefix = "",
|
||||
),
|
||||
cxx_srcs = glob(
|
||||
[
|
||||
"platform/cxx/**/*.cpp",
|
||||
],
|
||||
),
|
||||
cxx_tests = [":tests"],
|
||||
fbandroid_deps = [
|
||||
react_native_target("jni/react/jni:jni"),
|
||||
],
|
||||
fbandroid_exported_headers = subdir_glob(
|
||||
[
|
||||
("platform/android", "*.h"),
|
||||
],
|
||||
prefix = "react/textlayoutmanager",
|
||||
),
|
||||
fbandroid_headers = subdir_glob(
|
||||
[
|
||||
("platform/android", "**/*.h"),
|
||||
],
|
||||
prefix = "",
|
||||
),
|
||||
fbandroid_srcs = glob(
|
||||
[
|
||||
"platform/android/**/*.cpp",
|
||||
],
|
||||
),
|
||||
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
|
||||
fbobjc_labels = ["supermodule:ios/default/public.react_native.infra"],
|
||||
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
|
||||
force_static = True,
|
||||
ios_deps = [
|
||||
],
|
||||
ios_exported_headers = subdir_glob(
|
||||
[
|
||||
("platform/ios", "*.h"),
|
||||
],
|
||||
prefix = "react/textlayoutmanager",
|
||||
),
|
||||
ios_frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/CoreGraphics.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
],
|
||||
ios_headers = subdir_glob(
|
||||
[
|
||||
("platform/ios", "**/*.h"),
|
||||
],
|
||||
prefix = "",
|
||||
),
|
||||
ios_srcs = glob(
|
||||
[
|
||||
"platform/ios/**/*.cpp",
|
||||
"platform/ios/**/*.mm",
|
||||
],
|
||||
),
|
||||
macosx_tests_override = [],
|
||||
platforms = (ANDROID, APPLE, CXX),
|
||||
preprocessor_flags = [
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"//xplat/fbsystrace:fbsystrace",
|
||||
"//xplat/folly:headers_only",
|
||||
"//xplat/folly:memory",
|
||||
"//xplat/folly:molly",
|
||||
"//xplat/third-party/glog:glog",
|
||||
YOGA_CXX_TARGET,
|
||||
react_native_xplat_target("fabric/attributedstring:attributedstring"),
|
||||
react_native_xplat_target("fabric/core:core"),
|
||||
react_native_xplat_target("utils:utils"),
|
||||
react_native_xplat_target("fabric/debug:debug"),
|
||||
react_native_xplat_target("fabric/graphics:graphics"),
|
||||
react_native_xplat_target("fabric/uimanager:uimanager"),
|
||||
],
|
||||
)
|
||||
|
||||
fb_xplat_cxx_test(
|
||||
name = "tests",
|
||||
srcs = glob(["tests/**/*.cpp"]),
|
||||
headers = glob(["tests/**/*.h"]),
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
contacts = ["oncall+react_native@xmail.facebook.com"],
|
||||
platforms = (
|
||||
# `Apple` and `Android` flavors are disabled because the module (built with those flavors) requires Emulator/Simulator (which is expensive and slow). At the same time, we don't really have tests here.
|
||||
# ANDROID,
|
||||
# APPLE,
|
||||
CXX,
|
||||
),
|
||||
deps = [
|
||||
":textlayoutmanager",
|
||||
"//xplat/folly:molly",
|
||||
"//xplat/third-party/gmock:gtest",
|
||||
],
|
||||
)
|
12
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/TextMeasureCache.cpp
generated
vendored
Normal file
12
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/TextMeasureCache.cpp
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "TextMeasureCache.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {} // namespace react
|
||||
} // namespace facebook
|
195
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/TextMeasureCache.h
generated
vendored
Normal file
195
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/TextMeasureCache.h
generated
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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 <react/attributedstring/AttributedString.h>
|
||||
#include <react/attributedstring/ParagraphAttributes.h>
|
||||
#include <react/core/LayoutConstraints.h>
|
||||
#include <react/utils/FloatComparison.h>
|
||||
#include <react/utils/SimpleThreadSafeCache.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Describes a result of text measuring.
|
||||
*/
|
||||
class TextMeasurement final {
|
||||
public:
|
||||
class Attachment final {
|
||||
public:
|
||||
Rect frame;
|
||||
bool isClipped;
|
||||
};
|
||||
|
||||
using Attachments = std::vector<Attachment>;
|
||||
|
||||
Size size;
|
||||
Attachments attachments;
|
||||
};
|
||||
|
||||
// The Key type that is used for Text Measure Cache.
|
||||
// The equivalence and hashing operations of this are defined to respect the
|
||||
// nature of text measuring.
|
||||
class TextMeasureCacheKey final {
|
||||
public:
|
||||
AttributedString attributedString{};
|
||||
ParagraphAttributes paragraphAttributes{};
|
||||
LayoutConstraints layoutConstraints{};
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum size of the Cache.
|
||||
* The number was empirically chosen based on approximation of an average amount
|
||||
* of meaningful measures per surface.
|
||||
*/
|
||||
constexpr auto kSimpleThreadSafeCacheSizeCap = size_t{256};
|
||||
|
||||
/*
|
||||
* Thread-safe, evicting hash table designed to store text measurement
|
||||
* information.
|
||||
*/
|
||||
using TextMeasureCache = SimpleThreadSafeCache<
|
||||
TextMeasureCacheKey,
|
||||
TextMeasurement,
|
||||
kSimpleThreadSafeCacheSizeCap>;
|
||||
|
||||
inline bool areTextAttributesEquivalentLayoutWise(
|
||||
TextAttributes const &lhs,
|
||||
TextAttributes const &rhs) {
|
||||
// Here we check all attributes that affect layout metrics and don't check any
|
||||
// attributes that affect only a decorative aspect of displayed text (like
|
||||
// colors).
|
||||
return std::tie(
|
||||
lhs.fontFamily,
|
||||
lhs.fontWeight,
|
||||
lhs.fontStyle,
|
||||
lhs.fontVariant,
|
||||
lhs.allowFontScaling,
|
||||
lhs.alignment) ==
|
||||
std::tie(
|
||||
rhs.fontFamily,
|
||||
rhs.fontWeight,
|
||||
rhs.fontStyle,
|
||||
rhs.fontVariant,
|
||||
rhs.allowFontScaling,
|
||||
rhs.alignment) &&
|
||||
floatEquality(lhs.fontSize, rhs.fontSize) &&
|
||||
floatEquality(lhs.fontSizeMultiplier, rhs.fontSizeMultiplier) &&
|
||||
floatEquality(lhs.letterSpacing, rhs.letterSpacing) &&
|
||||
floatEquality(lhs.lineHeight, rhs.lineHeight);
|
||||
}
|
||||
|
||||
inline size_t textAttributesHashLayoutWise(
|
||||
TextAttributes const &textAttributes) {
|
||||
// Taking into account the same props as
|
||||
// `areTextAttributesEquivalentLayoutWise` mentions.
|
||||
return folly::hash::hash_combine(
|
||||
0,
|
||||
textAttributes.fontFamily,
|
||||
textAttributes.fontSize,
|
||||
textAttributes.fontSizeMultiplier,
|
||||
textAttributes.fontWeight,
|
||||
textAttributes.fontStyle,
|
||||
textAttributes.fontVariant,
|
||||
textAttributes.allowFontScaling,
|
||||
textAttributes.letterSpacing,
|
||||
textAttributes.lineHeight,
|
||||
textAttributes.alignment);
|
||||
}
|
||||
|
||||
inline bool areAttributedStringFragmentsEquivalentLayoutWise(
|
||||
AttributedString::Fragment const &lhs,
|
||||
AttributedString::Fragment const &rhs) {
|
||||
return lhs.string == rhs.string &&
|
||||
areTextAttributesEquivalentLayoutWise(
|
||||
lhs.textAttributes, rhs.textAttributes) &&
|
||||
// LayoutMetrics of an attachment fragment affects the size of a measured
|
||||
// attributed string.
|
||||
(!lhs.isAttachment() ||
|
||||
(lhs.parentShadowView.layoutMetrics ==
|
||||
rhs.parentShadowView.layoutMetrics));
|
||||
}
|
||||
|
||||
inline size_t textAttributesHashLayoutWise(
|
||||
AttributedString::Fragment const &fragment) {
|
||||
// Here we are not taking `isAttachment` and `layoutMetrics` into account
|
||||
// because they are logically interdependent and this can break an invariant
|
||||
// between hash and equivalence functions (and cause cache misses).
|
||||
return folly::hash::hash_combine(
|
||||
0,
|
||||
fragment.string,
|
||||
textAttributesHashLayoutWise(fragment.textAttributes));
|
||||
}
|
||||
|
||||
inline bool areAttributedStringsEquivalentLayoutWise(
|
||||
AttributedString const &lhs,
|
||||
AttributedString const &rhs) {
|
||||
auto &lhsFragment = lhs.getFragments();
|
||||
auto &rhsFragment = rhs.getFragments();
|
||||
|
||||
if (lhsFragment.size() != rhsFragment.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto size = lhsFragment.size();
|
||||
for (auto i = size_t{0}; i < size; i++) {
|
||||
if (!areAttributedStringFragmentsEquivalentLayoutWise(
|
||||
lhsFragment.at(i), rhsFragment.at(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline size_t textAttributedStringHashLayoutWise(
|
||||
AttributedString const &attributedString) {
|
||||
auto seed = size_t{0};
|
||||
|
||||
for (auto const &fragment : attributedString.getFragments()) {
|
||||
seed =
|
||||
folly::hash::hash_combine(seed, textAttributesHashLayoutWise(fragment));
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
inline bool operator==(
|
||||
TextMeasureCacheKey const &lhs,
|
||||
TextMeasureCacheKey const &rhs) {
|
||||
return areAttributedStringsEquivalentLayoutWise(
|
||||
lhs.attributedString, rhs.attributedString) &&
|
||||
lhs.paragraphAttributes == rhs.paragraphAttributes &&
|
||||
lhs.layoutConstraints.maximumSize.width ==
|
||||
rhs.layoutConstraints.maximumSize.width;
|
||||
}
|
||||
|
||||
inline bool operator!=(
|
||||
TextMeasureCacheKey const &lhs,
|
||||
TextMeasureCacheKey const &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<facebook::react::TextMeasureCacheKey> {
|
||||
size_t operator()(facebook::react::TextMeasureCacheKey const &key) const {
|
||||
return folly::hash::hash_combine(
|
||||
0,
|
||||
textAttributedStringHashLayoutWise(key.attributedString),
|
||||
key.paragraphAttributes,
|
||||
key.layoutConstraints.maximumSize.width);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
123
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp
generated
vendored
Normal file
123
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "TextLayoutManager.h"
|
||||
|
||||
#include <react/attributedstring/conversions.h>
|
||||
#include <react/core/conversions.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
TextLayoutManager::~TextLayoutManager() {}
|
||||
|
||||
void *TextLayoutManager::getNativeTextLayoutManager() const {
|
||||
return self_;
|
||||
}
|
||||
|
||||
TextMeasurement TextLayoutManager::measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
auto &attributedString = attributedStringBox.getValue();
|
||||
|
||||
return measureCache_.get(
|
||||
{attributedString, paragraphAttributes, layoutConstraints},
|
||||
[&](TextMeasureCacheKey const &key) {
|
||||
return doMeasure(
|
||||
attributedString, paragraphAttributes, layoutConstraints);
|
||||
});
|
||||
}
|
||||
|
||||
TextMeasurement TextLayoutManager::doMeasure(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
const jni::global_ref<jobject> &fabricUIManager =
|
||||
contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
|
||||
|
||||
int attachmentsCount = 0;
|
||||
for (auto fragment : attributedString.getFragments()) {
|
||||
if (fragment.isAttachment()) {
|
||||
attachmentsCount++;
|
||||
}
|
||||
}
|
||||
auto env = Environment::current();
|
||||
auto attachmentPositions = env->NewIntArray(attachmentsCount * 2);
|
||||
|
||||
static auto measure =
|
||||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
|
||||
->getMethod<jlong(
|
||||
jint,
|
||||
jstring,
|
||||
ReadableMap::javaobject,
|
||||
ReadableMap::javaobject,
|
||||
ReadableMap::javaobject,
|
||||
jfloat,
|
||||
jfloat,
|
||||
jfloat,
|
||||
jfloat,
|
||||
jintArray)>("measure");
|
||||
|
||||
auto minimumSize = layoutConstraints.minimumSize;
|
||||
auto maximumSize = layoutConstraints.maximumSize;
|
||||
|
||||
auto serializedAttributedString = toDynamic(attributedString);
|
||||
local_ref<JString> componentName = make_jstring("RCTText");
|
||||
local_ref<ReadableNativeMap::javaobject> attributedStringRNM =
|
||||
ReadableNativeMap::newObjectCxxArgs(serializedAttributedString);
|
||||
local_ref<ReadableNativeMap::javaobject> paragraphAttributesRNM =
|
||||
ReadableNativeMap::newObjectCxxArgs(toDynamic(paragraphAttributes));
|
||||
|
||||
local_ref<ReadableMap::javaobject> attributedStringRM = make_local(
|
||||
reinterpret_cast<ReadableMap::javaobject>(attributedStringRNM.get()));
|
||||
local_ref<ReadableMap::javaobject> paragraphAttributesRM = make_local(
|
||||
reinterpret_cast<ReadableMap::javaobject>(paragraphAttributesRNM.get()));
|
||||
auto size = yogaMeassureToSize(measure(
|
||||
fabricUIManager,
|
||||
-1,
|
||||
componentName.get(),
|
||||
attributedStringRM.get(),
|
||||
paragraphAttributesRM.get(),
|
||||
nullptr,
|
||||
minimumSize.width,
|
||||
maximumSize.width,
|
||||
minimumSize.height,
|
||||
maximumSize.height,
|
||||
attachmentPositions));
|
||||
|
||||
jint *attachmentData = env->GetIntArrayElements(attachmentPositions, 0);
|
||||
|
||||
auto attachments = TextMeasurement::Attachments{};
|
||||
if (attachmentsCount > 0) {
|
||||
folly::dynamic fragments = serializedAttributedString["fragments"];
|
||||
int attachmentIndex = 0;
|
||||
for (int i = 0; i < fragments.size(); i++) {
|
||||
folly::dynamic fragment = fragments[i];
|
||||
if (fragment["isAttachment"] == true) {
|
||||
float top = attachmentData[attachmentIndex * 2];
|
||||
float left = attachmentData[attachmentIndex * 2 + 1];
|
||||
float width = fragment["width"].getInt();
|
||||
float height = fragment["height"].getInt();
|
||||
|
||||
auto rect = facebook::react::Rect{{left, top},
|
||||
facebook::react::Size{width, height}};
|
||||
attachments.push_back(TextMeasurement::Attachment{rect, false});
|
||||
attachmentIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// DELETE REF
|
||||
env->DeleteLocalRef(attachmentPositions);
|
||||
return TextMeasurement{size, attachments};
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
58
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.h
generated
vendored
Normal file
58
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.h
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 <react/attributedstring/AttributedString.h>
|
||||
#include <react/attributedstring/AttributedStringBox.h>
|
||||
#include <react/core/LayoutConstraints.h>
|
||||
#include <react/textlayoutmanager/TextMeasureCache.h>
|
||||
#include <react/utils/ContextContainer.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class TextLayoutManager;
|
||||
|
||||
using SharedTextLayoutManager = std::shared_ptr<const TextLayoutManager>;
|
||||
|
||||
/*
|
||||
* Cross platform facade for Android-specific TextLayoutManager.
|
||||
*/
|
||||
class TextLayoutManager {
|
||||
public:
|
||||
TextLayoutManager(const ContextContainer::Shared &contextContainer)
|
||||
: contextContainer_(contextContainer){};
|
||||
~TextLayoutManager();
|
||||
|
||||
/*
|
||||
* Measures `attributedString` using native text rendering infrastructure.
|
||||
*/
|
||||
TextMeasurement measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
/*
|
||||
* Returns an opaque pointer to platform-specific TextLayoutManager.
|
||||
* Is used on a native views layer to delegate text rendering to the manager.
|
||||
*/
|
||||
void *getNativeTextLayoutManager() const;
|
||||
|
||||
private:
|
||||
TextMeasurement doMeasure(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
void *self_;
|
||||
ContextContainer::Shared contextContainer_;
|
||||
TextMeasureCache measureCache_{};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
27
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp
generated
vendored
Normal file
27
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "TextLayoutManager.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
TextLayoutManager::~TextLayoutManager() {}
|
||||
|
||||
void *TextLayoutManager::getNativeTextLayoutManager() const {
|
||||
return self_;
|
||||
}
|
||||
|
||||
Size TextLayoutManager::measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
return Size{0, 0};
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
55
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h
generated
vendored
Normal file
55
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 <memory>
|
||||
|
||||
#include <react/attributedstring/AttributedString.h>
|
||||
#include <react/attributedstring/AttributedStringBox.h>
|
||||
#include <react/attributedstring/ParagraphAttributes.h>
|
||||
#include <react/core/LayoutConstraints.h>
|
||||
#include <react/utils/ContextContainer.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class TextLayoutManager;
|
||||
|
||||
using SharedTextLayoutManager = std::shared_ptr<const TextLayoutManager>;
|
||||
|
||||
/*
|
||||
* Cross platform facade for Android-specific TextLayoutManager.
|
||||
*/
|
||||
class TextLayoutManager {
|
||||
public:
|
||||
TextLayoutManager(const ContextContainer::Shared &contextContainer)
|
||||
: contextContainer_(contextContainer){};
|
||||
~TextLayoutManager();
|
||||
|
||||
/*
|
||||
* Measures `attributedStringBox` using native text rendering infrastructure.
|
||||
*/
|
||||
Size measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
/*
|
||||
* Returns an opaque pointer to platform-specific TextLayoutManager.
|
||||
* Is used on a native views layer to delegate text rendering to the manager.
|
||||
*/
|
||||
void *getNativeTextLayoutManager() const;
|
||||
|
||||
private:
|
||||
void *self_;
|
||||
|
||||
ContextContainer::Shared contextContainer_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
20
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/NSTextStorage+FontScaling.h
generated
vendored
Normal file
20
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/NSTextStorage+FontScaling.h
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NSTextStorage (FontScaling)
|
||||
|
||||
- (void)scaleFontSizeToFitSize:(CGSize)size
|
||||
minimumFontSize:(CGFloat)minimumFontSize
|
||||
maximumFontSize:(CGFloat)maximumFontSize;
|
||||
|
||||
- (void)scaleFontSizeWithRatio:(CGFloat)ratio
|
||||
minimumFontSize:(CGFloat)minimumFontSize
|
||||
maximumFontSize:(CGFloat)maximumFontSize;
|
||||
|
||||
@end
|
117
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/NSTextStorage+FontScaling.m
generated
vendored
Normal file
117
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/NSTextStorage+FontScaling.m
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "NSTextStorage+FontScaling.h"
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, RCTTextSizeComparisonOptions) {
|
||||
RCTTextSizeComparisonSmaller = 1 << 0,
|
||||
RCTTextSizeComparisonLarger = 1 << 1,
|
||||
RCTTextSizeComparisonWithinRange = 1 << 2,
|
||||
};
|
||||
|
||||
@implementation NSTextStorage (FontScaling)
|
||||
|
||||
- (void)scaleFontSizeToFitSize:(CGSize)size
|
||||
minimumFontSize:(CGFloat)minimumFontSize
|
||||
maximumFontSize:(CGFloat)maximumFontSize
|
||||
{
|
||||
CGFloat bottomRatio = 1.0 / 128.0;
|
||||
CGFloat topRatio = 128.0;
|
||||
CGFloat ratio = 1.0;
|
||||
|
||||
NSAttributedString *originalAttributedString = [self copy];
|
||||
|
||||
CGFloat lastRatioWhichFits = 0.02;
|
||||
|
||||
while (true) {
|
||||
[self scaleFontSizeWithRatio:ratio minimumFontSize:minimumFontSize maximumFontSize:maximumFontSize];
|
||||
|
||||
RCTTextSizeComparisonOptions comparsion = [self compareToSize:size thresholdRatio:0.01];
|
||||
|
||||
if ((comparsion & RCTTextSizeComparisonWithinRange) && (comparsion & RCTTextSizeComparisonSmaller)) {
|
||||
return;
|
||||
} else if (comparsion & RCTTextSizeComparisonSmaller) {
|
||||
bottomRatio = ratio;
|
||||
lastRatioWhichFits = ratio;
|
||||
} else {
|
||||
topRatio = ratio;
|
||||
}
|
||||
|
||||
ratio = (topRatio + bottomRatio) / 2.0;
|
||||
|
||||
CGFloat kRatioThreshold = 0.005;
|
||||
if (ABS(topRatio - bottomRatio) < kRatioThreshold || ABS(topRatio - ratio) < kRatioThreshold ||
|
||||
ABS(bottomRatio - ratio) < kRatioThreshold) {
|
||||
[self replaceCharactersInRange:(NSRange){0, self.length} withAttributedString:originalAttributedString];
|
||||
|
||||
[self scaleFontSizeWithRatio:lastRatioWhichFits minimumFontSize:minimumFontSize maximumFontSize:maximumFontSize];
|
||||
return;
|
||||
}
|
||||
|
||||
[self replaceCharactersInRange:(NSRange){0, self.length} withAttributedString:originalAttributedString];
|
||||
}
|
||||
}
|
||||
|
||||
- (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size thresholdRatio:(CGFloat)thresholdRatio
|
||||
{
|
||||
NSLayoutManager *layoutManager = self.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
|
||||
[layoutManager ensureLayoutForTextContainer:textContainer];
|
||||
|
||||
// Does it fit the text container?
|
||||
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
|
||||
NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:glyphRange.length - 1];
|
||||
|
||||
if (truncatedGlyphRange.location != NSNotFound) {
|
||||
return RCTTextSizeComparisonLarger;
|
||||
}
|
||||
|
||||
CGSize measuredSize = [layoutManager usedRectForTextContainer:textContainer].size;
|
||||
|
||||
// Does it fit the size?
|
||||
BOOL fitsSize = size.width >= measuredSize.width && size.height >= measuredSize.height;
|
||||
|
||||
CGSize thresholdSize = (CGSize){
|
||||
size.width * thresholdRatio,
|
||||
size.height * thresholdRatio,
|
||||
};
|
||||
|
||||
RCTTextSizeComparisonOptions result = 0;
|
||||
|
||||
result |= (fitsSize) ? RCTTextSizeComparisonSmaller : RCTTextSizeComparisonLarger;
|
||||
|
||||
if (ABS(measuredSize.width - size.width) < thresholdSize.width) {
|
||||
result = result | RCTTextSizeComparisonWithinRange;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)scaleFontSizeWithRatio:(CGFloat)ratio
|
||||
minimumFontSize:(CGFloat)minimumFontSize
|
||||
maximumFontSize:(CGFloat)maximumFontSize
|
||||
{
|
||||
[self beginEditing];
|
||||
|
||||
[self enumerateAttribute:NSFontAttributeName
|
||||
inRange:(NSRange){0, self.length}
|
||||
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
||||
usingBlock:^(UIFont *_Nullable font, NSRange range, BOOL *_Nonnull stop) {
|
||||
if (!font) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat fontSize = MAX(MIN(font.pointSize * ratio, maximumFontSize), minimumFontSize);
|
||||
|
||||
[self addAttribute:NSFontAttributeName value:[font fontWithSize:fontSize] range:range];
|
||||
}];
|
||||
|
||||
[self endEditing];
|
||||
}
|
||||
|
||||
@end
|
41
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTAttributedTextUtils.h
generated
vendored
Normal file
41
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTAttributedTextUtils.h
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#include <react/attributedstring/AttributedString.h>
|
||||
#include <react/attributedstring/AttributedStringBox.h>
|
||||
#include <react/attributedstring/TextAttributes.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const RCTAttributedStringIsHighlightedAttributeName = @"IsHighlighted";
|
||||
NSString *const RCTAttributedStringEventEmitterKey = @"EventEmitter";
|
||||
|
||||
/*
|
||||
* Creates `NSTextAttributes` from given `facebook::react::TextAttributes`
|
||||
*/
|
||||
NSDictionary<NSAttributedStringKey, id> *RCTNSTextAttributesFromTextAttributes(
|
||||
facebook::react::TextAttributes const &textAttributes);
|
||||
|
||||
/*
|
||||
* Conversions amond `NSAttributedString`, `AttributedString` and `AttributedStringBox`.
|
||||
*/
|
||||
NSAttributedString *RCTNSAttributedStringFromAttributedString(
|
||||
facebook::react::AttributedString const &attributedString);
|
||||
|
||||
NSAttributedString *RCTNSAttributedStringFromAttributedStringBox(
|
||||
facebook::react::AttributedStringBox const &attributedStringBox);
|
||||
|
||||
facebook::react::AttributedStringBox RCTAttributedStringBoxFromNSAttributedString(
|
||||
NSAttributedString *nsAttributedString);
|
||||
|
||||
@interface RCTWeakEventEmitterWrapper : NSObject
|
||||
@property (nonatomic, assign) facebook::react::SharedEventEmitter eventEmitter;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
283
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTAttributedTextUtils.mm
generated
vendored
Normal file
283
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTAttributedTextUtils.mm
generated
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "RCTAttributedTextUtils.h"
|
||||
|
||||
#include <react/core/LayoutableShadowNode.h>
|
||||
#include <react/textlayoutmanager/RCTFontProperties.h>
|
||||
#include <react/textlayoutmanager/RCTFontUtils.h>
|
||||
#include <react/textlayoutmanager/RCTTextPrimitivesConversions.h>
|
||||
#include <react/utils/ManagedObjectWrapper.h>
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
@implementation RCTWeakEventEmitterWrapper {
|
||||
std::weak_ptr<const EventEmitter> _weakEventEmitter;
|
||||
}
|
||||
|
||||
- (void)setEventEmitter:(SharedEventEmitter)eventEmitter
|
||||
{
|
||||
_weakEventEmitter = eventEmitter;
|
||||
}
|
||||
|
||||
- (SharedEventEmitter)eventEmitter
|
||||
{
|
||||
return _weakEventEmitter.lock();
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_weakEventEmitter.reset();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
inline static UIFontWeight RCTUIFontWeightFromInteger(NSInteger fontWeight)
|
||||
{
|
||||
assert(fontWeight > 50);
|
||||
assert(fontWeight < 950);
|
||||
|
||||
static UIFontWeight weights[] = {/* ~100 */ UIFontWeightUltraLight,
|
||||
/* ~200 */ UIFontWeightThin,
|
||||
/* ~300 */ UIFontWeightLight,
|
||||
/* ~400 */ UIFontWeightRegular,
|
||||
/* ~500 */ UIFontWeightMedium,
|
||||
/* ~600 */ UIFontWeightSemibold,
|
||||
/* ~700 */ UIFontWeightBold,
|
||||
/* ~800 */ UIFontWeightHeavy,
|
||||
/* ~900 */ UIFontWeightBlack};
|
||||
// The expression is designed to convert something like 760 or 830 to 7.
|
||||
return weights[(fontWeight + 50) / 100 - 1];
|
||||
}
|
||||
|
||||
inline static UIFont *RCTEffectiveFontFromTextAttributes(const TextAttributes &textAttributes)
|
||||
{
|
||||
NSString *fontFamily = [NSString stringWithCString:textAttributes.fontFamily.c_str() encoding:NSUTF8StringEncoding];
|
||||
|
||||
RCTFontProperties fontProperties;
|
||||
fontProperties.family = fontFamily;
|
||||
fontProperties.size = textAttributes.fontSize;
|
||||
fontProperties.style = textAttributes.fontStyle.hasValue()
|
||||
? RCTFontStyleFromFontStyle(textAttributes.fontStyle.value())
|
||||
: RCTFontStyleUndefined;
|
||||
fontProperties.variant = textAttributes.fontVariant.hasValue()
|
||||
? RCTFontVariantFromFontVariant(textAttributes.fontVariant.value())
|
||||
: RCTFontVariantUndefined;
|
||||
fontProperties.weight = textAttributes.fontWeight.hasValue()
|
||||
? RCTUIFontWeightFromInteger((NSInteger)textAttributes.fontWeight.value())
|
||||
: NAN;
|
||||
fontProperties.sizeMultiplier = textAttributes.fontSizeMultiplier;
|
||||
|
||||
return RCTFontWithFontProperties(fontProperties);
|
||||
}
|
||||
|
||||
inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const TextAttributes &textAttributes)
|
||||
{
|
||||
return textAttributes.allowFontScaling.value_or(true) && !isnan(textAttributes.fontSizeMultiplier)
|
||||
? textAttributes.fontSizeMultiplier
|
||||
: 1.0;
|
||||
}
|
||||
|
||||
inline static UIColor *RCTEffectiveForegroundColorFromTextAttributes(const TextAttributes &textAttributes)
|
||||
{
|
||||
UIColor *effectiveForegroundColor = RCTUIColorFromSharedColor(textAttributes.foregroundColor) ?: [UIColor blackColor];
|
||||
|
||||
if (!isnan(textAttributes.opacity)) {
|
||||
effectiveForegroundColor = [effectiveForegroundColor
|
||||
colorWithAlphaComponent:CGColorGetAlpha(effectiveForegroundColor.CGColor) * textAttributes.opacity];
|
||||
}
|
||||
|
||||
return effectiveForegroundColor;
|
||||
}
|
||||
|
||||
inline static UIColor *RCTEffectiveBackgroundColorFromTextAttributes(const TextAttributes &textAttributes)
|
||||
{
|
||||
UIColor *effectiveBackgroundColor = RCTUIColorFromSharedColor(textAttributes.backgroundColor);
|
||||
|
||||
if (effectiveBackgroundColor && !isnan(textAttributes.opacity)) {
|
||||
effectiveBackgroundColor = [effectiveBackgroundColor
|
||||
colorWithAlphaComponent:CGColorGetAlpha(effectiveBackgroundColor.CGColor) * textAttributes.opacity];
|
||||
}
|
||||
|
||||
return effectiveBackgroundColor ?: [UIColor clearColor];
|
||||
}
|
||||
|
||||
NSDictionary<NSAttributedStringKey, id> *RCTNSTextAttributesFromTextAttributes(TextAttributes const &textAttributes)
|
||||
{
|
||||
NSMutableDictionary<NSAttributedStringKey, id> *attributes = [NSMutableDictionary dictionaryWithCapacity:10];
|
||||
|
||||
// Font
|
||||
UIFont *font = RCTEffectiveFontFromTextAttributes(textAttributes);
|
||||
if (font) {
|
||||
attributes[NSFontAttributeName] = font;
|
||||
}
|
||||
|
||||
// Colors
|
||||
UIColor *effectiveForegroundColor = RCTEffectiveForegroundColorFromTextAttributes(textAttributes);
|
||||
|
||||
if (textAttributes.foregroundColor || !isnan(textAttributes.opacity)) {
|
||||
attributes[NSForegroundColorAttributeName] = effectiveForegroundColor;
|
||||
}
|
||||
|
||||
if (textAttributes.backgroundColor || !isnan(textAttributes.opacity)) {
|
||||
attributes[NSBackgroundColorAttributeName] = RCTEffectiveBackgroundColorFromTextAttributes(textAttributes);
|
||||
}
|
||||
|
||||
// Kerning
|
||||
if (!isnan(textAttributes.letterSpacing)) {
|
||||
attributes[NSKernAttributeName] = @(textAttributes.letterSpacing);
|
||||
}
|
||||
|
||||
// Paragraph Style
|
||||
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
|
||||
BOOL isParagraphStyleUsed = NO;
|
||||
if (textAttributes.alignment.hasValue()) {
|
||||
TextAlignment textAlignment = textAttributes.alignment.value_or(TextAlignment::Natural);
|
||||
if (textAttributes.layoutDirection.value_or(LayoutDirection::LeftToRight) == LayoutDirection::RightToLeft) {
|
||||
if (textAlignment == TextAlignment::Right) {
|
||||
textAlignment = TextAlignment::Left;
|
||||
} else if (textAlignment == TextAlignment::Left) {
|
||||
textAlignment = TextAlignment::Right;
|
||||
}
|
||||
}
|
||||
|
||||
paragraphStyle.alignment = RCTNSTextAlignmentFromTextAlignment(textAlignment);
|
||||
isParagraphStyleUsed = YES;
|
||||
}
|
||||
|
||||
if (textAttributes.baseWritingDirection.hasValue()) {
|
||||
paragraphStyle.baseWritingDirection =
|
||||
RCTNSWritingDirectionFromWritingDirection(textAttributes.baseWritingDirection.value());
|
||||
isParagraphStyleUsed = YES;
|
||||
}
|
||||
|
||||
if (!isnan(textAttributes.lineHeight)) {
|
||||
CGFloat lineHeight = textAttributes.lineHeight * RCTEffectiveFontSizeMultiplierFromTextAttributes(textAttributes);
|
||||
paragraphStyle.minimumLineHeight = lineHeight;
|
||||
paragraphStyle.maximumLineHeight = lineHeight;
|
||||
isParagraphStyleUsed = YES;
|
||||
}
|
||||
|
||||
if (isParagraphStyleUsed) {
|
||||
attributes[NSParagraphStyleAttributeName] = paragraphStyle;
|
||||
}
|
||||
|
||||
// Decoration
|
||||
if (textAttributes.textDecorationLineType.value_or(TextDecorationLineType::None) != TextDecorationLineType::None) {
|
||||
auto textDecorationLineType = textAttributes.textDecorationLineType.value();
|
||||
|
||||
NSUnderlineStyle style = RCTNSUnderlineStyleFromStyleAndPattern(
|
||||
textAttributes.textDecorationLineStyle.value_or(TextDecorationLineStyle::Single),
|
||||
textAttributes.textDecorationLinePattern.value_or(TextDecorationLinePattern::Solid));
|
||||
|
||||
UIColor *textDecorationColor = RCTUIColorFromSharedColor(textAttributes.textDecorationColor);
|
||||
|
||||
// Underline
|
||||
if (textDecorationLineType == TextDecorationLineType::Underline ||
|
||||
textDecorationLineType == TextDecorationLineType::UnderlineStrikethrough) {
|
||||
attributes[NSUnderlineStyleAttributeName] = @(style);
|
||||
|
||||
if (textDecorationColor) {
|
||||
attributes[NSUnderlineColorAttributeName] = textDecorationColor;
|
||||
}
|
||||
}
|
||||
|
||||
// Strikethrough
|
||||
if (textDecorationLineType == TextDecorationLineType::Strikethrough ||
|
||||
textDecorationLineType == TextDecorationLineType::UnderlineStrikethrough) {
|
||||
attributes[NSStrikethroughStyleAttributeName] = @(style);
|
||||
|
||||
if (textDecorationColor) {
|
||||
attributes[NSStrikethroughColorAttributeName] = textDecorationColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shadow
|
||||
if (textAttributes.textShadowOffset.hasValue()) {
|
||||
auto textShadowOffset = textAttributes.textShadowOffset.value();
|
||||
NSShadow *shadow = [NSShadow new];
|
||||
shadow.shadowOffset = CGSize{textShadowOffset.width, textShadowOffset.height};
|
||||
shadow.shadowBlurRadius = textAttributes.textShadowRadius;
|
||||
shadow.shadowColor = RCTUIColorFromSharedColor(textAttributes.textShadowColor);
|
||||
attributes[NSShadowAttributeName] = shadow;
|
||||
}
|
||||
|
||||
// Special
|
||||
if (textAttributes.isHighlighted) {
|
||||
attributes[RCTAttributedStringIsHighlightedAttributeName] = @YES;
|
||||
}
|
||||
|
||||
return [attributes copy];
|
||||
}
|
||||
|
||||
NSAttributedString *RCTNSAttributedStringFromAttributedString(const AttributedString &attributedString)
|
||||
{
|
||||
static UIImage *placeholderImage;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
placeholderImage = [[UIImage alloc] init];
|
||||
});
|
||||
|
||||
NSMutableAttributedString *nsAttributedString = [[NSMutableAttributedString alloc] init];
|
||||
|
||||
[nsAttributedString beginEditing];
|
||||
|
||||
for (auto fragment : attributedString.getFragments()) {
|
||||
NSMutableAttributedString *nsAttributedStringFragment;
|
||||
|
||||
if (fragment.isAttachment()) {
|
||||
auto layoutMetrics = fragment.parentShadowView.layoutMetrics;
|
||||
CGRect bounds = {.origin = {.x = layoutMetrics.frame.origin.x, .y = layoutMetrics.frame.origin.y},
|
||||
.size = {.width = layoutMetrics.frame.size.width, .height = layoutMetrics.frame.size.height}};
|
||||
|
||||
NSTextAttachment *attachment = [NSTextAttachment new];
|
||||
attachment.image = placeholderImage;
|
||||
attachment.bounds = bounds;
|
||||
|
||||
nsAttributedStringFragment = [[NSMutableAttributedString attributedStringWithAttachment:attachment] mutableCopy];
|
||||
} else {
|
||||
NSString *string = [NSString stringWithCString:fragment.string.c_str() encoding:NSUTF8StringEncoding];
|
||||
|
||||
nsAttributedStringFragment = [[NSMutableAttributedString alloc]
|
||||
initWithString:string
|
||||
attributes:RCTNSTextAttributesFromTextAttributes(fragment.textAttributes)];
|
||||
}
|
||||
|
||||
if (fragment.parentShadowView.componentHandle) {
|
||||
RCTWeakEventEmitterWrapper *eventEmitterWrapper = [RCTWeakEventEmitterWrapper new];
|
||||
eventEmitterWrapper.eventEmitter = fragment.parentShadowView.eventEmitter;
|
||||
|
||||
NSDictionary<NSAttributedStringKey, id> *additionalTextAttributes =
|
||||
@{RCTAttributedStringEventEmitterKey : eventEmitterWrapper};
|
||||
|
||||
[nsAttributedStringFragment addAttributes:additionalTextAttributes
|
||||
range:NSMakeRange(0, nsAttributedStringFragment.length)];
|
||||
}
|
||||
|
||||
[nsAttributedString appendAttributedString:nsAttributedStringFragment];
|
||||
}
|
||||
|
||||
[nsAttributedString endEditing];
|
||||
|
||||
return nsAttributedString;
|
||||
}
|
||||
|
||||
NSAttributedString *RCTNSAttributedStringFromAttributedStringBox(AttributedStringBox const &attributedStringBox)
|
||||
{
|
||||
switch (attributedStringBox.getMode()) {
|
||||
case AttributedStringBox::Mode::Value:
|
||||
return RCTNSAttributedStringFromAttributedString(attributedStringBox.getValue());
|
||||
case AttributedStringBox::Mode::OpaquePointer:
|
||||
return (NSAttributedString *)unwrapManagedObject(attributedStringBox.getOpaquePointer());
|
||||
}
|
||||
}
|
||||
|
||||
AttributedStringBox RCTAttributedStringBoxFromNSAttributedString(NSAttributedString *nsAttributedString)
|
||||
{
|
||||
return nsAttributedString.length ? AttributedStringBox{wrapManagedObject(nsAttributedString)} : AttributedStringBox{};
|
||||
}
|
38
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontProperties.h
generated
vendored
Normal file
38
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontProperties.h
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTFontStyle) {
|
||||
RCTFontStyleUndefined = -1,
|
||||
RCTFontStyleNormal,
|
||||
RCTFontStyleItalic,
|
||||
RCTFontStyleOblique,
|
||||
};
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, RCTFontVariant) {
|
||||
RCTFontVariantUndefined = -1,
|
||||
RCTFontVariantDefault = 0,
|
||||
RCTFontVariantSmallCaps = 1 << 1,
|
||||
RCTFontVariantOldstyleNums = 1 << 2,
|
||||
RCTFontVariantLiningNums = 1 << 3,
|
||||
RCTFontVariantTabularNums = 1 << 4,
|
||||
RCTFontVariantProportionalNums = 1 << 5,
|
||||
};
|
||||
|
||||
struct RCTFontProperties {
|
||||
NSString *family = nil;
|
||||
CGFloat size = NAN;
|
||||
UIFontWeight weight = NAN;
|
||||
RCTFontStyle style = RCTFontStyleUndefined;
|
||||
RCTFontVariant variant = RCTFontVariantUndefined;
|
||||
CGFloat sizeMultiplier = NAN;
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
19
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.h
generated
vendored
Normal file
19
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.h
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <react/textlayoutmanager/RCTFontProperties.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* Returns UIFont instance corresponded to given font properties.
|
||||
*/
|
||||
UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
166
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm
generated
vendored
Normal file
166
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "RCTFontUtils.h"
|
||||
|
||||
#import <algorithm>
|
||||
#import <cmath>
|
||||
#import <limits>
|
||||
#import <mutex>
|
||||
|
||||
static RCTFontProperties RCTDefaultFontProperties()
|
||||
{
|
||||
static RCTFontProperties defaultFontProperties;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
defaultFontProperties.family = [UIFont systemFontOfSize:defaultFontProperties.size].familyName;
|
||||
defaultFontProperties.size = 14;
|
||||
defaultFontProperties.weight = UIFontWeightRegular;
|
||||
defaultFontProperties.style = RCTFontStyleNormal;
|
||||
defaultFontProperties.variant = RCTFontVariantDefault;
|
||||
defaultFontProperties.sizeMultiplier = 1.0;
|
||||
});
|
||||
|
||||
return defaultFontProperties;
|
||||
}
|
||||
|
||||
static RCTFontProperties RCTResolveFontProperties(
|
||||
RCTFontProperties fontProperties,
|
||||
RCTFontProperties baseFontProperties)
|
||||
{
|
||||
fontProperties.family = fontProperties.family.length ? fontProperties.family : baseFontProperties.family;
|
||||
fontProperties.size = !isnan(fontProperties.size) ? fontProperties.size : baseFontProperties.size;
|
||||
fontProperties.weight = !isnan(fontProperties.weight) ? fontProperties.weight : baseFontProperties.weight;
|
||||
fontProperties.style =
|
||||
fontProperties.style != RCTFontStyleUndefined ? fontProperties.style : baseFontProperties.style;
|
||||
fontProperties.variant =
|
||||
fontProperties.variant != RCTFontVariantUndefined ? fontProperties.variant : baseFontProperties.variant;
|
||||
return fontProperties;
|
||||
}
|
||||
|
||||
static UIFontWeight RCTGetFontWeight(UIFont *font)
|
||||
{
|
||||
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||
return [traits[UIFontWeightTrait] doubleValue];
|
||||
}
|
||||
|
||||
static RCTFontStyle RCTGetFontStyle(UIFont *font)
|
||||
{
|
||||
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||
UIFontDescriptorSymbolicTraits symbolicTraits = [traits[UIFontSymbolicTrait] unsignedIntValue];
|
||||
if (symbolicTraits & UIFontDescriptorTraitItalic) {
|
||||
return RCTFontStyleItalic;
|
||||
}
|
||||
|
||||
return RCTFontStyleNormal;
|
||||
}
|
||||
|
||||
static NSArray *RCTFontFeatures(RCTFontVariant fontVariant)
|
||||
{
|
||||
// FIXME:
|
||||
return @[];
|
||||
}
|
||||
|
||||
static UIFont *RCTDefaultFontWithFontProperties(RCTFontProperties fontProperties)
|
||||
{
|
||||
static NSCache *fontCache;
|
||||
static std::mutex fontCacheMutex;
|
||||
|
||||
NSString *cacheKey = [NSString stringWithFormat:@"%.1f/%.2f", fontProperties.size, fontProperties.weight];
|
||||
UIFont *font;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fontCacheMutex);
|
||||
if (!fontCache) {
|
||||
fontCache = [NSCache new];
|
||||
}
|
||||
font = [fontCache objectForKey:cacheKey];
|
||||
}
|
||||
|
||||
if (!font) {
|
||||
font = [UIFont systemFontOfSize:fontProperties.size weight:fontProperties.weight];
|
||||
|
||||
if (fontProperties.variant == RCTFontStyleItalic) {
|
||||
UIFontDescriptor *fontDescriptor = [font fontDescriptor];
|
||||
UIFontDescriptorSymbolicTraits symbolicTraits = fontDescriptor.symbolicTraits;
|
||||
|
||||
symbolicTraits |= UIFontDescriptorTraitItalic;
|
||||
|
||||
fontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:symbolicTraits];
|
||||
font = [UIFont fontWithDescriptor:fontDescriptor size:fontProperties.size];
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fontCacheMutex);
|
||||
[fontCache setObject:font forKey:cacheKey];
|
||||
}
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
UIFont *RCTFontWithFontProperties(RCTFontProperties fontProperties)
|
||||
{
|
||||
RCTFontProperties defaultFontProperties = RCTDefaultFontProperties();
|
||||
fontProperties = RCTResolveFontProperties(fontProperties, defaultFontProperties);
|
||||
|
||||
assert(!isnan(fontProperties.sizeMultiplier));
|
||||
CGFloat effectiveFontSize = fontProperties.sizeMultiplier * fontProperties.size;
|
||||
UIFont *font;
|
||||
if ([fontProperties.family isEqualToString:defaultFontProperties.family]) {
|
||||
// Handle system font as special case. This ensures that we preserve
|
||||
// the specific metrics of the standard system font as closely as possible.
|
||||
font = RCTDefaultFontWithFontProperties(fontProperties);
|
||||
} else {
|
||||
NSArray<NSString *> *fontNames = [UIFont fontNamesForFamilyName:fontProperties.family];
|
||||
|
||||
if (fontNames.count == 0) {
|
||||
// Gracefully handle being given a font name rather than font family, for
|
||||
// example: "Helvetica Light Oblique" rather than just "Helvetica".
|
||||
font = [UIFont fontWithName:fontProperties.family size:effectiveFontSize];
|
||||
|
||||
if (!font) {
|
||||
// Failback to system font.
|
||||
font = [UIFont systemFontOfSize:effectiveFontSize weight:fontProperties.weight];
|
||||
}
|
||||
} else {
|
||||
// Get the closest font that matches the given weight for the fontFamily
|
||||
CGFloat closestWeight = INFINITY;
|
||||
for (NSString *name in fontNames) {
|
||||
UIFont *fontMatch = [UIFont fontWithName:name size:effectiveFontSize];
|
||||
|
||||
if (RCTGetFontStyle(fontMatch) != fontProperties.style) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CGFloat testWeight = RCTGetFontWeight(fontMatch);
|
||||
if (ABS(testWeight - fontProperties.weight) < ABS(closestWeight - fontProperties.weight)) {
|
||||
font = fontMatch;
|
||||
closestWeight = testWeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (!font) {
|
||||
// If we still don't have a match at least return the first font in the
|
||||
// fontFamily This is to support built-in font Zapfino and other custom
|
||||
// single font families like Impact
|
||||
font = [UIFont fontWithName:fontNames[0] size:effectiveFontSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply font variants to font object.
|
||||
if (fontProperties.variant != RCTFontVariantDefault) {
|
||||
NSArray *fontFeatures = RCTFontFeatures(fontProperties.variant);
|
||||
UIFontDescriptor *fontDescriptor = [font.fontDescriptor
|
||||
fontDescriptorByAddingAttributes:@{UIFontDescriptorFeatureSettingsAttribute : fontFeatures}];
|
||||
font = [UIFont fontWithDescriptor:fontDescriptor size:effectiveFontSize];
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
43
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextLayoutManager.h
generated
vendored
Normal file
43
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextLayoutManager.h
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <react/attributedstring/AttributedString.h>
|
||||
#import <react/attributedstring/ParagraphAttributes.h>
|
||||
#import <react/core/LayoutConstraints.h>
|
||||
#import <react/graphics/Geometry.h>
|
||||
#import <react/textlayoutmanager/TextMeasureCache.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* iOS-specific TextLayoutManager
|
||||
*/
|
||||
@interface RCTTextLayoutManager : NSObject
|
||||
|
||||
- (facebook::react::TextMeasurement)measureAttributedString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints;
|
||||
|
||||
- (facebook::react::TextMeasurement)measureNSAttributedString:(NSAttributedString *)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints;
|
||||
|
||||
- (void)drawAttributedString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
frame:(CGRect)frame;
|
||||
|
||||
- (facebook::react::SharedEventEmitter)
|
||||
getEventEmitterWithAttributeString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
frame:(CGRect)frame
|
||||
atPoint:(CGPoint)point;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
182
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextLayoutManager.mm
generated
vendored
Normal file
182
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextLayoutManager.mm
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "RCTTextLayoutManager.h"
|
||||
|
||||
#import "NSTextStorage+FontScaling.h"
|
||||
#import "RCTAttributedTextUtils.h"
|
||||
|
||||
#import <react/utils/SimpleThreadSafeCache.h>
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
@implementation RCTTextLayoutManager {
|
||||
SimpleThreadSafeCache<AttributedString, std::shared_ptr<const void>, 256> _cache;
|
||||
}
|
||||
|
||||
static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsizeMode)
|
||||
{
|
||||
switch (ellipsizeMode) {
|
||||
case EllipsizeMode::Clip:
|
||||
return NSLineBreakByClipping;
|
||||
case EllipsizeMode::Head:
|
||||
return NSLineBreakByTruncatingHead;
|
||||
case EllipsizeMode::Tail:
|
||||
return NSLineBreakByTruncatingTail;
|
||||
case EllipsizeMode::Middle:
|
||||
return NSLineBreakByTruncatingMiddle;
|
||||
}
|
||||
}
|
||||
|
||||
- (TextMeasurement)measureNSAttributedString:(NSAttributedString *)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(LayoutConstraints)layoutConstraints
|
||||
{
|
||||
if (attributedString.length == 0) {
|
||||
// This is not really an optimization because that should be checked much earlier on the call stack.
|
||||
// Sometimes, very irregularly, measuring an empty string crashes/freezes iOS internal text infrastructure.
|
||||
// This is our last line of defense.
|
||||
return {};
|
||||
}
|
||||
|
||||
CGSize maximumSize = CGSize{layoutConstraints.maximumSize.width, CGFLOAT_MAX};
|
||||
|
||||
NSTextStorage *textStorage = [self _textStorageAndLayoutManagerWithAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:maximumSize];
|
||||
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
[layoutManager ensureLayoutForTextContainer:textContainer];
|
||||
|
||||
CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
|
||||
|
||||
__block auto attachments = TextMeasurement::Attachments{};
|
||||
|
||||
[textStorage
|
||||
enumerateAttribute:NSAttachmentAttributeName
|
||||
inRange:NSMakeRange(0, textStorage.length)
|
||||
options:0
|
||||
usingBlock:^(NSTextAttachment *attachment, NSRange range, BOOL *stop) {
|
||||
if (!attachment) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGSize attachmentSize = attachment.bounds.size;
|
||||
CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer];
|
||||
|
||||
UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil];
|
||||
|
||||
CGRect frame = {{glyphRect.origin.x,
|
||||
glyphRect.origin.y + glyphRect.size.height - attachmentSize.height + font.descender},
|
||||
attachmentSize};
|
||||
|
||||
auto rect = facebook::react::Rect{facebook::react::Point{frame.origin.x, frame.origin.y},
|
||||
facebook::react::Size{frame.size.width, frame.size.height}};
|
||||
|
||||
attachments.push_back(TextMeasurement::Attachment{rect, false});
|
||||
}];
|
||||
|
||||
return TextMeasurement{{size.width, size.height}, attachments};
|
||||
}
|
||||
|
||||
- (TextMeasurement)measureAttributedString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(LayoutConstraints)layoutConstraints
|
||||
{
|
||||
return [self measureNSAttributedString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
layoutConstraints:layoutConstraints];
|
||||
}
|
||||
|
||||
- (void)drawAttributedString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
frame:(CGRect)frame
|
||||
{
|
||||
NSTextStorage *textStorage = [self
|
||||
_textStorageAndLayoutManagerWithAttributesString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:frame.size];
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
|
||||
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
|
||||
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:frame.origin];
|
||||
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:frame.origin];
|
||||
}
|
||||
|
||||
- (NSTextStorage *)_textStorageAndLayoutManagerWithAttributesString:(NSAttributedString *)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
size:(CGSize)size
|
||||
{
|
||||
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
|
||||
|
||||
textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
|
||||
textContainer.lineBreakMode = paragraphAttributes.maximumNumberOfLines > 0
|
||||
? RCTNSLineBreakModeFromEllipsizeMode(paragraphAttributes.ellipsizeMode)
|
||||
: NSLineBreakByClipping;
|
||||
textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
|
||||
|
||||
NSLayoutManager *layoutManager = [NSLayoutManager new];
|
||||
layoutManager.usesFontLeading = NO;
|
||||
[layoutManager addTextContainer:textContainer];
|
||||
|
||||
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
|
||||
|
||||
[textStorage addLayoutManager:layoutManager];
|
||||
|
||||
if (paragraphAttributes.adjustsFontSizeToFit) {
|
||||
CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
|
||||
CGFloat maximumFontSize = !isnan(paragraphAttributes.maximumFontSize) ? paragraphAttributes.maximumFontSize : 96.0;
|
||||
[textStorage scaleFontSizeToFitSize:size minimumFontSize:minimumFontSize maximumFontSize:maximumFontSize];
|
||||
}
|
||||
|
||||
return textStorage;
|
||||
}
|
||||
|
||||
- (SharedEventEmitter)getEventEmitterWithAttributeString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
frame:(CGRect)frame
|
||||
atPoint:(CGPoint)point
|
||||
{
|
||||
NSTextStorage *textStorage = [self
|
||||
_textStorageAndLayoutManagerWithAttributesString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:frame.size];
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
|
||||
CGFloat fraction;
|
||||
NSUInteger characterIndex = [layoutManager characterIndexForPoint:point
|
||||
inTextContainer:textContainer
|
||||
fractionOfDistanceBetweenInsertionPoints:&fraction];
|
||||
|
||||
// If the point is not before (fraction == 0.0) the first character and not
|
||||
// after (fraction == 1.0) the last character, then the attribute is valid.
|
||||
if (textStorage.length > 0 && (fraction > 0 || characterIndex > 0) &&
|
||||
(fraction < 1 || characterIndex < textStorage.length - 1)) {
|
||||
RCTWeakEventEmitterWrapper *eventEmitterWrapper =
|
||||
(RCTWeakEventEmitterWrapper *)[textStorage attribute:RCTAttributedStringEventEmitterKey
|
||||
atIndex:characterIndex
|
||||
effectiveRange:NULL];
|
||||
return eventEmitterWrapper.eventEmitter;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSAttributedString *)_nsAttributedStringFromAttributedString:(AttributedString)attributedString
|
||||
{
|
||||
auto sharedNSAttributedString = _cache.get(attributedString, [](const AttributedString attributedString) {
|
||||
return std::shared_ptr<void>(
|
||||
(__bridge_retained void *)RCTNSAttributedStringFromAttributedString(attributedString), CFRelease);
|
||||
});
|
||||
|
||||
return (__bridge NSAttributedString *)sharedNSAttributedString.get();
|
||||
}
|
||||
|
||||
@end
|
102
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextPrimitivesConversions.h
generated
vendored
Normal file
102
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTTextPrimitivesConversions.h
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#include <react/textlayoutmanager/RCTFontProperties.h>
|
||||
#include <react/textlayoutmanager/RCTFontUtils.h>
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
inline static NSTextAlignment RCTNSTextAlignmentFromTextAlignment(TextAlignment textAlignment)
|
||||
{
|
||||
switch (textAlignment) {
|
||||
case TextAlignment::Natural:
|
||||
return NSTextAlignmentNatural;
|
||||
case TextAlignment::Left:
|
||||
return NSTextAlignmentLeft;
|
||||
case TextAlignment::Right:
|
||||
return NSTextAlignmentRight;
|
||||
case TextAlignment::Center:
|
||||
return NSTextAlignmentCenter;
|
||||
case TextAlignment::Justified:
|
||||
return NSTextAlignmentJustified;
|
||||
}
|
||||
}
|
||||
|
||||
inline static NSWritingDirection RCTNSWritingDirectionFromWritingDirection(WritingDirection writingDirection)
|
||||
{
|
||||
switch (writingDirection) {
|
||||
case WritingDirection::Natural:
|
||||
return NSWritingDirectionNatural;
|
||||
case WritingDirection::LeftToRight:
|
||||
return NSWritingDirectionLeftToRight;
|
||||
case WritingDirection::RightToLeft:
|
||||
return NSWritingDirectionRightToLeft;
|
||||
}
|
||||
}
|
||||
|
||||
inline static RCTFontStyle RCTFontStyleFromFontStyle(FontStyle fontStyle)
|
||||
{
|
||||
switch (fontStyle) {
|
||||
case FontStyle::Normal:
|
||||
return RCTFontStyleNormal;
|
||||
case FontStyle::Italic:
|
||||
return RCTFontStyleItalic;
|
||||
case FontStyle::Oblique:
|
||||
return RCTFontStyleOblique;
|
||||
}
|
||||
}
|
||||
|
||||
inline static RCTFontVariant RCTFontVariantFromFontVariant(FontVariant fontVariant)
|
||||
{
|
||||
return (RCTFontVariant)fontVariant;
|
||||
}
|
||||
|
||||
inline static NSUnderlineStyle RCTNSUnderlineStyleFromStyleAndPattern(
|
||||
TextDecorationLineStyle textDecorationLineStyle,
|
||||
TextDecorationLinePattern textDecorationLinePattern)
|
||||
{
|
||||
NSUnderlineStyle style = NSUnderlineStyleNone;
|
||||
|
||||
switch (textDecorationLineStyle) {
|
||||
case TextDecorationLineStyle::Single:
|
||||
style = NSUnderlineStyle(style | NSUnderlineStyleSingle);
|
||||
break;
|
||||
case TextDecorationLineStyle::Thick:
|
||||
style = NSUnderlineStyle(style | NSUnderlineStyleThick);
|
||||
break;
|
||||
case TextDecorationLineStyle::Double:
|
||||
style = NSUnderlineStyle(style | NSUnderlineStyleDouble);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (textDecorationLinePattern) {
|
||||
case TextDecorationLinePattern::Solid:
|
||||
style = NSUnderlineStyle(style | NSUnderlinePatternSolid);
|
||||
break;
|
||||
case TextDecorationLinePattern::Dash:
|
||||
style = NSUnderlineStyle(style | NSUnderlinePatternDash);
|
||||
break;
|
||||
case TextDecorationLinePattern::Dot:
|
||||
style = NSUnderlineStyle(style | NSUnderlinePatternDot);
|
||||
break;
|
||||
case TextDecorationLinePattern::DashDot:
|
||||
style = NSUnderlineStyle(style | NSUnderlinePatternDashDot);
|
||||
break;
|
||||
case TextDecorationLinePattern::DashDotDot:
|
||||
style = NSUnderlineStyle(style | NSUnderlinePatternDashDotDot);
|
||||
break;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
inline static UIColor *RCTUIColorFromSharedColor(const SharedColor &color)
|
||||
{
|
||||
return color ? [UIColor colorWithCGColor:color.get()] : nil;
|
||||
}
|
54
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.h
generated
vendored
Normal file
54
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.h
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <memory>
|
||||
|
||||
#include <react/attributedstring/AttributedStringBox.h>
|
||||
#include <react/attributedstring/ParagraphAttributes.h>
|
||||
#include <react/core/LayoutConstraints.h>
|
||||
#include <react/textlayoutmanager/TextMeasureCache.h>
|
||||
#include <react/utils/ContextContainer.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class TextLayoutManager;
|
||||
|
||||
using SharedTextLayoutManager = std::shared_ptr<const TextLayoutManager>;
|
||||
|
||||
/*
|
||||
* Cross platform facade for iOS-specific RCTTTextLayoutManager.
|
||||
*/
|
||||
class TextLayoutManager {
|
||||
public:
|
||||
using Shared = std::shared_ptr<TextLayoutManager const>;
|
||||
|
||||
TextLayoutManager(ContextContainer::Shared const &contextContainer);
|
||||
|
||||
/*
|
||||
* Measures `attributedString` using native text rendering infrastructure.
|
||||
*/
|
||||
TextMeasurement measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
/*
|
||||
* Returns an opaque pointer to platform-specific TextLayoutManager.
|
||||
* Is used on a native views layer to delegate text rendering to the manager.
|
||||
*/
|
||||
std::shared_ptr<void> getNativeTextLayoutManager() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<void> self_;
|
||||
TextMeasureCache measureCache_{};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
67
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.mm
generated
vendored
Normal file
67
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.mm
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "TextLayoutManager.h"
|
||||
|
||||
#include <react/utils/ManagedObjectWrapper.h>
|
||||
|
||||
#import "RCTTextLayoutManager.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
TextLayoutManager::TextLayoutManager(ContextContainer::Shared const &contextContainer)
|
||||
{
|
||||
self_ = wrapManagedObject([RCTTextLayoutManager new]);
|
||||
}
|
||||
|
||||
std::shared_ptr<void> TextLayoutManager::getNativeTextLayoutManager() const
|
||||
{
|
||||
assert(self_ && "Stored NativeTextLayoutManager must not be null.");
|
||||
return self_;
|
||||
}
|
||||
|
||||
TextMeasurement TextLayoutManager::measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const
|
||||
{
|
||||
RCTTextLayoutManager *textLayoutManager = (RCTTextLayoutManager *)unwrapManagedObject(self_);
|
||||
|
||||
auto measurement = TextMeasurement{};
|
||||
|
||||
switch (attributedStringBox.getMode()) {
|
||||
case AttributedStringBox::Mode::Value: {
|
||||
auto &attributedString = attributedStringBox.getValue();
|
||||
|
||||
measurement = measureCache_.get(
|
||||
{attributedString, paragraphAttributes, layoutConstraints}, [&](TextMeasureCacheKey const &key) {
|
||||
return [textLayoutManager measureAttributedString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
layoutConstraints:layoutConstraints];
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case AttributedStringBox::Mode::OpaquePointer: {
|
||||
NSAttributedString *nsAttributedString =
|
||||
(NSAttributedString *)unwrapManagedObject(attributedStringBox.getOpaquePointer());
|
||||
|
||||
measurement = [textLayoutManager measureNSAttributedString:nsAttributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
layoutConstraints:layoutConstraints];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
measurement.size = layoutConstraints.clamp(measurement.size);
|
||||
|
||||
return measurement;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
18
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/tests/TextLayoutManagerTest.cpp
generated
vendored
Normal file
18
node_modules/react-native/ReactCommon/fabric/textlayoutmanager/tests/TextLayoutManagerTest.cpp
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <react/textlayoutmanager/TextLayoutManager.h>
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
TEST(TextLayoutManagerTest, testSomething) {
|
||||
// TODO:
|
||||
}
|
Reference in New Issue
Block a user