| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /**
- Copyright (c) 2014-present, Facebook, Inc.
- All rights reserved.
-
- This source code is licensed under the BSD-style license found in the
- LICENSE file in the root directory of this source tree. An additional grant
- of patent rights can be found in the PATENTS file in the same directory.
- */
- #import "POPAnimationRuntime.h"
- #import <objc/objc.h>
- #import <QuartzCore/QuartzCore.h>
- #if TARGET_OS_IPHONE
- #import <UIKit/UIKit.h>
- #endif
- #import "POPCGUtils.h"
- #import "POPDefines.h"
- #import "POPGeometry.h"
- #import "POPVector.h"
- static Boolean pointerEqual(const void *ptr1, const void *ptr2) {
- return ptr1 == ptr2;
- }
- static CFHashCode pointerHash(const void *ptr) {
- return (CFHashCode)(ptr);
- }
- CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity)
- {
- CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
- // weak, pointer keys
- kcb.retain = NULL;
- kcb.release = NULL;
- kcb.equal = pointerEqual;
- kcb.hash = pointerHash;
- CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
- // weak, pointer values
- vcb.retain = NULL;
- vcb.release = NULL;
- vcb.equal = pointerEqual;
- return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
- }
- CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity)
- {
- CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
- // weak, pointer keys
- kcb.retain = NULL;
- kcb.release = NULL;
- kcb.equal = pointerEqual;
- kcb.hash = pointerHash;
- // strong, object values
- CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
- return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
- }
- static bool FBCompareTypeEncoding(const char *objctype, POPValueType type)
- {
- switch (type)
- {
- case kPOPValueFloat:
- return (strcmp(objctype, @encode(float)) == 0
- || strcmp(objctype, @encode(double)) == 0
- );
- case kPOPValuePoint:
- return (strcmp(objctype, @encode(CGPoint)) == 0
- #if !TARGET_OS_IPHONE
- || strcmp(objctype, @encode(NSPoint)) == 0
- #endif
- );
- case kPOPValueSize:
- return (strcmp(objctype, @encode(CGSize)) == 0
- #if !TARGET_OS_IPHONE
- || strcmp(objctype, @encode(NSSize)) == 0
- #endif
- );
- case kPOPValueRect:
- return (strcmp(objctype, @encode(CGRect)) == 0
- #if !TARGET_OS_IPHONE
- || strcmp(objctype, @encode(NSRect)) == 0
- #endif
- );
- case kPOPValueEdgeInsets:
- #if TARGET_OS_IPHONE
- return strcmp(objctype, @encode(UIEdgeInsets)) == 0;
- #else
- return false;
- #endif
-
- case kPOPValueAffineTransform:
- return strcmp(objctype, @encode(CGAffineTransform)) == 0;
- case kPOPValueTransform:
- return strcmp(objctype, @encode(CATransform3D)) == 0;
- case kPOPValueRange:
- return strcmp(objctype, @encode(CFRange)) == 0
- || strcmp(objctype, @encode (NSRange)) == 0;
- case kPOPValueInteger:
- return (strcmp(objctype, @encode(int)) == 0
- || strcmp(objctype, @encode(unsigned int)) == 0
- || strcmp(objctype, @encode(short)) == 0
- || strcmp(objctype, @encode(unsigned short)) == 0
- || strcmp(objctype, @encode(long)) == 0
- || strcmp(objctype, @encode(unsigned long)) == 0
- || strcmp(objctype, @encode(long long)) == 0
- || strcmp(objctype, @encode(unsigned long long)) == 0
- );
-
- case kPOPValueSCNVector3:
- #if SCENEKIT_SDK_AVAILABLE
- return strcmp(objctype, @encode(SCNVector3)) == 0;
- #else
- return false;
- #endif
-
- case kPOPValueSCNVector4:
- #if SCENEKIT_SDK_AVAILABLE
- return strcmp(objctype, @encode(SCNVector4)) == 0;
- #else
- return false;
- #endif
-
- default:
- return false;
- }
- }
- POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length)
- {
- if (NULL != objctype) {
- for (size_t idx = 0; idx < length; idx++) {
- if (FBCompareTypeEncoding(objctype, types[idx]))
- return types[idx];
- }
- }
- return kPOPValueUnknown;
- }
- POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length)
- {
- if ([obj isKindOfClass:[NSValue class]]) {
- return POPSelectValueType([obj objCType], types, length);
- } else if (NULL != POPCGColorWithColor(obj)) {
- return kPOPValueColor;
- }
- return kPOPValueUnknown;
- }
- const POPValueType kPOPAnimatableAllTypes[12] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueAffineTransform, kPOPValueTransform, kPOPValueRange, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4};
- const POPValueType kPOPAnimatableSupportTypes[10] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4};
- NSString *POPValueTypeToString(POPValueType t)
- {
- switch (t) {
- case kPOPValueUnknown:
- return @"unknown";
- case kPOPValueInteger:
- return @"int";
- case kPOPValueFloat:
- return @"CGFloat";
- case kPOPValuePoint:
- return @"CGPoint";
- case kPOPValueSize:
- return @"CGSize";
- case kPOPValueRect:
- return @"CGRect";
- case kPOPValueEdgeInsets:
- return @"UIEdgeInsets";
- case kPOPValueAffineTransform:
- return @"CGAffineTransform";
- case kPOPValueTransform:
- return @"CATransform3D";
- case kPOPValueRange:
- return @"CFRange";
- case kPOPValueColor:
- return @"CGColorRef";
- case kPOPValueSCNVector3:
- return @"SCNVector3";
- case kPOPValueSCNVector4:
- return @"SCNVector4";
- default:
- return nil;
- }
- }
- id POPBox(VectorConstRef vec, POPValueType type, bool force)
- {
- if (NULL == vec)
- return nil;
-
- switch (type) {
- case kPOPValueInteger:
- case kPOPValueFloat:
- return @(vec->data()[0]);
- break;
- case kPOPValuePoint:
- return [NSValue valueWithCGPoint:vec->cg_point()];
- break;
- case kPOPValueSize:
- return [NSValue valueWithCGSize:vec->cg_size()];
- break;
- case kPOPValueRect:
- return [NSValue valueWithCGRect:vec->cg_rect()];
- break;
- #if TARGET_OS_IPHONE
- case kPOPValueEdgeInsets:
- return [NSValue valueWithUIEdgeInsets:vec->ui_edge_insets()];
- break;
- #endif
- case kPOPValueColor: {
- return (__bridge_transfer id)vec->cg_color();
- break;
- }
- #if SCENEKIT_SDK_AVAILABLE
- case kPOPValueSCNVector3: {
- return [NSValue valueWithSCNVector3:vec->scn_vector3()];
- break;
- }
- case kPOPValueSCNVector4: {
- return [NSValue valueWithSCNVector4:vec->scn_vector4()];
- break;
- }
- #endif
- default:
- return force ? [NSValue valueWithCGPoint:vec->cg_point()] : nil;
- break;
- }
- }
- static VectorRef vectorize(id value, POPValueType type)
- {
- Vector *vec = NULL;
- switch (type) {
- case kPOPValueInteger:
- case kPOPValueFloat:
- #if CGFLOAT_IS_DOUBLE
- vec = Vector::new_cg_float([value doubleValue]);
- #else
- vec = Vector::new_cg_float([value floatValue]);
- #endif
- break;
- case kPOPValuePoint:
- vec = Vector::new_cg_point([value CGPointValue]);
- break;
- case kPOPValueSize:
- vec = Vector::new_cg_size([value CGSizeValue]);
- break;
- case kPOPValueRect:
- vec = Vector::new_cg_rect([value CGRectValue]);
- break;
- #if TARGET_OS_IPHONE
- case kPOPValueEdgeInsets:
- vec = Vector::new_ui_edge_insets([value UIEdgeInsetsValue]);
- break;
- #endif
- case kPOPValueAffineTransform:
- vec = Vector::new_cg_affine_transform([value CGAffineTransformValue]);
- break;
- case kPOPValueColor:
- vec = Vector::new_cg_color(POPCGColorWithColor(value));
- break;
- #if SCENEKIT_SDK_AVAILABLE
- case kPOPValueSCNVector3:
- vec = Vector::new_scn_vector3([value SCNVector3Value]);
- break;
- case kPOPValueSCNVector4:
- vec = Vector::new_scn_vector4([value SCNVector4Value]);
- break;
- #endif
- default:
- break;
- }
-
- return VectorRef(vec);
- }
- VectorRef POPUnbox(id value, POPValueType &animationType, NSUInteger &count, bool validate)
- {
- if (nil == value) {
- count = 0;
- return VectorRef(NULL);
- }
- // determine type of value
- POPValueType valueType = POPSelectValueType(value, kPOPAnimatableSupportTypes, POP_ARRAY_COUNT(kPOPAnimatableSupportTypes));
- // handle unknown types
- if (kPOPValueUnknown == valueType) {
- NSString *valueDesc = [[value class] description];
- [NSException raise:@"Unsuported value" format:@"Animating %@ values is not supported", valueDesc];
- }
- // vectorize
- VectorRef vec = vectorize(value, valueType);
- if (kPOPValueUnknown == animationType || 0 == count) {
- // update animation type based on value type
- animationType = valueType;
- if (NULL != vec) {
- count = vec->size();
- }
- } else if (validate) {
- // allow for mismatched types, so long as vector size matches
- if (count != vec->size()) {
- [NSException raise:@"Invalid value" format:@"%@ should be of type %@", value, POPValueTypeToString(animationType)];
- }
- }
-
- return vec;
- }
|