POPAnimationRuntime.mm 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /**
  2. Copyright (c) 2014-present, Facebook, Inc.
  3. All rights reserved.
  4. This source code is licensed under the BSD-style license found in the
  5. LICENSE file in the root directory of this source tree. An additional grant
  6. of patent rights can be found in the PATENTS file in the same directory.
  7. */
  8. #import "POPAnimationRuntime.h"
  9. #import <objc/objc.h>
  10. #import <QuartzCore/QuartzCore.h>
  11. #if TARGET_OS_IPHONE
  12. #import <UIKit/UIKit.h>
  13. #endif
  14. #import "POPCGUtils.h"
  15. #import "POPDefines.h"
  16. #import "POPGeometry.h"
  17. #import "POPVector.h"
  18. static Boolean pointerEqual(const void *ptr1, const void *ptr2) {
  19. return ptr1 == ptr2;
  20. }
  21. static CFHashCode pointerHash(const void *ptr) {
  22. return (CFHashCode)(ptr);
  23. }
  24. CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity)
  25. {
  26. CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
  27. // weak, pointer keys
  28. kcb.retain = NULL;
  29. kcb.release = NULL;
  30. kcb.equal = pointerEqual;
  31. kcb.hash = pointerHash;
  32. CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
  33. // weak, pointer values
  34. vcb.retain = NULL;
  35. vcb.release = NULL;
  36. vcb.equal = pointerEqual;
  37. return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
  38. }
  39. CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity)
  40. {
  41. CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
  42. // weak, pointer keys
  43. kcb.retain = NULL;
  44. kcb.release = NULL;
  45. kcb.equal = pointerEqual;
  46. kcb.hash = pointerHash;
  47. // strong, object values
  48. CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
  49. return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
  50. }
  51. static bool FBCompareTypeEncoding(const char *objctype, POPValueType type)
  52. {
  53. switch (type)
  54. {
  55. case kPOPValueFloat:
  56. return (strcmp(objctype, @encode(float)) == 0
  57. || strcmp(objctype, @encode(double)) == 0
  58. );
  59. case kPOPValuePoint:
  60. return (strcmp(objctype, @encode(CGPoint)) == 0
  61. #if !TARGET_OS_IPHONE
  62. || strcmp(objctype, @encode(NSPoint)) == 0
  63. #endif
  64. );
  65. case kPOPValueSize:
  66. return (strcmp(objctype, @encode(CGSize)) == 0
  67. #if !TARGET_OS_IPHONE
  68. || strcmp(objctype, @encode(NSSize)) == 0
  69. #endif
  70. );
  71. case kPOPValueRect:
  72. return (strcmp(objctype, @encode(CGRect)) == 0
  73. #if !TARGET_OS_IPHONE
  74. || strcmp(objctype, @encode(NSRect)) == 0
  75. #endif
  76. );
  77. case kPOPValueEdgeInsets:
  78. #if TARGET_OS_IPHONE
  79. return strcmp(objctype, @encode(UIEdgeInsets)) == 0;
  80. #else
  81. return false;
  82. #endif
  83. case kPOPValueAffineTransform:
  84. return strcmp(objctype, @encode(CGAffineTransform)) == 0;
  85. case kPOPValueTransform:
  86. return strcmp(objctype, @encode(CATransform3D)) == 0;
  87. case kPOPValueRange:
  88. return strcmp(objctype, @encode(CFRange)) == 0
  89. || strcmp(objctype, @encode (NSRange)) == 0;
  90. case kPOPValueInteger:
  91. return (strcmp(objctype, @encode(int)) == 0
  92. || strcmp(objctype, @encode(unsigned int)) == 0
  93. || strcmp(objctype, @encode(short)) == 0
  94. || strcmp(objctype, @encode(unsigned short)) == 0
  95. || strcmp(objctype, @encode(long)) == 0
  96. || strcmp(objctype, @encode(unsigned long)) == 0
  97. || strcmp(objctype, @encode(long long)) == 0
  98. || strcmp(objctype, @encode(unsigned long long)) == 0
  99. );
  100. case kPOPValueSCNVector3:
  101. #if SCENEKIT_SDK_AVAILABLE
  102. return strcmp(objctype, @encode(SCNVector3)) == 0;
  103. #else
  104. return false;
  105. #endif
  106. case kPOPValueSCNVector4:
  107. #if SCENEKIT_SDK_AVAILABLE
  108. return strcmp(objctype, @encode(SCNVector4)) == 0;
  109. #else
  110. return false;
  111. #endif
  112. default:
  113. return false;
  114. }
  115. }
  116. POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length)
  117. {
  118. if (NULL != objctype) {
  119. for (size_t idx = 0; idx < length; idx++) {
  120. if (FBCompareTypeEncoding(objctype, types[idx]))
  121. return types[idx];
  122. }
  123. }
  124. return kPOPValueUnknown;
  125. }
  126. POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length)
  127. {
  128. if ([obj isKindOfClass:[NSValue class]]) {
  129. return POPSelectValueType([obj objCType], types, length);
  130. } else if (NULL != POPCGColorWithColor(obj)) {
  131. return kPOPValueColor;
  132. }
  133. return kPOPValueUnknown;
  134. }
  135. const POPValueType kPOPAnimatableAllTypes[12] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueAffineTransform, kPOPValueTransform, kPOPValueRange, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4};
  136. const POPValueType kPOPAnimatableSupportTypes[10] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4};
  137. NSString *POPValueTypeToString(POPValueType t)
  138. {
  139. switch (t) {
  140. case kPOPValueUnknown:
  141. return @"unknown";
  142. case kPOPValueInteger:
  143. return @"int";
  144. case kPOPValueFloat:
  145. return @"CGFloat";
  146. case kPOPValuePoint:
  147. return @"CGPoint";
  148. case kPOPValueSize:
  149. return @"CGSize";
  150. case kPOPValueRect:
  151. return @"CGRect";
  152. case kPOPValueEdgeInsets:
  153. return @"UIEdgeInsets";
  154. case kPOPValueAffineTransform:
  155. return @"CGAffineTransform";
  156. case kPOPValueTransform:
  157. return @"CATransform3D";
  158. case kPOPValueRange:
  159. return @"CFRange";
  160. case kPOPValueColor:
  161. return @"CGColorRef";
  162. case kPOPValueSCNVector3:
  163. return @"SCNVector3";
  164. case kPOPValueSCNVector4:
  165. return @"SCNVector4";
  166. default:
  167. return nil;
  168. }
  169. }
  170. id POPBox(VectorConstRef vec, POPValueType type, bool force)
  171. {
  172. if (NULL == vec)
  173. return nil;
  174. switch (type) {
  175. case kPOPValueInteger:
  176. case kPOPValueFloat:
  177. return @(vec->data()[0]);
  178. break;
  179. case kPOPValuePoint:
  180. return [NSValue valueWithCGPoint:vec->cg_point()];
  181. break;
  182. case kPOPValueSize:
  183. return [NSValue valueWithCGSize:vec->cg_size()];
  184. break;
  185. case kPOPValueRect:
  186. return [NSValue valueWithCGRect:vec->cg_rect()];
  187. break;
  188. #if TARGET_OS_IPHONE
  189. case kPOPValueEdgeInsets:
  190. return [NSValue valueWithUIEdgeInsets:vec->ui_edge_insets()];
  191. break;
  192. #endif
  193. case kPOPValueColor: {
  194. return (__bridge_transfer id)vec->cg_color();
  195. break;
  196. }
  197. #if SCENEKIT_SDK_AVAILABLE
  198. case kPOPValueSCNVector3: {
  199. return [NSValue valueWithSCNVector3:vec->scn_vector3()];
  200. break;
  201. }
  202. case kPOPValueSCNVector4: {
  203. return [NSValue valueWithSCNVector4:vec->scn_vector4()];
  204. break;
  205. }
  206. #endif
  207. default:
  208. return force ? [NSValue valueWithCGPoint:vec->cg_point()] : nil;
  209. break;
  210. }
  211. }
  212. static VectorRef vectorize(id value, POPValueType type)
  213. {
  214. Vector *vec = NULL;
  215. switch (type) {
  216. case kPOPValueInteger:
  217. case kPOPValueFloat:
  218. #if CGFLOAT_IS_DOUBLE
  219. vec = Vector::new_cg_float([value doubleValue]);
  220. #else
  221. vec = Vector::new_cg_float([value floatValue]);
  222. #endif
  223. break;
  224. case kPOPValuePoint:
  225. vec = Vector::new_cg_point([value CGPointValue]);
  226. break;
  227. case kPOPValueSize:
  228. vec = Vector::new_cg_size([value CGSizeValue]);
  229. break;
  230. case kPOPValueRect:
  231. vec = Vector::new_cg_rect([value CGRectValue]);
  232. break;
  233. #if TARGET_OS_IPHONE
  234. case kPOPValueEdgeInsets:
  235. vec = Vector::new_ui_edge_insets([value UIEdgeInsetsValue]);
  236. break;
  237. #endif
  238. case kPOPValueAffineTransform:
  239. vec = Vector::new_cg_affine_transform([value CGAffineTransformValue]);
  240. break;
  241. case kPOPValueColor:
  242. vec = Vector::new_cg_color(POPCGColorWithColor(value));
  243. break;
  244. #if SCENEKIT_SDK_AVAILABLE
  245. case kPOPValueSCNVector3:
  246. vec = Vector::new_scn_vector3([value SCNVector3Value]);
  247. break;
  248. case kPOPValueSCNVector4:
  249. vec = Vector::new_scn_vector4([value SCNVector4Value]);
  250. break;
  251. #endif
  252. default:
  253. break;
  254. }
  255. return VectorRef(vec);
  256. }
  257. VectorRef POPUnbox(id value, POPValueType &animationType, NSUInteger &count, bool validate)
  258. {
  259. if (nil == value) {
  260. count = 0;
  261. return VectorRef(NULL);
  262. }
  263. // determine type of value
  264. POPValueType valueType = POPSelectValueType(value, kPOPAnimatableSupportTypes, POP_ARRAY_COUNT(kPOPAnimatableSupportTypes));
  265. // handle unknown types
  266. if (kPOPValueUnknown == valueType) {
  267. NSString *valueDesc = [[value class] description];
  268. [NSException raise:@"Unsuported value" format:@"Animating %@ values is not supported", valueDesc];
  269. }
  270. // vectorize
  271. VectorRef vec = vectorize(value, valueType);
  272. if (kPOPValueUnknown == animationType || 0 == count) {
  273. // update animation type based on value type
  274. animationType = valueType;
  275. if (NULL != vec) {
  276. count = vec->size();
  277. }
  278. } else if (validate) {
  279. // allow for mismatched types, so long as vector size matches
  280. if (count != vec->size()) {
  281. [NSException raise:@"Invalid value" format:@"%@ should be of type %@", value, POPValueTypeToString(animationType)];
  282. }
  283. }
  284. return vec;
  285. }