├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Configuration ├── Compiler.xcconfig ├── Product │ ├── ApplicationTests.xcconfig │ ├── Framework.xcconfig │ ├── LogicTests.xcconfig │ └── StaticLibrary.xcconfig └── Project │ ├── Project-Debug.xcconfig │ ├── Project-Profile.xcconfig │ ├── Project-Release.xcconfig │ └── Project.xcconfig ├── Images ├── EmbeddedBinaries.png ├── pop.gif └── pop.png ├── LICENSE ├── PATENTS ├── Podfile ├── Podfile.lock ├── README.md ├── codecov.yml ├── pop-tests ├── POPAnimatable.h ├── POPAnimatable.mm ├── POPAnimatablePropertyTests.mm ├── POPAnimationMRRTests.mm ├── POPAnimationTests.mm ├── POPAnimationTestsExtras.h ├── POPAnimationTestsExtras.mm ├── POPBaseAnimationTests.h ├── POPBaseAnimationTests.mm ├── POPBasicAnimationTests.mm ├── POPCustomAnimationTests.mm ├── POPDecayAnimationTests.mm ├── POPEaseInEaseOutAnimationTests.mm ├── POPSpringAnimationTests.mm ├── pop-tests-ios-Info.plist ├── pop-tests-osx-Info.plist └── pop-tests-tvos-Info.plist ├── pop.podspec ├── pop.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── pop-ios-framework.xcscheme │ ├── pop-ios-static.xcscheme │ ├── pop-osx-framework.xcscheme │ └── pop-tvos-framework.xcscheme ├── pop.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist └── pop ├── POP.h ├── POPAction.h ├── POPAnimatableProperty.h ├── POPAnimatableProperty.mm ├── POPAnimatablePropertyTypes.h ├── POPAnimation.h ├── POPAnimation.mm ├── POPAnimationEvent.h ├── POPAnimationEvent.mm ├── POPAnimationEventInternal.h ├── POPAnimationExtras.h ├── POPAnimationExtras.mm ├── POPAnimationInternal.h ├── POPAnimationPrivate.h ├── POPAnimationRuntime.h ├── POPAnimationRuntime.mm ├── POPAnimationTracer.h ├── POPAnimationTracer.mm ├── POPAnimationTracerInternal.h ├── POPAnimator.h ├── POPAnimator.mm ├── POPAnimatorPrivate.h ├── POPBasicAnimation.h ├── POPBasicAnimation.mm ├── POPBasicAnimationInternal.h ├── POPCGUtils.h ├── POPCGUtils.mm ├── POPCustomAnimation.h ├── POPCustomAnimation.mm ├── POPDecayAnimation.h ├── POPDecayAnimation.mm ├── POPDecayAnimationInternal.h ├── POPDefines.h ├── POPGeometry.h ├── POPGeometry.mm ├── POPLayerExtras.h ├── POPLayerExtras.mm ├── POPMath.h ├── POPMath.mm ├── POPPropertyAnimation.h ├── POPPropertyAnimation.mm ├── POPPropertyAnimationInternal.h ├── POPSpringAnimation.h ├── POPSpringAnimation.mm ├── POPSpringAnimationInternal.h ├── POPSpringSolver.h ├── POPVector.h ├── POPVector.mm ├── WebCore ├── FloatConversion.h ├── TransformationMatrix.cpp ├── TransformationMatrix.h └── UnitBezier.h ├── module.modulemap ├── pop-ios-Info.plist ├── pop-osx-Info.plist └── pop-tvos-Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | *.pbxuser 4 | *.perspective 5 | *.perspectivev3 6 | 7 | *.mode1v3 8 | *.mode2v3 9 | 10 | *.xcodeproj/xcuserdata/*.xcuserdatad 11 | 12 | *.xccheckout 13 | *.xcuserdatad 14 | 15 | Pods 16 | 17 | DerivedData 18 | build 19 | 20 | .ruby-version -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | only: 3 | - master 4 | language: objective-c 5 | os: osx 6 | osx_image: xcode9.2 7 | env: 8 | matrix: 9 | - TEST_TYPE=iOS 10 | - TEST_TYPE=OSX 11 | - TEST_TYPE=tvOS 12 | - TEST_TYPE=CocoaPods 13 | install: 14 | - | 15 | if [ "$TEST_TYPE" = iOS ] || [ "$TEST_TYPE" = OSX ] || [ "$TEST_TYPE" = tvOS ]; then 16 | gem install xcpretty -N --no-ri --no-rdoc 17 | gem install cocoapods --quiet --no-ri --no-rdoc 18 | pod install 19 | fi 20 | script: 21 | - | 22 | if [ "$TEST_TYPE" = iOS ]; then 23 | set -o pipefail 24 | xcodebuild -workspace pop.xcworkspace -scheme pop-ios-framework -sdk iphonesimulator build test -destination "platform=iOS Simulator,name=iPhone SE" GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 25 | elif [ "$TEST_TYPE" = OSX ]; then 26 | set -o pipefail 27 | xcodebuild -workspace pop.xcworkspace -scheme pop-osx-framework -sdk macosx build test GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 28 | elif [ "$TEST_TYPE" = tvOS ]; then 29 | set -o pipefail 30 | xcodebuild -workspace pop.xcworkspace -scheme pop-tvos-framework -sdk appletvsimulator build test -destination "platform=tvOS Simulator,name=Apple TV" GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcpretty -c 31 | elif [ "$TEST_TYPE" = CocoaPods ]; then 32 | pod lib lint pop.podspec 33 | pod lib lint --use-libraries pop.podspec 34 | fi 35 | after_success: 36 | - | 37 | if [ "$TEST_TYPE" = iOS ] || [ "$TEST_TYPE" = OSX ] || [ "$TEST_TYPE" = tvOS ]; then 38 | bash <(curl -s https://codecov.io/bash) 39 | fi 40 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | We want to make contributing to Pop as easy and transparent as 3 | possible. If you run into problems, please open an issue. We also actively welcome pull requests. 4 | 5 | ## Pull Requests 6 | 1. Fork the repo and create your branch from `master`. 7 | 2. If you've added code that should be tested, add tests 8 | 3. If you've changed APIs, update the documentation. 9 | 4. Ensure the test suite passes. 10 | 5. Make sure your code lints. 11 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 12 | 13 | ## Contributor License Agreement ("CLA") 14 | In order to accept your pull request, we need you to submit a CLA. You only need 15 | to do this once to work on any of Facebook's open source projects. 16 | 17 | Complete your CLA here: 18 | 19 | ## Issues 20 | We use GitHub issues to track public bugs. Please ensure your description is 21 | clear and has sufficient instructions to be able to reproduce the issue. 22 | 23 | ## Coding Style 24 | * 2 spaces for indentation rather than tabs 25 | 26 | ## License 27 | By contributing to Pop you agree that your contributions will be licensed 28 | under its BSD license. 29 | -------------------------------------------------------------------------------- /Configuration/Compiler.xcconfig: -------------------------------------------------------------------------------- 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 | // Deployment targets 11 | MACOSX_DEPLOYMENT_TARGET = 10.7 12 | IPHONEOS_DEPLOYMENT_TARGET = 8.0 13 | TVOS_DEPLOYMENT_TARGET = 9.0 14 | 15 | // Warnings 16 | GCC_TREAT_WARNINGS_AS_ERRORS = YES 17 | CLANG_WARN_CONSTANT_CONVERSION = YES 18 | CLANG_WARN_ENUM_CONVERSION = YES 19 | CLANG_WARN_INT_CONVERSION = YES 20 | CLANG_WARN_INFINITE_RECURSION = YES 21 | CLANG_WARN_SUSPICIOUS_MOVE = YES 22 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 23 | CLANG_WARN_BOOL_CONVERSION = YES 24 | CLANG_WARN_EMPTY_BODY = YES 25 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES 26 | CLANG_WARN_CXX0X_EXTENSIONS = NO 27 | CLANG_WARN_UNREACHABLE_CODE = YES 28 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES 29 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 30 | CLANG_WARN_STRICT_PROTOTYPES = YES 31 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO 32 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES 33 | GCC_WARN_ABOUT_RETURN_TYPE = YES 34 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES 35 | GCC_WARN_MISSING_PARENTHESES = YES 36 | GCC_WARN_SHADOW = YES 37 | GCC_WARN_SIGN_COMPARE = YES 38 | GCC_WARN_UNINITIALIZED_AUTOS = YES 39 | GCC_WARN_UNDECLARED_SELECTOR = YES 40 | GCC_WARN_UNUSED_FUNCTION = YES 41 | GCC_WARN_UNUSED_VARIABLE = YES 42 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 43 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES 44 | CLANG_WARN_COMMA = YES 45 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES 46 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES 47 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES 48 | WARNING_CFLAGS = -Wall -Wextra -Wno-unused-parameter 49 | 50 | // Language 51 | GCC_C_LANGUAGE_STANDARD = gnu99 52 | CLANG_CXX_LANGUAGE_STANDARD = c++11 53 | CLANG_CXX_LIBRARY = libc++ 54 | 55 | // Application Extension 56 | APPLICATION_EXTENSION_API_ONLY = YES 57 | 58 | // Preprocessing 59 | ENABLE_STRICT_OBJC_MSGSEND = YES 60 | 61 | // Enable ARC 62 | CLANG_ENABLE_OBJC_ARC = YES 63 | 64 | // Modules 65 | CLANG_ENABLE_MODULES=YES 66 | 67 | // Search Paths 68 | ALWAYS_SEARCH_USER_PATHS = NO 69 | FRAMEWORK_SEARCH_PATHS = $(inherited) $(BUILT_PRODUCTS_DIR) 70 | LIBRARY_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR) $(inherited) 71 | HEADER_SEARCH_PATHS = $(inherited) $(SYMROOT)/Headers $(DERIVED_FILE_DIR) 72 | 73 | // Code Generation 74 | GCC_DYNAMIC_NO_PIC = NO 75 | GCC_NO_COMMON_BLOCKS = YES 76 | GCC_INLINES_ARE_PRIVATE_EXTERN = YES 77 | GCC_SYMBOLS_PRIVATE_EXTERN = NO 78 | -------------------------------------------------------------------------------- /Configuration/Product/ApplicationTests.xcconfig: -------------------------------------------------------------------------------- 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 | #include "LogicTests.xcconfig" 11 | 12 | // Linking 13 | BUNDLE_LOADER = $(BUILT_PRODUCTS_DIR)/$(PROJECT_NAME)TestHost.app/$(PROJECT_NAME)TestHost 14 | 15 | // Unit Testing 16 | TEST_HOST = "$(BUNDLE_LOADER)" 17 | -------------------------------------------------------------------------------- /Configuration/Product/Framework.xcconfig: -------------------------------------------------------------------------------- 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 | #include "../Compiler.xcconfig" 11 | 12 | // Version 13 | DYLIB_COMPATIBILITY_VERSION = 1 14 | DYLIB_CURRENT_VERSION = 1 15 | CURRENT_PROJECT_VERSION = 1 16 | -------------------------------------------------------------------------------- /Configuration/Product/LogicTests.xcconfig: -------------------------------------------------------------------------------- 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 | #include "../Compiler.xcconfig" 11 | 12 | // Deployment 13 | DSTROOT = /tmp/$(TARGET_NAME) 14 | SKIP_INSTALL = YES 15 | -------------------------------------------------------------------------------- /Configuration/Product/StaticLibrary.xcconfig: -------------------------------------------------------------------------------- 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 | #include "../Compiler.xcconfig" 11 | 12 | // Deployment 13 | DSTROOT = /tmp/$(TARGET_NAME) 14 | INSTALL_PATH = $(SYMROOT)/Headers 15 | SKIP_INSTALL = YES 16 | 17 | // declare inlines as extern 18 | GCC_INLINES_ARE_PRIVATE_EXTERN = YES 19 | 20 | // Use PRODUCT_NAME instead of TARGET_NAME to support multiple targets for different platforms 21 | PUBLIC_HEADERS_FOLDER_PATH = include/$(PRODUCT_NAME) 22 | -------------------------------------------------------------------------------- /Configuration/Project/Project-Debug.xcconfig: -------------------------------------------------------------------------------- 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 | #include "Project.xcconfig" 11 | 12 | // Architectures 13 | ONLY_ACTIVE_ARCH = YES 14 | 15 | // Code Generation 16 | GCC_OPTIMIZATION_LEVEL = 0 17 | 18 | // Enable assertions 19 | ENABLE_NS_ASSERTIONS = YES 20 | 21 | // Avoid compression overhead 22 | COMPRESS_PNG_FILES = NO 23 | 24 | // Deployment 25 | COPY_PHASE_STRIP = NO 26 | 27 | // Default to dwarf 28 | DEBUG_INFORMATION_FORMAT = dwarf 29 | 30 | // Testing 31 | ENABLE_TESTABILITY = YES 32 | -------------------------------------------------------------------------------- /Configuration/Project/Project-Profile.xcconfig: -------------------------------------------------------------------------------- 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 | #include "Project.xcconfig" 11 | 12 | // Code Generation 13 | GCC_OPTIMIZATION_LEVEL = s 14 | 15 | // Disable assertions 16 | ENABLE_NS_ASSERTIONS = NO 17 | 18 | // Enable Xcode PNG compression 19 | COMPRESS_PNG_FILES = YES 20 | 21 | // Deployment 22 | COPY_PHASE_STRIP = NO 23 | 24 | // Preprocessing 25 | GCC_PREPROCESSOR_DEFINITIONS = PROFILE=1 NS_BLOCK_ASSERTIONS NDEBUG 26 | 27 | // We need debug symbols for profiling 28 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 29 | 30 | // Not all libraries have a Profile version. Allow using the Release version if they don't. 31 | LIBRARY_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR) $(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME) 32 | -------------------------------------------------------------------------------- /Configuration/Project/Project-Release.xcconfig: -------------------------------------------------------------------------------- 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 | #include "Project.xcconfig" 11 | 12 | // Code Generation 13 | GCC_OPTIMIZATION_LEVEL = s 14 | 15 | // Disable assertions 16 | ENABLE_NS_ASSERTIONS = NO 17 | 18 | // Enable Xcode PNG compression 19 | COMPRESS_PNG_FILES = YES 20 | 21 | // Build Options 22 | VALIDATE_PRODUCT = YES 23 | 24 | // Preprocessing 25 | GCC_PREPROCESSOR_DEFINITIONS = PROFILE=1 NS_BLOCK_ASSERTIONS NDEBUG 26 | -------------------------------------------------------------------------------- /Configuration/Project/Project.xcconfig: -------------------------------------------------------------------------------- 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 | #include "../Compiler.xcconfig" 11 | 12 | // Install 13 | SKIP_INSTALL = YES 14 | 15 | // Code Signing 16 | CODE_SIGN_IDENTITY = 17 | -------------------------------------------------------------------------------- /Images/EmbeddedBinaries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebookarchive/pop/87d1f8b74cdaa4699d7a9f6be1ff5202014c581f/Images/EmbeddedBinaries.png -------------------------------------------------------------------------------- /Images/pop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebookarchive/pop/87d1f8b74cdaa4699d7a9f6be1ff5202014c581f/Images/pop.gif -------------------------------------------------------------------------------- /Images/pop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebookarchive/pop/87d1f8b74cdaa4699d7a9f6be1ff5202014c581f/Images/pop.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For Pop software 4 | 5 | Copyright (c) 2014, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the Pop software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook’s rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. 34 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | abstract_target 'Tests' do 2 | pod 'OCMock', '~> 2.2' 3 | 4 | target :'pop-tests-ios' do 5 | platform :ios, '6.0' 6 | end 7 | 8 | target :'pop-tests-tvos' do 9 | platform :tvos, '9.0' 10 | end 11 | 12 | target :'pop-tests-osx' do 13 | platform :osx, '10.8' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - OCMock (2.2.4) 3 | 4 | DEPENDENCIES: 5 | - OCMock (~> 2.2) 6 | 7 | SPEC CHECKSUMS: 8 | OCMock: a6a7dc0e3997fb9f35d99f72528698ebf60d64f2 9 | 10 | PODFILE CHECKSUM: 06e2f62938dff5782de5abf2adf6966a85f24637 11 | 12 | COCOAPODS: 1.2.1 13 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - pop-tests/* 4 | status: 5 | patch: false 6 | changes: false 7 | project: 8 | default: 9 | target: 50 10 | comment: false 11 | -------------------------------------------------------------------------------- /pop-tests/POPAnimatable.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | #import 15 | 16 | @interface POPAnimatable : NSObject 17 | 18 | @property (nonatomic, assign) float radius; 19 | 20 | @property (nonatomic, assign) CGPoint position; 21 | 22 | - (NSArray *)recordedValuesForKey:(NSString *)key; 23 | 24 | - (void)startRecording; 25 | 26 | - (void)stopRecording; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /pop-tests/POPAnimatable.mm: -------------------------------------------------------------------------------- 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 | #import "POPAnimatable.h" 11 | 12 | #import 13 | 14 | @implementation POPAnimatable 15 | { 16 | BOOL _recording; 17 | NSMutableDictionary *_recordedValuesDict; 18 | } 19 | @synthesize radius = _radius; 20 | @synthesize position = _position; 21 | 22 | static void record_value(POPAnimatable *self, NSString *key, id value) 23 | { 24 | if (!self->_recordedValuesDict) { 25 | self->_recordedValuesDict = [NSMutableDictionary new]; 26 | } 27 | NSMutableArray *values = self->_recordedValuesDict[key]; 28 | if (!values) { 29 | values = [NSMutableArray array]; 30 | self->_recordedValuesDict[key] = values; 31 | } 32 | [values addObject:value]; 33 | } 34 | 35 | static void record_value(POPAnimatable *self, NSString *key, float f) 36 | { 37 | record_value(self, key, @(f)); 38 | } 39 | 40 | static void record_value(POPAnimatable *self, NSString *key, CGPoint p) 41 | { 42 | record_value(self, key, [NSValue valueWithCGPoint:p]); 43 | } 44 | 45 | - (void)setRadius:(float)radius 46 | { 47 | _radius = radius; 48 | if (_recording) { 49 | record_value(self, @"radius", radius); 50 | } 51 | } 52 | 53 | - (void)setPosition:(CGPoint)position 54 | { 55 | _position = position; 56 | if (_recording) { 57 | record_value(self, @"position", position); 58 | } 59 | } 60 | 61 | - (NSArray *)recordedValuesForKey:(NSString *)key 62 | { 63 | return _recordedValuesDict[key]; 64 | } 65 | 66 | - (void)startRecording 67 | { 68 | _recording = YES; 69 | } 70 | 71 | - (void)stopRecording 72 | { 73 | _recording = NO; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /pop-tests/POPAnimatablePropertyTests.mm: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | static const CGFloat epsilon = 0.0001f; 15 | static NSArray *properties = @[@"name", @"readBlock", @"writeBlock", @"threshold"]; 16 | 17 | static void assertPropertyEqual(id self, POPAnimatableProperty *prop1, POPAnimatableProperty *prop2) 18 | { 19 | for (NSString *property in properties) { 20 | id value = [prop1 valueForKey:property]; 21 | id valueCopy = [prop2 valueForKey:property]; 22 | XCTAssertEqualObjects(value, valueCopy, @"unexpected inequality; value:%@ copy:%@", value, valueCopy); 23 | } 24 | } 25 | 26 | @interface POPAnimatablePropertyTests : XCTestCase 27 | @end 28 | 29 | @implementation POPAnimatablePropertyTests 30 | 31 | - (void)testProvidedExistence 32 | { 33 | NSArray *names = @[kPOPLayerPosition, 34 | kPOPLayerOpacity, 35 | kPOPLayerScaleXY, 36 | kPOPLayerSubscaleXY, 37 | kPOPLayerSubtranslationX, 38 | kPOPLayerSubtranslationY, 39 | kPOPLayerSubtranslationZ, 40 | kPOPLayerSubtranslationXY, 41 | kPOPLayerZPosition, 42 | kPOPLayerSize, 43 | kPOPLayerRotation, 44 | kPOPLayerRotationY, 45 | kPOPLayerRotationX, 46 | kPOPLayerShadowColor, 47 | kPOPLayerShadowOffset, 48 | kPOPLayerShadowOpacity, 49 | kPOPLayerShadowRadius, 50 | kPOPLayerCornerRadius, 51 | kPOPLayerBorderWidth, 52 | kPOPLayerBorderColor, 53 | kPOPShapeLayerStrokeStart, 54 | kPOPShapeLayerStrokeEnd, 55 | kPOPShapeLayerStrokeColor, 56 | kPOPShapeLayerLineWidth, 57 | kPOPShapeLayerLineDashPhase, 58 | #if TARGET_OS_IPHONE 59 | kPOPViewAlpha, 60 | kPOPViewBackgroundColor, 61 | kPOPViewCenter, 62 | kPOPViewFrame, 63 | kPOPViewBounds, 64 | kPOPViewSize, 65 | kPOPViewTintColor, 66 | kPOPScrollViewZoomScale, 67 | kPOPTableViewContentSize, 68 | kPOPTableViewContentOffset, 69 | kPOPCollectionViewContentSize, 70 | kPOPCollectionViewContentSize, 71 | kPOPLabelTextColor 72 | #else 73 | kPOPViewFrame, 74 | kPOPViewBounds, 75 | kPOPViewAlphaValue, 76 | kPOPViewFrameRotation, 77 | kPOPViewFrameCenterRotation, 78 | kPOPViewBoundsRotation, 79 | kPOPWindowFrame, 80 | kPOPWindowAlphaValue, 81 | kPOPWindowBackgroundColor 82 | #endif 83 | ]; 84 | 85 | for (NSString *name in names) { 86 | POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:name]; 87 | XCTAssertNotNil(prop, @"animatable property %@ should exist", name); 88 | } 89 | } 90 | 91 | - (void)testUserCreation 92 | { 93 | static NSString *name = @"lalalala"; 94 | static CGFloat threshold = 0.07; 95 | POPAnimatableProperty *prop; 96 | 97 | prop = [POPAnimatableProperty propertyWithName:name]; 98 | XCTAssertNil(prop, @"animatable property %@ should not exist", name); 99 | 100 | prop = [POPAnimatableProperty propertyWithName:name initializer:^(POPMutableAnimatableProperty *p){ 101 | p.threshold = threshold; 102 | }]; 103 | XCTAssertNotNil(prop, @"animatable property %@ should exist", name); 104 | XCTAssertEqualWithAccuracy(threshold, prop.threshold, epsilon, @"property threshold %f should equal %f", prop.threshold, threshold); 105 | } 106 | 107 | - (void)testClassCluster 108 | { 109 | POPAnimatableProperty *instance1 = [[POPAnimatableProperty alloc] init]; 110 | POPAnimatableProperty *instance2 = [[POPAnimatableProperty alloc] init]; 111 | XCTAssertTrue(instance1 == instance2, @"instance1:%@ instance2:%@", instance1, instance2); 112 | 113 | for (NSString *property in properties) { 114 | XCTAssertNoThrow([instance1 valueForKey:property], @"exception on %@", property); 115 | } 116 | } 117 | 118 | - (void)testCopying 119 | { 120 | // instance 121 | POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:kPOPLayerBounds]; 122 | 123 | // instance copy 124 | POPAnimatableProperty *propCopy = [prop copy]; 125 | 126 | // test equality 127 | assertPropertyEqual(self, prop, propCopy); 128 | } 129 | 130 | - (void)testMutableCopying 131 | { 132 | // instance 133 | POPAnimatableProperty *prop = [POPAnimatableProperty propertyWithName:kPOPLayerBounds]; 134 | 135 | // instance copy 136 | POPAnimatableProperty *propCopy = [prop mutableCopy]; 137 | 138 | // test equality 139 | assertPropertyEqual(self, prop, propCopy); 140 | } 141 | 142 | @end 143 | -------------------------------------------------------------------------------- /pop-tests/POPAnimationMRRTests.mm: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | #import 15 | 16 | #import 17 | #import 18 | 19 | #import "POPAnimationTestsExtras.h" 20 | 21 | @interface POPAnimationMRRTests : XCTestCase 22 | { 23 | POPAnimator *_animator; 24 | CFTimeInterval _beginTime; 25 | } 26 | @end 27 | 28 | @implementation POPAnimationMRRTests 29 | 30 | - (void)setUp 31 | { 32 | [super setUp]; 33 | _animator = [[POPAnimator sharedAnimator] retain]; 34 | _beginTime = CACurrentMediaTime(); 35 | _animator.beginTime = _beginTime; 36 | } 37 | 38 | - (void)tearDown 39 | { 40 | [_animator release]; 41 | _animator = nil; 42 | [super tearDown]; 43 | } 44 | 45 | - (void)testZeroingDelegate 46 | { 47 | POPBasicAnimation *anim = FBTestLinearPositionAnimation(); 48 | 49 | @autoreleasepool { 50 | id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)]; 51 | anim.delegate = delegate; 52 | XCTAssertNotNil(anim.delegate, @"delegate should not be nil"); 53 | } 54 | 55 | XCTAssertNil(anim.delegate, @"delegate should be nil"); 56 | } 57 | 58 | - (void)testAnimationCancellationOnAnimatableDeallocation 59 | { 60 | id layer = nil; 61 | POPBasicAnimation *anim = FBTestLinearPositionAnimation(); 62 | id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)]; 63 | 64 | @autoreleasepool { 65 | layer = [OCMockObject niceMockForClass:[CALayer class]]; 66 | anim.delegate = delegate; 67 | 68 | // expect position start 69 | [[delegate expect] pop_animationDidStart:anim]; 70 | 71 | // run 72 | [layer pop_addAnimation:anim forKey:@""]; 73 | POPAnimatorRenderTimes(_animator, _beginTime, @[@0.0]); 74 | 75 | // verify 76 | [layer verify]; 77 | [delegate verify]; 78 | 79 | // expect stop unfinished 80 | [[delegate expect] pop_animationDidStop:anim finished:NO]; 81 | layer = nil; 82 | } 83 | 84 | // run 85 | POPAnimatorRenderTimes(_animator, _beginTime, @[@0.5]); 86 | 87 | // verify 88 | [delegate verify]; 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /pop-tests/POPAnimationTestsExtras.h: -------------------------------------------------------------------------------- 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 | #import "POPVector.h" 11 | @class POPAnimator; 12 | @class POPBasicAnimation; 13 | 14 | extern void POPAnimatorRenderTime(POPAnimator *animator, CFTimeInterval beginTime, CFTimeInterval time); 15 | extern void POPAnimatorRenderTimes(POPAnimator *animator, CFTimeInterval beginTime, NSArray *times); 16 | extern void POPAnimatorRenderDuration(POPAnimator *animator, CFAbsoluteTime beginTime, CFTimeInterval duration, CFTimeInterval step); 17 | 18 | extern POPBasicAnimation *FBTestLinearPositionAnimation(CFTimeInterval beginTime = 0); 19 | extern POP::Vector2r FBTestInterpolateLinear(POP::Vector2r start, POP::Vector2r end, CGFloat progress); 20 | -------------------------------------------------------------------------------- /pop-tests/POPAnimationTestsExtras.mm: -------------------------------------------------------------------------------- 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 | #import "POPAnimationTestsExtras.h" 11 | 12 | #import 13 | #import 14 | 15 | void POPAnimatorRenderTime(POPAnimator *animator, CFTimeInterval beginTime, CFTimeInterval time) 16 | { 17 | [animator renderTime:beginTime + time]; 18 | } 19 | 20 | void POPAnimatorRenderTimes(POPAnimator *animator, CFTimeInterval beginTime, NSArray *times) 21 | { 22 | for (NSNumber *time in times) { 23 | [animator renderTime:beginTime + time.doubleValue]; 24 | } 25 | } 26 | 27 | void POPAnimatorRenderDuration(POPAnimator *animator, CFTimeInterval beginTime, CFTimeInterval duration, CFTimeInterval step) 28 | { 29 | CFTimeInterval initialTime = animator.beginTime; 30 | animator.beginTime = beginTime; 31 | NSCAssert(step > 0, @"unexpected step %f", step); 32 | CFTimeInterval time = 0; 33 | while(time <= duration) { 34 | [animator renderTime:beginTime + time]; 35 | time += step; 36 | } 37 | animator.beginTime = initialTime; 38 | } 39 | 40 | POPBasicAnimation *FBTestLinearPositionAnimation(CFTimeInterval beginTime) 41 | { 42 | POPBasicAnimation *anim = [POPBasicAnimation linearAnimation]; 43 | anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerPosition]; 44 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)]; 45 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)]; 46 | anim.duration = 1; 47 | anim.beginTime = beginTime; 48 | return anim; 49 | } 50 | 51 | POP::Vector2r FBTestInterpolateLinear(POP::Vector2r start, POP::Vector2r end, CGFloat progress) 52 | { 53 | return start + ((end - start) * progress); 54 | } 55 | -------------------------------------------------------------------------------- /pop-tests/POPBaseAnimationTests.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | #import "POPCGUtils.h" 15 | 16 | @class CALayer; 17 | @class POPAnimator; 18 | @class POPAnimatableProperty; 19 | @class POPAnimation; 20 | @class POPPropertyAnimation; 21 | 22 | @interface POPBaseAnimationTests : XCTestCase 23 | 24 | // two layers for test use 25 | @property (strong, nonatomic) CALayer *layer1, *layer2; 26 | 27 | // the animator to use for rendering 28 | @property (strong, nonatomic) POPAnimator *animator; 29 | 30 | // the time tests began 31 | @property (assign, nonatomic) CFTimeInterval beginTime; 32 | 33 | // radius animatable property 34 | @property (strong, nonatomic) POPAnimatableProperty *radiusProperty; 35 | 36 | - (void)testCopyingSucceedsForConcreteAnimation:(POPAnimation *)anim; 37 | - (void)testCopyingSucceedsForConcretePropertyAnimation:(POPPropertyAnimation *)anim; 38 | 39 | @end 40 | 41 | // max frame count required for animations to converge 42 | extern NSUInteger kPOPAnimationConvergenceMaxFrameCount; 43 | 44 | // counts the number of events of value within epsilon, starting from end 45 | extern NSUInteger POPAnimationCountLastEventValues(NSArray *events, NSNumber *value, float epsilon = 0); 46 | 47 | // returns YES if array of value events contain specified value 48 | extern BOOL POPAnimationEventsContainValue(NSArray *events, NSNumber *value); 49 | 50 | // equality with epsilon 51 | #define _EQL_(x, y, epsilon) (std::abs ((x) - (y)) < epsilon) 52 | 53 | // color equality assert 54 | #define POPAssertColorEqual(c1, c2) \ 55 | { \ 56 | CGFloat v1[4], v2[4]; \ 57 | POPCGColorGetRGBAComponents(c1, v1); \ 58 | POPCGColorGetRGBAComponents(c2, v2); \ 59 | XCTAssertTrue(_EQL_(v1[0], v2[0], 1e-6) && _EQL_(v1[1], v2[1], 1e-6) && _EQL_(v1[2], v2[2], 1e-6) && _EQL_(v1[3], v2[3], 1e-6), @"not equal color:[r:%f g:%f b:%f a:%f] color:[r:%f g:%f b:%f a:%f]", v1[0], v1[1], v1[2], v1[3], v2[0], v2[1], v2[2], v2[3]); \ 60 | } 61 | 62 | extern void configureConcreteAnimation(POPAnimation *anim); 63 | extern void configureConcretePropertyAnimation(POPPropertyAnimation *anim); 64 | -------------------------------------------------------------------------------- /pop-tests/POPBaseAnimationTests.mm: -------------------------------------------------------------------------------- 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 | #import "POPBaseAnimationTests.h" 11 | 12 | #import 13 | 14 | #import 15 | 16 | #import 17 | #import 18 | 19 | #import "POPAnimatable.h" 20 | #import "POPAnimationTestsExtras.h" 21 | #import "POPAnimationInternal.h" 22 | 23 | @implementation POPBaseAnimationTests 24 | { 25 | CALayer *_layer1; 26 | CALayer *_layer2; 27 | POPAnimator *_animator; 28 | CFTimeInterval _beginTime; 29 | POPAnimatableProperty *_radiusProperty; 30 | id delegate; 31 | } 32 | @synthesize layer1 = _layer1; 33 | @synthesize layer2 = _layer2; 34 | @synthesize animator = _animator; 35 | @synthesize beginTime = _beginTime; 36 | @synthesize radiusProperty = _radiusProperty; 37 | 38 | - (void)setUp 39 | { 40 | [super setUp]; 41 | _layer1 = [[CALayer alloc] init]; 42 | _layer2 = [[CALayer alloc] init]; 43 | _animator = [POPAnimator sharedAnimator]; 44 | _radiusProperty = [POPAnimatableProperty propertyWithName:@"radius" initializer:^(POPMutableAnimatableProperty *prop){ 45 | prop.readBlock = ^(POPAnimatable *obj, CGFloat values[]) { 46 | values[0] = [obj radius]; 47 | }; 48 | prop.writeBlock = ^(POPAnimatable *obj, const CGFloat values[]) { 49 | obj.radius = values[0]; 50 | }; 51 | prop.threshold = 0.01; 52 | }]; 53 | _beginTime = CACurrentMediaTime(); 54 | _animator.beginTime = _beginTime; 55 | } 56 | 57 | - (void)testCopyingSucceedsForConcreteAnimation:(POPAnimation *)anim 58 | { 59 | POPAnimation *copy = [anim copy]; 60 | 61 | XCTAssertEqualObjects(copy.name, anim.name, @"expected equality; value1:%@ value2:%@", copy.name, anim.name); 62 | XCTAssertEqual(copy.beginTime, anim.beginTime, @"expected equality; value1:%@ value2:%@", @(copy.beginTime), @(anim.beginTime)); 63 | XCTAssertEqualObjects(copy.delegate, anim.delegate, @"expected equality; value1:%@ value2:%@", copy.delegate, anim.delegate); 64 | XCTAssertEqualObjects(copy.animationDidStartBlock, anim.animationDidStartBlock, @"expected equality; value1:%@ value2:%@", copy.animationDidStartBlock, anim.animationDidStartBlock); 65 | XCTAssertEqualObjects(copy.animationDidReachToValueBlock, anim.animationDidReachToValueBlock, @"expected equality; value1:%@ value2:%@", copy.animationDidReachToValueBlock, anim.animationDidReachToValueBlock); 66 | XCTAssertEqualObjects(copy.completionBlock, anim.completionBlock, @"expected equality; value1:%@ value2:%@", copy.completionBlock, anim.completionBlock); 67 | XCTAssertEqualObjects(copy.animationDidApplyBlock, anim.animationDidApplyBlock, @"expected equality; value1:%@ value2:%@", copy.animationDidApplyBlock, anim.animationDidApplyBlock); 68 | XCTAssertEqual(copy.removedOnCompletion, anim.removedOnCompletion, @"expected equality; value1:%@ value2:%@", @(copy.removedOnCompletion), @(anim.removedOnCompletion)); 69 | XCTAssertEqual(copy.autoreverses, anim.autoreverses, @"expected equality; value1:%@ value2:%@", @(copy.autoreverses), @(anim.autoreverses)); 70 | XCTAssertEqual(copy.repeatCount, anim.repeatCount, @"expected equality; value1:%@ value2:%@", @(copy.repeatCount), @(anim.repeatCount)); 71 | XCTAssertEqual(copy.repeatForever, anim.repeatForever, @"expected equality; value1:%@ value2:%@", @(copy.repeatForever), @(anim.repeatForever)); 72 | } 73 | 74 | - (void)testCopyingSucceedsForConcretePropertyAnimation:(POPPropertyAnimation *)anim 75 | { 76 | [self testCopyingSucceedsForConcreteAnimation:anim]; 77 | 78 | POPPropertyAnimation *copy = [anim copy]; 79 | 80 | XCTAssertEqualObjects(copy.fromValue, anim.fromValue, @"expected equality; value1:%@ value2:%@", copy.fromValue, anim.fromValue); 81 | XCTAssertEqualObjects(copy.toValue, anim.toValue, @"expected equality; value1:%@ value2:%@", copy.toValue, anim.toValue); 82 | XCTAssertEqual(copy.roundingFactor, anim.roundingFactor, @"expected equality; value1:%@ value2:%@", @(copy.roundingFactor), @(anim.roundingFactor)); 83 | XCTAssertEqual(copy.clampMode, anim.clampMode, @"expected equality; value1:%@ value2:%@", @(copy.clampMode), @(anim.clampMode)); 84 | XCTAssertEqual(copy.additive, anim.additive, @"expected equality; value1:%@ value2:%@", @(copy.additive), @(anim.additive)); 85 | } 86 | 87 | @end 88 | 89 | NSUInteger kPOPAnimationConvergenceMaxFrameCount = 12; // 12 frames, ~200ms at 1/60fps, the user perseption threshold 90 | 91 | NSUInteger POPAnimationCountLastEventValues(NSArray *events, NSNumber *value, float epsilon) 92 | { 93 | __block NSUInteger count = 0; 94 | [events enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(POPAnimationValueEvent *event, NSUInteger idx, BOOL *ptrStop) { 95 | 96 | BOOL match = 0 == epsilon ? [event.value isEqualToValue:value] : fabsf([event.value floatValue] - [value floatValue]) < epsilon; 97 | if (!match) { 98 | *ptrStop = YES; 99 | } else { 100 | count++; 101 | } 102 | }]; 103 | return count; 104 | } 105 | 106 | BOOL POPAnimationEventsContainValue(NSArray *events, NSNumber *value) 107 | { 108 | for (POPAnimationValueEvent *event in events) { 109 | if ([event.value isEqual:value]) { 110 | return YES; 111 | } 112 | } 113 | return NO; 114 | } 115 | 116 | void configureConcreteAnimation(POPAnimation *anim) 117 | { 118 | static id delegate = [NSObject new]; 119 | 120 | anim.name = @"pop_animation_copy_test"; 121 | anim.beginTime = 1.234; 122 | anim.delegate = delegate; // dummy delegate 123 | anim.animationDidStartBlock = ^(POPAnimation *a){ NSLog(@"Animation Did Start"); }; 124 | anim.animationDidReachToValueBlock = ^(POPAnimation *a){ NSLog(@"Animation Did Reach To Value"); }; 125 | anim.completionBlock = ^(POPAnimation *a, BOOL finished){ NSLog(@"Animation Finished"); }; 126 | anim.animationDidApplyBlock = ^(POPAnimation *){ NSLog(@"Animation Applied"); }; 127 | anim.removedOnCompletion = NO; // not default 128 | anim.autoreverses = YES; // not default 129 | anim.repeatCount = 42; 130 | anim.repeatForever = YES; // not default 131 | } 132 | 133 | void configureConcretePropertyAnimation(POPPropertyAnimation *anim) 134 | { 135 | configureConcreteAnimation(anim); 136 | 137 | // Decay animations don't use fromValue, so setting it here causes issues. 138 | if (![anim isMemberOfClass:[POPDecayAnimation class]]) { 139 | 140 | anim.fromValue = @(12345); 141 | } 142 | 143 | anim.toValue = @(77888); 144 | anim.roundingFactor = 0.257; 145 | anim.clampMode = 87; 146 | anim.additive = YES; // not default 147 | } 148 | -------------------------------------------------------------------------------- /pop-tests/POPBasicAnimationTests.mm: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | #import 14 | 15 | #import "POPAnimatable.h" 16 | #import "POPAnimationTestsExtras.h" 17 | #import "POPBaseAnimationTests.h" 18 | 19 | @interface POPBasicAnimationTests : POPBaseAnimationTests 20 | 21 | @end 22 | 23 | @implementation POPBasicAnimationTests 24 | 25 | - (void)testGreaterThanOneControlPointC1Y 26 | { 27 | POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionX]; 28 | anim.fromValue = @0; 29 | anim.toValue = @100; 30 | anim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.15f :1.5f :0.55f :1.0f]; 31 | anim.duration = 0.36; 32 | 33 | POPAnimationTracer *tracer = anim.tracer; 34 | [tracer start]; 35 | 36 | CALayer *layer = [CALayer layer]; 37 | [layer pop_addAnimation:anim forKey:nil]; 38 | 39 | // run animation 40 | POPAnimatorRenderDuration(self.animator, self.beginTime, 3, 1.0/60.0); 41 | 42 | // verify write count 43 | NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite]; 44 | XCTAssertTrue(writeEvents.count > 10, @"expected more write events %@", tracer.allEvents); 45 | 46 | // verify last written value is equal to animation to value 47 | id lastValue = [(POPAnimationValueEvent *)writeEvents.lastObject value]; 48 | XCTAssertEqualObjects(lastValue, anim.toValue, @"expected more write events %@", tracer.allEvents); 49 | 50 | // verify last written value is less than previous value 51 | id prevLastValue = [(POPAnimationValueEvent *)writeEvents[writeEvents.count - 2] value]; 52 | XCTAssertTrue(NSOrderedDescending == [prevLastValue compare:lastValue], @"unexpected lastValue; prevLastValue:%@ events:%@", prevLastValue, tracer.allEvents); 53 | } 54 | 55 | - (void)testColorInterpolation 56 | { 57 | POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerBackgroundColor]; 58 | 59 | #if TARGET_OS_IPHONE 60 | anim.fromValue = [UIColor whiteColor]; 61 | anim.toValue = [UIColor redColor]; 62 | #else 63 | anim.fromValue = [NSColor whiteColor]; 64 | anim.toValue = [NSColor redColor]; 65 | #endif 66 | 67 | POPAnimationTracer *tracer = anim.tracer; 68 | [tracer start]; 69 | 70 | CALayer *layer = [CALayer layer]; 71 | [layer pop_addAnimation:anim forKey:nil]; 72 | 73 | // run animation 74 | POPAnimatorRenderDuration(self.animator, self.beginTime, 3, 1.0/60.0); 75 | 76 | // verify write events 77 | NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite]; 78 | XCTAssertTrue(writeEvents.count > 5, @"expected more write events %@", tracer.allEvents); 79 | 80 | // assert final value 81 | POPAssertColorEqual((__bridge CGColorRef)anim.toValue, layer.backgroundColor); 82 | } 83 | 84 | - (void)testZeroDurationAnimation 85 | { 86 | POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerBackgroundColor]; 87 | anim.duration = 0.0f; 88 | 89 | #if TARGET_OS_IPHONE 90 | anim.fromValue = [UIColor whiteColor]; 91 | anim.toValue = [UIColor redColor]; 92 | #else 93 | anim.fromValue = [NSColor whiteColor]; 94 | anim.toValue = [NSColor redColor]; 95 | #endif 96 | 97 | POPAnimationTracer *tracer = anim.tracer; 98 | [tracer start]; 99 | 100 | CALayer *layer = [CALayer layer]; 101 | [layer pop_addAnimation:anim forKey:nil]; 102 | 103 | // run animation 104 | POPAnimatorRenderDuration(self.animator, self.beginTime, 3, 1.0/60.0); 105 | 106 | // verify write events 107 | NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite]; 108 | XCTAssertTrue(writeEvents.count == 1, @"expected one write event %@", tracer.allEvents); 109 | NSArray *stopEvents = [tracer eventsWithType:kPOPAnimationEventDidStop]; 110 | XCTAssertTrue(stopEvents.count == 1, @"expected one stop event %@", tracer.allEvents); 111 | 112 | // assert final value 113 | POPAssertColorEqual((__bridge CGColorRef)anim.toValue, layer.backgroundColor); 114 | } 115 | 116 | #if TARGET_OS_IPHONE 117 | - (void)testEdgeInsetsSupport 118 | { 119 | const UIEdgeInsets fromEdgeInsets = UIEdgeInsetsZero; 120 | const UIEdgeInsets toEdgeInsets = UIEdgeInsetsMake(100, 200, 200, 400); 121 | 122 | POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPScrollViewContentInset]; 123 | anim.fromValue = [NSValue valueWithUIEdgeInsets:fromEdgeInsets]; 124 | anim.toValue = [NSValue valueWithUIEdgeInsets:toEdgeInsets]; 125 | 126 | id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)]; 127 | anim.delegate = delegate; 128 | 129 | // expect start and stop to be called 130 | [[delegate expect] pop_animationDidStart:anim]; 131 | [[delegate expect] pop_animationDidStop:anim finished:YES]; 132 | 133 | // start tracer 134 | POPAnimationTracer *tracer = anim.tracer; 135 | [tracer start]; 136 | 137 | id scrollView = [OCMockObject niceMockForClass:[UIScrollView class]]; 138 | [scrollView pop_addAnimation:anim forKey:nil]; 139 | 140 | // expect final value to be set 141 | [[scrollView expect] setContentInset:toEdgeInsets]; 142 | 143 | // run animation 144 | POPAnimatorRenderDuration(self.animator, self.beginTime, 3, 1.0/60.0); 145 | 146 | NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite]; 147 | 148 | // verify delegate 149 | [delegate verify]; 150 | 151 | // verify scroll view 152 | [scrollView verify]; 153 | 154 | POPAnimationValueEvent *lastEvent = [writeEvents lastObject]; 155 | UIEdgeInsets lastEdgeInsets = [lastEvent.value UIEdgeInsetsValue]; 156 | 157 | // verify last insets are to insets 158 | XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(lastEdgeInsets, toEdgeInsets), @"unexpected last edge insets value: %@", lastEvent); 159 | } 160 | #endif 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /pop-tests/POPCustomAnimationTests.mm: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | #import 15 | 16 | #import "POPAnimatable.h" 17 | #import "POPAnimationTestsExtras.h" 18 | #import "POPBaseAnimationTests.h" 19 | 20 | static const CGFloat epsilon = 0.0001f; 21 | 22 | @interface POPCustomAnimationTests : POPBaseAnimationTests 23 | @end 24 | 25 | @implementation POPCustomAnimationTests 26 | 27 | - (void)testCallbackFinished 28 | { 29 | static NSString * const key = @"key"; 30 | static CFTimeInterval const timeInterval = 0.1; 31 | 32 | __block NSUInteger callbackCount = 0; 33 | 34 | // animation 35 | POPCustomAnimation *anim = [POPCustomAnimation animationWithBlock:^BOOL(id target, POPCustomAnimation *animation) { 36 | if (0 != callbackCount) { 37 | // validate elapsed time 38 | XCTAssertEqualWithAccuracy(animation.elapsedTime, timeInterval, epsilon, @"expected elapsedTime:%f %@", timeInterval, animation); 39 | } 40 | 41 | // increment callback count 42 | callbackCount++; 43 | 44 | return callbackCount < 3; 45 | }]; 46 | 47 | anim.beginTime = self.beginTime; 48 | 49 | // delegate 50 | id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)]; 51 | 52 | // expect start, progress & stop to all be called 53 | [[delegate expect] pop_animationDidStart:anim]; 54 | [[delegate expect] pop_animationDidStop:anim finished:YES]; 55 | [[delegate expect] pop_animationDidApply:anim]; 56 | 57 | anim.delegate = delegate; 58 | 59 | POPAnimationTracer *tracer = anim.tracer; 60 | [tracer start]; 61 | 62 | // layer 63 | id layer = [OCMockObject niceMockForClass:[CALayer class]]; 64 | [layer pop_addAnimation:anim forKey:key]; 65 | 66 | POPAnimatorRenderDuration(self.animator, self.beginTime + 0.1, 5, 0.1); 67 | XCTAssertTrue(callbackCount == 3, @"unexpected callbackCount:%lu", (unsigned long)callbackCount); 68 | 69 | NSArray *startEvents = [tracer eventsWithType:kPOPAnimationEventDidStart]; 70 | XCTAssertTrue(1 == startEvents.count, @"unexpected startEvents count %@", startEvents); 71 | 72 | NSArray *stopEvents = [tracer eventsWithType:kPOPAnimationEventDidStop]; 73 | XCTAssertTrue(1 == stopEvents.count, @"unexpected stopEvents count %@", stopEvents); 74 | 75 | [layer verify]; 76 | [delegate verify]; 77 | } 78 | 79 | - (void)testCallbackCancelled 80 | { 81 | static NSString * const key = @"key"; 82 | static CFTimeInterval const timeInterval = 0.1; 83 | 84 | __block NSUInteger callbackCount = 0; 85 | 86 | // animation 87 | POPCustomAnimation *anim = [POPCustomAnimation animationWithBlock:^BOOL(id target, POPCustomAnimation *animation) { 88 | if (0 == callbackCount) { 89 | // validate elapsed time acruel 90 | XCTAssertEqualWithAccuracy(animation.elapsedTime, 0., epsilon, @"expected elapsedTime:%f %@", timeInterval, animation); 91 | } else { 92 | // validate elapsed time acruel 93 | XCTAssertEqualWithAccuracy(animation.elapsedTime, timeInterval, epsilon, @"expected elapsedTime:%f %@", timeInterval, animation); 94 | } 95 | 96 | // increment callback count 97 | callbackCount++; 98 | 99 | if (callbackCount == 3) { 100 | [target pop_removeAnimationForKey:key]; 101 | } 102 | 103 | return callbackCount < 3; 104 | }]; 105 | 106 | anim.beginTime = self.beginTime; 107 | 108 | // delegate 109 | id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)]; 110 | 111 | // expect start, progress & stop to all be called 112 | [[delegate expect] pop_animationDidStart:anim]; 113 | [[delegate expect] pop_animationDidStop:anim finished:NO]; 114 | [[delegate expect] pop_animationDidApply:anim]; 115 | 116 | anim.delegate = delegate; 117 | 118 | POPAnimationTracer *tracer = anim.tracer; 119 | [tracer start]; 120 | 121 | // layer 122 | id layer = [OCMockObject niceMockForClass:[CALayer class]]; 123 | [layer pop_addAnimation:anim forKey:key]; 124 | 125 | POPAnimatorRenderDuration(self.animator, self.beginTime + 0.1, 5, 0.1); 126 | XCTAssertTrue(callbackCount == 3, @"unexpected callbackCount:%lu", (unsigned long)callbackCount); 127 | 128 | NSArray *startEvents = [tracer eventsWithType:kPOPAnimationEventDidStart]; 129 | XCTAssertTrue(1 == startEvents.count, @"unexpected startEvents count %@", startEvents); 130 | 131 | NSArray *stopEvents = [tracer eventsWithType:kPOPAnimationEventDidStop]; 132 | XCTAssertTrue(1 == stopEvents.count, @"unexpected stopEvents count %@", stopEvents); 133 | 134 | [layer verify]; 135 | [delegate verify]; 136 | } 137 | 138 | - (void)testAssociation 139 | { 140 | static NSString * const key = @"key"; 141 | 142 | __block id blockTarget = nil; 143 | 144 | POPCustomAnimation *anim = [POPCustomAnimation animationWithBlock:^(id target, POPCustomAnimation *animation) { 145 | blockTarget = target; 146 | return YES; 147 | }]; 148 | 149 | id layer = [OCMockObject niceMockForClass:[CALayer class]]; 150 | 151 | [layer pop_addAnimation:anim forKey:key]; 152 | 153 | // verify animation & key 154 | XCTAssertTrue(anim == [layer pop_animationForKey:key], @"expected:%@ actual:%@", anim, [layer pop_animationForKey:key]); 155 | XCTAssertTrue([[layer pop_animationKeys] containsObject:key], @"expected:%@ actual:%@", key, [layer pop_animationKeys]); 156 | 157 | POPAnimatorRenderDuration(self.animator, self.beginTime, 1, 0.1); 158 | 159 | XCTAssertEqualObjects(layer, blockTarget, @"expected:%@ actual:%@", layer, blockTarget); 160 | 161 | // remove animations 162 | [layer pop_removeAnimationForKey:key]; 163 | 164 | // verify animation & key 165 | XCTAssertFalse(anim == [layer pop_animationForKey:key], @"expected:%@ actual:%@", (id)nil, [layer pop_animationForKey:key]); 166 | XCTAssertFalse([[layer pop_animationKeys] containsObject:key], @"expected:%@ actual:%@", (id)nil, [layer pop_animationKeys]); 167 | } 168 | 169 | @end 170 | -------------------------------------------------------------------------------- /pop-tests/POPEaseInEaseOutAnimationTests.mm: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | #import 15 | 16 | #import 17 | #import 18 | 19 | #import "POPAnimatable.h" 20 | #import "POPAnimationTestsExtras.h" 21 | #import "POPBaseAnimationTests.h" 22 | 23 | @interface POPEaseInEaseOutAnimationTests : POPBaseAnimationTests 24 | @end 25 | 26 | @implementation POPEaseInEaseOutAnimationTests 27 | 28 | - (void)testCompletion 29 | { 30 | // animation 31 | // the default from, to and bounciness values are used 32 | POPBasicAnimation *anim = [POPBasicAnimation easeInEaseOutAnimation]; 33 | anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerScaleXY]; 34 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)]; 35 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(0.97, 0.97)]; 36 | 37 | // delegate 38 | id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)]; 39 | 40 | // expect start, progress & stop to all be called 41 | [[delegate expect] pop_animationDidStart:anim]; 42 | [[delegate expect] pop_animationDidStop:anim finished:YES]; 43 | 44 | anim.delegate = delegate; 45 | 46 | CALayer *layer = [CALayer layer]; 47 | [layer pop_addAnimation:anim forKey:@"key"]; 48 | 49 | POPAnimatorRenderTimes(self.animator, self.beginTime, @[@0.0, @0.1, @0.2, @0.4]); 50 | [delegate verify]; 51 | } 52 | 53 | - (void)testRectSupport 54 | { 55 | const CGRect fromRect = CGRectMake(0, 0, 0, 0); 56 | const CGRect toRect = CGRectMake(100, 200, 200, 400); 57 | 58 | POPBasicAnimation *anim = [POPBasicAnimation easeInEaseOutAnimation]; 59 | anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerBounds]; 60 | anim.fromValue = [NSValue valueWithCGRect:fromRect]; 61 | anim.toValue = [NSValue valueWithCGRect:toRect]; 62 | 63 | id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)]; 64 | anim.delegate = delegate; 65 | 66 | // expect start and stop to be called 67 | [[delegate expect] pop_animationDidStart:anim]; 68 | [[delegate expect] pop_animationDidStop:anim finished:YES]; 69 | 70 | // start tracer 71 | POPAnimationTracer *tracer = anim.tracer; 72 | [tracer start]; 73 | 74 | CALayer *layer = [CALayer layer]; 75 | [layer pop_addAnimation:anim forKey:@""]; 76 | 77 | // run animation 78 | POPAnimatorRenderDuration(self.animator, self.beginTime, 1, 1.0/60.0); 79 | 80 | NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite]; 81 | 82 | // verify delegate 83 | [delegate verify]; 84 | 85 | POPAnimationValueEvent *lastEvent = [writeEvents lastObject]; 86 | CGRect lastRect = [lastEvent.value CGRectValue]; 87 | 88 | // verify last rect is to rect 89 | XCTAssertTrue(CGRectEqualToRect(lastRect, toRect), @"unexpected last rect value: %@", lastEvent); 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /pop-tests/pop-tests-ios-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /pop-tests/pop-tests-osx-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /pop-tests/pop-tests-tvos-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /pop.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'pop' 3 | spec.version = '1.0.11' 4 | spec.license = { :type => 'BSD' } 5 | spec.homepage = 'https://github.com/facebook/pop' 6 | spec.authors = { 'Kimon Tsinteris' => 'kimon@mac.com' } 7 | spec.summary = 'Extensible animation framework for iOS and OS X.' 8 | spec.source = { :git => 'https://github.com/facebook/pop.git', :tag => '1.0.10' } 9 | spec.source_files = 'pop/**/*.{h,m,mm,cpp}' 10 | spec.public_header_files = 'pop/{POP,POPAnimatableProperty,POPAnimatablePropertyTypes,POPAnimation,POPAnimationEvent,POPAnimationExtras,POPAnimationTracer,POPAnimator,POPBasicAnimation,POPCustomAnimation,POPDecayAnimation,POPDefines,POPGeometry,POPLayerExtras,POPPropertyAnimation,POPSpringAnimation,POPVector}.h' 11 | spec.requires_arc = true 12 | spec.social_media_url = 'https://twitter.com/fbOpenSource' 13 | spec.library = 'c++' 14 | spec.pod_target_xcconfig = { 15 | 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++11', 16 | 'CLANG_CXX_LIBRARY' => 'libc++' 17 | } 18 | spec.ios.deployment_target = '8.0' 19 | spec.osx.deployment_target = '10.8' 20 | spec.tvos.deployment_target = '9.0' 21 | end 22 | -------------------------------------------------------------------------------- /pop.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /pop.xcodeproj/xcshareddata/xcschemes/pop-ios-framework.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /pop.xcodeproj/xcshareddata/xcschemes/pop-ios-static.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /pop.xcodeproj/xcshareddata/xcschemes/pop-osx-framework.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /pop.xcodeproj/xcshareddata/xcschemes/pop-tvos-framework.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /pop.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /pop.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pop/POP.h: -------------------------------------------------------------------------------- 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 | #ifndef POP_POP_H 11 | #define POP_POP_H 12 | 13 | #import 14 | 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | 30 | #endif /* POP_POP_H */ 31 | -------------------------------------------------------------------------------- /pop/POPAction.h: -------------------------------------------------------------------------------- 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 | #ifndef POPACTION_H 11 | #define POPACTION_H 12 | 13 | #import 14 | 15 | #import 16 | 17 | #ifdef __cplusplus 18 | 19 | namespace POP { 20 | 21 | /** 22 | @abstract Disables Core Animation actions using RAII. 23 | @discussion The disablement of actions is scoped to the current transaction. 24 | */ 25 | class ActionDisabler 26 | { 27 | BOOL state; 28 | 29 | public: 30 | ActionDisabler() POP_NOTHROW 31 | { 32 | state = [CATransaction disableActions]; 33 | [CATransaction setDisableActions:YES]; 34 | } 35 | 36 | ~ActionDisabler() 37 | { 38 | [CATransaction setDisableActions:state]; 39 | } 40 | }; 41 | 42 | /** 43 | @abstract Enables Core Animation actions using RAII. 44 | @discussion The enablement of actions is scoped to the current transaction. 45 | */ 46 | class ActionEnabler 47 | { 48 | BOOL state; 49 | 50 | public: 51 | ActionEnabler() POP_NOTHROW 52 | { 53 | state = [CATransaction disableActions]; 54 | [CATransaction setDisableActions:NO]; 55 | } 56 | 57 | ~ActionEnabler() 58 | { 59 | [CATransaction setDisableActions:state]; 60 | } 61 | }; 62 | 63 | } 64 | 65 | #endif /* __cplusplus */ 66 | 67 | #endif /* POPACTION_H */ 68 | -------------------------------------------------------------------------------- /pop/POPAnimatablePropertyTypes.h: -------------------------------------------------------------------------------- 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 | typedef void (^POPAnimatablePropertyReadBlock)(id obj, CGFloat values[]); 11 | typedef void (^POPAnimatablePropertyWriteBlock)(id obj, const CGFloat values[]); 12 | -------------------------------------------------------------------------------- /pop/POPAnimation.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | #import 14 | 15 | @class CAMediaTimingFunction; 16 | 17 | /** 18 | @abstract The abstract animation base class. 19 | @discussion Instantiate and use one of the concrete animation subclasses. 20 | */ 21 | @interface POPAnimation : NSObject 22 | 23 | /** 24 | @abstract The name of the animation. 25 | @discussion Optional property to help identify the animation. 26 | */ 27 | @property (copy, nonatomic) NSString *name; 28 | 29 | /** 30 | @abstract The beginTime of the animation in media time. 31 | @discussion Defaults to 0 and starts immediately. 32 | */ 33 | @property (assign, nonatomic) CFTimeInterval beginTime; 34 | 35 | /** 36 | @abstract The animation delegate. 37 | @discussion See {@ref POPAnimationDelegate} for details. 38 | */ 39 | @property (weak, nonatomic) id delegate; 40 | 41 | /** 42 | @abstract The animation tracer. 43 | @discussion Returns the existing tracer, creating one if needed. Call start/stop on the tracer to toggle event collection. 44 | */ 45 | @property (readonly, nonatomic) POPAnimationTracer *tracer; 46 | 47 | /** 48 | @abstract Optional block called on animation start. 49 | */ 50 | @property (copy, nonatomic) void (^animationDidStartBlock)(POPAnimation *anim); 51 | 52 | /** 53 | @abstract Optional block called when value meets or exceeds to value. 54 | */ 55 | @property (copy, nonatomic) void (^animationDidReachToValueBlock)(POPAnimation *anim); 56 | 57 | /** 58 | @abstract Optional block called on animation completion. 59 | */ 60 | @property (copy, nonatomic) void (^completionBlock)(POPAnimation *anim, BOOL finished); 61 | 62 | /** 63 | @abstract Optional block called each frame animation is applied. 64 | */ 65 | @property (copy, nonatomic) void (^animationDidApplyBlock)(POPAnimation *anim); 66 | 67 | /** 68 | @abstract Flag indicating whether animation should be removed on completion. 69 | @discussion Setting to NO can facilitate animation reuse. Defaults to YES. 70 | */ 71 | @property (assign, nonatomic) BOOL removedOnCompletion; 72 | 73 | /** 74 | @abstract Flag indicating whether animation is paused. 75 | @discussion A paused animation is excluded from the list of active animations. On initial creation, defaults to YES. On animation addition, the animation is implicity unpaused. On animation completion, the animation is implicity paused including for animations with removedOnCompletion set to NO. 76 | */ 77 | @property (assign, nonatomic, getter = isPaused) BOOL paused; 78 | 79 | /** 80 | @abstract Flag indicating whether animation autoreverses. 81 | @discussion An animation that autoreverses will have twice the duration before it is considered finished. It will animate to the toValue, stop, then animate back to the original fromValue. The delegate methods are called as follows: 82 | 83 | 1) animationDidStart: is called at the beginning, as usual, and then after each toValue is reached and the autoreverse is going to start. 84 | 2) animationDidReachToValue: is called every time the toValue is reached. The toValue is swapped with the fromValue at the end of each animation segment. This means that with autoreverses set to YES, the animationDidReachToValue: delegate method will be called a minimum of twice. 85 | 3) animationDidStop:finished: is called every time the toValue is reached, the finished argument will be NO if the autoreverse is not yet complete. 86 | */ 87 | @property (assign, nonatomic) BOOL autoreverses; 88 | 89 | /** 90 | @abstract The number of times to repeat the animation. 91 | @discussion A repeatCount of 0 or 1 means that the animation will not repeat, just like Core Animation. A repeatCount of 2 or greater means that the animation will run that many times before stopping. The delegate methods are called as follows: 92 | 93 | 1) animationDidStart: is called at the beginning of each animation repeat. 94 | 2) animationDidReachToValue: is called every time the toValue is reached. 95 | 3) animationDidStop:finished: is called every time the toValue is reached, the finished argument will be NO if the autoreverse is not yet complete. 96 | 97 | When combined with the autoreverses property, a singular animation is effectively twice as long. 98 | */ 99 | @property (assign, nonatomic) NSInteger repeatCount; 100 | 101 | /** 102 | @abstract Repeat the animation forever. 103 | @discussion This property will make the animation repeat forever. The value of the repeatCount property is undefined when this property is set. The finished parameter of the delegate callback animationDidStop:finished: will always be NO. 104 | */ 105 | @property (assign, nonatomic) BOOL repeatForever; 106 | 107 | @end 108 | 109 | /** 110 | @abstract The animation delegate. 111 | */ 112 | @protocol POPAnimationDelegate 113 | @optional 114 | 115 | /** 116 | @abstract Called on animation start. 117 | @param anim The relevant animation. 118 | */ 119 | - (void)pop_animationDidStart:(POPAnimation *)anim; 120 | 121 | /** 122 | @abstract Called when value meets or exceeds to value. 123 | @param anim The relevant animation. 124 | */ 125 | - (void)pop_animationDidReachToValue:(POPAnimation *)anim; 126 | 127 | /** 128 | @abstract Called on animation stop. 129 | @param anim The relevant animation. 130 | @param finished Flag indicating finished state. Flag is true if the animation reached completion before being removed. 131 | */ 132 | - (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished; 133 | 134 | /** 135 | @abstract Called each frame animation is applied. 136 | @param anim The relevant animation. 137 | */ 138 | - (void)pop_animationDidApply:(POPAnimation *)anim; 139 | 140 | @end 141 | 142 | 143 | @interface NSObject (POP) 144 | 145 | /** 146 | @abstract Add an animation to the reciver. 147 | @param anim The animation to add. 148 | @param key The key used to identify the animation. 149 | @discussion The 'key' may be any string such that only one animation per unique key is added per object. 150 | */ 151 | - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key; 152 | 153 | /** 154 | @abstract Remove all animations attached to the receiver. 155 | */ 156 | - (void)pop_removeAllAnimations; 157 | 158 | /** 159 | @abstract Remove any animation attached to the receiver for 'key'. 160 | @param key The key used to identify the animation. 161 | */ 162 | - (void)pop_removeAnimationForKey:(NSString *)key; 163 | 164 | /** 165 | @abstract Returns an array containing the keys of all animations currently attached to the receiver. 166 | The order of keys reflects the order in which animations will be applied. 167 | */ 168 | - (NSArray *)pop_animationKeys; 169 | 170 | /** 171 | @abstract Returns any animation attached to the receiver. 172 | @param key The key used to identify the animation. 173 | @returns The animation currently attached, or nil if no such animation exists. 174 | */ 175 | - (id)pop_animationForKey:(NSString *)key; 176 | 177 | @end 178 | 179 | /** 180 | * This implementation of NSCopying does not do any copying of animation's state, but only configuration. 181 | * i.e. you cannot copy an animation and expect to apply it to a view and have the copied animation pick up where the original left off. 182 | * Two common uses of copying animations: 183 | * * you need to apply the same animation to multiple different views. 184 | * * you need to absolutely ensure that the the caller of your function cannot mutate the animation once it's been passed in. 185 | */ 186 | @interface POPAnimation (NSCopying) 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /pop/POPAnimation.mm: -------------------------------------------------------------------------------- 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 | #import "POPAnimationExtras.h" 11 | #import "POPAnimationInternal.h" 12 | 13 | #import 14 | 15 | #import "POPAction.h" 16 | #import "POPAnimationRuntime.h" 17 | #import "POPAnimationTracerInternal.h" 18 | #import "POPAnimatorPrivate.h" 19 | 20 | using namespace POP; 21 | 22 | #pragma mark - POPAnimation 23 | 24 | @implementation POPAnimation 25 | @synthesize solver = _solver; 26 | @synthesize currentValue = _currentValue; 27 | @synthesize progressMarkers = _progressMarkers; 28 | 29 | #pragma mark - Lifecycle 30 | 31 | - (id)init 32 | { 33 | [NSException raise:NSStringFromClass([self class]) format:@"Attempting to instantiate an abstract class. Use a concrete subclass instead."]; 34 | return nil; 35 | } 36 | 37 | - (id)_init 38 | { 39 | self = [super init]; 40 | if (nil != self) { 41 | [self _initState]; 42 | } 43 | return self; 44 | } 45 | 46 | - (void)_initState 47 | { 48 | _state = new POPAnimationState(self); 49 | } 50 | 51 | - (void)dealloc 52 | { 53 | if (_state) { 54 | delete _state; 55 | _state = NULL; 56 | }; 57 | } 58 | 59 | #pragma mark - Properties 60 | 61 | - (id)delegate 62 | { 63 | return _state->delegate; 64 | } 65 | 66 | - (void)setDelegate:(id)delegate 67 | { 68 | _state->setDelegate(delegate); 69 | } 70 | 71 | - (BOOL)isPaused 72 | { 73 | return _state->paused; 74 | } 75 | 76 | - (void)setPaused:(BOOL)paused 77 | { 78 | _state->setPaused(paused ? true : false); 79 | } 80 | 81 | - (NSInteger)repeatCount 82 | { 83 | if (_state->autoreverses) { 84 | return _state->repeatCount / 2; 85 | } else { 86 | return _state->repeatCount; 87 | } 88 | } 89 | 90 | - (void)setRepeatCount:(NSInteger)repeatCount 91 | { 92 | if (repeatCount > 0) { 93 | if (repeatCount > NSIntegerMax / 2) { 94 | repeatCount = NSIntegerMax / 2; 95 | } 96 | 97 | if (_state->autoreverses) { 98 | _state->repeatCount = (repeatCount * 2); 99 | } else { 100 | _state->repeatCount = repeatCount; 101 | } 102 | } 103 | } 104 | 105 | - (BOOL)autoreverses 106 | { 107 | return _state->autoreverses; 108 | } 109 | 110 | - (void)setAutoreverses:(BOOL)autoreverses 111 | { 112 | _state->autoreverses = autoreverses; 113 | if (autoreverses) { 114 | if (_state->repeatCount == 0) { 115 | [self setRepeatCount:1]; 116 | } 117 | } 118 | } 119 | 120 | FB_PROPERTY_GET(POPAnimationState, type, POPAnimationType); 121 | DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidStartBlock, setAnimationDidStartBlock:, POPAnimationDidStartBlock); 122 | DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidReachToValueBlock, setAnimationDidReachToValueBlock:, POPAnimationDidReachToValueBlock); 123 | DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, completionBlock, setCompletionBlock:, POPAnimationCompletionBlock); 124 | DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidApplyBlock, setAnimationDidApplyBlock:, POPAnimationDidApplyBlock); 125 | DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, name, setName:, NSString*); 126 | DEFINE_RW_PROPERTY(POPAnimationState, beginTime, setBeginTime:, CFTimeInterval); 127 | DEFINE_RW_FLAG(POPAnimationState, removedOnCompletion, removedOnCompletion, setRemovedOnCompletion:); 128 | DEFINE_RW_FLAG(POPAnimationState, repeatForever, repeatForever, setRepeatForever:); 129 | 130 | - (id)valueForUndefinedKey:(NSString *)key 131 | { 132 | return _state->dict[key]; 133 | } 134 | 135 | - (void)setValue:(id)value forUndefinedKey:(NSString *)key 136 | { 137 | if (!value) { 138 | [_state->dict removeObjectForKey:key]; 139 | } else { 140 | if (!_state->dict) 141 | _state->dict = [[NSMutableDictionary alloc] init]; 142 | _state->dict[key] = value; 143 | } 144 | } 145 | 146 | - (POPAnimationTracer *)tracer 147 | { 148 | if (!_state->tracer) { 149 | _state->tracer = [[POPAnimationTracer alloc] initWithAnimation:self]; 150 | } 151 | return _state->tracer; 152 | } 153 | 154 | - (NSString *)description 155 | { 156 | NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self]; 157 | [self _appendDescription:s debug:NO]; 158 | [s appendString:@">"]; 159 | return s; 160 | } 161 | 162 | - (NSString *)debugDescription 163 | { 164 | NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self]; 165 | [self _appendDescription:s debug:YES]; 166 | [s appendString:@">"]; 167 | return s; 168 | } 169 | 170 | #pragma mark - Utility 171 | 172 | POPAnimationState *POPAnimationGetState(POPAnimation *a) 173 | { 174 | return a->_state; 175 | } 176 | 177 | - (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime 178 | { 179 | return YES; 180 | } 181 | 182 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug 183 | { 184 | if (_state->name) 185 | [s appendFormat:@"; name = %@", _state->name]; 186 | 187 | if (!self.removedOnCompletion) 188 | [s appendFormat:@"; removedOnCompletion = %@", POPStringFromBOOL(self.removedOnCompletion)]; 189 | 190 | if (debug) { 191 | if (_state->active) 192 | [s appendFormat:@"; active = %@", POPStringFromBOOL(_state->active)]; 193 | 194 | if (_state->paused) 195 | [s appendFormat:@"; paused = %@", POPStringFromBOOL(_state->paused)]; 196 | } 197 | 198 | if (_state->beginTime) { 199 | [s appendFormat:@"; beginTime = %f", _state->beginTime]; 200 | } 201 | 202 | for (NSString *key in _state->dict) { 203 | [s appendFormat:@"; %@ = %@", key, _state->dict[key]]; 204 | } 205 | } 206 | 207 | @end 208 | 209 | 210 | #pragma mark - POPPropertyAnimation 211 | 212 | #pragma mark - POPBasicAnimation 213 | 214 | #pragma mark - POPDecayAnimation 215 | 216 | @implementation NSObject (POP) 217 | 218 | - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key 219 | { 220 | [[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key]; 221 | } 222 | 223 | - (void)pop_removeAllAnimations 224 | { 225 | [[POPAnimator sharedAnimator] removeAllAnimationsForObject:self]; 226 | } 227 | 228 | - (void)pop_removeAnimationForKey:(NSString *)key 229 | { 230 | [[POPAnimator sharedAnimator] removeAnimationForObject:self key:key]; 231 | } 232 | 233 | - (NSArray *)pop_animationKeys 234 | { 235 | return [[POPAnimator sharedAnimator] animationKeysForObject:self]; 236 | } 237 | 238 | - (id)pop_animationForKey:(NSString *)key 239 | { 240 | return [[POPAnimator sharedAnimator] animationForObject:self key:key]; 241 | } 242 | 243 | @end 244 | 245 | @implementation NSProxy (POP) 246 | 247 | - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key 248 | { 249 | [[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key]; 250 | } 251 | 252 | - (void)pop_removeAllAnimations 253 | { 254 | [[POPAnimator sharedAnimator] removeAllAnimationsForObject:self]; 255 | } 256 | 257 | - (void)pop_removeAnimationForKey:(NSString *)key 258 | { 259 | [[POPAnimator sharedAnimator] removeAnimationForObject:self key:key]; 260 | } 261 | 262 | - (NSArray *)pop_animationKeys 263 | { 264 | return [[POPAnimator sharedAnimator] animationKeysForObject:self]; 265 | } 266 | 267 | - (id)pop_animationForKey:(NSString *)key 268 | { 269 | return [[POPAnimator sharedAnimator] animationForObject:self key:key]; 270 | } 271 | 272 | @end 273 | 274 | @implementation POPAnimation (NSCopying) 275 | 276 | - (instancetype)copyWithZone:(NSZone *)zone 277 | { 278 | /* 279 | * Must use [self class] instead of POPAnimation so that subclasses can call this via super. 280 | * Even though POPAnimation and POPPropertyAnimation throw exceptions on init, 281 | * it's safe to call it since you can only copy objects that have been successfully created. 282 | */ 283 | POPAnimation *copy = [[[self class] allocWithZone:zone] init]; 284 | 285 | if (copy) { 286 | copy.name = self.name; 287 | copy.beginTime = self.beginTime; 288 | copy.delegate = self.delegate; 289 | copy.animationDidStartBlock = self.animationDidStartBlock; 290 | copy.animationDidReachToValueBlock = self.animationDidReachToValueBlock; 291 | copy.completionBlock = self.completionBlock; 292 | copy.animationDidApplyBlock = self.animationDidApplyBlock; 293 | copy.removedOnCompletion = self.removedOnCompletion; 294 | 295 | copy.autoreverses = self.autoreverses; 296 | copy.repeatCount = self.repeatCount; 297 | copy.repeatForever = self.repeatForever; 298 | } 299 | 300 | return copy; 301 | } 302 | 303 | @end -------------------------------------------------------------------------------- /pop/POPAnimationEvent.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | /** 13 | @abstract Enumeraton of animation event types. 14 | */ 15 | typedef NS_ENUM(NSUInteger, POPAnimationEventType) { 16 | kPOPAnimationEventPropertyRead = 0, 17 | kPOPAnimationEventPropertyWrite, 18 | kPOPAnimationEventToValueUpdate, 19 | kPOPAnimationEventFromValueUpdate, 20 | kPOPAnimationEventVelocityUpdate, 21 | kPOPAnimationEventBouncinessUpdate, 22 | kPOPAnimationEventSpeedUpdate, 23 | kPOPAnimationEventFrictionUpdate, 24 | kPOPAnimationEventMassUpdate, 25 | kPOPAnimationEventTensionUpdate, 26 | kPOPAnimationEventDidStart, 27 | kPOPAnimationEventDidStop, 28 | kPOPAnimationEventDidReachToValue, 29 | kPOPAnimationEventAutoreversed 30 | }; 31 | 32 | /** 33 | @abstract The base animation event class. 34 | */ 35 | @interface POPAnimationEvent : NSObject 36 | 37 | /** 38 | @abstract The event type. See {@ref POPAnimationEventType} for possible values. 39 | */ 40 | @property (readonly, nonatomic, assign) POPAnimationEventType type; 41 | 42 | /** 43 | @abstract The time of event. 44 | */ 45 | @property (readonly, nonatomic, assign) CFTimeInterval time; 46 | 47 | /** 48 | @abstract Optional string describing the animation at time of event. 49 | */ 50 | @property (readonly, nonatomic, copy) NSString *animationDescription; 51 | 52 | @end 53 | 54 | /** 55 | @abstract An animation event subclass for recording value and velocity. 56 | */ 57 | @interface POPAnimationValueEvent : POPAnimationEvent 58 | 59 | /** 60 | @abstract The value recorded. 61 | */ 62 | @property (readonly, nonatomic, strong) id value; 63 | 64 | /** 65 | @abstract The velocity recorded, if any. 66 | */ 67 | @property (readonly, nonatomic, strong) id velocity; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /pop/POPAnimationEvent.mm: -------------------------------------------------------------------------------- 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 | #import "POPAnimationEvent.h" 11 | #import "POPAnimationEventInternal.h" 12 | 13 | static NSString *stringFromType(POPAnimationEventType aType) 14 | { 15 | switch (aType) { 16 | case kPOPAnimationEventPropertyRead: 17 | return @"read"; 18 | case kPOPAnimationEventPropertyWrite: 19 | return @"write"; 20 | case kPOPAnimationEventToValueUpdate: 21 | return @"toValue"; 22 | case kPOPAnimationEventFromValueUpdate: 23 | return @"fromValue"; 24 | case kPOPAnimationEventVelocityUpdate: 25 | return @"velocity"; 26 | case kPOPAnimationEventSpeedUpdate: 27 | return @"speed"; 28 | case kPOPAnimationEventBouncinessUpdate: 29 | return @"bounciness"; 30 | case kPOPAnimationEventFrictionUpdate: 31 | return @"friction"; 32 | case kPOPAnimationEventMassUpdate: 33 | return @"mass"; 34 | case kPOPAnimationEventTensionUpdate: 35 | return @"tension"; 36 | case kPOPAnimationEventDidStart: 37 | return @"didStart"; 38 | case kPOPAnimationEventDidStop: 39 | return @"didStop"; 40 | case kPOPAnimationEventDidReachToValue: 41 | return @"didReachToValue"; 42 | case kPOPAnimationEventAutoreversed: 43 | return @"autoreversed"; 44 | default: 45 | return nil; 46 | } 47 | } 48 | 49 | @implementation POPAnimationEvent 50 | @synthesize type = _type; 51 | @synthesize time = _time; 52 | @synthesize animationDescription = _animationDescription; 53 | 54 | - (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime 55 | { 56 | self = [super init]; 57 | if (nil != self) { 58 | _type = aType; 59 | _time = aTime; 60 | } 61 | return self; 62 | } 63 | 64 | - (NSString *)description 65 | { 66 | NSMutableString *s = [NSMutableString stringWithFormat:@""]; 69 | return s; 70 | } 71 | 72 | // subclass override 73 | - (void)_appendDescription:(NSMutableString *)s 74 | { 75 | if (0 != _animationDescription.length) { 76 | [s appendFormat:@"; animation = %@", _animationDescription]; 77 | } 78 | } 79 | 80 | @end 81 | 82 | @implementation POPAnimationValueEvent 83 | @synthesize value = _value; 84 | @synthesize velocity = _velocity; 85 | 86 | - (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime value:(id)aValue 87 | { 88 | self = [self initWithType:aType time:aTime]; 89 | if (nil != self) { 90 | _value = aValue; 91 | } 92 | return self; 93 | } 94 | 95 | - (void)_appendDescription:(NSMutableString *)s 96 | { 97 | [super _appendDescription:s]; 98 | 99 | if (nil != _value) { 100 | [s appendFormat:@"; value = %@", _value]; 101 | } 102 | 103 | if (nil != _velocity) { 104 | [s appendFormat:@"; velocity = %@", _velocity]; 105 | } 106 | } 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /pop/POPAnimationEventInternal.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import "POPAnimationEvent.h" 13 | 14 | @interface POPAnimationEvent () 15 | 16 | /** 17 | @abstract Default initializer. 18 | */ 19 | - (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time; 20 | 21 | /** 22 | @abstract Readwrite redefinition of public property. 23 | */ 24 | @property (readwrite, nonatomic, copy) NSString *animationDescription; 25 | 26 | @end 27 | 28 | @interface POPAnimationValueEvent () 29 | 30 | /** 31 | @abstract Default initializer. 32 | */ 33 | - (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time value:(id)value; 34 | 35 | /** 36 | @abstract Readwrite redefinition of public property. 37 | */ 38 | @property (readwrite, nonatomic, strong) id velocity; 39 | 40 | @end 41 | 42 | -------------------------------------------------------------------------------- /pop/POPAnimationExtras.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | #import 14 | 15 | /** 16 | @abstract The current drag coefficient. 17 | @discussion A value greater than 1.0 indicates Simulator slow-motion animations are enabled. Defaults to 1.0. 18 | */ 19 | extern CGFloat POPAnimationDragCoefficient(void); 20 | 21 | @interface CAAnimation (POPAnimationExtras) 22 | 23 | /** 24 | @abstract Apply the current drag coefficient to animation speed. 25 | @discussion Convenience utility to respect Simulator slow-motion animation settings. 26 | */ 27 | - (void)pop_applyDragCoefficient; 28 | 29 | @end 30 | 31 | @interface POPSpringAnimation (POPAnimationExtras) 32 | 33 | /** 34 | @abstract Converts from spring bounciness and speed to tension, friction and mass dynamics values. 35 | */ 36 | + (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass; 37 | 38 | /** 39 | @abstract Converts from dynamics tension, friction and mass to spring bounciness and speed values. 40 | */ 41 | + (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /pop/POPAnimationExtras.mm: -------------------------------------------------------------------------------- 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 | #import "POPAnimationExtras.h" 11 | #import "POPAnimationPrivate.h" 12 | 13 | #if TARGET_OS_IPHONE 14 | #import 15 | #endif 16 | 17 | #if TARGET_IPHONE_SIMULATOR 18 | UIKIT_EXTERN float UIAnimationDragCoefficient(); // UIKit private drag coefficient, use judiciously 19 | #endif 20 | 21 | #import "POPMath.h" 22 | 23 | CGFloat POPAnimationDragCoefficient() 24 | { 25 | #if TARGET_IPHONE_SIMULATOR 26 | return UIAnimationDragCoefficient(); 27 | #else 28 | return 1.0; 29 | #endif 30 | } 31 | 32 | @implementation CAAnimation (POPAnimationExtras) 33 | 34 | - (void)pop_applyDragCoefficient 35 | { 36 | CGFloat k = POPAnimationDragCoefficient(); 37 | if (k != 0 && k != 1) 38 | self.speed = 1 / k; 39 | } 40 | 41 | @end 42 | 43 | @implementation POPSpringAnimation (POPAnimationExtras) 44 | 45 | static const CGFloat POPBouncy3NormalizationRange = 20.0; 46 | static const CGFloat POPBouncy3NormalizationScale = 1.7; 47 | static const CGFloat POPBouncy3BouncinessNormalizedMin = 0.0; 48 | static const CGFloat POPBouncy3BouncinessNormalizedMax = 0.8; 49 | static const CGFloat POPBouncy3SpeedNormalizedMin = 0.5; 50 | static const CGFloat POPBouncy3SpeedNormalizedMax = 200; 51 | static const CGFloat POPBouncy3FrictionInterpolationMax = 0.01; 52 | 53 | + (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass 54 | { 55 | double b = POPNormalize(bounciness / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange); 56 | b = POPProjectNormal(b, POPBouncy3BouncinessNormalizedMin, POPBouncy3BouncinessNormalizedMax); 57 | 58 | double s = POPNormalize(speed / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange); 59 | 60 | CGFloat tension = POPProjectNormal(s, POPBouncy3SpeedNormalizedMin, POPBouncy3SpeedNormalizedMax); 61 | CGFloat friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax); 62 | 63 | tension = POP_ANIMATION_TENSION_FOR_QC_TENSION(tension); 64 | friction = POP_ANIMATION_FRICTION_FOR_QC_FRICTION(friction); 65 | 66 | if (outTension) { 67 | *outTension = tension; 68 | } 69 | 70 | if (outFriction) { 71 | *outFriction = friction; 72 | } 73 | 74 | if (outMass) { 75 | *outMass = 1.0; 76 | } 77 | } 78 | 79 | + (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed 80 | { 81 | // Convert to QC values, in which our calculations are done. 82 | CGFloat qcFriction = QC_FRICTION_FOR_POP_ANIMATION_FRICTION(friction); 83 | CGFloat qcTension = QC_TENSION_FOR_POP_ANIMATION_TENSION(tension); 84 | 85 | // Friction is a function of bounciness and tension, according to the following: 86 | // friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax); 87 | // Solve for bounciness, given a tension and friction. 88 | 89 | CGFloat nobounceTension = POPBouncy3NoBounce(qcTension); 90 | CGFloat bounciness1, bounciness2; 91 | 92 | POPQuadraticSolve((nobounceTension - POPBouncy3FrictionInterpolationMax), // a 93 | 2 * (POPBouncy3FrictionInterpolationMax - nobounceTension), // b 94 | (nobounceTension - qcFriction), // c 95 | bounciness1, // x1 96 | bounciness2); // x2 97 | 98 | 99 | // Choose the quadratic solution within the normalized bounciness range 100 | CGFloat projectedNormalizedBounciness = (bounciness2 < POPBouncy3BouncinessNormalizedMax) ? bounciness2 : bounciness1; 101 | CGFloat projectedNormalizedSpeed = qcTension; 102 | 103 | // Reverse projection + normalization 104 | CGFloat bounciness = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3BouncinessNormalizedMax - POPBouncy3BouncinessNormalizedMin)) * (projectedNormalizedBounciness - POPBouncy3BouncinessNormalizedMin); 105 | CGFloat speed = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3SpeedNormalizedMax - POPBouncy3SpeedNormalizedMin)) * (projectedNormalizedSpeed - POPBouncy3SpeedNormalizedMin); 106 | 107 | // Write back results 108 | if (outBounciness) { 109 | *outBounciness = bounciness; 110 | } 111 | 112 | if (outSpeed) { 113 | *outSpeed = speed; 114 | } 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /pop/POPAnimationPrivate.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #define POP_ANIMATION_FRICTION_FOR_QC_FRICTION(qcFriction) (25.0 + (((qcFriction - 8.0) / 2.0) * (25.0 - 19.0))) 13 | #define POP_ANIMATION_TENSION_FOR_QC_TENSION(qcTension) (194.0 + (((qcTension - 30.0) / 50.0) * (375.0 - 194.0))) 14 | 15 | #define QC_FRICTION_FOR_POP_ANIMATION_FRICTION(fbFriction) (8.0 + 2.0 * ((fbFriction - 25.0)/(25.0 - 19.0))) 16 | #define QC_TENSION_FOR_POP_ANIMATION_TENSION(fbTension) (30.0 + 50.0 * ((fbTension - 194.0)/(375.0 - 194.0))) 17 | -------------------------------------------------------------------------------- /pop/POPAnimationRuntime.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | #import 14 | 15 | #import "POPAnimatablePropertyTypes.h" 16 | #import "POPVector.h" 17 | 18 | enum POPValueType 19 | { 20 | kPOPValueUnknown = 0, 21 | kPOPValueInteger, 22 | kPOPValueFloat, 23 | kPOPValuePoint, 24 | kPOPValueSize, 25 | kPOPValueRect, 26 | kPOPValueEdgeInsets, 27 | kPOPValueAffineTransform, 28 | kPOPValueTransform, 29 | kPOPValueRange, 30 | kPOPValueColor, 31 | kPOPValueSCNVector3, 32 | kPOPValueSCNVector4, 33 | }; 34 | 35 | using namespace POP; 36 | 37 | /** 38 | Returns value type based on objc type description, given list of supported value types and length. 39 | */ 40 | extern POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length); 41 | 42 | /** 43 | Returns value type based on objc object, given a list of supported value types and length. 44 | */ 45 | extern POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length); 46 | 47 | /** 48 | Array of all value types. 49 | */ 50 | extern const POPValueType kPOPAnimatableAllTypes[12]; 51 | 52 | /** 53 | Array of all value types supported for animation. 54 | */ 55 | extern const POPValueType kPOPAnimatableSupportTypes[10]; 56 | 57 | /** 58 | Returns a string description of a value type. 59 | */ 60 | extern NSString *POPValueTypeToString(POPValueType t); 61 | 62 | /** 63 | Returns a mutable dictionary of weak pointer keys to weak pointer values. 64 | */ 65 | extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity) CF_RETURNS_RETAINED; 66 | 67 | /** 68 | Returns a mutable dictionary of weak pointer keys to weak pointer values. 69 | */ 70 | extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity) CF_RETURNS_RETAINED; 71 | 72 | /** 73 | Box a vector. 74 | */ 75 | extern id POPBox(VectorConstRef vec, POPValueType type, bool force = false); 76 | 77 | /** 78 | Unbox a vector. 79 | */ 80 | extern VectorRef POPUnbox(id value, POPValueType &type, NSUInteger &count, bool validate); 81 | 82 | /** 83 | Read object value and return a Vector4r. 84 | */ 85 | NS_INLINE Vector4r read_values(POPAnimatablePropertyReadBlock read, id obj, size_t count) 86 | { 87 | Vector4r vec = Vector4r::Zero(); 88 | if (0 == count) 89 | return vec; 90 | 91 | read(obj, vec.data()); 92 | 93 | return vec; 94 | } 95 | 96 | NS_INLINE NSString *POPStringFromBOOL(BOOL value) 97 | { 98 | return value ? @"YES" : @"NO"; 99 | } 100 | -------------------------------------------------------------------------------- /pop/POPAnimationTracer.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | @class POPAnimation; 15 | 16 | /** 17 | @abstract Tracer of animation events to facilitate unit testing & debugging. 18 | */ 19 | @interface POPAnimationTracer : NSObject 20 | 21 | /** 22 | @abstract Start recording events. 23 | */ 24 | - (void)start; 25 | 26 | /** 27 | @abstract Stop recording events. 28 | */ 29 | - (void)stop; 30 | 31 | /** 32 | @abstract Resets any recoded events. Continues recording events if already started. 33 | */ 34 | - (void)reset; 35 | 36 | /** 37 | @abstract Property representing all recorded events. 38 | @discussion Events are returned in order of occurrence. 39 | */ 40 | @property (nonatomic, assign, readonly) NSArray *allEvents; 41 | 42 | /** 43 | @abstract Property representing all recorded write events for convenience. 44 | @discussion Events are returned in order of occurrence. 45 | */ 46 | @property (nonatomic, assign, readonly) NSArray *writeEvents; 47 | 48 | /** 49 | @abstract Queries for events of specified type. 50 | @param type The type of event to return. 51 | @returns An array of events of specified type in order of occurrence. 52 | */ 53 | - (NSArray *)eventsWithType:(POPAnimationEventType)type; 54 | 55 | /** 56 | @abstract Property indicating whether tracer should automatically log events and reset collection on animation completion. 57 | */ 58 | @property (nonatomic, assign) BOOL shouldLogAndResetOnCompletion; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /pop/POPAnimationTracer.mm: -------------------------------------------------------------------------------- 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 | #import "POPAnimationTracer.h" 11 | 12 | #import 13 | 14 | #import "POPAnimationEventInternal.h" 15 | #import "POPAnimationInternal.h" 16 | #import "POPSpringAnimation.h" 17 | 18 | @implementation POPAnimationTracer 19 | { 20 | __weak POPAnimation *_animation; 21 | POPAnimationState *_animationState; 22 | NSMutableArray *_events; 23 | BOOL _animationHasVelocity; 24 | } 25 | @synthesize shouldLogAndResetOnCompletion = _shouldLogAndResetOnCompletion; 26 | 27 | static POPAnimationEvent *create_event(POPAnimationTracer *self, POPAnimationEventType type, id value = nil, bool recordAnimation = false) 28 | { 29 | bool useLocalTime = 0 != self->_animationState->startTime; 30 | CFTimeInterval time = useLocalTime 31 | ? self->_animationState->lastTime - self->_animationState->startTime 32 | : self->_animationState->lastTime; 33 | 34 | POPAnimationEvent *event; 35 | __strong POPAnimation* animation = self->_animation; 36 | 37 | if (!value) { 38 | event = [[POPAnimationEvent alloc] initWithType:type time:time]; 39 | } else { 40 | event = [[POPAnimationValueEvent alloc] initWithType:type time:time value:value]; 41 | if (self->_animationHasVelocity) { 42 | [(POPAnimationValueEvent *)event setVelocity:[(POPSpringAnimation *)animation velocity]]; 43 | } 44 | } 45 | 46 | if (recordAnimation) { 47 | event.animationDescription = [animation description]; 48 | } 49 | 50 | return event; 51 | } 52 | 53 | - (id)initWithAnimation:(POPAnimation *)anAnim 54 | { 55 | self = [super init]; 56 | if (nil != self) { 57 | _animation = anAnim; 58 | _animationState = POPAnimationGetState(anAnim); 59 | _events = [[NSMutableArray alloc] initWithCapacity:50]; 60 | _animationHasVelocity = [anAnim respondsToSelector:@selector(velocity)]; 61 | } 62 | return self; 63 | } 64 | 65 | - (void)readPropertyValue:(id)aValue 66 | { 67 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyRead, aValue); 68 | [_events addObject:event]; 69 | } 70 | 71 | - (void)writePropertyValue:(id)aValue 72 | { 73 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyWrite, aValue); 74 | [_events addObject:event]; 75 | } 76 | 77 | - (void)updateToValue:(id)aValue 78 | { 79 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventToValueUpdate, aValue); 80 | [_events addObject:event]; 81 | } 82 | 83 | - (void)updateFromValue:(id)aValue 84 | { 85 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventFromValueUpdate, aValue); 86 | [_events addObject:event]; 87 | } 88 | 89 | - (void)updateVelocity:(id)aValue 90 | { 91 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventVelocityUpdate, aValue); 92 | [_events addObject:event]; 93 | } 94 | 95 | - (void)updateSpeed:(float)aFloat 96 | { 97 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventSpeedUpdate, @(aFloat)); 98 | [_events addObject:event]; 99 | } 100 | 101 | - (void)updateBounciness:(float)aFloat 102 | { 103 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventBouncinessUpdate, @(aFloat)); 104 | [_events addObject:event]; 105 | } 106 | 107 | - (void)updateFriction:(float)aFloat 108 | { 109 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventFrictionUpdate, @(aFloat)); 110 | [_events addObject:event]; 111 | } 112 | 113 | - (void)updateMass:(float)aFloat 114 | { 115 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventMassUpdate, @(aFloat)); 116 | [_events addObject:event]; 117 | } 118 | 119 | - (void)updateTension:(float)aFloat 120 | { 121 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventTensionUpdate, @(aFloat)); 122 | [_events addObject:event]; 123 | } 124 | 125 | - (void)didStart 126 | { 127 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStart, nil, true); 128 | [_events addObject:event]; 129 | } 130 | 131 | - (void)didStop:(BOOL)finished 132 | { 133 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStop, @(finished), true); 134 | [_events addObject:event]; 135 | 136 | if (_shouldLogAndResetOnCompletion) { 137 | NSLog(@"events:%@", self.allEvents); 138 | [self reset]; 139 | } 140 | } 141 | 142 | - (void)didReachToValue:(id)aValue 143 | { 144 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidReachToValue, aValue); 145 | [_events addObject:event]; 146 | } 147 | 148 | - (void)autoreversed 149 | { 150 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventAutoreversed); 151 | [_events addObject:event]; 152 | } 153 | 154 | - (void)start 155 | { 156 | POPAnimationState *s = POPAnimationGetState(_animation); 157 | s->tracing = true; 158 | } 159 | 160 | - (void)stop 161 | { 162 | POPAnimationState *s = POPAnimationGetState(_animation); 163 | s->tracing = false; 164 | } 165 | 166 | - (void)reset 167 | { 168 | [_events removeAllObjects]; 169 | } 170 | 171 | - (NSArray *)allEvents 172 | { 173 | return [_events copy]; 174 | } 175 | 176 | - (NSArray *)writeEvents 177 | { 178 | return [self eventsWithType:kPOPAnimationEventPropertyWrite]; 179 | } 180 | 181 | - (NSArray *)eventsWithType:(POPAnimationEventType)aType 182 | { 183 | NSMutableArray *array = [NSMutableArray array]; 184 | for (POPAnimationEvent *event in _events) { 185 | if (aType == event.type) { 186 | [array addObject:event]; 187 | } 188 | } 189 | return array; 190 | } 191 | 192 | @end 193 | -------------------------------------------------------------------------------- /pop/POPAnimationTracerInternal.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | @interface POPAnimationTracer (Internal) 15 | 16 | /** 17 | @abstract Designated initializer. Pass the animation being traced. 18 | */ 19 | - (instancetype)initWithAnimation:(POPAnimation *)anAnim; 20 | 21 | /** 22 | @abstract Records read value. 23 | */ 24 | - (void)readPropertyValue:(id)aValue; 25 | 26 | /** 27 | @abstract Records write value. 28 | */ 29 | - (void)writePropertyValue:(id)aValue; 30 | 31 | /** 32 | Records to value update. 33 | */ 34 | - (void)updateToValue:(id)aValue; 35 | 36 | /** 37 | @abstract Records from value update. 38 | */ 39 | - (void)updateFromValue:(id)aValue; 40 | 41 | /** 42 | @abstract Records from value update. 43 | */ 44 | - (void)updateVelocity:(id)aValue; 45 | 46 | /** 47 | @abstract Records bounciness update. 48 | */ 49 | - (void)updateBounciness:(float)aFloat; 50 | 51 | /** 52 | @abstract Records speed update. 53 | */ 54 | - (void)updateSpeed:(float)aFloat; 55 | 56 | /** 57 | @abstract Records friction update. 58 | */ 59 | - (void)updateFriction:(float)aFloat; 60 | 61 | /** 62 | @abstract Records mass update. 63 | */ 64 | - (void)updateMass:(float)aFloat; 65 | 66 | /** 67 | @abstract Records tension update. 68 | */ 69 | - (void)updateTension:(float)aFloat; 70 | 71 | /** 72 | @abstract Records did add. 73 | */ 74 | - (void)didAdd; 75 | 76 | /** 77 | @abstract Records did start. 78 | */ 79 | - (void)didStart; 80 | 81 | /** 82 | @abstract Records did stop. 83 | */ 84 | - (void)didStop:(BOOL)finished; 85 | 86 | /** 87 | @abstract Records did reach to value. 88 | */ 89 | - (void)didReachToValue:(id)aValue; 90 | 91 | /** 92 | @abstract Records when an autoreverse animation takes place. 93 | */ 94 | - (void)autoreversed; 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /pop/POPAnimator.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | @protocol POPAnimatorDelegate; 13 | 14 | /** 15 | @abstract The animator class renders animations. 16 | */ 17 | @interface POPAnimator : NSObject 18 | 19 | /** 20 | @abstract The shared animator instance. 21 | @discussion Consumers should generally use the shared instance in lieu of creating new instances. 22 | */ 23 | + (instancetype)sharedAnimator; 24 | 25 | #if !TARGET_OS_IPHONE 26 | /** 27 | @abstract Allows to select display to bind. Returns nil if failed to create the display link. 28 | */ 29 | - (instancetype)initWithDisplayID:(CGDirectDisplayID)displayID; 30 | #endif 31 | 32 | /** 33 | @abstract The optional animator delegate. 34 | */ 35 | @property (weak, nonatomic) id delegate; 36 | 37 | /** 38 | @abstract Retrieves the nominal refresh period of a display link. Returns zero if unavailable. 39 | */ 40 | @property (readonly, nonatomic) CFTimeInterval refreshPeriod; 41 | 42 | @end 43 | 44 | /** 45 | @abstract The animator delegate. 46 | */ 47 | @protocol POPAnimatorDelegate 48 | 49 | /** 50 | @abstract Called on each frame before animation application. 51 | */ 52 | - (void)animatorWillAnimate:(POPAnimator *)animator; 53 | 54 | /** 55 | @abstract Called on each frame after animation application. 56 | */ 57 | - (void)animatorDidAnimate:(POPAnimator *)animator; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /pop/POPAnimatorPrivate.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | @class POPAnimation; 13 | 14 | @protocol POPAnimatorObserving 15 | @required 16 | 17 | /** 18 | @abstract Called on each observer after animator has advanced. Core Animation actions are disabled by default. 19 | */ 20 | - (void)animatorDidAnimate:(POPAnimator *)animator; 21 | 22 | @end 23 | 24 | @interface POPAnimator () 25 | 26 | #if !TARGET_OS_IPHONE 27 | /** 28 | Determines whether or not to use a high priority background thread for animation updates. Using a background thread can result in faster, more responsive updates, but may be less compatible. Defaults to YES. 29 | */ 30 | + (BOOL)disableBackgroundThread; 31 | + (void)setDisableBackgroundThread:(BOOL)flag; 32 | 33 | /** 34 | Determines the frequency (Hz) of the timer used when no display is available. Defaults to 60Hz. 35 | */ 36 | + (uint64_t)displayTimerFrequency; 37 | + (void)setDisplayTimerFrequency:(uint64_t)frequency; 38 | #endif 39 | 40 | /** 41 | Used for externally driven animator instances. 42 | */ 43 | @property (assign, nonatomic) BOOL disableDisplayLink; 44 | 45 | /** 46 | Time used when starting animations. Defaults to 0 meaning current media time is used. Exposed for unit testing. 47 | */ 48 | @property (assign, nonatomic) CFTimeInterval beginTime; 49 | 50 | /** 51 | Exposed for unit testing. 52 | */ 53 | - (void)renderTime:(CFTimeInterval)time; 54 | 55 | /** 56 | Funnel methods for category additions. 57 | */ 58 | - (void)addAnimation:(POPAnimation *)anim forObject:(id)obj key:(NSString *)key; 59 | - (void)removeAllAnimationsForObject:(id)obj; 60 | - (void)removeAnimationForObject:(id)obj key:(NSString *)key; 61 | - (NSArray *)animationKeysForObject:(id)obj; 62 | - (POPAnimation *)animationForObject:(id)obj key:(NSString *)key; 63 | 64 | /** 65 | @abstract Add an animator observer. Observer will be notified of each subsequent animator advance until removal. 66 | */ 67 | - (void)addObserver:(id)observer; 68 | 69 | /** 70 | @abstract Remove an animator observer. 71 | */ 72 | - (void)removeObserver:(id)observer; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /pop/POPBasicAnimation.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | /** 13 | @abstract A concrete basic animation class. 14 | @discussion Animation is achieved through interpolation. 15 | */ 16 | @interface POPBasicAnimation : POPPropertyAnimation 17 | 18 | /** 19 | @abstract The designated initializer. 20 | @returns An instance of a basic animation. 21 | */ 22 | + (instancetype)animation; 23 | 24 | /** 25 | @abstract Convenience initializer that returns an animation with animatable property of name. 26 | @param name The name of the animatable property. 27 | @returns An instance of a basic animation configured with specified animatable property. 28 | */ 29 | + (instancetype)animationWithPropertyNamed:(NSString *)name; 30 | 31 | /** 32 | @abstract Convenience constructor. 33 | @returns Returns a basic animation with kCAMediaTimingFunctionDefault timing function. 34 | */ 35 | + (instancetype)defaultAnimation; 36 | 37 | /** 38 | @abstract Convenience constructor. 39 | @returns Returns a basic animation with kCAMediaTimingFunctionLinear timing function. 40 | */ 41 | + (instancetype)linearAnimation; 42 | 43 | /** 44 | @abstract Convenience constructor. 45 | @returns Returns a basic animation with kCAMediaTimingFunctionEaseIn timing function. 46 | */ 47 | + (instancetype)easeInAnimation; 48 | 49 | /** 50 | @abstract Convenience constructor. 51 | @returns Returns a basic animation with kCAMediaTimingFunctionEaseOut timing function. 52 | */ 53 | + (instancetype)easeOutAnimation; 54 | 55 | /** 56 | @abstract Convenience constructor. 57 | @returns Returns a basic animation with kCAMediaTimingFunctionEaseInEaseOut timing function. 58 | */ 59 | + (instancetype)easeInEaseOutAnimation; 60 | 61 | /** 62 | @abstract The duration in seconds. Defaults to 0.4. 63 | */ 64 | @property (assign, nonatomic) CFTimeInterval duration; 65 | 66 | /** 67 | @abstract A timing function defining the pacing of the animation. Defaults to nil indicating pacing according to kCAMediaTimingFunctionDefault. 68 | */ 69 | @property (strong, nonatomic) CAMediaTimingFunction *timingFunction; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /pop/POPBasicAnimation.mm: -------------------------------------------------------------------------------- 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 | #import "POPBasicAnimationInternal.h" 11 | 12 | @implementation POPBasicAnimation 13 | 14 | #undef __state 15 | #define __state ((POPBasicAnimationState *)_state) 16 | 17 | #pragma mark - Lifecycle 18 | 19 | + (instancetype)animation 20 | { 21 | return [[self alloc] init]; 22 | } 23 | 24 | + (instancetype)animationWithPropertyNamed:(NSString *)aName 25 | { 26 | POPBasicAnimation *anim = [self animation]; 27 | anim.property = [POPAnimatableProperty propertyWithName:aName]; 28 | return anim; 29 | } 30 | 31 | - (void)_initState 32 | { 33 | _state = new POPBasicAnimationState(self); 34 | } 35 | 36 | + (instancetype)linearAnimation 37 | { 38 | POPBasicAnimation *anim = [self animation]; 39 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 40 | return anim; 41 | } 42 | 43 | + (instancetype)easeInAnimation 44 | { 45 | POPBasicAnimation *anim = [self animation]; 46 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; 47 | return anim; 48 | } 49 | 50 | + (instancetype)easeOutAnimation 51 | { 52 | POPBasicAnimation *anim = [self animation]; 53 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 54 | return anim; 55 | } 56 | 57 | + (instancetype)easeInEaseOutAnimation 58 | { 59 | POPBasicAnimation *anim = [self animation]; 60 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 61 | return anim; 62 | } 63 | 64 | + (instancetype)defaultAnimation 65 | { 66 | POPBasicAnimation *anim = [self animation]; 67 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; 68 | return anim; 69 | } 70 | 71 | - (id)init 72 | { 73 | return [self _init]; 74 | } 75 | 76 | #pragma mark - Properties 77 | 78 | DEFINE_RW_PROPERTY(POPBasicAnimationState, duration, setDuration:, CFTimeInterval); 79 | DEFINE_RW_PROPERTY_OBJ(POPBasicAnimationState, timingFunction, setTimingFunction:, CAMediaTimingFunction*, __state->updatedTimingFunction();); 80 | 81 | #pragma mark - Utility 82 | 83 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug 84 | { 85 | [super _appendDescription:s debug:debug]; 86 | if (__state->duration) 87 | [s appendFormat:@"; duration = %f", __state->duration]; 88 | } 89 | 90 | @end 91 | 92 | @implementation POPBasicAnimation (NSCopying) 93 | 94 | - (instancetype)copyWithZone:(NSZone *)zone { 95 | 96 | POPBasicAnimation *copy = [super copyWithZone:zone]; 97 | 98 | if (copy) { 99 | copy.duration = self.duration; 100 | copy.timingFunction = self.timingFunction; // not a 'copy', but timing functions are publicly immutable. 101 | } 102 | 103 | return copy; 104 | } 105 | 106 | @end -------------------------------------------------------------------------------- /pop/POPBasicAnimationInternal.h: -------------------------------------------------------------------------------- 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 | #import "POPBasicAnimation.h" 11 | 12 | #import "POPPropertyAnimationInternal.h" 13 | 14 | // default animation duration 15 | static CGFloat const kPOPAnimationDurationDefault = 0.4; 16 | 17 | // progress threshold for computing done 18 | static CGFloat const kPOPProgressThreshold = 1e-6; 19 | 20 | static void interpolate(POPValueType valueType, NSUInteger count, const CGFloat *fromVec, const CGFloat *toVec, CGFloat *outVec, CGFloat p) 21 | { 22 | switch (valueType) { 23 | case kPOPValueInteger: 24 | case kPOPValueFloat: 25 | case kPOPValuePoint: 26 | case kPOPValueSize: 27 | case kPOPValueRect: 28 | case kPOPValueEdgeInsets: 29 | case kPOPValueColor: 30 | POPInterpolateVector(count, outVec, fromVec, toVec, p); 31 | break; 32 | default: 33 | NSCAssert(false, @"unhandled type %d", valueType); 34 | break; 35 | } 36 | } 37 | 38 | struct _POPBasicAnimationState : _POPPropertyAnimationState 39 | { 40 | CAMediaTimingFunction *timingFunction; 41 | double timingControlPoints[4]; 42 | CFTimeInterval duration; 43 | CFTimeInterval timeProgress; 44 | 45 | _POPBasicAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim), 46 | timingFunction(nil), 47 | timingControlPoints{0.}, 48 | duration(kPOPAnimationDurationDefault), 49 | timeProgress(0.) 50 | { 51 | type = kPOPAnimationBasic; 52 | } 53 | 54 | bool isDone() { 55 | if (_POPPropertyAnimationState::isDone()) { 56 | return true; 57 | } 58 | return timeProgress + kPOPProgressThreshold >= 1.; 59 | } 60 | 61 | void updatedTimingFunction() 62 | { 63 | float vec[4] = {0.}; 64 | [timingFunction getControlPointAtIndex:1 values:&vec[0]]; 65 | [timingFunction getControlPointAtIndex:2 values:&vec[2]]; 66 | for (NSUInteger idx = 0; idx < POP_ARRAY_COUNT(vec); idx++) { 67 | timingControlPoints[idx] = vec[idx]; 68 | } 69 | } 70 | 71 | bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { 72 | // default timing function 73 | if (!timingFunction) { 74 | ((POPBasicAnimation *)self).timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; 75 | } 76 | 77 | // solve for normalized time, aka progress [0, 1] 78 | CGFloat p = 1.0f; 79 | if (duration > 0.0f) { 80 | // cap local time to duration 81 | CFTimeInterval t = MIN(time - startTime, duration) / duration; 82 | p = POPTimingFunctionSolve(timingControlPoints, t, SOLVE_EPS(duration)); 83 | timeProgress = t; 84 | } else { 85 | timeProgress = 1.; 86 | } 87 | 88 | // interpolate and advance 89 | interpolate(valueType, valueCount, fromVec->data(), toVec->data(), currentVec->data(), p); 90 | progress = p; 91 | clampCurrentValue(); 92 | 93 | return true; 94 | } 95 | }; 96 | 97 | typedef struct _POPBasicAnimationState POPBasicAnimationState; 98 | -------------------------------------------------------------------------------- /pop/POPCGUtils.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #if TARGET_OS_IPHONE 13 | #import 14 | #else 15 | #import 16 | #endif 17 | 18 | #import "POPDefines.h" 19 | 20 | #if SCENEKIT_SDK_AVAILABLE 21 | #import 22 | #endif 23 | 24 | POP_EXTERN_C_BEGIN 25 | 26 | NS_INLINE CGPoint values_to_point(const CGFloat values[]) 27 | { 28 | return CGPointMake(values[0], values[1]); 29 | } 30 | 31 | NS_INLINE CGSize values_to_size(const CGFloat values[]) 32 | { 33 | return CGSizeMake(values[0], values[1]); 34 | } 35 | 36 | NS_INLINE CGRect values_to_rect(const CGFloat values[]) 37 | { 38 | return CGRectMake(values[0], values[1], values[2], values[3]); 39 | } 40 | 41 | #if SCENEKIT_SDK_AVAILABLE 42 | NS_INLINE SCNVector3 values_to_vec3(const CGFloat values[]) 43 | { 44 | return SCNVector3Make(values[0], values[1], values[2]); 45 | } 46 | 47 | NS_INLINE SCNVector4 values_to_vec4(const CGFloat values[]) 48 | { 49 | return SCNVector4Make(values[0], values[1], values[2], values[3]); 50 | } 51 | #endif 52 | 53 | #if TARGET_OS_IPHONE 54 | 55 | NS_INLINE UIEdgeInsets values_to_edge_insets(const CGFloat values[]) 56 | { 57 | return UIEdgeInsetsMake(values[0], values[1], values[2], values[3]); 58 | } 59 | 60 | #endif 61 | 62 | NS_INLINE void values_from_point(CGFloat values[], CGPoint p) 63 | { 64 | values[0] = p.x; 65 | values[1] = p.y; 66 | } 67 | 68 | NS_INLINE void values_from_size(CGFloat values[], CGSize s) 69 | { 70 | values[0] = s.width; 71 | values[1] = s.height; 72 | } 73 | 74 | NS_INLINE void values_from_rect(CGFloat values[], CGRect r) 75 | { 76 | values[0] = r.origin.x; 77 | values[1] = r.origin.y; 78 | values[2] = r.size.width; 79 | values[3] = r.size.height; 80 | } 81 | 82 | #if SCENEKIT_SDK_AVAILABLE 83 | NS_INLINE void values_from_vec3(CGFloat values[], SCNVector3 v) 84 | { 85 | values[0] = v.x; 86 | values[1] = v.y; 87 | values[2] = v.z; 88 | } 89 | 90 | NS_INLINE void values_from_vec4(CGFloat values[], SCNVector4 v) 91 | { 92 | values[0] = v.x; 93 | values[1] = v.y; 94 | values[2] = v.z; 95 | values[3] = v.w; 96 | } 97 | #endif 98 | 99 | #if TARGET_OS_IPHONE 100 | 101 | NS_INLINE void values_from_edge_insets(CGFloat values[], UIEdgeInsets i) 102 | { 103 | values[0] = i.top; 104 | values[1] = i.left; 105 | values[2] = i.bottom; 106 | values[3] = i.right; 107 | } 108 | 109 | #endif 110 | 111 | /** 112 | Takes a CGColorRef and converts it into RGBA components, if necessary. 113 | */ 114 | extern void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]); 115 | 116 | /** 117 | Takes RGBA components and returns a CGColorRef. 118 | */ 119 | extern CGColorRef POPCGColorRGBACreate(const CGFloat components[]) CF_RETURNS_RETAINED; 120 | 121 | /** 122 | Takes a color reference and returns a CGColor. 123 | */ 124 | extern CGColorRef POPCGColorWithColor(id color) CF_RETURNS_NOT_RETAINED; 125 | 126 | #if TARGET_OS_IPHONE 127 | 128 | /** 129 | Takes a UIColor and converts it into RGBA components, if necessary. 130 | */ 131 | extern void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]); 132 | 133 | /** 134 | Takes RGBA components and returns a UIColor. 135 | */ 136 | extern UIColor *POPUIColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED; 137 | 138 | #else 139 | 140 | /** 141 | Takes a NSColor and converts it into RGBA components, if necessary. 142 | */ 143 | extern void POPNSColorGetRGBAComponents(NSColor *color, CGFloat components[]); 144 | 145 | /** 146 | Takes RGBA components and returns a NSColor. 147 | */ 148 | extern NSColor *POPNSColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED; 149 | 150 | #endif 151 | 152 | POP_EXTERN_C_END 153 | -------------------------------------------------------------------------------- /pop/POPCGUtils.mm: -------------------------------------------------------------------------------- 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 | #import "POPCGUtils.h" 11 | 12 | #import 13 | 14 | void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]) 15 | { 16 | if (color) { 17 | const CGFloat *colors = CGColorGetComponents(color); 18 | size_t count = CGColorGetNumberOfComponents(color); 19 | 20 | if (4 == count) { 21 | // RGB colorspace 22 | components[0] = colors[0]; 23 | components[1] = colors[1]; 24 | components[2] = colors[2]; 25 | components[3] = colors[3]; 26 | } else if (2 == count) { 27 | // Grey colorspace 28 | components[0] = components[1] = components[2] = colors[0]; 29 | components[3] = colors[1]; 30 | } else { 31 | // Use CI to convert 32 | CIColor *ciColor = [CIColor colorWithCGColor:color]; 33 | components[0] = ciColor.red; 34 | components[1] = ciColor.green; 35 | components[2] = ciColor.blue; 36 | components[3] = ciColor.alpha; 37 | } 38 | } else { 39 | memset(components, 0, 4 * sizeof(components[0])); 40 | } 41 | } 42 | 43 | CGColorRef POPCGColorRGBACreate(const CGFloat components[]) 44 | { 45 | #if TARGET_OS_IPHONE 46 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 47 | CGColorRef color = CGColorCreate(space, components); 48 | CGColorSpaceRelease(space); 49 | return color; 50 | #else 51 | return CGColorCreateGenericRGB(components[0], components[1], components[2], components[3]); 52 | #endif 53 | } 54 | 55 | CGColorRef POPCGColorWithColor(id color) 56 | { 57 | if (CFGetTypeID((__bridge CFTypeRef)color) == CGColorGetTypeID()) { 58 | return ((__bridge CGColorRef)color); 59 | } 60 | #if TARGET_OS_IPHONE 61 | else if ([color isKindOfClass:[UIColor class]]) { 62 | return [color CGColor]; 63 | } 64 | #else 65 | else if ([color isKindOfClass:[NSColor class]]) { 66 | // -[NSColor CGColor] is only supported since OSX 10.8+ 67 | if ([color respondsToSelector:@selector(CGColor)]) { 68 | return [color CGColor]; 69 | } 70 | 71 | /* 72 | * Otherwise create a CGColorRef manually. 73 | * 74 | * The original accessor is (or would be) declared as: 75 | * @property(readonly) CGColorRef CGColor; 76 | * - (CGColorRef)CGColor NS_RETURNS_INNER_POINTER CF_RETURNS_NOT_RETAINED; 77 | * 78 | * (Please note that OSX' accessor is atomic, while iOS' isn't.) 79 | * 80 | * The access to the NSColor object must thus be synchronized 81 | * and the CGColorRef be stored as an associated object, 82 | * to return a reference which doesn't need to be released manually. 83 | */ 84 | @synchronized(color) { 85 | static const void* key = &key; 86 | 87 | CGColorRef colorRef = (__bridge CGColorRef)objc_getAssociatedObject(color, key); 88 | 89 | if (!colorRef) { 90 | size_t numberOfComponents = [(NSColor *)color numberOfComponents]; 91 | CGFloat components[numberOfComponents]; 92 | CGColorSpaceRef colorSpace = [[(NSColor *)color colorSpace] CGColorSpace]; 93 | 94 | [color getComponents:components]; 95 | 96 | colorRef = CGColorCreate(colorSpace, components); 97 | 98 | objc_setAssociatedObject(color, key, (__bridge id)colorRef, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 99 | CGColorRelease(colorRef); 100 | } 101 | 102 | return colorRef; 103 | } 104 | } 105 | #endif 106 | return nil; 107 | } 108 | 109 | #if TARGET_OS_IPHONE 110 | 111 | void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]) 112 | { 113 | return POPCGColorGetRGBAComponents(POPCGColorWithColor(color), components); 114 | } 115 | 116 | UIColor *POPUIColorRGBACreate(const CGFloat components[]) 117 | { 118 | CGColorRef colorRef = POPCGColorRGBACreate(components); 119 | UIColor *color = [[UIColor alloc] initWithCGColor:colorRef]; 120 | CGColorRelease(colorRef); 121 | return color; 122 | } 123 | 124 | #else 125 | 126 | void POPNSColorGetRGBAComponents(NSColor *color, CGFloat components[]) 127 | { 128 | return POPCGColorGetRGBAComponents(POPCGColorWithColor(color), components); 129 | } 130 | 131 | NSColor *POPNSColorRGBACreate(const CGFloat components[]) 132 | { 133 | CGColorRef colorRef = POPCGColorRGBACreate(components); 134 | NSColor *color = nil; 135 | 136 | if (colorRef) { 137 | if ([NSColor respondsToSelector:@selector(colorWithCGColor:)]) { 138 | color = [NSColor colorWithCGColor:colorRef]; 139 | } else { 140 | color = [NSColor colorWithCIColor:[CIColor colorWithCGColor:colorRef]]; 141 | } 142 | 143 | CGColorRelease(colorRef); 144 | } 145 | 146 | return color; 147 | } 148 | 149 | #endif 150 | 151 | -------------------------------------------------------------------------------- /pop/POPCustomAnimation.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | @class POPCustomAnimation; 13 | 14 | /** 15 | @abstract POPCustomAnimationBlock is the callback block of a custom animation. 16 | @discussion This block will be executed for each animation frame and should update the property or properties being animated based on current timing. 17 | @param target The object being animated. Reference the passed in target to help avoid retain loops. 18 | @param animation The custom animation instance. Use to determine the current and elapsed time since last callback. Reference the passed in animation to help avoid retain loops. 19 | @return Flag indicating whether the animation should continue animating. Return NO to indicate animation is done. 20 | */ 21 | typedef BOOL (^POPCustomAnimationBlock)(id target, POPCustomAnimation *animation); 22 | 23 | /** 24 | @abstract POPCustomAnimation is a concrete animation subclass for custom animations. 25 | */ 26 | @interface POPCustomAnimation : POPAnimation 27 | 28 | /** 29 | @abstract Creates and returns an initialized custom animation instance. 30 | @discussion This is the designated initializer. 31 | @param block The custom animation callback block. See {@ref POPCustomAnimationBlock}. 32 | @return The initialized custom animation instance. 33 | */ 34 | + (instancetype)animationWithBlock:(POPCustomAnimationBlock)block; 35 | 36 | /** 37 | @abstract The current animation time at time of callback. 38 | */ 39 | @property (readonly, nonatomic) CFTimeInterval currentTime; 40 | 41 | /** 42 | @abstract The elapsed animation time since last callback. 43 | */ 44 | @property (readonly, nonatomic) CFTimeInterval elapsedTime; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /pop/POPCustomAnimation.mm: -------------------------------------------------------------------------------- 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 | #import "POPAnimationInternal.h" 11 | 12 | #import "POPCustomAnimation.h" 13 | 14 | @interface POPCustomAnimation () 15 | @property (nonatomic, copy) POPCustomAnimationBlock animate; 16 | @end 17 | 18 | @implementation POPCustomAnimation 19 | @synthesize currentTime = _currentTime; 20 | @synthesize elapsedTime = _elapsedTime; 21 | @synthesize animate = _animate; 22 | 23 | + (instancetype)animationWithBlock:(BOOL(^)(id target, POPCustomAnimation *))block 24 | { 25 | POPCustomAnimation *b = [[self alloc] _init]; 26 | b.animate = block; 27 | return b; 28 | } 29 | 30 | - (id)_init 31 | { 32 | self = [super _init]; 33 | if (nil != self) { 34 | _state->type = kPOPAnimationCustom; 35 | } 36 | return self; 37 | } 38 | 39 | - (CFTimeInterval)beginTime 40 | { 41 | POPAnimationState *s = POPAnimationGetState(self); 42 | return s->startTime > 0 ? s->startTime : s->beginTime; 43 | } 44 | 45 | - (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime 46 | { 47 | _currentTime = currentTime; 48 | _elapsedTime = elapsedTime; 49 | return _animate(object, self); 50 | } 51 | 52 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug 53 | { 54 | [s appendFormat:@"; elapsedTime = %f; currentTime = %f;", _elapsedTime, _currentTime]; 55 | } 56 | 57 | @end 58 | 59 | /** 60 | * Note that only the animate block is copied, but not the current/elapsed times 61 | */ 62 | @implementation POPCustomAnimation (NSCopying) 63 | 64 | - (instancetype)copyWithZone:(NSZone *)zone { 65 | 66 | POPCustomAnimation *copy = [super copyWithZone:zone]; 67 | 68 | if (copy) { 69 | copy.animate = self.animate; 70 | } 71 | 72 | return copy; 73 | } 74 | 75 | @end -------------------------------------------------------------------------------- /pop/POPDecayAnimation.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | /** 13 | @abstract A concrete decay animation class. 14 | @discussion Animation is achieved through gradual decay of animation value. 15 | */ 16 | @interface POPDecayAnimation : POPPropertyAnimation 17 | 18 | /** 19 | @abstract The designated initializer. 20 | @returns An instance of a decay animation. 21 | */ 22 | + (instancetype)animation; 23 | 24 | /** 25 | @abstract Convenience initializer that returns an animation with animatable property of name. 26 | @param name The name of the animatable property. 27 | @returns An instance of a decay animation configured with specified animatable property. 28 | */ 29 | + (instancetype)animationWithPropertyNamed:(NSString *)name; 30 | 31 | /** 32 | @abstract The current velocity value. 33 | @discussion Set before animation start to account for initial velocity. Expressed in change of value units per second. The only POPValueTypes supported for velocity are: kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, and kPOPValueSize. 34 | */ 35 | @property (copy, nonatomic) id velocity; 36 | 37 | /** 38 | @abstract The original velocity value. 39 | @discussion Since the velocity property is modified as the animation progresses, this property stores the original, passed in velocity to support autoreverse and repeatCount. 40 | */ 41 | @property (copy, nonatomic, readonly) id originalVelocity; 42 | 43 | /** 44 | @abstract The deceleration factor. 45 | @discussion Values specifies should be in the range [0, 1]. Lower values results in faster deceleration. Defaults to 0.998. 46 | */ 47 | @property (assign, nonatomic) CGFloat deceleration; 48 | 49 | /** 50 | @abstract The expected duration. 51 | @discussion Derived based on input velocity and deceleration values. 52 | */ 53 | @property (readonly, assign, nonatomic) CFTimeInterval duration; 54 | 55 | /** 56 | The to value is derived based on input velocity and deceleration. 57 | */ 58 | - (void)setToValue:(id)toValue NS_UNAVAILABLE; 59 | 60 | /** 61 | @abstract The reversed velocity. 62 | @discussion The reversed velocity based on the originalVelocity when the animation was set up. 63 | */ 64 | - (id)reversedVelocity; 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /pop/POPDecayAnimation.mm: -------------------------------------------------------------------------------- 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 | #import "POPDecayAnimationInternal.h" 11 | 12 | #if TARGET_OS_IPHONE 13 | #import 14 | #endif 15 | 16 | const POPValueType supportedVelocityTypes[6] = { kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, kPOPValueSize, kPOPValueEdgeInsets }; 17 | 18 | @implementation POPDecayAnimation 19 | 20 | #pragma mark - Lifecycle 21 | 22 | #undef __state 23 | #define __state ((POPDecayAnimationState *)_state) 24 | 25 | + (instancetype)animation 26 | { 27 | return [[self alloc] init]; 28 | } 29 | 30 | + (instancetype)animationWithPropertyNamed:(NSString *)aName 31 | { 32 | POPDecayAnimation *anim = [self animation]; 33 | anim.property = [POPAnimatableProperty propertyWithName:aName]; 34 | return anim; 35 | } 36 | 37 | - (id)init 38 | { 39 | return [self _init]; 40 | } 41 | 42 | - (void)_initState 43 | { 44 | _state = new POPDecayAnimationState(self); 45 | } 46 | 47 | #pragma mark - Properties 48 | 49 | DEFINE_RW_PROPERTY(POPDecayAnimationState, deceleration, setDeceleration:, CGFloat, __state->toVec = NULL;); 50 | 51 | @dynamic velocity; 52 | 53 | - (id)toValue 54 | { 55 | [self _ensureComputedProperties]; 56 | return POPBox(__state->toVec, __state->valueType); 57 | } 58 | 59 | - (CFTimeInterval)duration 60 | { 61 | [self _ensureComputedProperties]; 62 | return __state->duration; 63 | } 64 | 65 | - (void)setFromValue:(id)fromValue 66 | { 67 | super.fromValue = fromValue; 68 | [self _invalidateComputedProperties]; 69 | } 70 | 71 | - (void)setToValue:(id)aValue 72 | { 73 | // no-op 74 | NSLog(@"ignoring to value on decay animation %@", self); 75 | } 76 | 77 | - (id)reversedVelocity 78 | { 79 | id reversedVelocity = nil; 80 | 81 | POPValueType velocityType = POPSelectValueType(self.originalVelocity, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes)); 82 | if (velocityType == kPOPValueFloat) { 83 | #if CGFLOAT_IS_DOUBLE 84 | CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity doubleValue]; 85 | #else 86 | CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity floatValue]; 87 | #endif 88 | NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityFloat); 89 | reversedVelocity = negativeOriginalVelocityNumber; 90 | } else if (velocityType == kPOPValueInteger) { 91 | NSInteger originalVelocityInteger = [(NSNumber *)self.originalVelocity integerValue]; 92 | NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityInteger); 93 | reversedVelocity = negativeOriginalVelocityNumber; 94 | } else if (velocityType == kPOPValuePoint) { 95 | CGPoint originalVelocityPoint = [self.originalVelocity CGPointValue]; 96 | CGPoint negativeOriginalVelocityPoint = CGPointMake(-originalVelocityPoint.x, -originalVelocityPoint.y); 97 | reversedVelocity = [NSValue valueWithCGPoint:negativeOriginalVelocityPoint]; 98 | } else if (velocityType == kPOPValueRect) { 99 | CGRect originalVelocityRect = [self.originalVelocity CGRectValue]; 100 | CGRect negativeOriginalVelocityRect = CGRectMake(-originalVelocityRect.origin.x, -originalVelocityRect.origin.y, -originalVelocityRect.size.width, -originalVelocityRect.size.height); 101 | reversedVelocity = [NSValue valueWithCGRect:negativeOriginalVelocityRect]; 102 | } else if (velocityType == kPOPValueSize) { 103 | CGSize originalVelocitySize = [self.originalVelocity CGSizeValue]; 104 | CGSize negativeOriginalVelocitySize = CGSizeMake(-originalVelocitySize.width, -originalVelocitySize.height); 105 | reversedVelocity = [NSValue valueWithCGSize:negativeOriginalVelocitySize]; 106 | } else if (velocityType == kPOPValueEdgeInsets) { 107 | #if TARGET_OS_IPHONE 108 | UIEdgeInsets originalVelocityInsets = [self.originalVelocity UIEdgeInsetsValue]; 109 | UIEdgeInsets negativeOriginalVelocityInsets = UIEdgeInsetsMake(-originalVelocityInsets.top, -originalVelocityInsets.left, -originalVelocityInsets.bottom, -originalVelocityInsets.right); 110 | reversedVelocity = [NSValue valueWithUIEdgeInsets:negativeOriginalVelocityInsets]; 111 | #endif 112 | } 113 | 114 | return reversedVelocity; 115 | } 116 | 117 | - (id)originalVelocity 118 | { 119 | return POPBox(__state->originalVelocityVec, __state->valueType); 120 | } 121 | 122 | - (id)velocity 123 | { 124 | return POPBox(__state->velocityVec, __state->valueType); 125 | } 126 | 127 | - (void)setVelocity:(id)aValue 128 | { 129 | POPValueType valueType = POPSelectValueType(aValue, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes)); 130 | if (valueType != kPOPValueUnknown) { 131 | VectorRef vec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES); 132 | VectorRef origVec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES); 133 | 134 | if (!vec_equal(vec, __state->velocityVec)) { 135 | __state->velocityVec = vec; 136 | __state->originalVelocityVec = origVec; 137 | 138 | if (__state->tracing) { 139 | [__state->tracer updateVelocity:aValue]; 140 | } 141 | 142 | [self _invalidateComputedProperties]; 143 | 144 | // automatically unpause active animations 145 | if (__state->active && __state->paused) { 146 | __state->fromVec = NULL; 147 | __state->setPaused(false); 148 | } 149 | } 150 | } else { 151 | __state->velocityVec = NULL; 152 | NSLog(@"Invalid velocity value for the decayAnimation: %@", aValue); 153 | } 154 | } 155 | 156 | #pragma mark - Utility 157 | 158 | - (void)_ensureComputedProperties 159 | { 160 | if (NULL == __state->toVec) { 161 | __state->computeDuration(); 162 | __state->computeToValue(); 163 | } 164 | } 165 | 166 | - (void)_invalidateComputedProperties 167 | { 168 | __state->toVec = NULL; 169 | __state->duration = 0; 170 | } 171 | 172 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug 173 | { 174 | [super _appendDescription:s debug:debug]; 175 | 176 | if (0 != self.duration) { 177 | [s appendFormat:@"; duration = %f", self.duration]; 178 | } 179 | 180 | if (__state->deceleration) { 181 | [s appendFormat:@"; deceleration = %f", __state->deceleration]; 182 | } 183 | } 184 | 185 | @end 186 | 187 | @implementation POPDecayAnimation (NSCopying) 188 | 189 | - (instancetype)copyWithZone:(NSZone *)zone { 190 | 191 | POPDecayAnimation *copy = [super copyWithZone:zone]; 192 | 193 | if (copy) { 194 | // Set the velocity to the animation's original velocity, not its current. 195 | copy.velocity = self.originalVelocity; 196 | copy.deceleration = self.deceleration; 197 | 198 | } 199 | 200 | return copy; 201 | } 202 | 203 | @end -------------------------------------------------------------------------------- /pop/POPDecayAnimationInternal.h: -------------------------------------------------------------------------------- 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 | #import "POPDecayAnimation.h" 11 | 12 | #import 13 | 14 | #import "POPPropertyAnimationInternal.h" 15 | 16 | // minimal velocity factor before decay animation is considered complete, in units / s 17 | static CGFloat kPOPAnimationDecayMinimalVelocityFactor = 5.; 18 | 19 | // default decay animation deceleration 20 | static CGFloat kPOPAnimationDecayDecelerationDefault = 0.998; 21 | 22 | static void decay_position(CGFloat *x, CGFloat *v, NSUInteger count, CFTimeInterval dt, CGFloat deceleration) 23 | { 24 | dt *= 1000; 25 | 26 | // v0 = v / 1000 27 | // v = v0 * powf(deceleration, dt); 28 | // v = v * 1000; 29 | 30 | // x0 = x; 31 | // x = x0 + v0 * deceleration * (1 - powf(deceleration, dt)) / (1 - deceleration) 32 | float v0[count]; 33 | float kv = powf(deceleration, dt); 34 | float kx = deceleration * (1 - kv) / (1 - deceleration); 35 | 36 | for (NSUInteger idx = 0; idx < count; idx++) { 37 | v0[idx] = v[idx] / 1000.; 38 | v[idx] = v0[idx] * kv * 1000.; 39 | x[idx] = x[idx] + v0[idx] * kx; 40 | } 41 | } 42 | 43 | struct _POPDecayAnimationState : _POPPropertyAnimationState 44 | { 45 | double deceleration; 46 | CFTimeInterval duration; 47 | 48 | _POPDecayAnimationState(id __unsafe_unretained anim) : 49 | _POPPropertyAnimationState(anim), 50 | deceleration(kPOPAnimationDecayDecelerationDefault), 51 | duration(0) 52 | { 53 | type = kPOPAnimationDecay; 54 | } 55 | 56 | bool isDone() { 57 | if (_POPPropertyAnimationState::isDone()) { 58 | return true; 59 | } 60 | 61 | CGFloat f = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor; 62 | const CGFloat *velocityValues = vec_data(velocityVec); 63 | for (NSUInteger idx = 0; idx < valueCount; idx++) { 64 | if (std::abs((velocityValues[idx])) >= f) 65 | return false; 66 | } 67 | return true; 68 | 69 | } 70 | 71 | void computeDuration() { 72 | 73 | // compute duration till threshold velocity 74 | Vector4r scaledVelocity = vector4(velocityVec) / 1000.; 75 | 76 | double k = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor / 1000.; 77 | double vx = k / scaledVelocity.x; 78 | double vy = k / scaledVelocity.y; 79 | double vz = k / scaledVelocity.z; 80 | double vw = k / scaledVelocity.w; 81 | double d = log(deceleration) * 1000.; 82 | duration = MAX(MAX(MAX(log(fabs(vx)) / d, log(fabs(vy)) / d), log(fabs(vz)) / d), log(fabs(vw)) / d); 83 | 84 | // ensure velocity threshold is exceeded 85 | if (std::isnan(duration) || duration < 0) { 86 | duration = 0; 87 | } 88 | } 89 | 90 | void computeToValue() { 91 | // to value assuming final velocity as a factor of dynamics threshold 92 | // derived from v' = v * d^dt used in decay_position 93 | // to compute the to value with maximal dt, p' = p + (v * d) / (1 - d) 94 | VectorRef fromValue = NULL != currentVec ? currentVec : fromVec; 95 | if (!fromValue) { 96 | return; 97 | } 98 | 99 | // ensure duration is computed 100 | if (0 == duration) { 101 | computeDuration(); 102 | } 103 | 104 | // compute to value 105 | VectorRef toValue(Vector::new_vector(fromValue.get())); 106 | Vector4r velocity = velocityVec->vector4r(); 107 | decay_position(toValue->data(), velocity.data(), valueCount, duration, deceleration); 108 | toVec = toValue; 109 | } 110 | 111 | bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { 112 | // advance past not yet initialized animations 113 | if (NULL == currentVec) { 114 | return false; 115 | } 116 | 117 | decay_position(currentVec->data(), velocityVec->data(), valueCount, dt, deceleration); 118 | 119 | // clamp to compute end value; avoid possibility of decaying past 120 | clampCurrentValue(kPOPAnimationClampEnd | clampMode); 121 | 122 | return true; 123 | } 124 | 125 | }; 126 | 127 | typedef struct _POPDecayAnimationState POPDecayAnimationState; 128 | -------------------------------------------------------------------------------- /pop/POPDefines.h: -------------------------------------------------------------------------------- 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 | #ifndef POP_POPDefines_h 11 | #define POP_POPDefines_h 12 | 13 | #import 14 | 15 | #ifdef __cplusplus 16 | # define POP_EXTERN_C_BEGIN extern "C" { 17 | # define POP_EXTERN_C_END } 18 | #else 19 | # define POP_EXTERN_C_BEGIN 20 | # define POP_EXTERN_C_END 21 | #endif 22 | 23 | #define POP_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0]) 24 | 25 | #if defined (__cplusplus) && defined (__GNUC__) 26 | # define POP_NOTHROW __attribute__ ((nothrow)) 27 | #else 28 | # define POP_NOTHROW 29 | #endif 30 | 31 | #if defined(POP_USE_SCENEKIT) 32 | # if TARGET_OS_MAC || TARGET_OS_IPHONE 33 | # define SCENEKIT_SDK_AVAILABLE 1 34 | # endif 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /pop/POPGeometry.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #if TARGET_OS_IPHONE 13 | #import 14 | #endif 15 | 16 | #if !TARGET_OS_IPHONE 17 | 18 | /** NSValue extensions to support animatable types. */ 19 | @interface NSValue (POP) 20 | 21 | /** 22 | @abstract Creates an NSValue given a CGPoint. 23 | */ 24 | + (NSValue *)valueWithCGPoint:(CGPoint)point; 25 | 26 | /** 27 | @abstract Creates an NSValue given a CGSize. 28 | */ 29 | + (NSValue *)valueWithCGSize:(CGSize)size; 30 | 31 | /** 32 | @abstract Creates an NSValue given a CGRect. 33 | */ 34 | + (NSValue *)valueWithCGRect:(CGRect)rect; 35 | 36 | /** 37 | @abstract Creates an NSValue given a CFRange. 38 | */ 39 | + (NSValue *)valueWithCFRange:(CFRange)range; 40 | 41 | /** 42 | @abstract Creates an NSValue given a CGAffineTransform. 43 | */ 44 | + (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform; 45 | 46 | /** 47 | @abstract Returns the underlying CGPoint value. 48 | */ 49 | - (CGPoint)CGPointValue; 50 | 51 | /** 52 | @abstract Returns the underlying CGSize value. 53 | */ 54 | - (CGSize)CGSizeValue; 55 | 56 | /** 57 | @abstract Returns the underlying CGRect value. 58 | */ 59 | - (CGRect)CGRectValue; 60 | 61 | /** 62 | @abstract Returns the underlying CFRange value. 63 | */ 64 | - (CFRange)CFRangeValue; 65 | 66 | /** 67 | @abstract Returns the underlying CGAffineTransform value. 68 | */ 69 | - (CGAffineTransform)CGAffineTransformValue; 70 | 71 | @end 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /pop/POPGeometry.mm: -------------------------------------------------------------------------------- 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 | #import "POPGeometry.h" 11 | 12 | #if !TARGET_OS_IPHONE 13 | @implementation NSValue (POP) 14 | 15 | + (NSValue *)valueWithCGPoint:(CGPoint)point { 16 | return [NSValue valueWithBytes:&point objCType:@encode(CGPoint)]; 17 | } 18 | 19 | + (NSValue *)valueWithCGSize:(CGSize)size { 20 | return [NSValue valueWithBytes:&size objCType:@encode(CGSize)]; 21 | } 22 | 23 | + (NSValue *)valueWithCGRect:(CGRect)rect { 24 | return [NSValue valueWithBytes:&rect objCType:@encode(CGRect)]; 25 | } 26 | 27 | + (NSValue *)valueWithCFRange:(CFRange)range { 28 | return [NSValue valueWithBytes:&range objCType:@encode(CFRange)]; 29 | } 30 | 31 | + (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform 32 | { 33 | return [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)]; 34 | } 35 | 36 | - (CGPoint)CGPointValue { 37 | CGPoint result; 38 | [self getValue:&result]; 39 | return result; 40 | } 41 | 42 | - (CGSize)CGSizeValue { 43 | CGSize result; 44 | [self getValue:&result]; 45 | return result; 46 | } 47 | 48 | - (CGRect)CGRectValue { 49 | CGRect result; 50 | [self getValue:&result]; 51 | return result; 52 | } 53 | 54 | - (CFRange)CFRangeValue { 55 | CFRange result; 56 | [self getValue:&result]; 57 | return result; 58 | } 59 | 60 | - (CGAffineTransform)CGAffineTransformValue { 61 | CGAffineTransform result; 62 | [self getValue:&result]; 63 | return result; 64 | } 65 | @end 66 | 67 | #endif 68 | 69 | #if TARGET_OS_IPHONE 70 | #import "POPDefines.h" 71 | 72 | #if SCENEKIT_SDK_AVAILABLE 73 | #import 74 | 75 | /** 76 | Dirty hacks because iOS is weird and decided to define both SCNVector3's and SCNVector4's objCType as "t". However @encode(SCNVector3) and @encode(SCNVector4) both return the proper definition ("{SCNVector3=fff}" and "{SCNVector4=ffff}" respectively) 77 | 78 | [[NSValue valueWithSCNVector3:SCNVector3Make(0.0, 0.0, 0.0)] objcType] returns "t", whereas it should return "{SCNVector3=fff}". 79 | 80 | *flips table* 81 | */ 82 | @implementation NSValue (SceneKitFixes) 83 | 84 | + (NSValue *)valueWithSCNVector3:(SCNVector3)vec3 { 85 | return [NSValue valueWithBytes:&vec3 objCType:@encode(SCNVector3)]; 86 | } 87 | 88 | + (NSValue *)valueWithSCNVector4:(SCNVector4)vec4 { 89 | return [NSValue valueWithBytes:&vec4 objCType:@encode(SCNVector4)]; 90 | } 91 | 92 | @end 93 | #endif 94 | #endif 95 | -------------------------------------------------------------------------------- /pop/POPLayerExtras.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | POP_EXTERN_C_BEGIN 15 | 16 | #pragma mark - Scale 17 | 18 | /** 19 | @abstract Returns layer scale factor for the x axis. 20 | */ 21 | extern CGFloat POPLayerGetScaleX(CALayer *l); 22 | 23 | /** 24 | @abstract Set layer scale factor for the x axis. 25 | */ 26 | extern void POPLayerSetScaleX(CALayer *l, CGFloat f); 27 | 28 | /** 29 | @abstract Returns layer scale factor for the y axis. 30 | */ 31 | extern CGFloat POPLayerGetScaleY(CALayer *l); 32 | 33 | /** 34 | @abstract Set layer scale factor for the y axis. 35 | */ 36 | extern void POPLayerSetScaleY(CALayer *l, CGFloat f); 37 | 38 | /** 39 | @abstract Returns layer scale factor for the z axis. 40 | */ 41 | extern CGFloat POPLayerGetScaleZ(CALayer *l); 42 | 43 | /** 44 | @abstract Set layer scale factor for the z axis. 45 | */ 46 | extern void POPLayerSetScaleZ(CALayer *l, CGFloat f); 47 | 48 | /** 49 | @abstract Returns layer scale factors for x and y access as point. 50 | */ 51 | extern CGPoint POPLayerGetScaleXY(CALayer *l); 52 | 53 | /** 54 | @abstract Sets layer x and y scale factors given point. 55 | */ 56 | extern void POPLayerSetScaleXY(CALayer *l, CGPoint p); 57 | 58 | #pragma mark - Translation 59 | 60 | /** 61 | @abstract Returns layer translation factor for the x axis. 62 | */ 63 | extern CGFloat POPLayerGetTranslationX(CALayer *l); 64 | 65 | /** 66 | @abstract Set layer translation factor for the x axis. 67 | */ 68 | extern void POPLayerSetTranslationX(CALayer *l, CGFloat f); 69 | 70 | /** 71 | @abstract Returns layer translation factor for the y axis. 72 | */ 73 | extern CGFloat POPLayerGetTranslationY(CALayer *l); 74 | 75 | /** 76 | @abstract Set layer translation factor for the y axis. 77 | */ 78 | extern void POPLayerSetTranslationY(CALayer *l, CGFloat f); 79 | 80 | /** 81 | @abstract Returns layer translation factor for the z axis. 82 | */ 83 | extern CGFloat POPLayerGetTranslationZ(CALayer *l); 84 | 85 | /** 86 | @abstract Set layer translation factor for the z axis. 87 | */ 88 | extern void POPLayerSetTranslationZ(CALayer *l, CGFloat f); 89 | 90 | /** 91 | @abstract Returns layer translation factors for x and y access as point. 92 | */ 93 | extern CGPoint POPLayerGetTranslationXY(CALayer *l); 94 | 95 | /** 96 | @abstract Sets layer x and y translation factors given point. 97 | */ 98 | extern void POPLayerSetTranslationXY(CALayer *l, CGPoint p); 99 | 100 | #pragma mark - Rotation 101 | 102 | /** 103 | @abstract Returns layer rotation, in radians, in the X axis. 104 | */ 105 | extern CGFloat POPLayerGetRotationX(CALayer *l); 106 | 107 | /** 108 | @abstract Sets layer rotation, in radians, in the X axis. 109 | */ 110 | extern void POPLayerSetRotationX(CALayer *l, CGFloat f); 111 | 112 | /** 113 | @abstract Returns layer rotation, in radians, in the Y axis. 114 | */ 115 | extern CGFloat POPLayerGetRotationY(CALayer *l); 116 | 117 | /** 118 | @abstract Sets layer rotation, in radians, in the Y axis. 119 | */ 120 | extern void POPLayerSetRotationY(CALayer *l, CGFloat f); 121 | 122 | /** 123 | @abstract Returns layer rotation, in radians, in the Z axis. 124 | */ 125 | extern CGFloat POPLayerGetRotationZ(CALayer *l); 126 | 127 | /** 128 | @abstract Sets layer rotation, in radians, in the Z axis. 129 | */ 130 | extern void POPLayerSetRotationZ(CALayer *l, CGFloat f); 131 | 132 | /** 133 | @abstract Returns layer rotation, in radians, in the Z axis. 134 | */ 135 | extern CGFloat POPLayerGetRotation(CALayer *l); 136 | 137 | /** 138 | @abstract Sets layer rotation, in radians, in the Z axis. 139 | */ 140 | extern void POPLayerSetRotation(CALayer *l, CGFloat f); 141 | 142 | #pragma mark - Sublayer Scale 143 | 144 | /** 145 | @abstract Returns sublayer scale factors for x and y access as point. 146 | */ 147 | extern CGPoint POPLayerGetSubScaleXY(CALayer *l); 148 | 149 | /** 150 | @abstract Sets sublayer x and y scale factors given point. 151 | */ 152 | extern void POPLayerSetSubScaleXY(CALayer *l, CGPoint p); 153 | 154 | #pragma mark - Sublayer Translation 155 | 156 | /** 157 | @abstract Returns sublayer translation factor for the x axis. 158 | */ 159 | extern CGFloat POPLayerGetSubTranslationX(CALayer *l); 160 | 161 | /** 162 | @abstract Set sublayer translation factor for the x axis. 163 | */ 164 | extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f); 165 | 166 | /** 167 | @abstract Returns sublayer translation factor for the y axis. 168 | */ 169 | extern CGFloat POPLayerGetSubTranslationY(CALayer *l); 170 | 171 | /** 172 | @abstract Set sublayer translation factor for the y axis. 173 | */ 174 | extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f); 175 | 176 | /** 177 | @abstract Returns sublayer translation factor for the z axis. 178 | */ 179 | extern CGFloat POPLayerGetSubTranslationZ(CALayer *l); 180 | 181 | /** 182 | @abstract Set sublayer translation factor for the z axis. 183 | */ 184 | extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f); 185 | 186 | /** 187 | @abstract Returns sublayer translation factors for x and y access as point. 188 | */ 189 | extern CGPoint POPLayerGetSubTranslationXY(CALayer *l); 190 | 191 | /** 192 | @abstract Sets sublayer x and y translation factors given point. 193 | */ 194 | extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p); 195 | 196 | POP_EXTERN_C_END 197 | -------------------------------------------------------------------------------- /pop/POPLayerExtras.mm: -------------------------------------------------------------------------------- 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 | #import "POPLayerExtras.h" 11 | 12 | #include "TransformationMatrix.h" 13 | 14 | using namespace WebCore; 15 | 16 | #define DECOMPOSE_TRANSFORM(L) \ 17 | TransformationMatrix _m(L.transform); \ 18 | TransformationMatrix::DecomposedType _d; \ 19 | _m.decompose(_d); 20 | 21 | #define RECOMPOSE_TRANSFORM(L) \ 22 | _m.recompose(_d); \ 23 | L.transform = _m.transform3d(); 24 | 25 | #define RECOMPOSE_ROT_TRANSFORM(L) \ 26 | _m.recompose(_d, true); \ 27 | L.transform = _m.transform3d(); 28 | 29 | #define DECOMPOSE_SUBLAYER_TRANSFORM(L) \ 30 | TransformationMatrix _m(L.sublayerTransform); \ 31 | TransformationMatrix::DecomposedType _d; \ 32 | _m.decompose(_d); 33 | 34 | #define RECOMPOSE_SUBLAYER_TRANSFORM(L) \ 35 | _m.recompose(_d); \ 36 | L.sublayerTransform = _m.transform3d(); 37 | 38 | #pragma mark - Scale 39 | 40 | NS_INLINE void ensureNonZeroValue(CGFloat &f) 41 | { 42 | if (f == 0) { 43 | f = 1e-6; 44 | } 45 | } 46 | 47 | NS_INLINE void ensureNonZeroValue(CGPoint &p) 48 | { 49 | if (p.x == 0 && p.y == 0) { 50 | p.x = 1e-6; 51 | p.y = 1e-6; 52 | } 53 | } 54 | 55 | CGFloat POPLayerGetScaleX(CALayer *l) 56 | { 57 | DECOMPOSE_TRANSFORM(l); 58 | return _d.scaleX; 59 | } 60 | 61 | void POPLayerSetScaleX(CALayer *l, CGFloat f) 62 | { 63 | ensureNonZeroValue(f); 64 | DECOMPOSE_TRANSFORM(l); 65 | _d.scaleX = f; 66 | RECOMPOSE_TRANSFORM(l); 67 | } 68 | 69 | CGFloat POPLayerGetScaleY(CALayer *l) 70 | { 71 | DECOMPOSE_TRANSFORM(l); 72 | return _d.scaleY; 73 | } 74 | 75 | void POPLayerSetScaleY(CALayer *l, CGFloat f) 76 | { 77 | ensureNonZeroValue(f); 78 | DECOMPOSE_TRANSFORM(l); 79 | _d.scaleY = f; 80 | RECOMPOSE_TRANSFORM(l); 81 | } 82 | 83 | CGFloat POPLayerGetScaleZ(CALayer *l) 84 | { 85 | DECOMPOSE_TRANSFORM(l); 86 | return _d.scaleZ; 87 | } 88 | 89 | void POPLayerSetScaleZ(CALayer *l, CGFloat f) 90 | { 91 | ensureNonZeroValue(f); 92 | DECOMPOSE_TRANSFORM(l); 93 | _d.scaleZ = f; 94 | RECOMPOSE_TRANSFORM(l); 95 | } 96 | 97 | CGPoint POPLayerGetScaleXY(CALayer *l) 98 | { 99 | DECOMPOSE_TRANSFORM(l); 100 | return CGPointMake(_d.scaleX, _d.scaleY); 101 | } 102 | 103 | void POPLayerSetScaleXY(CALayer *l, CGPoint p) 104 | { 105 | ensureNonZeroValue(p); 106 | DECOMPOSE_TRANSFORM(l); 107 | _d.scaleX = p.x; 108 | _d.scaleY = p.y; 109 | RECOMPOSE_TRANSFORM(l); 110 | } 111 | 112 | #pragma mark - Translation 113 | 114 | CGFloat POPLayerGetTranslationX(CALayer *l) 115 | { 116 | DECOMPOSE_TRANSFORM(l); 117 | return _d.translateX; 118 | } 119 | 120 | void POPLayerSetTranslationX(CALayer *l, CGFloat f) 121 | { 122 | DECOMPOSE_TRANSFORM(l); 123 | _d.translateX = f; 124 | RECOMPOSE_TRANSFORM(l); 125 | } 126 | 127 | CGFloat POPLayerGetTranslationY(CALayer *l) 128 | { 129 | DECOMPOSE_TRANSFORM(l); 130 | return _d.translateY; 131 | } 132 | 133 | void POPLayerSetTranslationY(CALayer *l, CGFloat f) 134 | { 135 | DECOMPOSE_TRANSFORM(l); 136 | _d.translateY = f; 137 | RECOMPOSE_TRANSFORM(l); 138 | } 139 | 140 | CGFloat POPLayerGetTranslationZ(CALayer *l) 141 | { 142 | DECOMPOSE_TRANSFORM(l); 143 | return _d.translateZ; 144 | } 145 | 146 | void POPLayerSetTranslationZ(CALayer *l, CGFloat f) 147 | { 148 | DECOMPOSE_TRANSFORM(l); 149 | _d.translateZ = f; 150 | RECOMPOSE_TRANSFORM(l); 151 | } 152 | 153 | CGPoint POPLayerGetTranslationXY(CALayer *l) 154 | { 155 | DECOMPOSE_TRANSFORM(l); 156 | return CGPointMake(_d.translateX, _d.translateY); 157 | } 158 | 159 | void POPLayerSetTranslationXY(CALayer *l, CGPoint p) 160 | { 161 | DECOMPOSE_TRANSFORM(l); 162 | _d.translateX = p.x; 163 | _d.translateY = p.y; 164 | RECOMPOSE_TRANSFORM(l); 165 | } 166 | 167 | #pragma mark - Rotation 168 | 169 | CGFloat POPLayerGetRotationX(CALayer *l) 170 | { 171 | DECOMPOSE_TRANSFORM(l); 172 | return _d.rotateX; 173 | } 174 | 175 | void POPLayerSetRotationX(CALayer *l, CGFloat f) 176 | { 177 | DECOMPOSE_TRANSFORM(l); 178 | _d.rotateX = f; 179 | RECOMPOSE_ROT_TRANSFORM(l); 180 | } 181 | 182 | CGFloat POPLayerGetRotationY(CALayer *l) 183 | { 184 | DECOMPOSE_TRANSFORM(l); 185 | return _d.rotateY; 186 | } 187 | 188 | void POPLayerSetRotationY(CALayer *l, CGFloat f) 189 | { 190 | DECOMPOSE_TRANSFORM(l); 191 | _d.rotateY = f; 192 | RECOMPOSE_ROT_TRANSFORM(l); 193 | } 194 | 195 | CGFloat POPLayerGetRotationZ(CALayer *l) 196 | { 197 | DECOMPOSE_TRANSFORM(l); 198 | return _d.rotateZ; 199 | } 200 | 201 | void POPLayerSetRotationZ(CALayer *l, CGFloat f) 202 | { 203 | DECOMPOSE_TRANSFORM(l); 204 | _d.rotateZ = f; 205 | RECOMPOSE_ROT_TRANSFORM(l); 206 | } 207 | 208 | CGFloat POPLayerGetRotation(CALayer *l) 209 | { 210 | return POPLayerGetRotationZ(l); 211 | } 212 | 213 | void POPLayerSetRotation(CALayer *l, CGFloat f) 214 | { 215 | POPLayerSetRotationZ(l, f); 216 | } 217 | 218 | #pragma mark - Sublayer Scale 219 | 220 | CGPoint POPLayerGetSubScaleXY(CALayer *l) 221 | { 222 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 223 | return CGPointMake(_d.scaleX, _d.scaleY); 224 | } 225 | 226 | void POPLayerSetSubScaleXY(CALayer *l, CGPoint p) 227 | { 228 | ensureNonZeroValue(p); 229 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 230 | _d.scaleX = p.x; 231 | _d.scaleY = p.y; 232 | RECOMPOSE_SUBLAYER_TRANSFORM(l); 233 | } 234 | 235 | #pragma mark - Sublayer Translation 236 | 237 | extern CGFloat POPLayerGetSubTranslationX(CALayer *l) 238 | { 239 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 240 | return _d.translateX; 241 | } 242 | 243 | extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f) 244 | { 245 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 246 | _d.translateX = f; 247 | RECOMPOSE_SUBLAYER_TRANSFORM(l); 248 | } 249 | 250 | extern CGFloat POPLayerGetSubTranslationY(CALayer *l) 251 | { 252 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 253 | return _d.translateY; 254 | } 255 | 256 | extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f) 257 | { 258 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 259 | _d.translateY = f; 260 | RECOMPOSE_SUBLAYER_TRANSFORM(l); 261 | } 262 | 263 | extern CGFloat POPLayerGetSubTranslationZ(CALayer *l) 264 | { 265 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 266 | return _d.translateZ; 267 | } 268 | 269 | extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f) 270 | { 271 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 272 | _d.translateZ = f; 273 | RECOMPOSE_SUBLAYER_TRANSFORM(l); 274 | } 275 | 276 | extern CGPoint POPLayerGetSubTranslationXY(CALayer *l) 277 | { 278 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 279 | return CGPointMake(_d.translateX, _d.translateY); 280 | } 281 | 282 | extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p) 283 | { 284 | DECOMPOSE_SUBLAYER_TRANSFORM(l); 285 | _d.translateX = p.x; 286 | _d.translateY = p.y; 287 | RECOMPOSE_SUBLAYER_TRANSFORM(l); 288 | } 289 | -------------------------------------------------------------------------------- /pop/POPMath.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | #import "POPDefines.h" 15 | 16 | NS_INLINE CGFloat sqrtr(CGFloat f) 17 | { 18 | #if CGFLOAT_IS_DOUBLE 19 | return sqrt(f); 20 | #else 21 | return sqrtf(f); 22 | #endif 23 | } 24 | 25 | // round to nearest sub; pass 2.0 to round to every 0.5 (eg: retina pixels) 26 | NS_INLINE CGFloat POPSubRound(CGFloat f, CGFloat sub) 27 | { 28 | return round(f * sub) / sub; 29 | } 30 | 31 | #define MIX(a, b, f) ((a) + (f) * ((b) - (a))) 32 | 33 | // the longer the duration, the higher the necessary precision 34 | #define SOLVE_EPS(dur) (1. / (1000. * (dur))) 35 | 36 | #define _EQLF_(x, y, epsilon) (fabsf ((x) - (y)) < epsilon) 37 | 38 | extern void POPInterpolateVector(NSUInteger count, CGFloat *dst, const CGFloat *from, const CGFloat *to, CGFloat f); 39 | 40 | extern double POPTimingFunctionSolve(const double vec[4], double t, double eps); 41 | 42 | // quadratic mapping of t [0, 1] to [start, end] 43 | extern double POPQuadraticOutInterpolation(double t, double start, double end); 44 | 45 | // normalize value to [0, 1] based on its range [startValue, endValue] 46 | extern double POPNormalize(double value, double startValue, double endValue); 47 | 48 | // project a normalized value [0, 1] to a given range [start, end] 49 | extern double POPProjectNormal(double n, double start, double end); 50 | 51 | // solve a quadratic equation of the form a * x^2 + b * x + c = 0 52 | extern void POPQuadraticSolve(CGFloat a, CGFloat b, CGFloat c, CGFloat &x1, CGFloat &x2); 53 | 54 | // for a given tension return the bouncy 3 friction that produces no bounce 55 | extern double POPBouncy3NoBounce(double tension); 56 | -------------------------------------------------------------------------------- /pop/POPMath.mm: -------------------------------------------------------------------------------- 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 | #import "POPMath.h" 11 | 12 | #import "POPAnimationPrivate.h" 13 | #import "UnitBezier.h" 14 | 15 | void POPInterpolateVector(NSUInteger count, CGFloat *dst, const CGFloat *from, const CGFloat *to, CGFloat f) 16 | { 17 | for (NSUInteger idx = 0; idx < count; idx++) { 18 | dst[idx] = MIX(from[idx], to[idx], f); 19 | } 20 | } 21 | 22 | double POPTimingFunctionSolve(const double vec[4], double t, double eps) 23 | { 24 | WebCore::UnitBezier bezier(vec[0], vec[1], vec[2], vec[3]); 25 | return bezier.solve(t, eps); 26 | } 27 | 28 | double POPNormalize(double value, double startValue, double endValue) 29 | { 30 | return (value - startValue) / (endValue - startValue); 31 | } 32 | 33 | double POPProjectNormal(double n, double start, double end) 34 | { 35 | return start + (n * (end - start)); 36 | } 37 | 38 | static double linear_interpolation(double t, double start, double end) 39 | { 40 | return t * end + (1.f - t) * start; 41 | } 42 | 43 | double POPQuadraticOutInterpolation(double t, double start, double end) 44 | { 45 | return linear_interpolation(2*t - t*t, start, end); 46 | } 47 | 48 | static double b3_friction1(double x) 49 | { 50 | return (0.0007 * pow(x, 3)) - (0.031 * pow(x, 2)) + 0.64 * x + 1.28; 51 | } 52 | 53 | static double b3_friction2(double x) 54 | { 55 | return (0.000044 * pow(x, 3)) - (0.006 * pow(x, 2)) + 0.36 * x + 2.; 56 | } 57 | 58 | static double b3_friction3(double x) 59 | { 60 | return (0.00000045 * pow(x, 3)) - (0.000332 * pow(x, 2)) + 0.1078 * x + 5.84; 61 | } 62 | 63 | double POPBouncy3NoBounce(double tension) 64 | { 65 | double friction = 0; 66 | if (tension <= 18.) { 67 | friction = b3_friction1(tension); 68 | } else if (tension > 18 && tension <= 44) { 69 | friction = b3_friction2(tension); 70 | } else if (tension > 44) { 71 | friction = b3_friction3(tension); 72 | } else { 73 | assert(false); 74 | } 75 | return friction; 76 | } 77 | 78 | void POPQuadraticSolve(CGFloat a, CGFloat b, CGFloat c, CGFloat &x1, CGFloat &x2) 79 | { 80 | CGFloat discriminant = sqrt(b * b - 4 * a * c); 81 | x1 = (-b + discriminant) / (2 * a); 82 | x2 = (-b - discriminant) / (2 * a); 83 | } 84 | -------------------------------------------------------------------------------- /pop/POPPropertyAnimation.h: -------------------------------------------------------------------------------- 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 | #import 11 | #import 12 | 13 | /** 14 | @abstract Flags for clamping animation values. 15 | @discussion Animation values can optionally be clamped to avoid overshoot. kPOPAnimationClampStart ensures values are more than fromValue and kPOPAnimationClampEnd ensures values are less than toValue. 16 | */ 17 | typedef NS_OPTIONS(NSUInteger, POPAnimationClampFlags) 18 | { 19 | kPOPAnimationClampNone = 0, 20 | kPOPAnimationClampStart = 1UL << 0, 21 | kPOPAnimationClampEnd = 1UL << 1, 22 | kPOPAnimationClampBoth = kPOPAnimationClampStart | kPOPAnimationClampEnd, 23 | }; 24 | 25 | /** 26 | @abstract The semi-concrete property animation subclass. 27 | */ 28 | @interface POPPropertyAnimation : POPAnimation 29 | 30 | /** 31 | @abstract The property to animate. 32 | */ 33 | @property (strong, nonatomic) POPAnimatableProperty *property; 34 | 35 | /** 36 | @abstract The value to animate from. 37 | @discussion The value type should match the property. If unspecified, the value is initialized to the object's current value on animation start. 38 | */ 39 | @property (copy, nonatomic) id fromValue; 40 | 41 | /** 42 | @abstract The value to animate to. 43 | @discussion The value type should match the property. If unspecified, the value is initialized to the object's current value on animation start. 44 | */ 45 | @property (copy, nonatomic) id toValue; 46 | 47 | /** 48 | @abstract The rounding factor applied to the current animated value. 49 | @discussion Specify 1.0 to animate between integral values. Defaults to 0 meaning no rounding. 50 | */ 51 | @property (assign, nonatomic) CGFloat roundingFactor; 52 | 53 | /** 54 | @abstract The clamp mode applied to the current animated value. 55 | @discussion See {@ref POPAnimationClampFlags} for possible values. Defaults to kPOPAnimationClampNone. 56 | */ 57 | @property (assign, nonatomic) NSUInteger clampMode; 58 | 59 | /** 60 | @abstract The flag indicating whether values should be "added" each frame, rather than set. 61 | @discussion Addition may be type dependent. Defaults to NO. 62 | */ 63 | @property (assign, nonatomic, getter = isAdditive) BOOL additive; 64 | 65 | @end 66 | 67 | @interface POPPropertyAnimation (CustomProperty) 68 | 69 | + (instancetype)animationWithCustomPropertyNamed:(NSString *)name 70 | readBlock:(POPAnimatablePropertyReadBlock)readBlock 71 | writeBlock:(POPAnimatablePropertyWriteBlock)writeBlock; 72 | 73 | + (instancetype)animationWithCustomPropertyReadBlock:(POPAnimatablePropertyReadBlock)readBlock 74 | writeBlock:(POPAnimatablePropertyWriteBlock)writeBlock; 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /pop/POPPropertyAnimation.mm: -------------------------------------------------------------------------------- 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 | #import "POPPropertyAnimationInternal.h" 11 | 12 | @implementation POPPropertyAnimation 13 | 14 | #pragma mark - Lifecycle 15 | 16 | #undef __state 17 | #define __state ((POPPropertyAnimationState *)_state) 18 | 19 | - (void)_initState 20 | { 21 | _state = new POPPropertyAnimationState(self); 22 | } 23 | 24 | #pragma mark - Properties 25 | 26 | DEFINE_RW_FLAG(POPPropertyAnimationState, additive, isAdditive, setAdditive:); 27 | DEFINE_RW_PROPERTY(POPPropertyAnimationState, roundingFactor, setRoundingFactor:, CGFloat); 28 | DEFINE_RW_PROPERTY(POPPropertyAnimationState, clampMode, setClampMode:, NSUInteger); 29 | DEFINE_RW_PROPERTY_OBJ(POPPropertyAnimationState, property, setProperty:, POPAnimatableProperty*, ((POPPropertyAnimationState*)_state)->updatedDynamicsThreshold();); 30 | DEFINE_RW_PROPERTY_OBJ_COPY(POPPropertyAnimationState, progressMarkers, setProgressMarkers:, NSArray*, ((POPPropertyAnimationState*)_state)->updatedProgressMarkers();); 31 | 32 | - (id)fromValue 33 | { 34 | return POPBox(__state->fromVec, __state->valueType); 35 | } 36 | 37 | - (void)setFromValue:(id)aValue 38 | { 39 | POPPropertyAnimationState *s = __state; 40 | VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES); 41 | if (!vec_equal(vec, s->fromVec)) { 42 | s->fromVec = vec; 43 | 44 | if (s->tracing) { 45 | [s->tracer updateFromValue:aValue]; 46 | } 47 | } 48 | } 49 | 50 | - (id)toValue 51 | { 52 | return POPBox(__state->toVec, __state->valueType); 53 | } 54 | 55 | - (void)setToValue:(id)aValue 56 | { 57 | POPPropertyAnimationState *s = __state; 58 | VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES); 59 | 60 | if (!vec_equal(vec, s->toVec)) { 61 | s->toVec = vec; 62 | 63 | // invalidate to dependent state 64 | s->didReachToValue = false; 65 | s->distanceVec = NULL; 66 | 67 | if (s->tracing) { 68 | [s->tracer updateToValue:aValue]; 69 | } 70 | 71 | // automatically unpause active animations 72 | if (s->active && s->paused) { 73 | s->setPaused(false); 74 | } 75 | } 76 | } 77 | 78 | - (id)currentValue 79 | { 80 | return POPBox(__state->currentValue(), __state->valueType); 81 | } 82 | 83 | #pragma mark - Utility 84 | 85 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug 86 | { 87 | [s appendFormat:@"; from = %@; to = %@", describe(__state->fromVec), describe(__state->toVec)]; 88 | 89 | if (_state->active) 90 | [s appendFormat:@"; currentValue = %@", describe(__state->currentValue())]; 91 | 92 | if (__state->velocityVec && 0 != __state->velocityVec->norm()) 93 | [s appendFormat:@"; velocity = %@", describe(__state->velocityVec)]; 94 | 95 | if (!self.removedOnCompletion) 96 | [s appendFormat:@"; removedOnCompletion = %@", POPStringFromBOOL(self.removedOnCompletion)]; 97 | 98 | if (__state->progressMarkers) 99 | [s appendFormat:@"; progressMarkers = [%@]", [__state->progressMarkers componentsJoinedByString:@", "]]; 100 | 101 | if (_state->active) 102 | [s appendFormat:@"; progress = %f", __state->progress]; 103 | } 104 | 105 | @end 106 | 107 | @implementation POPPropertyAnimation (NSCopying) 108 | 109 | - (instancetype)copyWithZone:(NSZone *)zone { 110 | 111 | POPPropertyAnimation *copy = [super copyWithZone:zone]; 112 | 113 | if (copy) { 114 | copy.property = [self.property copyWithZone:zone]; 115 | copy.fromValue = self.fromValue; 116 | copy.toValue = self.toValue; 117 | copy.roundingFactor = self.roundingFactor; 118 | copy.clampMode = self.clampMode; 119 | copy.additive = self.additive; 120 | } 121 | 122 | return copy; 123 | } 124 | 125 | @end 126 | 127 | @implementation POPPropertyAnimation (CustomProperty) 128 | 129 | + (instancetype)animationWithCustomPropertyNamed:(NSString *)name 130 | readBlock:(POPAnimatablePropertyReadBlock)readBlock 131 | writeBlock:(POPAnimatablePropertyWriteBlock)writeBlock 132 | { 133 | POPPropertyAnimation *animation = [[self alloc] init]; 134 | animation.property = [POPAnimatableProperty propertyWithName:name initializer:^(POPMutableAnimatableProperty *prop) { 135 | prop.readBlock = readBlock; 136 | prop.writeBlock = writeBlock; 137 | }]; 138 | return animation; 139 | } 140 | 141 | + (instancetype)animationWithCustomPropertyReadBlock:(POPAnimatablePropertyReadBlock)readBlock 142 | writeBlock:(POPAnimatablePropertyWriteBlock)writeBlock 143 | { 144 | return [self animationWithCustomPropertyNamed:[NSUUID UUID].UUIDString 145 | readBlock:readBlock 146 | writeBlock:writeBlock]; 147 | } 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /pop/POPSpringAnimation.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | /** 13 | @abstract A concrete spring animation class. 14 | @discussion Animation is achieved through modeling spring dynamics. 15 | */ 16 | @interface POPSpringAnimation : POPPropertyAnimation 17 | 18 | /** 19 | @abstract The designated initializer. 20 | @returns An instance of a spring animation. 21 | */ 22 | + (instancetype)animation; 23 | 24 | /** 25 | @abstract Convenience initializer that returns an animation with animatable property of name. 26 | @param name The name of the animatable property. 27 | @returns An instance of a spring animation configured with specified animatable property. 28 | */ 29 | + (instancetype)animationWithPropertyNamed:(NSString *)name; 30 | 31 | /** 32 | @abstract The current velocity value. 33 | @discussion Set before animation start to account for initial velocity. Expressed in change of value units per second. 34 | */ 35 | @property (copy, nonatomic) id velocity; 36 | 37 | /** 38 | @abstract The effective bounciness. 39 | @discussion Use in conjunction with 'springSpeed' to change animation effect. Values are converted into corresponding dynamics constants. Higher values increase spring movement range resulting in more oscillations and springiness. Defined as a value in the range [0, 20]. Defaults to 4. 40 | */ 41 | @property (assign, nonatomic) CGFloat springBounciness; 42 | 43 | /** 44 | @abstract The effective speed. 45 | @discussion Use in conjunction with 'springBounciness' to change animation effect. Values are converted into corresponding dynamics constants. Higher values increase the dampening power of the spring resulting in a faster initial velocity and more rapid bounce slowdown. Defined as a value in the range [0, 20]. Defaults to 12. 46 | */ 47 | @property (assign, nonatomic) CGFloat springSpeed; 48 | 49 | /** 50 | @abstract The tension used in the dynamics simulation. 51 | @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect. 52 | */ 53 | @property (assign, nonatomic) CGFloat dynamicsTension; 54 | 55 | /** 56 | @abstract The friction used in the dynamics simulation. 57 | @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect. 58 | */ 59 | @property (assign, nonatomic) CGFloat dynamicsFriction; 60 | 61 | /** 62 | @abstract The mass used in the dynamics simulation. 63 | @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect. 64 | */ 65 | @property (assign, nonatomic) CGFloat dynamicsMass; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /pop/POPSpringAnimation.mm: -------------------------------------------------------------------------------- 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 | #import "POPSpringAnimationInternal.h" 11 | 12 | @implementation POPSpringAnimation 13 | 14 | #pragma mark - Lifecycle 15 | 16 | #undef __state 17 | #define __state ((POPSpringAnimationState *)_state) 18 | 19 | + (instancetype)animation 20 | { 21 | return [[self alloc] init]; 22 | } 23 | 24 | + (instancetype)animationWithPropertyNamed:(NSString *)aName 25 | { 26 | POPSpringAnimation *anim = [self animation]; 27 | anim.property = [POPAnimatableProperty propertyWithName:aName]; 28 | return anim; 29 | } 30 | 31 | - (void)_initState 32 | { 33 | _state = new POPSpringAnimationState(self); 34 | } 35 | 36 | - (id)init 37 | { 38 | self = [super _init]; 39 | if (nil != self) { 40 | __state->solver = new SpringSolver4d(1, 1, 1); 41 | __state->updatedDynamicsThreshold(); 42 | __state->updatedBouncinessAndSpeed(); 43 | } 44 | return self; 45 | } 46 | 47 | - (void)dealloc 48 | { 49 | if (__state) { 50 | delete __state->solver; 51 | __state->solver = NULL; 52 | } 53 | } 54 | 55 | #pragma mark - Properties 56 | 57 | - (id)velocity 58 | { 59 | return POPBox(__state->velocityVec, __state->valueType); 60 | } 61 | 62 | - (void)setVelocity:(id)aValue 63 | { 64 | POPPropertyAnimationState *s = __state; 65 | VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES); 66 | VectorRef origVec = POPUnbox(aValue, s->valueType, s->valueCount, YES); 67 | if (!vec_equal(vec, s->velocityVec)) { 68 | s->velocityVec = vec; 69 | s->originalVelocityVec = origVec; 70 | 71 | if (s->tracing) { 72 | [s->tracer updateVelocity:aValue]; 73 | } 74 | } 75 | } 76 | 77 | DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsTension, setDynamicsTension:, CGFloat, [self _updatedDynamicsTension];); 78 | DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsFriction, setDynamicsFriction:, CGFloat, [self _updatedDynamicsFriction];); 79 | DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsMass, setDynamicsMass:, CGFloat, [self _updatedDynamicsMass];); 80 | 81 | FB_PROPERTY_GET(POPSpringAnimationState, springSpeed, CGFloat); 82 | - (void)setSpringSpeed:(CGFloat)aFloat 83 | { 84 | POPSpringAnimationState *s = __state; 85 | if (s->userSpecifiedDynamics || aFloat != s->springSpeed) { 86 | s->springSpeed = aFloat; 87 | s->userSpecifiedDynamics = false; 88 | s->updatedBouncinessAndSpeed(); 89 | if (s->tracing) { 90 | [s->tracer updateSpeed:aFloat]; 91 | } 92 | } 93 | } 94 | 95 | FB_PROPERTY_GET(POPSpringAnimationState, springBounciness, CGFloat); 96 | - (void)setSpringBounciness:(CGFloat)aFloat 97 | { 98 | POPSpringAnimationState *s = __state; 99 | if (s->userSpecifiedDynamics || aFloat != s->springBounciness) { 100 | s->springBounciness = aFloat; 101 | s->userSpecifiedDynamics = false; 102 | s->updatedBouncinessAndSpeed(); 103 | if (s->tracing) { 104 | [s->tracer updateBounciness:aFloat]; 105 | } 106 | } 107 | } 108 | 109 | - (SpringSolver4d *)solver 110 | { 111 | return __state->solver; 112 | } 113 | 114 | - (void)setSolver:(SpringSolver4d *)aSolver 115 | { 116 | if (aSolver != __state->solver) { 117 | if (__state->solver) { 118 | delete(__state->solver); 119 | } 120 | __state->solver = aSolver; 121 | } 122 | } 123 | 124 | #pragma mark - Utility 125 | 126 | - (void)_updatedDynamicsTension 127 | { 128 | __state->userSpecifiedDynamics = true; 129 | if(__state->tracing) { 130 | [__state->tracer updateTension:__state->dynamicsTension]; 131 | } 132 | __state->updatedDynamics(); 133 | } 134 | 135 | - (void)_updatedDynamicsFriction 136 | { 137 | __state->userSpecifiedDynamics = true; 138 | if(__state->tracing) { 139 | [__state->tracer updateFriction:__state->dynamicsFriction]; 140 | } 141 | __state->updatedDynamics(); 142 | } 143 | 144 | - (void)_updatedDynamicsMass 145 | { 146 | __state->userSpecifiedDynamics = true; 147 | if(__state->tracing) { 148 | [__state->tracer updateMass:__state->dynamicsMass]; 149 | } 150 | __state->updatedDynamics(); 151 | } 152 | 153 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug 154 | { 155 | [super _appendDescription:s debug:debug]; 156 | 157 | if (debug) { 158 | if (_state->userSpecifiedDynamics) { 159 | [s appendFormat:@"; dynamics = (tension:%f, friction:%f, mass:%f)", __state->dynamicsTension, __state->dynamicsFriction, __state->dynamicsMass]; 160 | } else { 161 | [s appendFormat:@"; bounciness = %f; speed = %f", __state->springBounciness, __state->springSpeed]; 162 | } 163 | } 164 | } 165 | 166 | @end 167 | 168 | @implementation POPSpringAnimation (NSCopying) 169 | 170 | - (instancetype)copyWithZone:(NSZone *)zone { 171 | 172 | POPSpringAnimation *copy = [super copyWithZone:zone]; 173 | 174 | if (copy) { 175 | id velocity = POPBox(__state->originalVelocityVec, __state->valueType); 176 | 177 | // If velocity never gets set, then POPBox will return nil, messing up __state->valueCount. 178 | if (velocity) { 179 | copy.velocity = velocity; 180 | } 181 | 182 | copy.springBounciness = self.springBounciness; 183 | copy.springSpeed = self.springSpeed; 184 | copy.dynamicsTension = self.dynamicsTension; 185 | copy.dynamicsFriction = self.dynamicsFriction; 186 | copy.dynamicsMass = self.dynamicsMass; 187 | } 188 | 189 | return copy; 190 | } 191 | 192 | @end -------------------------------------------------------------------------------- /pop/POPSpringAnimationInternal.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import "POPAnimationExtras.h" 13 | #import "POPPropertyAnimationInternal.h" 14 | 15 | struct _POPSpringAnimationState : _POPPropertyAnimationState 16 | { 17 | SpringSolver4d *solver; 18 | CGFloat springSpeed; 19 | CGFloat springBounciness; // normalized springiness 20 | CGFloat dynamicsTension; // tension 21 | CGFloat dynamicsFriction; // friction 22 | CGFloat dynamicsMass; // mass 23 | 24 | _POPSpringAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim), 25 | solver(nullptr), 26 | springSpeed(12.), 27 | springBounciness(4.), 28 | dynamicsTension(0), 29 | dynamicsFriction(0), 30 | dynamicsMass(0) 31 | { 32 | type = kPOPAnimationSpring; 33 | } 34 | 35 | bool hasConverged() 36 | { 37 | NSUInteger count = valueCount; 38 | if (shouldRound()) { 39 | return vec_equal(previous2Vec, previousVec) && vec_equal(previousVec, toVec); 40 | } else { 41 | if (!previousVec || !previous2Vec) 42 | return false; 43 | 44 | CGFloat t = dynamicsThreshold / 5; 45 | 46 | const CGFloat *toValues = toVec->data(); 47 | const CGFloat *previousValues = previousVec->data(); 48 | const CGFloat *previous2Values = previous2Vec->data(); 49 | 50 | for (NSUInteger idx = 0; idx < count; idx++) { 51 | if ((std::abs(toValues[idx] - previousValues[idx]) >= t) || (std::abs(previous2Values[idx] - previousValues[idx]) >= t)) { 52 | return false; 53 | } 54 | } 55 | return true; 56 | } 57 | } 58 | 59 | bool isDone() { 60 | if (_POPPropertyAnimationState::isDone()) { 61 | return true; 62 | } 63 | return solver->started() && (hasConverged() || solver->hasConverged()); 64 | } 65 | 66 | void updatedDynamics() 67 | { 68 | if (NULL != solver) { 69 | solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass); 70 | } 71 | } 72 | 73 | void updatedDynamicsThreshold() 74 | { 75 | _POPPropertyAnimationState::updatedDynamicsThreshold(); 76 | if (NULL != solver) { 77 | solver->setThreshold(dynamicsThreshold); 78 | } 79 | } 80 | 81 | void updatedBouncinessAndSpeed() { 82 | [POPSpringAnimation convertBounciness:springBounciness speed:springSpeed toTension:&dynamicsTension friction:&dynamicsFriction mass:&dynamicsMass]; 83 | updatedDynamics(); 84 | } 85 | 86 | bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { 87 | // advance past not yet initialized animations 88 | if (NULL == currentVec) { 89 | return false; 90 | } 91 | 92 | CFTimeInterval localTime = time - startTime; 93 | 94 | Vector4d value = vector4d(currentVec); 95 | Vector4d toValue = vector4d(toVec); 96 | Vector4d velocity = vector4d(velocityVec); 97 | 98 | SSState4d state; 99 | state.p = toValue - value; 100 | 101 | // the solver assumes a spring of size zero 102 | // flip the velocity from user perspective to solver perspective 103 | state.v = velocity * -1; 104 | 105 | solver->advance(state, localTime, dt); 106 | value = toValue - state.p; 107 | 108 | // flip velocity back to user perspective 109 | velocity = state.v * -1; 110 | 111 | *currentVec = value; 112 | 113 | if (velocityVec) { 114 | *velocityVec = velocity; 115 | } 116 | 117 | clampCurrentValue(); 118 | 119 | return true; 120 | } 121 | 122 | virtual void reset(bool all) { 123 | _POPPropertyAnimationState::reset(all); 124 | 125 | if (solver) { 126 | solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass); 127 | solver->reset(); 128 | } 129 | } 130 | }; 131 | 132 | typedef struct _POPSpringAnimationState POPSpringAnimationState; 133 | -------------------------------------------------------------------------------- /pop/POPSpringSolver.h: -------------------------------------------------------------------------------- 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 | #import 11 | 12 | #import 13 | 14 | namespace POP { 15 | 16 | template 17 | struct SSState 18 | { 19 | T p; 20 | T v; 21 | }; 22 | 23 | template 24 | struct SSDerivative 25 | { 26 | T dp; 27 | T dv; 28 | }; 29 | 30 | typedef SSState SSState4d; 31 | typedef SSDerivative SSDerivative4d; 32 | 33 | const CFTimeInterval solverDt = 0.001f; 34 | const CFTimeInterval maxSolverDt = 30.0f; 35 | 36 | /** 37 | Templated spring solver class. 38 | */ 39 | template 40 | class SpringSolver 41 | { 42 | double _k; // stiffness 43 | double _b; // dampening 44 | double _m; // mass 45 | 46 | double _tp; // threshold 47 | double _tv; // threshold velocity 48 | double _ta; // threshold acceleration 49 | 50 | CFTimeInterval _accumulatedTime; 51 | SSState _lastState; 52 | T _lastDv; 53 | bool _started; 54 | 55 | public: 56 | SpringSolver(double k, double b, double m = 1) : _k(k), _b(b), _m(m), _started(false) 57 | { 58 | _accumulatedTime = 0; 59 | _lastState.p = T::Zero(); 60 | _lastState.v = T::Zero(); 61 | _lastDv = T::Zero(); 62 | setThreshold(1.); 63 | } 64 | 65 | ~SpringSolver() 66 | { 67 | } 68 | 69 | bool started() 70 | { 71 | return _started; 72 | } 73 | 74 | void setConstants(double k, double b, double m) 75 | { 76 | _k = k; 77 | _b = b; 78 | _m = m; 79 | } 80 | 81 | void setThreshold(double t) 82 | { 83 | _tp = t / 2; // half a unit 84 | _tv = 25.0 * t; // 5 units per second, squared for comparison 85 | _ta = 625.0 * t * t; // 5 units per second squared, squared for comparison 86 | } 87 | 88 | T acceleration(const SSState &state, double t) 89 | { 90 | return state.p*(-_k/_m) - state.v*(_b/_m); 91 | } 92 | 93 | SSDerivative evaluate(const SSState &initial, double t) 94 | { 95 | SSDerivative output; 96 | output.dp = initial.v; 97 | output.dv = acceleration(initial, t); 98 | return output; 99 | } 100 | 101 | SSDerivative evaluate(const SSState &initial, double t, double dt, const SSDerivative &d) 102 | { 103 | SSState state; 104 | state.p = initial.p + d.dp*dt; 105 | state.v = initial.v + d.dv*dt; 106 | SSDerivative output; 107 | output.dp = state.v; 108 | output.dv = acceleration(state, t+dt); 109 | return output; 110 | } 111 | 112 | void integrate(SSState &state, double t, double dt) 113 | { 114 | SSDerivative a = evaluate(state, t); 115 | SSDerivative b = evaluate(state, t, dt*0.5, a); 116 | SSDerivative c = evaluate(state, t, dt*0.5, b); 117 | SSDerivative d = evaluate(state, t, dt, c); 118 | 119 | T dpdt = (a.dp + (b.dp + c.dp)*2.0 + d.dp) * (1.0/6.0); 120 | T dvdt = (a.dv + (b.dv + c.dv)*2.0 + d.dv) * (1.0/6.0); 121 | 122 | state.p = state.p + dpdt*dt; 123 | state.v = state.v + dvdt*dt; 124 | 125 | _lastDv = dvdt; 126 | } 127 | 128 | SSState interpolate(const SSState &previous, const SSState ¤t, double alpha) 129 | { 130 | SSState state; 131 | state.p = current.p*alpha + previous.p*(1-alpha); 132 | state.v = current.v*alpha + previous.v*(1-alpha); 133 | return state; 134 | } 135 | 136 | void advance(SSState &state, double t, double dt) 137 | { 138 | _started = true; 139 | 140 | if (dt > maxSolverDt) { 141 | // excessive time step, force shut down 142 | _lastDv = _lastState.v = _lastState.p = T::Zero(); 143 | } else { 144 | _accumulatedTime += dt; 145 | 146 | SSState previousState = state, currentState = state; 147 | while (_accumulatedTime >= solverDt) { 148 | previousState = currentState; 149 | this->integrate(currentState, t, solverDt); 150 | t += solverDt; 151 | _accumulatedTime -= solverDt; 152 | } 153 | CFTimeInterval alpha = _accumulatedTime / solverDt; 154 | _lastState = state = this->interpolate(previousState, currentState, alpha); 155 | } 156 | } 157 | 158 | bool hasConverged() 159 | { 160 | if (!_started) { 161 | return false; 162 | } 163 | 164 | for (size_t idx = 0; idx < _lastState.p.size(); idx++) { 165 | if (fabs(_lastState.p(idx)) >= _tp) { 166 | return false; 167 | } 168 | } 169 | 170 | return (_lastState.v.squaredNorm() < _tv) && (_lastDv.squaredNorm() < _ta); 171 | } 172 | 173 | void reset() 174 | { 175 | _accumulatedTime = 0; 176 | _lastState.p = T::Zero(); 177 | _lastState.v = T::Zero(); 178 | _lastDv = T::Zero(); 179 | _started = false; 180 | } 181 | }; 182 | 183 | /** 184 | Convenience spring solver type definitions. 185 | */ 186 | typedef SpringSolver SpringSolver2d; 187 | typedef SpringSolver SpringSolver3d; 188 | typedef SpringSolver SpringSolver4d; 189 | } 190 | 191 | -------------------------------------------------------------------------------- /pop/WebCore/FloatConversion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 Apple Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 | * its contributors may be used to endorse or promote products derived 15 | * from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef FloatConversion_h 30 | #define FloatConversion_h 31 | 32 | #include 33 | 34 | namespace WebCore { 35 | 36 | template 37 | float narrowPrecisionToFloat(T); 38 | 39 | template<> 40 | inline float narrowPrecisionToFloat(double number) 41 | { 42 | return static_cast(number); 43 | } 44 | 45 | template 46 | CGFloat narrowPrecisionToCGFloat(T); 47 | 48 | template<> 49 | inline CGFloat narrowPrecisionToCGFloat(double number) 50 | { 51 | return static_cast(number); 52 | } 53 | 54 | } // namespace WebCore 55 | 56 | #endif // FloatConversion_h 57 | -------------------------------------------------------------------------------- /pop/WebCore/UnitBezier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef UnitBezier_h 27 | #define UnitBezier_h 28 | 29 | #include 30 | 31 | namespace WebCore { 32 | 33 | struct UnitBezier { 34 | UnitBezier(double p1x, double p1y, double p2x, double p2y) 35 | { 36 | // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). 37 | cx = 3.0 * p1x; 38 | bx = 3.0 * (p2x - p1x) - cx; 39 | ax = 1.0 - cx -bx; 40 | 41 | cy = 3.0 * p1y; 42 | by = 3.0 * (p2y - p1y) - cy; 43 | ay = 1.0 - cy - by; 44 | } 45 | 46 | double sampleCurveX(double t) 47 | { 48 | // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. 49 | return ((ax * t + bx) * t + cx) * t; 50 | } 51 | 52 | double sampleCurveY(double t) 53 | { 54 | return ((ay * t + by) * t + cy) * t; 55 | } 56 | 57 | double sampleCurveDerivativeX(double t) 58 | { 59 | return (3.0 * ax * t + 2.0 * bx) * t + cx; 60 | } 61 | 62 | // Given an x value, find a parametric value it came from. 63 | double solveCurveX(double x, double epsilon) 64 | { 65 | double t0; 66 | double t1; 67 | double t2; 68 | double x2; 69 | double d2; 70 | int i; 71 | 72 | // First try a few iterations of Newton's method -- normally very fast. 73 | for (t2 = x, i = 0; i < 8; i++) { 74 | x2 = sampleCurveX(t2) - x; 75 | if (fabs (x2) < epsilon) 76 | return t2; 77 | d2 = sampleCurveDerivativeX(t2); 78 | if (fabs(d2) < 1e-6) 79 | break; 80 | t2 = t2 - x2 / d2; 81 | } 82 | 83 | // Fall back to the bisection method for reliability. 84 | t0 = 0.0; 85 | t1 = 1.0; 86 | t2 = x; 87 | 88 | if (t2 < t0) 89 | return t0; 90 | if (t2 > t1) 91 | return t1; 92 | 93 | while (t0 < t1) { 94 | x2 = sampleCurveX(t2); 95 | if (fabs(x2 - x) < epsilon) 96 | return t2; 97 | if (x > x2) 98 | t0 = t2; 99 | else 100 | t1 = t2; 101 | t2 = (t1 - t0) * .5 + t0; 102 | } 103 | 104 | // Failure. 105 | return t2; 106 | } 107 | 108 | double solve(double x, double epsilon) 109 | { 110 | return sampleCurveY(solveCurveX(x, epsilon)); 111 | } 112 | 113 | private: 114 | double ax; 115 | double bx; 116 | double cx; 117 | 118 | double ay; 119 | double by; 120 | double cy; 121 | }; 122 | } 123 | #endif 124 | -------------------------------------------------------------------------------- /pop/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module pop { 2 | umbrella header "POP.h" 3 | 4 | exclude header "POPAnimationPrivate.h" 5 | exclude header "POPAnimatorPrivate.h" 6 | } 7 | -------------------------------------------------------------------------------- /pop/pop-ios-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.facebook.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2014 Facebook. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /pop/pop-osx-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.facebook.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Copyright © 2014 Facebook. All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /pop/pop-tvos-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.facebook.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------