YGNode.cpp 17 KB

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