Skip to content

Commit bae3e3b

Browse files
Levi McCallumlevi
authored andcommitted
Add latest ComponentKit text kit renderer into project
1 parent 9032962 commit bae3e3b

19 files changed

Lines changed: 1875 additions & 0 deletions

AsyncDisplayKit.xcodeproj/project.pbxproj

Lines changed: 80 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright (c) 2014-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#import <Foundation/Foundation.h>
12+
13+
#import <string>
14+
15+
// From folly:
16+
// This is the Hash128to64 function from Google's cityhash (available
17+
// under the MIT License). We use it to reduce multiple 64 bit hashes
18+
// into a single hash.
19+
inline uint64_t CKHashCombine(const uint64_t upper, const uint64_t lower) {
20+
// Murmur-inspired hashing.
21+
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
22+
uint64_t a = (lower ^ upper) * kMul;
23+
a ^= (a >> 47);
24+
uint64_t b = (upper ^ a) * kMul;
25+
b ^= (b >> 47);
26+
b *= kMul;
27+
return b;
28+
}
29+
30+
#if __LP64__
31+
inline size_t CKHash64ToNative(uint64_t key) {
32+
return key;
33+
}
34+
#else
35+
36+
// Thomas Wang downscaling hash function
37+
inline size_t CKHash64ToNative(uint64_t key) {
38+
key = (~key) + (key << 18);
39+
key = key ^ (key >> 31);
40+
key = key * 21;
41+
key = key ^ (key >> 11);
42+
key = key + (key << 6);
43+
key = key ^ (key >> 22);
44+
return (uint32_t) key;
45+
}
46+
#endif
47+
48+
NSUInteger CKIntegerArrayHash(const NSUInteger *subhashes, NSUInteger count);
49+
50+
namespace CK {
51+
// Default is not an ObjC class
52+
template<typename T, typename V = bool>
53+
struct is_objc_class : std::false_type { };
54+
55+
// Conditionally enable this template specialization on whether T is convertible to id, makes the is_objc_class a true_type
56+
template<typename T>
57+
struct is_objc_class<T, typename std::enable_if<std::is_convertible<T, id>::value, bool>::type> : std::true_type { };
58+
59+
// CKUtils::hash<T>()(value) -> either std::hash<T> if c++ or [o hash] if ObjC object.
60+
template <typename T, typename Enable = void> struct hash;
61+
62+
// For non-objc types, defer to std::hash
63+
template <typename T> struct hash<T, typename std::enable_if<!is_objc_class<T>::value>::type> {
64+
size_t operator ()(const T& a) {
65+
return std::hash<T>()(a);
66+
}
67+
};
68+
69+
// For objc types, call [o hash]
70+
template <typename T> struct hash<T, typename std::enable_if<is_objc_class<T>::value>::type> {
71+
size_t operator ()(id o) {
72+
return [o hash];
73+
}
74+
};
75+
76+
template <typename T, typename Enable = void> struct is_equal;
77+
78+
// For non-objc types use == operator
79+
template <typename T> struct is_equal<T, typename std::enable_if<!is_objc_class<T>::value>::type> {
80+
bool operator ()(const T& a, const T& b) {
81+
return a == b;
82+
}
83+
};
84+
85+
// For objc types, check pointer equality, then use -isEqual:
86+
template <typename T> struct is_equal<T, typename std::enable_if<is_objc_class<T>::value>::type> {
87+
bool operator ()(id a, id b) {
88+
return a == b || [a isEqual:b];
89+
}
90+
};
91+
92+
};
93+
94+
namespace CKTupleOperations
95+
{
96+
// Recursive case (hash up to Index)
97+
template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
98+
struct _hash_helper
99+
{
100+
static size_t hash(Tuple const& tuple)
101+
{
102+
size_t prev = _hash_helper<Tuple, Index-1>::hash(tuple);
103+
using TypeForIndex = typename std::tuple_element<Index,Tuple>::type;
104+
size_t thisHash = CK::hash<TypeForIndex>()(std::get<Index>(tuple));
105+
return CKHashCombine(prev, thisHash);
106+
}
107+
};
108+
109+
// Base case (hash 0th element)
110+
template <class Tuple>
111+
struct _hash_helper<Tuple, 0>
112+
{
113+
static size_t hash(Tuple const& tuple)
114+
{
115+
using TypeForIndex = typename std::tuple_element<0,Tuple>::type;
116+
return CK::hash<TypeForIndex>()(std::get<0>(tuple));
117+
}
118+
};
119+
120+
// Recursive case (elements equal up to Index)
121+
template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
122+
struct _eq_helper
123+
{
124+
static bool equal(Tuple const& a, Tuple const& b)
125+
{
126+
bool prev = _eq_helper<Tuple, Index-1>::equal(a, b);
127+
using TypeForIndex = typename std::tuple_element<Index,Tuple>::type;
128+
auto aValue = std::get<Index>(a);
129+
auto bValue = std::get<Index>(b);
130+
return prev && CK::is_equal<TypeForIndex>()(aValue, bValue);
131+
}
132+
};
133+
134+
// Base case (0th elements equal)
135+
template <class Tuple>
136+
struct _eq_helper<Tuple, 0>
137+
{
138+
static bool equal(Tuple const& a, Tuple const& b)
139+
{
140+
using TypeForIndex = typename std::tuple_element<0,Tuple>::type;
141+
auto& aValue = std::get<0>(a);
142+
auto& bValue = std::get<0>(b);
143+
return CK::is_equal<TypeForIndex>()(aValue, bValue);
144+
}
145+
};
146+
147+
148+
template <typename ... TT> struct hash;
149+
150+
template <typename ... TT>
151+
struct hash<std::tuple<TT...>>
152+
{
153+
size_t operator()(std::tuple<TT...> const& tt) const
154+
{
155+
return _hash_helper<std::tuple<TT...>>::hash(tt);
156+
}
157+
};
158+
159+
160+
template <typename ... TT> struct equal_to;
161+
162+
template <typename ... TT>
163+
struct equal_to<std::tuple<TT...>>
164+
{
165+
bool operator()(std::tuple<TT...> const& a, std::tuple<TT...> const& b) const
166+
{
167+
return _eq_helper<std::tuple<TT...>>::equal(a, b);
168+
}
169+
};
170+
171+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright (c) 2014-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#import <UIKit/UIKit.h>
12+
13+
#ifndef ComponentKit_CKTextKitAttributes_h
14+
#define ComponentKit_CKTextKitAttributes_h
15+
16+
@protocol CKTextKitTruncating;
17+
18+
extern NSString *const CKTextKitTruncationAttributeName;
19+
/**
20+
Use CKTextKitEntityAttribute as the value of this attribute to embed a link or other interactable content inside the
21+
text.
22+
*/
23+
extern NSString *const CKTextKitEntityAttributeName;
24+
25+
static inline BOOL _objectsEqual(id<NSObject> obj1, id<NSObject> obj2)
26+
{
27+
return obj1 == obj2 ? YES : [obj1 isEqual:obj2];
28+
}
29+
30+
/**
31+
All NSObject values in this struct should be copied when passed into the TextComponent.
32+
*/
33+
struct CKTextKitAttributes {
34+
/**
35+
The string to be drawn. CKTextKit will not augment this string with default colors, etc. so this must be complete.
36+
*/
37+
NSAttributedString *attributedString;
38+
/**
39+
The string to use as the truncation string, usually just "...". If you have a range of text you would like to
40+
restrict highlighting to (for instance if you have "... Continue Reading", use the CKTextKitTruncationAttributeName
41+
to mark the specific range of the string that should be highlightable.
42+
*/
43+
NSAttributedString *truncationAttributedString;
44+
/**
45+
This is the character set that CKTextKit should attempt to avoid leaving as a trailing character before your
46+
truncation token. By default this set includes "\s\t\n\r.,!?:;" so you don't end up with ugly looking truncation
47+
text like "Hey, this is some fancy Truncation!\n\n...". Instead it would be truncated as "Hey, this is some fancy
48+
truncation...". This is not always possible.
49+
50+
Set this to the empty charset if you want to just use the "dumb" truncation behavior. A nil value will be
51+
substituted with the default described above.
52+
*/
53+
NSCharacterSet *avoidTailTruncationSet;
54+
/**
55+
The line-break mode to apply to the text. Since this also impacts how TextKit will attempt to truncate the text
56+
in your string, we only support NSLineBreakByWordWrapping and NSLineBreakByCharWrapping.
57+
*/
58+
NSLineBreakMode lineBreakMode;
59+
/**
60+
The maximum number of lines to draw in the drawable region. Leave blank or set to 0 to define no maximum.
61+
*/
62+
NSUInteger maximumNumberOfLines;
63+
/**
64+
The shadow offset for any shadows applied to the text. The coordinate space for this is the same as UIKit, so a
65+
positive width means towards the right, and a positive height means towards the bottom.
66+
*/
67+
CGSize shadowOffset;
68+
/**
69+
The color to use in drawing the text's shadow.
70+
*/
71+
UIColor *shadowColor;
72+
/**
73+
The opacity of the shadow from 0 to 1.
74+
*/
75+
CGFloat shadowOpacity;
76+
/**
77+
The radius that should be applied to the shadow blur. Larger values mean a larger, more blurred shadow.
78+
*/
79+
CGFloat shadowRadius;
80+
/**
81+
A pointer to a function that that returns a custom layout manager subclass. If nil, defaults to NSLayoutManager.
82+
*/
83+
NSLayoutManager *(*layoutManagerFactory)(void);
84+
85+
/**
86+
We provide an explicit copy function so we can use aggregate initializer syntax while providing copy semantics for
87+
the NSObjects inside.
88+
*/
89+
const CKTextKitAttributes copy() const
90+
{
91+
return {
92+
[attributedString copy],
93+
[truncationAttributedString copy],
94+
[avoidTailTruncationSet copy],
95+
lineBreakMode,
96+
maximumNumberOfLines,
97+
shadowOffset,
98+
[shadowColor copy],
99+
shadowOpacity,
100+
shadowRadius,
101+
layoutManagerFactory
102+
};
103+
};
104+
105+
bool operator==(const CKTextKitAttributes &other) const
106+
{
107+
// These comparisons are in a specific order to reduce the overall cost of this function.
108+
return lineBreakMode == other.lineBreakMode
109+
&& maximumNumberOfLines == other.maximumNumberOfLines
110+
&& shadowOpacity == other.shadowOpacity
111+
&& shadowRadius == other.shadowRadius
112+
&& layoutManagerFactory == other.layoutManagerFactory
113+
&& CGSizeEqualToSize(shadowOffset, other.shadowOffset)
114+
&& _objectsEqual(avoidTailTruncationSet, other.avoidTailTruncationSet)
115+
&& _objectsEqual(shadowColor, other.shadowColor)
116+
&& _objectsEqual(attributedString, other.attributedString)
117+
&& _objectsEqual(truncationAttributedString, other.truncationAttributedString);
118+
}
119+
120+
size_t hash() const;
121+
};
122+
123+
#endif
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (c) 2014-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#import "CKTextKitAttributes.h"
12+
13+
#import "CKEqualityHashHelpers.h"
14+
15+
#include <functional>
16+
17+
NSString *const CKTextKitTruncationAttributeName = @"ck_truncation";
18+
NSString *const CKTextKitEntityAttributeName = @"ck_entity";
19+
20+
size_t CKTextKitAttributes::hash() const
21+
{
22+
NSUInteger subhashes[] = {
23+
[attributedString hash],
24+
[truncationAttributedString hash],
25+
[avoidTailTruncationSet hash],
26+
std::hash<NSUInteger>()((NSUInteger) layoutManagerFactory),
27+
std::hash<NSInteger>()(lineBreakMode),
28+
std::hash<NSInteger>()(maximumNumberOfLines),
29+
std::hash<CGFloat>()(shadowOffset.width),
30+
std::hash<CGFloat>()(shadowOffset.height),
31+
[shadowColor hash],
32+
std::hash<CGFloat>()(shadowOpacity),
33+
std::hash<CGFloat>()(shadowRadius),
34+
};
35+
return CKIntegerArrayHash(subhashes, sizeof(subhashes) / sizeof(subhashes[0]));
36+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2014-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#import <UIKit/UIKit.h>
12+
13+
/**
14+
A threadsafe container for the TextKit components that CKTextKit uses to lay out and truncate its text.
15+
16+
This container is the sole owner and manager of the TextKit classes. This is an important model because of major
17+
thread safety issues inside vanilla TextKit. It provides a central locking location for accessing TextKit methods.
18+
*/
19+
@interface CKTextKitContext : NSObject
20+
21+
/**
22+
Initializes a context and its associated TextKit components.
23+
24+
Initialization of TextKit components is a globally locking operation so be careful of bottlenecks with this class.
25+
*/
26+
- (instancetype)initWithAttributedString:(NSAttributedString *)attributedString
27+
lineBreakMode:(NSLineBreakMode)lineBreakMode
28+
maximumNumberOfLines:(NSUInteger)maximumNumberOfLines
29+
constrainedSize:(CGSize)constrainedSize
30+
layoutManagerFactory:(NSLayoutManager*(*)(void))layoutManagerFactory;
31+
32+
/**
33+
All operations on TextKit values MUST occur within this locked context. Simultaneous access (even non-mutative) to
34+
TextKit components may cause crashes.
35+
36+
The block provided MUST not call out to client code from within its scope or it is possible for this to cause deadlocks
37+
in your application. Use with EXTREME care.
38+
39+
Callers MUST NOT keep a ref to these internal objects and use them later. This WILL cause crashes in your application.
40+
*/
41+
- (void)performBlockWithLockedTextKitComponents:(void (^)(NSLayoutManager *layoutManager,
42+
NSTextStorage *textStorage,
43+
NSTextContainer *textContainer))block;
44+
45+
@end

0 commit comments

Comments
 (0)