RCTWrapperShadowView.m 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTWrapperShadowView.h"
  8. #import <React/RCTBridge.h>
  9. #import <React/RCTUIManager.h>
  10. #import <React/RCTShadowView+Layout.h>
  11. #import "RCTWrapperView.h"
  12. @implementation RCTWrapperShadowView
  13. {
  14. __weak RCTBridge *_bridge;
  15. RCTWrapperMeasureBlock _measureBlock;
  16. CGSize _intrinsicContentSize;
  17. }
  18. - (instancetype)initWithBridge:(RCTBridge *)bridge
  19. {
  20. if (self = [super init]) {
  21. _bridge = bridge;
  22. YGNodeSetMeasureFunc(self.yogaNode, RCTWrapperShadowViewMeasure);
  23. }
  24. return self;
  25. }
  26. static YGSize RCTWrapperShadowViewMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode)
  27. {
  28. CGSize minimumSize = CGSizeMake(0, 0);
  29. CGSize maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
  30. switch (widthMode) {
  31. case YGMeasureModeUndefined:
  32. break;
  33. case YGMeasureModeExactly:
  34. minimumSize.width = width;
  35. maximumSize.width = width;
  36. break;
  37. case YGMeasureModeAtMost:
  38. maximumSize.width = width;
  39. break;
  40. }
  41. switch (heightMode) {
  42. case YGMeasureModeUndefined:
  43. break;
  44. case YGMeasureModeExactly:
  45. minimumSize.height = height;
  46. maximumSize.height = height;
  47. break;
  48. case YGMeasureModeAtMost:
  49. maximumSize.height = height;
  50. break;
  51. }
  52. RCTWrapperShadowView *shadowView = (__bridge RCTWrapperShadowView *)YGNodeGetContext(node);
  53. CGSize size = [shadowView measureWithMinimumSize:minimumSize maximumSize:maximumSize];
  54. return (YGSize){
  55. RCTYogaFloatFromCoreGraphicsFloat(size.width),
  56. RCTYogaFloatFromCoreGraphicsFloat(size.height)
  57. };
  58. }
  59. - (CGSize)measureWithMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
  60. {
  61. dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC);
  62. if (!_measureBlock) {
  63. RCTBridge *bridge = _bridge;
  64. __block RCTWrapperMeasureBlock measureBlock;
  65. NSNumber *reactTag = self.reactTag;
  66. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  67. dispatch_async(dispatch_get_main_queue(), ^{
  68. RCTUIManager *uiManager = bridge.uiManager;
  69. RCTWrapperView *view = (RCTWrapperView *)[uiManager viewForReactTag:reactTag];
  70. measureBlock = view.measureBlock;
  71. dispatch_semaphore_signal(semaphore);
  72. });
  73. if (dispatch_semaphore_wait(semaphore, timeout)) {
  74. RCTLogError(@"Unable to retrieve `measureBlock` for view (%@) because the main thread is busy.", self);
  75. }
  76. _measureBlock = measureBlock;
  77. }
  78. if (!_measureBlock) {
  79. return maximumSize;
  80. }
  81. __block CGSize size = maximumSize;
  82. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  83. dispatch_async(dispatch_get_main_queue(), ^{
  84. size = self->_measureBlock(minimumSize, maximumSize);
  85. dispatch_semaphore_signal(semaphore);
  86. });
  87. if (dispatch_semaphore_wait(semaphore, timeout)) {
  88. RCTLogError(@"Unable to compute layout for view (%@) because the main thread is busy.", self);
  89. }
  90. return size;
  91. }
  92. - (BOOL)isYogaLeafNode
  93. {
  94. return YES;
  95. }
  96. - (CGSize)intrinsicContentSize
  97. {
  98. return _intrinsicContentSize;
  99. }
  100. - (void)setIntrinsicContentSize:(CGSize)size
  101. {
  102. _intrinsicContentSize = size;
  103. YGNodeMarkDirty(self.yogaNode);
  104. }
  105. @end