diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..239ffece --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: CI + +on: [push, pull_request] + +jobs: + website: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 8.x + - name: Install dependencies + run: yarn install --frozen-lockfile --ignore-scripts + working-directory: website + - name: Build + run: yarn build + working-directory: website + - name: Deploy + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: website/public + cname: yogalayout.com + keep_files: true + user_name: 'Yoga-bot' + user_email: 'yogabot@fb.com' + android: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Install NDK 21 + run: echo "y" | sudo /usr/local/lib/android/sdk/tools/bin/sdkmanager --install "ndk;21.0.6113669" "ndk;20.0.5594570" --sdk_root=${ANDROID_SDK_ROOT} + - name: Install dependencies + run: | + if [[ -n "${{ secrets.encrypted_d27e803291ff_iv }}" ]]; then + openssl aes-256-cbc -K ${{ secrets.encrypted_d27e803291ff_key }} -iv {{ secrets.encrypted_d27e803291ff_iv }} -in scripts/setup-keys.enc -d >> gradle.properties; + fi + sudo apt-get update + sudo apt-get install -y ninja-build + pushd $HOME + git clone --depth 1 https://github.com/facebook/buck.git + cd buck + ant + popd + echo "$HOME/buck/bin" >> $GITHUB_PATH + export PATH=$PATH:$HOME/buck/bin/ + buck --version + - name: Build + # TODO: Run the tests here again. They're currently crashing the JVM in GitHub Actions for some reason. + run: ./gradlew :yoga-layout:assembleDebug diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..1231fb66 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,32 @@ +name: Publish + +on: + release: + types: + - created + workflow_dispatch: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Install dependencies + run: source scripts/android-setup.sh && installAndroidSDK + - name: Write GPG Sec Ring + run: echo '${{ secrets.GPG_KEY_CONTENTS }}' | base64 -d > /tmp/secring.gpg + - name: Update gradle.properties + run: echo -e "signing.secretKeyRingFile=/tmp/secring.gpg\nsigning.keyId=${{ secrets.SIGNING_KEY_ID }}\nsigning.password=${{ secrets.SIGNING_PASSWORD }}\nmavenCentralPassword=${{ secrets.SONATYPE_NEXUS_PASSWORD }}\nmavenCentralUsername=${{ secrets.SONATYPE_NEXUS_USERNAME }}" >> gradle.properties + - name: Upload Android Archives + run: ./gradlew :yoga:assembleRelease publish --info + - name: Release and close + run: ./gradlew closeAndReleaseRepository + - name: Clean secrets + if: always() + run: rm /tmp/secring.gpg diff --git a/.gitignore b/.gitignore index c4a6bf0f..44f230ed 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ /.buckd /gentest/test.html .buckversion +.cxx +.idea +/local.properties # Jekyll /.sass-cache/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3ae55d1f..00000000 --- a/.travis.yml +++ /dev/null @@ -1,77 +0,0 @@ -language: java -os: linux -dist: trusty -addons: - apt: - sources: - - llvm-toolchain-trusty-6.0 - - ubuntu-toolchain-r-test - packages: - - clang-6.0 - -env: - - TARGET: website - - TARGET: android - -install: -- cd website -- yarn --ignore-scripts -- cd .. - -cache: - directories: - - $HOME/buck - - $HOME/.gradle - -before_install: - - | - if [[ -n "$encrypted_d27e803291ff_iv" ]]; then - openssl aes-256-cbc -K $encrypted_d27e803291ff_key -iv $encrypted_d27e803291ff_iv -in scripts/setup-keys.enc -d >> gradle.properties; - fi - # Android - - | - if [[ $TARGET = "android" ]]; then - pushd $HOME - git clone --depth 1 https://github.com/facebook/buck.git - cd buck - ant - popd - export PATH=$PATH:$HOME/buck/bin/ - buck --version - export TERMINAL=dumb - source scripts/android-setup.sh && installAndroidSDK - export ANDROID_SDK=$ANDROID_HOME - export ANDROID_NDK_REPOSITORY=$HOME/android-ndk - export ANDROID_NDK_HOME=$ANDROID_NDK_REPOSITORY/android-ndk-r15c - fi - # Website - - | - if [[ $TARGET = "website" ]]; then - nvm install 8 - nvm use 8 - fi - -script: - - | - if [[ $TARGET = "android" ]]; then - ./gradlew testDebugUnit && scripts/publish-snapshot.sh - fi - - | - if [[ $TARGET = "website" ]]; then - pushd website - yarn build - popd - fi - -deploy: - provider: pages - skip-cleanup: true - github-token: $GITHUB_TOKEN - fqdn: yogalayout.com - local-dir: website/public - email: yogabot@fb.com - name: Yoga-bot - keep-history: true - on: - branch: master - condition: $TARGET = website diff --git a/BUCK b/BUCK index fa0e5580..eb96206f 100644 --- a/BUCK +++ b/BUCK @@ -40,6 +40,20 @@ yoga_cxx_library( ], ) +yoga_cxx_library( + name = "yoga-static", + srcs = glob(["yoga/**/*.cpp"]), + compiler_flags = LIBRARY_COMPILER_FLAGS, + preferred_linkage = "static", + public_include_directories = ["."], + raw_headers = glob(["yoga/**/*.h"]), + tests = [":YogaTests"], + visibility = ["PUBLIC"], + deps = [ + ":ndklog", + ], +) + yoga_cxx_library( name = "yogaForDebug", srcs = glob(["yoga/**/*.cpp"]), diff --git a/README.md b/README.md index 689851d6..527879ff 100644 --- a/README.md +++ b/README.md @@ -46,3 +46,29 @@ This will now only run the standalone webpack build upon install. | node | Builds node js version. | | standalone | Runs webpack. | | none | Does nothing. You can use the prepackaged libs. | + +## Maintainer Release Guide + +To publish a new release, follow these steps: + +1. Ensure you have your GPG key set up and your [OSS Sonatype](https://oss.sonatype.org/) credentials handy. +2. Add the follow entries to either your local `gradle.properties` (don't forget to revert) or your global `~/.gradle/gradle.properties`: + +``` +# You get these from https://oss.sonatype.org/#profile;User%20Token +mavenCentralRepositoryUsername= +mavenCentralRepositoryPassword= + +# You can get the keyId (in GPG 1.4 format) by running `gpg1 --list-keys`. +signing.secretKeyRingFile= +signing.keyId= +signing.password= +``` + +3. Change the `VERSION_NAME` in `gradle.properties` to a non-SNAPSHOT release. +4. Commit and land the version change. +5. Run `./gradlew publishToMaven`. +6. Run `./gradlew closeAndReleaseRepository`. +7. Change the `VERSION_NAME` in `gradle.properties` back to a new SNAPSHOT release. +8. Commit and land the version change. +9. Celebrate! You've made a release! diff --git a/ReactYoga.xcodeproj/project.pbxproj b/ReactYoga.xcodeproj/project.pbxproj index 715c686a..090c6e09 100644 --- a/ReactYoga.xcodeproj/project.pbxproj +++ b/ReactYoga.xcodeproj/project.pbxproj @@ -191,7 +191,6 @@ 27595AD71E575C7800CCE2B1 /* SampleCxxModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D41E03699D0018521A /* SampleCxxModule.h */; }; 27595AD81E575C7800CCE2B1 /* SystraceSection.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0D51E03699D0018521A /* SystraceSection.h */; }; 2D0EB9F32021067800CAF88A /* RCTUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = F1EFDA4E201F660F00EE6E4C /* RCTUIUtils.m */; }; - 2D16E68E1FA4FD3900B85C8A /* RCTTVNavigationEventEmitter.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D0B842D1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h */; }; 2D1D83CE1F74E2DA00615550 /* libdouble-conversion.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D383D621EBD27B9005632C8 /* libdouble-conversion.a */; }; 2D3B5E931D9B087300451313 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; }; 2D3B5E941D9B087900451313 /* RCTBundleURLProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 68EFE4ED1CF6EB3900A1DE13 /* RCTBundleURLProvider.m */; }; @@ -269,8 +268,6 @@ 3D0B842A1EC0B49400B2BD8E /* RCTTVRemoteHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0B84281EC0B49400B2BD8E /* RCTTVRemoteHandler.h */; }; 3D0B842B1EC0B49400B2BD8E /* RCTTVRemoteHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D0B84291EC0B49400B2BD8E /* RCTTVRemoteHandler.m */; }; 3D0B842C1EC0B4EA00B2BD8E /* RCTTVView.m in Sources */ = {isa = PBXBuildFile; fileRef = 130443D71E401AD800D93A67 /* RCTTVView.m */; }; - 3D0B842F1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0B842D1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h */; }; - 3D0B84301EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D0B842E1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m */; }; 3D0E378A1F1CC40000DCAC9F /* RCTWebSocketModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */; }; 3D0E378E1F1CC59100DCAC9F /* RCTWebSocketModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */; }; 3D0E378F1F1CC5CF00DCAC9F /* RCTWebSocketModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */; }; @@ -1275,7 +1272,6 @@ 594F0A471FD233BD007FBE96 /* RCTSurfaceView.h in Copy Headers */, 594F0A481FD233BD007FBE96 /* RCTSurfaceHostingView.h in Copy Headers */, 594F0A491FD233BD007FBE96 /* RCTSurfaceSizeMeasureMode.h in Copy Headers */, - 2D16E68E1FA4FD3900B85C8A /* RCTTVNavigationEventEmitter.h in Copy Headers */, 59500D481F71C67600B122B7 /* RCTUIManagerUtils.h in Copy Headers */, 3D0E37901F1CC5E100DCAC9F /* RCTWebSocketModule.h in Copy Headers */, 5960C1BF1F0804F50066FD5B /* RCTLayoutAnimation.h in Copy Headers */, @@ -1876,8 +1872,6 @@ 39C50FFA2046EE3500CEE534 /* RCTVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVersion.m; sourceTree = ""; }; 3D0B84281EC0B49400B2BD8E /* RCTTVRemoteHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTVRemoteHandler.h; sourceTree = ""; }; 3D0B84291EC0B49400B2BD8E /* RCTTVRemoteHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTVRemoteHandler.m; sourceTree = ""; }; - 3D0B842D1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTVNavigationEventEmitter.h; sourceTree = ""; }; - 3D0B842E1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTVNavigationEventEmitter.m; sourceTree = ""; }; 3D0E37891F1CC40000DCAC9F /* RCTWebSocketModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTWebSocketModule.h; path = WebSocket/RCTWebSocketModule.h; sourceTree = ""; }; 3D1E68D81CABD13900DD7465 /* RCTDisplayLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDisplayLink.h; sourceTree = ""; }; 3D1E68D91CABD13900DD7465 /* RCTDisplayLink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDisplayLink.m; sourceTree = ""; }; @@ -2346,8 +2340,6 @@ 0EEEA8DE2239002200A8C82D /* RCTSurfacePresenterStub.m */, 13B07FED1A69327A00A75B9A /* RCTTiming.h */, 13B07FEE1A69327A00A75B9A /* RCTTiming.m */, - 3D0B842D1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h */, - 3D0B842E1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m */, 13E067481A70F434002CDEE1 /* RCTUIManager.h */, 13E067491A70F434002CDEE1 /* RCTUIManager.m */, 59EB6DB91EBD6FC90072A5E7 /* RCTUIManagerObserverCoordinator.h */, @@ -2945,7 +2937,6 @@ 3D302F311DF828F800D6DDAE /* RCTBundleURLProvider.h in Headers */, 3D302F321DF828F800D6DDAE /* RCTConvert.h in Headers */, 3D302F331DF828F800D6DDAE /* RCTDefines.h in Headers */, - 3D0B842F1EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.h in Headers */, 3D302F341DF828F800D6DDAE /* RCTDisplayLink.h in Headers */, 3D302F351DF828F800D6DDAE /* RCTErrorCustomizer.h in Headers */, 3D302F361DF828F800D6DDAE /* RCTErrorInfo.h in Headers */, @@ -3994,7 +3985,6 @@ 2D3B5EC81D9B095800451313 /* RCTActivityIndicatorViewManager.m in Sources */, 3DCD185D1DF978E7007FE5A1 /* RCTReloadCommand.m in Sources */, 130443DB1E401ADD00D93A67 /* RCTConvert+Transform.m in Sources */, - 3D0B84301EC0B51200B2BD8E /* RCTTVNavigationEventEmitter.m in Sources */, 2D3B5EC61D9B095000451313 /* RCTProfileTrampoline-x86_64.S in Sources */, 2D3B5EA61D9B08CA00451313 /* RCTTouchEvent.m in Sources */, 2D8C2E331DA40441000EE098 /* RCTMultipartStreamReader.m in Sources */, diff --git a/Yoga.podspec b/Yoga.podspec index 24e1c0b8..2b09977d 100644 --- a/Yoga.podspec +++ b/Yoga.podspec @@ -33,6 +33,6 @@ Pod::Spec.new do |spec| '-fPIC' ] spec.source_files = 'yoga/**/*.{c,h,cpp}' - spec.public_header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGValue}.h' + spec.public_header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGNode,YGStyle,YGValue}.h' end diff --git a/YogaKit/BUCK b/YogaKit/BUCK index c3d534e8..acefcdb3 100644 --- a/YogaKit/BUCK +++ b/YogaKit/BUCK @@ -37,11 +37,14 @@ yoga_apple_library( ), compiler_flags = COMPILER_FLAGS, frameworks = [ + "$SDKROOT/System/Library/Frameworks/CoreGraphics.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/UIKit.framework", ], header_path_prefix = "", link_whole = True, + modular = True, + module_name = "YogaKit", visibility = ["PUBLIC"], deps = [ yoga_dep(":yoga"), diff --git a/YogaKit/Source/UIView+Yoga.h b/YogaKit/Source/UIView+Yoga.h index cac23385..4c85dcc4 100644 --- a/YogaKit/Source/UIView+Yoga.h +++ b/YogaKit/Source/UIView+Yoga.h @@ -5,28 +5,29 @@ * LICENSE file in the root directory of this source tree. */ -#import "YGLayout.h" #import +#import "YGLayout.h" NS_ASSUME_NONNULL_BEGIN -typedef void (^YGLayoutConfigurationBlock)(YGLayout *layout); +typedef void (^YGLayoutConfigurationBlock)(YGLayout* layout); @interface UIView (Yoga) /** The YGLayout that is attached to this view. It is lazily created. */ -@property (nonatomic, readonly, strong) YGLayout *yoga; +@property(nonatomic, readonly, strong) YGLayout* yoga; /** Indicates whether or not Yoga is enabled */ -@property (nonatomic, readonly, assign) BOOL isYogaEnabled; +@property(nonatomic, readonly, assign) BOOL isYogaEnabled; /** - In ObjC land, every time you access `view.yoga.*` you are adding another `objc_msgSend` - to your code. If you plan on making multiple changes to YGLayout, it's more performant - to use this method, which uses a single objc_msgSend call. + In ObjC land, every time you access `view.yoga.*` you are adding another + `objc_msgSend` to your code. If you plan on making multiple changes to + YGLayout, it's more performant to use this method, which uses a single + objc_msgSend call. */ - (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block NS_SWIFT_NAME(configureLayout(block:)); diff --git a/YogaKit/Source/UIView+Yoga.m b/YogaKit/Source/UIView+Yoga.m index ba133919..e472c9c7 100644 --- a/YogaKit/Source/UIView+Yoga.m +++ b/YogaKit/Source/UIView+Yoga.m @@ -5,32 +5,30 @@ * LICENSE file in the root directory of this source tree. */ +#import #import "UIView+Yoga.h" #import "YGLayout+Private.h" -#import -static const void *kYGYogaAssociatedKey = &kYGYogaAssociatedKey; +static const void* kYGYogaAssociatedKey = &kYGYogaAssociatedKey; @implementation UIView (YogaKit) -- (YGLayout *)yoga -{ - YGLayout *yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey); +- (YGLayout*)yoga { + YGLayout* yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey); if (!yoga) { yoga = [[YGLayout alloc] initWithView:self]; - objc_setAssociatedObject(self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject( + self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return yoga; } -- (BOOL)isYogaEnabled -{ +- (BOOL)isYogaEnabled { return objc_getAssociatedObject(self, kYGYogaAssociatedKey) != nil; } -- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block -{ +- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block { if (block != nil) { block(self.yoga); } diff --git a/YogaKit/Source/YGLayout+Private.h b/YogaKit/Source/YGLayout+Private.h index 00ab40f5..0588d950 100644 --- a/YogaKit/Source/YGLayout+Private.h +++ b/YogaKit/Source/YGLayout+Private.h @@ -5,13 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -#import "YGLayout.h" #import +#import "YGLayout.h" @interface YGLayout () -@property (nonatomic, assign, readonly) YGNodeRef node; +@property(nonatomic, assign, readonly) YGNodeRef node; -- (instancetype)initWithView:(UIView *)view; +- (instancetype)initWithView:(UIView*)view; @end diff --git a/YogaKit/Source/YGLayout.h b/YogaKit/Source/YGLayout.h index 19f3982b..5a60f95e 100644 --- a/YogaKit/Source/YGLayout.h +++ b/YogaKit/Source/YGLayout.h @@ -7,15 +7,15 @@ #import #import -#import #import +#import YG_EXTERN_C_BEGIN -extern YGValue YGPointValue(CGFloat value) - NS_SWIFT_UNAVAILABLE("Use the swift Int and FloatingPoint extensions instead"); -extern YGValue YGPercentValue(CGFloat value) - NS_SWIFT_UNAVAILABLE("Use the swift Int and FloatingPoint extensions instead"); +extern YGValue YGPointValue(CGFloat value) NS_SWIFT_UNAVAILABLE( + "Use the swift Int and FloatingPoint extensions instead"); +extern YGValue YGPercentValue(CGFloat value) NS_SWIFT_UNAVAILABLE( + "Use the swift Int and FloatingPoint extensions instead"); YG_EXTERN_C_END @@ -44,103 +44,107 @@ typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { The property that decides if we should include this view when calculating layout. Defaults to YES. */ -@property (nonatomic, readwrite, assign, setter=setIncludedInLayout:) BOOL isIncludedInLayout; +@property(nonatomic, readwrite, assign, setter=setIncludedInLayout:) + BOOL isIncludedInLayout; /** - The property that decides during layout/sizing whether or not styling properties should be applied. - Defaults to NO. + The property that decides during layout/sizing whether or not styling + properties should be applied. Defaults to NO. */ -@property (nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled; +@property(nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled; -@property (nonatomic, readwrite, assign) YGDirection direction; -@property (nonatomic, readwrite, assign) YGFlexDirection flexDirection; -@property (nonatomic, readwrite, assign) YGJustify justifyContent; -@property (nonatomic, readwrite, assign) YGAlign alignContent; -@property (nonatomic, readwrite, assign) YGAlign alignItems; -@property (nonatomic, readwrite, assign) YGAlign alignSelf; -@property (nonatomic, readwrite, assign) YGPositionType position; -@property (nonatomic, readwrite, assign) YGWrap flexWrap; -@property (nonatomic, readwrite, assign) YGOverflow overflow; -@property (nonatomic, readwrite, assign) YGDisplay display; +@property(nonatomic, readwrite, assign) YGDirection direction; +@property(nonatomic, readwrite, assign) YGFlexDirection flexDirection; +@property(nonatomic, readwrite, assign) YGJustify justifyContent; +@property(nonatomic, readwrite, assign) YGAlign alignContent; +@property(nonatomic, readwrite, assign) YGAlign alignItems; +@property(nonatomic, readwrite, assign) YGAlign alignSelf; +@property(nonatomic, readwrite, assign) YGPositionType position; +@property(nonatomic, readwrite, assign) YGWrap flexWrap; +@property(nonatomic, readwrite, assign) YGOverflow overflow; +@property(nonatomic, readwrite, assign) YGDisplay display; -@property (nonatomic, readwrite, assign) CGFloat flex; -@property (nonatomic, readwrite, assign) CGFloat flexGrow; -@property (nonatomic, readwrite, assign) CGFloat flexShrink; -@property (nonatomic, readwrite, assign) YGValue flexBasis; +@property(nonatomic, readwrite, assign) CGFloat flex; +@property(nonatomic, readwrite, assign) CGFloat flexGrow; +@property(nonatomic, readwrite, assign) CGFloat flexShrink; +@property(nonatomic, readwrite, assign) YGValue flexBasis; -@property (nonatomic, readwrite, assign) YGValue left; -@property (nonatomic, readwrite, assign) YGValue top; -@property (nonatomic, readwrite, assign) YGValue right; -@property (nonatomic, readwrite, assign) YGValue bottom; -@property (nonatomic, readwrite, assign) YGValue start; -@property (nonatomic, readwrite, assign) YGValue end; +@property(nonatomic, readwrite, assign) YGValue left; +@property(nonatomic, readwrite, assign) YGValue top; +@property(nonatomic, readwrite, assign) YGValue right; +@property(nonatomic, readwrite, assign) YGValue bottom; +@property(nonatomic, readwrite, assign) YGValue start; +@property(nonatomic, readwrite, assign) YGValue end; -@property (nonatomic, readwrite, assign) YGValue marginLeft; -@property (nonatomic, readwrite, assign) YGValue marginTop; -@property (nonatomic, readwrite, assign) YGValue marginRight; -@property (nonatomic, readwrite, assign) YGValue marginBottom; -@property (nonatomic, readwrite, assign) YGValue marginStart; -@property (nonatomic, readwrite, assign) YGValue marginEnd; -@property (nonatomic, readwrite, assign) YGValue marginHorizontal; -@property (nonatomic, readwrite, assign) YGValue marginVertical; -@property (nonatomic, readwrite, assign) YGValue margin; +@property(nonatomic, readwrite, assign) YGValue marginLeft; +@property(nonatomic, readwrite, assign) YGValue marginTop; +@property(nonatomic, readwrite, assign) YGValue marginRight; +@property(nonatomic, readwrite, assign) YGValue marginBottom; +@property(nonatomic, readwrite, assign) YGValue marginStart; +@property(nonatomic, readwrite, assign) YGValue marginEnd; +@property(nonatomic, readwrite, assign) YGValue marginHorizontal; +@property(nonatomic, readwrite, assign) YGValue marginVertical; +@property(nonatomic, readwrite, assign) YGValue margin; -@property (nonatomic, readwrite, assign) YGValue paddingLeft; -@property (nonatomic, readwrite, assign) YGValue paddingTop; -@property (nonatomic, readwrite, assign) YGValue paddingRight; -@property (nonatomic, readwrite, assign) YGValue paddingBottom; -@property (nonatomic, readwrite, assign) YGValue paddingStart; -@property (nonatomic, readwrite, assign) YGValue paddingEnd; -@property (nonatomic, readwrite, assign) YGValue paddingHorizontal; -@property (nonatomic, readwrite, assign) YGValue paddingVertical; -@property (nonatomic, readwrite, assign) YGValue padding; +@property(nonatomic, readwrite, assign) YGValue paddingLeft; +@property(nonatomic, readwrite, assign) YGValue paddingTop; +@property(nonatomic, readwrite, assign) YGValue paddingRight; +@property(nonatomic, readwrite, assign) YGValue paddingBottom; +@property(nonatomic, readwrite, assign) YGValue paddingStart; +@property(nonatomic, readwrite, assign) YGValue paddingEnd; +@property(nonatomic, readwrite, assign) YGValue paddingHorizontal; +@property(nonatomic, readwrite, assign) YGValue paddingVertical; +@property(nonatomic, readwrite, assign) YGValue padding; -@property (nonatomic, readwrite, assign) CGFloat borderLeftWidth; -@property (nonatomic, readwrite, assign) CGFloat borderTopWidth; -@property (nonatomic, readwrite, assign) CGFloat borderRightWidth; -@property (nonatomic, readwrite, assign) CGFloat borderBottomWidth; -@property (nonatomic, readwrite, assign) CGFloat borderStartWidth; -@property (nonatomic, readwrite, assign) CGFloat borderEndWidth; -@property (nonatomic, readwrite, assign) CGFloat borderWidth; +@property(nonatomic, readwrite, assign) CGFloat borderLeftWidth; +@property(nonatomic, readwrite, assign) CGFloat borderTopWidth; +@property(nonatomic, readwrite, assign) CGFloat borderRightWidth; +@property(nonatomic, readwrite, assign) CGFloat borderBottomWidth; +@property(nonatomic, readwrite, assign) CGFloat borderStartWidth; +@property(nonatomic, readwrite, assign) CGFloat borderEndWidth; +@property(nonatomic, readwrite, assign) CGFloat borderWidth; -@property (nonatomic, readwrite, assign) YGValue width; -@property (nonatomic, readwrite, assign) YGValue height; -@property (nonatomic, readwrite, assign) YGValue minWidth; -@property (nonatomic, readwrite, assign) YGValue minHeight; -@property (nonatomic, readwrite, assign) YGValue maxWidth; -@property (nonatomic, readwrite, assign) YGValue maxHeight; +@property(nonatomic, readwrite, assign) YGValue width; +@property(nonatomic, readwrite, assign) YGValue height; +@property(nonatomic, readwrite, assign) YGValue minWidth; +@property(nonatomic, readwrite, assign) YGValue minHeight; +@property(nonatomic, readwrite, assign) YGValue maxWidth; +@property(nonatomic, readwrite, assign) YGValue maxHeight; // Yoga specific properties, not compatible with flexbox specification -@property (nonatomic, readwrite, assign) CGFloat aspectRatio; +@property(nonatomic, readwrite, assign) CGFloat aspectRatio; /** Get the resolved direction of this node. This won't be YGDirectionInherit */ -@property (nonatomic, readonly, assign) YGDirection resolvedDirection; +@property(nonatomic, readonly, assign) YGDirection resolvedDirection; /** - Perform a layout calculation and update the frames of the views in the hierarchy with the results. - If the origin is not preserved, the root view's layout results will applied from {0,0}. + Perform a layout calculation and update the frames of the views in the + hierarchy with the results. If the origin is not preserved, the root view's + layout results will applied from {0,0}. */ - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin NS_SWIFT_NAME(applyLayout(preservingOrigin:)); /** - Perform a layout calculation and update the frames of the views in the hierarchy with the results. - If the origin is not preserved, the root view's layout results will applied from {0,0}. + Perform a layout calculation and update the frames of the views in the + hierarchy with the results. If the origin is not preserved, the root view's + layout results will applied from {0,0}. */ - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility NS_SWIFT_NAME(applyLayout(preservingOrigin:dimensionFlexibility:)); /** - Returns the size of the view if no constraints were given. This could equivalent to calling [self - sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; + Returns the size of the view if no constraints were given. This could + equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; */ -@property (nonatomic, readonly, assign) CGSize intrinsicSize; +@property(nonatomic, readonly, assign) CGSize intrinsicSize; /** - Returns the size of the view based on provided constraints. Pass NaN for an unconstrained dimension. + Returns the size of the view based on provided constraints. Pass NaN for an + unconstrained dimension. */ - (CGSize)calculateLayoutWithSize:(CGSize)size NS_SWIFT_NAME(calculateLayout(with:)); @@ -148,19 +152,19 @@ typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { /** Returns the number of children that are using Flexbox. */ -@property (nonatomic, readonly, assign) NSUInteger numberOfChildren; +@property(nonatomic, readonly, assign) NSUInteger numberOfChildren; /** - Return a BOOL indiciating whether or not we this node contains any subviews that are included in - Yoga's layout. + Return a BOOL indiciating whether or not we this node contains any subviews + that are included in Yoga's layout. */ -@property (nonatomic, readonly, assign) BOOL isLeaf; +@property(nonatomic, readonly, assign) BOOL isLeaf; /** Return's a BOOL indicating if a view is dirty. When a node is dirty it usually indicates that it will be remeasured on the next layout pass. */ -@property (nonatomic, readonly, assign) BOOL isDirty; +@property(nonatomic, readonly, assign) BOOL isDirty; /** Mark that a view's layout needs to be recalculated. Only works for leaf views. diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index f924bfc6..6398babe 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -5,153 +5,184 @@ * LICENSE file in the root directory of this source tree. */ -#import "YGLayout+Private.h" #import "UIView+Yoga.h" +#import "YGLayout+Private.h" -#define YG_PROPERTY(type, lowercased_name, capitalized_name) \ -- (type)lowercased_name \ -{ \ - return YGNodeStyleGet##capitalized_name(self.node); \ -} \ - \ -- (void)set##capitalized_name:(type)lowercased_name \ -{ \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \ +#define YG_PROPERTY(type, lowercased_name, capitalized_name) \ + -(type)lowercased_name { \ + return YGNodeStyleGet##capitalized_name(self.node); \ + } \ + \ + -(void)set##capitalized_name : (type)lowercased_name { \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \ + } + +#define YG_VALUE_PROPERTY(lowercased_name, capitalized_name) \ + -(YGValue)lowercased_name { \ + return YGNodeStyleGet##capitalized_name(self.node); \ + } \ + \ + -(void)set##capitalized_name : (YGValue)lowercased_name { \ + switch (lowercased_name.unit) { \ + case YGUnitUndefined: \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ + break; \ + case YGUnitPoint: \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ + break; \ + case YGUnitPercent: \ + YGNodeStyleSet##capitalized_name##Percent( \ + self.node, lowercased_name.value); \ + break; \ + default: \ + NSAssert(NO, @"Not implemented"); \ + } \ + } + +#define YG_AUTO_VALUE_PROPERTY(lowercased_name, capitalized_name) \ + -(YGValue)lowercased_name { \ + return YGNodeStyleGet##capitalized_name(self.node); \ + } \ + \ + -(void)set##capitalized_name : (YGValue)lowercased_name { \ + switch (lowercased_name.unit) { \ + case YGUnitPoint: \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ + break; \ + case YGUnitPercent: \ + YGNodeStyleSet##capitalized_name##Percent( \ + self.node, lowercased_name.value); \ + break; \ + case YGUnitAuto: \ + YGNodeStyleSet##capitalized_name##Auto(self.node); \ + break; \ + default: \ + NSAssert(NO, @"Not implemented"); \ + } \ + } + +#define YG_EDGE_PROPERTY_GETTER( \ + type, lowercased_name, capitalized_name, property, edge) \ + -(type)lowercased_name { \ + return YGNodeStyleGet##property(self.node, edge); \ + } + +#define YG_EDGE_PROPERTY_SETTER( \ + lowercased_name, capitalized_name, property, edge) \ + -(void)set##capitalized_name : (CGFloat)lowercased_name { \ + YGNodeStyleSet##property(self.node, edge, lowercased_name); \ + } + +#define YG_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \ + YG_EDGE_PROPERTY_GETTER( \ + CGFloat, lowercased_name, capitalized_name, property, edge) \ + YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) + +#define YG_VALUE_EDGE_PROPERTY_SETTER( \ + objc_lowercased_name, objc_capitalized_name, c_name, edge) \ + -(void)set##objc_capitalized_name : (YGValue)objc_lowercased_name { \ + switch (objc_lowercased_name.unit) { \ + case YGUnitUndefined: \ + YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ + break; \ + case YGUnitPoint: \ + YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ + break; \ + case YGUnitPercent: \ + YGNodeStyleSet##c_name##Percent( \ + self.node, edge, objc_lowercased_name.value); \ + break; \ + default: \ + NSAssert(NO, @"Not implemented"); \ + } \ + } + +#define YG_VALUE_EDGE_PROPERTY( \ + lowercased_name, capitalized_name, property, edge) \ + YG_EDGE_PROPERTY_GETTER( \ + YGValue, lowercased_name, capitalized_name, property, edge) \ + YG_VALUE_EDGE_PROPERTY_SETTER( \ + lowercased_name, capitalized_name, property, edge) + +#define YG_VALUE_EDGES_PROPERTIES(lowercased_name, capitalized_name) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##Left, \ + capitalized_name##Left, \ + capitalized_name, \ + YGEdgeLeft) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##Top, \ + capitalized_name##Top, \ + capitalized_name, \ + YGEdgeTop) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##Right, \ + capitalized_name##Right, \ + capitalized_name, \ + YGEdgeRight) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##Bottom, \ + capitalized_name##Bottom, \ + capitalized_name, \ + YGEdgeBottom) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##Start, \ + capitalized_name##Start, \ + capitalized_name, \ + YGEdgeStart) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##End, \ + capitalized_name##End, \ + capitalized_name, \ + YGEdgeEnd) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##Horizontal, \ + capitalized_name##Horizontal, \ + capitalized_name, \ + YGEdgeHorizontal) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name##Vertical, \ + capitalized_name##Vertical, \ + capitalized_name, \ + YGEdgeVertical) \ + YG_VALUE_EDGE_PROPERTY( \ + lowercased_name, capitalized_name, capitalized_name, YGEdgeAll) + +YGValue YGPointValue(CGFloat value) { + return (YGValue){.value = value, .unit = YGUnitPoint}; } -#define YG_VALUE_PROPERTY(lowercased_name, capitalized_name) \ -- (YGValue)lowercased_name \ -{ \ - return YGNodeStyleGet##capitalized_name(self.node); \ -} \ - \ -- (void)set##capitalized_name:(YGValue)lowercased_name \ -{ \ - switch (lowercased_name.unit) { \ - case YGUnitUndefined: \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ - break; \ - case YGUnitPoint: \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ - break; \ - case YGUnitPercent: \ - YGNodeStyleSet##capitalized_name##Percent(self.node, lowercased_name.value); \ - break; \ - default: \ - NSAssert(NO, @"Not implemented"); \ - } \ -} - -#define YG_AUTO_VALUE_PROPERTY(lowercased_name, capitalized_name) \ -- (YGValue)lowercased_name \ -{ \ - return YGNodeStyleGet##capitalized_name(self.node); \ -} \ - \ -- (void)set##capitalized_name:(YGValue)lowercased_name \ -{ \ - switch (lowercased_name.unit) { \ - case YGUnitPoint: \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ - break; \ - case YGUnitPercent: \ - YGNodeStyleSet##capitalized_name##Percent(self.node, lowercased_name.value); \ - break; \ - case YGUnitAuto: \ - YGNodeStyleSet##capitalized_name##Auto(self.node); \ - break; \ - default: \ - NSAssert(NO, @"Not implemented"); \ - } \ -} - -#define YG_EDGE_PROPERTY_GETTER(type, lowercased_name, capitalized_name, property, edge) \ -- (type)lowercased_name \ -{ \ - return YGNodeStyleGet##property(self.node, edge); \ -} - -#define YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) \ -- (void)set##capitalized_name:(CGFloat)lowercased_name \ -{ \ - YGNodeStyleSet##property(self.node, edge, lowercased_name); \ -} - -#define YG_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \ -YG_EDGE_PROPERTY_GETTER(CGFloat, lowercased_name, capitalized_name, property, edge) \ -YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) - -#define YG_VALUE_EDGE_PROPERTY_SETTER(objc_lowercased_name, objc_capitalized_name, c_name, edge) \ -- (void)set##objc_capitalized_name:(YGValue)objc_lowercased_name \ -{ \ - switch (objc_lowercased_name.unit) { \ - case YGUnitUndefined: \ - YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ - break; \ - case YGUnitPoint: \ - YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ - break; \ - case YGUnitPercent: \ - YGNodeStyleSet##c_name##Percent(self.node, edge, objc_lowercased_name.value); \ - break; \ - default: \ - NSAssert(NO, @"Not implemented"); \ - } \ -} - -#define YG_VALUE_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \ -YG_EDGE_PROPERTY_GETTER(YGValue, lowercased_name, capitalized_name, property, edge) \ -YG_VALUE_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) - -#define YG_VALUE_EDGES_PROPERTIES(lowercased_name, capitalized_name) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##Left, capitalized_name##Left, capitalized_name, YGEdgeLeft) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##Top, capitalized_name##Top, capitalized_name, YGEdgeTop) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##Right, capitalized_name##Right, capitalized_name, YGEdgeRight) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##Bottom, capitalized_name##Bottom, capitalized_name, YGEdgeBottom) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##Start, capitalized_name##Start, capitalized_name, YGEdgeStart) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##End, capitalized_name##End, capitalized_name, YGEdgeEnd) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##Horizontal, capitalized_name##Horizontal, capitalized_name, YGEdgeHorizontal) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name##Vertical, capitalized_name##Vertical, capitalized_name, YGEdgeVertical) \ -YG_VALUE_EDGE_PROPERTY(lowercased_name, capitalized_name, capitalized_name, YGEdgeAll) - -YGValue YGPointValue(CGFloat value) -{ - return (YGValue) { .value = value, .unit = YGUnitPoint }; -} - -YGValue YGPercentValue(CGFloat value) -{ - return (YGValue) { .value = value, .unit = YGUnitPercent }; +YGValue YGPercentValue(CGFloat value) { + return (YGValue){.value = value, .unit = YGUnitPercent}; } static YGConfigRef globalConfig; @interface YGLayout () -@property (nonatomic, weak, readonly) UIView *view; +@property(nonatomic, weak, readonly) UIView* view; @property(nonatomic, assign, readonly) BOOL isUIView; @end @implementation YGLayout -@synthesize isEnabled=_isEnabled; -@synthesize isIncludedInLayout=_isIncludedInLayout; -@synthesize node=_node; +@synthesize isEnabled = _isEnabled; +@synthesize isIncludedInLayout = _isIncludedInLayout; +@synthesize node = _node; -+ (void)initialize -{ ++ (void)initialize { globalConfig = YGConfigNew(); - YGConfigSetExperimentalFeatureEnabled(globalConfig, YGExperimentalFeatureWebFlexBasis, true); + YGConfigSetExperimentalFeatureEnabled( + globalConfig, YGExperimentalFeatureWebFlexBasis, true); YGConfigSetPointScaleFactor(globalConfig, [UIScreen mainScreen].scale); } -- (instancetype)initWithView:(UIView*)view -{ +- (instancetype)initWithView:(UIView*)view { if (self = [super init]) { _view = view; _node = YGNodeNewWithConfig(globalConfig); - YGNodeSetContext(_node, (__bridge void *) view); + YGNodeSetContext(_node, (__bridge void*)view); _isEnabled = NO; _isIncludedInLayout = YES; _isUIView = [view isMemberOfClass:[UIView class]]; @@ -160,18 +191,15 @@ static YGConfigRef globalConfig; return self; } -- (void)dealloc -{ +- (void)dealloc { YGNodeFree(self.node); } -- (BOOL)isDirty -{ +- (BOOL)isDirty { return YGNodeIsDirty(self.node); } -- (void)markDirty -{ +- (void)markDirty { if (self.isDirty || !self.isLeaf) { return; } @@ -187,17 +215,17 @@ static YGConfigRef globalConfig; YGNodeMarkDirty(node); } -- (NSUInteger)numberOfChildren -{ +- (NSUInteger)numberOfChildren { return YGNodeGetChildCount(self.node); } -- (BOOL)isLeaf -{ - NSAssert([NSThread isMainThread], @"This method must be called on the main thread."); +- (BOOL)isLeaf { + NSAssert( + [NSThread isMainThread], + @"This method must be called on the main thread."); if (self.isEnabled) { - for (UIView *subview in self.view.subviews) { - YGLayout *const yoga = subview.yoga; + for (UIView* subview in self.view.subviews) { + YGLayout* const yoga = subview.yoga; if (yoga.isEnabled && yoga.isIncludedInLayout) { return NO; } @@ -209,13 +237,11 @@ static YGConfigRef globalConfig; #pragma mark - Style -- (YGPositionType)position -{ +- (YGPositionType)position { return YGNodeStyleGetPositionType(self.node); } -- (void)setPosition:(YGPositionType)position -{ +- (void)setPosition:(YGPositionType)position { YGNodeStyleSetPositionType(self.node, position); } @@ -261,25 +287,23 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) #pragma mark - Layout and Sizing -- (YGDirection)resolvedDirection -{ +- (YGDirection)resolvedDirection { return YGNodeLayoutGetDirection(self.node); } -- (void)applyLayout -{ +- (void)applyLayout { [self calculateLayoutWithSize:self.view.bounds.size]; YGApplyLayoutToViewHierarchy(self.view, NO); } -- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin -{ +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin { [self calculateLayoutWithSize:self.view.bounds.size]; YGApplyLayoutToViewHierarchy(self.view, preserveOrigin); } -- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility -{ +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin + dimensionFlexibility: + (YGDimensionFlexibility)dimensionFlexibility { CGSize size = self.view.bounds.size; if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) { size.width = YGUndefined; @@ -291,18 +315,15 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) YGApplyLayoutToViewHierarchy(self.view, preserveOrigin); } - -- (CGSize)intrinsicSize -{ +- (CGSize)intrinsicSize { const CGSize constrainedSize = { - .width = YGUndefined, - .height = YGUndefined, + .width = YGUndefined, + .height = YGUndefined, }; return [self calculateLayoutWithSize:constrainedSize]; } -- (CGSize)calculateLayoutWithSize:(CGSize)size -{ +- (CGSize)calculateLayoutWithSize:(CGSize)size { NSAssert([NSThread isMainThread], @"Yoga calculation must be done on main."); NSAssert(self.isEnabled, @"Yoga is not enabled for this view."); @@ -310,30 +331,28 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) const YGNodeRef node = self.node; YGNodeCalculateLayout( - node, - size.width, - size.height, - YGNodeStyleGetDirection(node)); + node, size.width, size.height, YGNodeStyleGetDirection(node)); - return (CGSize) { - .width = YGNodeLayoutGetWidth(node), - .height = YGNodeLayoutGetHeight(node), + return (CGSize){ + .width = YGNodeLayoutGetWidth(node), + .height = YGNodeLayoutGetHeight(node), }; } #pragma mark - Private static YGSize YGMeasureView( - YGNodeRef node, - float width, - YGMeasureMode widthMode, - float height, - YGMeasureMode heightMode) -{ - const CGFloat constrainedWidth = (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width; - const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height; + YGNodeRef node, + float width, + YGMeasureMode widthMode, + float height, + YGMeasureMode heightMode) { + const CGFloat constrainedWidth = + (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width; + const CGFloat constrainedHeight = + (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : height; - UIView *view = (__bridge UIView*) YGNodeGetContext(node); + UIView* view = (__bridge UIView*)YGNodeGetContext(node); CGSize sizeThatFits = CGSizeZero; // The default implementation of sizeThatFits: returns the existing size of @@ -349,17 +368,18 @@ static YGSize YGMeasureView( }]; } - return (YGSize) { - .width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode), - .height = YGSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode), + return (YGSize){ + .width = YGSanitizeMeasurement( + constrainedWidth, sizeThatFits.width, widthMode), + .height = YGSanitizeMeasurement( + constrainedHeight, sizeThatFits.height, heightMode), }; } static CGFloat YGSanitizeMeasurement( - CGFloat constrainedSize, - CGFloat measuredSize, - YGMeasureMode measureMode) -{ + CGFloat constrainedSize, + CGFloat measuredSize, + YGMeasureMode measureMode) { CGFloat result; if (measureMode == YGMeasureModeExactly) { result = constrainedSize; @@ -372,13 +392,14 @@ static CGFloat YGSanitizeMeasurement( return result; } -static BOOL YGNodeHasExactSameChildren(const YGNodeRef node, NSArray *subviews) -{ +static BOOL YGNodeHasExactSameChildren( + const YGNodeRef node, + NSArray* subviews) { if (YGNodeGetChildCount(node) != subviews.count) { return NO; } - for (int i=0; i * return YES; } -static void YGAttachNodesFromViewHierachy(UIView *const view) -{ - YGLayout *const yoga = view.yoga; +static void YGAttachNodesFromViewHierachy(UIView* const view) { + YGLayout* const yoga = view.yoga; const YGNodeRef node = yoga.node; // Only leaf nodes should have a measure function @@ -399,8 +419,9 @@ static void YGAttachNodesFromViewHierachy(UIView *const view) } else { YGNodeSetMeasureFunc(node, NULL); - NSMutableArray *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; - for (UIView *subview in view.subviews) { + NSMutableArray* subviewsToInclude = + [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; + for (UIView* subview in view.subviews) { if (subview.yoga.isEnabled && subview.yoga.isIncludedInLayout) { [subviewsToInclude addObject:subview]; } @@ -408,19 +429,18 @@ static void YGAttachNodesFromViewHierachy(UIView *const view) if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) { YGRemoveAllChildren(node); - for (int i=0; i - DynamicLibrary + StaticLibrary true v141 Unicode @@ -48,7 +48,7 @@ Unicode - DynamicLibrary + StaticLibrary false v141 true @@ -62,13 +62,13 @@ Unicode - DynamicLibrary + StaticLibrary true v141 Unicode - DynamicLibrary + StaticLibrary false v141 true @@ -227,6 +227,8 @@ + + @@ -236,6 +238,7 @@ + @@ -243,14 +246,16 @@ + + - + diff --git a/csharp/Yoga/Yoga.vcxproj.filters b/csharp/Yoga/Yoga.vcxproj.filters index 3243c630..c03f853a 100755 --- a/csharp/Yoga/Yoga.vcxproj.filters +++ b/csharp/Yoga/Yoga.vcxproj.filters @@ -1,104 +1,119 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Resource Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + \ No newline at end of file diff --git a/csharp/Yoga/dllmain.cpp b/csharp/Yoga/dllmain.cpp index fb983975..450f087c 100644 --- a/csharp/Yoga/dllmain.cpp +++ b/csharp/Yoga/dllmain.cpp @@ -8,7 +8,8 @@ // dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" -BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { +BOOL APIENTRY +DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: diff --git a/csharp/Yoga/targetver.h b/csharp/Yoga/targetver.h index 571eb774..551298ff 100644 --- a/csharp/Yoga/targetver.h +++ b/csharp/Yoga/targetver.h @@ -9,7 +9,8 @@ // Including SDKDDKVer.h defines the highest available Windows platform. -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. +// If you wish to build your application for a previous Windows platform, +// include WinSDKVer.h and set the _WIN32_WINNT macro to the platform you wish +// to support before including SDKDDKVer.h. #include diff --git a/csharp/tests/Facebook.Yoga/YGDisplayTest.cs b/csharp/tests/Facebook.Yoga/YGDisplayTest.cs index 237686ba..659cb37f 100644 --- a/csharp/tests/Facebook.Yoga/YGDisplayTest.cs +++ b/csharp/tests/Facebook.Yoga/YGDisplayTest.cs @@ -1,9 +1,10 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ + // @Generated by gentest/gentest.rb from gentest/fixtures/YGDisplayTest.html using System; @@ -333,5 +334,47 @@ namespace Facebook.Yoga Assert.AreEqual(0f, root_child1.LayoutHeight); } + [Test] + public void Test_display_none_with_position_absolute() + { + YogaConfig config = new YogaConfig(); + + YogaNode root = new YogaNode(config); + root.Width = 100; + root.Height = 100; + + YogaNode root_child0 = new YogaNode(config); + root_child0.PositionType = YogaPositionType.Absolute; + root_child0.Width = 100; + root_child0.Height = 100; + root_child0.Display = YogaDisplay.None; + root.Insert(0, root_child0); + root.StyleDirection = YogaDirection.LTR; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(100f, root.LayoutWidth); + Assert.AreEqual(100f, root.LayoutHeight); + + Assert.AreEqual(0f, root_child0.LayoutX); + Assert.AreEqual(0f, root_child0.LayoutY); + Assert.AreEqual(0f, root_child0.LayoutWidth); + Assert.AreEqual(0f, root_child0.LayoutHeight); + + root.StyleDirection = YogaDirection.RTL; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(100f, root.LayoutWidth); + Assert.AreEqual(100f, root.LayoutHeight); + + Assert.AreEqual(0f, root_child0.LayoutX); + Assert.AreEqual(0f, root_child0.LayoutY); + Assert.AreEqual(0f, root_child0.LayoutWidth); + Assert.AreEqual(0f, root_child0.LayoutHeight); + } + } } diff --git a/gentest/fixtures/YGDisplayTest.html b/gentest/fixtures/YGDisplayTest.html index 74d11ba4..f11533f8 100644 --- a/gentest/fixtures/YGDisplayTest.html +++ b/gentest/fixtures/YGDisplayTest.html @@ -25,3 +25,7 @@
+ +
+
+
diff --git a/gentest/gentest-cs.js b/gentest/gentest-cs.js index 2e276180..f0cbd7fb 100644 --- a/gentest/gentest-cs.js +++ b/gentest/gentest-cs.js @@ -120,8 +120,9 @@ CSEmitter.prototype = Object.create(Emitter.prototype, { YGOverflowHidden:{value:'YogaOverflow.Hidden'}, YGOverflowVisible:{value:'YogaOverflow.Visible'}, - YGPositionTypeAbsolute:{value:'YogaPositionType.Absolute'}, + YGPositionTypeAbsolute:{value:'YogaPositionType.Static'}, YGPositionTypeRelative:{value:'YogaPositionType.Relative'}, + YGPositionTypeAbsolute:{value:'YogaPositionType.Absolute'}, YGUndefined:{value:'YogaConstants.Undefined'}, diff --git a/gentest/gentest.js b/gentest/gentest.js index ca370928..12e76f33 100755 --- a/gentest/gentest.js +++ b/gentest/gentest.js @@ -41,11 +41,11 @@ function assert(condition, message) { function printTest(e, LTRContainer, RTLContainer, genericContainer) { e.push([ - '/**', + '/*', ' * Copyright (c) Facebook, Inc. and its affiliates.', ' *', - ' * This source code is licensed under the MIT license found in the LICENSE', - ' * file in the root directory of this source tree.', + ' * This source code is licensed under the MIT license found in the', + ' * LICENSE file in the root directory of this source tree.', ' */', '// @Generated by gentest/gentest.rb from gentest/fixtures/' + document.title + '.html', '', diff --git a/gentest/gentest.rb b/gentest/gentest.rb index 22114501..01fec93e 100644 --- a/gentest/gentest.rb +++ b/gentest/gentest.rb @@ -7,13 +7,14 @@ require 'watir' require 'fileutils' -caps = Selenium::WebDriver::Remote::Capabilities.chrome( - "loggingPrefs"=>{ - "browser"=>"ALL", - "performance"=>"ALL" - } -) -browser = Watir::Browser.new(:chrome, :desired_capabilities => caps, :switches => ['--force-device-scale-factor=1', '--window-position=0,0']) +browser = Watir::Browser.new(:chrome, "goog:loggingPrefs" => { + "browser" => "ALL", + "performance" => "ALL" + }, + "chromeOptions" => { + "w3c" => "false" + }, + :switches => ['--force-device-scale-factor=1', '--window-position=0,0']) Dir.chdir(File.dirname($0)) diff --git a/gradle.properties b/gradle.properties index 820eae63..d5653873 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ org.gradle.jvmargs=-Xmx1536M -VERSION_NAME=1.16.0-SNAPSHOT +VERSION_NAME=1.19.0 POM_URL=https://github.com/facebook/yoga POM_SCM_URL=https://github.com/facebook/yoga.git POM_SCM_CONNECTION=scm:git:https://github.com/facebook/yoga.git @@ -17,5 +17,8 @@ POM_SCM_DEV_CONNECTION=scm:git:git@github.com:facebook/yoga.git POM_LICENSE_NAME=MIT License POM_LICENSE_URL=https://github.com/facebook/yoga/blob/master/LICENSE POM_LICENSE_DIST=repo +POM_LICENCE_NAME=MIT License +POM_LICENCE_URL=https://github.com/facebook/yoga/blob/master/LICENSE +POM_LICENCE_DIST=repo POM_DEVELOPER_ID=facebook POM_DEVELOPER_NAME=facebook diff --git a/gradle/android-maven-install.gradle b/gradle/android-maven-install.gradle deleted file mode 100644 index a5e7b823..00000000 --- a/gradle/android-maven-install.gradle +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// Configure the Android maven publication - -apply plugin: 'com.github.dcendents.android-maven' - -version = VERSION_NAME -group = GROUP -// Set the .aar / .jar base file name to match the artifact ID -// in case the module has a different name -project.archivesBaseName = POM_ARTIFACT_ID - -install { - repositories.mavenInstaller { - // This generates POM.xml with proper parameters - pom.project { - name POM_NAME - artifactId POM_ARTIFACT_ID - packaging POM_PACKAGING - description POM_DESCRIPTION - url projectUrl - - scm { - url scmUrl - connection scmConnection - developerConnection scmDeveloperConnection - } - - licenses projectLicenses - - developers { - developer { - id developerId - name developerName - } - } - } - } -} diff --git a/gradle/android-tasks.gradle b/gradle/android-tasks.gradle deleted file mode 100644 index 9e7028a9..00000000 --- a/gradle/android-tasks.gradle +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// Android tasks for Javadoc and sources.jar generation - -afterEvaluate { project -> - if (POM_PACKAGING == 'aar') { - task androidJavadoc(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - exclude '**/pom.xml' - exclude '**/proguard_annotations.pro' - classpath += files(android.bootClasspath) - } - - task androidJavadocJar(type: Jar) { - classifier = 'javadoc' - from androidJavadoc.destinationDir - } - - task androidSourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.java.srcDirs - } - - android.libraryVariants.all { variant -> - def name = variant.name.capitalize() - task "jar${name}"(type: Jar, dependsOn: variant.javaCompile) { - from variant.javaCompile.destinationDir - } - } - - artifacts.add('archives', androidJavadocJar) - artifacts.add('archives', androidSourcesJar) - } - - if (POM_PACKAGING == 'jar') { - task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir - } - - task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource - } - - artifacts.add('archives', javadocJar) - artifacts.add('archives', sourcesJar) - } -} diff --git a/gradle/bintray.gradle b/gradle/bintray.gradle deleted file mode 100644 index 20262c13..00000000 --- a/gradle/bintray.gradle +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// Upload to Bintray -apply plugin: 'com.jfrog.bintray' - -def getBintrayUsername() { - return project.hasProperty('bintrayUsername') ? property('bintrayUsername') : System.getenv('BINTRAY_USERNAME') -} - -def getBintrayApiKey() { - return project.hasProperty('bintrayApiKey') ? property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') -} - -def getBintrayGpgPassword() { - return project.hasProperty('bintrayGpgPassword') ? property('bintrayGpgPassword') : System.getenv('BINTRAY_GPG_PASSWORD') -} - -def getMavenCentralUsername() { - return project.hasProperty('mavenCentralUsername') ? property('mavenCentralUsername') : System.getenv('MAVEN_CENTRAL_USERNAME') -} - -def getMavenCentralPassword() { - return project.hasProperty('mavenCentralPassword') ? property('mavenCentralPassword') : System.getenv('MAVEN_CENTRAL_PASSWORD') -} - -def shouldSyncWithMavenCentral() { - return project.hasProperty('syncWithMavenCentral') ? property('syncWithMavenCentral').toBoolean() : false -} - -def dryRunOnly() { - return project.hasProperty('dryRun') ? property('dryRun').toBoolean() : false -} - -bintray { - user = getBintrayUsername() - key = getBintrayApiKey() - configurations = ['archives'] - pkg { - repo = bintrayRepo - userOrg = bintrayUserOrg - name = bintrayName - desc = bintrayDescription - websiteUrl = projectUrl - issueTrackerUrl = issuesUrl - vcsUrl = scmUrl - licenses = projectLicenses - dryRun = dryRunOnly() - override = true - publish = true - publicDownloadNumbers = true - version { - desc = bintrayDescription - gpg { - sign = true - passphrase = getBintrayGpgPassword() - } - mavenCentralSync { - sync = shouldSyncWithMavenCentral() - user = getMavenCentralUsername() - password = getMavenCentralPassword() - close = '1' // If set to 0, you have to manually click release - } - } - } -} diff --git a/gradle/gradle-mvn-push.gradle b/gradle/gradle-mvn-push.gradle deleted file mode 100644 index f7b6f1a1..00000000 --- a/gradle/gradle-mvn-push.gradle +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2013 Chris Banes - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'signing' - -version = VERSION_NAME -group = GROUP - -def isReleaseBuild() { - return VERSION_NAME.contains('SNAPSHOT') == false -} - -def getReleaseRepositoryUrl() { - return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL - : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" -} - -def getSnapshotRepositoryUrl() { - return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL - : "https://oss.sonatype.org/content/repositories/snapshots/" -} - -def getRepositoryUsername() { - return hasProperty('SONATYPE_NEXUS_USERNAME') ? SONATYPE_NEXUS_USERNAME : "" -} - -def getRepositoryPassword() { - return hasProperty('SONATYPE_NEXUS_PASSWORD') ? SONATYPE_NEXUS_PASSWORD : "" -} - -afterEvaluate { project -> - uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - pom.groupId = GROUP - pom.artifactId = POM_ARTIFACT_ID - pom.version = VERSION_NAME - - repository(url: getReleaseRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - snapshotRepository(url: getSnapshotRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - - pom.project { - name POM_NAME - packaging POM_PACKAGING - description POM_DESCRIPTION - url POM_URL - - scm { - url POM_SCM_URL - connection POM_SCM_CONNECTION - developerConnection POM_SCM_DEV_CONNECTION - } - - licenses { - license { - name POM_LICENSE_NAME - url POM_LICENSE_URL - distribution POM_LICENSE_DIST - } - } - - developers { - developer { - id POM_DEVELOPER_ID - name POM_DEVELOPER_NAME - } - } - } - } - } - } - - signing { - required { isReleaseBuild() && gradle.taskGraph.hasTask('uploadArchives') } - sign configurations.archives - } -} diff --git a/gradle/release-bintray.gradle b/gradle/release-bintray.gradle deleted file mode 100644 index 1c6e6891..00000000 --- a/gradle/release-bintray.gradle +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// Set up everything required for releasing on Bintray -ext { - bintrayRepo = 'maven' - bintrayUserOrg = 'facebook' - bintrayName = "${GROUP}:${POM_ARTIFACT_ID}" - bintrayDescription = POM_DESCRIPTION - projectUrl = POM_URL - issuesUrl = 'https://github.com/facebook/yoga/issues' - scmUrl = POM_SCM_URL - scmConnection = POM_SCM_CONNECTION - scmDeveloperConnection = POM_SCM_DEV_CONNECTION - - publishedGroupId = GROUP - libraryName = 'yoga' - artifact = 'yoga' - - developerId = POM_DEVELOPER_ID - developerName = POM_DEVELOPER_NAME - - projectLicenses = { - license { - name = POM_LICENSE_NAME - url = POM_LICENSE_URL - distribution = POM_LICENSE_DIST - } - } -} - -// Set up the Android Maven publication (POM etc.) -apply from: rootProject.file('gradle/android-maven-install.gradle') - -// Upload to Bintray -apply from: rootProject.file('gradle/bintray.gradle') diff --git a/gradle/release.gradle b/gradle/release.gradle deleted file mode 100644 index b63d0f2e..00000000 --- a/gradle/release.gradle +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// Common Android tasks for all releases that generate Javadocs, sources, etc. -apply from: rootProject.file('gradle/android-tasks.gradle') - -// Upload to Bintray -apply from: rootProject.file('gradle/release-bintray.gradle') - -// Upload directly to standard Maven Central (for SNAPSHOTs) -apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8772300a..7ff90540 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip diff --git a/java/BUCK b/java/BUCK index 72be4261..627c5678 100644 --- a/java/BUCK +++ b/java/BUCK @@ -3,11 +3,11 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "CXX_LIBRARY_WHITELIST", "JNI_TARGET", "JSR_305_TARGET", "JUNIT_TARGET", "PROGRUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "YOGA_ROOTS", "yoga_cxx_lib", "yoga_cxx_library", "yoga_dep", "yoga_java_binary", "yoga_java_library", "yoga_java_test", "yoga_prebuilt_cxx_library") +load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "CXX_LIBRARY_WHITELIST", "JNI_TARGET", "JSR_305_TARGET", "JUNIT_TARGET", "PROGUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "YOGA_ROOTS", "yoga_cxx_lib", "yoga_cxx_library", "yoga_dep", "yoga_java_binary", "yoga_java_library", "yoga_java_test", "yoga_prebuilt_cxx_library") CXX_LIBRARY_WHITELIST_FOR_TESTS = CXX_LIBRARY_WHITELIST + [ yoga_cxx_lib("testutil:jni"), - yoga_cxx_lib("testutil:testutil"), + yoga_cxx_lib("testutil:testutil-jni"), ] YOGA_JAVA_IMPLEMENTATION_FILES = [ @@ -54,7 +54,7 @@ yoga_cxx_library( visibility = ["PUBLIC"], deps = [ JNI_TARGET, - yoga_dep(":yoga"), + yoga_dep(":yoga-static"), ":ndklog", ], ) @@ -71,7 +71,7 @@ yoga_java_library( visibility = ["PUBLIC"], deps = [ JSR_305_TARGET, - PROGRUARD_ANNOTATIONS_TARGET, + PROGUARD_ANNOTATIONS_TARGET, ], ) @@ -85,7 +85,7 @@ yoga_java_library( ":java-interface", ":jni", JSR_305_TARGET, - PROGRUARD_ANNOTATIONS_TARGET, + PROGUARD_ANNOTATIONS_TARGET, SOLOADER_TARGET, ], ) @@ -108,6 +108,7 @@ yoga_java_library( yoga_java_test( name = "tests", srcs = glob(["tests/**/*.java"]), + contacts = ["oncall+yoga@xmail.facebook.com"], cxx_library_whitelist = CXX_LIBRARY_WHITELIST_FOR_TESTS, use_cxx_libraries = True, visibility = ["PUBLIC"], diff --git a/java/build.gradle b/java/build.gradle index 7c404c17..8d78a03f 100644 --- a/java/build.gradle +++ b/java/build.gradle @@ -5,17 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -apply plugin: 'com.jfrog.bintray' apply plugin: 'com.android.library' -apply plugin: 'com.github.dcendents.android-maven' -apply plugin: 'maven-publish' - -group = GROUP -version = VERSION_NAME android { compileSdkVersion rootProject.compileSdkVersion buildToolsVersion rootProject.buildToolsVersion + ndkVersion rootProject.ndkVersion defaultConfig { minSdkVersion rootProject.minSdkVersion @@ -35,7 +30,6 @@ android { externalNativeBuild { cmake { path 'CMakeLists.txt' - version '3.6.0-rc2' } } @@ -58,32 +52,11 @@ android { } dependencies { - implementation 'com.google.code.findbugs:jsr305:3.0.1' + implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation project(':yoga:proguard-annotations') - implementation 'com.facebook.soloader:soloader:0.5.1' + implementation 'com.facebook.soloader:soloader:0.10.1' testImplementation 'junit:junit:4.12' testImplementation project(':testutil') } -task sourcesJar(type: Jar) { - classifier = 'source' - from android.sourceSets.main.java.srcDirs -} - -task javadoc(type: Javadoc) { - failOnError false - source = android.sourceSets.main.java.sourceFiles - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - classpath += configurations.compile -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} - -ext { - bintrayName = 'com.facebook.yoga:yoga' -} - -apply from: rootProject.file('gradle/release.gradle') +apply plugin: 'com.vanniktech.maven.publish' diff --git a/java/com/facebook/yoga/YogaAlign.java b/java/com/facebook/yoga/YogaAlign.java index afeaa500..82c6cbfb 100644 --- a/java/com/facebook/yoga/YogaAlign.java +++ b/java/com/facebook/yoga/YogaAlign.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaAlign { AUTO(0), FLEX_START(1), diff --git a/java/com/facebook/yoga/YogaBaselineFunction.java b/java/com/facebook/yoga/YogaBaselineFunction.java index a859aff4..dbd405c6 100644 --- a/java/com/facebook/yoga/YogaBaselineFunction.java +++ b/java/com/facebook/yoga/YogaBaselineFunction.java @@ -7,14 +7,10 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public interface YogaBaselineFunction { /** * Return the baseline of the node in points. When no baseline function is set the baseline * default to the computed height of the node. */ - @DoNotStrip float baseline(YogaNode node, float width, float height); } diff --git a/java/com/facebook/yoga/YogaDimension.java b/java/com/facebook/yoga/YogaDimension.java index 77ff6caa..cebcdc47 100644 --- a/java/com/facebook/yoga/YogaDimension.java +++ b/java/com/facebook/yoga/YogaDimension.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaDimension { WIDTH(0), HEIGHT(1); diff --git a/java/com/facebook/yoga/YogaDirection.java b/java/com/facebook/yoga/YogaDirection.java index e18ee9fa..4e75d303 100644 --- a/java/com/facebook/yoga/YogaDirection.java +++ b/java/com/facebook/yoga/YogaDirection.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaDirection { INHERIT(0), LTR(1), diff --git a/java/com/facebook/yoga/YogaDisplay.java b/java/com/facebook/yoga/YogaDisplay.java index e69d74b3..76cbfd77 100644 --- a/java/com/facebook/yoga/YogaDisplay.java +++ b/java/com/facebook/yoga/YogaDisplay.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaDisplay { FLEX(0), NONE(1); diff --git a/java/com/facebook/yoga/YogaEdge.java b/java/com/facebook/yoga/YogaEdge.java index e60ffd88..cba17934 100644 --- a/java/com/facebook/yoga/YogaEdge.java +++ b/java/com/facebook/yoga/YogaEdge.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaEdge { LEFT(0), TOP(1), diff --git a/java/com/facebook/yoga/YogaExperimentalFeature.java b/java/com/facebook/yoga/YogaExperimentalFeature.java index 8eb1bd2a..76525eab 100644 --- a/java/com/facebook/yoga/YogaExperimentalFeature.java +++ b/java/com/facebook/yoga/YogaExperimentalFeature.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaExperimentalFeature { WEB_FLEX_BASIS(0); diff --git a/java/com/facebook/yoga/YogaFlexDirection.java b/java/com/facebook/yoga/YogaFlexDirection.java index c844074e..83060e13 100644 --- a/java/com/facebook/yoga/YogaFlexDirection.java +++ b/java/com/facebook/yoga/YogaFlexDirection.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaFlexDirection { COLUMN(0), COLUMN_REVERSE(1), diff --git a/java/com/facebook/yoga/YogaJustify.java b/java/com/facebook/yoga/YogaJustify.java index 3508e17d..3d39015e 100644 --- a/java/com/facebook/yoga/YogaJustify.java +++ b/java/com/facebook/yoga/YogaJustify.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaJustify { FLEX_START(0), CENTER(1), diff --git a/java/com/facebook/yoga/YogaLogLevel.java b/java/com/facebook/yoga/YogaLogLevel.java index 57cb4aa0..f6a84023 100644 --- a/java/com/facebook/yoga/YogaLogLevel.java +++ b/java/com/facebook/yoga/YogaLogLevel.java @@ -28,6 +28,7 @@ public enum YogaLogLevel { return mIntValue; } + @DoNotStrip public static YogaLogLevel fromInt(int value) { switch (value) { case 0: return ERROR; diff --git a/java/com/facebook/yoga/YogaMeasureFunction.java b/java/com/facebook/yoga/YogaMeasureFunction.java index 335c4c79..8b8533ba 100644 --- a/java/com/facebook/yoga/YogaMeasureFunction.java +++ b/java/com/facebook/yoga/YogaMeasureFunction.java @@ -7,14 +7,10 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public interface YogaMeasureFunction { /** * Return a value created by YogaMeasureOutput.make(width, height); */ - @DoNotStrip long measure( YogaNode node, float width, diff --git a/java/com/facebook/yoga/YogaMeasureMode.java b/java/com/facebook/yoga/YogaMeasureMode.java index dbfd22c7..848d4aa7 100644 --- a/java/com/facebook/yoga/YogaMeasureMode.java +++ b/java/com/facebook/yoga/YogaMeasureMode.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaMeasureMode { UNDEFINED(0), EXACTLY(1), diff --git a/java/com/facebook/yoga/YogaNative.java b/java/com/facebook/yoga/YogaNative.java index 334eaab5..3674b42f 100644 --- a/java/com/facebook/yoga/YogaNative.java +++ b/java/com/facebook/yoga/YogaNative.java @@ -34,6 +34,7 @@ public class YogaNative { static native void jni_YGNodeFreeJNI(long nativePointer); static native void jni_YGNodeResetJNI(long nativePointer); static native void jni_YGNodeInsertChildJNI(long nativePointer, long childPointer, int index); + static native void jni_YGNodeSwapChildJNI(long nativePointer, long childPointer, int index); static native void jni_YGNodeSetIsReferenceBaselineJNI(long nativePointer, boolean isReferenceBaseline); static native boolean jni_YGNodeIsReferenceBaselineJNI(long nativePointer); static native void jni_YGNodeClearChildrenJNI(long nativePointer); diff --git a/java/com/facebook/yoga/YogaNode.java b/java/com/facebook/yoga/YogaNode.java index baa0c517..109172ee 100644 --- a/java/com/facebook/yoga/YogaNode.java +++ b/java/com/facebook/yoga/YogaNode.java @@ -9,7 +9,15 @@ package com.facebook.yoga; import javax.annotation.Nullable; -public abstract class YogaNode { +public abstract class YogaNode implements YogaProps { + + /** The interface the {@link #getData()} object can optionally implement. */ + public interface Inputs { + + /** Requests the data object to disable mutations of its inputs. */ + void freeze(final YogaNode node, final @Nullable YogaNode parent); + } + public abstract void reset(); public abstract int getChildCount(); @@ -25,12 +33,10 @@ public abstract class YogaNode { public abstract YogaNode removeChildAt(int i); /** - * @returns the {@link YogaNode} that owns this {@link YogaNode}. - * The owner is used to identify the YogaTree that a {@link YogaNode} belongs - * to. - * This method will return the parent of the {@link YogaNode} when the - * {@link YogaNode} only belongs to one YogaTree or null when the - * {@link YogaNode} is shared between two or more YogaTrees. + * @returns the {@link YogaNode} that owns this {@link YogaNode}. The owner is used to identify + * the YogaTree that a {@link YogaNode} belongs to. This method will return the parent of the + * {@link YogaNode} when the {@link YogaNode} only belongs to one YogaTree or null when the + * {@link YogaNode} is shared between two or more YogaTrees. */ @Nullable public abstract YogaNode getOwner(); @@ -214,4 +220,6 @@ public abstract class YogaNode { public abstract void print(); public abstract YogaNode cloneWithoutChildren(); + + public abstract YogaNode cloneWithChildren(); } diff --git a/java/com/facebook/yoga/YogaNodeJNIBase.java b/java/com/facebook/yoga/YogaNodeJNIBase.java index 45d017c4..7efb8ce1 100644 --- a/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -15,7 +15,7 @@ import javax.annotation.Nullable; @DoNotStrip public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { - /* Those flags needs be in sync with YGJNI.cpp */ + /* Those flags needs be in sync with YGJNI.h */ private static final byte MARGIN = 1; private static final byte PADDING = 2; private static final byte BORDER = 4; @@ -39,11 +39,9 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { protected long mNativePointer; @Nullable private Object mData; - @DoNotStrip - private @Nullable float[] arr = null; + @DoNotStrip private @Nullable float[] arr = null; - @DoNotStrip - private int mLayoutDirection = 0; + @DoNotStrip private int mLayoutDirection = 0; private boolean mHasNewLayout = true; @@ -59,7 +57,7 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { } YogaNodeJNIBase(YogaConfig config) { - this(YogaNative.jni_YGNodeNewWithConfigJNI(((YogaConfigJNIBase)config).mNativePointer)); + this(YogaNative.jni_YGNodeNewWithConfigJNI(((YogaConfigJNIBase) config).mNativePointer)); } public void reset() { @@ -85,6 +83,9 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { } public void addChildAt(YogaNode c, int i) { + if (!(c instanceof YogaNodeJNIBase)) { + return; + } YogaNodeJNIBase child = (YogaNodeJNIBase) c; if (child.mOwner != null) { throw new IllegalStateException("Child already has a parent, it must be removed first."); @@ -106,6 +107,38 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { return YogaNative.jni_YGNodeIsReferenceBaselineJNI(mNativePointer); } + public void swapChildAt(YogaNode newChild, int position) { + if (!(newChild instanceof YogaNodeJNIBase)) { + return; + } + YogaNodeJNIBase child = (YogaNodeJNIBase) newChild; + mChildren.remove(position); + mChildren.add(position, child); + child.mOwner = this; + YogaNative.jni_YGNodeSwapChildJNI(mNativePointer, child.mNativePointer, position); + } + + @Override + public YogaNodeJNIBase cloneWithChildren() { + try { + YogaNodeJNIBase clonedYogaNode = (YogaNodeJNIBase) super.clone(); + if (clonedYogaNode.mChildren != null) { + clonedYogaNode.mChildren = new ArrayList<>(clonedYogaNode.mChildren); + } + long clonedNativePointer = YogaNative.jni_YGNodeCloneJNI(mNativePointer); + clonedYogaNode.mOwner = null; + clonedYogaNode.mNativePointer = clonedNativePointer; + for (int i = 0; i < clonedYogaNode.getChildCount(); i++) { + clonedYogaNode.swapChildAt(clonedYogaNode.getChildAt(i).cloneWithChildren(), i); + } + + return clonedYogaNode; + } catch (CloneNotSupportedException ex) { + // This class implements Cloneable, this should not happen + throw new RuntimeException(ex); + } + } + @Override public YogaNodeJNIBase cloneWithoutChildren() { try { @@ -138,12 +171,11 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { } /** - * @returns the {@link YogaNode} that owns this {@link YogaNode}. - * The owner is used to identify the YogaTree that a {@link YogaNode} belongs - * to. - * This method will return the parent of the {@link YogaNode} when the - * {@link YogaNode} only belongs to one YogaTree or null when the - * {@link YogaNode} is shared between two or more YogaTrees. + * The owner is used to identify the YogaTree that a {@link YogaNode} belongs to. This method will + * return the parent of the {@link YogaNode} when the {@link YogaNode} only belongs to one + * YogaTree or null when the {@link YogaNode} is shared between two or more YogaTrees. + * + * @return the {@link YogaNode} that owns this {@link YogaNode}. */ @Nullable public YogaNodeJNIBase getOwner() { @@ -165,12 +197,18 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { long[] nativePointers = null; YogaNodeJNIBase[] nodes = null; + freeze(null); + ArrayList n = new ArrayList<>(); n.add(this); for (int i = 0; i < n.size(); ++i) { - List children = n.get(i).mChildren; + final YogaNodeJNIBase parent = n.get(i); + List children = parent.mChildren; if (children != null) { - n.addAll(children); + for (YogaNodeJNIBase child : children) { + child.freeze(parent); + n.add(child); + } } } @@ -183,6 +221,13 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { YogaNative.jni_YGNodeCalculateLayoutJNI(mNativePointer, width, height, nativePointers, nodes); } + private void freeze(YogaNode parent) { + Object data = getData(); + if (data instanceof Inputs) { + ((Inputs) data).freeze(this, parent); + } + } + public void dirty() { YogaNative.jni_YGNodeMarkDirtyJNI(mNativePointer); } @@ -197,6 +242,9 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { @Override public void copyStyle(YogaNode srcNode) { + if (!(srcNode instanceof YogaNodeJNIBase)) { + return; + } YogaNative.jni_YGNodeCopyStyleJNI(mNativePointer, ((YogaNodeJNIBase) srcNode).mNativePointer); } @@ -509,8 +557,8 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { } /** - * Use the set logger (defaults to adb log) to print out the styles, children, and computed - * layout of the tree rooted at this node. + * Use the set logger (defaults to adb log) to print out the styles, children, and computed layout + * of the tree rooted at this node. */ public void print() { YogaNative.jni_YGNodePrintJNI(mNativePointer); @@ -521,7 +569,7 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { * This is different than calling removeChildAt and addChildAt because this method ONLY replaces * the child in the mChildren datastructure. @DoNotStrip: called from JNI * - * @return the nativePointer of the newNode {@linl YogaNode} + * @return the nativePointer of the newNode {@link YogaNode} */ @DoNotStrip private final long replaceChild(YogaNodeJNIBase newNode, int childIndex) { @@ -559,7 +607,9 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { } public boolean getDoesLegacyStretchFlagAffectsLayout() { - return arr != null && (((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & DOES_LEGACY_STRETCH_BEHAVIOUR) == DOES_LEGACY_STRETCH_BEHAVIOUR); + return arr != null + && (((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & DOES_LEGACY_STRETCH_BEHAVIOUR) + == DOES_LEGACY_STRETCH_BEHAVIOUR); } @Override @@ -575,9 +625,13 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { case BOTTOM: return arr[LAYOUT_MARGIN_START_INDEX + 3]; case START: - return getLayoutDirection() == YogaDirection.RTL ? arr[LAYOUT_MARGIN_START_INDEX + 2] : arr[LAYOUT_MARGIN_START_INDEX]; + return getLayoutDirection() == YogaDirection.RTL + ? arr[LAYOUT_MARGIN_START_INDEX + 2] + : arr[LAYOUT_MARGIN_START_INDEX]; case END: - return getLayoutDirection() == YogaDirection.RTL ? arr[LAYOUT_MARGIN_START_INDEX] : arr[LAYOUT_MARGIN_START_INDEX + 2]; + return getLayoutDirection() == YogaDirection.RTL + ? arr[LAYOUT_MARGIN_START_INDEX] + : arr[LAYOUT_MARGIN_START_INDEX + 2]; default: throw new IllegalArgumentException("Cannot get layout margins of multi-edge shorthands"); } @@ -589,7 +643,9 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { @Override public float getLayoutPadding(YogaEdge edge) { if (arr != null && ((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & PADDING) == PADDING) { - int paddingStartIndex = LAYOUT_PADDING_START_INDEX - ((((int)arr[LAYOUT_EDGE_SET_FLAG_INDEX] & MARGIN) == MARGIN) ? 0 : 4); + int paddingStartIndex = + LAYOUT_PADDING_START_INDEX + - ((((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & MARGIN) == MARGIN) ? 0 : 4); switch (edge) { case LEFT: return arr[paddingStartIndex]; @@ -600,9 +656,13 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { case BOTTOM: return arr[paddingStartIndex + 3]; case START: - return getLayoutDirection() == YogaDirection.RTL ? arr[paddingStartIndex + 2] : arr[paddingStartIndex]; + return getLayoutDirection() == YogaDirection.RTL + ? arr[paddingStartIndex + 2] + : arr[paddingStartIndex]; case END: - return getLayoutDirection() == YogaDirection.RTL ? arr[paddingStartIndex] : arr[paddingStartIndex + 2]; + return getLayoutDirection() == YogaDirection.RTL + ? arr[paddingStartIndex] + : arr[paddingStartIndex + 2]; default: throw new IllegalArgumentException("Cannot get layout paddings of multi-edge shorthands"); } @@ -614,7 +674,10 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { @Override public float getLayoutBorder(YogaEdge edge) { if (arr != null && ((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & BORDER) == BORDER) { - int borderStartIndex = LAYOUT_BORDER_START_INDEX - ((((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & MARGIN) == MARGIN) ? 0 : 4) - ((((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & PADDING) == PADDING) ? 0 : 4); + int borderStartIndex = + LAYOUT_BORDER_START_INDEX + - ((((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & MARGIN) == MARGIN) ? 0 : 4) + - ((((int) arr[LAYOUT_EDGE_SET_FLAG_INDEX] & PADDING) == PADDING) ? 0 : 4); switch (edge) { case LEFT: return arr[borderStartIndex]; @@ -625,9 +688,13 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { case BOTTOM: return arr[borderStartIndex + 3]; case START: - return getLayoutDirection() == YogaDirection.RTL ? arr[borderStartIndex + 2] : arr[borderStartIndex]; + return getLayoutDirection() == YogaDirection.RTL + ? arr[borderStartIndex + 2] + : arr[borderStartIndex]; case END: - return getLayoutDirection() == YogaDirection.RTL ? arr[borderStartIndex] : arr[borderStartIndex + 2]; + return getLayoutDirection() == YogaDirection.RTL + ? arr[borderStartIndex] + : arr[borderStartIndex + 2]; default: throw new IllegalArgumentException("Cannot get layout border of multi-edge shorthands"); } @@ -638,7 +705,8 @@ public abstract class YogaNodeJNIBase extends YogaNode implements Cloneable { @Override public YogaDirection getLayoutDirection() { - return YogaDirection.fromInt(arr != null ? (int) arr[LAYOUT_DIRECTION_INDEX] : mLayoutDirection); + return YogaDirection.fromInt( + arr != null ? (int) arr[LAYOUT_DIRECTION_INDEX] : mLayoutDirection); } @Override diff --git a/java/com/facebook/yoga/YogaNodeType.java b/java/com/facebook/yoga/YogaNodeType.java index 8d45d6ae..4386bf38 100644 --- a/java/com/facebook/yoga/YogaNodeType.java +++ b/java/com/facebook/yoga/YogaNodeType.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaNodeType { DEFAULT(0), TEXT(1); diff --git a/java/com/facebook/yoga/YogaOverflow.java b/java/com/facebook/yoga/YogaOverflow.java index 0e75106e..90c97881 100644 --- a/java/com/facebook/yoga/YogaOverflow.java +++ b/java/com/facebook/yoga/YogaOverflow.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaOverflow { VISIBLE(0), HIDDEN(1), diff --git a/java/com/facebook/yoga/YogaPositionType.java b/java/com/facebook/yoga/YogaPositionType.java index 23c2786f..d61c3244 100644 --- a/java/com/facebook/yoga/YogaPositionType.java +++ b/java/com/facebook/yoga/YogaPositionType.java @@ -7,12 +7,10 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaPositionType { - RELATIVE(0), - ABSOLUTE(1); + STATIC(0), + RELATIVE(1), + ABSOLUTE(2); private final int mIntValue; @@ -26,8 +24,9 @@ public enum YogaPositionType { public static YogaPositionType fromInt(int value) { switch (value) { - case 0: return RELATIVE; - case 1: return ABSOLUTE; + case 0: return STATIC; + case 1: return RELATIVE; + case 2: return ABSOLUTE; default: throw new IllegalArgumentException("Unknown enum value: " + value); } } diff --git a/java/com/facebook/yoga/YogaPrintOptions.java b/java/com/facebook/yoga/YogaPrintOptions.java index bc0c2de0..9a7f02ec 100644 --- a/java/com/facebook/yoga/YogaPrintOptions.java +++ b/java/com/facebook/yoga/YogaPrintOptions.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaPrintOptions { LAYOUT(1), STYLE(2), diff --git a/java/com/facebook/yoga/YogaProps.java b/java/com/facebook/yoga/YogaProps.java new file mode 100644 index 00000000..9faa520f --- /dev/null +++ b/java/com/facebook/yoga/YogaProps.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.yoga; + +public interface YogaProps { + + /* Width properties */ + + void setWidth(float width); + + void setWidthPercent(float percent); + + void setMinWidth(float minWidth); + + void setMinWidthPercent(float percent); + + void setMaxWidth(float maxWidth); + + void setMaxWidthPercent(float percent); + + void setWidthAuto(); + + /* Height properties */ + + void setHeight(float height); + + void setHeightPercent(float percent); + + void setMinHeight(float minHeight); + + void setMinHeightPercent(float percent); + + void setMaxHeight(float maxHeight); + + void setMaxHeightPercent(float percent); + + void setHeightAuto(); + + /* Margin properties */ + + void setMargin(YogaEdge edge, float margin); + + void setMarginPercent(YogaEdge edge, float percent); + + void setMarginAuto(YogaEdge edge); + + /* Padding properties */ + + void setPadding(YogaEdge edge, float padding); + + void setPaddingPercent(YogaEdge edge, float percent); + + /* Position properties */ + + void setPositionType(YogaPositionType positionType); + + void setPosition(YogaEdge edge, float position); + + void setPositionPercent(YogaEdge edge, float percent); + + /* Alignment properties */ + + void setAlignContent(YogaAlign alignContent); + + void setAlignItems(YogaAlign alignItems); + + void setAlignSelf(YogaAlign alignSelf); + + /* Flex properties */ + + void setFlex(float flex); + + void setFlexBasisAuto(); + + void setFlexBasisPercent(float percent); + + void setFlexBasis(float flexBasis); + + void setFlexDirection(YogaFlexDirection direction); + + void setFlexGrow(float flexGrow); + + void setFlexShrink(float flexShrink); + + /* Other properties */ + + void setJustifyContent(YogaJustify justifyContent); + + void setDirection(YogaDirection direction); + + void setBorder(YogaEdge edge, float value); + + void setWrap(YogaWrap wrap); + + void setAspectRatio(float aspectRatio); + + void setIsReferenceBaseline(boolean isReferenceBaseline); + + void setMeasureFunction(YogaMeasureFunction measureFunction); + + void setBaselineFunction(YogaBaselineFunction yogaBaselineFunction); + + /* Getters */ + + YogaValue getWidth(); + + YogaValue getMinWidth(); + + YogaValue getMaxWidth(); + + YogaValue getHeight(); + + YogaValue getMinHeight(); + + YogaValue getMaxHeight(); + + YogaDirection getStyleDirection(); + + YogaFlexDirection getFlexDirection(); + + YogaJustify getJustifyContent(); + + YogaAlign getAlignItems(); + + YogaAlign getAlignSelf(); + + YogaAlign getAlignContent(); + + YogaPositionType getPositionType(); + + float getFlexGrow(); + + float getFlexShrink(); + + YogaValue getFlexBasis(); + + float getAspectRatio(); + + YogaValue getMargin(YogaEdge edge); + + YogaValue getPadding(YogaEdge edge); + + YogaValue getPosition(YogaEdge edge); + + float getBorder(YogaEdge edge); +} diff --git a/java/com/facebook/yoga/YogaStyleInputs.java b/java/com/facebook/yoga/YogaStyleInputs.java index dc26bad8..21ca2803 100644 --- a/java/com/facebook/yoga/YogaStyleInputs.java +++ b/java/com/facebook/yoga/YogaStyleInputs.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public class YogaStyleInputs { public static final short LAYOUT_DIRECTION = 0; public static final short FLEX_DIRECTION = 1; diff --git a/java/com/facebook/yoga/YogaUnit.java b/java/com/facebook/yoga/YogaUnit.java index d43c8ff1..5a7e5e66 100644 --- a/java/com/facebook/yoga/YogaUnit.java +++ b/java/com/facebook/yoga/YogaUnit.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaUnit { UNDEFINED(0), POINT(1), diff --git a/java/com/facebook/yoga/YogaWrap.java b/java/com/facebook/yoga/YogaWrap.java index 23af8a40..7ad00568 100644 --- a/java/com/facebook/yoga/YogaWrap.java +++ b/java/com/facebook/yoga/YogaWrap.java @@ -7,9 +7,6 @@ package com.facebook.yoga; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip public enum YogaWrap { NO_WRAP(0), WRAP(1), diff --git a/java/jni/ScopedGlobalRef.h b/java/jni/ScopedGlobalRef.h index b1c18e68..fa98214a 100644 --- a/java/jni/ScopedGlobalRef.h +++ b/java/jni/ScopedGlobalRef.h @@ -84,9 +84,7 @@ public: return *this; } - ~ScopedGlobalRef() { - reset(); - } + ~ScopedGlobalRef() { reset(); } /** * Deletes the currently held reference and reassigns a new one to the @@ -120,9 +118,7 @@ public: /** * Returns true if the underlying JNI reference is not NULL. */ - operator bool() const { - return mGlobalRef != NULL; - } + operator bool() const { return mGlobalRef != NULL; } ScopedGlobalRef(const ScopedGlobalRef& ref) = delete; ScopedGlobalRef& operator=(const ScopedGlobalRef& other) = delete; diff --git a/java/jni/ScopedLocalRef.h b/java/jni/ScopedLocalRef.h index 0c5e9440..2368ced2 100644 --- a/java/jni/ScopedLocalRef.h +++ b/java/jni/ScopedLocalRef.h @@ -83,9 +83,7 @@ public: return *this; } - ~ScopedLocalRef() { - reset(); - } + ~ScopedLocalRef() { reset(); } /** * Deletes the currently held reference and reassigns a new one to the @@ -119,9 +117,7 @@ public: /** * Returns true if the underlying JNI reference is not NULL. */ - operator bool() const { - return mLocalRef != NULL; - } + operator bool() const { return mLocalRef != NULL; } ScopedLocalRef(const ScopedLocalRef& ref) = delete; ScopedLocalRef& operator=(const ScopedLocalRef& other) = delete; diff --git a/java/jni/YGJNIVanilla.cpp b/java/jni/YGJNIVanilla.cpp index 3ac88ac1..3503be40 100644 --- a/java/jni/YGJNIVanilla.cpp +++ b/java/jni/YGJNIVanilla.cpp @@ -15,6 +15,7 @@ #include #include #include +#include "YogaJniException.h" using namespace facebook::yoga::vanillajni; using facebook::yoga::detail::Log; @@ -195,7 +196,7 @@ static void jni_YGConfigSetLoggerJNI( delete context; YGConfigSetContext(config, nullptr); } - config->setLogger(nullptr); + YGConfigSetLogger(config, nullptr); } } @@ -224,6 +225,16 @@ static void jni_YGNodeInsertChildJNI( _jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer), index); } +static void jni_YGNodeSwapChildJNI( + JNIEnv* env, + jobject obj, + jlong nativePointer, + jlong childPointer, + jint index) { + YGNodeSwapChild( + _jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer), index); +} + static void jni_YGNodeSetIsReferenceBaselineJNI( JNIEnv* env, jobject obj, @@ -372,8 +383,18 @@ static void jni_YGNodeCalculateLayoutJNI( YGNodeStyleGetDirection(_jlong2YGNodeRef(nativePointer)), layoutContext); YGTransferLayoutOutputsRecursive(env, obj, root, layoutContext); - } catch (jthrowable throwable) { - env->Throw(throwable); + } catch (const YogaJniException& jniException) { + ScopedLocalRef throwable = jniException.getThrowable(); + if (throwable.get()) { + env->Throw(throwable.get()); + } + } catch (const std::logic_error& ex) { + env->ExceptionClear(); + jclass cl = env->FindClass("Ljava/lang/IllegalStateException;"); + static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId( + env, cl, "", "(Ljava/lang/String;)V"); + auto throwable = env->NewObject(cl, methodId, env->NewStringUTF(ex.what())); + env->Throw(static_cast(throwable)); } } @@ -705,8 +726,7 @@ static void jni_YGNodePrintJNI(JNIEnv* env, jobject obj, jlong nativePointer) { const YGNodeRef node = _jlong2YGNodeRef(nativePointer); YGNodePrint( node, - (YGPrintOptions)( - YGPrintOptionsStyle | YGPrintOptionsLayout | YGPrintOptionsChildren)); + (YGPrintOptions) (YGPrintOptionsStyle | YGPrintOptionsLayout | YGPrintOptionsChildren)); #endif } @@ -750,6 +770,7 @@ static JNINativeMethod methods[] = { {"jni_YGNodeFreeJNI", "(J)V", (void*) jni_YGNodeFreeJNI}, {"jni_YGNodeResetJNI", "(J)V", (void*) jni_YGNodeResetJNI}, {"jni_YGNodeInsertChildJNI", "(JJI)V", (void*) jni_YGNodeInsertChildJNI}, + {"jni_YGNodeSwapChildJNI", "(JJI)V", (void*) jni_YGNodeSwapChildJNI}, {"jni_YGNodeSetIsReferenceBaselineJNI", "(JZ)V", (void*) jni_YGNodeSetIsReferenceBaselineJNI}, diff --git a/java/jni/YogaJniException.cpp b/java/jni/YogaJniException.cpp new file mode 100644 index 00000000..5d6bfbfe --- /dev/null +++ b/java/jni/YogaJniException.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include "YogaJniException.h" +#include "common.h" + +namespace facebook { +namespace yoga { +namespace vanillajni { + +YogaJniException::YogaJniException() { + jclass cl = getCurrentEnv()->FindClass("Ljava/lang/RuntimeException;"); + static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId( + getCurrentEnv(), cl, "", "()V"); + auto throwable = getCurrentEnv()->NewObject(cl, methodId); + throwable_ = + newGlobalRef(getCurrentEnv(), static_cast(throwable)); +} + +YogaJniException::YogaJniException(jthrowable throwable) { + throwable_ = newGlobalRef(getCurrentEnv(), throwable); +} + +YogaJniException::YogaJniException(YogaJniException&& rhs) + : throwable_(std::move(rhs.throwable_)) {} + +YogaJniException::YogaJniException(const YogaJniException& rhs) { + throwable_ = newGlobalRef(getCurrentEnv(), rhs.throwable_.get()); +} + +YogaJniException::~YogaJniException() { + try { + throwable_.reset(); + } catch (...) { + std::terminate(); + } +} + +ScopedLocalRef YogaJniException::getThrowable() const noexcept { + return make_local_ref( + getCurrentEnv(), + static_cast(getCurrentEnv()->NewLocalRef(throwable_.get()))); +} +} // namespace vanillajni +} // namespace yoga +} // namespace facebook diff --git a/java/jni/YogaJniException.h b/java/jni/YogaJniException.h new file mode 100644 index 00000000..d333adf5 --- /dev/null +++ b/java/jni/YogaJniException.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include "common.h" + +namespace facebook { +namespace yoga { +namespace vanillajni { +/** + * This class wraps a Java exception (jthrowable) into a C++ exception; A global + * reference to Java exception (jthrowable) is made so that the exception object + * does not gets cleared before jni call completion + */ +class YogaJniException : public std::exception { +public: + YogaJniException(); + ~YogaJniException() override; + + explicit YogaJniException(jthrowable throwable); + + YogaJniException(YogaJniException&& rhs); + + YogaJniException(const YogaJniException& other); + + ScopedLocalRef getThrowable() const noexcept; + +private: + ScopedGlobalRef throwable_; +}; +} // namespace vanillajni +} // namespace yoga +} // namespace facebook diff --git a/java/jni/common.cpp b/java/jni/common.cpp index f69ef94f..37b56770 100644 --- a/java/jni/common.cpp +++ b/java/jni/common.cpp @@ -18,11 +18,11 @@ void registerNatives( size_t numMethods) { jclass clazz = env->FindClass(className); - assertNoPendingJniException(env); + assertNoPendingJniExceptionIf(env, !clazz); - env->RegisterNatives(clazz, methods, numMethods); + auto result = env->RegisterNatives(clazz, methods, numMethods); - assertNoPendingJniException(env); + assertNoPendingJniExceptionIf(env, result != JNI_OK); } jmethodID getStaticMethodId( @@ -32,7 +32,7 @@ jmethodID getStaticMethodId( const char* methodDescriptor) { jmethodID methodId = env->GetStaticMethodID(clazz, methodName, methodDescriptor); - assertNoPendingJniException(env); + assertNoPendingJniExceptionIf(env, !methodId); return methodId; } @@ -42,7 +42,7 @@ jmethodID getMethodId( const char* methodName, const char* methodDescriptor) { jmethodID methodId = env->GetMethodID(clazz, methodName, methodDescriptor); - assertNoPendingJniException(env); + assertNoPendingJniExceptionIf(env, !methodId); return methodId; } @@ -52,7 +52,7 @@ jfieldID getFieldId( const char* fieldName, const char* fieldSignature) { jfieldID fieldId = env->GetFieldID(clazz, fieldName, fieldSignature); - assertNoPendingJniException(env); + assertNoPendingJniExceptionIf(env, !fieldId); return fieldId; } @@ -77,13 +77,16 @@ DEFINE_CALL_METHOD_FOR_PRIMITIVE_INTERFACE(void, Void) { assertNoPendingJniException(env); } -ScopedLocalRef -callStaticObjectMethod(JNIEnv* env, jclass clazz, jmethodID methodId, ...) { +ScopedLocalRef callStaticObjectMethod( + JNIEnv* env, + jclass clazz, + jmethodID methodId, + ...) { va_list args; va_start(args, methodId); jobject result = env->CallStaticObjectMethodV(clazz, methodId, args); va_end(args); - assertNoPendingJniException(env); + assertNoPendingJniExceptionIf(env, !result); return make_local_ref(env, result); } @@ -96,6 +99,16 @@ ScopedGlobalRef newGlobalRef(JNIEnv* env, jobject obj) { return make_global_ref(result); } + +ScopedGlobalRef newGlobalRef(JNIEnv* env, jthrowable obj) { + jthrowable result = static_cast(env->NewGlobalRef(obj)); + + if (!result) { + logErrorMessageAndDie("Could not obtain global reference from object"); + } + + return make_global_ref(result); +} } // namespace vanillajni } // namespace yoga } // namespace facebook diff --git a/java/jni/common.h b/java/jni/common.h index eebf8e9c..fda1e06d 100644 --- a/java/jni/common.h +++ b/java/jni/common.h @@ -61,14 +61,19 @@ DEFINE_CALL_METHOD_FOR_PRIMITIVE_INTERFACE(void, Void); DEFINE_CALL_METHOD_FOR_PRIMITIVE_INTERFACE(jlong, Long); DEFINE_CALL_METHOD_FOR_PRIMITIVE_INTERFACE(jfloat, Float); -ScopedLocalRef -callStaticObjectMethod(JNIEnv* env, jclass clazz, jmethodID methodId, ...); +ScopedLocalRef callStaticObjectMethod( + JNIEnv* env, + jclass clazz, + jmethodID methodId, + ...); /** * Given a local or a global reference, this method creates a new global * reference out of it. If any error happens, aborts the process. */ ScopedGlobalRef newGlobalRef(JNIEnv* env, jobject obj); + +ScopedGlobalRef newGlobalRef(JNIEnv* env, jthrowable obj); } // namespace vanillajni } // namespace yoga } // namespace facebook diff --git a/java/jni/corefunctions.cpp b/java/jni/corefunctions.cpp index 04435724..8d522289 100644 --- a/java/jni/corefunctions.cpp +++ b/java/jni/corefunctions.cpp @@ -7,6 +7,7 @@ #include "corefunctions.h" #include "macros.h" +#include "YogaJniException.h" namespace facebook { namespace yoga { @@ -72,7 +73,20 @@ void assertNoPendingJniException(JNIEnv* env) { logErrorMessageAndDie("Unable to get pending JNI exception."); } env->ExceptionClear(); - throw throwable; + throw YogaJniException(throwable); +} + +void assertNoPendingJniExceptionIf(JNIEnv* env, bool condition) { + if (!condition) { + return; + } + + if (env->ExceptionCheck() == JNI_TRUE) { + assertNoPendingJniException(env); + return; + } + + throw YogaJniException(); } } // namespace vanillajni diff --git a/java/jni/corefunctions.h b/java/jni/corefunctions.h index 73d6cce4..18736dbb 100644 --- a/java/jni/corefunctions.h +++ b/java/jni/corefunctions.h @@ -47,6 +47,8 @@ void logErrorMessageAndDie(const char* message); */ void assertNoPendingJniException(JNIEnv* env); +void assertNoPendingJniExceptionIf(JNIEnv* env, bool condition); + } // namespace vanillajni } // namespace yoga } // namespace facebook diff --git a/java/proguard-annotations/build.gradle b/java/proguard-annotations/build.gradle index c4476d9e..97754e99 100644 --- a/java/proguard-annotations/build.gradle +++ b/java/proguard-annotations/build.gradle @@ -10,4 +10,4 @@ apply plugin: 'java' sourceCompatibility = '1.7' targetCompatibility = '1.7' -apply from: rootProject.file('gradle/release.gradle') +apply plugin: 'com.vanniktech.maven.publish' diff --git a/java/proguard-annotations/src/main/java/com/facebook/proguard/annotations/DoNotStripAny.java b/java/proguard-annotations/src/main/java/com/facebook/proguard/annotations/DoNotStripAny.java new file mode 100644 index 00000000..48f71f2b --- /dev/null +++ b/java/proguard-annotations/src/main/java/com/facebook/proguard/annotations/DoNotStripAny.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.proguard.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.CLASS; + +/** + * Add this annotation to a class to instruct Proguard to not strip it or any of its fields or + * methods out. + * + *

This is useful for methods called via reflection that could appear as unused to Proguard. + */ +@Target({ElementType.TYPE}) +@Retention(CLASS) +public @interface DoNotStripAny {} diff --git a/java/tests/com/facebook/yoga/YGDisplayTest.java b/java/tests/com/facebook/yoga/YGDisplayTest.java index f1e6f896..999548bd 100644 --- a/java/tests/com/facebook/yoga/YGDisplayTest.java +++ b/java/tests/com/facebook/yoga/YGDisplayTest.java @@ -1,9 +1,10 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ + // @Generated by gentest/gentest.rb from gentest/fixtures/YGDisplayTest.html package com.facebook.yoga; @@ -337,6 +338,47 @@ public class YGDisplayTest { assertEquals(0f, root_child1.getLayoutHeight(), 0.0f); } + @Test + public void test_display_none_with_position_absolute() { + YogaConfig config = YogaConfigFactory.create(); + + final YogaNode root = createNode(config); + root.setWidth(100f); + root.setHeight(100f); + + final YogaNode root_child0 = createNode(config); + root_child0.setPositionType(YogaPositionType.ABSOLUTE); + root_child0.setWidth(100f); + root_child0.setHeight(100f); + root_child0.setDisplay(YogaDisplay.NONE); + root.addChildAt(root_child0, 0); + root.setDirection(YogaDirection.LTR); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(100f, root.getLayoutWidth(), 0.0f); + assertEquals(100f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(0f, root_child0.getLayoutHeight(), 0.0f); + + root.setDirection(YogaDirection.RTL); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(100f, root.getLayoutWidth(), 0.0f); + assertEquals(100f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(0f, root_child0.getLayoutHeight(), 0.0f); + } + private YogaNode createNode(YogaConfig config) { return mNodeFactory.create(config); } diff --git a/java/tests/com/facebook/yoga/YogaLoggerTest.java b/java/tests/com/facebook/yoga/YogaLoggerTest.java index 17316f6e..f88409d6 100644 --- a/java/tests/com/facebook/yoga/YogaLoggerTest.java +++ b/java/tests/com/facebook/yoga/YogaLoggerTest.java @@ -9,10 +9,62 @@ package com.facebook.yoga; import org.junit.Test; import java.lang.ref.WeakReference; +import java.util.List; +import java.util.ArrayList; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class YogaLoggerTest { + + @Test + public void testRemovingLoggerFromConfig() throws Exception { + final List logs = new ArrayList<>(); + + final YogaConfig config = YogaConfigFactory.create(); + YogaLogger logger = new YogaLogger() { + @Override + public void log(YogaLogLevel level, String message) { + logs.add(message); + } + }; + config.setLogger(logger); + + final YogaNode root = YogaNodeFactory.create(config); + root.setFlexDirection(YogaFlexDirection.ROW); + root.setAlignItems(YogaAlign.BASELINE); + + final YogaNode child1 = YogaNodeFactory.create(config); + root.addChildAt(child1, 0); + + final YogaNode child2 = YogaNodeFactory.create(config); + child2.setBaselineFunction(new YogaBaselineFunction() { + public float baseline(YogaNode node, float width, float height) { + return Float.NaN; + } + }); + root.addChildAt(child2, 1); + + assertEquals(logs.size(), 0); + try { + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + fail("Expected calculateLayout to throw"); + } catch (IllegalStateException e) { + } + + assertEquals(logs.size(), 1); + + config.setLogger(null); + + try { + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + fail("Expected calculateLayout to throw again"); + } catch (IllegalStateException e) { + } + + assertEquals(logs.size(), 1); + } + @Test public void testLoggerLeak() throws Exception { final YogaConfig config = YogaConfigFactory.create(); diff --git a/java/tests/com/facebook/yoga/YogaNodeStylePropertiesTest.java b/java/tests/com/facebook/yoga/YogaNodeStylePropertiesTest.java index 649c7279..c39ea024 100644 --- a/java/tests/com/facebook/yoga/YogaNodeStylePropertiesTest.java +++ b/java/tests/com/facebook/yoga/YogaNodeStylePropertiesTest.java @@ -191,7 +191,7 @@ public class YogaNodeStylePropertiesTest { public void testPositionTypeDefault() { final YogaNode node = createNode(); - assertEquals(YogaPositionType.RELATIVE, node.getPositionType()); + assertEquals(YogaPositionType.STATIC, node.getPositionType()); } @Test diff --git a/javascript/.flowconfig b/javascript/.flowconfig index 1fed4453..6bd402f8 100644 --- a/javascript/.flowconfig +++ b/javascript/.flowconfig @@ -7,5 +7,9 @@ [lints] [options] +types_first=false [strict] + +[version] +^0.140.0 diff --git a/javascript/sources/Node.cc b/javascript/sources/Node.cc index 7e6833fe..421cfa71 100644 --- a/javascript/sources/Node.cc +++ b/javascript/sources/Node.cc @@ -23,8 +23,8 @@ static YGSize globalMeasureFunc( Node const& node = *reinterpret_cast(YGNodeGetContext(nodeRef)); Size size = node.callMeasureFunc(width, widthMode, height, heightMode); - YGSize ygSize = {static_cast(size.width), - static_cast(size.height)}; + YGSize ygSize = { + static_cast(size.width), static_cast(size.height)}; return ygSize; } diff --git a/javascript/sources/Size.hh b/javascript/sources/Size.hh index d7ea6da9..9f550a96 100644 --- a/javascript/sources/Size.hh +++ b/javascript/sources/Size.hh @@ -18,7 +18,5 @@ struct Size { Size(double width, double height) : width(width), height(height) {} - void toJS(nbind::cbOutput expose) const { - expose(width, height); - } + void toJS(nbind::cbOutput expose) const { expose(width, height); } }; diff --git a/javascript/sources/Value.hh b/javascript/sources/Value.hh index e7a9cf66..2581ae4a 100644 --- a/javascript/sources/Value.hh +++ b/javascript/sources/Value.hh @@ -21,7 +21,5 @@ struct Value { Value(int unit, double value) : unit(unit), value(value) {} - void toJS(nbind::cbOutput expose) const { - expose(unit, value); - } + void toJS(nbind::cbOutput expose) const { expose(unit, value); } }; diff --git a/javascript/tests/Facebook.Yoga/YGDisplayTest.js b/javascript/tests/Facebook.Yoga/YGDisplayTest.js index e5be4a55..cf65ab22 100644 --- a/javascript/tests/Facebook.Yoga/YGDisplayTest.js +++ b/javascript/tests/Facebook.Yoga/YGDisplayTest.js @@ -1,9 +1,10 @@ /** * Copyright (c) Facebook, Inc. and its affiliates. * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ + // @Generated by gentest/gentest.rb from gentest/fixtures/YGDisplayTest.html var Yoga = Yoga || require("../../sources/entry-" + process.env.TEST_ENTRY); @@ -342,3 +343,48 @@ it("display_none_with_position", function () { config.free(); } }); +it("display_none_with_position_absolute", function () { + var config = Yoga.Config.create(); + + try { + var root = Yoga.Node.create(config); + root.setWidth(100); + root.setHeight(100); + + var root_child0 = Yoga.Node.create(config); + root_child0.setPositionType(Yoga.POSITION_TYPE_ABSOLUTE); + root_child0.setWidth(100); + root_child0.setHeight(100); + root_child0.setDisplay(Yoga.DISPLAY_NONE); + root.insertChild(root_child0, 0); + root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_LTR); + + console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")"); + console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")"); + console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")"); + + console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")"); + console.assert(0 === root_child0.getComputedWidth(), "0 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")"); + console.assert(0 === root_child0.getComputedHeight(), "0 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")"); + + root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_RTL); + + console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")"); + console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")"); + console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")"); + + console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")"); + console.assert(0 === root_child0.getComputedWidth(), "0 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")"); + console.assert(0 === root_child0.getComputedHeight(), "0 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")"); + } finally { + if (typeof root !== "undefined") { + root.freeRecursive(); + } + + config.free(); + } +}); diff --git a/lib/fb/build.gradle b/lib/fb/build.gradle index d5e5e202..a3495d8f 100644 --- a/lib/fb/build.gradle +++ b/lib/fb/build.gradle @@ -33,8 +33,8 @@ android { } dependencies { - implementation 'com.facebook.soloader:soloader:0.5.1' - implementation 'com.google.code.findbugs:jsr305:3.0.1' + implementation 'com.facebook.soloader:soloader:0.10.1' + implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation project(':yoga:proguard-annotations') } } diff --git a/lib/fb/src/main/java/com/facebook/jni/BUCK b/lib/fb/src/main/java/com/facebook/jni/BUCK index e048811d..38526c26 100644 --- a/lib/fb/src/main/java/com/facebook/jni/BUCK +++ b/lib/fb/src/main/java/com/facebook/jni/BUCK @@ -3,7 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -load("//tools/build_defs/oss:yoga_defs.bzl", "JSR_305_TARGET", "PROGRUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "yoga_java_library") +load("//tools/build_defs/oss:yoga_defs.bzl", "JSR_305_TARGET", "PROGUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "yoga_java_library") yoga_java_library( name = "jni", @@ -13,7 +13,7 @@ yoga_java_library( "PUBLIC", ], deps = [ - PROGRUARD_ANNOTATIONS_TARGET, + PROGUARD_ANNOTATIONS_TARGET, SOLOADER_TARGET, JSR_305_TARGET, ], diff --git a/lib/soloader/BUCK b/lib/soloader/BUCK index 04e2f5ff..eaff4f68 100644 --- a/lib/soloader/BUCK +++ b/lib/soloader/BUCK @@ -3,10 +3,9 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native") -load("//tools/build_defs/oss:yoga_defs.bzl", "YOGA_ROOTS") +load("//tools/build_defs/oss:yoga_defs.bzl", "YOGA_ROOTS", "yoga_prebuilt_aar") -fb_native.android_prebuilt_aar( +yoga_prebuilt_aar( name = "soloader", aar = "soloader-0.5.1.aar", visibility = YOGA_ROOTS, diff --git a/scripts/publish-snapshot.sh b/scripts/publish-snapshot.sh index 02c45457..236d8055 100755 --- a/scripts/publish-snapshot.sh +++ b/scripts/publish-snapshot.sh @@ -14,17 +14,8 @@ set -e BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" IS_SNAPSHOT="$(grep 'VERSION_NAME=[0-9\.]\+-SNAPSHOT' "$BASEDIR/gradle.properties")" -if [ "$TRAVIS_REPO_SLUG" != "facebook/yoga" ]; then - echo >&2 "Skipping repository. Expected project to be 'facebook/yoga', but was '$TRAVIS_REPO_SLUG'." - exit -elif [ "$TRAVIS_BRANCH" != "master" ]; then - echo >&2 "Skipping build. Expected branch name to be 'master', but was '$TRAVIS_BRANCH'." - exit -elif [ "$TRAVIS_PULL_REQUEST" != "false" ]; then - echo >&2 "Skipping build. Only considering non-PR builds, but URL was '$TRAVIS_PULL_REQUEST'." - exit -elif [ "$IS_SNAPSHOT" == "" ]; then +if [ "$IS_SNAPSHOT" == "" ]; then echo >&2 "Skipping build. Given build doesn't appear to be a SNAPSHOT release." else - env TERMINAL=dumb "$BASEDIR/gradlew" uploadArchives + env TERMINAL=dumb "$BASEDIR/gradlew" publish fi diff --git a/tests/BitUtilsTest.cpp b/tests/BitUtilsTest.cpp new file mode 100644 index 00000000..d20ee307 --- /dev/null +++ b/tests/BitUtilsTest.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +namespace facebook { +namespace yoga { + +TEST(BitUtils, one_boolean_defaults_to_false) { + constexpr uint8_t flags = 0; + + ASSERT_EQ(detail::getBooleanData(flags, 0), false); + static_assert( + detail::getBooleanData(flags, 0) == false, + "first boolean member must default to false"); +} + +TEST(BitUtils, one_boolean_can_be_initialized_to_true) { + constexpr uint8_t flags = 1; + + ASSERT_EQ(detail::getBooleanData(flags, 0), true); + static_assert( + detail::getBooleanData(flags, 0) == true, + "first boolean member must be initialized to true"); +} + +TEST(BitUtils, one_boolean_can_be_set_to_true) { + uint8_t flags = 0; + + detail::setBooleanData(flags, 0, true); + ASSERT_EQ(detail::getBooleanData(flags, 0), true); +} + +TEST(BitUtils, second_boolean_defaults_to_false) { + constexpr uint8_t flags = 0; + + ASSERT_EQ(detail::getBooleanData(flags, 1), false); + static_assert( + detail::getBooleanData(flags, 1) == false, + "second boolean member must default to false"); +} + +TEST(BitUtils, second_boolean_can_be_initialized_to_true) { + constexpr uint8_t flags = 2; + + ASSERT_EQ(detail::getBooleanData(flags, 0), false); + ASSERT_EQ(detail::getBooleanData(flags, 1), true); + static_assert( + detail::getBooleanData(flags, 0) == false, + "first boolean member must default to false"); + static_assert( + detail::getBooleanData(flags, 1) == true, + "second boolean member must be initialized to true"); +} + +TEST(BitUtils, second_boolean_can_be_set_to_true) { + uint8_t flags = 0; + + detail::setBooleanData(flags, 1, true); + ASSERT_EQ(detail::getBooleanData(flags, 0), false); + ASSERT_EQ(detail::getBooleanData(flags, 1), true); +} + +TEST(BitUtils, third_boolean_defaults_to_false) { + constexpr uint8_t flags = 0; + + ASSERT_EQ(detail::getBooleanData(flags, 2), false); + static_assert( + detail::getBooleanData(flags, 2) == false, + "second boolean member must default to false"); +} + +TEST(BitUtils, third_boolean_can_be_initialized_to_true) { + constexpr uint8_t flags = 4; + + ASSERT_EQ(detail::getBooleanData(flags, 0), false); + ASSERT_EQ(detail::getBooleanData(flags, 1), false); + ASSERT_EQ(detail::getBooleanData(flags, 2), true); + static_assert( + detail::getBooleanData(flags, 0) == false, + "first boolean member must default to false"); + static_assert( + detail::getBooleanData(flags, 1) == false, + "second boolean member must default to false"); + static_assert( + detail::getBooleanData(flags, 2) == true, + "second boolean member must be initialized to true"); +} + +TEST(BitUtils, third_boolean_can_be_set_to_true) { + uint8_t flags = 0; + + detail::setBooleanData(flags, 2, true); + ASSERT_EQ(detail::getBooleanData(flags, 0), false); + ASSERT_EQ(detail::getBooleanData(flags, 1), false); + ASSERT_EQ(detail::getBooleanData(flags, 2), true); +} + +TEST(BitUtils, setting_boolean_values_does_not_spill_over) { + uint8_t flags = 0; + + detail::setBooleanData(flags, 1, (bool) 7); + + ASSERT_EQ(detail::getBooleanData(flags, 0), false); + ASSERT_EQ(detail::getBooleanData(flags, 1), true); + ASSERT_EQ(detail::getBooleanData(flags, 2), false); +} + +TEST(BitUtils, first_enum_defaults_to_0) { + constexpr uint8_t flags = 0; + + ASSERT_EQ(detail::getEnumData(flags, 0), YGAlignAuto); + static_assert( + detail::getEnumData(flags, 0) == YGAlignAuto, + "first enum member must default to 0"); +} + +TEST(BitUtils, first_enum_can_be_set) { + uint8_t flags = 0; + + detail::setEnumData(flags, 0, YGAlignSpaceBetween); + + ASSERT_EQ(detail::getEnumData(flags, 0), YGAlignSpaceBetween); +} + +TEST(BitUtils, second_enum_defaults_to_0) { + constexpr uint8_t flags = 0; + static constexpr size_t alignOffset = 0; + static constexpr size_t edgeOffset = 3; + + ASSERT_EQ(detail::getEnumData(flags, alignOffset), YGAlignAuto); + ASSERT_EQ(detail::getEnumData(flags, edgeOffset), YGEdgeLeft); + static_assert( + detail::getEnumData(flags, alignOffset) == YGAlignAuto, + "first enum member must default to 0"); + static_assert( + detail::getEnumData(flags, edgeOffset) == YGEdgeLeft, + "second enum member must default to 0"); +} + +TEST(BitUtils, second_enum_can_be_set) { + uint8_t flags = 0; + static constexpr size_t alignOffset = 0; + static constexpr size_t edgeOffset = 3; + + detail::setEnumData(flags, edgeOffset, YGEdgeAll); + + ASSERT_EQ(detail::getEnumData(flags, alignOffset), YGAlignAuto); + ASSERT_EQ(detail::getEnumData(flags, edgeOffset), YGEdgeAll); +} + +TEST(BitUtils, third_enum_defaults_to_0) { + constexpr uint8_t flags = 0; + static constexpr size_t alignOffset = 0; + static constexpr size_t boolOffset = 3; + static constexpr size_t edgesOffset = 4; + + ASSERT_EQ(detail::getEnumData(flags, alignOffset), YGAlignAuto); + ASSERT_EQ(detail::getBooleanData(flags, boolOffset), false); + ASSERT_EQ(detail::getEnumData(flags, edgesOffset), YGEdgeLeft); + static_assert( + detail::getEnumData(flags, alignOffset) == YGAlignAuto, + "first enum member must default to 0"); + static_assert( + detail::getBooleanData(flags, boolOffset) == false, + "middle boolean member must default to false"); + static_assert( + detail::getEnumData(flags, edgesOffset) == YGEdgeLeft, + "last enum member must default to 0"); +} + +TEST(BitUtils, third_enum_can_be_set) { + uint8_t flags = 0; + static constexpr size_t alignOffset = 0; + static constexpr size_t boolOffset = 3; + static constexpr size_t edgesOffset = 4; + + detail::setEnumData(flags, edgesOffset, YGEdgeVertical); + + ASSERT_EQ(detail::getEnumData(flags, alignOffset), YGAlignAuto); + ASSERT_EQ(detail::getBooleanData(flags, boolOffset), false); + ASSERT_EQ(detail::getEnumData(flags, edgesOffset), YGEdgeVertical); +} + +TEST(BitUtils, setting_values_does_not_spill_over) { + uint8_t flags = 0; + static constexpr size_t alignOffset = 0; + static constexpr size_t edgesOffset = 3; + static constexpr size_t boolOffset = 7; + + detail::setEnumData(flags, edgesOffset, (YGEdge) 0xffffff); + + ASSERT_EQ(detail::getEnumData(flags, alignOffset), 0); + ASSERT_EQ(detail::getBooleanData(flags, boolOffset), false); + ASSERT_EQ(detail::getEnumData(flags, edgesOffset), 0xf); +} + +} // namespace yoga +} // namespace facebook diff --git a/tests/BitfieldTest.cpp b/tests/BitfieldTest.cpp deleted file mode 100644 index bb999c64..00000000 --- a/tests/BitfieldTest.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include -#include - -namespace facebook { -namespace yoga { - -TEST(Bitfield, one_boolean_defaults_to_false) { - constexpr auto bf = Bitfield{}; - - ASSERT_EQ(bf.at<0>(), false); - static_assert( - bf.at<0>() == false, "first boolean member must default to false"); -} - -TEST(Bitfield, one_boolean_can_be_initialized_to_true) { - constexpr auto bf = Bitfield{true}; - - ASSERT_EQ(bf.at<0>(), true); - static_assert( - bf.at<0>() == true, "first boolean member must be initialized to true"); -} - -TEST(Bitfield, one_boolean_can_be_set_to_true) { - auto bf = Bitfield{}; - - bf.at<0>() = true; - ASSERT_EQ(bf.at<0>(), true); -} - -TEST(Bitfield, second_boolean_defaults_to_false) { - constexpr auto bf = Bitfield{}; - - ASSERT_EQ(bf.at<1>(), false); - static_assert( - bf.at<1>() == false, "second boolean member must default to false"); -} - -TEST(Bitfield, second_boolean_can_be_initialized_to_true) { - constexpr auto bf = Bitfield{false, true}; - - ASSERT_EQ(bf.at<0>(), false); - ASSERT_EQ(bf.at<1>(), true); - static_assert( - bf.at<0>() == false, "first boolean member must default to false"); - static_assert( - bf.at<1>() == true, "second boolean member must be initialized to true"); -} - -TEST(Bitfield, second_boolean_can_be_set_to_true) { - auto bf = Bitfield{}; - - bf.at<1>() = true; - ASSERT_EQ(bf.at<0>(), false); - ASSERT_EQ(bf.at<1>(), true); -} - -TEST(Bitfield, third_boolean_defaults_to_false) { - constexpr auto bf = Bitfield{}; - - ASSERT_EQ(bf.at<2>(), false); - static_assert( - bf.at<2>() == false, "second boolean member must default to false"); -} - -TEST(Bitfield, third_boolean_can_be_initialized_to_true) { - constexpr auto bf = Bitfield{false, false, true}; - - ASSERT_EQ(bf.at<0>(), false); - ASSERT_EQ(bf.at<1>(), false); - ASSERT_EQ(bf.at<2>(), true); - static_assert( - bf.at<0>() == false, "first boolean member must default to false"); - static_assert( - bf.at<1>() == false, "second boolean member must default to false"); - static_assert( - bf.at<2>() == true, "second boolean member must be initialized to true"); -} - -TEST(Bitfield, third_boolean_can_be_set_to_true) { - auto bf = Bitfield{}; - - bf.at<2>() = true; - ASSERT_EQ(bf.at<0>(), false); - ASSERT_EQ(bf.at<1>(), false); - ASSERT_EQ(bf.at<2>(), true); -} - -TEST(Bitfield, initializing_boolean_values_does_not_spill_over) { - constexpr auto bf = - Bitfield{false, (bool) 7, false}; - - ASSERT_EQ(bf.at<0>(), false); - ASSERT_EQ(bf.at<1>(), true); - ASSERT_EQ(bf.at<2>(), false); - static_assert( - bf.at<0>() == false, "first boolean member must be initialized to false"); - static_assert( - bf.at<1>() == true, "second boolean member must be initialized to true"); - static_assert( - bf.at<2>() == false, "third boolean member must be initialized to false"); -} - -TEST(Bitfield, setting_boolean_values_does_not_spill_over) { - auto bf = Bitfield{}; - - bf.at<1>() = (bool) 7; - - ASSERT_EQ(bf.at<0>(), false); - ASSERT_EQ(bf.at<1>(), true); - ASSERT_EQ(bf.at<2>(), false); -} - -TEST(Bitfield, first_enum_defaults_to_0) { - constexpr auto bf = Bitfield{}; - - ASSERT_EQ(bf.at<0>(), YGAlignAuto); - static_assert( - bf.at<0>() == YGAlignAuto, "first enum member must default to 0"); -} - -TEST(Bitfield, first_enum_can_be_initialized) { - constexpr auto bf = Bitfield{YGAlignFlexEnd}; - - ASSERT_EQ(bf.at<0>(), YGAlignFlexEnd); - static_assert( - bf.at<0>() == YGAlignFlexEnd, - "first enum member must be initialized to YGAlignFlexEnd"); -} - -TEST(Bitfield, first_enum_can_be_set) { - auto bf = Bitfield{}; - - bf.at<0>() = YGAlignSpaceBetween; - - ASSERT_EQ(bf.at<0>(), YGAlignSpaceBetween); -} - -TEST(Bitfield, second_enum_defaults_to_0) { - constexpr auto bf = Bitfield{}; - - ASSERT_EQ(bf.at<0>(), YGAlignAuto); - ASSERT_EQ(bf.at<1>(), YGEdgeLeft); - static_assert( - bf.at<0>() == YGAlignAuto, "first enum member must default to 0"); - static_assert( - bf.at<1>() == YGEdgeLeft, "second enum member must default to 0"); -} - -TEST(Bitfield, second_enum_can_be_initialized) { - constexpr auto bf = - Bitfield{YGAlignAuto, YGEdgeAll}; - - ASSERT_EQ(bf.at<0>(), YGAlignAuto); - ASSERT_EQ(bf.at<1>(), YGEdgeAll); - static_assert( - bf.at<0>() == YGAlignAuto, "first enum member must default to 0"); - static_assert( - bf.at<1>() == YGEdgeAll, - "second enum member must be initialized to YGEdgeAll"); -} - -TEST(Bitfield, second_enum_can_be_set) { - auto bf = Bitfield{}; - - bf.at<1>() = YGEdgeAll; - - ASSERT_EQ(bf.at<0>(), YGAlignAuto); - ASSERT_EQ(bf.at<1>(), YGEdgeAll); -} - -TEST(Bitfield, third_enum_defaults_to_0) { - constexpr auto bf = Bitfield{}; - - ASSERT_EQ(bf.at<0>(), YGAlignAuto); - ASSERT_EQ(bf.at<1>(), false); - ASSERT_EQ(bf.at<2>(), YGEdgeLeft); - static_assert( - bf.at<0>() == YGAlignAuto, "first enum member must default to 0"); - static_assert( - bf.at<1>() == false, "middle boolean member must default to false"); - static_assert(bf.at<2>() == YGEdgeLeft, "last enum member must default to 0"); -} - -TEST(Bitfield, third_enum_can_be_initialized) { - constexpr auto bf = Bitfield{ - YGAlignAuto, false, YGEdgeVertical}; - - ASSERT_EQ(bf.at<0>(), YGAlignAuto); - ASSERT_EQ(bf.at<1>(), false); - ASSERT_EQ(bf.at<2>(), YGEdgeVertical); - static_assert( - bf.at<0>() == YGAlignAuto, "first enum member must default to 0"); - static_assert( - bf.at<1>() == false, "middle boolean member must default to false"); - static_assert( - bf.at<2>() == YGEdgeVertical, - "second enum member must be initialized to YGEdgeVertical"); -} - -TEST(Bitfield, third_enum_can_be_set) { - auto bf = Bitfield{}; - - bf.at<2>() = YGEdgeVertical; - - ASSERT_EQ(bf.at<0>(), YGAlignAuto); - ASSERT_EQ(bf.at<1>(), false); - ASSERT_EQ(bf.at<2>(), YGEdgeVertical); -} - -TEST(Bitfield, initializing_values_does_not_spill_over) { - constexpr auto bf = Bitfield{ - (YGAlign) 0, (YGEdge) 0xffffff, false}; - - ASSERT_EQ(bf.at<0>(), (YGAlign) 0); - ASSERT_EQ(bf.at<1>(), 0xf); - ASSERT_EQ(bf.at<2>(), false); - static_assert(bf.at<0>() == 0, "first enum member must be initialized to 0"); - static_assert( - bf.at<1>() == 0xf, "second member must be initialized to YGEdgeVertical"); - static_assert( - bf.at<2>() == false, "boolean member must be initialized to false"); -} - -TEST(Bitfield, setting_values_does_not_spill_over) { - auto bf = Bitfield{}; - - bf.at<1>() = (YGEdge) 0xffffff; - - ASSERT_EQ(bf.at<0>(), 0); - ASSERT_EQ(bf.at<1>(), 0xf); - ASSERT_EQ(bf.at<2>(), false); -} - -} // namespace yoga -} // namespace facebook diff --git a/tests/EventsTest.cpp b/tests/EventsTest.cpp index cf887b2d..e8300846 100644 --- a/tests/EventsTest.cpp +++ b/tests/EventsTest.cpp @@ -303,8 +303,8 @@ EventArgs createArgs( }; EventArgs args = createArgs(node, data); - args.eventTestDataPtr = {new EventTestData{eventTestData}, - deleteEventTestData}; + args.eventTestDataPtr = { + new EventTestData{eventTestData}, deleteEventTestData}; return args; } diff --git a/tests/YGComputedMarginTest.cpp b/tests/YGComputedMarginTest.cpp index b74e4174..fedfd561 100644 --- a/tests/YGComputedMarginTest.cpp +++ b/tests/YGComputedMarginTest.cpp @@ -29,12 +29,13 @@ TEST(YogaTest, computed_layout_margin) { } TEST(YogaTest, margin_side_overrides_horizontal_and_vertical) { - const std::array edges = {{YGEdgeTop, - YGEdgeBottom, - YGEdgeStart, - YGEdgeEnd, - YGEdgeLeft, - YGEdgeRight}}; + const std::array edges = { + {YGEdgeTop, + YGEdgeBottom, + YGEdgeStart, + YGEdgeEnd, + YGEdgeLeft, + YGEdgeRight}}; for (float edgeValue = 0; edgeValue < 2; ++edgeValue) { for (const auto& edge : edges) { @@ -58,12 +59,13 @@ TEST(YogaTest, margin_side_overrides_horizontal_and_vertical) { } TEST(YogaTest, margin_side_overrides_all) { - const std::array edges = {{YGEdgeTop, - YGEdgeBottom, - YGEdgeStart, - YGEdgeEnd, - YGEdgeLeft, - YGEdgeRight}}; + const std::array edges = { + {YGEdgeTop, + YGEdgeBottom, + YGEdgeStart, + YGEdgeEnd, + YGEdgeLeft, + YGEdgeRight}}; for (float edgeValue = 0; edgeValue < 2; ++edgeValue) { for (const auto& edge : edges) { diff --git a/tests/YGComputedPaddingTest.cpp b/tests/YGComputedPaddingTest.cpp index 677ed3a6..c3aabab7 100644 --- a/tests/YGComputedPaddingTest.cpp +++ b/tests/YGComputedPaddingTest.cpp @@ -29,12 +29,13 @@ TEST(YogaTest, computed_layout_padding) { } TEST(YogaTest, padding_side_overrides_horizontal_and_vertical) { - const std::array edges = {{YGEdgeTop, - YGEdgeBottom, - YGEdgeStart, - YGEdgeEnd, - YGEdgeLeft, - YGEdgeRight}}; + const std::array edges = { + {YGEdgeTop, + YGEdgeBottom, + YGEdgeStart, + YGEdgeEnd, + YGEdgeLeft, + YGEdgeRight}}; for (float edgeValue = 0; edgeValue < 2; ++edgeValue) { for (const auto& edge : edges) { @@ -58,12 +59,13 @@ TEST(YogaTest, padding_side_overrides_horizontal_and_vertical) { } TEST(YogaTest, padding_side_overrides_all) { - const std::array edges = {{YGEdgeTop, - YGEdgeBottom, - YGEdgeStart, - YGEdgeEnd, - YGEdgeLeft, - YGEdgeRight}}; + const std::array edges = { + {YGEdgeTop, + YGEdgeBottom, + YGEdgeStart, + YGEdgeEnd, + YGEdgeLeft, + YGEdgeRight}}; for (float edgeValue = 0; edgeValue < 2; ++edgeValue) { for (const auto& edge : edges) { diff --git a/tests/YGDefaultValuesTest.cpp b/tests/YGDefaultValuesTest.cpp index 249a7605..a622c1b3 100644 --- a/tests/YGDefaultValuesTest.cpp +++ b/tests/YGDefaultValuesTest.cpp @@ -20,7 +20,7 @@ TEST(YogaTest, assert_default_values) { ASSERT_EQ(YGAlignFlexStart, YGNodeStyleGetAlignContent(root)); ASSERT_EQ(YGAlignStretch, YGNodeStyleGetAlignItems(root)); ASSERT_EQ(YGAlignAuto, YGNodeStyleGetAlignSelf(root)); - ASSERT_EQ(YGPositionTypeRelative, YGNodeStyleGetPositionType(root)); + ASSERT_EQ(YGPositionTypeStatic, YGNodeStyleGetPositionType(root)); ASSERT_EQ(YGWrapNoWrap, YGNodeStyleGetFlexWrap(root)); ASSERT_EQ(YGOverflowVisible, YGNodeStyleGetOverflow(root)); ASSERT_FLOAT_EQ(0, YGNodeStyleGetFlexGrow(root)); diff --git a/tests/YGDisplayTest.cpp b/tests/YGDisplayTest.cpp index ebd2bcd5..edc53358 100644 --- a/tests/YGDisplayTest.cpp +++ b/tests/YGDisplayTest.cpp @@ -1,9 +1,10 @@ /* * Copyright (c) Facebook, Inc. and its affiliates. * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ + // @Generated by gentest/gentest.rb from gentest/fixtures/YGDisplayTest.html #include @@ -327,3 +328,45 @@ TEST(YogaTest, display_none_with_position) { YGConfigFree(config); } + +TEST(YogaTest, display_none_with_position_absolute) { + const YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root, 100); + YGNodeStyleSetHeight(root, 100); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute); + YGNodeStyleSetWidth(root_child0, 100); + YGNodeStyleSetHeight(root_child0, 100); + YGNodeStyleSetDisplay(root_child0, YGDisplayNone); + YGNodeInsertChild(root, root_child0, 0); + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} diff --git a/tests/YGFlexTest.cpp b/tests/YGFlexTest.cpp index 21c7578d..ab6dec76 100644 --- a/tests/YGFlexTest.cpp +++ b/tests/YGFlexTest.cpp @@ -605,3 +605,121 @@ TEST(YogaTest, flex_grow_less_than_factor_one) { YGConfigFree(config); } + +TEST(YogaTest, flex_shrink_min_width) { + const YGConfigRef config = YGConfigNew(); + YGConfigSetUseWebDefaults(config, true); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetWidth(root, 500); + YGNodeStyleSetHeight(root, 500); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeStyleSetWidth(root_child0, 100); + YGNodeStyleSetMinWidth(root_child0, 301); + YGNodeStyleSetHeight(root_child0, 100); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child1, YGFlexDirectionRow); + YGNodeStyleSetWidth(root_child1, 100); + YGNodeStyleSetMinWidth(root_child1, 25); + YGNodeStyleSetHeight(root_child1, 100); + YGNodeInsertChild(root, root_child1, 1); + + const YGNodeRef root_child2 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child2, YGFlexDirectionRow); + YGNodeStyleSetWidth(root_child2, 100); + YGNodeStyleSetHeight(root_child2, 100); + YGNodeInsertChild(root, root_child2, 2); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(301, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(301, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1)); + + ASSERT_FLOAT_EQ(401, YGNodeLayoutGetLeft(root_child2)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2)); + ASSERT_FLOAT_EQ(99, YGNodeLayoutGetWidth(root_child2)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} + +TEST(YogaTest, flex_shrink_flex_grow_min_width) { + const YGConfigRef config = YGConfigNew(); + YGConfigSetUseWebDefaults(config, true); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetWidth(root, 500); + YGNodeStyleSetHeight(root, 500); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeStyleSetFlexGrow(root_child0, 0); + YGNodeStyleSetFlexShrink(root_child0, 1); + YGNodeStyleSetWidth(root_child0, 100); + YGNodeStyleSetMinWidth(root_child0, 301); + YGNodeStyleSetHeight(root_child0, 100); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child1, YGFlexDirectionRow); + YGNodeStyleSetFlexGrow(root_child1, 1); + YGNodeStyleSetFlexShrink(root_child1, 1); + YGNodeStyleSetWidth(root_child1, 100); + YGNodeStyleSetMinWidth(root_child1, 25); + YGNodeStyleSetHeight(root_child1, 100); + YGNodeInsertChild(root, root_child1, 1); + + const YGNodeRef root_child2 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child2, YGFlexDirectionRow); + YGNodeStyleSetWidth(root_child2, 100); + YGNodeStyleSetHeight(root_child2, 100); + YGNodeStyleSetFlexShrink(root_child2, 1); + YGNodeStyleSetFlexGrow(root_child2, 1); + YGNodeInsertChild(root, root_child2, 2); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(301, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(301, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1)); + + ASSERT_FLOAT_EQ(401, YGNodeLayoutGetLeft(root_child2)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2)); + ASSERT_FLOAT_EQ(99, YGNodeLayoutGetWidth(root_child2)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} diff --git a/tests/YGLoggerTest.cpp b/tests/YGLoggerTest.cpp index 5c319ba6..f9d8002c 100644 --- a/tests/YGLoggerTest.cpp +++ b/tests/YGLoggerTest.cpp @@ -73,8 +73,7 @@ TEST(YogaTest, logger_default_node_should_print_no_style_info) { YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR); YGNodePrint( root, - (YGPrintOptions)( - YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); + (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); YGConfigSetLogger(config, NULL); YGNodeFree(root); @@ -98,8 +97,7 @@ TEST(YogaTest, logger_node_with_percentage_absolute_position_and_margin) { YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR); YGNodePrint( root, - (YGPrintOptions)( - YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); + (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); YGConfigSetLogger(config, NULL); YGNodeFree(root); @@ -122,8 +120,7 @@ TEST(YogaTest, logger_node_with_children_should_print_indented) { YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR); YGNodePrint( root, - (YGPrintOptions)( - YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); + (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); YGConfigSetLogger(config, NULL); YGNodeFreeRecursive(root); diff --git a/tests/YGMeasureTest.cpp b/tests/YGMeasureTest.cpp index 38c28059..e47607d4 100644 --- a/tests/YGMeasureTest.cpp +++ b/tests/YGMeasureTest.cpp @@ -580,7 +580,7 @@ TEST(YogaDeathTest, cannot_add_child_to_node_with_measure_func) { root->setMeasureFunc(_measure); const YGNodeRef root_child0 = YGNodeNew(); - ASSERT_DEATH(YGNodeInsertChild(root, root_child0, 0), "Cannot add child.*"); + ASSERT_THROW(YGNodeInsertChild(root, root_child0, 0), std::logic_error); YGNodeFree(root_child0); YGNodeFreeRecursive(root); } @@ -589,7 +589,7 @@ TEST(YogaDeathTest, cannot_add_nonnull_measure_func_to_non_leaf_node) { const YGNodeRef root = YGNodeNew(); const YGNodeRef root_child0 = YGNodeNew(); YGNodeInsertChild(root, root_child0, 0); - ASSERT_DEATH(root->setMeasureFunc(_measure), "Cannot set measure function.*"); + ASSERT_THROW(root->setMeasureFunc(_measure), std::logic_error); YGNodeFreeRecursive(root); } @@ -654,6 +654,19 @@ static YGSize _measure_90_10( }; } +static YGSize _measure_100_100( + YGNodeRef node, + float width, + YGMeasureMode widthMode, + float height, + YGMeasureMode heightMode) { + + return YGSize{ + .width = 100, + .height = 100, + }; +} + TEST(YogaTest, percent_with_text_node) { const YGConfigRef config = YGConfigNew(); @@ -686,9 +699,211 @@ TEST(YogaTest, percent_with_text_node) { ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0)); ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1)); - ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1)); ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1)); - ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1)); + ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} + +TEST(YogaTest, percent_margin_with_measure_func) { + const YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetWidth(root, 500); + YGNodeStyleSetHeight(root, 500); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child0, 100); + YGNodeStyleSetHeight(root_child0, 100); + YGNodeStyleSetMargin(root_child0, YGEdgeTop, 0); + root_child0->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child1, 100); + YGNodeStyleSetHeight(root_child1, 100); + YGNodeStyleSetMargin(root_child1, YGEdgeTop, 100); + root_child1->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child1, 1); + + const YGNodeRef root_child2 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child2, 100); + YGNodeStyleSetHeight(root_child2, 100); + YGNodeStyleSetMarginPercent(root_child2, YGEdgeTop, 10); + root_child2->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child2, 2); + + const YGNodeRef root_child3 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child3, 100); + YGNodeStyleSetHeight(root_child3, 100); + YGNodeStyleSetMarginPercent(root_child3, YGEdgeTop, 20); + root_child3->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child3, 3); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1)); + + ASSERT_FLOAT_EQ(200, YGNodeLayoutGetLeft(root_child2)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2)); + + ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child3)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child3)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child3)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child3)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} + +TEST(YogaTest, percent_padding_with_measure_func) { + const YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetAlignItems(root, YGAlignFlexStart); + YGNodeStyleSetAlignContent(root, YGAlignFlexStart); + YGNodeStyleSetWidth(root, 500); + YGNodeStyleSetHeight(root, 500); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child0, 100); + YGNodeStyleSetHeight(root_child0, 100); + YGNodeStyleSetPadding(root_child0, YGEdgeTop, 0); + root_child0->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child1, 100); + YGNodeStyleSetHeight(root_child1, 100); + YGNodeStyleSetPadding(root_child1, YGEdgeTop, 100); + root_child1->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child1, 1); + + const YGNodeRef root_child2 = YGNodeNewWithConfig(config); + YGNodeStyleSetPaddingPercent(root_child2, YGEdgeTop, 10); + root_child2->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child2, 2); + + const YGNodeRef root_child3 = YGNodeNewWithConfig(config); + YGNodeStyleSetPaddingPercent(root_child3, YGEdgeTop, 20); + root_child3->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child3, 3); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1)); + + ASSERT_FLOAT_EQ(200, YGNodeLayoutGetLeft(root_child2)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2)); + ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child2)); + + ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child3)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child3)); + ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child3)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} + +TEST(YogaTest, percent_padding_and_percent_margin_with_measure_func) { + const YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetAlignItems(root, YGAlignFlexStart); + YGNodeStyleSetAlignContent(root, YGAlignFlexStart); + YGNodeStyleSetWidth(root, 500); + YGNodeStyleSetHeight(root, 500); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child0, 100); + YGNodeStyleSetHeight(root_child0, 100); + YGNodeStyleSetPadding(root_child0, YGEdgeTop, 0); + root_child0->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child1, 100); + YGNodeStyleSetHeight(root_child1, 100); + YGNodeStyleSetPadding(root_child1, YGEdgeTop, 100); + root_child1->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child1, 1); + + const YGNodeRef root_child2 = YGNodeNewWithConfig(config); + YGNodeStyleSetPaddingPercent(root_child2, YGEdgeTop, 10); + YGNodeStyleSetMarginPercent(root_child2, YGEdgeTop, 10); + root_child2->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child2, 2); + + const YGNodeRef root_child3 = YGNodeNewWithConfig(config); + YGNodeStyleSetPaddingPercent(root_child3, YGEdgeTop, 20); + YGNodeStyleSetMarginPercent(root_child3, YGEdgeTop, 20); + root_child3->setMeasureFunc(_measure_100_100); + YGNodeInsertChild(root, root_child3, 3); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1)); + + ASSERT_FLOAT_EQ(200, YGNodeLayoutGetLeft(root_child2)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2)); + ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child2)); + + ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child3)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child3)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child3)); + ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child3)); YGNodeFreeRecursive(root); diff --git a/tests/YGStyleAccessorsTest.cpp b/tests/YGStyleAccessorsTest.cpp index 541f354f..d0bda431 100644 --- a/tests/YGStyleAccessorsTest.cpp +++ b/tests/YGStyleAccessorsTest.cpp @@ -132,9 +132,10 @@ ACCESSOR_TEST( ACCESSOR_TEST( positionType, - YGPositionTypeRelative, + YGPositionTypeStatic, YGPositionTypeAbsolute, - YGPositionTypeRelative) + YGPositionTypeRelative, + YGPositionTypeStatic) ACCESSOR_TEST( flexWrap, diff --git a/tests/YGTreeMutationTest.cpp b/tests/YGTreeMutationTest.cpp index bf07f39e..26f0b900 100644 --- a/tests/YGTreeMutationTest.cpp +++ b/tests/YGTreeMutationTest.cpp @@ -29,8 +29,8 @@ TEST(YogaTest, set_children_adds_children_to_parent) { const std::vector expectedChildren = {root_child0, root_child1}; ASSERT_EQ(children, expectedChildren); - const std::vector owners = {YGNodeGetOwner(root_child0), - YGNodeGetOwner(root_child1)}; + const std::vector owners = { + YGNodeGetOwner(root_child0), YGNodeGetOwner(root_child1)}; const std::vector expectedOwners = {root, root}; ASSERT_EQ(owners, expectedOwners); @@ -49,8 +49,8 @@ TEST(YogaTest, set_children_to_empty_removes_old_children) { const std::vector expectedChildren = {}; ASSERT_EQ(children, expectedChildren); - const std::vector owners = {YGNodeGetOwner(root_child0), - YGNodeGetOwner(root_child1)}; + const std::vector owners = { + YGNodeGetOwner(root_child0), YGNodeGetOwner(root_child1)}; const std::vector expectedOwners = {nullptr, nullptr}; ASSERT_EQ(owners, expectedOwners); @@ -73,8 +73,8 @@ TEST(YogaTest, set_children_replaces_non_common_children) { const std::vector expectedChildren = {root_child2, root_child3}; ASSERT_EQ(children, expectedChildren); - const std::vector owners = {YGNodeGetOwner(root_child0), - YGNodeGetOwner(root_child1)}; + const std::vector owners = { + YGNodeGetOwner(root_child0), YGNodeGetOwner(root_child1)}; const std::vector expectedOwners = {nullptr, nullptr}; ASSERT_EQ(owners, expectedOwners); @@ -100,10 +100,11 @@ TEST(YogaTest, set_children_keeps_and_reorders_common_children) { root_child2, root_child1, root_child3}; ASSERT_EQ(children, expectedChildren); - const std::vector owners = {YGNodeGetOwner(root_child0), - YGNodeGetOwner(root_child1), - YGNodeGetOwner(root_child2), - YGNodeGetOwner(root_child3)}; + const std::vector owners = { + YGNodeGetOwner(root_child0), + YGNodeGetOwner(root_child1), + YGNodeGetOwner(root_child2), + YGNodeGetOwner(root_child3)}; const std::vector expectedOwners = {nullptr, root, root, root}; ASSERT_EQ(owners, expectedOwners); diff --git a/testutil/BUCK b/testutil/BUCK index 56ee97fe..1a66f91b 100644 --- a/testutil/BUCK +++ b/testutil/BUCK @@ -11,6 +11,21 @@ yoga_cxx_library( deps = [yoga_dep(":yoga")], ) +yoga_cxx_library( + name = "testutil-jni", + srcs = ["src/main/cpp/testutil/testutil.cpp"], + header_namespace = "", + exported_headers = subdir_glob([("src/main/cpp/include", "yoga/testutil/testutil.h")]), + compiler_flags = LIBRARY_COMPILER_FLAGS, + platforms = ANDROID, + soname = "libyoga_testutil.$(ext)", + visibility = ["PUBLIC"], + deps = [ + yoga_dep("java:jni"), + yoga_dep(":yoga"), + ], +) + yoga_java_library( name = "java", srcs = ["src/main/java/com/facebook/yoga/TestUtil.java"], @@ -32,7 +47,7 @@ yoga_cxx_library( soname = "libyoga_testutil_jni.$(ext)", visibility = ["PUBLIC"], deps = [ - ":testutil", + ":testutil-jni", FBJNI_TARGET, ], ) diff --git a/testutil/build.gradle b/testutil/build.gradle index 647d66d3..d36e8673 100644 --- a/testutil/build.gradle +++ b/testutil/build.gradle @@ -29,11 +29,10 @@ android { externalNativeBuild { cmake { path 'src/main/cpp/CMakeLists.txt' - version '3.6.0-rc2' } } dependencies { - implementation 'com.facebook.soloader:soloader:0.5.1' + implementation 'com.facebook.soloader:soloader:0.10.1' } } diff --git a/tools/build_defs/oss/yoga_defs.bzl b/tools/build_defs/oss/yoga_defs.bzl index 4c50e984..2c108c20 100644 --- a/tools/build_defs/oss/yoga_defs.bzl +++ b/tools/build_defs/oss/yoga_defs.bzl @@ -14,7 +14,7 @@ JSR_305_TARGET = "//lib/jsr-305:jsr-305" JUNIT_TARGET = "//lib/junit:junit" -PROGRUARD_ANNOTATIONS_TARGET = "//java/proguard-annotations/src/main/java/com/facebook/proguard/annotations:annotations" +PROGUARD_ANNOTATIONS_TARGET = "//java/proguard-annotations/src/main/java/com/facebook/proguard/annotations:annotations" SOLOADER_TARGET = "//lib/soloader:soloader" @@ -202,6 +202,9 @@ def yoga_prebuilt_cxx_library(*args, **kwargs): def yoga_prebuilt_jar(*args, **kwargs): native.prebuilt_jar(*args, **kwargs) +def yoga_prebuilt_aar(*args, **kwargs): + native.android_prebuilt_aar(*args, **kwargs) + def is_apple_platform(): return True diff --git a/website/.flowconfig b/website/.flowconfig index 1fed4453..6bd402f8 100644 --- a/website/.flowconfig +++ b/website/.flowconfig @@ -7,5 +7,9 @@ [lints] [options] +types_first=false [strict] + +[version] +^0.140.0 diff --git a/website/package.json b/website/package.json index 442b13f6..53445418 100644 --- a/website/package.json +++ b/website/package.json @@ -32,6 +32,6 @@ "develop": "gatsby develop" }, "devDependencies": { - "prettier": "1.17.0" + "prettier": "1.19.1" } } diff --git a/website/src/components/Playground/src/CodeComponentKit.js b/website/src/components/Playground/src/CodeComponentKit.js index 74cc2db2..00111508 100644 --- a/website/src/components/Playground/src/CodeComponentKit.js +++ b/website/src/components/Playground/src/CodeComponentKit.js @@ -73,9 +73,9 @@ function keyLookup(key: string): string { function getValue(value) { if (typeof value === 'string' && /%$/.test(value)) { - return `CKRelativeDimension::Percent(${parseFloat(value)})`; + return `RCRelativeDimension::Percent(${parseFloat(value)})`; } else if (value === 'auto') { - return 'CKRelativeDimension::Auto()'; + return 'RCRelativeDimension::Auto()'; } else { return String(parseFloat(value)); } diff --git a/website/src/components/Playground/src/CodeLitho.js b/website/src/components/Playground/src/CodeLitho.js index 0e9f782b..cc96c840 100644 --- a/website/src/components/Playground/src/CodeLitho.js +++ b/website/src/components/Playground/src/CodeLitho.js @@ -24,7 +24,7 @@ function getEnum(yogaEnum: string, value: string | number): string { position: 'Position', flexWrap: 'Wrap', positionType: 'PositionType', - direction: 'Driection', + direction: 'Direction', }; if (!enumLookup[yogaEnum]) { @@ -47,8 +47,8 @@ function dipOrPercent(value) { return value === 'auto' ? 'Auto' : typeof value === 'string' && /%$/.test(value) - ? 'Percent' - : 'Dip'; + ? 'Percent' + : 'Dip'; } function getValue(value) { diff --git a/website/src/components/Playground/src/Editor.css b/website/src/components/Playground/src/Editor.css index f53451f7..57954947 100644 --- a/website/src/components/Playground/src/Editor.css +++ b/website/src/components/Playground/src/Editor.css @@ -51,7 +51,10 @@ } .Editor .ant-tabs-tabpane { - overflow-y: scroll; + overflow-y: auto; + min-height: 320px; + height: 100%; + max-height: 25vh; padding: 15px; } diff --git a/website/src/components/Playground/src/Editor.js b/website/src/components/Playground/src/Editor.js index f7076865..4b6b6593 100644 --- a/website/src/components/Playground/src/Editor.js +++ b/website/src/components/Playground/src/Editor.js @@ -196,7 +196,7 @@ export default class Editor extends Component { onChange={this.props.onChangeLayout} /> - +

Width × Height diff --git a/website/src/components/Playground/src/URLShortener.js b/website/src/components/Playground/src/URLShortener.js index 77130a0f..27049801 100644 --- a/website/src/components/Playground/src/URLShortener.js +++ b/website/src/components/Playground/src/URLShortener.js @@ -52,9 +52,7 @@ export default class URLShortener extends Component<{}, State> { } fetch( - `https://cors-anywhere.herokuapp.com/tinyurl.com/api-create.php?url=${ - window.location.href - }`, + `https://cors-anywhere.herokuapp.com/tinyurl.com/api-create.php?url=${window.location.href}`, ) .then(res => res.text()) .then(shortURL => this.setState({shortURL, loading: false})) diff --git a/website/src/pages/docs/index.js b/website/src/pages/docs/index.js index 66e0a363..96dee1ae 100644 --- a/website/src/pages/docs/index.js +++ b/website/src/pages/docs/index.js @@ -49,17 +49,16 @@ export default ({data}) => ( ({node}) => node.fileAbsolutePath.indexOf(`/${category}/`) > -1, ) - .map( - ({node}) => - node.frontmatter.redirect ? ( - - {node.frontmatter.title} - - ) : ( - - {node.frontmatter.title} - - ), + .map(({node}) => + node.frontmatter.redirect ? ( + + {node.frontmatter.title} + + ) : ( + + {node.frontmatter.title} + + ), )} ), diff --git a/website/yarn.lock b/website/yarn.lock index 509efeca..fa5a26e2 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -6978,10 +6978,10 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier@1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.0.tgz#53b303676eed22cc14a9f0cec09b477b3026c008" - integrity sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw== +prettier@1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== pretty-bytes@^4.0.2: version "4.0.2" diff --git a/yoga/BitUtils.h b/yoga/BitUtils.h new file mode 100644 index 00000000..2161effc --- /dev/null +++ b/yoga/BitUtils.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include "YGEnums.h" + +namespace facebook { +namespace yoga { + +namespace detail { + +constexpr size_t log2ceilFn(size_t n) { + return n < 1 ? 0 : (1 + log2ceilFn(n / 2)); +} + +constexpr int mask(size_t bitWidth, size_t index) { + return ((1 << bitWidth) - 1) << index; +} + +// The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL +template +constexpr size_t bitWidthFn() { + static_assert( + enums::count() > 0, "Enums must have at least one entries"); + return log2ceilFn(enums::count() - 1); +} + +template +constexpr Enum getEnumData(int flags, size_t index) { + return static_cast((flags & mask(bitWidthFn(), index)) >> index); +} + +template +void setEnumData(uint32_t& flags, size_t index, int newValue) { + flags = (flags & ~mask(bitWidthFn(), index)) | + ((newValue << index) & (mask(bitWidthFn(), index))); +} + +template +void setEnumData(uint8_t& flags, size_t index, int newValue) { + flags = (flags & ~static_cast(mask(bitWidthFn(), index))) | + ((newValue << index) & + (static_cast(mask(bitWidthFn(), index)))); +} + +constexpr bool getBooleanData(int flags, size_t index) { + return (flags >> index) & 1; +} + +inline void setBooleanData(uint8_t& flags, size_t index, bool value) { + if (value) { + flags |= 1 << index; + } else { + flags &= ~(1 << index); + } +} + +} // namespace detail +} // namespace yoga +} // namespace facebook diff --git a/yoga/Bitfield.h b/yoga/Bitfield.h deleted file mode 100644 index 02645961..00000000 --- a/yoga/Bitfield.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include - -namespace facebook { -namespace yoga { - -namespace detail { - -constexpr size_t log2ceil(size_t n) { - return n < 1 ? 0 : (1 + log2ceil(n / 2)); -} - -// The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL -template -constexpr size_t bitWidth() { - static_assert( - enums::count() > 0, "Enums must have at least one entries"); - return log2ceil(enums::count() - 1); -} - -// Number of bits needed for a boolean -template <> -constexpr size_t bitWidth() { - return 1; -} - -template -struct BitTraits {}; - -template -struct BitTraits { - // Base cases - static constexpr size_t width(size_t) { return 0; } - static constexpr size_t shift(size_t) { return 0; } -}; - -template -struct BitTraits { - using Rest = BitTraits; - - static constexpr size_t width(size_t idx) { - return idx == 0 ? bitWidth() : Rest::width(idx - 1); - } - - static constexpr size_t shift(size_t idx) { - return idx == 0 ? Rest::width(0) + Rest::shift(0) : Rest::shift(idx - 1); - } - - static constexpr U mask(size_t idx) { - return ((U{1} << width(idx)) - 1) << shift(idx); - } -}; - -template -struct IndexedType { - using Type = typename IndexedType::Type; -}; - -template -struct IndexedType<0, T, Ts...> { - using Type = T; -}; - -} // namespace detail - -template -class Bitfield { - static_assert( - std::is_integral::value, - "Bitfield needs an integral storage type"); - static_assert( - std::is_unsigned::value, - "Bitfield needs an unsigned storage type"); - static_assert(sizeof...(Fields) > 0, "Bitfield needs at least one member"); - - using BitTraits = detail::BitTraits; - -#if !defined(_MSC_VER) || _MSC_VER > 1914 - static_assert( - BitTraits::shift(0) + BitTraits::width(0) <= - std::numeric_limits::digits, - "Specified storage type is too narrow to hold all types"); -#endif - - template - using TypeAt = typename detail::IndexedType::Type; - - template - static constexpr Storage initStorage(Value value, Values... values) { - return ((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx)) | - initStorage(values...); - } - - template - static constexpr Storage initStorage() { - return Storage{0}; - } - - Storage storage_ = 0; - -public: - template - class Ref { - Bitfield& bitfield_; - - public: - Ref(Bitfield& bitfield) : bitfield_(bitfield) {} - Ref& operator=(TypeAt value) { - bitfield_.storage_ = (bitfield_.storage_ & ~BitTraits::mask(Idx)) | - ((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx)); - return *this; - } - operator TypeAt() const { - return const_cast(bitfield_).at(); - } - }; - - constexpr Bitfield() = default; - constexpr Bitfield(Fields... values) : storage_{initStorage<0>(values...)} {} - - template - constexpr TypeAt at() const { - return static_cast>( - (storage_ & BitTraits::mask(Idx)) >> BitTraits::shift(Idx)); - } - - template - Ref at() { - return {*this}; - } -}; - -} // namespace yoga -} // namespace facebook diff --git a/yoga/CompactValue.h b/yoga/CompactValue.h index be933a16..f398668e 100644 --- a/yoga/CompactValue.h +++ b/yoga/CompactValue.h @@ -125,8 +125,8 @@ public: data.repr &= ~PERCENT_BIT; data.repr += BIAS; - return YGValue{data.value, - payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint}; + return YGValue{ + data.value, payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint}; } bool isUndefined() const noexcept { diff --git a/yoga/Utils.cpp b/yoga/Utils.cpp index 761f3515..eaa74b06 100644 --- a/yoga/Utils.cpp +++ b/yoga/Utils.cpp @@ -6,6 +6,7 @@ */ #include "Utils.h" +#include using namespace facebook; @@ -52,6 +53,13 @@ bool YGFloatsEqual(const float a, const float b) { return yoga::isUndefined(a) && yoga::isUndefined(b); } +bool YGDoubleEqual(const double a, const double b) { + if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { + return fabs(a - b) < 0.0001; + } + return yoga::isUndefined(a) && yoga::isUndefined(b); +} + float YGFloatSanitize(const float val) { return yoga::isUndefined(val) ? 0 : val; } @@ -65,3 +73,7 @@ YGFloatOptional YGFloatOptionalMax(YGFloatOptional op1, YGFloatOptional op2) { } return op1.isUndefined() ? op2 : op1; } + +void throwLogicalErrorWithMessage(const char* message) { + throw std::logic_error(message); +} diff --git a/yoga/Utils.h b/yoga/Utils.h index bce8dfca..57e1d45d 100644 --- a/yoga/Utils.h +++ b/yoga/Utils.h @@ -64,6 +64,8 @@ inline bool YGValueEqual( // difference between two floats is less than 0.0001f or both are undefined. bool YGFloatsEqual(const float a, const float b); +bool YGDoubleEqual(const double a, const double b); + float YGFloatMax(const float a, const float b); YGFloatOptional YGFloatOptionalMax( @@ -141,3 +143,5 @@ inline YGFloatOptional YGResolveValueMargin( const float ownerSize) { return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize); } + +void throwLogicalErrorWithMessage(const char* message); diff --git a/yoga/YGEnums.cpp b/yoga/YGEnums.cpp index 3c130129..c01d3d94 100644 --- a/yoga/YGEnums.cpp +++ b/yoga/YGEnums.cpp @@ -179,6 +179,8 @@ const char* YGOverflowToString(const YGOverflow value) { const char* YGPositionTypeToString(const YGPositionType value) { switch (value) { + case YGPositionTypeStatic: + return "static"; case YGPositionTypeRelative: return "relative"; case YGPositionTypeAbsolute: diff --git a/yoga/YGEnums.h b/yoga/YGEnums.h index 4241281d..3dc458dc 100644 --- a/yoga/YGEnums.h +++ b/yoga/YGEnums.h @@ -128,7 +128,11 @@ YG_ENUM_SEQ_DECL( YGOverflowHidden, YGOverflowScroll) -YG_ENUM_SEQ_DECL(YGPositionType, YGPositionTypeRelative, YGPositionTypeAbsolute) +YG_ENUM_SEQ_DECL( + YGPositionType, + YGPositionTypeStatic, + YGPositionTypeRelative, + YGPositionTypeAbsolute) YG_ENUM_DECL( YGPrintOptions, diff --git a/yoga/YGLayout.h b/yoga/YGLayout.h index 658a31f2..b7604d8e 100644 --- a/yoga/YGLayout.h +++ b/yoga/YGLayout.h @@ -6,10 +6,12 @@ */ #pragma once -#include "Bitfield.h" +#include "BitUtils.h" #include "YGFloatOptional.h" #include "Yoga-internal.h" +using namespace facebook::yoga; + struct YGLayout { std::array position = {}; std::array dimensions = {{YGUndefined, YGUndefined}}; @@ -18,12 +20,14 @@ struct YGLayout { std::array padding = {}; private: - static constexpr size_t directionIdx = 0; - static constexpr size_t didUseLegacyFlagIdx = 1; - static constexpr size_t doesLegacyStretchFlagAffectsLayoutIdx = 2; - static constexpr size_t hadOverflowIdx = 3; - facebook::yoga::Bitfield flags_ = - {YGDirectionInherit, false, false, false}; + static constexpr size_t directionOffset = 0; + static constexpr size_t didUseLegacyFlagOffset = + directionOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t doesLegacyStretchFlagAffectsLayoutOffset = + didUseLegacyFlagOffset + 1; + static constexpr size_t hadOverflowOffset = + doesLegacyStretchFlagAffectsLayoutOffset + 1; + uint8_t flags = 0; public: uint32_t computedFlexBasisGeneration = 0; @@ -32,7 +36,7 @@ public: // Instead of recomputing the entire layout every single time, we cache some // information to break early when nothing changed uint32_t generationCount = 0; - YGDirection lastOwnerDirection = (YGDirection) -1; + YGDirection lastOwnerDirection = YGDirectionInherit; uint32_t nextCachedMeasurementsIndex = 0; std::array @@ -41,27 +45,41 @@ public: YGCachedMeasurement cachedLayout = YGCachedMeasurement(); - YGDirection direction() const { return flags_.at(); } - decltype(flags_)::Ref direction() { - return flags_.at(); + YGDirection direction() const { + return facebook::yoga::detail::getEnumData( + flags, directionOffset); } - bool didUseLegacyFlag() const { return flags_.at(); } - decltype(flags_)::Ref didUseLegacyFlag() { - return flags_.at(); + void setDirection(YGDirection direction) { + facebook::yoga::detail::setEnumData( + flags, directionOffset, direction); + } + + bool didUseLegacyFlag() const { + return facebook::yoga::detail::getBooleanData( + flags, didUseLegacyFlagOffset); + } + + void setDidUseLegacyFlag(bool val) { + facebook::yoga::detail::setBooleanData(flags, didUseLegacyFlagOffset, val); } bool doesLegacyStretchFlagAffectsLayout() const { - return flags_.at(); - } - decltype(flags_)::Ref - doesLegacyStretchFlagAffectsLayout() { - return flags_.at(); + return facebook::yoga::detail::getBooleanData( + flags, doesLegacyStretchFlagAffectsLayoutOffset); } - bool hadOverflow() const { return flags_.at(); } - decltype(flags_)::Ref hadOverflow() { - return flags_.at(); + void setDoesLegacyStretchFlagAffectsLayout(bool val) { + facebook::yoga::detail::setBooleanData( + flags, doesLegacyStretchFlagAffectsLayoutOffset, val); + } + + bool hadOverflow() const { + return facebook::yoga::detail::getBooleanData(flags, hadOverflowOffset); + } + void setHadOverflow(bool hadOverflow) { + facebook::yoga::detail::setBooleanData( + flags, hadOverflowOffset, hadOverflow); } bool operator==(YGLayout layout) const; diff --git a/yoga/YGNode.cpp b/yoga/YGNode.cpp index 1d49b007..f4c14bf3 100644 --- a/yoga/YGNode.cpp +++ b/yoga/YGNode.cpp @@ -16,7 +16,7 @@ using facebook::yoga::detail::CompactValue; YGNode::YGNode(YGNode&& node) { context_ = node.context_; - flags_ = node.flags_; + flags = node.flags; measure_ = node.measure_; baseline_ = node.baseline_; print_ = node.print_; @@ -29,7 +29,7 @@ YGNode::YGNode(YGNode&& node) { config_ = node.config_; resolvedDimensions_ = node.resolvedDimensions_; for (auto c : children_) { - c->setOwner(c); + c->setOwner(this); } } @@ -42,7 +42,7 @@ YGNode::YGNode(const YGNode& node, YGConfigRef config) : YGNode{node} { void YGNode::print(void* printContext) { if (print_.noContext != nullptr) { - if (flags_.at()) { + if (facebook::yoga::detail::getBooleanData(flags, printUsesContext_)) { print_.withContext(this, printContext); } else { print_.noContext(this); @@ -50,89 +50,111 @@ void YGNode::print(void* printContext) { } } +CompactValue YGNode::computeEdgeValueForRow( + const YGStyle::Edges& edges, + YGEdge rowEdge, + YGEdge edge, + CompactValue defaultValue) { + if (!edges[rowEdge].isUndefined()) { + return edges[rowEdge]; + } else if (!edges[edge].isUndefined()) { + return edges[edge]; + } else if (!edges[YGEdgeHorizontal].isUndefined()) { + return edges[YGEdgeHorizontal]; + } else if (!edges[YGEdgeAll].isUndefined()) { + return edges[YGEdgeAll]; + } else { + return defaultValue; + } +} + +CompactValue YGNode::computeEdgeValueForColumn( + const YGStyle::Edges& edges, + YGEdge edge, + CompactValue defaultValue) { + if (!edges[edge].isUndefined()) { + return edges[edge]; + } else if (!edges[YGEdgeVertical].isUndefined()) { + return edges[YGEdgeVertical]; + } else if (!edges[YGEdgeAll].isUndefined()) { + return edges[YGEdgeAll]; + } else { + return defaultValue; + } +} + YGFloatOptional YGNode::getLeadingPosition( const YGFlexDirection axis, const float axisSize) const { - if (YGFlexDirectionIsRow(axis)) { - auto leadingPosition = YGComputedEdgeValue( - style_.position(), YGEdgeStart, CompactValue::ofUndefined()); - if (!leadingPosition.isUndefined()) { - return YGResolveValue(leadingPosition, axisSize); - } - } - - auto leadingPosition = YGComputedEdgeValue( - style_.position(), leading[axis], CompactValue::ofUndefined()); - - return leadingPosition.isUndefined() - ? YGFloatOptional{0} - : YGResolveValue(leadingPosition, axisSize); + auto leadingPosition = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.position(), + YGEdgeStart, + leading[axis], + CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.position(), leading[axis], CompactValue::ofZero()); + return YGResolveValue(leadingPosition, axisSize); } YGFloatOptional YGNode::getTrailingPosition( const YGFlexDirection axis, const float axisSize) const { - if (YGFlexDirectionIsRow(axis)) { - auto trailingPosition = YGComputedEdgeValue( - style_.position(), YGEdgeEnd, CompactValue::ofUndefined()); - if (!trailingPosition.isUndefined()) { - return YGResolveValue(trailingPosition, axisSize); - } - } - - auto trailingPosition = YGComputedEdgeValue( - style_.position(), trailing[axis], CompactValue::ofUndefined()); - - return trailingPosition.isUndefined() - ? YGFloatOptional{0} - : YGResolveValue(trailingPosition, axisSize); + auto trailingPosition = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.position(), + YGEdgeEnd, + trailing[axis], + CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.position(), trailing[axis], CompactValue::ofZero()); + return YGResolveValue(trailingPosition, axisSize); } bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { - return (YGFlexDirectionIsRow(axis) && - !YGComputedEdgeValue( - style_.position(), YGEdgeStart, CompactValue::ofUndefined()) - .isUndefined()) || - !YGComputedEdgeValue( - style_.position(), leading[axis], CompactValue::ofUndefined()) - .isUndefined(); + auto leadingPosition = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.position(), + YGEdgeStart, + leading[axis], + CompactValue::ofUndefined()) + : computeEdgeValueForColumn( + style_.position(), leading[axis], CompactValue::ofUndefined()); + return !leadingPosition.isUndefined(); } bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const { - return (YGFlexDirectionIsRow(axis) && - !YGComputedEdgeValue( - style_.position(), YGEdgeEnd, CompactValue::ofUndefined()) - .isUndefined()) || - !YGComputedEdgeValue( - style_.position(), trailing[axis], CompactValue::ofUndefined()) - .isUndefined(); + auto trailingPosition = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.position(), + YGEdgeEnd, + trailing[axis], + CompactValue::ofUndefined()) + : computeEdgeValueForColumn( + style_.position(), trailing[axis], CompactValue::ofUndefined()); + return !trailingPosition.isUndefined(); } YGFloatOptional YGNode::getLeadingMargin( const YGFlexDirection axis, const float widthSize) const { - if (YGFlexDirectionIsRow(axis) && - !style_.margin()[YGEdgeStart].isUndefined()) { - return YGResolveValueMargin(style_.margin()[YGEdgeStart], widthSize); - } - - return YGResolveValueMargin( - YGComputedEdgeValue( - style_.margin(), leading[axis], CompactValue::ofZero()), - widthSize); + auto leadingMargin = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.margin(), YGEdgeStart, leading[axis], CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.margin(), leading[axis], CompactValue::ofZero()); + return YGResolveValueMargin(leadingMargin, widthSize); } YGFloatOptional YGNode::getTrailingMargin( const YGFlexDirection axis, const float widthSize) const { - if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) { - return YGResolveValueMargin(style_.margin()[YGEdgeEnd], widthSize); - } - - return YGResolveValueMargin( - YGComputedEdgeValue( - style_.margin(), trailing[axis], CompactValue::ofZero()), - widthSize); + auto trailingMargin = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.margin(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.margin(), trailing[axis], CompactValue::ofZero()); + return YGResolveValueMargin(trailingMargin, widthSize); } YGFloatOptional YGNode::getMarginForAxis( @@ -147,15 +169,14 @@ YGSize YGNode::measure( float height, YGMeasureMode heightMode, void* layoutContext) { - - return flags_.at() + return facebook::yoga::detail::getBooleanData(flags, measureUsesContext_) ? measure_.withContext( this, width, widthMode, height, heightMode, layoutContext) : measure_.noContext(this, width, widthMode, height, heightMode); } float YGNode::baseline(float width, float height, void* layoutContext) { - return flags_.at() + return facebook::yoga::detail::getBooleanData(flags, baselineUsesContext_) ? baseline_.withContext(this, width, height, layoutContext) : baseline_.noContext(this, width, height); } @@ -166,7 +187,7 @@ void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) { if (measureFunc.noContext == nullptr) { // TODO: t18095186 Move nodeType to opt-in function and mark appropriate // places in Litho - flags_.at() = YGNodeTypeDefault; + setNodeType(YGNodeTypeDefault); } else { YGAssertWithNode( this, @@ -182,14 +203,14 @@ void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) { } void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) { - flags_.at() = false; + facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, false); decltype(YGNode::measure_) m; m.noContext = measureFunc; setMeasureFunc(m); } YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) { - flags_.at() = true; + facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, true); decltype(YGNode::measure_) m; m.withContext = measureFunc; setMeasureFunc(m); @@ -208,10 +229,10 @@ void YGNode::insertChild(YGNodeRef child, uint32_t index) { } void YGNode::setDirty(bool isDirty) { - if (isDirty == flags_.at()) { + if (isDirty == facebook::yoga::detail::getBooleanData(flags, isDirty_)) { return; } - flags_.at() = isDirty; + facebook::yoga::detail::setBooleanData(flags, isDirty_, isDirty); if (isDirty && dirtied_) { dirtied_(this); } @@ -232,7 +253,7 @@ void YGNode::removeChild(uint32_t index) { } void YGNode::setLayoutDirection(YGDirection direction) { - layout_.direction() = direction; + layout_.setDirection(direction); } void YGNode::setLayoutMargin(float margin, int index) { @@ -270,7 +291,7 @@ void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) { } void YGNode::setLayoutHadOverflow(bool hadOverflow) { - layout_.hadOverflow() = hadOverflow; + layout_.setHadOverflow(hadOverflow); } void YGNode::setLayoutDimension(float dimension, int index) { @@ -307,6 +328,9 @@ void YGNode::setPosition( const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, directionRespectingRoot); + // Here we should check for `YGPositionTypeStatic` and in this case zero inset + // properties (left, right, top, bottom, begin, end). + // https://www.w3.org/TR/css-position-3/#valdef-position-static const YGFloatOptional relativePositionMain = relativePosition(mainAxis, mainSize); const YGFloatOptional relativePositionCross = @@ -351,7 +375,9 @@ YGValue YGNode::resolveFlexBasisPtr() const { return flexBasis; } if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { - return flags_.at() ? YGValueAuto : YGValueZero; + return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) + ? YGValueAuto + : YGValueZero; } return YGValueAuto; } @@ -390,7 +416,7 @@ void YGNode::cloneChildrenIfNeeded(void* cloneContext) { } void YGNode::markDirtyAndPropogate() { - if (!flags_.at()) { + if (!facebook::yoga::detail::getBooleanData(flags, isDirty_)) { setDirty(true); setLayoutComputedFlexBasis(YGFloatOptional()); if (owner_) { @@ -400,7 +426,7 @@ void YGNode::markDirtyAndPropogate() { } void YGNode::markDirtyAndPropogateDownwards() { - flags_.at() = true; + facebook::yoga::detail::setBooleanData(flags, isDirty_, true); for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) { childNode->markDirtyAndPropogateDownwards(); }); @@ -427,83 +453,64 @@ float YGNode::resolveFlexShrink() const { if (!style_.flexShrink().isUndefined()) { return style_.flexShrink().unwrap(); } - if (!flags_.at() && !style_.flex().isUndefined() && - style_.flex().unwrap() < 0.0f) { + if (!facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) && + !style_.flex().isUndefined() && style_.flex().unwrap() < 0.0f) { return -style_.flex().unwrap(); } - return flags_.at() ? kWebDefaultFlexShrink - : kDefaultFlexShrink; + return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) + ? kWebDefaultFlexShrink + : kDefaultFlexShrink; } bool YGNode::isNodeFlexible() { return ( - (style_.positionType() == YGPositionTypeRelative) && + (style_.positionType() != YGPositionTypeAbsolute) && (resolveFlexGrow() != 0 || resolveFlexShrink() != 0)); } float YGNode::getLeadingBorder(const YGFlexDirection axis) const { - YGValue leadingBorder; - if (YGFlexDirectionIsRow(axis) && - !style_.border()[YGEdgeStart].isUndefined()) { - leadingBorder = style_.border()[YGEdgeStart]; - if (leadingBorder.value >= 0) { - return leadingBorder.value; - } - } - - leadingBorder = YGComputedEdgeValue( - style_.border(), leading[axis], CompactValue::ofZero()); - return YGFloatMax(leadingBorder.value, 0.0f); + YGValue leadingBorder = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.border(), YGEdgeStart, leading[axis], CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.border(), leading[axis], CompactValue::ofZero()); + return fmaxf(leadingBorder.value, 0.0f); } -float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const { - YGValue trailingBorder; - if (YGFlexDirectionIsRow(flexDirection) && - !style_.border()[YGEdgeEnd].isUndefined()) { - trailingBorder = style_.border()[YGEdgeEnd]; - if (trailingBorder.value >= 0.0f) { - return trailingBorder.value; - } - } - - trailingBorder = YGComputedEdgeValue( - style_.border(), trailing[flexDirection], CompactValue::ofZero()); - return YGFloatMax(trailingBorder.value, 0.0f); +float YGNode::getTrailingBorder(const YGFlexDirection axis) const { + YGValue trailingBorder = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.border(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.border(), trailing[axis], CompactValue::ofZero()); + return fmaxf(trailingBorder.value, 0.0f); } YGFloatOptional YGNode::getLeadingPadding( const YGFlexDirection axis, const float widthSize) const { - const YGFloatOptional paddingEdgeStart = - YGResolveValue(style_.padding()[YGEdgeStart], widthSize); - if (YGFlexDirectionIsRow(axis) && - !style_.padding()[YGEdgeStart].isUndefined() && - !paddingEdgeStart.isUndefined() && paddingEdgeStart.unwrap() >= 0.0f) { - return paddingEdgeStart; - } - - YGFloatOptional resolvedValue = YGResolveValue( - YGComputedEdgeValue( - style_.padding(), leading[axis], CompactValue::ofZero()), - widthSize); - return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); + auto leadingPadding = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.padding(), + YGEdgeStart, + leading[axis], + CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.padding(), leading[axis], CompactValue::ofZero()); + return YGFloatOptionalMax( + YGResolveValue(leadingPadding, widthSize), YGFloatOptional(0.0f)); } YGFloatOptional YGNode::getTrailingPadding( const YGFlexDirection axis, const float widthSize) const { - const YGFloatOptional paddingEdgeEnd = - YGResolveValue(style_.padding()[YGEdgeEnd], widthSize); - if (YGFlexDirectionIsRow(axis) && paddingEdgeEnd >= YGFloatOptional{0.0f}) { - return paddingEdgeEnd; - } - - YGFloatOptional resolvedValue = YGResolveValue( - YGComputedEdgeValue( - style_.padding(), trailing[axis], CompactValue::ofZero()), - widthSize); - - return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); + auto trailingPadding = YGFlexDirectionIsRow(axis) + ? computeEdgeValueForRow( + style_.padding(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) + : computeEdgeValueForColumn( + style_.padding(), trailing[axis], CompactValue::ofZero()); + return YGFloatOptionalMax( + YGResolveValue(trailingPadding, widthSize), YGFloatOptional(0.0f)); } YGFloatOptional YGNode::getLeadingPaddingAndBorder( @@ -536,11 +543,11 @@ bool YGNode::didUseLegacyFlag() { void YGNode::setLayoutDoesLegacyFlagAffectsLayout( bool doesLegacyFlagAffectsLayout) { - layout_.doesLegacyStretchFlagAffectsLayout() = doesLegacyFlagAffectsLayout; + layout_.setDoesLegacyStretchFlagAffectsLayout(doesLegacyFlagAffectsLayout); } void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) { - layout_.didUseLegacyFlag() = didUseLegacyFlag; + layout_.setDidUseLegacyFlag(didUseLegacyFlag); } bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const { @@ -577,7 +584,8 @@ void YGNode::reset() { clearChildren(); - auto webDefaults = flags_.at(); + auto webDefaults = + facebook::yoga::detail::getBooleanData(flags, useWebDefaults_); *this = YGNode{getConfig()}; if (webDefaults) { useWebDefaults(); diff --git a/yoga/YGNode.h b/yoga/YGNode.h index 2967a1e2..4b6e6277 100644 --- a/yoga/YGNode.h +++ b/yoga/YGNode.h @@ -6,9 +6,12 @@ */ #pragma once + +#ifdef __cplusplus + #include #include -#include "Bitfield.h" +#include "BitUtils.h" #include "CompactValue.h" #include "YGConfig.h" #include "YGLayout.h" @@ -35,10 +38,7 @@ private: static constexpr size_t useWebDefaults_ = 7; void* context_ = nullptr; - using Flags = facebook::yoga:: - Bitfield; - Flags flags_ = - {true, false, false, YGNodeTypeDefault, false, false, false, false}; + uint8_t flags = 1; uint8_t reserved_ = 0; union { YGMeasureFunc noContext; @@ -70,13 +70,13 @@ private: void setBaselineFunc(decltype(baseline_)); void useWebDefaults() { - flags_.at() = true; + facebook::yoga::detail::setBooleanData(flags, useWebDefaults_, true); style_.flexDirection() = YGFlexDirectionRow; style_.alignContent() = YGAlignStretch; } // DANGER DANGER DANGER! - // If the the node assigned to has children, we'd either have to deallocate + // If the node assigned to has children, we'd either have to deallocate // them (potentially incorrect) or ignore them (danger of leaks). Only ever // use this after checking that there are no children. // DO NOT CHANGE THE VISIBILITY OF THIS METHOD! @@ -114,9 +114,13 @@ public: void print(void*); - bool getHasNewLayout() const { return flags_.at(); } + bool getHasNewLayout() const { + return facebook::yoga::detail::getBooleanData(flags, hasNewLayout_); + } - YGNodeType getNodeType() const { return flags_.at(); } + YGNodeType getNodeType() const { + return facebook::yoga::detail::getEnumData(flags, nodeType_); + } bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; } @@ -142,7 +146,9 @@ public: uint32_t getLineIndex() const { return lineIndex_; } - bool isReferenceBaseline() { return flags_.at(); } + bool isReferenceBaseline() { + return facebook::yoga::detail::getBooleanData(flags, isReferenceBaseline_); + } // returns the YGNodeRef that owns this YGNode. An owner is used to identify // the YogaTree that a YGNode belongs to. This method will return the parent @@ -175,7 +181,9 @@ public: YGConfigRef getConfig() const { return config_; } - bool isDirty() const { return flags_.at(); } + bool isDirty() const { + return facebook::yoga::detail::getBooleanData(flags, isDirty_); + } std::array getResolvedDimensions() const { return resolvedDimensions_; @@ -185,6 +193,17 @@ public: return resolvedDimensions_[index]; } + static CompactValue computeEdgeValueForColumn( + const YGStyle::Edges& edges, + YGEdge edge, + CompactValue defaultValue); + + static CompactValue computeEdgeValueForRow( + const YGStyle::Edges& edges, + YGEdge rowEdge, + YGEdge edge, + CompactValue defaultValue); + // Methods related to positions, margin, padding and border YGFloatOptional getLeadingPosition( const YGFlexDirection axis, @@ -223,19 +242,22 @@ public: void setPrintFunc(YGPrintFunc printFunc) { print_.noContext = printFunc; - flags_.at() = false; + facebook::yoga::detail::setBooleanData(flags, printUsesContext_, false); } void setPrintFunc(PrintWithContextFn printFunc) { print_.withContext = printFunc; - flags_.at() = true; + facebook::yoga::detail::setBooleanData(flags, printUsesContext_, true); } void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); } void setHasNewLayout(bool hasNewLayout) { - flags_.at() = hasNewLayout; + facebook::yoga::detail::setBooleanData(flags, hasNewLayout_, hasNewLayout); } - void setNodeType(YGNodeType nodeType) { flags_.at() = nodeType; } + void setNodeType(YGNodeType nodeType) { + return facebook::yoga::detail::setEnumData( + flags, nodeType_, nodeType); + } void setMeasureFunc(YGMeasureFunc measureFunc); void setMeasureFunc(MeasureWithContextFn); @@ -244,11 +266,11 @@ public: } void setBaselineFunc(YGBaselineFunc baseLineFunc) { - flags_.at() = false; + facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, false); baseline_.noContext = baseLineFunc; } void setBaselineFunc(BaselineWithContextFn baseLineFunc) { - flags_.at() = true; + facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, true); baseline_.withContext = baseLineFunc; } void setBaselineFunc(std::nullptr_t) { @@ -264,7 +286,8 @@ public: void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; } void setIsReferenceBaseline(bool isReferenceBaseline) { - flags_.at() = isReferenceBaseline; + facebook::yoga::detail::setBooleanData( + flags, isReferenceBaseline_, isReferenceBaseline); } void setOwner(YGNodeRef owner) { owner_ = owner; } @@ -321,3 +344,5 @@ public: bool isLayoutTreeEqualToNode(const YGNode& node) const; void reset(); }; + +#endif diff --git a/yoga/YGNodePrint.cpp b/yoga/YGNodePrint.cpp index 26efa485..72d147db 100644 --- a/yoga/YGNodePrint.cpp +++ b/yoga/YGNodePrint.cpp @@ -104,10 +104,13 @@ static void appendEdgeIfNotUndefined( const string& str, const YGStyle::Edges& edges, const YGEdge edge) { - appendNumberIfNotUndefined( - base, - str, - YGComputedEdgeValue(edges, edge, detail::CompactValue::ofUndefined())); + // TODO: this doesn't take RTL / YGEdgeStart / YGEdgeEnd into account + auto value = (edge == YGEdgeLeft || edge == YGEdgeRight) + ? YGNode::computeEdgeValueForRow( + edges, edge, edge, detail::CompactValue::ofUndefined()) + : YGNode::computeEdgeValueForColumn( + edges, edge, detail::CompactValue::ofUndefined()); + appendNumberIfNotUndefined(base, str, value); } void YGNodeToString( diff --git a/yoga/YGStyle.h b/yoga/YGStyle.h index b066b346..aab7599c 100644 --- a/yoga/YGStyle.h +++ b/yoga/YGStyle.h @@ -6,16 +6,19 @@ */ #pragma once + +#ifdef __cplusplus + #include #include #include #include -#include "Bitfield.h" #include "CompactValue.h" #include "YGEnums.h" #include "YGFloatOptional.h" #include "Yoga-internal.h" #include "Yoga.h" +#include "BitUtils.h" class YOGA_EXPORT YGStyle { template @@ -27,6 +30,19 @@ public: using Dimensions = Values; using Edges = Values; + template + struct BitfieldRef { + YGStyle& style; + size_t offset; + operator T() const { + return facebook::yoga::detail::getEnumData(style.flags, offset); + } + BitfieldRef& operator=(T x) { + facebook::yoga::detail::setEnumData(style.flags, offset, x); + return *this; + } + }; + template struct Ref { YGStyle& style; @@ -60,43 +76,35 @@ public: CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; } }; - YGStyle() = default; + YGStyle() { + alignContent() = YGAlignFlexStart; + alignItems() = YGAlignStretch; + } ~YGStyle() = default; private: - static constexpr size_t directionIdx = 0; - static constexpr size_t flexDirectionIdx = 1; - static constexpr size_t justifyContentIdx = 2; - static constexpr size_t alignContentIdx = 3; - static constexpr size_t alignItemsIdx = 4; - static constexpr size_t alignSelfIdx = 5; - static constexpr size_t positionTypeIdx = 6; - static constexpr size_t flexWrapIdx = 7; - static constexpr size_t overflowIdx = 8; - static constexpr size_t displayIdx = 9; - using Flags = facebook::yoga::Bitfield< - uint32_t, - YGDirection, - YGFlexDirection, - YGJustify, - YGAlign, - YGAlign, - YGAlign, - YGPositionType, - YGWrap, - YGOverflow, - YGDisplay>; + static constexpr size_t directionOffset = 0; + static constexpr size_t flexdirectionOffset = + directionOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t justifyContentOffset = flexdirectionOffset + + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t alignContentOffset = + justifyContentOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t alignItemsOffset = + alignContentOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t alignSelfOffset = + alignItemsOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t positionTypeOffset = + alignSelfOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t flexWrapOffset = + positionTypeOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t overflowOffset = + flexWrapOffset + facebook::yoga::detail::bitWidthFn(); + static constexpr size_t displayOffset = + overflowOffset + facebook::yoga::detail::bitWidthFn(); + + uint32_t flags = 0; - Flags flags_ = {YGDirectionInherit, - YGFlexDirectionColumn, - YGJustifyFlexStart, - YGAlignFlexStart, - YGAlignStretch, - YGAlignAuto, - YGPositionTypeRelative, - YGWrapNoWrap, - YGOverflowVisible, - YGDisplayFlex}; YGFloatOptional flex_ = {}; YGFloatOptional flexGrow_ = {}; YGFloatOptional flexShrink_ = {}; @@ -115,45 +123,68 @@ public: // for library users needing a type using ValueRepr = std::remove_reference::type; - YGDirection direction() const { return flags_.at(); } - Flags::Ref direction() { return flags_.at(); } + YGDirection direction() const { + return facebook::yoga::detail::getEnumData( + flags, directionOffset); + } + BitfieldRef direction() { return {*this, directionOffset}; } YGFlexDirection flexDirection() const { - return flags_.at(); + return facebook::yoga::detail::getEnumData( + flags, flexdirectionOffset); } - Flags::Ref flexDirection() { - return flags_.at(); + BitfieldRef flexDirection() { + return {*this, flexdirectionOffset}; } - YGJustify justifyContent() const { return flags_.at(); } - Flags::Ref justifyContent() { - return flags_.at(); + YGJustify justifyContent() const { + return facebook::yoga::detail::getEnumData( + flags, justifyContentOffset); + } + BitfieldRef justifyContent() { + return {*this, justifyContentOffset}; } - YGAlign alignContent() const { return flags_.at(); } - Flags::Ref alignContent() { - return flags_.at(); + YGAlign alignContent() const { + return facebook::yoga::detail::getEnumData( + flags, alignContentOffset); + } + BitfieldRef alignContent() { return {*this, alignContentOffset}; } + + YGAlign alignItems() const { + return facebook::yoga::detail::getEnumData( + flags, alignItemsOffset); + } + BitfieldRef alignItems() { return {*this, alignItemsOffset}; } + + YGAlign alignSelf() const { + return facebook::yoga::detail::getEnumData(flags, alignSelfOffset); + } + BitfieldRef alignSelf() { return {*this, alignSelfOffset}; } + + YGPositionType positionType() const { + return facebook::yoga::detail::getEnumData( + flags, positionTypeOffset); + } + BitfieldRef positionType() { + return {*this, positionTypeOffset}; } - YGAlign alignItems() const { return flags_.at(); } - Flags::Ref alignItems() { return flags_.at(); } - - YGAlign alignSelf() const { return flags_.at(); } - Flags::Ref alignSelf() { return flags_.at(); } - - YGPositionType positionType() const { return flags_.at(); } - Flags::Ref positionType() { - return flags_.at(); + YGWrap flexWrap() const { + return facebook::yoga::detail::getEnumData(flags, flexWrapOffset); } + BitfieldRef flexWrap() { return {*this, flexWrapOffset}; } - YGWrap flexWrap() const { return flags_.at(); } - Flags::Ref flexWrap() { return flags_.at(); } + YGOverflow overflow() const { + return facebook::yoga::detail::getEnumData( + flags, overflowOffset); + } + BitfieldRef overflow() { return {*this, overflowOffset}; } - YGOverflow overflow() const { return flags_.at(); } - Flags::Ref overflow() { return flags_.at(); } - - YGDisplay display() const { return flags_.at(); } - Flags::Ref display() { return flags_.at(); } + YGDisplay display() const { + return facebook::yoga::detail::getEnumData(flags, displayOffset); + } + BitfieldRef display() { return {*this, displayOffset}; } YGFloatOptional flex() const { return flex_; } Ref flex() { return {*this}; } @@ -201,3 +232,5 @@ YOGA_EXPORT bool operator==(const YGStyle& lhs, const YGStyle& rhs); YOGA_EXPORT inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) { return !(lhs == rhs); } + +#endif diff --git a/yoga/YGValue.h b/yoga/YGValue.h index aaa10c3f..a2000978 100644 --- a/yoga/YGValue.h +++ b/yoga/YGValue.h @@ -11,6 +11,13 @@ #include "YGEnums.h" #include "YGMacros.h" +#if defined(_MSC_VER) && defined(__clang__) +#define COMPILING_WITH_CLANG_ON_WINDOWS +#endif +#if defined(COMPILING_WITH_CLANG_ON_WINDOWS) +#include +constexpr float YGUndefined = std::numeric_limits::quiet_NaN(); +#else YG_EXTERN_C_BEGIN // Not defined in MSVC++ @@ -20,6 +27,7 @@ static const uint32_t __nan = 0x7fc00000; #endif #define YGUndefined NAN +#endif typedef struct YGValue { float value; @@ -30,7 +38,10 @@ YOGA_EXPORT extern const YGValue YGValueAuto; YOGA_EXPORT extern const YGValue YGValueUndefined; YOGA_EXPORT extern const YGValue YGValueZero; +#if !defined(COMPILING_WITH_CLANG_ON_WINDOWS) YG_EXTERN_C_END +#endif +#undef COMPILING_WITH_CLANG_ON_WINDOWS #ifdef __cplusplus diff --git a/yoga/Yoga-internal.h b/yoga/Yoga-internal.h index 0b3368a0..acd173be 100644 --- a/yoga/Yoga-internal.h +++ b/yoga/Yoga-internal.h @@ -33,6 +33,10 @@ inline bool isUndefined(float value) { return std::isnan(value); } +inline bool isUndefined(double value) { + return std::isnan(value); +} + } // namespace yoga } // namespace facebook @@ -54,10 +58,10 @@ struct YGCachedMeasurement { float computedHeight; YGCachedMeasurement() - : availableWidth(0), - availableHeight(0), - widthMeasureMode((YGMeasureMode) -1), - heightMeasureMode((YGMeasureMode) -1), + : availableWidth(-1), + availableHeight(-1), + widthMeasureMode(YGMeasureModeUndefined), + heightMeasureMode(YGMeasureModeUndefined), computedWidth(-1), computedHeight(-1) {} @@ -144,8 +148,3 @@ static const float kDefaultFlexShrink = 0.0f; static const float kWebDefaultFlexShrink = 1.0f; extern bool YGFloatsEqual(const float a, const float b); -extern facebook::yoga::detail::CompactValue YGComputedEdgeValue( - const facebook::yoga::detail::Values< - facebook::yoga::enums::count()>& edges, - YGEdge edge, - facebook::yoga::detail::CompactValue defaultValue); diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index 04d199a3..2c68674a 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -106,38 +106,12 @@ static int YGDefaultLog( #undef YG_UNUSED #endif -YOGA_EXPORT bool YGFloatIsUndefined(const float value) { +static inline bool YGDoubleIsUndefined(const double value) { return facebook::yoga::isUndefined(value); } -detail::CompactValue YGComputedEdgeValue( - const YGStyle::Edges& edges, - YGEdge edge, - detail::CompactValue defaultValue) { - if (!edges[edge].isUndefined()) { - return edges[edge]; - } - - if ((edge == YGEdgeTop || edge == YGEdgeBottom) && - !edges[YGEdgeVertical].isUndefined()) { - return edges[YGEdgeVertical]; - } - - if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart || - edge == YGEdgeEnd) && - !edges[YGEdgeHorizontal].isUndefined()) { - return edges[YGEdgeHorizontal]; - } - - if (!edges[YGEdgeAll].isUndefined()) { - return edges[YGEdgeAll]; - } - - if (edge == YGEdgeStart || edge == YGEdgeEnd) { - return detail::CompactValue::ofUndefined(); - } - - return defaultValue; +YOGA_EXPORT bool YGFloatIsUndefined(const float value) { + return facebook::yoga::isUndefined(value); } YOGA_EXPORT void* YGNodeGetContext(YGNodeRef node) { @@ -249,9 +223,6 @@ YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) { static YGConfigRef YGConfigClone(const YGConfig& oldConfig) { const YGConfigRef config = new YGConfig(oldConfig); YGAssert(config != nullptr, "Could not allocate memory for config"); - if (config == nullptr) { - abort(); - } gConfigInstanceCount++; return config; } @@ -386,6 +357,14 @@ YOGA_EXPORT void YGNodeInsertChild( owner->markDirtyAndPropogate(); } +YOGA_EXPORT void YGNodeSwapChild( + const YGNodeRef owner, + const YGNodeRef child, + const uint32_t index) { + owner->replaceChild(child, index); + child->setOwner(owner); +} + YOGA_EXPORT void YGNodeRemoveChild( const YGNodeRef owner, const YGNodeRef excludedChild) { @@ -1126,7 +1105,7 @@ static bool YGIsBaselineLayout(const YGNodeRef node) { const uint32_t childCount = YGNodeGetChildCount(node); for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = YGNodeGetChild(node, i); - if (child->getStyle().positionType() == YGPositionTypeRelative && + if (child->getStyle().positionType() != YGPositionTypeAbsolute && child->getStyle().alignSelf() == YGAlignBaseline) { return true; } @@ -1655,8 +1634,8 @@ static void YGNodeAbsoluteLayoutChild( static void YGNodeWithMeasureFuncSetMeasuredDimensions( const YGNodeRef node, - const float availableWidth, - const float availableHeight, + float availableWidth, + float availableHeight, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, const float ownerWidth, @@ -1669,40 +1648,40 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( node->hasMeasureFunc(), "Expected node to have custom measure function"); - const float paddingAndBorderAxisRow = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); - const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis( - node, YGFlexDirectionColumn, availableWidth); - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, availableWidth).unwrap(); - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, availableWidth).unwrap(); + if (widthMeasureMode == YGMeasureModeUndefined) { + availableWidth = YGUndefined; + } + if (heightMeasureMode == YGMeasureModeUndefined) { + availableHeight = YGUndefined; + } + + const auto& padding = node->getLayout().padding; + const auto& border = node->getLayout().border; + const float paddingAndBorderAxisRow = padding[YGEdgeLeft] + + padding[YGEdgeRight] + border[YGEdgeLeft] + border[YGEdgeRight]; + const float paddingAndBorderAxisColumn = padding[YGEdgeTop] + + padding[YGEdgeBottom] + border[YGEdgeTop] + border[YGEdgeBottom]; // We want to make sure we don't call measure with negative size const float innerWidth = YGFloatIsUndefined(availableWidth) ? availableWidth - : YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow); + : YGFloatMax(0, availableWidth - paddingAndBorderAxisRow); const float innerHeight = YGFloatIsUndefined(availableHeight) ? availableHeight - : YGFloatMax( - 0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn); + : YGFloatMax(0, availableHeight - paddingAndBorderAxisColumn); if (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly) { // Don't bother sizing the text if both dimensions are already defined. node->setLayoutMeasuredDimension( YGNodeBoundAxis( - node, - YGFlexDirectionRow, - availableWidth - marginAxisRow, - ownerWidth, - ownerWidth), + node, YGFlexDirectionRow, availableWidth, ownerWidth, ownerWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, YGFlexDirectionColumn, - availableHeight - marginAxisColumn, + availableHeight, ownerHeight, ownerWidth), YGDimensionHeight); @@ -1739,7 +1718,7 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( (widthMeasureMode == YGMeasureModeUndefined || widthMeasureMode == YGMeasureModeAtMost) ? measuredSize.width + paddingAndBorderAxisRow - : availableWidth - marginAxisRow, + : availableWidth, ownerWidth, ownerWidth), YGDimensionWidth); @@ -1751,7 +1730,7 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( (heightMeasureMode == YGMeasureModeUndefined || heightMeasureMode == YGMeasureModeAtMost) ? measuredSize.height + paddingAndBorderAxisColumn - : availableHeight - marginAxisColumn, + : availableHeight, ownerHeight, ownerWidth), YGDimensionHeight); @@ -1768,37 +1747,28 @@ static void YGNodeEmptyContainerSetMeasuredDimensions( const YGMeasureMode heightMeasureMode, const float ownerWidth, const float ownerHeight) { - const float paddingAndBorderAxisRow = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth); - const float paddingAndBorderAxisColumn = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth); - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap(); - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap(); + const auto& padding = node->getLayout().padding; + const auto& border = node->getLayout().border; + float width = availableWidth; + if (widthMeasureMode == YGMeasureModeUndefined || + widthMeasureMode == YGMeasureModeAtMost) { + width = padding[YGEdgeLeft] + padding[YGEdgeRight] + border[YGEdgeLeft] + + border[YGEdgeRight]; + } node->setLayoutMeasuredDimension( - YGNodeBoundAxis( - node, - YGFlexDirectionRow, - (widthMeasureMode == YGMeasureModeUndefined || - widthMeasureMode == YGMeasureModeAtMost) - ? paddingAndBorderAxisRow - : availableWidth - marginAxisRow, - ownerWidth, - ownerWidth), + YGNodeBoundAxis(node, YGFlexDirectionRow, width, ownerWidth, ownerWidth), YGDimensionWidth); + float height = availableHeight; + if (heightMeasureMode == YGMeasureModeUndefined || + heightMeasureMode == YGMeasureModeAtMost) { + height = padding[YGEdgeTop] + padding[YGEdgeBottom] + border[YGEdgeTop] + + border[YGEdgeBottom]; + } node->setLayoutMeasuredDimension( YGNodeBoundAxis( - node, - YGFlexDirectionColumn, - (heightMeasureMode == YGMeasureModeUndefined || - heightMeasureMode == YGMeasureModeAtMost) - ? paddingAndBorderAxisColumn - : availableHeight - marginAxisColumn, - ownerHeight, - ownerWidth), + node, YGFlexDirectionColumn, height, ownerHeight, ownerWidth), YGDimensionHeight); } @@ -1816,11 +1786,6 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) || (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) { - auto marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap(); - auto marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap(); - node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, @@ -1829,7 +1794,7 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( (widthMeasureMode == YGMeasureModeAtMost && availableWidth < 0.0f) ? 0.0f - : availableWidth - marginAxisRow, + : availableWidth, ownerWidth, ownerWidth), YGDimensionWidth); @@ -1842,7 +1807,7 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( (heightMeasureMode == YGMeasureModeAtMost && availableHeight < 0.0f) ? 0.0f - : availableHeight - marginAxisColumn, + : availableHeight, ownerHeight, ownerWidth), YGDimensionHeight); @@ -1866,21 +1831,11 @@ static void YGZeroOutLayoutRecursivly( static float YGNodeCalculateAvailableInnerDim( const YGNodeConstRef node, - YGFlexDirection axis, - float availableDim, - float ownerDim, - float ownerDimForMarginPadding) { - YGFlexDirection direction = - YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn; - YGDimension dimension = - YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight; - - const float margin = - node->getMarginForAxis(direction, ownerDimForMarginPadding).unwrap(); - const float paddingAndBorder = - YGNodePaddingAndBorderForAxis(node, direction, ownerDimForMarginPadding); - - float availableInnerDim = availableDim - margin - paddingAndBorder; + const YGDimension dimension, + const float availableDim, + const float paddingAndBorder, + const float ownerDim) { + float availableInnerDim = availableDim - paddingAndBorder; // Max dimension overrides predefined dimension value; Min dimension in turn // overrides both of the above if (!YGFloatIsUndefined(availableInnerDim)) { @@ -2330,7 +2285,8 @@ static void YGDistributeFreeSpaceFirstPass( // first and second passes. deltaFreeSpace += boundMainSize - childFlexBasis; collectedFlexItemsValues.totalFlexShrinkScaledFactors -= - flexShrinkScaledFactor; + (-currentRelativeChild->resolveFlexShrink() * + currentRelativeChild->getLayout().computedFlexBasis.unwrap()); } } } else if ( @@ -2492,7 +2448,7 @@ static void YGJustifyMainAxis( i < collectedFlexItemsValues.endOfLineIndex; i++) { const YGNodeRef child = node->getChild(i); - if (child->getStyle().positionType() == YGPositionTypeRelative) { + if (child->getStyle().positionType() != YGPositionTypeAbsolute) { if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) { numberOfAutoMarginsOnCurrentLine++; } @@ -2576,7 +2532,7 @@ static void YGJustifyMainAxis( // Now that we placed the element, we need to update the variables. // We need to do that only for relative elements. Absolute elements do not // take part in that phase. - if (childStyle.positionType() == YGPositionTypeRelative) { + if (childStyle.positionType() != YGPositionTypeAbsolute) { if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) { collectedFlexItemsValues.mainDim += collectedFlexItemsValues.remainingFreeSpace / @@ -2766,16 +2722,22 @@ static void YGNodelayoutImpl( const YGEdge startEdge = direction == YGDirectionLTR ? YGEdgeLeft : YGEdgeRight; const YGEdge endEdge = direction == YGDirectionLTR ? YGEdgeRight : YGEdgeLeft; - node->setLayoutMargin( - node->getLeadingMargin(flexRowDirection, ownerWidth).unwrap(), startEdge); - node->setLayoutMargin( - node->getTrailingMargin(flexRowDirection, ownerWidth).unwrap(), endEdge); - node->setLayoutMargin( - node->getLeadingMargin(flexColumnDirection, ownerWidth).unwrap(), - YGEdgeTop); - node->setLayoutMargin( - node->getTrailingMargin(flexColumnDirection, ownerWidth).unwrap(), - YGEdgeBottom); + + const float marginRowLeading = + node->getLeadingMargin(flexRowDirection, ownerWidth).unwrap(); + node->setLayoutMargin(marginRowLeading, startEdge); + const float marginRowTrailing = + node->getTrailingMargin(flexRowDirection, ownerWidth).unwrap(); + node->setLayoutMargin(marginRowTrailing, endEdge); + const float marginColumnLeading = + node->getLeadingMargin(flexColumnDirection, ownerWidth).unwrap(); + node->setLayoutMargin(marginColumnLeading, YGEdgeTop); + const float marginColumnTrailing = + node->getTrailingMargin(flexColumnDirection, ownerWidth).unwrap(); + node->setLayoutMargin(marginColumnTrailing, YGEdgeBottom); + + const float marginAxisRow = marginRowLeading + marginRowTrailing; + const float marginAxisColumn = marginColumnLeading + marginColumnTrailing; node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), startEdge); node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), endEdge); @@ -2798,8 +2760,8 @@ static void YGNodelayoutImpl( if (node->hasMeasureFunc()) { YGNodeWithMeasureFuncSetMeasuredDimensions( node, - availableWidth, - availableHeight, + availableWidth - marginAxisRow, + availableHeight - marginAxisColumn, widthMeasureMode, heightMeasureMode, ownerWidth, @@ -2814,8 +2776,8 @@ static void YGNodelayoutImpl( if (childCount == 0) { YGNodeEmptyContainerSetMeasuredDimensions( node, - availableWidth, - availableHeight, + availableWidth - marginAxisRow, + availableHeight - marginAxisColumn, widthMeasureMode, heightMeasureMode, ownerWidth, @@ -2828,8 +2790,8 @@ static void YGNodelayoutImpl( if (!performLayout && YGNodeFixedSizeSetMeasuredDimensions( node, - availableWidth, - availableHeight, + availableWidth - marginAxisRow, + availableHeight - marginAxisColumn, widthMeasureMode, heightMeasureMode, ownerWidth, @@ -2853,12 +2815,14 @@ static void YGNodelayoutImpl( const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth; - const float leadingPaddingAndBorderCross = - node->getLeadingPaddingAndBorder(crossAxis, ownerWidth).unwrap(); const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth); + const float leadingPaddingAndBorderCross = + node->getLeadingPaddingAndBorder(crossAxis, ownerWidth).unwrap(); + const float trailingPaddingAndBorderCross = + node->getTrailingPaddingAndBorder(crossAxis, ownerWidth).unwrap(); const float paddingAndBorderAxisCross = - YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth); + leadingPaddingAndBorderCross + trailingPaddingAndBorderCross; YGMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode; @@ -2870,35 +2834,20 @@ static void YGNodelayoutImpl( const float paddingAndBorderAxisColumn = isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain; - const float marginAxisRow = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap(); - const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap(); - - const auto& minDimensions = node->getStyle().minDimensions(); - const auto& maxDimensions = node->getStyle().maxDimensions(); - const float minInnerWidth = - YGResolveValue(minDimensions[YGDimensionWidth], ownerWidth).unwrap() - - paddingAndBorderAxisRow; - const float maxInnerWidth = - YGResolveValue(maxDimensions[YGDimensionWidth], ownerWidth).unwrap() - - paddingAndBorderAxisRow; - const float minInnerHeight = - YGResolveValue(minDimensions[YGDimensionHeight], ownerHeight).unwrap() - - paddingAndBorderAxisColumn; - const float maxInnerHeight = - YGResolveValue(maxDimensions[YGDimensionHeight], ownerHeight).unwrap() - - paddingAndBorderAxisColumn; - - const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight; - const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight; - // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS float availableInnerWidth = YGNodeCalculateAvailableInnerDim( - node, YGFlexDirectionRow, availableWidth, ownerWidth, ownerWidth); + node, + YGDimensionWidth, + availableWidth - marginAxisRow, + paddingAndBorderAxisRow, + ownerWidth); float availableInnerHeight = YGNodeCalculateAvailableInnerDim( - node, YGFlexDirectionColumn, availableHeight, ownerHeight, ownerWidth); + node, + YGDimensionHeight, + availableHeight - marginAxisColumn, + paddingAndBorderAxisColumn, + ownerHeight); float availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight; @@ -2970,6 +2919,28 @@ static void YGNodelayoutImpl( // If we don't measure with exact main dimension we want to ensure we don't // violate min and max if (measureModeMainDim != YGMeasureModeExactly) { + const auto& minDimensions = node->getStyle().minDimensions(); + const auto& maxDimensions = node->getStyle().maxDimensions(); + const float minInnerWidth = + YGResolveValue(minDimensions[YGDimensionWidth], ownerWidth).unwrap() - + paddingAndBorderAxisRow; + const float maxInnerWidth = + YGResolveValue(maxDimensions[YGDimensionWidth], ownerWidth).unwrap() - + paddingAndBorderAxisRow; + const float minInnerHeight = + YGResolveValue(minDimensions[YGDimensionHeight], ownerHeight) + .unwrap() - + paddingAndBorderAxisColumn; + const float maxInnerHeight = + YGResolveValue(maxDimensions[YGDimensionHeight], ownerHeight) + .unwrap() - + paddingAndBorderAxisColumn; + + const float minInnerMainDim = + isMainAxisRow ? minInnerWidth : minInnerHeight; + const float maxInnerMainDim = + isMainAxisRow ? maxInnerWidth : maxInnerHeight; + if (!YGFloatIsUndefined(minInnerMainDim) && collectedFlexItemsValues.sizeConsumedOnCurrentLine < minInnerMainDim) { @@ -3298,7 +3269,7 @@ static void YGNodelayoutImpl( if (child->getStyle().display() == YGDisplayNone) { continue; } - if (child->getStyle().positionType() == YGPositionTypeRelative) { + if (child->getStyle().positionType() != YGPositionTypeAbsolute) { if (child->getLineIndex() != i) { break; } @@ -3340,7 +3311,7 @@ static void YGNodelayoutImpl( if (child->getStyle().display() == YGDisplayNone) { continue; } - if (child->getStyle().positionType() == YGPositionTypeRelative) { + if (child->getStyle().positionType() != YGPositionTypeAbsolute) { switch (YGNodeAlignItem(node, child)) { case YGAlignFlexStart: { child->setLayoutPosition( @@ -3518,8 +3489,8 @@ static void YGNodelayoutImpl( YGNodeBoundAxisWithinMinAndMax( node, crossAxis, - YGFloatOptional{totalLineCrossDim + - paddingAndBorderAxisCross}, + YGFloatOptional{ + totalLineCrossDim + paddingAndBorderAxisCross}, crossAxisownerSize) .unwrap()), paddingAndBorderAxisCross), @@ -3531,7 +3502,7 @@ static void YGNodelayoutImpl( if (performLayout && node->getStyle().flexWrap() == YGWrapWrapReverse) { for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = YGNodeGetChild(node, i); - if (child->getStyle().positionType() == YGPositionTypeRelative) { + if (child->getStyle().positionType() != YGPositionTypeAbsolute) { child->setLayoutPosition( node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().position[pos[crossAxis]] - @@ -3544,7 +3515,8 @@ static void YGNodelayoutImpl( if (performLayout) { // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN for (auto child : node->getChildren()) { - if (child->getStyle().positionType() != YGPositionTypeAbsolute) { + if (child->getStyle().display() == YGDisplayNone || + child->getStyle().positionType() != YGPositionTypeAbsolute) { continue; } YGNodeAbsoluteLayoutChild( @@ -3648,14 +3620,14 @@ static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid( } YOGA_EXPORT float YGRoundValueToPixelGrid( - const float value, - const float pointScaleFactor, + const double value, + const double pointScaleFactor, const bool forceCeil, const bool forceFloor) { - double scaledValue = ((double) value) * pointScaleFactor; + double scaledValue = value * pointScaleFactor; // We want to calculate `fractial` such that `floor(scaledValue) = scaledValue // - fractial`. - float fractial = fmodf(scaledValue, 1.0f); + double fractial = fmod(scaledValue, 1.0); if (fractial < 0) { // This branch is for handling negative numbers for `value`. // @@ -3674,28 +3646,28 @@ YOGA_EXPORT float YGRoundValueToPixelGrid( // - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3 ++fractial; } - if (YGFloatsEqual(fractial, 0)) { + if (YGDoubleEqual(fractial, 0)) { // First we check if the value is already rounded scaledValue = scaledValue - fractial; - } else if (YGFloatsEqual(fractial, 1.0f)) { - scaledValue = scaledValue - fractial + 1.0f; + } else if (YGDoubleEqual(fractial, 1.0)) { + scaledValue = scaledValue - fractial + 1.0; } else if (forceCeil) { // Next we check if we need to use forced rounding - scaledValue = scaledValue - fractial + 1.0f; + scaledValue = scaledValue - fractial + 1.0; } else if (forceFloor) { scaledValue = scaledValue - fractial; } else { // Finally we just round the value scaledValue = scaledValue - fractial + - (!YGFloatIsUndefined(fractial) && - (fractial > 0.5f || YGFloatsEqual(fractial, 0.5f)) - ? 1.0f - : 0.0f); + (!YGDoubleIsUndefined(fractial) && + (fractial > 0.5 || YGDoubleEqual(fractial, 0.5)) + ? 1.0 + : 0.0); } - return (YGFloatIsUndefined(scaledValue) || - YGFloatIsUndefined(pointScaleFactor)) + return (YGDoubleIsUndefined(scaledValue) || + YGDoubleIsUndefined(pointScaleFactor)) ? YGUndefined - : scaledValue / pointScaleFactor; + : (float) (scaledValue / pointScaleFactor); } YOGA_EXPORT bool YGNodeCanUseCachedMeasurement( @@ -3805,8 +3777,10 @@ bool YGLayoutNodeInternal( if (needToVisitNode) { // Invalidate the cached results. layout->nextCachedMeasurementsIndex = 0; - layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1; - layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1; + layout->cachedLayout.availableWidth = -1; + layout->cachedLayout.availableHeight = -1; + layout->cachedLayout.widthMeasureMode = YGMeasureModeUndefined; + layout->cachedLayout.heightMeasureMode = YGMeasureModeUndefined; layout->cachedLayout.computedWidth = -1; layout->cachedLayout.computedHeight = -1; } @@ -4063,24 +4037,24 @@ YOGA_EXPORT void YGConfigSetPointScaleFactor( static void YGRoundToPixelGrid( const YGNodeRef node, - const float pointScaleFactor, - const float absoluteLeft, - const float absoluteTop) { + const double pointScaleFactor, + const double absoluteLeft, + const double absoluteTop) { if (pointScaleFactor == 0.0f) { return; } - const float nodeLeft = node->getLayout().position[YGEdgeLeft]; - const float nodeTop = node->getLayout().position[YGEdgeTop]; + const double nodeLeft = node->getLayout().position[YGEdgeLeft]; + const double nodeTop = node->getLayout().position[YGEdgeTop]; - const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth]; - const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight]; + const double nodeWidth = node->getLayout().dimensions[YGDimensionWidth]; + const double nodeHeight = node->getLayout().dimensions[YGDimensionHeight]; - const float absoluteNodeLeft = absoluteLeft + nodeLeft; - const float absoluteNodeTop = absoluteTop + nodeTop; + const double absoluteNodeLeft = absoluteLeft + nodeLeft; + const double absoluteNodeTop = absoluteTop + nodeTop; - const float absoluteNodeRight = absoluteNodeLeft + nodeWidth; - const float absoluteNodeBottom = absoluteNodeTop + nodeHeight; + const double absoluteNodeRight = absoluteNodeLeft + nodeWidth; + const double absoluteNodeBottom = absoluteNodeTop + nodeHeight; // If a node has a custom measure function we never want to round down its // size as this could lead to unwanted text truncation. @@ -4098,11 +4072,11 @@ static void YGRoundToPixelGrid( // whole number, we don't have any fraction To verify if the result is close // to whole number we want to check both floor and ceil numbers const bool hasFractionalWidth = - !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) && - !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0); + !YGDoubleEqual(fmod(nodeWidth * pointScaleFactor, 1.0), 0) && + !YGDoubleEqual(fmod(nodeWidth * pointScaleFactor, 1.0), 1.0); const bool hasFractionalHeight = - !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) && - !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0); + !YGDoubleEqual(fmod(nodeHeight * pointScaleFactor, 1.0), 0) && + !YGDoubleEqual(fmod(nodeHeight * pointScaleFactor, 1.0), 1.0); node->setLayoutDimension( YGRoundValueToPixelGrid( @@ -4220,9 +4194,7 @@ YOGA_EXPORT void YGNodeCalculateLayoutWithContext( if (node->getConfig()->printTree) { YGNodePrint( node, - (YGPrintOptions)( - YGPrintOptionsLayout | YGPrintOptionsChildren | - YGPrintOptionsStyle)); + (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); } #endif } @@ -4282,9 +4254,7 @@ YOGA_EXPORT void YGNodeCalculateLayoutWithContext( if (nodeWithoutLegacyFlag->getConfig()->printTree) { YGNodePrint( nodeWithoutLegacyFlag, - (YGPrintOptions)( - YGPrintOptionsLayout | YGPrintOptionsChildren | - YGPrintOptionsStyle)); + (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); } #endif } @@ -4323,6 +4293,7 @@ YOGA_EXPORT void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( void YGAssert(const bool condition, const char* message) { if (!condition) { Log::log(YGNodeRef{nullptr}, YGLogLevelFatal, nullptr, "%s\n", message); + throwLogicalErrorWithMessage(message); } } @@ -4332,6 +4303,7 @@ void YGAssertWithNode( const char* message) { if (!condition) { Log::log(node, YGLogLevelFatal, nullptr, "%s\n", message); + throwLogicalErrorWithMessage(message); } } @@ -4341,6 +4313,7 @@ void YGAssertWithConfig( const char* message) { if (!condition) { Log::log(config, YGLogLevelFatal, nullptr, "%s\n", message); + throwLogicalErrorWithMessage(message); } } diff --git a/yoga/Yoga.h b/yoga/Yoga.h index 68ed0a62..86cd65e2 100644 --- a/yoga/Yoga.h +++ b/yoga/Yoga.h @@ -69,6 +69,11 @@ WIN_EXPORT void YGNodeInsertChild( YGNodeRef child, uint32_t index); +WIN_EXPORT void YGNodeSwapChild( + YGNodeRef node, + YGNodeRef child, + uint32_t index); + WIN_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child); WIN_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node); WIN_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, uint32_t index); @@ -102,7 +107,7 @@ WIN_EXPORT void YGNodeMarkDirty(YGNodeRef node); // Marks the current node and all its descendants as dirty. // -// Intended to be used for Uoga benchmarks. Don't use in production, as calling +// Intended to be used for Yoga benchmarks. Don't use in production, as calling // `YGCalculateLayout` will cause the recalculation of each and every node. WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(YGNodeRef node); @@ -347,8 +352,8 @@ WIN_EXPORT void YGConfigSetContext(YGConfigRef config, void* context); WIN_EXPORT void* YGConfigGetContext(YGConfigRef config); WIN_EXPORT float YGRoundValueToPixelGrid( - float value, - float pointScaleFactor, + double value, + double pointScaleFactor, bool forceCeil, bool forceFloor); diff --git a/yoga/event/event.cpp b/yoga/event/event.cpp index 2b07e381..3af3e83a 100644 --- a/yoga/event/event.cpp +++ b/yoga/event/event.cpp @@ -8,7 +8,6 @@ #include "event.h" #include #include -#include namespace facebook { namespace yoga { diff --git a/yoga/event/event.h b/yoga/event/event.h index 309dacb5..404ec376 100644 --- a/yoga/event/event.h +++ b/yoga/event/event.h @@ -11,6 +11,7 @@ #include #include #include +#include struct YGConfig; struct YGNode; diff --git a/yoga/log.cpp b/yoga/log.cpp index fe6fbbc6..eb3da039 100644 --- a/yoga/log.cpp +++ b/yoga/log.cpp @@ -26,10 +26,6 @@ void vlog( va_list args) { YGConfig* logConfig = config != nullptr ? config : YGConfigGetDefault(); logConfig->log(logConfig, node, level, context, format, args); - - if (level == YGLogLevelFatal) { - abort(); - } } } // namespace