YGNode.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /**
  2. * Copyright (c) 2014-present, Facebook, Inc.
  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. #include "YGNode.h"
  8. #include <iostream>
  9. #include "Utils.h"
  10. YGFloatOptional YGNode::getLeadingPosition(
  11. const YGFlexDirection& axis,
  12. const float& axisSize) const {
  13. if (YGFlexDirectionIsRow(axis)) {
  14. const YGValue* leadingPosition =
  15. YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined);
  16. if (leadingPosition->unit != YGUnitUndefined) {
  17. return YGResolveValue(*leadingPosition, axisSize);
  18. }
  19. }
  20. const YGValue* leadingPosition =
  21. YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined);
  22. return leadingPosition->unit == YGUnitUndefined
  23. ? YGFloatOptional(0)
  24. : YGResolveValue(*leadingPosition, axisSize);
  25. }
  26. YGFloatOptional YGNode::getTrailingPosition(
  27. const YGFlexDirection& axis,
  28. const float& axisSize) const {
  29. if (YGFlexDirectionIsRow(axis)) {
  30. const YGValue* trailingPosition =
  31. YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined);
  32. if (trailingPosition->unit != YGUnitUndefined) {
  33. return YGResolveValue(*trailingPosition, axisSize);
  34. }
  35. }
  36. const YGValue* trailingPosition =
  37. YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined);
  38. return trailingPosition->unit == YGUnitUndefined
  39. ? YGFloatOptional(0)
  40. : YGResolveValue(*trailingPosition, axisSize);
  41. }
  42. bool YGNode::isLeadingPositionDefined(const YGFlexDirection& axis) const {
  43. return (YGFlexDirectionIsRow(axis) &&
  44. YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined)
  45. ->unit != YGUnitUndefined) ||
  46. YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined)
  47. ->unit != YGUnitUndefined;
  48. }
  49. bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const {
  50. return (YGFlexDirectionIsRow(axis) &&
  51. YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined)
  52. ->unit != YGUnitUndefined) ||
  53. YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined)
  54. ->unit != YGUnitUndefined;
  55. }
  56. YGFloatOptional YGNode::getLeadingMargin(
  57. const YGFlexDirection& axis,
  58. const float& widthSize) const {
  59. if (YGFlexDirectionIsRow(axis) &&
  60. style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
  61. return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
  62. }
  63. return YGResolveValueMargin(
  64. *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero),
  65. widthSize);
  66. }
  67. YGFloatOptional YGNode::getTrailingMargin(
  68. const YGFlexDirection& axis,
  69. const float& widthSize) const {
  70. if (YGFlexDirectionIsRow(axis) &&
  71. style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
  72. return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
  73. }
  74. return YGResolveValueMargin(
  75. *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero),
  76. widthSize);
  77. }
  78. YGFloatOptional YGNode::getMarginForAxis(
  79. const YGFlexDirection& axis,
  80. const float& widthSize) const {
  81. return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
  82. }
  83. // Setters
  84. void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
  85. if (measureFunc == nullptr) {
  86. measure_ = nullptr;
  87. // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
  88. // places in Litho
  89. nodeType_ = YGNodeTypeDefault;
  90. } else {
  91. YGAssertWithNode(
  92. this,
  93. children_.size() == 0,
  94. "Cannot set measure function: Nodes with measure functions cannot have children.");
  95. measure_ = measureFunc;
  96. // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
  97. // places in Litho
  98. setNodeType(YGNodeTypeText);
  99. }
  100. measure_ = measureFunc;
  101. }
  102. void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
  103. children_[index] = child;
  104. }
  105. void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
  106. std::replace(children_.begin(), children_.end(), oldChild, newChild);
  107. }
  108. void YGNode::insertChild(YGNodeRef child, uint32_t index) {
  109. children_.insert(children_.begin() + index, child);
  110. }
  111. void YGNode::setDirty(bool isDirty) {
  112. if (isDirty == isDirty_) {
  113. return;
  114. }
  115. isDirty_ = isDirty;
  116. if (isDirty && dirtied_) {
  117. dirtied_(this);
  118. }
  119. }
  120. bool YGNode::removeChild(YGNodeRef child) {
  121. std::vector<YGNodeRef>::iterator p =
  122. std::find(children_.begin(), children_.end(), child);
  123. if (p != children_.end()) {
  124. children_.erase(p);
  125. return true;
  126. }
  127. return false;
  128. }
  129. void YGNode::removeChild(uint32_t index) {
  130. children_.erase(children_.begin() + index);
  131. }
  132. void YGNode::setLayoutDirection(YGDirection direction) {
  133. layout_.direction = direction;
  134. }
  135. void YGNode::setLayoutMargin(float margin, int index) {
  136. layout_.margin[index] = margin;
  137. }
  138. void YGNode::setLayoutBorder(float border, int index) {
  139. layout_.border[index] = border;
  140. }
  141. void YGNode::setLayoutPadding(float padding, int index) {
  142. layout_.padding[index] = padding;
  143. }
  144. void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
  145. layout_.lastOwnerDirection = direction;
  146. }
  147. void YGNode::setLayoutComputedFlexBasis(
  148. const YGFloatOptional& computedFlexBasis) {
  149. layout_.computedFlexBasis = computedFlexBasis;
  150. }
  151. void YGNode::setLayoutPosition(float position, int index) {
  152. layout_.position[index] = position;
  153. }
  154. void YGNode::setLayoutComputedFlexBasisGeneration(
  155. uint32_t computedFlexBasisGeneration) {
  156. layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
  157. }
  158. void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
  159. layout_.measuredDimensions[index] = measuredDimension;
  160. }
  161. void YGNode::setLayoutHadOverflow(bool hadOverflow) {
  162. layout_.hadOverflow = hadOverflow;
  163. }
  164. void YGNode::setLayoutDimension(float dimension, int index) {
  165. layout_.dimensions[index] = dimension;
  166. }
  167. // If both left and right are defined, then use left. Otherwise return
  168. // +left or -right depending on which is defined.
  169. YGFloatOptional YGNode::relativePosition(
  170. const YGFlexDirection& axis,
  171. const float& axisSize) const {
  172. if (isLeadingPositionDefined(axis)) {
  173. return getLeadingPosition(axis, axisSize);
  174. }
  175. YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
  176. if (!trailingPosition.isUndefined()) {
  177. trailingPosition.setValue(-1 * trailingPosition.getValue());
  178. }
  179. return trailingPosition;
  180. }
  181. void YGNode::setPosition(
  182. const YGDirection direction,
  183. const float mainSize,
  184. const float crossSize,
  185. const float ownerWidth) {
  186. /* Root nodes should be always layouted as LTR, so we don't return negative
  187. * values. */
  188. const YGDirection directionRespectingRoot =
  189. owner_ != nullptr ? direction : YGDirectionLTR;
  190. const YGFlexDirection mainAxis =
  191. YGResolveFlexDirection(style_.flexDirection, directionRespectingRoot);
  192. const YGFlexDirection crossAxis =
  193. YGFlexDirectionCross(mainAxis, directionRespectingRoot);
  194. const YGFloatOptional relativePositionMain =
  195. relativePosition(mainAxis, mainSize);
  196. const YGFloatOptional relativePositionCross =
  197. relativePosition(crossAxis, crossSize);
  198. setLayoutPosition(
  199. YGUnwrapFloatOptional(
  200. getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain),
  201. leading[mainAxis]);
  202. setLayoutPosition(
  203. YGUnwrapFloatOptional(
  204. getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain),
  205. trailing[mainAxis]);
  206. setLayoutPosition(
  207. YGUnwrapFloatOptional(
  208. getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross),
  209. leading[crossAxis]);
  210. setLayoutPosition(
  211. YGUnwrapFloatOptional(
  212. getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross),
  213. trailing[crossAxis]);
  214. }
  215. YGNode::YGNode()
  216. : context_(nullptr),
  217. print_(nullptr),
  218. hasNewLayout_(true),
  219. nodeType_(YGNodeTypeDefault),
  220. measure_(nullptr),
  221. baseline_(nullptr),
  222. dirtied_(nullptr),
  223. style_(YGStyle()),
  224. layout_(YGLayout()),
  225. lineIndex_(0),
  226. owner_(nullptr),
  227. children_(YGVector()),
  228. config_(nullptr),
  229. isDirty_(false),
  230. resolvedDimensions_({{YGValueUndefined, YGValueUndefined}}) {}
  231. YGNode::YGNode(const YGNode& node)
  232. : context_(node.context_),
  233. print_(node.print_),
  234. hasNewLayout_(node.hasNewLayout_),
  235. nodeType_(node.nodeType_),
  236. measure_(node.measure_),
  237. baseline_(node.baseline_),
  238. dirtied_(node.dirtied_),
  239. style_(node.style_),
  240. layout_(node.layout_),
  241. lineIndex_(node.lineIndex_),
  242. owner_(node.owner_),
  243. children_(node.children_),
  244. config_(node.config_),
  245. isDirty_(node.isDirty_),
  246. resolvedDimensions_(node.resolvedDimensions_) {}
  247. YGNode::YGNode(const YGConfigRef newConfig) : YGNode() {
  248. config_ = newConfig;
  249. }
  250. YGNode::YGNode(
  251. void* context,
  252. YGPrintFunc print,
  253. bool hasNewLayout,
  254. YGNodeType nodeType,
  255. YGMeasureFunc measure,
  256. YGBaselineFunc baseline,
  257. YGDirtiedFunc dirtied,
  258. YGStyle style,
  259. const YGLayout& layout,
  260. uint32_t lineIndex,
  261. YGNodeRef owner,
  262. const YGVector& children,
  263. YGConfigRef config,
  264. bool isDirty,
  265. std::array<YGValue, 2> resolvedDimensions)
  266. : context_(context),
  267. print_(print),
  268. hasNewLayout_(hasNewLayout),
  269. nodeType_(nodeType),
  270. measure_(measure),
  271. baseline_(baseline),
  272. dirtied_(dirtied),
  273. style_(style),
  274. layout_(layout),
  275. lineIndex_(lineIndex),
  276. owner_(owner),
  277. children_(children),
  278. config_(config),
  279. isDirty_(isDirty),
  280. resolvedDimensions_(resolvedDimensions) {}
  281. YGNode& YGNode::operator=(const YGNode& node) {
  282. if (&node == this) {
  283. return *this;
  284. }
  285. for (auto child : children_) {
  286. delete child;
  287. }
  288. context_ = node.getContext();
  289. print_ = node.getPrintFunc();
  290. hasNewLayout_ = node.getHasNewLayout();
  291. nodeType_ = node.getNodeType();
  292. measure_ = node.getMeasure();
  293. baseline_ = node.getBaseline();
  294. dirtied_ = node.getDirtied();
  295. style_ = node.style_;
  296. layout_ = node.layout_;
  297. lineIndex_ = node.getLineIndex();
  298. owner_ = node.getOwner();
  299. children_ = node.getChildren();
  300. config_ = node.getConfig();
  301. isDirty_ = node.isDirty();
  302. resolvedDimensions_ = node.getResolvedDimensions();
  303. return *this;
  304. }
  305. YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
  306. if (YGFlexDirectionIsRow(axis) &&
  307. style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
  308. return style_.margin[YGEdgeStart];
  309. } else {
  310. return style_.margin[leading[axis]];
  311. }
  312. }
  313. YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
  314. if (YGFlexDirectionIsRow(axis) &&
  315. style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
  316. return style_.margin[YGEdgeEnd];
  317. } else {
  318. return style_.margin[trailing[axis]];
  319. }
  320. }
  321. YGValue YGNode::resolveFlexBasisPtr() const {
  322. YGValue flexBasis = style_.flexBasis;
  323. if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
  324. return flexBasis;
  325. }
  326. if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
  327. return config_->useWebDefaults ? YGValueAuto : YGValueZero;
  328. }
  329. return YGValueAuto;
  330. }
  331. void YGNode::resolveDimension() {
  332. for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
  333. if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
  334. YGValueEqual(
  335. getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
  336. resolvedDimensions_[dim] = style_.maxDimensions[dim];
  337. } else {
  338. resolvedDimensions_[dim] = style_.dimensions[dim];
  339. }
  340. }
  341. }
  342. YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
  343. if (style_.direction == YGDirectionInherit) {
  344. return ownerDirection > YGDirectionInherit ? ownerDirection
  345. : YGDirectionLTR;
  346. } else {
  347. return style_.direction;
  348. }
  349. }
  350. void YGNode::clearChildren() {
  351. children_.clear();
  352. children_.shrink_to_fit();
  353. }
  354. YGNode::~YGNode() {
  355. // All the member variables are deallocated externally, so no need to
  356. // deallocate here
  357. }
  358. // Other Methods
  359. void YGNode::cloneChildrenIfNeeded() {
  360. // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm
  361. // optimized for deletions.
  362. const uint32_t childCount = static_cast<uint32_t>(children_.size());
  363. if (childCount == 0) {
  364. // This is an empty set. Nothing to clone.
  365. return;
  366. }
  367. const YGNodeRef firstChild = children_.front();
  368. if (firstChild->getOwner() == this) {
  369. // If the first child has this node as its owner, we assume that it is
  370. // already unique. We can do this because if we have it has a child, that
  371. // means that its owner was at some point cloned which made that subtree
  372. // immutable. We also assume that all its sibling are cloned as well.
  373. return;
  374. }
  375. const YGCloneNodeFunc cloneNodeCallback = config_->cloneNodeCallback;
  376. for (uint32_t i = 0; i < childCount; ++i) {
  377. const YGNodeRef oldChild = children_[i];
  378. YGNodeRef newChild = nullptr;
  379. if (cloneNodeCallback) {
  380. newChild = cloneNodeCallback(oldChild, this, i);
  381. }
  382. if (newChild == nullptr) {
  383. newChild = YGNodeClone(oldChild);
  384. }
  385. replaceChild(newChild, i);
  386. newChild->setOwner(this);
  387. }
  388. }
  389. void YGNode::markDirtyAndPropogate() {
  390. if (!isDirty_) {
  391. setDirty(true);
  392. setLayoutComputedFlexBasis(YGFloatOptional());
  393. if (owner_) {
  394. owner_->markDirtyAndPropogate();
  395. }
  396. }
  397. }
  398. void YGNode::markDirtyAndPropogateDownwards() {
  399. isDirty_ = true;
  400. for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
  401. childNode->markDirtyAndPropogateDownwards();
  402. });
  403. }
  404. float YGNode::resolveFlexGrow() {
  405. // Root nodes flexGrow should always be 0
  406. if (owner_ == nullptr) {
  407. return 0.0;
  408. }
  409. if (!style_.flexGrow.isUndefined()) {
  410. return style_.flexGrow.getValue();
  411. }
  412. if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
  413. return style_.flex.getValue();
  414. }
  415. return kDefaultFlexGrow;
  416. }
  417. float YGNode::resolveFlexShrink() {
  418. if (owner_ == nullptr) {
  419. return 0.0;
  420. }
  421. if (!style_.flexShrink.isUndefined()) {
  422. return style_.flexShrink.getValue();
  423. }
  424. if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
  425. style_.flex.getValue() < 0.0f) {
  426. return -style_.flex.getValue();
  427. }
  428. return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
  429. }
  430. bool YGNode::isNodeFlexible() {
  431. return (
  432. (style_.positionType == YGPositionTypeRelative) &&
  433. (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
  434. }
  435. float YGNode::getLeadingBorder(const YGFlexDirection& axis) const {
  436. if (YGFlexDirectionIsRow(axis) &&
  437. style_.border[YGEdgeStart].unit != YGUnitUndefined &&
  438. !YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
  439. style_.border[YGEdgeStart].value >= 0.0f) {
  440. return style_.border[YGEdgeStart].value;
  441. }
  442. float computedEdgeValue =
  443. YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
  444. return YGFloatMax(computedEdgeValue, 0.0f);
  445. }
  446. float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const {
  447. if (YGFlexDirectionIsRow(flexDirection) &&
  448. style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
  449. !YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
  450. style_.border[YGEdgeEnd].value >= 0.0f) {
  451. return style_.border[YGEdgeEnd].value;
  452. }
  453. float computedEdgeValue =
  454. YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
  455. ->value;
  456. return YGFloatMax(computedEdgeValue, 0.0f);
  457. }
  458. YGFloatOptional YGNode::getLeadingPadding(
  459. const YGFlexDirection& axis,
  460. const float& widthSize) const {
  461. const YGFloatOptional& paddingEdgeStart =
  462. YGResolveValue(style_.padding[YGEdgeStart], widthSize);
  463. if (YGFlexDirectionIsRow(axis) &&
  464. style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
  465. !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) {
  466. return paddingEdgeStart;
  467. }
  468. YGFloatOptional resolvedValue = YGResolveValue(
  469. *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
  470. widthSize);
  471. return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
  472. }
  473. YGFloatOptional YGNode::getTrailingPadding(
  474. const YGFlexDirection& axis,
  475. const float& widthSize) const {
  476. if (YGFlexDirectionIsRow(axis) &&
  477. style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
  478. !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
  479. YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) {
  480. return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
  481. }
  482. YGFloatOptional resolvedValue = YGResolveValue(
  483. *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
  484. widthSize);
  485. return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
  486. }
  487. YGFloatOptional YGNode::getLeadingPaddingAndBorder(
  488. const YGFlexDirection& axis,
  489. const float& widthSize) const {
  490. return getLeadingPadding(axis, widthSize) +
  491. YGFloatOptional(getLeadingBorder(axis));
  492. }
  493. YGFloatOptional YGNode::getTrailingPaddingAndBorder(
  494. const YGFlexDirection& axis,
  495. const float& widthSize) const {
  496. return getTrailingPadding(axis, widthSize) +
  497. YGFloatOptional(getTrailingBorder(axis));
  498. }
  499. bool YGNode::didUseLegacyFlag() {
  500. bool didUseLegacyFlag = layout_.didUseLegacyFlag;
  501. if (didUseLegacyFlag) {
  502. return true;
  503. }
  504. for (const auto& child : children_) {
  505. if (child->layout_.didUseLegacyFlag) {
  506. didUseLegacyFlag = true;
  507. break;
  508. }
  509. }
  510. return didUseLegacyFlag;
  511. }
  512. void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
  513. config_->useLegacyStretchBehaviour = useLegacyFlag;
  514. for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
  515. childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
  516. });
  517. }
  518. void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
  519. bool doesLegacyFlagAffectsLayout) {
  520. layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
  521. }
  522. void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
  523. layout_.didUseLegacyFlag = didUseLegacyFlag;
  524. }
  525. bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
  526. if (children_.size() != node.children_.size()) {
  527. return false;
  528. }
  529. if (layout_ != node.layout_) {
  530. return false;
  531. }
  532. if (children_.size() == 0) {
  533. return true;
  534. }
  535. bool isLayoutTreeEqual = true;
  536. YGNodeRef otherNodeChildren = nullptr;
  537. for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
  538. otherNodeChildren = node.children_[i];
  539. isLayoutTreeEqual =
  540. children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
  541. if (!isLayoutTreeEqual) {
  542. return false;
  543. }
  544. }
  545. return isLayoutTreeEqual;
  546. }