diff --git a/Libraries/ART/ART.xcodeproj/project.pbxproj b/Libraries/ART/ART.xcodeproj/project.pbxproj new file mode 100644 index 00000000000..c3255c9656a --- /dev/null +++ b/Libraries/ART/ART.xcodeproj/project.pbxproj @@ -0,0 +1,371 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0CF68B051AF0549300FF9E5C /* ARTGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */; }; + 0CF68B061AF0549300FF9E5C /* ARTNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE01AF0549300FF9E5C /* ARTNode.m */; }; + 0CF68B071AF0549300FF9E5C /* ARTRenderable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */; }; + 0CF68B081AF0549300FF9E5C /* ARTShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE41AF0549300FF9E5C /* ARTShape.m */; }; + 0CF68B091AF0549300FF9E5C /* ARTSurfaceView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */; }; + 0CF68B0A1AF0549300FF9E5C /* ARTText.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE81AF0549300FF9E5C /* ARTText.m */; }; + 0CF68B0B1AF0549300FF9E5C /* ARTBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */; }; + 0CF68B0C1AF0549300FF9E5C /* ARTLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */; }; + 0CF68B0D1AF0549300FF9E5C /* ARTPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF01AF0549300FF9E5C /* ARTPattern.m */; }; + 0CF68B0E1AF0549300FF9E5C /* ARTRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */; }; + 0CF68B0F1AF0549300FF9E5C /* ARTSolidColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */; }; + 0CF68B101AF0549300FF9E5C /* RCTConvert+ART.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */; }; + 0CF68B111AF0549300FF9E5C /* ARTGroupManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */; }; + 0CF68B121AF0549300FF9E5C /* ARTNodeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */; }; + 0CF68B131AF0549300FF9E5C /* ARTRenderableManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */; }; + 0CF68B141AF0549300FF9E5C /* ARTShapeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */; }; + 0CF68B151AF0549300FF9E5C /* ARTSurfaceViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */; }; + 0CF68B161AF0549300FF9E5C /* ARTTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 0CF68ABF1AF0540F00FF9E5C /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0CF68AC11AF0540F00FF9E5C /* libART.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libART.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0CF68ADB1AF0549300FF9E5C /* ARTCGFloatArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTCGFloatArray.h; sourceTree = ""; }; + 0CF68ADC1AF0549300FF9E5C /* ARTContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTContainer.h; sourceTree = ""; }; + 0CF68ADD1AF0549300FF9E5C /* ARTGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTGroup.h; sourceTree = ""; }; + 0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTGroup.m; sourceTree = ""; }; + 0CF68ADF1AF0549300FF9E5C /* ARTNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTNode.h; sourceTree = ""; }; + 0CF68AE01AF0549300FF9E5C /* ARTNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTNode.m; sourceTree = ""; }; + 0CF68AE11AF0549300FF9E5C /* ARTRenderable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRenderable.h; sourceTree = ""; }; + 0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRenderable.m; sourceTree = ""; }; + 0CF68AE31AF0549300FF9E5C /* ARTShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTShape.h; sourceTree = ""; }; + 0CF68AE41AF0549300FF9E5C /* ARTShape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTShape.m; sourceTree = ""; }; + 0CF68AE51AF0549300FF9E5C /* ARTSurfaceView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTSurfaceView.h; sourceTree = ""; }; + 0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTSurfaceView.m; sourceTree = ""; }; + 0CF68AE71AF0549300FF9E5C /* ARTText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTText.h; sourceTree = ""; }; + 0CF68AE81AF0549300FF9E5C /* ARTText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTText.m; sourceTree = ""; }; + 0CF68AE91AF0549300FF9E5C /* ARTTextFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTTextFrame.h; sourceTree = ""; }; + 0CF68AEB1AF0549300FF9E5C /* ARTBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTBrush.h; sourceTree = ""; }; + 0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTBrush.m; sourceTree = ""; }; + 0CF68AED1AF0549300FF9E5C /* ARTLinearGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTLinearGradient.h; sourceTree = ""; }; + 0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTLinearGradient.m; sourceTree = ""; }; + 0CF68AEF1AF0549300FF9E5C /* ARTPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTPattern.h; sourceTree = ""; }; + 0CF68AF01AF0549300FF9E5C /* ARTPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTPattern.m; sourceTree = ""; }; + 0CF68AF11AF0549300FF9E5C /* ARTRadialGradient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRadialGradient.h; sourceTree = ""; }; + 0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRadialGradient.m; sourceTree = ""; }; + 0CF68AF31AF0549300FF9E5C /* ARTSolidColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTSolidColor.h; sourceTree = ""; }; + 0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTSolidColor.m; sourceTree = ""; }; + 0CF68AF61AF0549300FF9E5C /* RCTConvert+ART.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+ART.h"; sourceTree = ""; }; + 0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+ART.m"; sourceTree = ""; }; + 0CF68AF91AF0549300FF9E5C /* ARTGroupManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTGroupManager.h; sourceTree = ""; }; + 0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTGroupManager.m; sourceTree = ""; }; + 0CF68AFB1AF0549300FF9E5C /* ARTNodeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTNodeManager.h; sourceTree = ""; }; + 0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTNodeManager.m; sourceTree = ""; }; + 0CF68AFD1AF0549300FF9E5C /* ARTRenderableManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRenderableManager.h; sourceTree = ""; }; + 0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRenderableManager.m; sourceTree = ""; }; + 0CF68AFF1AF0549300FF9E5C /* ARTShapeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTShapeManager.h; sourceTree = ""; }; + 0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTShapeManager.m; sourceTree = ""; }; + 0CF68B011AF0549300FF9E5C /* ARTSurfaceViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTSurfaceViewManager.h; sourceTree = ""; }; + 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTSurfaceViewManager.m; sourceTree = ""; }; + 0CF68B031AF0549300FF9E5C /* ARTTextManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTTextManager.h; sourceTree = ""; }; + 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTTextManager.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0CF68ABE1AF0540F00FF9E5C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0CF68AB81AF0540F00FF9E5C = { + isa = PBXGroup; + children = ( + 0CF68ADB1AF0549300FF9E5C /* ARTCGFloatArray.h */, + 0CF68ADC1AF0549300FF9E5C /* ARTContainer.h */, + 0CF68ADD1AF0549300FF9E5C /* ARTGroup.h */, + 0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */, + 0CF68ADF1AF0549300FF9E5C /* ARTNode.h */, + 0CF68AE01AF0549300FF9E5C /* ARTNode.m */, + 0CF68AE11AF0549300FF9E5C /* ARTRenderable.h */, + 0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */, + 0CF68AE31AF0549300FF9E5C /* ARTShape.h */, + 0CF68AE41AF0549300FF9E5C /* ARTShape.m */, + 0CF68AE51AF0549300FF9E5C /* ARTSurfaceView.h */, + 0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */, + 0CF68AE71AF0549300FF9E5C /* ARTText.h */, + 0CF68AE81AF0549300FF9E5C /* ARTText.m */, + 0CF68AE91AF0549300FF9E5C /* ARTTextFrame.h */, + 0CF68AEA1AF0549300FF9E5C /* Brushes */, + 0CF68AF61AF0549300FF9E5C /* RCTConvert+ART.h */, + 0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */, + 0CF68AF81AF0549300FF9E5C /* ViewManagers */, + 0CF68AC21AF0540F00FF9E5C /* Products */, + ); + sourceTree = ""; + }; + 0CF68AC21AF0540F00FF9E5C /* Products */ = { + isa = PBXGroup; + children = ( + 0CF68AC11AF0540F00FF9E5C /* libART.a */, + ); + name = Products; + sourceTree = ""; + }; + 0CF68AEA1AF0549300FF9E5C /* Brushes */ = { + isa = PBXGroup; + children = ( + 0CF68AEB1AF0549300FF9E5C /* ARTBrush.h */, + 0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */, + 0CF68AED1AF0549300FF9E5C /* ARTLinearGradient.h */, + 0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */, + 0CF68AEF1AF0549300FF9E5C /* ARTPattern.h */, + 0CF68AF01AF0549300FF9E5C /* ARTPattern.m */, + 0CF68AF11AF0549300FF9E5C /* ARTRadialGradient.h */, + 0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */, + 0CF68AF31AF0549300FF9E5C /* ARTSolidColor.h */, + 0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */, + ); + path = Brushes; + sourceTree = ""; + }; + 0CF68AF81AF0549300FF9E5C /* ViewManagers */ = { + isa = PBXGroup; + children = ( + 0CF68AF91AF0549300FF9E5C /* ARTGroupManager.h */, + 0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */, + 0CF68AFB1AF0549300FF9E5C /* ARTNodeManager.h */, + 0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */, + 0CF68AFD1AF0549300FF9E5C /* ARTRenderableManager.h */, + 0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */, + 0CF68AFF1AF0549300FF9E5C /* ARTShapeManager.h */, + 0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */, + 0CF68B011AF0549300FF9E5C /* ARTSurfaceViewManager.h */, + 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */, + 0CF68B031AF0549300FF9E5C /* ARTTextManager.h */, + 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */, + ); + path = ViewManagers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0CF68AC01AF0540F00FF9E5C /* ART */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0CF68AD51AF0540F00FF9E5C /* Build configuration list for PBXNativeTarget "ART" */; + buildPhases = ( + 0CF68ABD1AF0540F00FF9E5C /* Sources */, + 0CF68ABE1AF0540F00FF9E5C /* Frameworks */, + 0CF68ABF1AF0540F00FF9E5C /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ART; + productName = ART; + productReference = 0CF68AC11AF0540F00FF9E5C /* libART.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0CF68AB91AF0540F00FF9E5C /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0620; + TargetAttributes = { + 0CF68AC01AF0540F00FF9E5C = { + CreatedOnToolsVersion = 6.2; + }; + }; + }; + buildConfigurationList = 0CF68ABC1AF0540F00FF9E5C /* Build configuration list for PBXProject "ART" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 0CF68AB81AF0540F00FF9E5C; + productRefGroup = 0CF68AC21AF0540F00FF9E5C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0CF68AC01AF0540F00FF9E5C /* ART */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 0CF68ABD1AF0540F00FF9E5C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0CF68B161AF0549300FF9E5C /* ARTTextManager.m in Sources */, + 0CF68B111AF0549300FF9E5C /* ARTGroupManager.m in Sources */, + 0CF68B0D1AF0549300FF9E5C /* ARTPattern.m in Sources */, + 0CF68B0A1AF0549300FF9E5C /* ARTText.m in Sources */, + 0CF68B121AF0549300FF9E5C /* ARTNodeManager.m in Sources */, + 0CF68B051AF0549300FF9E5C /* ARTGroup.m in Sources */, + 0CF68B131AF0549300FF9E5C /* ARTRenderableManager.m in Sources */, + 0CF68B091AF0549300FF9E5C /* ARTSurfaceView.m in Sources */, + 0CF68B0E1AF0549300FF9E5C /* ARTRadialGradient.m in Sources */, + 0CF68B151AF0549300FF9E5C /* ARTSurfaceViewManager.m in Sources */, + 0CF68B081AF0549300FF9E5C /* ARTShape.m in Sources */, + 0CF68B071AF0549300FF9E5C /* ARTRenderable.m in Sources */, + 0CF68B101AF0549300FF9E5C /* RCTConvert+ART.m in Sources */, + 0CF68B061AF0549300FF9E5C /* ARTNode.m in Sources */, + 0CF68B0F1AF0549300FF9E5C /* ARTSolidColor.m in Sources */, + 0CF68B0C1AF0549300FF9E5C /* ARTLinearGradient.m in Sources */, + 0CF68B0B1AF0549300FF9E5C /* ARTBrush.m in Sources */, + 0CF68B141AF0549300FF9E5C /* ARTShapeManager.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0CF68AD31AF0540F00FF9E5C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../React/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 0CF68AD41AF0540F00FF9E5C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../React/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0CF68AD61AF0540F00FF9E5C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 0CF68AD71AF0540F00FF9E5C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0CF68ABC1AF0540F00FF9E5C /* Build configuration list for PBXProject "ART" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0CF68AD31AF0540F00FF9E5C /* Debug */, + 0CF68AD41AF0540F00FF9E5C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0CF68AD51AF0540F00FF9E5C /* Build configuration list for PBXNativeTarget "ART" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0CF68AD61AF0540F00FF9E5C /* Debug */, + 0CF68AD71AF0540F00FF9E5C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0CF68AB91AF0540F00FF9E5C /* Project object */; +} diff --git a/Libraries/ART/ARTCGFloatArray.h b/Libraries/ART/ARTCGFloatArray.h new file mode 100644 index 00000000000..9d748549973 --- /dev/null +++ b/Libraries/ART/ARTCGFloatArray.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +// A little helper to make sure we have the right memory allocation ready for use. +// We assume that we will only this in one place so no reference counting is necessary. +// Needs to be freed when dealloced. + +// This is fragile since this relies on these values not getting reused. Consider +// wrapping these in an Obj-C class or some ARC hackery to get refcounting. + +typedef struct { + size_t count; + CGFloat *array; +} ARTCGFloatArray; diff --git a/Libraries/ART/ARTContainer.h b/Libraries/ART/ARTContainer.h new file mode 100644 index 00000000000..d83f7ae1a55 --- /dev/null +++ b/Libraries/ART/ARTContainer.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +@protocol ARTContainer + +// This is used as a hook for child to mark it's parent as dirty. +// This bubbles up to the root which gets marked as dirty. +- (void)invalidate; + +@end diff --git a/Libraries/ART/ARTGroup.h b/Libraries/ART/ARTGroup.h new file mode 100644 index 00000000000..15a8b643bb8 --- /dev/null +++ b/Libraries/ART/ARTGroup.h @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "ARTContainer.h" +#import "ARTNode.h" + +@interface ARTGroup : ARTNode + +@end diff --git a/Libraries/ART/ARTGroup.m b/Libraries/ART/ARTGroup.m new file mode 100644 index 00000000000..9ecbf8ee821 --- /dev/null +++ b/Libraries/ART/ARTGroup.m @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTGroup.h" + +@implementation ARTGroup + +- (void)renderLayerTo:(CGContextRef)context +{ +// TO-DO: Clipping rectangle + + for (ARTNode *node in self.subviews) { + [node renderTo:context]; + } +} + +@end diff --git a/Libraries/ART/ARTNode.h b/Libraries/ART/ARTNode.h new file mode 100644 index 00000000000..511c09a5a6a --- /dev/null +++ b/Libraries/ART/ARTNode.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import +#import + +/** + * ART nodes are implemented as empty UIViews but this is just an implementation detail to fit + * into the existing view management. They should also be shadow views and painted on a background + * thread. + */ + +@interface ARTNode : UIView + +@property (nonatomic, assign) CGFloat opacity; + +- (void)invalidate; +- (void)renderTo:(CGContextRef)context; + +/** + * renderTo will take opacity into account and draw renderLayerTo off-screen if there is opacity + * specified, then composite that onto the context. renderLayerTo always draws at opacity=1. + * @abstract + */ +- (void)renderLayerTo:(CGContextRef)context; + +@end diff --git a/Libraries/ART/ARTNode.m b/Libraries/ART/ARTNode.m new file mode 100644 index 00000000000..d23d5880a95 --- /dev/null +++ b/Libraries/ART/ARTNode.m @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTNode.h" + +#import "ARTContainer.h" + +@implementation ARTNode + +- (void)insertSubview:(UIView *)subview atIndex:(NSInteger)index +{ + [self invalidate]; + [super insertSubview:subview atIndex:index]; +} + +- (void)removeFromSuperview +{ + [self invalidate]; + [super removeFromSuperview]; +} + +- (void)setOpacity:(CGFloat)opacity +{ + [self invalidate]; + _opacity = opacity; +} + +- (void)setTransform:(CGAffineTransform)transform +{ + [self invalidate]; + super.transform = transform; +} + +- (void)invalidate +{ + id container = (id)self.superview; + [container invalidate]; +} + +- (void)renderTo:(CGContextRef)context +{ + if (self.opacity <= 0) { + // Nothing to paint + return; + } + if (self.opacity >= 1) { + // Just paint at full opacity + CGContextSaveGState(context); + CGContextConcatCTM(context, self.transform); + CGContextSetAlpha(context, 1); + [self renderLayerTo:context]; + CGContextRestoreGState(context); + return; + } + // This needs to be painted on a layer before being composited. + CGContextSaveGState(context); + CGContextConcatCTM(context, self.transform); + CGContextSetAlpha(context, self.opacity); + CGContextBeginTransparencyLayer(context, NULL); + [self renderLayerTo:context]; + CGContextEndTransparencyLayer(context); + CGContextRestoreGState(context); +} + +- (void)renderLayerTo:(CGContextRef)context +{ + // abstract +} + +@end diff --git a/Libraries/ART/ARTRenderable.h b/Libraries/ART/ARTRenderable.h new file mode 100644 index 00000000000..8eae9c25ae4 --- /dev/null +++ b/Libraries/ART/ARTRenderable.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "ARTBrush.h" +#import "ARTCGFloatArray.h" +#import "ARTNode.h" + +@interface ARTRenderable : ARTNode + +@property (nonatomic, strong) ARTBrush *fill; +@property (nonatomic, assign) CGColorRef stroke; +@property (nonatomic, assign) CGFloat strokeWidth; +@property (nonatomic, assign) CGLineCap strokeCap; +@property (nonatomic, assign) CGLineJoin strokeJoin; +@property (nonatomic, assign) ARTCGFloatArray strokeDash; + +@end diff --git a/Libraries/ART/ARTRenderable.m b/Libraries/ART/ARTRenderable.m new file mode 100644 index 00000000000..7ba9a9a6073 --- /dev/null +++ b/Libraries/ART/ARTRenderable.m @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTRenderable.h" + +@implementation ARTRenderable + +- (void)setFill:(ARTBrush *)fill +{ + [self invalidate]; + _fill = fill; +} + +- (void)setStroke:(CGColorRef)stroke +{ + if (stroke == _stroke) { + return; + } + [self invalidate]; + CGColorRelease(_stroke); + _stroke = CGColorRetain(stroke); +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth +{ + [self invalidate]; + _strokeWidth = strokeWidth; +} + +- (void)setStrokeCap:(CGLineCap)strokeCap +{ + [self invalidate]; + _strokeCap = strokeCap; +} + +- (void)setStrokeJoin:(CGLineJoin)strokeJoin +{ + [self invalidate]; + _strokeJoin = strokeJoin; +} + +- (void)setStrokeDash:(ARTCGFloatArray)strokeDash +{ + if (strokeDash.array == _strokeDash.array) { + return; + } + if (_strokeDash.array) { + free(_strokeDash.array); + } + [self invalidate]; + _strokeDash = strokeDash; +} + +- (void)dealloc +{ + CGColorRelease(_stroke); + if (_strokeDash.array) { + free(_strokeDash.array); + } +} + +- (void)renderTo:(CGContextRef)context +{ + if (self.opacity <= 0 || self.opacity >= 1 || (self.fill && self.stroke)) { + // If we have both fill and stroke, we will need to paint this using normal compositing + [super renderTo: context]; + return; + } + // This is a terminal with only one painting. Therefore we don't need to paint this + // off-screen. We can just composite it straight onto the buffer. + CGContextSaveGState(context); + CGContextConcatCTM(context, self.transform); + CGContextSetAlpha(context, self.opacity); + [self renderLayerTo:context]; + CGContextRestoreGState(context); +} + +- (void)renderLayerTo:(CGContextRef)context +{ + // abstract +} + +@end diff --git a/Libraries/ART/ARTSerializablePath.js b/Libraries/ART/ARTSerializablePath.js new file mode 100644 index 00000000000..2df8ff6bb83 --- /dev/null +++ b/Libraries/ART/ARTSerializablePath.js @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ARTSerializablePath + */ + +"use strict"; + +// TODO: Move this into an ART mode called "serialized" or something + +var Class = require('art/core/class.js'); +var Path = require('art/core/path.js'); + +var MOVE_TO = 0; +var CLOSE = 1; +var LINE_TO = 2; +var CURVE_TO = 3; +var ARC = 4; + +var SerializablePath = Class(Path, { + + initialize: function(path) { + this.reset(); + if (path instanceof SerializablePath) { + this.path = path.path.slice(0); + } else if (path) { + if (path.applyToPath) { + path.applyToPath(this); + } else { + this.push(path); + } + } + }, + + onReset: function() { + this.path = []; + }, + + onMove: function(sx, sy, x, y) { + this.path.push(MOVE_TO, x, y); + }, + + onLine: function(sx, sy, x, y) { + this.path.push(LINE_TO, x, y); + }, + + onBezierCurve: function(sx, sy, p1x, p1y, p2x, p2y, x, y) { + this.path.push(CURVE_TO, p1x, p1y, p2x, p2y, x, y); + }, + + _arcToBezier: Path.prototype.onArc, + + onArc: function(sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation) { + if (rx !== ry || rotation) { + return this._arcToBezier( + sx, sy, ex, ey, cx, cy, rx, ry, sa, ea, ccw, rotation + ); + } + this.path.push(ARC, cx, cy, rx, sa, ea, ccw ? 0 : 1); + }, + + onClose: function() { + this.path.push(CLOSE); + }, + + toJSON: function() { + return this.path; + } + +}); + +module.exports = SerializablePath; diff --git a/Libraries/ART/ARTShape.h b/Libraries/ART/ARTShape.h new file mode 100644 index 00000000000..7d13c268f6e --- /dev/null +++ b/Libraries/ART/ARTShape.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "ARTRenderable.h" + +@interface ARTShape : ARTRenderable + +@property (nonatomic, assign) CGPathRef d; + +@end diff --git a/Libraries/ART/ARTShape.m b/Libraries/ART/ARTShape.m new file mode 100644 index 00000000000..c07d68e62aa --- /dev/null +++ b/Libraries/ART/ARTShape.m @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTShape.h" + +@implementation ARTShape + +- (void)setD:(CGPathRef)d +{ + if (d == _d) { + return; + } + [self invalidate]; + CGPathRelease(_d); + _d = CGPathRetain(d); +} + +- (void)dealloc +{ + CGPathRelease(_d); +} + +- (void)renderLayerTo:(CGContextRef)context +{ + if ((!self.fill && !self.stroke) || !self.d) { + return; + } + + CGPathDrawingMode mode = kCGPathStroke; + if (self.fill) { + if ([self.fill applyFillColor:context]) { + mode = kCGPathFill; + } else { + CGContextSaveGState(context); + CGContextAddPath(context, self.d); + CGContextClip(context); + [self.fill paint:context]; + CGContextRestoreGState(context); + if (!self.stroke) { + return; + } + } + } + if (self.stroke) { + CGContextSetStrokeColorWithColor(context, self.stroke); + CGContextSetLineWidth(context, self.strokeWidth); + CGContextSetLineCap(context, self.strokeCap); + CGContextSetLineJoin(context, self.strokeJoin); + ARTCGFloatArray dash = self.strokeDash; + if (dash.count) { + CGContextSetLineDash(context, 0, dash.array, dash.count); + } + if (mode == kCGPathFill) { + mode = kCGPathFillStroke; + } + } + + CGContextAddPath(context, self.d); + CGContextDrawPath(context, mode); +} + +@end diff --git a/Libraries/ART/ARTSurfaceView.h b/Libraries/ART/ARTSurfaceView.h new file mode 100644 index 00000000000..8be8d95040c --- /dev/null +++ b/Libraries/ART/ARTSurfaceView.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "ARTContainer.h" + +@interface ARTSurfaceView : UIView + +@end diff --git a/Libraries/ART/ARTSurfaceView.m b/Libraries/ART/ARTSurfaceView.m new file mode 100644 index 00000000000..8949e43c349 --- /dev/null +++ b/Libraries/ART/ARTSurfaceView.m @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTSurfaceView.h" + +#import "ARTNode.h" +#import "RCTLog.h" + +@implementation ARTSurfaceView + +- (void)invalidate +{ + [self setNeedsDisplay]; +} + +- (void)drawRect:(CGRect)rect +{ + CGContextRef context = UIGraphicsGetCurrentContext(); + for (ARTNode *node in self.subviews) { + [node renderTo:context]; + } +} + +@end diff --git a/Libraries/ART/ARTText.h b/Libraries/ART/ARTText.h new file mode 100644 index 00000000000..ee976e329a4 --- /dev/null +++ b/Libraries/ART/ARTText.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "ARTRenderable.h" +#import "ARTTextFrame.h" + +@interface ARTText : ARTRenderable + +@property (nonatomic, assign) CTTextAlignment alignment; +@property (nonatomic, assign) ARTTextFrame textFrame; + +@end diff --git a/Libraries/ART/ARTText.m b/Libraries/ART/ARTText.m new file mode 100644 index 00000000000..7c8a570270b --- /dev/null +++ b/Libraries/ART/ARTText.m @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTText.h" + +#import + +@implementation ARTText + +- (void)setAlignment:(CTTextAlignment)alignment +{ + [self invalidate]; + _alignment = alignment; +} + +- (void)setTextFrame:(ARTTextFrame)frame +{ + if (frame.lines != _textFrame.lines && _textFrame.count) { + // We must release each line before overriding the old one + for (int i = 0; i < _textFrame.count; i++) { + CFRelease(_textFrame.lines[0]); + } + free(_textFrame.lines); + free(_textFrame.widths); + } + [self invalidate]; + _textFrame = frame; +} + +- (void)dealloc +{ + if (_textFrame.count) { + // We must release each line before freeing up this struct + for (int i = 0; i < _textFrame.count; i++) { + CFRelease(_textFrame.lines[0]); + } + free(_textFrame.lines); + free(_textFrame.widths); + } +} + +- (void)renderLayerTo:(CGContextRef)context +{ + ARTTextFrame frame = self.textFrame; + + if ((!self.fill && !self.stroke) || !frame.count) { + return; + } + + // to-do: draw along a path + + CGTextDrawingMode mode = kCGTextStroke; + if (self.fill) { + if ([self.fill applyFillColor:context]) { + mode = kCGTextFill; + } else { + + for (int i = 0; i < frame.count; i++) { + CGContextSaveGState(context); + // Inverse the coordinate space since CoreText assumes a bottom-up coordinate space + CGContextScaleCTM(context, 1.0, -1.0); + CGContextSetTextDrawingMode(context, kCGTextClip); + [self renderLineTo:context atIndex:i]; + // Inverse the coordinate space back to the original before filling + CGContextScaleCTM(context, 1.0, -1.0); + [self.fill paint:context]; + // Restore the state so that the next line can be clipped separately + CGContextRestoreGState(context); + } + + if (!self.stroke) { + return; + } + } + } + if (self.stroke) { + CGContextSetStrokeColorWithColor(context, self.stroke); + CGContextSetLineWidth(context, self.strokeWidth); + CGContextSetLineCap(context, self.strokeCap); + CGContextSetLineJoin(context, self.strokeJoin); + ARTCGFloatArray dash = self.strokeDash; + if (dash.count) { + CGContextSetLineDash(context, 0, dash.array, dash.count); + } + if (mode == kCGTextFill) { + mode = kCGTextFillStroke; + } + } + + CGContextSetTextDrawingMode(context, mode); + + // Inverse the coordinate space since CoreText assumes a bottom-up coordinate space + CGContextScaleCTM(context, 1.0, -1.0); + for (int i = 0; i < frame.count; i++) { + [self renderLineTo:context atIndex:i]; + } +} + +- (void)renderLineTo:(CGContextRef)context atIndex:(int)index +{ + ARTTextFrame frame = self.textFrame; + CGFloat shift; + switch (self.alignment) { + case kCTTextAlignmentRight: + shift = frame.widths[index]; + break; + case kCTTextAlignmentCenter: + shift = (frame.widths[index] / 2); + break; + default: + shift = 0; + break; + } + // We should consider snapping this shift to device pixels to improve rendering quality + // when a line has subpixel width. + CGContextSetTextPosition(context, -shift, -frame.baseLine - frame.lineHeight * index); + CTLineRef line = frame.lines[index]; + CTLineDraw(line, context); +} + +@end diff --git a/Libraries/ART/ARTTextFrame.h b/Libraries/ART/ARTTextFrame.h new file mode 100644 index 00000000000..1f6b557bfc7 --- /dev/null +++ b/Libraries/ART/ARTTextFrame.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +// A little helper to make sure we have a set of lines including width ready for use. +// We assume that we will only this in one place so no reference counting is necessary. +// Needs to be freed when dealloced. + +// This is fragile since this relies on these values not getting reused. Consider +// wrapping these in an Obj-C class or some ARC hackery to get refcounting. + +typedef struct { + size_t count; + CGFloat baseLine; // Distance from the origin to the base line of the first line + CGFloat lineHeight; // Distance between lines + CTLineRef *lines; + CGFloat *widths; // Width of each line +} ARTTextFrame; diff --git a/Libraries/ART/Brushes/ARTBrush.h b/Libraries/ART/Brushes/ARTBrush.h new file mode 100644 index 00000000000..05020dd7baf --- /dev/null +++ b/Libraries/ART/Brushes/ARTBrush.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import +#import + +@interface ARTBrush : NSObject + +/* @abstract */ +- (instancetype)initWithArray:(NSArray *)data NS_DESIGNATED_INITIALIZER; + +/** + * For certain brushes we can fast path a combined fill and stroke. + * For those brushes we override applyFillColor which sets the fill + * color to be used by those batch paints. Those return YES. + * We can't batch gradient painting in CoreGraphics, so those will + * return NO and paint gets called instead. + * @abstract + */ +- (BOOL)applyFillColor:(CGContextRef)context; + +/** + * paint fills the context with a brush. The context is assumed to + * be clipped. + * @abstract + */ +- (void)paint:(CGContextRef)context; + +@end diff --git a/Libraries/ART/Brushes/ARTBrush.m b/Libraries/ART/Brushes/ARTBrush.m new file mode 100644 index 00000000000..efc82dea35b --- /dev/null +++ b/Libraries/ART/Brushes/ARTBrush.m @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTBrush.h" + +@implementation ARTBrush + +- (instancetype)initWithArray:(NSArray *)data +{ + return [super init]; +} + +- (BOOL)applyFillColor:(CGContextRef)context +{ + return NO; +} + +- (void)paint:(CGContextRef)context +{ + // abstract +} + +@end diff --git a/Libraries/ART/Brushes/ARTLinearGradient.h b/Libraries/ART/Brushes/ARTLinearGradient.h new file mode 100644 index 00000000000..d7ff2e56844 --- /dev/null +++ b/Libraries/ART/Brushes/ARTLinearGradient.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTBrush.h" + +@interface ARTLinearGradient : ARTBrush + +@end diff --git a/Libraries/ART/Brushes/ARTLinearGradient.m b/Libraries/ART/Brushes/ARTLinearGradient.m new file mode 100644 index 00000000000..8793ff07bf7 --- /dev/null +++ b/Libraries/ART/Brushes/ARTLinearGradient.m @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTLinearGradient.h" + +#import "RCTConvert+ART.h" +#import "RCTLog.h" + +@implementation ARTLinearGradient +{ + CGGradientRef _gradient; + CGPoint _startPoint; + CGPoint _endPoint; +} + +- (instancetype)initWithArray:(NSArray *)array +{ + if ((self = [super initWithArray:array])) { + if (array.count < 5) { + RCTLogError(@"-[%@ %@] expects 5 elements, received %@", + self.class, NSStringFromSelector(_cmd), array); + return nil; + } + _startPoint = [RCTConvert CGPoint:array offset:1]; + _endPoint = [RCTConvert CGPoint:array offset:3]; + _gradient = CGGradientRetain([RCTConvert CGGradient:array offset:5]); + } + return self; +} + +- (void)dealloc +{ + CGGradientRelease(_gradient); +} + +- (void)paint:(CGContextRef)context +{ + CGGradientDrawingOptions extendOptions = + kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; + CGContextDrawLinearGradient(context, _gradient, _startPoint, _endPoint, extendOptions); +} + +@end diff --git a/Libraries/ART/Brushes/ARTPattern.h b/Libraries/ART/Brushes/ARTPattern.h new file mode 100644 index 00000000000..5f513ec60e2 --- /dev/null +++ b/Libraries/ART/Brushes/ARTPattern.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTBrush.h" + +@interface ARTPattern : ARTBrush + +@end diff --git a/Libraries/ART/Brushes/ARTPattern.m b/Libraries/ART/Brushes/ARTPattern.m new file mode 100644 index 00000000000..07dd8670018 --- /dev/null +++ b/Libraries/ART/Brushes/ARTPattern.m @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTPattern.h" + +#import "RCTConvert+ART.h" +#import "RCTLog.h" + +@implementation ARTPattern +{ + CGImageRef _image; + CGRect _rect; +} + +- (instancetype)initWithArray:(NSArray *)array +{ + if ((self = [super initWithArray:array])) { + if (array.count < 6) { + RCTLogError(@"-[%@ %@] expects 6 elements, received %@", + self.class, NSStringFromSelector(_cmd), array); + return nil; + } + _image = CGImageRetain([RCTConvert CGImage:array[1]]); + _rect = [RCTConvert CGRect:array offset:2]; + } + return self; +} + +- (void)dealloc +{ + CGImageRelease(_image); +} + +// Note: This could use applyFillColor with a pattern. This could be more efficient but +// to do that, we need to calculate our own user space CTM. + +- (void)paint:(CGContextRef)context +{ + CGContextDrawTiledImage(context, _rect, _image); +} + + + +@end diff --git a/Libraries/ART/Brushes/ARTRadialGradient.h b/Libraries/ART/Brushes/ARTRadialGradient.h new file mode 100644 index 00000000000..7f86d93058c --- /dev/null +++ b/Libraries/ART/Brushes/ARTRadialGradient.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTBrush.h" + +@interface ARTRadialGradient : ARTBrush + +@end diff --git a/Libraries/ART/Brushes/ARTRadialGradient.m b/Libraries/ART/Brushes/ARTRadialGradient.m new file mode 100644 index 00000000000..b59b1736937 --- /dev/null +++ b/Libraries/ART/Brushes/ARTRadialGradient.m @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTRadialGradient.h" + +#import "RCTConvert+ART.h" +#import "RCTLog.h" + +@implementation ARTRadialGradient +{ + CGGradientRef _gradient; + CGPoint _focusPoint; + CGPoint _centerPoint; + CGFloat _radius; + CGFloat _radiusRatio; +} + +- (instancetype)initWithArray:(NSArray *)array +{ + if ((self = [super initWithArray:array])) { + if (array.count < 7) { + RCTLogError(@"-[%@ %@] expects 7 elements, received %@", + self.class, NSStringFromSelector(_cmd), array); + return nil; + } + _radius = [RCTConvert CGFloat:array[3]]; + _radiusRatio = [RCTConvert CGFloat:array[4]] / _radius; + _focusPoint.x = [RCTConvert CGFloat:array[1]]; + _focusPoint.y = [RCTConvert CGFloat:array[2]] / _radiusRatio; + _centerPoint.x = [RCTConvert CGFloat:array[5]]; + _centerPoint.y = [RCTConvert CGFloat:array[6]] / _radiusRatio; + _gradient = CGGradientRetain([RCTConvert CGGradient:array offset:7]); + } + return self; +} + +- (void)dealloc +{ + CGGradientRelease(_gradient); +} + +- (void)paint:(CGContextRef)context +{ + CGAffineTransform transform = CGAffineTransformMakeScale(1, _radiusRatio); + CGContextConcatCTM(context, transform); + CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; + CGContextDrawRadialGradient(context, _gradient, _focusPoint, 0, _centerPoint, _radius, extendOptions); +} + +@end diff --git a/Libraries/ART/Brushes/ARTSolidColor.h b/Libraries/ART/Brushes/ARTSolidColor.h new file mode 100644 index 00000000000..f212c735680 --- /dev/null +++ b/Libraries/ART/Brushes/ARTSolidColor.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTBrush.h" + +@interface ARTSolidColor : ARTBrush + +@end diff --git a/Libraries/ART/Brushes/ARTSolidColor.m b/Libraries/ART/Brushes/ARTSolidColor.m new file mode 100644 index 00000000000..229942ddec6 --- /dev/null +++ b/Libraries/ART/Brushes/ARTSolidColor.m @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTSolidColor.h" + +#import "RCTConvert+ART.h" +#import "RCTLog.h" + +@implementation ARTSolidColor +{ + CGColorRef _color; +} + +- (instancetype)initWithArray:(NSArray *)array +{ + if ((self = [super initWithArray:array])) { + _color = CGColorRetain([RCTConvert CGColor:array offset:1]); + } + return self; +} + +- (void)dealloc +{ + CGColorRelease(_color); +} + +- (BOOL)applyFillColor:(CGContextRef)context +{ + CGContextSetFillColorWithColor(context, _color); + return YES; +} + +@end diff --git a/Libraries/ART/RCTConvert+ART.h b/Libraries/ART/RCTConvert+ART.h new file mode 100644 index 00000000000..24944fb1298 --- /dev/null +++ b/Libraries/ART/RCTConvert+ART.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "ARTBrush.h" +#import "ARTCGFloatArray.h" +#import "ARTTextFrame.h" +#import "RCTConvert.h" + +@interface RCTConvert (ART) + ++ (CGPathRef)CGPath:(id)json; ++ (CTFontRef)CTFont:(id)json; ++ (CTTextAlignment)CTTextAlignment:(id)json; ++ (ARTTextFrame)ARTTextFrame:(id)json; ++ (ARTCGFloatArray)ARTCGFloatArray:(id)json; ++ (ARTBrush *)ARTBrush:(id)json; + ++ (CGPoint)CGPoint:(id)json offset:(NSUInteger)offset; ++ (CGRect)CGRect:(id)json offset:(NSUInteger)offset; ++ (CGColorRef)CGColor:(id)json offset:(NSUInteger)offset; ++ (CGGradientRef)CGGradient:(id)json offset:(NSUInteger)offset; + +@end diff --git a/Libraries/ART/RCTConvert+ART.m b/Libraries/ART/RCTConvert+ART.m new file mode 100644 index 00000000000..4cd11bd3fbb --- /dev/null +++ b/Libraries/ART/RCTConvert+ART.m @@ -0,0 +1,234 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTConvert+ART.h" + +#import "ARTLinearGradient.h" +#import "ARTPattern.h" +#import "ARTRadialGradient.h" +#import "ARTSolidColor.h" +#import "RCTLog.h" + +@implementation RCTConvert (ART) + ++ (CGPathRef)CGPath:(id)json +{ + NSArray *arr = [self NSNumberArray:json]; + + NSUInteger count = [arr count]; + +#define NEXT_VALUE [self double:arr[i++]] + + CGMutablePathRef path = CGPathCreateMutable(); + CGPathMoveToPoint(path, NULL, 0, 0); + + @try { + NSUInteger i = 0; + while (i < count) { + NSUInteger type = [arr[i++] unsignedIntegerValue]; + switch (type) { + case 0: + CGPathMoveToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE); + break; + case 1: + CGPathCloseSubpath(path); + break; + case 2: + CGPathAddLineToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE); + break; + case 3: + CGPathAddCurveToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE); + break; + case 4: + CGPathAddArc(path, NULL, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE == 0); + break; + default: + RCTLogError(@"Invalid CGPath type %zd at element %zd of %@", type, i, arr); + CGPathRelease(path); + return NULL; + } + } + } + @catch (NSException *exception) { + RCTLogError(@"Invalid CGPath format: %@", arr); + CGPathRelease(path); + return NULL; + } + + return (CGPathRef)CFAutorelease(path); +} + ++ (CTFontRef)CTFont:(id)json +{ + NSDictionary *dict = [self NSDictionary:json]; + if (!dict) { + return nil; + } + CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)dict); + CTFontRef font = CTFontCreateWithFontDescriptor(fontDescriptor, 0.0, NULL); + CFRelease(fontDescriptor); + return (CTFontRef)CFAutorelease(font); +} + +RCT_ENUM_CONVERTER(CTTextAlignment, (@{ + @"auto": @(kCTTextAlignmentNatural), + @"left": @(kCTTextAlignmentLeft), + @"center": @(kCTTextAlignmentCenter), + @"right": @(kCTTextAlignmentRight), + @"justify": @(kCTTextAlignmentJustified), +}), kCTTextAlignmentNatural, integerValue) + +// This takes a tuple of text lines and a font to generate a CTLine for each text line. +// This prepares everything for rendering a frame of text in ARTText. ++ (ARTTextFrame)ARTTextFrame:(id)json +{ + NSDictionary *dict = [self NSDictionary:json]; + ARTTextFrame frame; + frame.count = 0; + + NSArray *lines = [self NSArray:dict[@"lines"]]; + NSUInteger lineCount = [lines count]; + if (lineCount == 0) { + return frame; + } + + CTFontRef font = [self CTFont:dict[@"font"]]; + if (!font) { + return frame; + } + + // Create a dictionary for this font + CFDictionaryRef attributes = (__bridge CFDictionaryRef)@{ + (NSString *)kCTFontAttributeName: (__bridge id)font, + (NSString *)kCTForegroundColorFromContextAttributeName: @YES + }; + + // Set up text frame with font metrics + CGFloat size = CTFontGetSize(font); + frame.count = lineCount; + frame.baseLine = size; // estimate base line + frame.lineHeight = size * 1.1; // Base on ART canvas line height estimate + frame.lines = malloc(sizeof(CTLineRef) * lineCount); + frame.widths = malloc(sizeof(CGFloat) * lineCount); + + [lines enumerateObjectsUsingBlock:^(NSString *text, NSUInteger i, BOOL *stop) { + + CFStringRef string = (__bridge CFStringRef)text; + CFAttributedStringRef attrString = CFAttributedStringCreate(kCFAllocatorDefault, string, attributes); + CTLineRef line = CTLineCreateWithAttributedString(attrString); + CFRelease(attrString); + + frame.lines[i] = line; + frame.widths[i] = CTLineGetTypographicBounds(line, NULL, NULL, NULL); + }]; + + return frame; +} + ++ (ARTCGFloatArray)ARTCGFloatArray:(id)json +{ + NSArray *arr = [self NSNumberArray:json]; + NSUInteger count = arr.count; + + ARTCGFloatArray array; + array.count = count; + array.array = NULL; + + if (count) { + // Ideally, these arrays should already use the same memory layout. + // In that case we shouldn't need this new malloc. + array.array = malloc(sizeof(CGFloat) * count); + for (NSUInteger i = 0; i < count; i++) { + array.array[i] = [arr[i] doubleValue]; + } + } + + return array; +} + ++ (ARTBrush *)ARTBrush:(id)json +{ + NSArray *arr = [self NSArray:json]; + NSUInteger type = [self NSUInteger:arr[0]]; + switch (type) { + case 0: // solid color + // These are probably expensive allocations since it's often the same value. + // We should memoize colors but look ups may be just as expensive. + return [[ARTSolidColor alloc] initWithArray:arr]; + case 1: // linear gradient + return [[ARTLinearGradient alloc] initWithArray:arr]; + case 2: // radial gradient + return [[ARTRadialGradient alloc] initWithArray:arr]; + case 3: // pattern + return [[ARTPattern alloc] initWithArray:arr]; + default: + RCTLogError(@"Unknown brush type: %zd", type); + return nil; + } +} + ++ (CGPoint)CGPoint:(id)json offset:(NSUInteger)offset +{ + NSArray *arr = [self NSArray:json]; + if (arr.count < offset + 2) { + RCTLogError(@"Too few elements in array (expected at least %zd): %@", 2 + offset, arr); + return CGPointZero; + } + return (CGPoint){ + [self CGFloat:arr[offset]], + [self CGFloat:arr[offset + 1]], + }; +} + ++ (CGRect)CGRect:(id)json offset:(NSUInteger)offset +{ + NSArray *arr = [self NSArray:json]; + if (arr.count < offset + 4) { + RCTLogError(@"Too few elements in array (expected at least %zd): %@", 4 + offset, arr); + return CGRectZero; + } + return (CGRect){ + {[self CGFloat:arr[offset]], [self CGFloat:arr[offset + 1]]}, + {[self CGFloat:arr[offset + 2]], [self CGFloat:arr[offset + 3]]}, + }; +} + ++ (CGColorRef)CGColor:(id)json offset:(NSUInteger)offset +{ + NSArray *arr = [self NSArray:json]; + if (arr.count < offset + 4) { + RCTLogError(@"Too few elements in array (expected at least %zd): %@", 4 + offset, arr); + return NULL; + } + return [self CGColor:[arr subarrayWithRange:(NSRange){offset, 4}]]; +} + ++ (CGGradientRef)CGGradient:(id)json offset:(NSUInteger)offset +{ + NSArray *arr = [self NSArray:json]; + if (arr.count < offset) { + RCTLogError(@"Too few elements in array (expected at least %zd): %@", offset, arr); + return NULL; + } + arr = [arr subarrayWithRange:(NSRange){offset, arr.count - offset}]; + ARTCGFloatArray colorsAndOffsets = [self ARTCGFloatArray:arr]; + size_t stops = colorsAndOffsets.count / 5; + CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); + CGGradientRef gradient = CGGradientCreateWithColorComponents( + rgb, + colorsAndOffsets.array, + colorsAndOffsets.array + stops * 4, + stops + ); + CGColorSpaceRelease(rgb); + free(colorsAndOffsets.array); + return (CGGradientRef)CFAutorelease(gradient); +} + +@end diff --git a/Libraries/ART/ReactIOSART.js b/Libraries/ART/ReactIOSART.js new file mode 100644 index 00000000000..9ef2f8843bf --- /dev/null +++ b/Libraries/ART/ReactIOSART.js @@ -0,0 +1,611 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactIOSART + */ + +"use strict"; + +var Color = require('art/core/color'); +var Path = require('ARTSerializablePath'); +var Transform = require('art/core/transform'); + +var React = require('React'); +var ReactIOSViewAttributes = require('ReactIOSViewAttributes'); + +var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass'); +var merge = require('merge'); + +// Diff Helpers + +function arrayDiffer(a, b) { + if (a == null) { + return true; + } + if (a.length !== b.length) { + return true; + } + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) { + return true; + } + } + return false; +} + +function fontAndLinesDiffer(a, b) { + if (a === b) { + return false; + } + if (a.font !== b.font) { + if (a.font === null) { + return true; + } + if (b.font === null) { + return true; + } + + var aTraits = a.font.NSCTFontTraitsAttribute; + var bTraits = b.font.NSCTFontTraitsAttribute; + + if ( + a.font.fontFamily !== b.font.fontFamily || + a.font.fontSize !== b.font.fontSize || + a.font.fontWeight !== b.font.fontWeight || + a.font.fontStyle !== b.font.fontStyle || + // TODO(6364240): remove iOS-specific attrs + a.font.NSFontFamilyAttribute !== b.font.NSFontFamilyAttribute || + a.font.NSFontSizeAttribute !== b.font.NSFontSizeAttribute || + aTraits.NSCTFontSymbolicTrait !== bTraits.NSCTFontSymbolicTrait + ) { + return true; + } + } + return arrayDiffer(a.lines, b.lines); +} + +// Native Attributes + +var SurfaceViewAttributes = merge(ReactIOSViewAttributes.UIView, { + // This should contain pixel information such as width, height and + // resolution to know what kind of buffer needs to be allocated. + // Currently we rely on UIViews and style to figure that out. +}); + +var NodeAttributes = { + transform: { diff: arrayDiffer }, + opacity: true, +}; + +var GroupAttributes = merge(NodeAttributes, { + clipping: { diff: arrayDiffer } +}); + +var RenderableAttributes = merge(NodeAttributes, { + fill: { diff: arrayDiffer }, + stroke: { diff: arrayDiffer }, + strokeWidth: true, + strokeCap: true, + strokeJoin: true, + strokeDash: { diff: arrayDiffer }, +}); + +var ShapeAttributes = merge(RenderableAttributes, { + d: { diff: arrayDiffer }, +}); + +var TextAttributes = merge(RenderableAttributes, { + alignment: true, + frame: { diff: fontAndLinesDiffer }, + path: { diff: arrayDiffer } +}); + +// Native Components + +var NativeSurfaceView = createReactIOSNativeComponentClass({ + validAttributes: SurfaceViewAttributes, + uiViewClassName: 'ARTSurfaceView', +}); + +var NativeGroup = createReactIOSNativeComponentClass({ + validAttributes: GroupAttributes, + uiViewClassName: 'ARTGroup', +}); + +var NativeShape = createReactIOSNativeComponentClass({ + validAttributes: ShapeAttributes, + uiViewClassName: 'ARTShape', +}); + +var NativeText = createReactIOSNativeComponentClass({ + validAttributes: TextAttributes, + uiViewClassName: 'ARTText', +}); + +// Utilities + +function childrenAsString(children) { + if (!children) { + return ''; + } + if (typeof children === 'string') { + return children; + } + if (children.length) { + return children.join('\n'); + } + return ''; +} + +// Surface - Root node of all ART + +var Surface = React.createClass({ + + render: function() { + var props = this.props; + var w = extractNumber(props.width, 0); + var h = extractNumber(props.height, 0); + return ( + + {this.props.children} + + ); + } + +}); + +// Node Props + +// TODO: The desktop version of ART has title and cursor. We should have +// accessibility support here too even though hovering doesn't work. + +function extractNumber(value, defaultValue) { + if (value == null) { + return defaultValue; + } + return +value; +} + +var pooledTransform = new Transform(); + +function extractTransform(props) { + var scaleX = props.scaleX != null ? props.scaleX : + props.scale != null ? props.scale : 1; + var scaleY = props.scaleY != null ? props.scaleY : + props.scale != null ? props.scale : 1; + + pooledTransform + .transformTo(1, 0, 0, 1, 0, 0) + .move(props.x || 0, props.y || 0) + .rotate(props.rotation || 0, props.originX, props.originY) + .scale(scaleX, scaleY, props.originX, props.originY); + + if (props.transform != null) { + pooledTransform.transform(props.transform); + } + + return [ + pooledTransform.xx, pooledTransform.yx, + pooledTransform.xy, pooledTransform.yy, + pooledTransform.x, pooledTransform.y, + ]; +} + +function extractOpacity(props) { + // TODO: visible === false should also have no hit detection + if (props.visible === false) { + return 0; + } + if (props.opacity == null) { + return 1; + } + return +props.opacity; +} + +// Groups + +// Note: ART has a notion of width and height on Group but AFAIK it's a noop in +// ReactART. + +var Group = React.createClass({ + + render: function() { + var props = this.props; + return ( + + {this.props.children} + + ); + } + +}); + +var ClippingRectangle = React.createClass({ + + render: function() { + var props = this.props; + var x = extractNumber(props.x, 0); + var y = extractNumber(props.y, 0); + var w = extractNumber(props.width, 0); + var h = extractNumber(props.height, 0); + var clipping = new Path() + .moveTo(x, y) + .line(w, 0) + .line(0, h) + .line(w, 0) + .close() + .toJSON(); + // The current clipping API requires x and y to be ignored in the transform + var propsExcludingXAndY = merge(props); + delete propsExcludingXAndY.x; + delete propsExcludingXAndY.y; + return ( + + {this.props.children} + + ); + } + +}); + +// Renderables + +var SOLID_COLOR = 0; +var LINEAR_GRADIENT = 1; +var RADIAL_GRADIENT = 2; +var PATTERN = 3; + +function insertColorIntoArray(color, targetArray, atIndex) { + var c = new Color(color); + targetArray[atIndex + 0] = c.red / 255; + targetArray[atIndex + 1] = c.green / 255; + targetArray[atIndex + 2] = c.blue / 255; + targetArray[atIndex + 3] = c.alpha; +} + +function insertColorsIntoArray(stops, targetArray, atIndex) { + var i = 0; + if ('length' in stops) { + while (i < stops.length) { + insertColorIntoArray(stops[i], targetArray, atIndex + i * 4); + i++; + } + } else { + for (var offset in stops) { + insertColorIntoArray(stops[offset], targetArray, atIndex + i * 4); + i++; + } + } + return atIndex + i * 4; +} + +function insertOffsetsIntoArray(stops, targetArray, atIndex, multi, reverse) { + var offsetNumber; + var i = 0; + if ('length' in stops) { + while (i < stops.length) { + offsetNumber = i / (stops.length - 1) * multi; + targetArray[atIndex + i] = reverse ? 1 - offsetNumber : offsetNumber; + i++; + } + } else { + for (var offsetString in stops) { + offsetNumber = (+offsetString) * multi; + targetArray[atIndex + i] = reverse ? 1 - offsetNumber : offsetNumber; + i++; + } + } + return atIndex + i; +} + +function insertColorStopsIntoArray(stops, targetArray, atIndex) { + var lastIndex = insertColorsIntoArray(stops, targetArray, atIndex); + insertOffsetsIntoArray(stops, targetArray, lastIndex, 1, false); +} + +function insertDoubleColorStopsIntoArray(stops, targetArray, atIndex) { + var lastIndex = insertColorsIntoArray(stops, targetArray, atIndex); + lastIndex = insertColorsIntoArray(stops, targetArray, lastIndex); + lastIndex = insertOffsetsIntoArray(stops, targetArray, lastIndex, 0.5, false); + insertOffsetsIntoArray(stops, targetArray, lastIndex, 0.5, true); +} + +function applyBoundingBoxToBrushData(brushData, props) { + var type = brushData[0]; + var width = +props.width; + var height = +props.height; + if (type === LINEAR_GRADIENT) { + brushData[1] *= width; + brushData[2] *= height; + brushData[3] *= width; + brushData[4] *= height; + } else if (type === RADIAL_GRADIENT) { + brushData[1] *= width; + brushData[2] *= height; + brushData[3] *= width; + brushData[4] *= height; + brushData[5] *= width; + brushData[6] *= height; + } else if (type === PATTERN) { + // todo + } +} + +function extractBrush(colorOrBrush, props) { + if (colorOrBrush == null) { + return null; + } + if (colorOrBrush._brush) { + if (colorOrBrush._bb) { + // The legacy API for Gradients allow for the bounding box to be used + // as a convenience for specifying gradient positions. This should be + // deprecated. It's not properly implemented in canvas mode. ReactART + // doesn't handle update to the bounding box correctly. That's why we + // mutate this so that if it's reused, we reuse the same resolved box. + applyBoundingBoxToBrushData(colorOrBrush._brush, props); + colorOrBrush._bb = false; + } + return colorOrBrush._brush; + } + var c = new Color(colorOrBrush); + return [SOLID_COLOR, c.red / 255, c.green / 255, c.blue / 255, c.alpha]; +} + +function extractColor(color) { + if (color == null) { + return null; + } + var c = new Color(color); + return [c.red / 255, c.green / 255, c.blue / 255, c.alpha]; +} + +function extractStrokeCap(strokeCap) { + switch (strokeCap) { + case 'butt': return 0; + case 'square': return 2; + default: return 1; // round + } +} + +function extractStrokeJoin(strokeJoin) { + switch (strokeJoin) { + case 'miter': return 0; + case 'bevel': return 2; + default: return 1; // round + } +} + +// Shape + +// Note: ART has a notion of width and height on Shape but AFAIK it's a noop in +// ReactART. + +var Shape = React.createClass({ + + render: function() { + var props = this.props; + var path = props.d || childrenAsString(props.children); + var d = new Path(path).toJSON(); + return ( + + ); + } + +}); + +// Text + +var cachedFontObjectsFromString = {}; + +function extractFontTraits(isBold, isItalic) { + var italic = isItalic ? 1 : 0; + var bold = isBold ? 2 : 0; + return { + NSCTFontSymbolicTrait: italic | bold + }; +} + +var fontFamilyPrefix = /^[\s"']*/; +var fontFamilySuffix = /[\s"']*$/; + +function extractSingleFontFamily(fontFamilyString) { + // ART on the web allows for multiple font-families to be specified. + // For compatibility, we extract the first font-family, hoping + // we'll get a match. + return fontFamilyString.split(',')[0] + .replace(fontFamilyPrefix, '') + .replace(fontFamilySuffix, ''); +} + +function parseFontString(font) { + if (cachedFontObjectsFromString.hasOwnProperty(font)) { + return cachedFontObjectsFromString[font]; + } + var regexp = /^\s*((?:(?:normal|bold|italic)\s+)*)(?:(\d+(?:\.\d+)?)[ptexm\%]*(?:\s*\/.*?)?\s+)?\s*\"?([^\"]*)/i; + var match = regexp.exec(font); + if (!match) { + return null; + } + var fontFamily = extractSingleFontFamily(match[3]); + var fontSize = +match[2] || 12; + var isBold = /bold/.exec(match[1]); + var isItalic = /italic/.exec(match[1]); + cachedFontObjectsFromString[font] = { + fontFamily: fontFamily, + fontSize: fontSize, + fontWeight: isBold ? 'bold' : 'normal', + fontStyle: isItalic ? 'italic' : 'normal', + // TODO(6364240): remove iOS-specific attrs + NSFontFamilyAttribute: fontFamily, + NSFontSizeAttribute: fontSize, + NSCTFontTraitsAttribute: extractFontTraits(isBold, isItalic) + }; + return cachedFontObjectsFromString[font]; +} + +function extractFont(font) { + if (font == null) { + return null; + } + if (typeof font === 'string') { + return parseFontString(font); + } + var fontFamily = extractSingleFontFamily(font.fontFamily); + var fontSize = +font.fontSize || 12; + return { + // Normalize + fontFamily: fontFamily, + fontSize: fontSize, + fontWeight: font.fontWeight, + fontStyle: font.fontStyle, + // TODO(6364240): remove iOS-specific attrs + NSFontFamilyAttribute: fontFamily, + NSFontSizeAttribute: fontSize, + NSCTFontTraitsAttribute: extractFontTraits( + font.fontWeight === 'bold', + font.fontStyle === 'italic' + ) + }; +} + +var newLine = /\n/g; +function extractFontAndLines(font, text) { + return { font: extractFont(font), lines: text.split(newLine) }; +} + +function extractAlignment(alignment) { + switch (alignment) { + case 'right': + return 1; + case 'center': + return 2; + default: + return 0; + } +} + +var Text = React.createClass({ + + render: function() { + var props = this.props; + var textPath = props.path ? new Path(props.path).toJSON() : null; + var textFrame = extractFontAndLines( + props.font, + childrenAsString(props.children) + ); + return ( + + ); + } + +}); + +// Declarative fill type objects - API design not finalized + +function LinearGradient(stops, x1, y1, x2, y2) { + var type = LINEAR_GRADIENT; + + if (arguments.length < 5) { + var angle = ((x1 == null) ? 270 : x1) * Math.PI / 180; + + var x = Math.cos(angle); + var y = -Math.sin(angle); + var l = (Math.abs(x) + Math.abs(y)) / 2; + + x *= l; y *= l; + + x1 = 0.5 - x; + x2 = 0.5 + x; + y1 = 0.5 - y; + y2 = 0.5 + y; + this._bb = true; + } else { + this._bb = false; + } + + var brushData = [type, +x1, +y1, +x2, +y2]; + insertColorStopsIntoArray(stops, brushData, 5); + this._brush = brushData; +} + +function RadialGradient(stops, fx, fy, rx, ry, cx, cy) { + if (ry == null) { + ry = rx; + } + if (cx == null) { + cx = fx; + } + if (cy == null) { + cy = fy; + } + if (fx == null) { + // As a convenience we allow the whole radial gradient to cover the + // bounding box. We should consider dropping this API. + fx = fy = rx = ry = cx = cy = 0.5; + this._bb = true; + } else { + this._bb = false; + } + // The ART API expects the radial gradient to be repeated at the edges. + // To simulate this we render the gradient twice as large and add double + // color stops. Ideally this API would become more restrictive so that this + // extra work isn't needed. + var brushData = [RADIAL_GRADIENT, +fx, +fy, +rx * 2, +ry * 2, +cx, +cy]; + insertDoubleColorStopsIntoArray(stops, brushData, 7); + this._brush = brushData; +} + +function Pattern(url, width, height, left, top) { + this._brush = [PATTERN, url, +left || 0, +top || 0, +width, +height]; +} + +var ReactART = { + + LinearGradient: LinearGradient, + RadialGradient: RadialGradient, + Pattern: Pattern, + Transform: Transform, + Path: Path, + Surface: Surface, + Group: Group, + ClippingRectangle: ClippingRectangle, + Shape: Shape, + Text: Text, + +}; + +module.exports = ReactART; diff --git a/Libraries/ART/ViewManagers/ARTGroupManager.h b/Libraries/ART/ViewManagers/ARTGroupManager.h new file mode 100644 index 00000000000..0a90eb3d6c1 --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTGroupManager.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTNodeManager.h" + +@interface ARTGroupManager : ARTNodeManager + +@end diff --git a/Libraries/ART/ViewManagers/ARTGroupManager.m b/Libraries/ART/ViewManagers/ARTGroupManager.m new file mode 100644 index 00000000000..15f55d4df12 --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTGroupManager.m @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTGroupManager.h" + +#import "ARTGroup.h" + +@implementation ARTGroupManager + +RCT_EXPORT_MODULE() + +- (ARTNode *)node +{ + return [[ARTGroup alloc] init]; +} + +@end diff --git a/Libraries/ART/ViewManagers/ARTNodeManager.h b/Libraries/ART/ViewManagers/ARTNodeManager.h new file mode 100644 index 00000000000..1097eefde91 --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTNodeManager.h @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTNode.h" +#import "RCTViewManager.h" + +@interface ARTNodeManager : RCTViewManager + +- (ARTNode *)node; + +@end diff --git a/Libraries/ART/ViewManagers/ARTNodeManager.m b/Libraries/ART/ViewManagers/ARTNodeManager.m new file mode 100644 index 00000000000..c2f0dba35ad --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTNodeManager.m @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTNodeManager.h" + +#import "ARTNode.h" + +@implementation ARTNodeManager + +RCT_EXPORT_MODULE() + +- (ARTNode *)node +{ + return [[ARTNode alloc] init]; +} + +- (UIView *)view +{ + return [self node]; +} + +- (RCTShadowView *)shadowView +{ + return nil; +} + +RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat) +RCT_EXPORT_VIEW_PROPERTY(transform, CGAffineTransform) + +@end diff --git a/Libraries/ART/ViewManagers/ARTRenderableManager.h b/Libraries/ART/ViewManagers/ARTRenderableManager.h new file mode 100644 index 00000000000..376fcf518b3 --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTRenderableManager.h @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTNodeManager.h" +#import "ARTRenderable.h" + +@interface ARTRenderableManager : ARTNodeManager + +- (ARTRenderable *)node; + +@end diff --git a/Libraries/ART/ViewManagers/ARTRenderableManager.m b/Libraries/ART/ViewManagers/ARTRenderableManager.m new file mode 100644 index 00000000000..01b579dca4c --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTRenderableManager.m @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTRenderableManager.h" + +#import "RCTConvert+ART.h" + +@implementation ARTRenderableManager + +RCT_EXPORT_MODULE() + +- (ARTRenderable *)node +{ + return [[ARTRenderable alloc] init]; +} + +RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat) +RCT_EXPORT_VIEW_PROPERTY(strokeCap, CGLineCap) +RCT_EXPORT_VIEW_PROPERTY(strokeJoin, CGLineJoin) +RCT_EXPORT_VIEW_PROPERTY(fill, ARTBrush) +RCT_EXPORT_VIEW_PROPERTY(stroke, CGColor) +RCT_EXPORT_VIEW_PROPERTY(strokeDash, ARTCGFloatArray) + +@end diff --git a/Libraries/ART/ViewManagers/ARTShapeManager.h b/Libraries/ART/ViewManagers/ARTShapeManager.h new file mode 100644 index 00000000000..d6bc76baa09 --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTShapeManager.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTRenderableManager.h" + +@interface ARTShapeManager : ARTRenderableManager + +@end diff --git a/Libraries/ART/ViewManagers/ARTShapeManager.m b/Libraries/ART/ViewManagers/ARTShapeManager.m new file mode 100644 index 00000000000..426237fa75c --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTShapeManager.m @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTShapeManager.h" + +#import "ARTShape.h" +#import "RCTConvert+ART.h" + +@implementation ARTShapeManager + +RCT_EXPORT_MODULE() + +- (ARTRenderable *)node +{ + return [[ARTShape alloc] init]; +} + +RCT_EXPORT_VIEW_PROPERTY(d, CGPath) + +@end diff --git a/Libraries/ART/ViewManagers/ARTSurfaceViewManager.h b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.h new file mode 100644 index 00000000000..6d8e140049e --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTViewManager.h" + +@interface ARTSurfaceViewManager : RCTViewManager + +@end diff --git a/Libraries/ART/ViewManagers/ARTSurfaceViewManager.m b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.m new file mode 100644 index 00000000000..ddfba6697be --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.m @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTSurfaceViewManager.h" + +#import "ARTSurfaceView.h" + +@implementation ARTSurfaceViewManager + +RCT_EXPORT_MODULE() + +- (UIView *)view +{ + return [[ARTSurfaceView alloc] init]; +} + +@end diff --git a/Libraries/ART/ViewManagers/ARTTextManager.h b/Libraries/ART/ViewManagers/ARTTextManager.h new file mode 100644 index 00000000000..48da9c891f4 --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTTextManager.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTRenderableManager.h" + +@interface ARTTextManager : ARTRenderableManager + +@end diff --git a/Libraries/ART/ViewManagers/ARTTextManager.m b/Libraries/ART/ViewManagers/ARTTextManager.m new file mode 100644 index 00000000000..473d0cf4fa4 --- /dev/null +++ b/Libraries/ART/ViewManagers/ARTTextManager.m @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ARTTextManager.h" + +#import "ARTText.h" +#import "RCTConvert+ART.h" + +@implementation ARTTextManager + +RCT_EXPORT_MODULE() + +- (ARTRenderable *)node +{ + return [[ARTText alloc] init]; +} + +RCT_EXPORT_VIEW_PROPERTY(alignment, CTTextAlignment) +RCT_REMAP_VIEW_PROPERTY(frame, textFrame, ARTTextFrame) + +@end