Fix SVACE issue
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / third-party / yoga / YGNode.cpp
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
8 #include "YGNode.h"
9 #include <iostream>
10 #include "Utils.h"
11
12 void* YGNode::getContext() const {
13   return context_;
14 }
15
16 YGPrintFunc YGNode::getPrintFunc() const {
17   return print_;
18 }
19
20 bool YGNode::getHasNewLayout() const {
21   return hasNewLayout_;
22 }
23
24 YGNodeType YGNode::getNodeType() const {
25   return nodeType_;
26 }
27
28 YGMeasureFunc YGNode::getMeasure() const {
29   return measure_;
30 }
31
32 YGBaselineFunc YGNode::getBaseline() const {
33   return baseline_;
34 }
35
36 YGDirtiedFunc YGNode::getDirtied() const {
37   return dirtied_;
38 }
39
40 YGStyle& YGNode::getStyle() {
41   return style_;
42 }
43
44 YGLayout& YGNode::getLayout() {
45   return layout_;
46 }
47
48 uint32_t YGNode::getLineIndex() const {
49   return lineIndex_;
50 }
51
52 YGNodeRef YGNode::getOwner() const {
53   return owner_;
54 }
55
56 YGVector YGNode::getChildren() const {
57   return children_;
58 }
59
60 uint32_t YGNode::getChildrenCount() const {
61   return static_cast<uint32_t>(children_.size());
62 }
63
64 YGNodeRef YGNode::getChild(uint32_t index) const {
65   return children_.at(index);
66 }
67
68 YGNodeRef YGNode::getNextChild() const {
69   return nextChild_;
70 }
71
72 YGConfigRef YGNode::getConfig() const {
73   return config_;
74 }
75
76 bool YGNode::isDirty() const {
77   return isDirty_;
78 }
79
80 YGValue YGNode::getResolvedDimension(int index) {
81   return resolvedDimensions_[index];
82 }
83
84 std::array<YGValue, 2> YGNode::getResolvedDimensions() const {
85   return resolvedDimensions_;
86 }
87
88 YGFloatOptional YGNode::getLeadingPosition(
89     const YGFlexDirection& axis,
90     const float& axisSize) const {
91   if (YGFlexDirectionIsRow(axis)) {
92     const YGValue* leadingPosition =
93         YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined);
94     if (leadingPosition->unit != YGUnitUndefined) {
95       return YGResolveValue(*leadingPosition, axisSize);
96     }
97   }
98
99   const YGValue* leadingPosition =
100       YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined);
101
102   return leadingPosition->unit == YGUnitUndefined
103       ? YGFloatOptional(0)
104       : YGResolveValue(*leadingPosition, axisSize);
105 }
106
107 YGFloatOptional YGNode::getTrailingPosition(
108     const YGFlexDirection& axis,
109     const float& axisSize) const {
110   if (YGFlexDirectionIsRow(axis)) {
111     const YGValue* trailingPosition =
112         YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined);
113     if (trailingPosition->unit != YGUnitUndefined) {
114       return YGResolveValue(*trailingPosition, axisSize);
115     }
116   }
117
118   const YGValue* trailingPosition =
119       YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined);
120
121   return trailingPosition->unit == YGUnitUndefined
122       ? YGFloatOptional(0)
123       : YGResolveValue(*trailingPosition, axisSize);
124 }
125
126 bool YGNode::isLeadingPositionDefined(const YGFlexDirection& axis) const {
127   return (YGFlexDirectionIsRow(axis) &&
128           YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined)
129                   ->unit != YGUnitUndefined) ||
130       YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined)
131           ->unit != YGUnitUndefined;
132 }
133
134 bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const {
135   return (YGFlexDirectionIsRow(axis) &&
136           YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined)
137                   ->unit != YGUnitUndefined) ||
138       YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined)
139           ->unit != YGUnitUndefined;
140 }
141
142 YGFloatOptional YGNode::getLeadingMargin(
143     const YGFlexDirection& axis,
144     const float& widthSize) const {
145   if (YGFlexDirectionIsRow(axis) &&
146       style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
147     return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
148   }
149
150   return YGResolveValueMargin(
151       *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero),
152       widthSize);
153 }
154
155 YGFloatOptional YGNode::getTrailingMargin(
156     const YGFlexDirection& axis,
157     const float& widthSize) const {
158   if (YGFlexDirectionIsRow(axis) &&
159       style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
160     return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
161   }
162
163   return YGResolveValueMargin(
164       *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero),
165       widthSize);
166 }
167
168 YGFloatOptional YGNode::getMarginForAxis(
169     const YGFlexDirection& axis,
170     const float& widthSize) const {
171   return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
172 }
173
174 // Setters
175
176 void YGNode::setContext(void* context) {
177   context_ = context;
178 }
179
180 void YGNode::setPrintFunc(YGPrintFunc printFunc) {
181   print_ = printFunc;
182 }
183
184 void YGNode::setHasNewLayout(bool hasNewLayout) {
185   hasNewLayout_ = hasNewLayout;
186 }
187
188 void YGNode::setNodeType(YGNodeType nodeType) {
189   nodeType_ = nodeType;
190 }
191
192 void YGNode::setStyleFlexDirection(YGFlexDirection direction) {
193   style_.flexDirection = direction;
194 }
195
196 void YGNode::setStyleAlignContent(YGAlign alignContent) {
197   style_.alignContent = alignContent;
198 }
199
200 void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
201   if (measureFunc == nullptr) {
202     measure_ = nullptr;
203     // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
204     // places in Litho
205     nodeType_ = YGNodeTypeDefault;
206   } else {
207     YGAssertWithNode(
208         this,
209         children_.size() == 0,
210         "Cannot set measure function: Nodes with measure functions cannot have children.");
211     measure_ = measureFunc;
212     // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
213     // places in Litho
214     setNodeType(YGNodeTypeText);
215   }
216
217   measure_ = measureFunc;
218 }
219
220 void YGNode::setBaseLineFunc(YGBaselineFunc baseLineFunc) {
221   baseline_ = baseLineFunc;
222 }
223
224 void YGNode::setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
225   dirtied_ = dirtiedFunc;
226 }
227
228 void YGNode::setStyle(const YGStyle& style) {
229   style_ = style;
230 }
231
232 void YGNode::setLayout(const YGLayout& layout) {
233   layout_ = layout;
234 }
235
236 void YGNode::setLineIndex(uint32_t lineIndex) {
237   lineIndex_ = lineIndex;
238 }
239
240 void YGNode::setOwner(YGNodeRef owner) {
241   owner_ = owner;
242 }
243
244 void YGNode::setChildren(const YGVector& children) {
245   children_ = children;
246 }
247
248 void YGNode::setNextChild(YGNodeRef nextChild) {
249   nextChild_ = nextChild;
250 }
251
252 void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
253   children_[index] = child;
254 }
255
256 void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
257   std::replace(children_.begin(), children_.end(), oldChild, newChild);
258 }
259
260 void YGNode::insertChild(YGNodeRef child, uint32_t index) {
261   children_.insert(children_.begin() + index, child);
262 }
263
264 void YGNode::setConfig(YGConfigRef config) {
265   config_ = config;
266 }
267
268 void YGNode::setDirty(bool isDirty) {
269   if (isDirty == isDirty_) {
270     return;
271   }
272   isDirty_ = isDirty;
273   if (isDirty && dirtied_) {
274     dirtied_(this);
275   }
276 }
277
278 bool YGNode::removeChild(YGNodeRef child) {
279   std::vector<YGNodeRef>::iterator p =
280       std::find(children_.begin(), children_.end(), child);
281   if (p != children_.end()) {
282     children_.erase(p);
283     return true;
284   }
285   return false;
286 }
287
288 void YGNode::removeChild(uint32_t index) {
289   children_.erase(children_.begin() + index);
290 }
291
292 void YGNode::setLayoutDirection(YGDirection direction) {
293   layout_.direction = direction;
294 }
295
296 void YGNode::setLayoutMargin(float margin, int index) {
297   layout_.margin[index] = margin;
298 }
299
300 void YGNode::setLayoutBorder(float border, int index) {
301   layout_.border[index] = border;
302 }
303
304 void YGNode::setLayoutPadding(float padding, int index) {
305   layout_.padding[index] = padding;
306 }
307
308 void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
309   layout_.lastOwnerDirection = direction;
310 }
311
312 void YGNode::setLayoutComputedFlexBasis(
313     const YGFloatOptional& computedFlexBasis) {
314   layout_.computedFlexBasis = computedFlexBasis;
315 }
316
317 void YGNode::setLayoutPosition(float position, int index) {
318   layout_.position[index] = position;
319 }
320
321 void YGNode::setLayoutComputedFlexBasisGeneration(
322     uint32_t computedFlexBasisGeneration) {
323   layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
324 }
325
326 void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
327   layout_.measuredDimensions[index] = measuredDimension;
328 }
329
330 void YGNode::setLayoutHadOverflow(bool hadOverflow) {
331   layout_.hadOverflow = hadOverflow;
332 }
333
334 void YGNode::setLayoutDimension(float dimension, int index) {
335   layout_.dimensions[index] = dimension;
336 }
337
338 // If both left and right are defined, then use left. Otherwise return
339 // +left or -right depending on which is defined.
340 YGFloatOptional YGNode::relativePosition(
341     const YGFlexDirection& axis,
342     const float& axisSize) const {
343   if (isLeadingPositionDefined(axis)) {
344     return getLeadingPosition(axis, axisSize);
345   }
346
347   YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
348   if (!trailingPosition.isUndefined()) {
349     trailingPosition.setValue(-1 * trailingPosition.getValue());
350   }
351   return trailingPosition;
352 }
353
354 void YGNode::setPosition(
355     const YGDirection direction,
356     const float mainSize,
357     const float crossSize,
358     const float ownerWidth) {
359   /* Root nodes should be always layouted as LTR, so we don't return negative
360    * values. */
361   const YGDirection directionRespectingRoot =
362       owner_ != nullptr ? direction : YGDirectionLTR;
363   const YGFlexDirection mainAxis =
364       YGResolveFlexDirection(style_.flexDirection, directionRespectingRoot);
365   const YGFlexDirection crossAxis =
366       YGFlexDirectionCross(mainAxis, directionRespectingRoot);
367
368   const YGFloatOptional relativePositionMain =
369       relativePosition(mainAxis, mainSize);
370   const YGFloatOptional relativePositionCross =
371       relativePosition(crossAxis, crossSize);
372
373   setLayoutPosition(
374       YGUnwrapFloatOptional(
375           getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain),
376       leading[mainAxis]);
377   setLayoutPosition(
378       YGUnwrapFloatOptional(
379           getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain),
380       trailing[mainAxis]);
381   setLayoutPosition(
382       YGUnwrapFloatOptional(
383           getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross),
384       leading[crossAxis]);
385   setLayoutPosition(
386       YGUnwrapFloatOptional(
387           getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross),
388       trailing[crossAxis]);
389 }
390
391 YGNode::YGNode()
392     : context_(nullptr),
393       print_(nullptr),
394       hasNewLayout_(true),
395       nodeType_(YGNodeTypeDefault),
396       measure_(nullptr),
397       baseline_(nullptr),
398       dirtied_(nullptr),
399       style_(YGStyle()),
400       layout_(YGLayout()),
401       lineIndex_(0),
402       owner_(nullptr),
403       children_(YGVector()),
404       nextChild_(nullptr),
405       config_(nullptr),
406       isDirty_(false),
407       resolvedDimensions_(std::array<YGValue, 2>{YGValueUndefined, YGValueUndefined}) {}
408       /**
409        * In the original file, to initialize resolvedDimensions_ above, we usee { { YGValueUndefined, YGValueUndefined } }.
410        * But it is not well work, so we modified it.
411        */
412
413 YGNode::YGNode(const YGNode& node)
414     : context_(node.context_),
415       print_(node.print_),
416       hasNewLayout_(node.hasNewLayout_),
417       nodeType_(node.nodeType_),
418       measure_(node.measure_),
419       baseline_(node.baseline_),
420       dirtied_(node.dirtied_),
421       style_(node.style_),
422       layout_(node.layout_),
423       lineIndex_(node.lineIndex_),
424       owner_(node.owner_),
425       children_(node.children_),
426       nextChild_(node.nextChild_),
427       config_(node.config_),
428       isDirty_(node.isDirty_),
429       resolvedDimensions_(node.resolvedDimensions_) {}
430
431 YGNode::YGNode(const YGConfigRef newConfig) : YGNode() {
432   config_ = newConfig;
433 }
434
435 YGNode::YGNode(
436     void* context,
437     YGPrintFunc print,
438     bool hasNewLayout,
439     YGNodeType nodeType,
440     YGMeasureFunc measure,
441     YGBaselineFunc baseline,
442     YGDirtiedFunc dirtied,
443     const YGStyle& style,
444     const YGLayout& layout,
445     uint32_t lineIndex,
446     YGNodeRef owner,
447     const YGVector& children,
448     YGNodeRef nextChild,
449     YGConfigRef config,
450     bool isDirty,
451     std::array<YGValue, 2> resolvedDimensions)
452     : context_(context),
453       print_(print),
454       hasNewLayout_(hasNewLayout),
455       nodeType_(nodeType),
456       measure_(measure),
457       baseline_(baseline),
458       dirtied_(dirtied),
459       style_(style),
460       layout_(layout),
461       lineIndex_(lineIndex),
462       owner_(owner),
463       children_(children),
464       nextChild_(nextChild),
465       config_(config),
466       isDirty_(isDirty),
467       resolvedDimensions_(resolvedDimensions) {}
468
469 YGNode& YGNode::operator=(const YGNode& node) {
470   if (&node == this) {
471     return *this;
472   }
473
474   for (auto child : children_) {
475     delete child;
476   }
477
478   context_ = node.getContext();
479   print_ = node.getPrintFunc();
480   hasNewLayout_ = node.getHasNewLayout();
481   nodeType_ = node.getNodeType();
482   measure_ = node.getMeasure();
483   baseline_ = node.getBaseline();
484   dirtied_ = node.getDirtied();
485   style_ = node.style_;
486   layout_ = node.layout_;
487   lineIndex_ = node.getLineIndex();
488   owner_ = node.getOwner();
489   children_ = node.getChildren();
490   nextChild_ = node.getNextChild();
491   config_ = node.getConfig();
492   isDirty_ = node.isDirty();
493   resolvedDimensions_ = node.getResolvedDimensions();
494
495   return *this;
496 }
497
498 YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
499   if (YGFlexDirectionIsRow(axis) &&
500       style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
501     return style_.margin[YGEdgeStart];
502   } else {
503     return style_.margin[leading[axis]];
504   }
505 }
506
507 YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
508   if (YGFlexDirectionIsRow(axis) &&
509       style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
510     return style_.margin[YGEdgeEnd];
511   } else {
512     return style_.margin[trailing[axis]];
513   }
514 }
515
516 YGValue YGNode::resolveFlexBasisPtr() const {
517   YGValue flexBasis = style_.flexBasis;
518   if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
519     return flexBasis;
520   }
521   if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
522     return config_->useWebDefaults ? YGValueAuto : YGValueZero;
523   }
524   return YGValueAuto;
525 }
526
527 void YGNode::resolveDimension() {
528   for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
529     if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
530         YGValueEqual(
531             getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
532       resolvedDimensions_[dim] = style_.maxDimensions[dim];
533     } else {
534       resolvedDimensions_[dim] = style_.dimensions[dim];
535     }
536   }
537 }
538
539 YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
540   if (style_.direction == YGDirectionInherit) {
541     return ownerDirection > YGDirectionInherit ? ownerDirection
542                                                 : YGDirectionLTR;
543   } else {
544     return style_.direction;
545   }
546 }
547
548 void YGNode::clearChildren() {
549   children_.clear();
550   children_.shrink_to_fit();
551 }
552
553 YGNode::~YGNode() {
554   // All the member variables are deallocated externally, so no need to
555   // deallocate here
556 }
557
558 // Other Methods
559
560 void YGNode::cloneChildrenIfNeeded() {
561   // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm
562   // optimized for deletions.
563
564   const uint32_t childCount = static_cast<uint32_t>(children_.size());
565   if (childCount == 0) {
566     // This is an empty set. Nothing to clone.
567     return;
568   }
569
570   const YGNodeRef firstChild = children_.front();
571   if (firstChild->getOwner() == this) {
572     // If the first child has this node as its owner, we assume that it is
573     // already unique. We can do this because if we have it has a child, that
574     // means that its owner was at some point cloned which made that subtree
575     // immutable. We also assume that all its sibling are cloned as well.
576     return;
577   }
578
579   const YGCloneNodeFunc cloneNodeCallback = config_->cloneNodeCallback;
580   for (uint32_t i = 0; i < childCount; ++i) {
581     const YGNodeRef oldChild = children_[i];
582     YGNodeRef newChild = nullptr;
583     if (cloneNodeCallback) {
584       newChild = cloneNodeCallback(oldChild, this, i);
585     }
586     if (newChild == nullptr) {
587       newChild = YGNodeClone(oldChild);
588     }
589     replaceChild(newChild, i);
590     newChild->setOwner(this);
591   }
592 }
593
594 void YGNode::markDirtyAndPropogate() {
595   if (!isDirty_) {
596     setDirty(true);
597     setLayoutComputedFlexBasis(YGFloatOptional());
598     if (owner_) {
599       owner_->markDirtyAndPropogate();
600     }
601   }
602 }
603
604 void YGNode::markDirtyAndPropogateDownwards() {
605   isDirty_ = true;
606   for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
607     childNode->markDirtyAndPropogateDownwards();
608   });
609 }
610
611 float YGNode::resolveFlexGrow() {
612   // Root nodes flexGrow should always be 0
613   if (owner_ == nullptr) {
614     return 0.0;
615   }
616   if (!style_.flexGrow.isUndefined()) {
617     return style_.flexGrow.getValue();
618   }
619   if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
620     return style_.flex.getValue();
621   }
622   return kDefaultFlexGrow;
623 }
624
625 float YGNode::resolveFlexShrink() {
626   if (owner_ == nullptr) {
627     return 0.0;
628   }
629   if (!style_.flexShrink.isUndefined()) {
630     return style_.flexShrink.getValue();
631   }
632   if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
633       style_.flex.getValue() < 0.0f) {
634     return -style_.flex.getValue();
635   }
636   return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
637 }
638
639 bool YGNode::isNodeFlexible() {
640   return (
641       (style_.positionType == YGPositionTypeRelative) &&
642       (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
643 }
644
645 float YGNode::getLeadingBorder(const YGFlexDirection& axis) const {
646   if (YGFlexDirectionIsRow(axis) &&
647       style_.border[YGEdgeStart].unit != YGUnitUndefined &&
648       !YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
649       style_.border[YGEdgeStart].value >= 0.0f) {
650     return style_.border[YGEdgeStart].value;
651   }
652
653   float computedEdgeValue =
654       YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
655   return YGFloatMax(computedEdgeValue, 0.0f);
656 }
657
658 float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const {
659   if (YGFlexDirectionIsRow(flexDirection) &&
660       style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
661       !YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
662       style_.border[YGEdgeEnd].value >= 0.0f) {
663     return style_.border[YGEdgeEnd].value;
664   }
665
666   float computedEdgeValue =
667       YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
668           ->value;
669   return YGFloatMax(computedEdgeValue, 0.0f);
670 }
671
672 YGFloatOptional YGNode::getLeadingPadding(
673     const YGFlexDirection& axis,
674     const float& widthSize) const {
675   const YGFloatOptional& paddingEdgeStart =
676       YGResolveValue(style_.padding[YGEdgeStart], widthSize);
677   if (YGFlexDirectionIsRow(axis) &&
678       style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
679       !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) {
680     return paddingEdgeStart;
681   }
682
683   YGFloatOptional resolvedValue = YGResolveValue(
684       *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
685       widthSize);
686   return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
687 }
688
689 YGFloatOptional YGNode::getTrailingPadding(
690     const YGFlexDirection& axis,
691     const float& widthSize) const {
692   if (YGFlexDirectionIsRow(axis) &&
693       style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
694       !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
695       YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) {
696     return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
697   }
698
699   YGFloatOptional resolvedValue = YGResolveValue(
700       *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
701       widthSize);
702
703   return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
704 }
705
706 YGFloatOptional YGNode::getLeadingPaddingAndBorder(
707     const YGFlexDirection& axis,
708     const float& widthSize) const {
709   return getLeadingPadding(axis, widthSize) +
710       YGFloatOptional(getLeadingBorder(axis));
711 }
712
713 YGFloatOptional YGNode::getTrailingPaddingAndBorder(
714     const YGFlexDirection& axis,
715     const float& widthSize) const {
716   return getTrailingPadding(axis, widthSize) +
717       YGFloatOptional(getTrailingBorder(axis));
718 }
719
720 bool YGNode::didUseLegacyFlag() {
721   bool didUseLegacyFlag = layout_.didUseLegacyFlag;
722   if (didUseLegacyFlag) {
723     return true;
724   }
725   for (const auto& child : children_) {
726     if (child->layout_.didUseLegacyFlag) {
727       didUseLegacyFlag = true;
728       break;
729     }
730   }
731   return didUseLegacyFlag;
732 }
733
734 void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
735   config_->useLegacyStretchBehaviour = useLegacyFlag;
736   for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
737     childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
738   });
739 }
740
741 void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
742     bool doesLegacyFlagAffectsLayout) {
743   layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
744 }
745
746 void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
747   layout_.didUseLegacyFlag = didUseLegacyFlag;
748 }
749
750 bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
751   if (children_.size() != node.children_.size()) {
752     return false;
753   }
754   if (layout_ != node.layout_) {
755     return false;
756   }
757   if (children_.size() == 0) {
758     return true;
759   }
760
761   bool isLayoutTreeEqual = true;
762   YGNodeRef otherNodeChildren = nullptr;
763   for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
764     otherNodeChildren = node.children_[i];
765     isLayoutTreeEqual =
766         children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
767     if (!isLayoutTreeEqual) {
768       return false;
769     }
770   }
771   return isLayoutTreeEqual;
772 }