Yoga.cpp 160 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056
  1. /*
  2. * Copyright (c) 2014-present, Facebook, Inc.
  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. */
  8. #include "Yoga.h"
  9. #include <float.h>
  10. #include <string.h>
  11. #include <algorithm>
  12. #include "Utils.h"
  13. #include "YGNode.h"
  14. #include "YGNodePrint.h"
  15. #include "Yoga-internal.h"
  16. #ifdef _MSC_VER
  17. #include <float.h>
  18. /* define fmaxf if < VC12 */
  19. #if _MSC_VER < 1800
  20. __forceinline const float fmaxf(const float a, const float b) {
  21. if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
  22. return (a > b) ? a : b;
  23. }
  24. return YGFloatIsUndefined(a) ? b : a;
  25. }
  26. #endif
  27. #endif
  28. #ifdef ANDROID
  29. static int YGAndroidLog(const YGConfigRef config,
  30. const YGNodeRef node,
  31. YGLogLevel level,
  32. const char *format,
  33. va_list args);
  34. #else
  35. static int YGDefaultLog(const YGConfigRef config,
  36. const YGNodeRef node,
  37. YGLogLevel level,
  38. const char *format,
  39. va_list args);
  40. #endif
  41. const YGValue YGValueZero = {0, YGUnitPoint};
  42. const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
  43. const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
  44. #ifdef ANDROID
  45. #include <android/log.h>
  46. static int YGAndroidLog(const YGConfigRef config,
  47. const YGNodeRef node,
  48. YGLogLevel level,
  49. const char *format,
  50. va_list args) {
  51. int androidLevel = YGLogLevelDebug;
  52. switch (level) {
  53. case YGLogLevelFatal:
  54. androidLevel = ANDROID_LOG_FATAL;
  55. break;
  56. case YGLogLevelError:
  57. androidLevel = ANDROID_LOG_ERROR;
  58. break;
  59. case YGLogLevelWarn:
  60. androidLevel = ANDROID_LOG_WARN;
  61. break;
  62. case YGLogLevelInfo:
  63. androidLevel = ANDROID_LOG_INFO;
  64. break;
  65. case YGLogLevelDebug:
  66. androidLevel = ANDROID_LOG_DEBUG;
  67. break;
  68. case YGLogLevelVerbose:
  69. androidLevel = ANDROID_LOG_VERBOSE;
  70. break;
  71. }
  72. const int result = __android_log_vprint(androidLevel, "yoga", format, args);
  73. return result;
  74. }
  75. #else
  76. #define YG_UNUSED(x) (void)(x);
  77. static int YGDefaultLog(const YGConfigRef config,
  78. const YGNodeRef node,
  79. YGLogLevel level,
  80. const char *format,
  81. va_list args) {
  82. YG_UNUSED(config);
  83. YG_UNUSED(node);
  84. switch (level) {
  85. case YGLogLevelError:
  86. case YGLogLevelFatal:
  87. return vfprintf(stderr, format, args);
  88. case YGLogLevelWarn:
  89. case YGLogLevelInfo:
  90. case YGLogLevelDebug:
  91. case YGLogLevelVerbose:
  92. default:
  93. return vprintf(format, args);
  94. }
  95. }
  96. #undef YG_UNUSED
  97. #endif
  98. bool YGFloatIsUndefined(const float value) {
  99. // Value of a float in the case of it being not defined is 10.1E20. Earlier
  100. // it used to be NAN, the benefit of which was that if NAN is involved in any
  101. // mathematical expression the result was NAN. But since we want to have
  102. // `-ffast-math` flag being used by compiler which assumes that the floating
  103. // point values are not NAN and Inf, we represent YGUndefined as 10.1E20. But
  104. // now if YGUndefined is involved in any mathematical operations this
  105. // value(10.1E20) would change. So the following check makes sure that if the
  106. // value is outside a range (-10E8, 10E8) then it is undefined.
  107. return value >= 10E8 || value <= -10E8;
  108. }
  109. const YGValue* YGComputedEdgeValue(
  110. const std::array<YGValue, YGEdgeCount>& edges,
  111. const YGEdge edge,
  112. const YGValue* const defaultValue) {
  113. if (edges[edge].unit != YGUnitUndefined) {
  114. return &edges[edge];
  115. }
  116. if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
  117. edges[YGEdgeVertical].unit != YGUnitUndefined) {
  118. return &edges[YGEdgeVertical];
  119. }
  120. if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart || edge == YGEdgeEnd) &&
  121. edges[YGEdgeHorizontal].unit != YGUnitUndefined) {
  122. return &edges[YGEdgeHorizontal];
  123. }
  124. if (edges[YGEdgeAll].unit != YGUnitUndefined) {
  125. return &edges[YGEdgeAll];
  126. }
  127. if (edge == YGEdgeStart || edge == YGEdgeEnd) {
  128. return &YGValueUndefined;
  129. }
  130. return defaultValue;
  131. }
  132. void* YGNodeGetContext(YGNodeRef node) {
  133. return node->getContext();
  134. }
  135. void YGNodeSetContext(YGNodeRef node, void* context) {
  136. return node->setContext(context);
  137. }
  138. YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node) {
  139. return node->getMeasure();
  140. }
  141. void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
  142. node->setMeasureFunc(measureFunc);
  143. }
  144. YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node) {
  145. return node->getBaseline();
  146. }
  147. void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) {
  148. node->setBaseLineFunc(baselineFunc);
  149. }
  150. YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) {
  151. return node->getDirtied();
  152. }
  153. void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) {
  154. node->setDirtiedFunc(dirtiedFunc);
  155. }
  156. YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node) {
  157. return node->getPrintFunc();
  158. }
  159. void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
  160. node->setPrintFunc(printFunc);
  161. }
  162. bool YGNodeGetHasNewLayout(YGNodeRef node) {
  163. return node->getHasNewLayout();
  164. }
  165. void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
  166. node->setHasNewLayout(hasNewLayout);
  167. }
  168. YGNodeType YGNodeGetNodeType(YGNodeRef node) {
  169. return node->getNodeType();
  170. }
  171. void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) {
  172. return node->setNodeType(nodeType);
  173. }
  174. bool YGNodeIsDirty(YGNodeRef node) {
  175. return node->isDirty();
  176. }
  177. bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) {
  178. return node->didUseLegacyFlag();
  179. }
  180. void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) {
  181. return node->markDirtyAndPropogateDownwards();
  182. }
  183. int32_t gNodeInstanceCount = 0;
  184. int32_t gConfigInstanceCount = 0;
  185. WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
  186. const YGNodeRef node = new YGNode();
  187. YGAssertWithConfig(
  188. config, node != nullptr, "Could not allocate memory for node");
  189. gNodeInstanceCount++;
  190. if (config->useWebDefaults) {
  191. node->setStyleFlexDirection(YGFlexDirectionRow);
  192. node->setStyleAlignContent(YGAlignStretch);
  193. }
  194. node->setConfig(config);
  195. return node;
  196. }
  197. YGConfigRef YGConfigGetDefault() {
  198. static YGConfigRef defaultConfig = YGConfigNew();
  199. return defaultConfig;
  200. }
  201. YGNodeRef YGNodeNew(void) {
  202. return YGNodeNewWithConfig(YGConfigGetDefault());
  203. }
  204. YGNodeRef YGNodeClone(YGNodeRef oldNode) {
  205. YGNodeRef node = new YGNode(*oldNode);
  206. YGAssertWithConfig(
  207. oldNode->getConfig(),
  208. node != nullptr,
  209. "Could not allocate memory for node");
  210. gNodeInstanceCount++;
  211. node->setOwner(nullptr);
  212. return node;
  213. }
  214. static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
  215. const YGConfigRef config = new YGConfig(oldConfig);
  216. YGAssert(config != nullptr, "Could not allocate memory for config");
  217. if (config == nullptr) {
  218. abort();
  219. }
  220. gConfigInstanceCount++;
  221. return config;
  222. }
  223. static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
  224. YGNodeRef node = YGNodeClone(oldNode);
  225. YGVector vec = YGVector();
  226. vec.reserve(oldNode->getChildren().size());
  227. YGNodeRef childNode = nullptr;
  228. for (auto& item : oldNode->getChildren()) {
  229. childNode = YGNodeDeepClone(item);
  230. childNode->setOwner(node);
  231. vec.push_back(childNode);
  232. }
  233. node->setChildren(vec);
  234. if (oldNode->getConfig() != nullptr) {
  235. node->setConfig(YGConfigClone(*(oldNode->getConfig())));
  236. }
  237. return node;
  238. }
  239. void YGNodeFree(const YGNodeRef node) {
  240. if (YGNodeRef owner = node->getOwner()) {
  241. owner->removeChild(node);
  242. node->setOwner(nullptr);
  243. }
  244. const uint32_t childCount = YGNodeGetChildCount(node);
  245. for (uint32_t i = 0; i < childCount; i++) {
  246. const YGNodeRef child = YGNodeGetChild(node, i);
  247. child->setOwner(nullptr);
  248. }
  249. node->clearChildren();
  250. delete node;
  251. gNodeInstanceCount--;
  252. }
  253. static void YGConfigFreeRecursive(const YGNodeRef root) {
  254. if (root->getConfig() != nullptr) {
  255. gConfigInstanceCount--;
  256. delete root->getConfig();
  257. }
  258. // Delete configs recursively for childrens
  259. for (uint32_t i = 0; i < root->getChildrenCount(); ++i) {
  260. YGConfigFreeRecursive(root->getChild(i));
  261. }
  262. }
  263. void YGNodeFreeRecursive(const YGNodeRef root) {
  264. while (YGNodeGetChildCount(root) > 0) {
  265. const YGNodeRef child = YGNodeGetChild(root, 0);
  266. if (child->getOwner() != root) {
  267. // Don't free shared nodes that we don't own.
  268. break;
  269. }
  270. YGNodeRemoveChild(root, child);
  271. YGNodeFreeRecursive(child);
  272. }
  273. YGNodeFree(root);
  274. }
  275. void YGNodeReset(const YGNodeRef node) {
  276. YGAssertWithNode(node,
  277. YGNodeGetChildCount(node) == 0,
  278. "Cannot reset a node which still has children attached");
  279. YGAssertWithNode(
  280. node,
  281. node->getOwner() == nullptr,
  282. "Cannot reset a node still attached to a owner");
  283. node->clearChildren();
  284. const YGConfigRef config = node->getConfig();
  285. *node = YGNode();
  286. if (config->useWebDefaults) {
  287. node->setStyleFlexDirection(YGFlexDirectionRow);
  288. node->setStyleAlignContent(YGAlignStretch);
  289. }
  290. node->setConfig(config);
  291. }
  292. int32_t YGNodeGetInstanceCount(void) {
  293. return gNodeInstanceCount;
  294. }
  295. int32_t YGConfigGetInstanceCount(void) {
  296. return gConfigInstanceCount;
  297. }
  298. YGConfigRef YGConfigNew(void) {
  299. #ifdef ANDROID
  300. const YGConfigRef config = new YGConfig(YGAndroidLog);
  301. #else
  302. const YGConfigRef config = new YGConfig(YGDefaultLog);
  303. #endif
  304. gConfigInstanceCount++;
  305. return config;
  306. }
  307. void YGConfigFree(const YGConfigRef config) {
  308. free(config);
  309. gConfigInstanceCount--;
  310. }
  311. void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) {
  312. memcpy(dest, src, sizeof(YGConfig));
  313. }
  314. void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) {
  315. YGAssertWithNode(
  316. node,
  317. child->getOwner() == nullptr,
  318. "Child already has a owner, it must be removed first.");
  319. YGAssertWithNode(
  320. node,
  321. node->getMeasure() == nullptr,
  322. "Cannot add child: Nodes with measure functions cannot have children.");
  323. node->cloneChildrenIfNeeded();
  324. node->insertChild(child, index);
  325. YGNodeRef owner = child->getOwner() ? nullptr : node;
  326. child->setOwner(owner);
  327. node->markDirtyAndPropogate();
  328. }
  329. void YGNodeInsertSharedChild(
  330. const YGNodeRef node,
  331. const YGNodeRef child,
  332. const uint32_t index) {
  333. YGAssertWithNode(
  334. node,
  335. node->getMeasure() == nullptr,
  336. "Cannot add child: Nodes with measure functions cannot have children.");
  337. node->insertChild(child, index);
  338. child->setOwner(nullptr);
  339. node->markDirtyAndPropogate();
  340. }
  341. void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) {
  342. // This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode
  343. // that excludes a child.
  344. const uint32_t childCount = YGNodeGetChildCount(owner);
  345. if (childCount == 0) {
  346. // This is an empty set. Nothing to remove.
  347. return;
  348. }
  349. const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
  350. if (firstChild->getOwner() == owner) {
  351. // If the first child has this node as its owner, we assume that it is already unique.
  352. // We can now try to delete a child in this list.
  353. if (owner->removeChild(excludedChild)) {
  354. excludedChild->setLayout(
  355. YGNode().getLayout()); // layout is no longer valid
  356. excludedChild->setOwner(nullptr);
  357. owner->markDirtyAndPropogate();
  358. }
  359. return;
  360. }
  361. // Otherwise we have to clone the node list except for the child we're trying to delete.
  362. // We don't want to simply clone all children, because then the host will need to free
  363. // the clone of the child that was just deleted.
  364. const YGCloneNodeFunc cloneNodeCallback =
  365. owner->getConfig()->cloneNodeCallback;
  366. uint32_t nextInsertIndex = 0;
  367. for (uint32_t i = 0; i < childCount; i++) {
  368. const YGNodeRef oldChild = owner->getChild(i);
  369. if (excludedChild == oldChild) {
  370. // Ignore the deleted child. Don't reset its layout or owner since it is still valid
  371. // in the other owner. However, since this owner has now changed, we need to mark it
  372. // as dirty.
  373. owner->markDirtyAndPropogate();
  374. continue;
  375. }
  376. YGNodeRef newChild = nullptr;
  377. if (cloneNodeCallback) {
  378. newChild = cloneNodeCallback(oldChild, owner, nextInsertIndex);
  379. }
  380. if (newChild == nullptr) {
  381. newChild = YGNodeClone(oldChild);
  382. }
  383. owner->replaceChild(newChild, nextInsertIndex);
  384. newChild->setOwner(owner);
  385. nextInsertIndex++;
  386. }
  387. while (nextInsertIndex < childCount) {
  388. owner->removeChild(nextInsertIndex);
  389. nextInsertIndex++;
  390. }
  391. }
  392. void YGNodeRemoveAllChildren(const YGNodeRef owner) {
  393. const uint32_t childCount = YGNodeGetChildCount(owner);
  394. if (childCount == 0) {
  395. // This is an empty set already. Nothing to do.
  396. return;
  397. }
  398. const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
  399. if (firstChild->getOwner() == owner) {
  400. // If the first child has this node as its owner, we assume that this child set is unique.
  401. for (uint32_t i = 0; i < childCount; i++) {
  402. const YGNodeRef oldChild = YGNodeGetChild(owner, i);
  403. oldChild->setLayout(YGNode().getLayout()); // layout is no longer valid
  404. oldChild->setOwner(nullptr);
  405. }
  406. owner->clearChildren();
  407. owner->markDirtyAndPropogate();
  408. return;
  409. }
  410. // Otherwise, we are not the owner of the child set. We don't have to do anything to clear it.
  411. owner->setChildren(YGVector());
  412. owner->markDirtyAndPropogate();
  413. }
  414. static void YGNodeSetChildrenInternal(YGNodeRef const owner, const std::vector<YGNodeRef> &children)
  415. {
  416. if (!owner) {
  417. return;
  418. }
  419. if (children.size() == 0) {
  420. if (YGNodeGetChildCount(owner) > 0) {
  421. for (YGNodeRef const child : owner->getChildren()) {
  422. child->setLayout(YGLayout());
  423. child->setOwner(nullptr);
  424. }
  425. owner->setChildren(YGVector());
  426. owner->markDirtyAndPropogate();
  427. }
  428. } else {
  429. if (YGNodeGetChildCount(owner) > 0) {
  430. for (YGNodeRef const oldChild : owner->getChildren()) {
  431. // Our new children may have nodes in common with the old children. We don't reset these common nodes.
  432. if (std::find(children.begin(), children.end(), oldChild) == children.end()) {
  433. oldChild->setLayout(YGLayout());
  434. oldChild->setOwner(nullptr);
  435. }
  436. }
  437. }
  438. owner->setChildren(children);
  439. for (YGNodeRef child : children) {
  440. child->setOwner(owner);
  441. }
  442. owner->markDirtyAndPropogate();
  443. }
  444. }
  445. void YGNodeSetChildren(YGNodeRef const owner, const YGNodeRef c[], const uint32_t count) {
  446. const YGVector children = {c, c + count};
  447. YGNodeSetChildrenInternal(owner, children);
  448. }
  449. void YGNodeSetChildren(YGNodeRef const owner, const std::vector<YGNodeRef> &children)
  450. {
  451. YGNodeSetChildrenInternal(owner, children);
  452. }
  453. YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) {
  454. if (index < node->getChildren().size()) {
  455. return node->getChild(index);
  456. }
  457. return nullptr;
  458. }
  459. uint32_t YGNodeGetChildCount(const YGNodeRef node) {
  460. return static_cast<uint32_t>(node->getChildren().size());
  461. }
  462. YGNodeRef YGNodeGetOwner(const YGNodeRef node) {
  463. return node->getOwner();
  464. }
  465. YGNodeRef YGNodeGetParent(const YGNodeRef node) {
  466. return node->getOwner();
  467. }
  468. void YGNodeMarkDirty(const YGNodeRef node) {
  469. YGAssertWithNode(
  470. node,
  471. node->getMeasure() != nullptr,
  472. "Only leaf nodes with custom measure functions"
  473. "should manually mark themselves as dirty");
  474. node->markDirtyAndPropogate();
  475. }
  476. void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) {
  477. if (!(dstNode->getStyle() == srcNode->getStyle())) {
  478. dstNode->setStyle(srcNode->getStyle());
  479. dstNode->markDirtyAndPropogate();
  480. }
  481. }
  482. float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
  483. return node->getStyle().flexGrow.isUndefined()
  484. ? kDefaultFlexGrow
  485. : node->getStyle().flexGrow.getValue();
  486. }
  487. float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
  488. return node->getStyle().flexShrink.isUndefined()
  489. ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
  490. : kDefaultFlexShrink)
  491. : node->getStyle().flexShrink.getValue();
  492. }
  493. #define YG_NODE_STYLE_PROPERTY_SETTER_IMPL( \
  494. type, name, paramName, instanceName) \
  495. void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
  496. if (node->getStyle().instanceName != paramName) { \
  497. YGStyle style = node->getStyle(); \
  498. style.instanceName = paramName; \
  499. node->setStyle(style); \
  500. node->markDirtyAndPropogate(); \
  501. } \
  502. }
  503. #define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
  504. type, name, paramName, instanceName) \
  505. void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
  506. YGValue value = { \
  507. YGFloatSanitize(paramName), \
  508. YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
  509. }; \
  510. if ((node->getStyle().instanceName.value != value.value && \
  511. value.unit != YGUnitUndefined) || \
  512. node->getStyle().instanceName.unit != value.unit) { \
  513. YGStyle style = node->getStyle(); \
  514. style.instanceName = value; \
  515. node->setStyle(style); \
  516. node->markDirtyAndPropogate(); \
  517. } \
  518. } \
  519. \
  520. void YGNodeStyleSet##name##Percent( \
  521. const YGNodeRef node, const type paramName) { \
  522. YGValue value = { \
  523. YGFloatSanitize(paramName), \
  524. YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
  525. }; \
  526. if ((node->getStyle().instanceName.value != value.value && \
  527. value.unit != YGUnitUndefined) || \
  528. node->getStyle().instanceName.unit != value.unit) { \
  529. YGStyle style = node->getStyle(); \
  530. \
  531. style.instanceName = value; \
  532. node->setStyle(style); \
  533. node->markDirtyAndPropogate(); \
  534. } \
  535. }
  536. #define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
  537. type, name, paramName, instanceName) \
  538. void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
  539. YGValue value = { \
  540. YGFloatSanitize(paramName), \
  541. YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
  542. }; \
  543. if ((node->getStyle().instanceName.value != value.value && \
  544. value.unit != YGUnitUndefined) || \
  545. node->getStyle().instanceName.unit != value.unit) { \
  546. YGStyle style = node->getStyle(); \
  547. style.instanceName = value; \
  548. node->setStyle(style); \
  549. node->markDirtyAndPropogate(); \
  550. } \
  551. } \
  552. \
  553. void YGNodeStyleSet##name##Percent( \
  554. const YGNodeRef node, const type paramName) { \
  555. if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \
  556. node->getStyle().instanceName.unit != YGUnitPercent) { \
  557. YGStyle style = node->getStyle(); \
  558. style.instanceName.value = YGFloatSanitize(paramName); \
  559. style.instanceName.unit = \
  560. YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \
  561. node->setStyle(style); \
  562. node->markDirtyAndPropogate(); \
  563. } \
  564. } \
  565. \
  566. void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \
  567. if (node->getStyle().instanceName.unit != YGUnitAuto) { \
  568. YGStyle style = node->getStyle(); \
  569. style.instanceName.value = 0; \
  570. style.instanceName.unit = YGUnitAuto; \
  571. node->setStyle(style); \
  572. node->markDirtyAndPropogate(); \
  573. } \
  574. }
  575. #define YG_NODE_STYLE_PROPERTY_IMPL(type, name, paramName, instanceName) \
  576. YG_NODE_STYLE_PROPERTY_SETTER_IMPL(type, name, paramName, instanceName) \
  577. \
  578. type YGNodeStyleGet##name(const YGNodeRef node) { \
  579. return node->getStyle().instanceName; \
  580. }
  581. #define YG_NODE_STYLE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName) \
  582. YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
  583. float, name, paramName, instanceName) \
  584. \
  585. type YGNodeStyleGet##name(const YGNodeRef node) { \
  586. YGValue value = node->getStyle().instanceName; \
  587. if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
  588. value.value = YGUndefined; \
  589. } \
  590. return value; \
  591. }
  592. #define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \
  593. type, name, paramName, instanceName) \
  594. YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
  595. float, name, paramName, instanceName) \
  596. \
  597. type YGNodeStyleGet##name(const YGNodeRef node) { \
  598. YGValue value = node->getStyle().instanceName; \
  599. if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
  600. value.value = YGUndefined; \
  601. } \
  602. return value; \
  603. }
  604. #define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \
  605. void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
  606. if (node->getStyle().instanceName[edge].unit != YGUnitAuto) { \
  607. YGStyle style = node->getStyle(); \
  608. style.instanceName[edge].value = 0; \
  609. style.instanceName[edge].unit = YGUnitAuto; \
  610. node->setStyle(style); \
  611. node->markDirtyAndPropogate(); \
  612. } \
  613. }
  614. #define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL( \
  615. type, name, paramName, instanceName) \
  616. void YGNodeStyleSet##name( \
  617. const YGNodeRef node, const YGEdge edge, const float paramName) { \
  618. YGValue value = { \
  619. YGFloatSanitize(paramName), \
  620. YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
  621. }; \
  622. if ((node->getStyle().instanceName[edge].value != value.value && \
  623. value.unit != YGUnitUndefined) || \
  624. node->getStyle().instanceName[edge].unit != value.unit) { \
  625. YGStyle style = node->getStyle(); \
  626. style.instanceName[edge] = value; \
  627. node->setStyle(style); \
  628. node->markDirtyAndPropogate(); \
  629. } \
  630. } \
  631. \
  632. void YGNodeStyleSet##name##Percent( \
  633. const YGNodeRef node, const YGEdge edge, const float paramName) { \
  634. YGValue value = { \
  635. YGFloatSanitize(paramName), \
  636. YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
  637. }; \
  638. if ((node->getStyle().instanceName[edge].value != value.value && \
  639. value.unit != YGUnitUndefined) || \
  640. node->getStyle().instanceName[edge].unit != value.unit) { \
  641. YGStyle style = node->getStyle(); \
  642. style.instanceName[edge] = value; \
  643. node->setStyle(style); \
  644. node->markDirtyAndPropogate(); \
  645. } \
  646. } \
  647. \
  648. WIN_STRUCT(type) \
  649. YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \
  650. YGValue value = node->getStyle().instanceName[edge]; \
  651. if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
  652. value.value = YGUndefined; \
  653. } \
  654. return WIN_STRUCT_REF(value); \
  655. }
  656. #define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
  657. type YGNodeLayoutGet##name(const YGNodeRef node) { \
  658. return node->getLayout().instanceName; \
  659. }
  660. #define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \
  661. type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \
  662. YGAssertWithNode( \
  663. node, \
  664. edge <= YGEdgeEnd, \
  665. "Cannot get layout properties of multi-edge shorthands"); \
  666. \
  667. if (edge == YGEdgeLeft) { \
  668. if (node->getLayout().direction == YGDirectionRTL) { \
  669. return node->getLayout().instanceName[YGEdgeEnd]; \
  670. } else { \
  671. return node->getLayout().instanceName[YGEdgeStart]; \
  672. } \
  673. } \
  674. \
  675. if (edge == YGEdgeRight) { \
  676. if (node->getLayout().direction == YGDirectionRTL) { \
  677. return node->getLayout().instanceName[YGEdgeStart]; \
  678. } else { \
  679. return node->getLayout().instanceName[YGEdgeEnd]; \
  680. } \
  681. } \
  682. \
  683. return node->getLayout().instanceName[edge]; \
  684. }
  685. // YG_NODE_PROPERTY_IMPL(void *, Context, context, context);
  686. // YG_NODE_PROPERTY_IMPL(YGPrintFunc, PrintFunc, printFunc, print);
  687. // YG_NODE_PROPERTY_IMPL(bool, HasNewLayout, hasNewLayout, hasNewLayout);
  688. // YG_NODE_PROPERTY_IMPL(YGNodeType, NodeType, nodeType, nodeType);
  689. YG_NODE_STYLE_PROPERTY_IMPL(YGDirection, Direction, direction, direction);
  690. YG_NODE_STYLE_PROPERTY_IMPL(YGFlexDirection, FlexDirection, flexDirection, flexDirection);
  691. YG_NODE_STYLE_PROPERTY_IMPL(YGJustify, JustifyContent, justifyContent, justifyContent);
  692. YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignContent, alignContent, alignContent);
  693. YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignItems, alignItems, alignItems);
  694. YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignSelf, alignSelf, alignSelf);
  695. YG_NODE_STYLE_PROPERTY_IMPL(YGPositionType, PositionType, positionType, positionType);
  696. YG_NODE_STYLE_PROPERTY_IMPL(YGWrap, FlexWrap, flexWrap, flexWrap);
  697. YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow);
  698. YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display);
  699. // TODO(T26792433): Change the API to accept YGFloatOptional.
  700. void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
  701. if (node->getStyle().flex != flex) {
  702. YGStyle style = node->getStyle();
  703. if (YGFloatIsUndefined(flex)) {
  704. style.flex = YGFloatOptional();
  705. } else {
  706. style.flex = YGFloatOptional(flex);
  707. }
  708. node->setStyle(style);
  709. node->markDirtyAndPropogate();
  710. }
  711. }
  712. // TODO(T26792433): Change the API to accept YGFloatOptional.
  713. float YGNodeStyleGetFlex(const YGNodeRef node) {
  714. return node->getStyle().flex.isUndefined() ? YGUndefined
  715. : node->getStyle().flex.getValue();
  716. }
  717. // TODO(T26792433): Change the API to accept YGFloatOptional.
  718. void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
  719. if (node->getStyle().flexGrow != flexGrow) {
  720. YGStyle style = node->getStyle();
  721. if (YGFloatIsUndefined(flexGrow)) {
  722. style.flexGrow = YGFloatOptional();
  723. } else {
  724. style.flexGrow = YGFloatOptional(flexGrow);
  725. }
  726. node->setStyle(style);
  727. node->markDirtyAndPropogate();
  728. }
  729. }
  730. // TODO(T26792433): Change the API to accept YGFloatOptional.
  731. void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
  732. if (node->getStyle().flexShrink != flexShrink) {
  733. YGStyle style = node->getStyle();
  734. if (YGFloatIsUndefined(flexShrink)) {
  735. style.flexShrink = YGFloatOptional();
  736. } else {
  737. style.flexShrink = YGFloatOptional(flexShrink);
  738. }
  739. node->setStyle(style);
  740. node->markDirtyAndPropogate();
  741. }
  742. }
  743. YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) {
  744. YGValue flexBasis = node->getStyle().flexBasis;
  745. if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) {
  746. // TODO(T26792433): Get rid off the use of YGUndefined at client side
  747. flexBasis.value = YGUndefined;
  748. }
  749. return flexBasis;
  750. }
  751. void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
  752. YGValue value = {
  753. YGFloatSanitize(flexBasis),
  754. YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint,
  755. };
  756. if ((node->getStyle().flexBasis.value != value.value &&
  757. value.unit != YGUnitUndefined) ||
  758. node->getStyle().flexBasis.unit != value.unit) {
  759. YGStyle style = node->getStyle();
  760. style.flexBasis = value;
  761. node->setStyle(style);
  762. node->markDirtyAndPropogate();
  763. }
  764. }
  765. void YGNodeStyleSetFlexBasisPercent(
  766. const YGNodeRef node,
  767. const float flexBasisPercent) {
  768. if (node->getStyle().flexBasis.value != flexBasisPercent ||
  769. node->getStyle().flexBasis.unit != YGUnitPercent) {
  770. YGStyle style = node->getStyle();
  771. style.flexBasis.value = YGFloatSanitize(flexBasisPercent);
  772. style.flexBasis.unit =
  773. YGFloatIsUndefined(flexBasisPercent) ? YGUnitAuto : YGUnitPercent;
  774. node->setStyle(style);
  775. node->markDirtyAndPropogate();
  776. }
  777. }
  778. void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
  779. if (node->getStyle().flexBasis.unit != YGUnitAuto) {
  780. YGStyle style = node->getStyle();
  781. style.flexBasis.value = 0;
  782. style.flexBasis.unit = YGUnitAuto;
  783. node->setStyle(style);
  784. node->markDirtyAndPropogate();
  785. }
  786. }
  787. YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position);
  788. YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin);
  789. YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin);
  790. YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding);
  791. // TODO(T26792433): Change the API to accept YGFloatOptional.
  792. void YGNodeStyleSetBorder(
  793. const YGNodeRef node,
  794. const YGEdge edge,
  795. const float border) {
  796. YGValue value = {
  797. YGFloatSanitize(border),
  798. YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint,
  799. };
  800. if ((node->getStyle().border[edge].value != value.value &&
  801. value.unit != YGUnitUndefined) ||
  802. node->getStyle().border[edge].unit != value.unit) {
  803. YGStyle style = node->getStyle();
  804. style.border[edge] = value;
  805. node->setStyle(style);
  806. node->markDirtyAndPropogate();
  807. }
  808. }
  809. float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
  810. if (node->getStyle().border[edge].unit == YGUnitUndefined ||
  811. node->getStyle().border[edge].unit == YGUnitAuto) {
  812. // TODO(T26792433): Rather than returning YGUndefined, change the api to
  813. // return YGFloatOptional.
  814. return YGUndefined;
  815. }
  816. return node->getStyle().border[edge].value;
  817. }
  818. // Yoga specific properties, not compatible with flexbox specification
  819. // TODO(T26792433): Change the API to accept YGFloatOptional.
  820. float YGNodeStyleGetAspectRatio(const YGNodeRef node) {
  821. const YGFloatOptional op = node->getStyle().aspectRatio;
  822. return op.isUndefined() ? YGUndefined : op.getValue();
  823. }
  824. // TODO(T26792433): Change the API to accept YGFloatOptional.
  825. void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
  826. if (node->getStyle().aspectRatio != aspectRatio) {
  827. YGStyle style = node->getStyle();
  828. style.aspectRatio = YGFloatOptional(aspectRatio);
  829. node->setStyle(style);
  830. node->markDirtyAndPropogate();
  831. }
  832. }
  833. YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]);
  834. YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]);
  835. YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinWidth, minWidth, minDimensions[YGDimensionWidth]);
  836. YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinHeight, minHeight, minDimensions[YGDimensionHeight]);
  837. YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]);
  838. YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]);
  839. YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]);
  840. YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]);
  841. YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]);
  842. YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]);
  843. YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
  844. YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
  845. YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
  846. YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow);
  847. YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
  848. YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
  849. YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding);
  850. bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
  851. return node->getLayout().doesLegacyStretchFlagAffectsLayout;
  852. }
  853. uint32_t gCurrentGenerationCount = 0;
  854. bool YGLayoutNodeInternal(const YGNodeRef node,
  855. const float availableWidth,
  856. const float availableHeight,
  857. const YGDirection ownerDirection,
  858. const YGMeasureMode widthMeasureMode,
  859. const YGMeasureMode heightMeasureMode,
  860. const float ownerWidth,
  861. const float ownerHeight,
  862. const bool performLayout,
  863. const char *reason,
  864. const YGConfigRef config);
  865. static void YGNodePrintInternal(const YGNodeRef node,
  866. const YGPrintOptions options) {
  867. std::string str;
  868. facebook::yoga::YGNodeToString(&str, node, options, 0);
  869. YGLog(node, YGLogLevelDebug, str.c_str());
  870. }
  871. void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {
  872. YGNodePrintInternal(node, options);
  873. }
  874. const std::array<YGEdge, 4> leading = {
  875. {YGEdgeTop, YGEdgeBottom, YGEdgeLeft, YGEdgeRight}};
  876. const std::array<YGEdge, 4> trailing = {
  877. {YGEdgeBottom, YGEdgeTop, YGEdgeRight, YGEdgeLeft}};
  878. static const std::array<YGEdge, 4> pos = {{
  879. YGEdgeTop,
  880. YGEdgeBottom,
  881. YGEdgeLeft,
  882. YGEdgeRight,
  883. }};
  884. static const std::array<YGDimension, 4> dim = {
  885. {YGDimensionHeight, YGDimensionHeight, YGDimensionWidth, YGDimensionWidth}};
  886. static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node,
  887. const YGFlexDirection axis,
  888. const float widthSize) {
  889. return YGUnwrapFloatOptional(
  890. node->getLeadingPaddingAndBorder(axis, widthSize) +
  891. node->getTrailingPaddingAndBorder(axis, widthSize));
  892. }
  893. static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) {
  894. const YGAlign align = child->getStyle().alignSelf == YGAlignAuto
  895. ? node->getStyle().alignItems
  896. : child->getStyle().alignSelf;
  897. if (align == YGAlignBaseline &&
  898. YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
  899. return YGAlignFlexStart;
  900. }
  901. return align;
  902. }
  903. static float YGBaseline(const YGNodeRef node) {
  904. if (node->getBaseline() != nullptr) {
  905. const float baseline = node->getBaseline()(
  906. node,
  907. node->getLayout().measuredDimensions[YGDimensionWidth],
  908. node->getLayout().measuredDimensions[YGDimensionHeight]);
  909. YGAssertWithNode(node,
  910. !YGFloatIsUndefined(baseline),
  911. "Expect custom baseline function to not return NaN");
  912. return baseline;
  913. }
  914. YGNodeRef baselineChild = nullptr;
  915. const uint32_t childCount = YGNodeGetChildCount(node);
  916. for (uint32_t i = 0; i < childCount; i++) {
  917. const YGNodeRef child = YGNodeGetChild(node, i);
  918. if (child->getLineIndex() > 0) {
  919. break;
  920. }
  921. if (child->getStyle().positionType == YGPositionTypeAbsolute) {
  922. continue;
  923. }
  924. if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
  925. baselineChild = child;
  926. break;
  927. }
  928. if (baselineChild == nullptr) {
  929. baselineChild = child;
  930. }
  931. }
  932. if (baselineChild == nullptr) {
  933. return node->getLayout().measuredDimensions[YGDimensionHeight];
  934. }
  935. const float baseline = YGBaseline(baselineChild);
  936. return baseline + baselineChild->getLayout().position[YGEdgeTop];
  937. }
  938. static bool YGIsBaselineLayout(const YGNodeRef node) {
  939. if (YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
  940. return false;
  941. }
  942. if (node->getStyle().alignItems == YGAlignBaseline) {
  943. return true;
  944. }
  945. const uint32_t childCount = YGNodeGetChildCount(node);
  946. for (uint32_t i = 0; i < childCount; i++) {
  947. const YGNodeRef child = YGNodeGetChild(node, i);
  948. if (child->getStyle().positionType == YGPositionTypeRelative &&
  949. child->getStyle().alignSelf == YGAlignBaseline) {
  950. return true;
  951. }
  952. }
  953. return false;
  954. }
  955. static inline float YGNodeDimWithMargin(const YGNodeRef node,
  956. const YGFlexDirection axis,
  957. const float widthSize) {
  958. return node->getLayout().measuredDimensions[dim[axis]] +
  959. YGUnwrapFloatOptional(
  960. node->getLeadingMargin(axis, widthSize) +
  961. node->getTrailingMargin(axis, widthSize));
  962. }
  963. static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node,
  964. const YGFlexDirection axis,
  965. const float ownerSize) {
  966. bool isUndefined =
  967. YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value);
  968. return !(
  969. node->getResolvedDimension(dim[axis]).unit == YGUnitAuto ||
  970. node->getResolvedDimension(dim[axis]).unit == YGUnitUndefined ||
  971. (node->getResolvedDimension(dim[axis]).unit == YGUnitPoint &&
  972. !isUndefined && node->getResolvedDimension(dim[axis]).value < 0.0f) ||
  973. (node->getResolvedDimension(dim[axis]).unit == YGUnitPercent &&
  974. !isUndefined &&
  975. (node->getResolvedDimension(dim[axis]).value < 0.0f ||
  976. YGFloatIsUndefined(ownerSize))));
  977. }
  978. static inline bool YGNodeIsLayoutDimDefined(const YGNodeRef node, const YGFlexDirection axis) {
  979. const float value = node->getLayout().measuredDimensions[dim[axis]];
  980. return !YGFloatIsUndefined(value) && value >= 0.0f;
  981. }
  982. static YGFloatOptional YGNodeBoundAxisWithinMinAndMax(
  983. const YGNodeRef node,
  984. const YGFlexDirection& axis,
  985. const float& value,
  986. const float& axisSize) {
  987. YGFloatOptional min;
  988. YGFloatOptional max;
  989. if (YGFlexDirectionIsColumn(axis)) {
  990. min = YGResolveValue(
  991. node->getStyle().minDimensions[YGDimensionHeight], axisSize);
  992. max = YGResolveValue(
  993. node->getStyle().maxDimensions[YGDimensionHeight], axisSize);
  994. } else if (YGFlexDirectionIsRow(axis)) {
  995. min = YGResolveValue(
  996. node->getStyle().minDimensions[YGDimensionWidth], axisSize);
  997. max = YGResolveValue(
  998. node->getStyle().maxDimensions[YGDimensionWidth], axisSize);
  999. }
  1000. if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) {
  1001. return max;
  1002. }
  1003. if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) {
  1004. return min;
  1005. }
  1006. return YGFloatOptional(value);
  1007. }
  1008. // Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't go
  1009. // below the
  1010. // padding and border amount.
  1011. static inline float YGNodeBoundAxis(const YGNodeRef node,
  1012. const YGFlexDirection axis,
  1013. const float value,
  1014. const float axisSize,
  1015. const float widthSize) {
  1016. return YGFloatMax(
  1017. YGUnwrapFloatOptional(
  1018. YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)),
  1019. YGNodePaddingAndBorderForAxis(node, axis, widthSize));
  1020. }
  1021. static void YGNodeSetChildTrailingPosition(const YGNodeRef node,
  1022. const YGNodeRef child,
  1023. const YGFlexDirection axis) {
  1024. const float size = child->getLayout().measuredDimensions[dim[axis]];
  1025. child->setLayoutPosition(
  1026. node->getLayout().measuredDimensions[dim[axis]] - size -
  1027. child->getLayout().position[pos[axis]],
  1028. trailing[axis]);
  1029. }
  1030. static void YGConstrainMaxSizeForMode(const YGNodeRef node,
  1031. const enum YGFlexDirection axis,
  1032. const float ownerAxisSize,
  1033. const float ownerWidth,
  1034. YGMeasureMode *mode,
  1035. float *size) {
  1036. const YGFloatOptional maxSize =
  1037. YGResolveValue(
  1038. node->getStyle().maxDimensions[dim[axis]], ownerAxisSize) +
  1039. YGFloatOptional(node->getMarginForAxis(axis, ownerWidth));
  1040. switch (*mode) {
  1041. case YGMeasureModeExactly:
  1042. case YGMeasureModeAtMost:
  1043. *size = (maxSize.isUndefined() || *size < maxSize.getValue())
  1044. ? *size
  1045. : maxSize.getValue();
  1046. break;
  1047. case YGMeasureModeUndefined:
  1048. if (!maxSize.isUndefined()) {
  1049. *mode = YGMeasureModeAtMost;
  1050. *size = maxSize.getValue();
  1051. }
  1052. break;
  1053. }
  1054. }
  1055. static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
  1056. const YGNodeRef child,
  1057. const float width,
  1058. const YGMeasureMode widthMode,
  1059. const float height,
  1060. const float ownerWidth,
  1061. const float ownerHeight,
  1062. const YGMeasureMode heightMode,
  1063. const YGDirection direction,
  1064. const YGConfigRef config) {
  1065. const YGFlexDirection mainAxis =
  1066. YGResolveFlexDirection(node->getStyle().flexDirection, direction);
  1067. const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
  1068. const float mainAxisSize = isMainAxisRow ? width : height;
  1069. const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
  1070. float childWidth;
  1071. float childHeight;
  1072. YGMeasureMode childWidthMeasureMode;
  1073. YGMeasureMode childHeightMeasureMode;
  1074. const YGFloatOptional resolvedFlexBasis =
  1075. YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize);
  1076. const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth);
  1077. const bool isColumnStyleDimDefined =
  1078. YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight);
  1079. if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) {
  1080. if (child->getLayout().computedFlexBasis.isUndefined() ||
  1081. (YGConfigIsExperimentalFeatureEnabled(
  1082. child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
  1083. child->getLayout().computedFlexBasisGeneration !=
  1084. gCurrentGenerationCount)) {
  1085. const YGFloatOptional& paddingAndBorder = YGFloatOptional(
  1086. YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth));
  1087. child->setLayoutComputedFlexBasis(
  1088. YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder));
  1089. }
  1090. } else if (isMainAxisRow && isRowStyleDimDefined) {
  1091. // The width is definite, so use that as the flex basis.
  1092. const YGFloatOptional& paddingAndBorder = YGFloatOptional(
  1093. YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth));
  1094. child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
  1095. YGResolveValue(
  1096. child->getResolvedDimension(YGDimensionWidth), ownerWidth),
  1097. paddingAndBorder));
  1098. } else if (!isMainAxisRow && isColumnStyleDimDefined) {
  1099. // The height is definite, so use that as the flex basis.
  1100. const YGFloatOptional& paddingAndBorder =
  1101. YGFloatOptional(YGNodePaddingAndBorderForAxis(
  1102. child, YGFlexDirectionColumn, ownerWidth));
  1103. child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
  1104. YGResolveValue(
  1105. child->getResolvedDimension(YGDimensionHeight), ownerHeight),
  1106. paddingAndBorder));
  1107. } else {
  1108. // Compute the flex basis and hypothetical main size (i.e. the clamped
  1109. // flex basis).
  1110. childWidth = YGUndefined;
  1111. childHeight = YGUndefined;
  1112. childWidthMeasureMode = YGMeasureModeUndefined;
  1113. childHeightMeasureMode = YGMeasureModeUndefined;
  1114. const float& marginRow = YGUnwrapFloatOptional(
  1115. child->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
  1116. const float& marginColumn = YGUnwrapFloatOptional(
  1117. child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
  1118. if (isRowStyleDimDefined) {
  1119. childWidth =
  1120. YGUnwrapFloatOptional(YGResolveValue(
  1121. child->getResolvedDimension(YGDimensionWidth), ownerWidth)) +
  1122. marginRow;
  1123. childWidthMeasureMode = YGMeasureModeExactly;
  1124. }
  1125. if (isColumnStyleDimDefined) {
  1126. childHeight =
  1127. YGUnwrapFloatOptional(YGResolveValue(
  1128. child->getResolvedDimension(YGDimensionHeight), ownerHeight)) +
  1129. marginColumn;
  1130. childHeightMeasureMode = YGMeasureModeExactly;
  1131. }
  1132. // The W3C spec doesn't say anything about the 'overflow' property,
  1133. // but all major browsers appear to implement the following logic.
  1134. if ((!isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
  1135. node->getStyle().overflow != YGOverflowScroll) {
  1136. if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) {
  1137. childWidth = width;
  1138. childWidthMeasureMode = YGMeasureModeAtMost;
  1139. }
  1140. }
  1141. if ((isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
  1142. node->getStyle().overflow != YGOverflowScroll) {
  1143. if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) {
  1144. childHeight = height;
  1145. childHeightMeasureMode = YGMeasureModeAtMost;
  1146. }
  1147. }
  1148. if (!child->getStyle().aspectRatio.isUndefined()) {
  1149. if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) {
  1150. childHeight = marginColumn +
  1151. (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
  1152. childHeightMeasureMode = YGMeasureModeExactly;
  1153. } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
  1154. childWidth = marginRow +
  1155. (childHeight - marginColumn) *
  1156. child->getStyle().aspectRatio.getValue();
  1157. childWidthMeasureMode = YGMeasureModeExactly;
  1158. }
  1159. }
  1160. // If child has no defined size in the cross axis and is set to stretch,
  1161. // set the cross
  1162. // axis to be measured exactly with the available inner width
  1163. const bool hasExactWidth = !YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly;
  1164. const bool childWidthStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
  1165. childWidthMeasureMode != YGMeasureModeExactly;
  1166. if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) {
  1167. childWidth = width;
  1168. childWidthMeasureMode = YGMeasureModeExactly;
  1169. if (!child->getStyle().aspectRatio.isUndefined()) {
  1170. childHeight =
  1171. (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
  1172. childHeightMeasureMode = YGMeasureModeExactly;
  1173. }
  1174. }
  1175. const bool hasExactHeight = !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly;
  1176. const bool childHeightStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
  1177. childHeightMeasureMode != YGMeasureModeExactly;
  1178. if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && childHeightStretch) {
  1179. childHeight = height;
  1180. childHeightMeasureMode = YGMeasureModeExactly;
  1181. if (!child->getStyle().aspectRatio.isUndefined()) {
  1182. childWidth = (childHeight - marginColumn) *
  1183. child->getStyle().aspectRatio.getValue();
  1184. childWidthMeasureMode = YGMeasureModeExactly;
  1185. }
  1186. }
  1187. YGConstrainMaxSizeForMode(
  1188. child, YGFlexDirectionRow, ownerWidth, ownerWidth, &childWidthMeasureMode, &childWidth);
  1189. YGConstrainMaxSizeForMode(child,
  1190. YGFlexDirectionColumn,
  1191. ownerHeight,
  1192. ownerWidth,
  1193. &childHeightMeasureMode,
  1194. &childHeight);
  1195. // Measure the child
  1196. YGLayoutNodeInternal(child,
  1197. childWidth,
  1198. childHeight,
  1199. direction,
  1200. childWidthMeasureMode,
  1201. childHeightMeasureMode,
  1202. ownerWidth,
  1203. ownerHeight,
  1204. false,
  1205. "measure",
  1206. config);
  1207. child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax(
  1208. child->getLayout().measuredDimensions[dim[mainAxis]],
  1209. YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))));
  1210. }
  1211. child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
  1212. }
  1213. static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
  1214. const YGNodeRef child,
  1215. const float width,
  1216. const YGMeasureMode widthMode,
  1217. const float height,
  1218. const YGDirection direction,
  1219. const YGConfigRef config) {
  1220. const YGFlexDirection mainAxis =
  1221. YGResolveFlexDirection(node->getStyle().flexDirection, direction);
  1222. const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
  1223. const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
  1224. float childWidth = YGUndefined;
  1225. float childHeight = YGUndefined;
  1226. YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined;
  1227. YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined;
  1228. const float& marginRow =
  1229. YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width));
  1230. const float& marginColumn = YGUnwrapFloatOptional(
  1231. child->getMarginForAxis(YGFlexDirectionColumn, width));
  1232. if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
  1233. childWidth =
  1234. YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)) +
  1235. marginRow;
  1236. } else {
  1237. // If the child doesn't have a specified width, compute the width based
  1238. // on the left/right
  1239. // offsets if they're defined.
  1240. if (child->isLeadingPositionDefined(YGFlexDirectionRow) &&
  1241. child->isTrailingPosDefined(YGFlexDirectionRow)) {
  1242. childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] -
  1243. (node->getLeadingBorder(YGFlexDirectionRow) +
  1244. node->getTrailingBorder(YGFlexDirectionRow)) -
  1245. YGUnwrapFloatOptional(
  1246. child->getLeadingPosition(YGFlexDirectionRow, width) +
  1247. child->getTrailingPosition(YGFlexDirectionRow, width));
  1248. childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
  1249. }
  1250. }
  1251. if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
  1252. childHeight =
  1253. YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)) +
  1254. marginColumn;
  1255. } else {
  1256. // If the child doesn't have a specified height, compute the height
  1257. // based on the top/bottom
  1258. // offsets if they're defined.
  1259. if (child->isLeadingPositionDefined(YGFlexDirectionColumn) &&
  1260. child->isTrailingPosDefined(YGFlexDirectionColumn)) {
  1261. childHeight =
  1262. node->getLayout().measuredDimensions[YGDimensionHeight] -
  1263. (node->getLeadingBorder(YGFlexDirectionColumn) +
  1264. node->getTrailingBorder(YGFlexDirectionColumn)) -
  1265. YGUnwrapFloatOptional(
  1266. child->getLeadingPosition(YGFlexDirectionColumn, height) +
  1267. child->getTrailingPosition(YGFlexDirectionColumn, height));
  1268. childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight, height, width);
  1269. }
  1270. }
  1271. // Exactly one dimension needs to be defined for us to be able to do aspect ratio
  1272. // calculation. One dimension being the anchor and the other being flexible.
  1273. if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) {
  1274. if (!child->getStyle().aspectRatio.isUndefined()) {
  1275. if (YGFloatIsUndefined(childWidth)) {
  1276. childWidth = marginRow +
  1277. (childHeight - marginColumn) *
  1278. child->getStyle().aspectRatio.getValue();
  1279. } else if (YGFloatIsUndefined(childHeight)) {
  1280. childHeight = marginColumn +
  1281. (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
  1282. }
  1283. }
  1284. }
  1285. // If we're still missing one or the other dimension, measure the content.
  1286. if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) {
  1287. childWidthMeasureMode =
  1288. YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly;
  1289. childHeightMeasureMode =
  1290. YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly;
  1291. // If the size of the owner is defined then try to constrain the absolute child to that size
  1292. // as well. This allows text within the absolute child to wrap to the size of its owner.
  1293. // This is the same behavior as many browsers implement.
  1294. if (!isMainAxisRow && YGFloatIsUndefined(childWidth) &&
  1295. widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) &&
  1296. width > 0) {
  1297. childWidth = width;
  1298. childWidthMeasureMode = YGMeasureModeAtMost;
  1299. }
  1300. YGLayoutNodeInternal(child,
  1301. childWidth,
  1302. childHeight,
  1303. direction,
  1304. childWidthMeasureMode,
  1305. childHeightMeasureMode,
  1306. childWidth,
  1307. childHeight,
  1308. false,
  1309. "abs-measure",
  1310. config);
  1311. childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] +
  1312. YGUnwrapFloatOptional(
  1313. child->getMarginForAxis(YGFlexDirectionRow, width));
  1314. childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] +
  1315. YGUnwrapFloatOptional(
  1316. child->getMarginForAxis(YGFlexDirectionColumn, width));
  1317. }
  1318. YGLayoutNodeInternal(child,
  1319. childWidth,
  1320. childHeight,
  1321. direction,
  1322. YGMeasureModeExactly,
  1323. YGMeasureModeExactly,
  1324. childWidth,
  1325. childHeight,
  1326. true,
  1327. "abs-layout",
  1328. config);
  1329. if (child->isTrailingPosDefined(mainAxis) &&
  1330. !child->isLeadingPositionDefined(mainAxis)) {
  1331. child->setLayoutPosition(
  1332. node->getLayout().measuredDimensions[dim[mainAxis]] -
  1333. child->getLayout().measuredDimensions[dim[mainAxis]] -
  1334. node->getTrailingBorder(mainAxis) -
  1335. YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) -
  1336. YGUnwrapFloatOptional(child->getTrailingPosition(
  1337. mainAxis, isMainAxisRow ? width : height)),
  1338. leading[mainAxis]);
  1339. } else if (
  1340. !child->isLeadingPositionDefined(mainAxis) &&
  1341. node->getStyle().justifyContent == YGJustifyCenter) {
  1342. child->setLayoutPosition(
  1343. (node->getLayout().measuredDimensions[dim[mainAxis]] -
  1344. child->getLayout().measuredDimensions[dim[mainAxis]]) /
  1345. 2.0f,
  1346. leading[mainAxis]);
  1347. } else if (
  1348. !child->isLeadingPositionDefined(mainAxis) &&
  1349. node->getStyle().justifyContent == YGJustifyFlexEnd) {
  1350. child->setLayoutPosition(
  1351. (node->getLayout().measuredDimensions[dim[mainAxis]] -
  1352. child->getLayout().measuredDimensions[dim[mainAxis]]),
  1353. leading[mainAxis]);
  1354. }
  1355. if (child->isTrailingPosDefined(crossAxis) &&
  1356. !child->isLeadingPositionDefined(crossAxis)) {
  1357. child->setLayoutPosition(
  1358. node->getLayout().measuredDimensions[dim[crossAxis]] -
  1359. child->getLayout().measuredDimensions[dim[crossAxis]] -
  1360. node->getTrailingBorder(crossAxis) -
  1361. YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) -
  1362. YGUnwrapFloatOptional(child->getTrailingPosition(
  1363. crossAxis, isMainAxisRow ? height : width)),
  1364. leading[crossAxis]);
  1365. } else if (
  1366. !child->isLeadingPositionDefined(crossAxis) &&
  1367. YGNodeAlignItem(node, child) == YGAlignCenter) {
  1368. child->setLayoutPosition(
  1369. (node->getLayout().measuredDimensions[dim[crossAxis]] -
  1370. child->getLayout().measuredDimensions[dim[crossAxis]]) /
  1371. 2.0f,
  1372. leading[crossAxis]);
  1373. } else if (
  1374. !child->isLeadingPositionDefined(crossAxis) &&
  1375. ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^
  1376. (node->getStyle().flexWrap == YGWrapWrapReverse))) {
  1377. child->setLayoutPosition(
  1378. (node->getLayout().measuredDimensions[dim[crossAxis]] -
  1379. child->getLayout().measuredDimensions[dim[crossAxis]]),
  1380. leading[crossAxis]);
  1381. }
  1382. }
  1383. static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node,
  1384. const float availableWidth,
  1385. const float availableHeight,
  1386. const YGMeasureMode widthMeasureMode,
  1387. const YGMeasureMode heightMeasureMode,
  1388. const float ownerWidth,
  1389. const float ownerHeight) {
  1390. YGAssertWithNode(
  1391. node,
  1392. node->getMeasure() != nullptr,
  1393. "Expected node to have custom measure function");
  1394. const float paddingAndBorderAxisRow =
  1395. YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
  1396. const float paddingAndBorderAxisColumn =
  1397. YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, availableWidth);
  1398. const float marginAxisRow = YGUnwrapFloatOptional(
  1399. node->getMarginForAxis(YGFlexDirectionRow, availableWidth));
  1400. const float marginAxisColumn = YGUnwrapFloatOptional(
  1401. node->getMarginForAxis(YGFlexDirectionColumn, availableWidth));
  1402. // We want to make sure we don't call measure with negative size
  1403. const float innerWidth = YGFloatIsUndefined(availableWidth)
  1404. ? availableWidth
  1405. : YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
  1406. const float innerHeight = YGFloatIsUndefined(availableHeight)
  1407. ? availableHeight
  1408. : YGFloatMax(
  1409. 0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
  1410. if (widthMeasureMode == YGMeasureModeExactly &&
  1411. heightMeasureMode == YGMeasureModeExactly) {
  1412. // Don't bother sizing the text if both dimensions are already defined.
  1413. node->setLayoutMeasuredDimension(
  1414. YGNodeBoundAxis(
  1415. node,
  1416. YGFlexDirectionRow,
  1417. availableWidth - marginAxisRow,
  1418. ownerWidth,
  1419. ownerWidth),
  1420. YGDimensionWidth);
  1421. node->setLayoutMeasuredDimension(
  1422. YGNodeBoundAxis(
  1423. node,
  1424. YGFlexDirectionColumn,
  1425. availableHeight - marginAxisColumn,
  1426. ownerHeight,
  1427. ownerWidth),
  1428. YGDimensionHeight);
  1429. } else {
  1430. // Measure the text under the current constraints.
  1431. const YGSize measuredSize = node->getMeasure()(
  1432. node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode);
  1433. node->setLayoutMeasuredDimension(
  1434. YGNodeBoundAxis(
  1435. node,
  1436. YGFlexDirectionRow,
  1437. (widthMeasureMode == YGMeasureModeUndefined ||
  1438. widthMeasureMode == YGMeasureModeAtMost)
  1439. ? measuredSize.width + paddingAndBorderAxisRow
  1440. : availableWidth - marginAxisRow,
  1441. ownerWidth,
  1442. ownerWidth),
  1443. YGDimensionWidth);
  1444. node->setLayoutMeasuredDimension(
  1445. YGNodeBoundAxis(
  1446. node,
  1447. YGFlexDirectionColumn,
  1448. (heightMeasureMode == YGMeasureModeUndefined ||
  1449. heightMeasureMode == YGMeasureModeAtMost)
  1450. ? measuredSize.height + paddingAndBorderAxisColumn
  1451. : availableHeight - marginAxisColumn,
  1452. ownerHeight,
  1453. ownerWidth),
  1454. YGDimensionHeight);
  1455. }
  1456. }
  1457. // For nodes with no children, use the available values if they were provided,
  1458. // or the minimum size as indicated by the padding and border sizes.
  1459. static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node,
  1460. const float availableWidth,
  1461. const float availableHeight,
  1462. const YGMeasureMode widthMeasureMode,
  1463. const YGMeasureMode heightMeasureMode,
  1464. const float ownerWidth,
  1465. const float ownerHeight) {
  1466. const float paddingAndBorderAxisRow =
  1467. YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth);
  1468. const float paddingAndBorderAxisColumn =
  1469. YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth);
  1470. const float marginAxisRow = YGUnwrapFloatOptional(
  1471. node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
  1472. const float marginAxisColumn = YGUnwrapFloatOptional(
  1473. node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
  1474. node->setLayoutMeasuredDimension(
  1475. YGNodeBoundAxis(
  1476. node,
  1477. YGFlexDirectionRow,
  1478. (widthMeasureMode == YGMeasureModeUndefined ||
  1479. widthMeasureMode == YGMeasureModeAtMost)
  1480. ? paddingAndBorderAxisRow
  1481. : availableWidth - marginAxisRow,
  1482. ownerWidth,
  1483. ownerWidth),
  1484. YGDimensionWidth);
  1485. node->setLayoutMeasuredDimension(
  1486. YGNodeBoundAxis(
  1487. node,
  1488. YGFlexDirectionColumn,
  1489. (heightMeasureMode == YGMeasureModeUndefined ||
  1490. heightMeasureMode == YGMeasureModeAtMost)
  1491. ? paddingAndBorderAxisColumn
  1492. : availableHeight - marginAxisColumn,
  1493. ownerHeight,
  1494. ownerWidth),
  1495. YGDimensionHeight);
  1496. }
  1497. static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node,
  1498. const float availableWidth,
  1499. const float availableHeight,
  1500. const YGMeasureMode widthMeasureMode,
  1501. const YGMeasureMode heightMeasureMode,
  1502. const float ownerWidth,
  1503. const float ownerHeight) {
  1504. if ((!YGFloatIsUndefined(availableWidth) &&
  1505. widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
  1506. (!YGFloatIsUndefined(availableHeight) &&
  1507. heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
  1508. (widthMeasureMode == YGMeasureModeExactly &&
  1509. heightMeasureMode == YGMeasureModeExactly)) {
  1510. const float& marginAxisColumn = YGUnwrapFloatOptional(
  1511. node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
  1512. const float& marginAxisRow = YGUnwrapFloatOptional(
  1513. node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
  1514. node->setLayoutMeasuredDimension(
  1515. YGNodeBoundAxis(
  1516. node,
  1517. YGFlexDirectionRow,
  1518. YGFloatIsUndefined(availableWidth) ||
  1519. (widthMeasureMode == YGMeasureModeAtMost &&
  1520. availableWidth < 0.0f)
  1521. ? 0.0f
  1522. : availableWidth - marginAxisRow,
  1523. ownerWidth,
  1524. ownerWidth),
  1525. YGDimensionWidth);
  1526. node->setLayoutMeasuredDimension(
  1527. YGNodeBoundAxis(
  1528. node,
  1529. YGFlexDirectionColumn,
  1530. YGFloatIsUndefined(availableHeight) ||
  1531. (heightMeasureMode == YGMeasureModeAtMost &&
  1532. availableHeight < 0.0f)
  1533. ? 0.0f
  1534. : availableHeight - marginAxisColumn,
  1535. ownerHeight,
  1536. ownerWidth),
  1537. YGDimensionHeight);
  1538. return true;
  1539. }
  1540. return false;
  1541. }
  1542. static void YGZeroOutLayoutRecursivly(const YGNodeRef node) {
  1543. memset(&(node->getLayout()), 0, sizeof(YGLayout));
  1544. node->setHasNewLayout(true);
  1545. node->cloneChildrenIfNeeded();
  1546. const uint32_t childCount = YGNodeGetChildCount(node);
  1547. for (uint32_t i = 0; i < childCount; i++) {
  1548. const YGNodeRef child = node->getChild(i);
  1549. YGZeroOutLayoutRecursivly(child);
  1550. }
  1551. }
  1552. static float YGNodeCalculateAvailableInnerDim(
  1553. const YGNodeRef node,
  1554. YGFlexDirection axis,
  1555. float availableDim,
  1556. float ownerDim) {
  1557. YGFlexDirection direction =
  1558. YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn;
  1559. YGDimension dimension =
  1560. YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight;
  1561. const float margin =
  1562. YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim));
  1563. const float paddingAndBorder =
  1564. YGNodePaddingAndBorderForAxis(node, direction, ownerDim);
  1565. float availableInnerDim = availableDim - margin - paddingAndBorder;
  1566. // Max dimension overrides predefined dimension value; Min dimension in turn
  1567. // overrides both of the above
  1568. if (!YGFloatIsUndefined(availableInnerDim)) {
  1569. // We want to make sure our available height does not violate min and max
  1570. // constraints
  1571. const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim);
  1572. const float minInnerDim = minDimensionOptional.isUndefined()
  1573. ? 0.0f
  1574. : minDimensionOptional.getValue() - paddingAndBorder;
  1575. const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim) ;
  1576. const float maxInnerDim = maxDimensionOptional.isUndefined()
  1577. ? FLT_MAX
  1578. : maxDimensionOptional.getValue() - paddingAndBorder;
  1579. availableInnerDim =
  1580. YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
  1581. }
  1582. return availableInnerDim;
  1583. }
  1584. static void YGNodeComputeFlexBasisForChildren(
  1585. const YGNodeRef node,
  1586. const float availableInnerWidth,
  1587. const float availableInnerHeight,
  1588. YGMeasureMode widthMeasureMode,
  1589. YGMeasureMode heightMeasureMode,
  1590. YGDirection direction,
  1591. YGFlexDirection mainAxis,
  1592. const YGConfigRef config,
  1593. bool performLayout,
  1594. float& totalOuterFlexBasis) {
  1595. YGNodeRef singleFlexChild = nullptr;
  1596. YGVector children = node->getChildren();
  1597. YGMeasureMode measureModeMainDim =
  1598. YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode;
  1599. // If there is only one child with flexGrow + flexShrink it means we can set
  1600. // the computedFlexBasis to 0 instead of measuring and shrinking / flexing the
  1601. // child to exactly match the remaining space
  1602. if (measureModeMainDim == YGMeasureModeExactly) {
  1603. for (auto child : children) {
  1604. if (child->isNodeFlexible()) {
  1605. if (singleFlexChild != nullptr ||
  1606. YGFloatsEqual(child->resolveFlexGrow(), 0.0f) ||
  1607. YGFloatsEqual(child->resolveFlexShrink(), 0.0f)) {
  1608. // There is already a flexible child, or this flexible child doesn't
  1609. // have flexGrow and flexShrink, abort
  1610. singleFlexChild = nullptr;
  1611. break;
  1612. } else {
  1613. singleFlexChild = child;
  1614. }
  1615. }
  1616. }
  1617. }
  1618. for (auto child : children) {
  1619. child->resolveDimension();
  1620. if (child->getStyle().display == YGDisplayNone) {
  1621. YGZeroOutLayoutRecursivly(child);
  1622. child->setHasNewLayout(true);
  1623. child->setDirty(false);
  1624. continue;
  1625. }
  1626. if (performLayout) {
  1627. // Set the initial position (relative to the owner).
  1628. const YGDirection childDirection = child->resolveDirection(direction);
  1629. const float mainDim = YGFlexDirectionIsRow(mainAxis)
  1630. ? availableInnerWidth
  1631. : availableInnerHeight;
  1632. const float crossDim = YGFlexDirectionIsRow(mainAxis)
  1633. ? availableInnerHeight
  1634. : availableInnerWidth;
  1635. child->setPosition(
  1636. childDirection, mainDim, crossDim, availableInnerWidth);
  1637. }
  1638. if (child->getStyle().positionType == YGPositionTypeAbsolute) {
  1639. continue;
  1640. }
  1641. if (child == singleFlexChild) {
  1642. child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
  1643. child->setLayoutComputedFlexBasis(YGFloatOptional(0));
  1644. } else {
  1645. YGNodeComputeFlexBasisForChild(
  1646. node,
  1647. child,
  1648. availableInnerWidth,
  1649. widthMeasureMode,
  1650. availableInnerHeight,
  1651. availableInnerWidth,
  1652. availableInnerHeight,
  1653. heightMeasureMode,
  1654. direction,
  1655. config);
  1656. }
  1657. totalOuterFlexBasis += YGUnwrapFloatOptional(
  1658. child->getLayout().computedFlexBasis +
  1659. child->getMarginForAxis(mainAxis, availableInnerWidth));
  1660. }
  1661. }
  1662. // This function assumes that all the children of node have their
  1663. // computedFlexBasis properly computed(To do this use
  1664. // YGNodeComputeFlexBasisForChildren function).
  1665. // This function calculates YGCollectFlexItemsRowMeasurement
  1666. static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
  1667. const YGNodeRef& node,
  1668. const YGDirection ownerDirection,
  1669. const float mainAxisownerSize,
  1670. const float availableInnerWidth,
  1671. const float availableInnerMainDim,
  1672. const uint32_t startOfLineIndex,
  1673. const uint32_t lineCount) {
  1674. YGCollectFlexItemsRowValues flexAlgoRowMeasurement = {};
  1675. flexAlgoRowMeasurement.relativeChildren.reserve(node->getChildren().size());
  1676. float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
  1677. const YGFlexDirection mainAxis = YGResolveFlexDirection(
  1678. node->getStyle().flexDirection, node->resolveDirection(ownerDirection));
  1679. const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
  1680. // Add items to the current line until it's full or we run out of items.
  1681. uint32_t endOfLineIndex = startOfLineIndex;
  1682. for (; endOfLineIndex < node->getChildrenCount(); endOfLineIndex++) {
  1683. const YGNodeRef child = node->getChild(endOfLineIndex);
  1684. if (child->getStyle().display == YGDisplayNone ||
  1685. child->getStyle().positionType == YGPositionTypeAbsolute) {
  1686. continue;
  1687. }
  1688. child->setLineIndex(lineCount);
  1689. const float childMarginMainAxis = YGUnwrapFloatOptional(
  1690. child->getMarginForAxis(mainAxis, availableInnerWidth));
  1691. const float flexBasisWithMinAndMaxConstraints =
  1692. YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
  1693. child,
  1694. mainAxis,
  1695. YGUnwrapFloatOptional(child->getLayout().computedFlexBasis),
  1696. mainAxisownerSize));
  1697. // If this is a multi-line flow and this item pushes us over the
  1698. // available size, we've
  1699. // hit the end of the current line. Break out of the loop and lay out
  1700. // the current line.
  1701. if (sizeConsumedOnCurrentLineIncludingMinConstraint +
  1702. flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
  1703. availableInnerMainDim &&
  1704. isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) {
  1705. break;
  1706. }
  1707. sizeConsumedOnCurrentLineIncludingMinConstraint +=
  1708. flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
  1709. flexAlgoRowMeasurement.sizeConsumedOnCurrentLine +=
  1710. flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
  1711. flexAlgoRowMeasurement.itemsOnLine++;
  1712. if (child->isNodeFlexible()) {
  1713. flexAlgoRowMeasurement.totalFlexGrowFactors += child->resolveFlexGrow();
  1714. // Unlike the grow factor, the shrink factor is scaled relative to the
  1715. // child dimension.
  1716. flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
  1717. -child->resolveFlexShrink() *
  1718. YGUnwrapFloatOptional(child->getLayout().computedFlexBasis);
  1719. }
  1720. flexAlgoRowMeasurement.relativeChildren.push_back(child);
  1721. }
  1722. // The total flex factor needs to be floored to 1.
  1723. if (flexAlgoRowMeasurement.totalFlexGrowFactors > 0 &&
  1724. flexAlgoRowMeasurement.totalFlexGrowFactors < 1) {
  1725. flexAlgoRowMeasurement.totalFlexGrowFactors = 1;
  1726. }
  1727. // The total flex shrink factor needs to be floored to 1.
  1728. if (flexAlgoRowMeasurement.totalFlexShrinkScaledFactors > 0 &&
  1729. flexAlgoRowMeasurement.totalFlexShrinkScaledFactors < 1) {
  1730. flexAlgoRowMeasurement.totalFlexShrinkScaledFactors = 1;
  1731. }
  1732. flexAlgoRowMeasurement.endOfLineIndex = endOfLineIndex;
  1733. return flexAlgoRowMeasurement;
  1734. }
  1735. // It distributes the free space to the flexible items and ensures that the size
  1736. // of the flex items abide the min and max constraints. At the end of this
  1737. // function the child nodes would have proper size. Prior using this function
  1738. // please ensure that YGDistributeFreeSpaceFirstPass is called.
  1739. static float YGDistributeFreeSpaceSecondPass(
  1740. YGCollectFlexItemsRowValues& collectedFlexItemsValues,
  1741. const YGNodeRef node,
  1742. const YGFlexDirection mainAxis,
  1743. const YGFlexDirection crossAxis,
  1744. const float mainAxisownerSize,
  1745. const float availableInnerMainDim,
  1746. const float availableInnerCrossDim,
  1747. const float availableInnerWidth,
  1748. const float availableInnerHeight,
  1749. const bool flexBasisOverflows,
  1750. const YGMeasureMode measureModeCrossDim,
  1751. const bool performLayout,
  1752. const YGConfigRef config) {
  1753. float childFlexBasis = 0;
  1754. float flexShrinkScaledFactor = 0;
  1755. float flexGrowFactor = 0;
  1756. float deltaFreeSpace = 0;
  1757. const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
  1758. const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
  1759. for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
  1760. childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
  1761. currentRelativeChild,
  1762. mainAxis,
  1763. YGUnwrapFloatOptional(
  1764. currentRelativeChild->getLayout().computedFlexBasis),
  1765. mainAxisownerSize));
  1766. float updatedMainSize = childFlexBasis;
  1767. if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
  1768. collectedFlexItemsValues.remainingFreeSpace < 0) {
  1769. flexShrinkScaledFactor =
  1770. -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
  1771. // Is this child able to shrink?
  1772. if (flexShrinkScaledFactor != 0) {
  1773. float childSize;
  1774. if (!YGFloatIsUndefined(
  1775. collectedFlexItemsValues.totalFlexShrinkScaledFactors) &&
  1776. collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
  1777. childSize = childFlexBasis + flexShrinkScaledFactor;
  1778. } else {
  1779. childSize = childFlexBasis +
  1780. (collectedFlexItemsValues.remainingFreeSpace /
  1781. collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
  1782. flexShrinkScaledFactor;
  1783. }
  1784. updatedMainSize = YGNodeBoundAxis(
  1785. currentRelativeChild,
  1786. mainAxis,
  1787. childSize,
  1788. availableInnerMainDim,
  1789. availableInnerWidth);
  1790. }
  1791. } else if (
  1792. !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
  1793. collectedFlexItemsValues.remainingFreeSpace > 0) {
  1794. flexGrowFactor = currentRelativeChild->resolveFlexGrow();
  1795. // Is this child able to grow?
  1796. if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
  1797. updatedMainSize = YGNodeBoundAxis(
  1798. currentRelativeChild,
  1799. mainAxis,
  1800. childFlexBasis +
  1801. collectedFlexItemsValues.remainingFreeSpace /
  1802. collectedFlexItemsValues.totalFlexGrowFactors *
  1803. flexGrowFactor,
  1804. availableInnerMainDim,
  1805. availableInnerWidth);
  1806. }
  1807. }
  1808. deltaFreeSpace += updatedMainSize - childFlexBasis;
  1809. const float marginMain = YGUnwrapFloatOptional(
  1810. currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth));
  1811. const float marginCross = YGUnwrapFloatOptional(
  1812. currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth));
  1813. float childCrossSize;
  1814. float childMainSize = updatedMainSize + marginMain;
  1815. YGMeasureMode childCrossMeasureMode;
  1816. YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
  1817. if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) {
  1818. childCrossSize = isMainAxisRow ? (childMainSize - marginMain) /
  1819. currentRelativeChild->getStyle().aspectRatio.getValue()
  1820. : (childMainSize - marginMain) *
  1821. currentRelativeChild->getStyle().aspectRatio.getValue();
  1822. childCrossMeasureMode = YGMeasureModeExactly;
  1823. childCrossSize += marginCross;
  1824. } else if (
  1825. !YGFloatIsUndefined(availableInnerCrossDim) &&
  1826. !YGNodeIsStyleDimDefined(
  1827. currentRelativeChild, crossAxis, availableInnerCrossDim) &&
  1828. measureModeCrossDim == YGMeasureModeExactly &&
  1829. !(isNodeFlexWrap && flexBasisOverflows) &&
  1830. YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
  1831. currentRelativeChild->marginLeadingValue(crossAxis).unit !=
  1832. YGUnitAuto &&
  1833. currentRelativeChild->marginTrailingValue(crossAxis).unit !=
  1834. YGUnitAuto) {
  1835. childCrossSize = availableInnerCrossDim;
  1836. childCrossMeasureMode = YGMeasureModeExactly;
  1837. } else if (!YGNodeIsStyleDimDefined(
  1838. currentRelativeChild, crossAxis, availableInnerCrossDim)) {
  1839. childCrossSize = availableInnerCrossDim;
  1840. childCrossMeasureMode = YGFloatIsUndefined(childCrossSize)
  1841. ? YGMeasureModeUndefined
  1842. : YGMeasureModeAtMost;
  1843. } else {
  1844. childCrossSize =
  1845. YGUnwrapFloatOptional(YGResolveValue(
  1846. currentRelativeChild->getResolvedDimension(dim[crossAxis]),
  1847. availableInnerCrossDim)) +
  1848. marginCross;
  1849. const bool isLoosePercentageMeasurement =
  1850. currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
  1851. YGUnitPercent &&
  1852. measureModeCrossDim != YGMeasureModeExactly;
  1853. childCrossMeasureMode =
  1854. YGFloatIsUndefined(childCrossSize) || isLoosePercentageMeasurement
  1855. ? YGMeasureModeUndefined
  1856. : YGMeasureModeExactly;
  1857. }
  1858. YGConstrainMaxSizeForMode(
  1859. currentRelativeChild,
  1860. mainAxis,
  1861. availableInnerMainDim,
  1862. availableInnerWidth,
  1863. &childMainMeasureMode,
  1864. &childMainSize);
  1865. YGConstrainMaxSizeForMode(
  1866. currentRelativeChild,
  1867. crossAxis,
  1868. availableInnerCrossDim,
  1869. availableInnerWidth,
  1870. &childCrossMeasureMode,
  1871. &childCrossSize);
  1872. const bool requiresStretchLayout =
  1873. !YGNodeIsStyleDimDefined(
  1874. currentRelativeChild, crossAxis, availableInnerCrossDim) &&
  1875. YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
  1876. currentRelativeChild->marginLeadingValue(crossAxis).unit !=
  1877. YGUnitAuto &&
  1878. currentRelativeChild->marginTrailingValue(crossAxis).unit != YGUnitAuto;
  1879. const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
  1880. const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
  1881. const YGMeasureMode childWidthMeasureMode =
  1882. isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
  1883. const YGMeasureMode childHeightMeasureMode =
  1884. !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
  1885. // Recursively call the layout algorithm for this child with the updated
  1886. // main size.
  1887. YGLayoutNodeInternal(
  1888. currentRelativeChild,
  1889. childWidth,
  1890. childHeight,
  1891. node->getLayout().direction,
  1892. childWidthMeasureMode,
  1893. childHeightMeasureMode,
  1894. availableInnerWidth,
  1895. availableInnerHeight,
  1896. performLayout && !requiresStretchLayout,
  1897. "flex",
  1898. config);
  1899. node->setLayoutHadOverflow(
  1900. node->getLayout().hadOverflow |
  1901. currentRelativeChild->getLayout().hadOverflow);
  1902. }
  1903. return deltaFreeSpace;
  1904. }
  1905. // It distributes the free space to the flexible items.For those flexible items
  1906. // whose min and max constraints are triggered, those flex item's clamped size
  1907. // is removed from the remaingfreespace.
  1908. static void YGDistributeFreeSpaceFirstPass(
  1909. YGCollectFlexItemsRowValues& collectedFlexItemsValues,
  1910. const YGFlexDirection mainAxis,
  1911. const float mainAxisownerSize,
  1912. const float availableInnerMainDim,
  1913. const float availableInnerWidth) {
  1914. float flexShrinkScaledFactor = 0;
  1915. float flexGrowFactor = 0;
  1916. float baseMainSize = 0;
  1917. float boundMainSize = 0;
  1918. float deltaFreeSpace = 0;
  1919. for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
  1920. float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
  1921. currentRelativeChild,
  1922. mainAxis,
  1923. YGUnwrapFloatOptional(
  1924. currentRelativeChild->getLayout().computedFlexBasis),
  1925. mainAxisownerSize));
  1926. if (collectedFlexItemsValues.remainingFreeSpace < 0) {
  1927. flexShrinkScaledFactor =
  1928. -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
  1929. // Is this child able to shrink?
  1930. if (!YGFloatIsUndefined(flexShrinkScaledFactor) &&
  1931. flexShrinkScaledFactor != 0) {
  1932. baseMainSize = childFlexBasis +
  1933. collectedFlexItemsValues.remainingFreeSpace /
  1934. collectedFlexItemsValues.totalFlexShrinkScaledFactors *
  1935. flexShrinkScaledFactor;
  1936. boundMainSize = YGNodeBoundAxis(
  1937. currentRelativeChild,
  1938. mainAxis,
  1939. baseMainSize,
  1940. availableInnerMainDim,
  1941. availableInnerWidth);
  1942. if (!YGFloatIsUndefined(baseMainSize) &&
  1943. !YGFloatIsUndefined(boundMainSize) &&
  1944. baseMainSize != boundMainSize) {
  1945. // By excluding this item's size and flex factor from remaining,
  1946. // this item's
  1947. // min/max constraints should also trigger in the second pass
  1948. // resulting in the
  1949. // item's size calculation being identical in the first and second
  1950. // passes.
  1951. deltaFreeSpace += boundMainSize - childFlexBasis;
  1952. collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
  1953. flexShrinkScaledFactor;
  1954. }
  1955. }
  1956. } else if (
  1957. !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
  1958. collectedFlexItemsValues.remainingFreeSpace > 0) {
  1959. flexGrowFactor = currentRelativeChild->resolveFlexGrow();
  1960. // Is this child able to grow?
  1961. if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
  1962. baseMainSize = childFlexBasis +
  1963. collectedFlexItemsValues.remainingFreeSpace /
  1964. collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
  1965. boundMainSize = YGNodeBoundAxis(
  1966. currentRelativeChild,
  1967. mainAxis,
  1968. baseMainSize,
  1969. availableInnerMainDim,
  1970. availableInnerWidth);
  1971. if (!YGFloatIsUndefined(baseMainSize) &&
  1972. !YGFloatIsUndefined(boundMainSize) &&
  1973. baseMainSize != boundMainSize) {
  1974. // By excluding this item's size and flex factor from remaining,
  1975. // this item's
  1976. // min/max constraints should also trigger in the second pass
  1977. // resulting in the
  1978. // item's size calculation being identical in the first and second
  1979. // passes.
  1980. deltaFreeSpace += boundMainSize - childFlexBasis;
  1981. collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
  1982. }
  1983. }
  1984. }
  1985. }
  1986. collectedFlexItemsValues.remainingFreeSpace -= deltaFreeSpace;
  1987. }
  1988. // Do two passes over the flex items to figure out how to distribute the
  1989. // remaining space.
  1990. // The first pass finds the items whose min/max constraints trigger,
  1991. // freezes them at those
  1992. // sizes, and excludes those sizes from the remaining space. The second
  1993. // pass sets the size
  1994. // of each flexible item. It distributes the remaining space amongst the
  1995. // items whose min/max
  1996. // constraints didn't trigger in pass 1. For the other items, it sets
  1997. // their sizes by forcing
  1998. // their min/max constraints to trigger again.
  1999. //
  2000. // This two pass approach for resolving min/max constraints deviates from
  2001. // the spec. The
  2002. // spec (https://www.w3.org/TR/YG-flexbox-1/#resolve-flexible-lengths)
  2003. // describes a process
  2004. // that needs to be repeated a variable number of times. The algorithm
  2005. // implemented here
  2006. // won't handle all cases but it was simpler to implement and it mitigates
  2007. // performance
  2008. // concerns because we know exactly how many passes it'll do.
  2009. //
  2010. // At the end of this function the child nodes would have the proper size
  2011. // assigned to them.
  2012. //
  2013. static void YGResolveFlexibleLength(
  2014. const YGNodeRef node,
  2015. YGCollectFlexItemsRowValues& collectedFlexItemsValues,
  2016. const YGFlexDirection mainAxis,
  2017. const YGFlexDirection crossAxis,
  2018. const float mainAxisownerSize,
  2019. const float availableInnerMainDim,
  2020. const float availableInnerCrossDim,
  2021. const float availableInnerWidth,
  2022. const float availableInnerHeight,
  2023. const bool flexBasisOverflows,
  2024. const YGMeasureMode measureModeCrossDim,
  2025. const bool performLayout,
  2026. const YGConfigRef config) {
  2027. const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace;
  2028. // First pass: detect the flex items whose min/max constraints trigger
  2029. YGDistributeFreeSpaceFirstPass(
  2030. collectedFlexItemsValues,
  2031. mainAxis,
  2032. mainAxisownerSize,
  2033. availableInnerMainDim,
  2034. availableInnerWidth);
  2035. // Second pass: resolve the sizes of the flexible items
  2036. const float distributedFreeSpace = YGDistributeFreeSpaceSecondPass(
  2037. collectedFlexItemsValues,
  2038. node,
  2039. mainAxis,
  2040. crossAxis,
  2041. mainAxisownerSize,
  2042. availableInnerMainDim,
  2043. availableInnerCrossDim,
  2044. availableInnerWidth,
  2045. availableInnerHeight,
  2046. flexBasisOverflows,
  2047. measureModeCrossDim,
  2048. performLayout,
  2049. config);
  2050. collectedFlexItemsValues.remainingFreeSpace =
  2051. originalFreeSpace - distributedFreeSpace;
  2052. }
  2053. static void YGJustifyMainAxis(
  2054. const YGNodeRef node,
  2055. YGCollectFlexItemsRowValues& collectedFlexItemsValues,
  2056. const uint32_t& startOfLineIndex,
  2057. const YGFlexDirection& mainAxis,
  2058. const YGFlexDirection& crossAxis,
  2059. const YGMeasureMode& measureModeMainDim,
  2060. const YGMeasureMode& measureModeCrossDim,
  2061. const float& mainAxisownerSize,
  2062. const float& ownerWidth,
  2063. const float& availableInnerMainDim,
  2064. const float& availableInnerCrossDim,
  2065. const float& availableInnerWidth,
  2066. const bool& performLayout) {
  2067. const YGStyle style = node->getStyle();
  2068. // If we are using "at most" rules in the main axis. Calculate the remaining
  2069. // space when constraint by the min size defined for the main axis.
  2070. if (measureModeMainDim == YGMeasureModeAtMost &&
  2071. collectedFlexItemsValues.remainingFreeSpace > 0) {
  2072. if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
  2073. !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
  2074. .isUndefined()) {
  2075. collectedFlexItemsValues.remainingFreeSpace = YGFloatMax(
  2076. 0,
  2077. YGUnwrapFloatOptional(YGResolveValue(
  2078. style.minDimensions[dim[mainAxis]], mainAxisownerSize)) -
  2079. (availableInnerMainDim -
  2080. collectedFlexItemsValues.remainingFreeSpace));
  2081. } else {
  2082. collectedFlexItemsValues.remainingFreeSpace = 0;
  2083. }
  2084. }
  2085. int numberOfAutoMarginsOnCurrentLine = 0;
  2086. for (uint32_t i = startOfLineIndex;
  2087. i < collectedFlexItemsValues.endOfLineIndex;
  2088. i++) {
  2089. const YGNodeRef child = node->getChild(i);
  2090. if (child->getStyle().positionType == YGPositionTypeRelative) {
  2091. if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
  2092. numberOfAutoMarginsOnCurrentLine++;
  2093. }
  2094. if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
  2095. numberOfAutoMarginsOnCurrentLine++;
  2096. }
  2097. }
  2098. }
  2099. // In order to position the elements in the main axis, we have two
  2100. // controls. The space between the beginning and the first element
  2101. // and the space between each two elements.
  2102. float leadingMainDim = 0;
  2103. float betweenMainDim = 0;
  2104. const YGJustify justifyContent = node->getStyle().justifyContent;
  2105. if (numberOfAutoMarginsOnCurrentLine == 0) {
  2106. switch (justifyContent) {
  2107. case YGJustifyCenter:
  2108. leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
  2109. break;
  2110. case YGJustifyFlexEnd:
  2111. leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
  2112. break;
  2113. case YGJustifySpaceBetween:
  2114. if (collectedFlexItemsValues.itemsOnLine > 1) {
  2115. betweenMainDim =
  2116. YGFloatMax(collectedFlexItemsValues.remainingFreeSpace, 0) /
  2117. (collectedFlexItemsValues.itemsOnLine - 1);
  2118. } else {
  2119. betweenMainDim = 0;
  2120. }
  2121. break;
  2122. case YGJustifySpaceEvenly:
  2123. // Space is distributed evenly across all elements
  2124. betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
  2125. (collectedFlexItemsValues.itemsOnLine + 1);
  2126. leadingMainDim = betweenMainDim;
  2127. break;
  2128. case YGJustifySpaceAround:
  2129. // Space on the edges is half of the space between elements
  2130. betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
  2131. collectedFlexItemsValues.itemsOnLine;
  2132. leadingMainDim = betweenMainDim / 2;
  2133. break;
  2134. case YGJustifyFlexStart:
  2135. break;
  2136. }
  2137. }
  2138. const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional(
  2139. node->getLeadingPaddingAndBorder(mainAxis, ownerWidth));
  2140. collectedFlexItemsValues.mainDim =
  2141. leadingPaddingAndBorderMain + leadingMainDim;
  2142. collectedFlexItemsValues.crossDim = 0;
  2143. for (uint32_t i = startOfLineIndex;
  2144. i < collectedFlexItemsValues.endOfLineIndex;
  2145. i++) {
  2146. const YGNodeRef child = node->getChild(i);
  2147. const YGStyle childStyle = child->getStyle();
  2148. const YGLayout childLayout = child->getLayout();
  2149. if (childStyle.display == YGDisplayNone) {
  2150. continue;
  2151. }
  2152. if (childStyle.positionType == YGPositionTypeAbsolute &&
  2153. child->isLeadingPositionDefined(mainAxis)) {
  2154. if (performLayout) {
  2155. // In case the child is position absolute and has left/top being
  2156. // defined, we override the position to whatever the user said
  2157. // (and margin/border).
  2158. child->setLayoutPosition(
  2159. YGUnwrapFloatOptional(
  2160. child->getLeadingPosition(mainAxis, availableInnerMainDim)) +
  2161. node->getLeadingBorder(mainAxis) +
  2162. YGUnwrapFloatOptional(
  2163. child->getLeadingMargin(mainAxis, availableInnerWidth)),
  2164. pos[mainAxis]);
  2165. }
  2166. } else {
  2167. // Now that we placed the element, we need to update the variables.
  2168. // We need to do that only for relative elements. Absolute elements
  2169. // do not take part in that phase.
  2170. if (childStyle.positionType == YGPositionTypeRelative) {
  2171. if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
  2172. collectedFlexItemsValues.mainDim +=
  2173. collectedFlexItemsValues.remainingFreeSpace /
  2174. numberOfAutoMarginsOnCurrentLine;
  2175. }
  2176. if (performLayout) {
  2177. child->setLayoutPosition(
  2178. childLayout.position[pos[mainAxis]] +
  2179. collectedFlexItemsValues.mainDim,
  2180. pos[mainAxis]);
  2181. }
  2182. if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
  2183. collectedFlexItemsValues.mainDim +=
  2184. collectedFlexItemsValues.remainingFreeSpace /
  2185. numberOfAutoMarginsOnCurrentLine;
  2186. }
  2187. bool canSkipFlex =
  2188. !performLayout && measureModeCrossDim == YGMeasureModeExactly;
  2189. if (canSkipFlex) {
  2190. // If we skipped the flex step, then we can't rely on the
  2191. // measuredDims because
  2192. // they weren't computed. This means we can't call
  2193. // YGNodeDimWithMargin.
  2194. collectedFlexItemsValues.mainDim += betweenMainDim +
  2195. YGUnwrapFloatOptional(child->getMarginForAxis(
  2196. mainAxis, availableInnerWidth)) +
  2197. YGUnwrapFloatOptional(childLayout.computedFlexBasis);
  2198. collectedFlexItemsValues.crossDim = availableInnerCrossDim;
  2199. } else {
  2200. // The main dimension is the sum of all the elements dimension plus
  2201. // the spacing.
  2202. collectedFlexItemsValues.mainDim += betweenMainDim +
  2203. YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
  2204. // The cross dimension is the max of the elements dimension since
  2205. // there can only be one element in that cross dimension.
  2206. collectedFlexItemsValues.crossDim = YGFloatMax(
  2207. collectedFlexItemsValues.crossDim,
  2208. YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
  2209. }
  2210. } else if (performLayout) {
  2211. child->setLayoutPosition(
  2212. childLayout.position[pos[mainAxis]] +
  2213. node->getLeadingBorder(mainAxis) + leadingMainDim,
  2214. pos[mainAxis]);
  2215. }
  2216. }
  2217. }
  2218. collectedFlexItemsValues.mainDim += YGUnwrapFloatOptional(
  2219. node->getTrailingPaddingAndBorder(mainAxis, ownerWidth));
  2220. }
  2221. //
  2222. // This is the main routine that implements a subset of the flexbox layout
  2223. // algorithm
  2224. // described in the W3C YG documentation: https://www.w3.org/TR/YG3-flexbox/.
  2225. //
  2226. // Limitations of this algorithm, compared to the full standard:
  2227. // * Display property is always assumed to be 'flex' except for Text nodes,
  2228. // which
  2229. // are assumed to be 'inline-flex'.
  2230. // * The 'zIndex' property (or any form of z ordering) is not supported. Nodes
  2231. // are
  2232. // stacked in document order.
  2233. // * The 'order' property is not supported. The order of flex items is always
  2234. // defined
  2235. // by document order.
  2236. // * The 'visibility' property is always assumed to be 'visible'. Values of
  2237. // 'collapse'
  2238. // and 'hidden' are not supported.
  2239. // * There is no support for forced breaks.
  2240. // * It does not support vertical inline directions (top-to-bottom or
  2241. // bottom-to-top text).
  2242. //
  2243. // Deviations from standard:
  2244. // * Section 4.5 of the spec indicates that all flex items have a default
  2245. // minimum
  2246. // main size. For text blocks, for example, this is the width of the widest
  2247. // word.
  2248. // Calculating the minimum width is expensive, so we forego it and assume a
  2249. // default
  2250. // minimum main size of 0.
  2251. // * Min/Max sizes in the main axis are not honored when resolving flexible
  2252. // lengths.
  2253. // * The spec indicates that the default value for 'flexDirection' is 'row',
  2254. // but
  2255. // the algorithm below assumes a default of 'column'.
  2256. //
  2257. // Input parameters:
  2258. // - node: current node to be sized and layed out
  2259. // - availableWidth & availableHeight: available size to be used for sizing
  2260. // the node
  2261. // or YGUndefined if the size is not available; interpretation depends on
  2262. // layout
  2263. // flags
  2264. // - ownerDirection: the inline (text) direction within the owner
  2265. // (left-to-right or
  2266. // right-to-left)
  2267. // - widthMeasureMode: indicates the sizing rules for the width (see below
  2268. // for explanation)
  2269. // - heightMeasureMode: indicates the sizing rules for the height (see below
  2270. // for explanation)
  2271. // - performLayout: specifies whether the caller is interested in just the
  2272. // dimensions
  2273. // of the node or it requires the entire node and its subtree to be layed
  2274. // out
  2275. // (with final positions)
  2276. //
  2277. // Details:
  2278. // This routine is called recursively to lay out subtrees of flexbox
  2279. // elements. It uses the
  2280. // information in node.style, which is treated as a read-only input. It is
  2281. // responsible for
  2282. // setting the layout.direction and layout.measuredDimensions fields for the
  2283. // input node as well
  2284. // as the layout.position and layout.lineIndex fields for its child nodes.
  2285. // The
  2286. // layout.measuredDimensions field includes any border or padding for the
  2287. // node but does
  2288. // not include margins.
  2289. //
  2290. // The spec describes four different layout modes: "fill available", "max
  2291. // content", "min
  2292. // content",
  2293. // and "fit content". Of these, we don't use "min content" because we don't
  2294. // support default
  2295. // minimum main sizes (see above for details). Each of our measure modes maps
  2296. // to a layout mode
  2297. // from the spec (https://www.w3.org/TR/YG3-sizing/#terms):
  2298. // - YGMeasureModeUndefined: max content
  2299. // - YGMeasureModeExactly: fill available
  2300. // - YGMeasureModeAtMost: fit content
  2301. //
  2302. // When calling YGNodelayoutImpl and YGLayoutNodeInternal, if the caller passes
  2303. // an available size of
  2304. // undefined then it must also pass a measure mode of YGMeasureModeUndefined
  2305. // in that dimension.
  2306. //
  2307. static void YGNodelayoutImpl(const YGNodeRef node,
  2308. const float availableWidth,
  2309. const float availableHeight,
  2310. const YGDirection ownerDirection,
  2311. const YGMeasureMode widthMeasureMode,
  2312. const YGMeasureMode heightMeasureMode,
  2313. const float ownerWidth,
  2314. const float ownerHeight,
  2315. const bool performLayout,
  2316. const YGConfigRef config) {
  2317. YGAssertWithNode(node,
  2318. YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined
  2319. : true,
  2320. "availableWidth is indefinite so widthMeasureMode must be "
  2321. "YGMeasureModeUndefined");
  2322. YGAssertWithNode(node,
  2323. YGFloatIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined
  2324. : true,
  2325. "availableHeight is indefinite so heightMeasureMode must be "
  2326. "YGMeasureModeUndefined");
  2327. // Set the resolved resolution in the node's layout.
  2328. const YGDirection direction = node->resolveDirection(ownerDirection);
  2329. node->setLayoutDirection(direction);
  2330. const YGFlexDirection flexRowDirection = YGResolveFlexDirection(YGFlexDirectionRow, direction);
  2331. const YGFlexDirection flexColumnDirection =
  2332. YGResolveFlexDirection(YGFlexDirectionColumn, direction);
  2333. node->setLayoutMargin(
  2334. YGUnwrapFloatOptional(
  2335. node->getLeadingMargin(flexRowDirection, ownerWidth)),
  2336. YGEdgeStart);
  2337. node->setLayoutMargin(
  2338. YGUnwrapFloatOptional(
  2339. node->getTrailingMargin(flexRowDirection, ownerWidth)),
  2340. YGEdgeEnd);
  2341. node->setLayoutMargin(
  2342. YGUnwrapFloatOptional(
  2343. node->getLeadingMargin(flexColumnDirection, ownerWidth)),
  2344. YGEdgeTop);
  2345. node->setLayoutMargin(
  2346. YGUnwrapFloatOptional(
  2347. node->getTrailingMargin(flexColumnDirection, ownerWidth)),
  2348. YGEdgeBottom);
  2349. node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart);
  2350. node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), YGEdgeEnd);
  2351. node->setLayoutBorder(node->getLeadingBorder(flexColumnDirection), YGEdgeTop);
  2352. node->setLayoutBorder(
  2353. node->getTrailingBorder(flexColumnDirection), YGEdgeBottom);
  2354. node->setLayoutPadding(
  2355. YGUnwrapFloatOptional(
  2356. node->getLeadingPadding(flexRowDirection, ownerWidth)),
  2357. YGEdgeStart);
  2358. node->setLayoutPadding(
  2359. YGUnwrapFloatOptional(
  2360. node->getTrailingPadding(flexRowDirection, ownerWidth)),
  2361. YGEdgeEnd);
  2362. node->setLayoutPadding(
  2363. YGUnwrapFloatOptional(
  2364. node->getLeadingPadding(flexColumnDirection, ownerWidth)),
  2365. YGEdgeTop);
  2366. node->setLayoutPadding(
  2367. YGUnwrapFloatOptional(
  2368. node->getTrailingPadding(flexColumnDirection, ownerWidth)),
  2369. YGEdgeBottom);
  2370. if (node->getMeasure() != nullptr) {
  2371. YGNodeWithMeasureFuncSetMeasuredDimensions(node,
  2372. availableWidth,
  2373. availableHeight,
  2374. widthMeasureMode,
  2375. heightMeasureMode,
  2376. ownerWidth,
  2377. ownerHeight);
  2378. return;
  2379. }
  2380. const uint32_t childCount = YGNodeGetChildCount(node);
  2381. if (childCount == 0) {
  2382. YGNodeEmptyContainerSetMeasuredDimensions(node,
  2383. availableWidth,
  2384. availableHeight,
  2385. widthMeasureMode,
  2386. heightMeasureMode,
  2387. ownerWidth,
  2388. ownerHeight);
  2389. return;
  2390. }
  2391. // If we're not being asked to perform a full layout we can skip the algorithm if we already know
  2392. // the size
  2393. if (!performLayout && YGNodeFixedSizeSetMeasuredDimensions(node,
  2394. availableWidth,
  2395. availableHeight,
  2396. widthMeasureMode,
  2397. heightMeasureMode,
  2398. ownerWidth,
  2399. ownerHeight)) {
  2400. return;
  2401. }
  2402. // At this point we know we're going to perform work. Ensure that each child has a mutable copy.
  2403. node->cloneChildrenIfNeeded();
  2404. // Reset layout flags, as they could have changed.
  2405. node->setLayoutHadOverflow(false);
  2406. // STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
  2407. const YGFlexDirection mainAxis =
  2408. YGResolveFlexDirection(node->getStyle().flexDirection, direction);
  2409. const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
  2410. const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
  2411. const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
  2412. const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
  2413. const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
  2414. const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional(
  2415. node->getLeadingPaddingAndBorder(crossAxis, ownerWidth));
  2416. const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth);
  2417. const float paddingAndBorderAxisCross =
  2418. YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth);
  2419. YGMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
  2420. YGMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
  2421. const float paddingAndBorderAxisRow =
  2422. isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross;
  2423. const float paddingAndBorderAxisColumn =
  2424. isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
  2425. const float marginAxisRow = YGUnwrapFloatOptional(
  2426. node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
  2427. const float marginAxisColumn = YGUnwrapFloatOptional(
  2428. node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
  2429. const float minInnerWidth =
  2430. YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) -
  2431. paddingAndBorderAxisRow;
  2432. const float maxInnerWidth =
  2433. YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) -
  2434. paddingAndBorderAxisRow;
  2435. const float minInnerHeight =
  2436. YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) -
  2437. paddingAndBorderAxisColumn;
  2438. const float maxInnerHeight =
  2439. YGUnwrapFloatOptional(YGResolveValue(
  2440. node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) -
  2441. paddingAndBorderAxisColumn;
  2442. const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
  2443. const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
  2444. // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
  2445. float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
  2446. node, YGFlexDirectionRow, availableWidth, ownerWidth);
  2447. float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
  2448. node, YGFlexDirectionColumn, availableHeight, ownerHeight);
  2449. float availableInnerMainDim =
  2450. isMainAxisRow ? availableInnerWidth : availableInnerHeight;
  2451. const float availableInnerCrossDim =
  2452. isMainAxisRow ? availableInnerHeight : availableInnerWidth;
  2453. float totalOuterFlexBasis = 0;
  2454. // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
  2455. YGNodeComputeFlexBasisForChildren(
  2456. node,
  2457. availableInnerWidth,
  2458. availableInnerHeight,
  2459. widthMeasureMode,
  2460. heightMeasureMode,
  2461. direction,
  2462. mainAxis,
  2463. config,
  2464. performLayout,
  2465. totalOuterFlexBasis);
  2466. const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
  2467. ? false
  2468. : totalOuterFlexBasis > availableInnerMainDim;
  2469. if (isNodeFlexWrap && flexBasisOverflows &&
  2470. measureModeMainDim == YGMeasureModeAtMost) {
  2471. measureModeMainDim = YGMeasureModeExactly;
  2472. }
  2473. // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
  2474. // Indexes of children that represent the first and last items in the line.
  2475. uint32_t startOfLineIndex = 0;
  2476. uint32_t endOfLineIndex = 0;
  2477. // Number of lines.
  2478. uint32_t lineCount = 0;
  2479. // Accumulated cross dimensions of all lines so far.
  2480. float totalLineCrossDim = 0;
  2481. // Max main dimension of all the lines.
  2482. float maxLineMainDim = 0;
  2483. YGCollectFlexItemsRowValues collectedFlexItemsValues;
  2484. for (; endOfLineIndex < childCount;
  2485. lineCount++, startOfLineIndex = endOfLineIndex) {
  2486. collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues(
  2487. node,
  2488. ownerDirection,
  2489. mainAxisownerSize,
  2490. availableInnerWidth,
  2491. availableInnerMainDim,
  2492. startOfLineIndex,
  2493. lineCount);
  2494. endOfLineIndex = collectedFlexItemsValues.endOfLineIndex;
  2495. // If we don't need to measure the cross axis, we can skip the entire flex
  2496. // step.
  2497. const bool canSkipFlex =
  2498. !performLayout && measureModeCrossDim == YGMeasureModeExactly;
  2499. // STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
  2500. // Calculate the remaining available space that needs to be allocated.
  2501. // If the main dimension size isn't known, it is computed based on
  2502. // the line length, so there's no more space left to distribute.
  2503. bool sizeBasedOnContent = false;
  2504. // If we don't measure with exact main dimension we want to ensure we don't violate min and max
  2505. if (measureModeMainDim != YGMeasureModeExactly) {
  2506. if (!YGFloatIsUndefined(minInnerMainDim) &&
  2507. collectedFlexItemsValues.sizeConsumedOnCurrentLine <
  2508. minInnerMainDim) {
  2509. availableInnerMainDim = minInnerMainDim;
  2510. } else if (
  2511. !YGFloatIsUndefined(maxInnerMainDim) &&
  2512. collectedFlexItemsValues.sizeConsumedOnCurrentLine >
  2513. maxInnerMainDim) {
  2514. availableInnerMainDim = maxInnerMainDim;
  2515. } else {
  2516. if (!node->getConfig()->useLegacyStretchBehaviour &&
  2517. ((YGFloatIsUndefined(
  2518. collectedFlexItemsValues.totalFlexGrowFactors) &&
  2519. collectedFlexItemsValues.totalFlexGrowFactors == 0) ||
  2520. (YGFloatIsUndefined(node->resolveFlexGrow()) &&
  2521. node->resolveFlexGrow() == 0))) {
  2522. // If we don't have any children to flex or we can't flex the node
  2523. // itself, space we've used is all space we need. Root node also
  2524. // should be shrunk to minimum
  2525. availableInnerMainDim =
  2526. collectedFlexItemsValues.sizeConsumedOnCurrentLine;
  2527. }
  2528. if (node->getConfig()->useLegacyStretchBehaviour) {
  2529. node->setLayoutDidUseLegacyFlag(true);
  2530. }
  2531. sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour;
  2532. }
  2533. }
  2534. if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
  2535. collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
  2536. collectedFlexItemsValues.sizeConsumedOnCurrentLine;
  2537. } else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
  2538. // availableInnerMainDim is indefinite which means the node is being sized based on its
  2539. // content.
  2540. // sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for
  2541. // its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
  2542. collectedFlexItemsValues.remainingFreeSpace =
  2543. -collectedFlexItemsValues.sizeConsumedOnCurrentLine;
  2544. }
  2545. if (!canSkipFlex) {
  2546. YGResolveFlexibleLength(
  2547. node,
  2548. collectedFlexItemsValues,
  2549. mainAxis,
  2550. crossAxis,
  2551. mainAxisownerSize,
  2552. availableInnerMainDim,
  2553. availableInnerCrossDim,
  2554. availableInnerWidth,
  2555. availableInnerHeight,
  2556. flexBasisOverflows,
  2557. measureModeCrossDim,
  2558. performLayout,
  2559. config);
  2560. }
  2561. node->setLayoutHadOverflow(
  2562. node->getLayout().hadOverflow |
  2563. (collectedFlexItemsValues.remainingFreeSpace < 0));
  2564. // STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
  2565. // At this point, all the children have their dimensions set in the main
  2566. // axis.
  2567. // Their dimensions are also set in the cross axis with the exception of
  2568. // items
  2569. // that are aligned "stretch". We need to compute these stretch values and
  2570. // set the final positions.
  2571. YGJustifyMainAxis(
  2572. node,
  2573. collectedFlexItemsValues,
  2574. startOfLineIndex,
  2575. mainAxis,
  2576. crossAxis,
  2577. measureModeMainDim,
  2578. measureModeCrossDim,
  2579. mainAxisownerSize,
  2580. ownerWidth,
  2581. availableInnerMainDim,
  2582. availableInnerCrossDim,
  2583. availableInnerWidth,
  2584. performLayout);
  2585. float containerCrossAxis = availableInnerCrossDim;
  2586. if (measureModeCrossDim == YGMeasureModeUndefined ||
  2587. measureModeCrossDim == YGMeasureModeAtMost) {
  2588. // Compute the cross axis from the max cross dimension of the children.
  2589. containerCrossAxis =
  2590. YGNodeBoundAxis(
  2591. node,
  2592. crossAxis,
  2593. collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
  2594. crossAxisownerSize,
  2595. ownerWidth) -
  2596. paddingAndBorderAxisCross;
  2597. }
  2598. // If there's no flex wrap, the cross dimension is defined by the container.
  2599. if (!isNodeFlexWrap && measureModeCrossDim == YGMeasureModeExactly) {
  2600. collectedFlexItemsValues.crossDim = availableInnerCrossDim;
  2601. }
  2602. // Clamp to the min/max size specified on the container.
  2603. collectedFlexItemsValues.crossDim =
  2604. YGNodeBoundAxis(
  2605. node,
  2606. crossAxis,
  2607. collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
  2608. crossAxisownerSize,
  2609. ownerWidth) -
  2610. paddingAndBorderAxisCross;
  2611. // STEP 7: CROSS-AXIS ALIGNMENT
  2612. // We can skip child alignment if we're just measuring the container.
  2613. if (performLayout) {
  2614. for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
  2615. const YGNodeRef child = node->getChild(i);
  2616. if (child->getStyle().display == YGDisplayNone) {
  2617. continue;
  2618. }
  2619. if (child->getStyle().positionType == YGPositionTypeAbsolute) {
  2620. // If the child is absolutely positioned and has a
  2621. // top/left/bottom/right set, override
  2622. // all the previously computed positions to set it correctly.
  2623. const bool isChildLeadingPosDefined =
  2624. child->isLeadingPositionDefined(crossAxis);
  2625. if (isChildLeadingPosDefined) {
  2626. child->setLayoutPosition(
  2627. YGUnwrapFloatOptional(child->getLeadingPosition(
  2628. crossAxis, availableInnerCrossDim)) +
  2629. node->getLeadingBorder(crossAxis) +
  2630. YGUnwrapFloatOptional(child->getLeadingMargin(
  2631. crossAxis, availableInnerWidth)),
  2632. pos[crossAxis]);
  2633. }
  2634. // If leading position is not defined or calculations result in Nan, default to border + margin
  2635. if (!isChildLeadingPosDefined ||
  2636. YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) {
  2637. child->setLayoutPosition(
  2638. node->getLeadingBorder(crossAxis) +
  2639. YGUnwrapFloatOptional(child->getLeadingMargin(
  2640. crossAxis, availableInnerWidth)),
  2641. pos[crossAxis]);
  2642. }
  2643. } else {
  2644. float leadingCrossDim = leadingPaddingAndBorderCross;
  2645. // For a relative children, we're either using alignItems (owner) or
  2646. // alignSelf (child) in order to determine the position in the cross
  2647. // axis
  2648. const YGAlign alignItem = YGNodeAlignItem(node, child);
  2649. // If the child uses align stretch, we need to lay it out one more
  2650. // time, this time
  2651. // forcing the cross-axis size to be the computed cross size for the
  2652. // current line.
  2653. if (alignItem == YGAlignStretch &&
  2654. child->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
  2655. child->marginTrailingValue(crossAxis).unit != YGUnitAuto) {
  2656. // If the child defines a definite size for its cross axis, there's
  2657. // no need to stretch.
  2658. if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
  2659. float childMainSize =
  2660. child->getLayout().measuredDimensions[dim[mainAxis]];
  2661. float childCrossSize =
  2662. !child->getStyle().aspectRatio.isUndefined()
  2663. ? ((YGUnwrapFloatOptional(child->getMarginForAxis(
  2664. crossAxis, availableInnerWidth)) +
  2665. (isMainAxisRow ? childMainSize /
  2666. child->getStyle().aspectRatio.getValue()
  2667. : childMainSize *
  2668. child->getStyle().aspectRatio.getValue())))
  2669. : collectedFlexItemsValues.crossDim;
  2670. childMainSize += YGUnwrapFloatOptional(
  2671. child->getMarginForAxis(mainAxis, availableInnerWidth));
  2672. YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
  2673. YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly;
  2674. YGConstrainMaxSizeForMode(child,
  2675. mainAxis,
  2676. availableInnerMainDim,
  2677. availableInnerWidth,
  2678. &childMainMeasureMode,
  2679. &childMainSize);
  2680. YGConstrainMaxSizeForMode(child,
  2681. crossAxis,
  2682. availableInnerCrossDim,
  2683. availableInnerWidth,
  2684. &childCrossMeasureMode,
  2685. &childCrossSize);
  2686. const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
  2687. const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
  2688. const YGMeasureMode childWidthMeasureMode =
  2689. YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined
  2690. : YGMeasureModeExactly;
  2691. const YGMeasureMode childHeightMeasureMode =
  2692. YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined
  2693. : YGMeasureModeExactly;
  2694. YGLayoutNodeInternal(
  2695. child,
  2696. childWidth,
  2697. childHeight,
  2698. direction,
  2699. childWidthMeasureMode,
  2700. childHeightMeasureMode,
  2701. availableInnerWidth,
  2702. availableInnerHeight,
  2703. true,
  2704. "stretch",
  2705. config);
  2706. }
  2707. } else {
  2708. const float remainingCrossDim = containerCrossAxis -
  2709. YGNodeDimWithMargin(child, crossAxis, availableInnerWidth);
  2710. if (child->marginLeadingValue(crossAxis).unit == YGUnitAuto &&
  2711. child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
  2712. leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim / 2);
  2713. } else if (
  2714. child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
  2715. // No-Op
  2716. } else if (
  2717. child->marginLeadingValue(crossAxis).unit == YGUnitAuto) {
  2718. leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim);
  2719. } else if (alignItem == YGAlignFlexStart) {
  2720. // No-Op
  2721. } else if (alignItem == YGAlignCenter) {
  2722. leadingCrossDim += remainingCrossDim / 2;
  2723. } else {
  2724. leadingCrossDim += remainingCrossDim;
  2725. }
  2726. }
  2727. // And we apply the position
  2728. child->setLayoutPosition(
  2729. child->getLayout().position[pos[crossAxis]] + totalLineCrossDim +
  2730. leadingCrossDim,
  2731. pos[crossAxis]);
  2732. }
  2733. }
  2734. }
  2735. totalLineCrossDim += collectedFlexItemsValues.crossDim;
  2736. maxLineMainDim =
  2737. YGFloatMax(maxLineMainDim, collectedFlexItemsValues.mainDim);
  2738. }
  2739. // STEP 8: MULTI-LINE CONTENT ALIGNMENT
  2740. if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) &&
  2741. !YGFloatIsUndefined(availableInnerCrossDim)) {
  2742. const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
  2743. float crossDimLead = 0;
  2744. float currentLead = leadingPaddingAndBorderCross;
  2745. switch (node->getStyle().alignContent) {
  2746. case YGAlignFlexEnd:
  2747. currentLead += remainingAlignContentDim;
  2748. break;
  2749. case YGAlignCenter:
  2750. currentLead += remainingAlignContentDim / 2;
  2751. break;
  2752. case YGAlignStretch:
  2753. if (availableInnerCrossDim > totalLineCrossDim) {
  2754. crossDimLead = remainingAlignContentDim / lineCount;
  2755. }
  2756. break;
  2757. case YGAlignSpaceAround:
  2758. if (availableInnerCrossDim > totalLineCrossDim) {
  2759. currentLead += remainingAlignContentDim / (2 * lineCount);
  2760. if (lineCount > 1) {
  2761. crossDimLead = remainingAlignContentDim / lineCount;
  2762. }
  2763. } else {
  2764. currentLead += remainingAlignContentDim / 2;
  2765. }
  2766. break;
  2767. case YGAlignSpaceBetween:
  2768. if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) {
  2769. crossDimLead = remainingAlignContentDim / (lineCount - 1);
  2770. }
  2771. break;
  2772. case YGAlignAuto:
  2773. case YGAlignFlexStart:
  2774. case YGAlignBaseline:
  2775. break;
  2776. }
  2777. uint32_t endIndex = 0;
  2778. for (uint32_t i = 0; i < lineCount; i++) {
  2779. const uint32_t startIndex = endIndex;
  2780. uint32_t ii;
  2781. // compute the line's height and find the endIndex
  2782. float lineHeight = 0;
  2783. float maxAscentForCurrentLine = 0;
  2784. float maxDescentForCurrentLine = 0;
  2785. for (ii = startIndex; ii < childCount; ii++) {
  2786. const YGNodeRef child = node->getChild(ii);
  2787. if (child->getStyle().display == YGDisplayNone) {
  2788. continue;
  2789. }
  2790. if (child->getStyle().positionType == YGPositionTypeRelative) {
  2791. if (child->getLineIndex() != i) {
  2792. break;
  2793. }
  2794. if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
  2795. lineHeight = YGFloatMax(
  2796. lineHeight,
  2797. child->getLayout().measuredDimensions[dim[crossAxis]] +
  2798. YGUnwrapFloatOptional(child->getMarginForAxis(
  2799. crossAxis, availableInnerWidth)));
  2800. }
  2801. if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
  2802. const float ascent = YGBaseline(child) +
  2803. YGUnwrapFloatOptional(child->getLeadingMargin(
  2804. YGFlexDirectionColumn, availableInnerWidth));
  2805. const float descent =
  2806. child->getLayout().measuredDimensions[YGDimensionHeight] +
  2807. YGUnwrapFloatOptional(child->getMarginForAxis(
  2808. YGFlexDirectionColumn, availableInnerWidth)) -
  2809. ascent;
  2810. maxAscentForCurrentLine =
  2811. YGFloatMax(maxAscentForCurrentLine, ascent);
  2812. maxDescentForCurrentLine =
  2813. YGFloatMax(maxDescentForCurrentLine, descent);
  2814. lineHeight = YGFloatMax(
  2815. lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
  2816. }
  2817. }
  2818. }
  2819. endIndex = ii;
  2820. lineHeight += crossDimLead;
  2821. if (performLayout) {
  2822. for (ii = startIndex; ii < endIndex; ii++) {
  2823. const YGNodeRef child = node->getChild(ii);
  2824. if (child->getStyle().display == YGDisplayNone) {
  2825. continue;
  2826. }
  2827. if (child->getStyle().positionType == YGPositionTypeRelative) {
  2828. switch (YGNodeAlignItem(node, child)) {
  2829. case YGAlignFlexStart: {
  2830. child->setLayoutPosition(
  2831. currentLead +
  2832. YGUnwrapFloatOptional(child->getLeadingMargin(
  2833. crossAxis, availableInnerWidth)),
  2834. pos[crossAxis]);
  2835. break;
  2836. }
  2837. case YGAlignFlexEnd: {
  2838. child->setLayoutPosition(
  2839. currentLead + lineHeight -
  2840. YGUnwrapFloatOptional(child->getTrailingMargin(
  2841. crossAxis, availableInnerWidth)) -
  2842. child->getLayout().measuredDimensions[dim[crossAxis]],
  2843. pos[crossAxis]);
  2844. break;
  2845. }
  2846. case YGAlignCenter: {
  2847. float childHeight =
  2848. child->getLayout().measuredDimensions[dim[crossAxis]];
  2849. child->setLayoutPosition(
  2850. currentLead + (lineHeight - childHeight) / 2,
  2851. pos[crossAxis]);
  2852. break;
  2853. }
  2854. case YGAlignStretch: {
  2855. child->setLayoutPosition(
  2856. currentLead +
  2857. YGUnwrapFloatOptional(child->getLeadingMargin(
  2858. crossAxis, availableInnerWidth)),
  2859. pos[crossAxis]);
  2860. // Remeasure child with the line height as it as been only measured with the
  2861. // owners height yet.
  2862. if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
  2863. const float childWidth = isMainAxisRow
  2864. ? (child->getLayout()
  2865. .measuredDimensions[YGDimensionWidth] +
  2866. YGUnwrapFloatOptional(child->getMarginForAxis(
  2867. mainAxis, availableInnerWidth)))
  2868. : lineHeight;
  2869. const float childHeight = !isMainAxisRow
  2870. ? (child->getLayout()
  2871. .measuredDimensions[YGDimensionHeight] +
  2872. YGUnwrapFloatOptional(child->getMarginForAxis(
  2873. crossAxis, availableInnerWidth)))
  2874. : lineHeight;
  2875. if (!(YGFloatsEqual(
  2876. childWidth,
  2877. child->getLayout()
  2878. .measuredDimensions[YGDimensionWidth]) &&
  2879. YGFloatsEqual(
  2880. childHeight,
  2881. child->getLayout()
  2882. .measuredDimensions[YGDimensionHeight]))) {
  2883. YGLayoutNodeInternal(child,
  2884. childWidth,
  2885. childHeight,
  2886. direction,
  2887. YGMeasureModeExactly,
  2888. YGMeasureModeExactly,
  2889. availableInnerWidth,
  2890. availableInnerHeight,
  2891. true,
  2892. "multiline-stretch",
  2893. config);
  2894. }
  2895. }
  2896. break;
  2897. }
  2898. case YGAlignBaseline: {
  2899. child->setLayoutPosition(
  2900. currentLead + maxAscentForCurrentLine - YGBaseline(child) +
  2901. YGUnwrapFloatOptional(child->getLeadingPosition(
  2902. YGFlexDirectionColumn, availableInnerCrossDim)),
  2903. YGEdgeTop);
  2904. break;
  2905. }
  2906. case YGAlignAuto:
  2907. case YGAlignSpaceBetween:
  2908. case YGAlignSpaceAround:
  2909. break;
  2910. }
  2911. }
  2912. }
  2913. }
  2914. currentLead += lineHeight;
  2915. }
  2916. }
  2917. // STEP 9: COMPUTING FINAL DIMENSIONS
  2918. node->setLayoutMeasuredDimension(
  2919. YGNodeBoundAxis(
  2920. node,
  2921. YGFlexDirectionRow,
  2922. availableWidth - marginAxisRow,
  2923. ownerWidth,
  2924. ownerWidth),
  2925. YGDimensionWidth);
  2926. node->setLayoutMeasuredDimension(
  2927. YGNodeBoundAxis(
  2928. node,
  2929. YGFlexDirectionColumn,
  2930. availableHeight - marginAxisColumn,
  2931. ownerHeight,
  2932. ownerWidth),
  2933. YGDimensionHeight);
  2934. // If the user didn't specify a width or height for the node, set the
  2935. // dimensions based on the children.
  2936. if (measureModeMainDim == YGMeasureModeUndefined ||
  2937. (node->getStyle().overflow != YGOverflowScroll &&
  2938. measureModeMainDim == YGMeasureModeAtMost)) {
  2939. // Clamp the size to the min/max size, if specified, and make sure it
  2940. // doesn't go below the padding and border amount.
  2941. node->setLayoutMeasuredDimension(
  2942. YGNodeBoundAxis(
  2943. node, mainAxis, maxLineMainDim, mainAxisownerSize, ownerWidth),
  2944. dim[mainAxis]);
  2945. } else if (
  2946. measureModeMainDim == YGMeasureModeAtMost &&
  2947. node->getStyle().overflow == YGOverflowScroll) {
  2948. node->setLayoutMeasuredDimension(
  2949. YGFloatMax(
  2950. YGFloatMin(
  2951. availableInnerMainDim + paddingAndBorderAxisMain,
  2952. YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
  2953. node, mainAxis, maxLineMainDim, mainAxisownerSize))),
  2954. paddingAndBorderAxisMain),
  2955. dim[mainAxis]);
  2956. }
  2957. if (measureModeCrossDim == YGMeasureModeUndefined ||
  2958. (node->getStyle().overflow != YGOverflowScroll &&
  2959. measureModeCrossDim == YGMeasureModeAtMost)) {
  2960. // Clamp the size to the min/max size, if specified, and make sure it
  2961. // doesn't go below the padding and border amount.
  2962. node->setLayoutMeasuredDimension(
  2963. YGNodeBoundAxis(
  2964. node,
  2965. crossAxis,
  2966. totalLineCrossDim + paddingAndBorderAxisCross,
  2967. crossAxisownerSize,
  2968. ownerWidth),
  2969. dim[crossAxis]);
  2970. } else if (
  2971. measureModeCrossDim == YGMeasureModeAtMost &&
  2972. node->getStyle().overflow == YGOverflowScroll) {
  2973. node->setLayoutMeasuredDimension(
  2974. YGFloatMax(
  2975. YGFloatMin(
  2976. availableInnerCrossDim + paddingAndBorderAxisCross,
  2977. YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
  2978. node,
  2979. crossAxis,
  2980. totalLineCrossDim + paddingAndBorderAxisCross,
  2981. crossAxisownerSize))),
  2982. paddingAndBorderAxisCross),
  2983. dim[crossAxis]);
  2984. }
  2985. // As we only wrapped in normal direction yet, we need to reverse the positions on wrap-reverse.
  2986. if (performLayout && node->getStyle().flexWrap == YGWrapWrapReverse) {
  2987. for (uint32_t i = 0; i < childCount; i++) {
  2988. const YGNodeRef child = YGNodeGetChild(node, i);
  2989. if (child->getStyle().positionType == YGPositionTypeRelative) {
  2990. child->setLayoutPosition(
  2991. node->getLayout().measuredDimensions[dim[crossAxis]] -
  2992. child->getLayout().position[pos[crossAxis]] -
  2993. child->getLayout().measuredDimensions[dim[crossAxis]],
  2994. pos[crossAxis]);
  2995. }
  2996. }
  2997. }
  2998. if (performLayout) {
  2999. // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
  3000. for (auto child : node->getChildren()) {
  3001. if (child->getStyle().positionType != YGPositionTypeAbsolute) {
  3002. continue;
  3003. }
  3004. YGNodeAbsoluteLayoutChild(
  3005. node,
  3006. child,
  3007. availableInnerWidth,
  3008. isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
  3009. availableInnerHeight,
  3010. direction,
  3011. config);
  3012. }
  3013. // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
  3014. const bool needsMainTrailingPos =
  3015. mainAxis == YGFlexDirectionRowReverse || mainAxis == YGFlexDirectionColumnReverse;
  3016. const bool needsCrossTrailingPos =
  3017. crossAxis == YGFlexDirectionRowReverse || crossAxis == YGFlexDirectionColumnReverse;
  3018. // Set trailing position if necessary.
  3019. if (needsMainTrailingPos || needsCrossTrailingPos) {
  3020. for (uint32_t i = 0; i < childCount; i++) {
  3021. const YGNodeRef child = node->getChild(i);
  3022. if (child->getStyle().display == YGDisplayNone) {
  3023. continue;
  3024. }
  3025. if (needsMainTrailingPos) {
  3026. YGNodeSetChildTrailingPosition(node, child, mainAxis);
  3027. }
  3028. if (needsCrossTrailingPos) {
  3029. YGNodeSetChildTrailingPosition(node, child, crossAxis);
  3030. }
  3031. }
  3032. }
  3033. }
  3034. }
  3035. uint32_t gDepth = 0;
  3036. bool gPrintTree = false;
  3037. bool gPrintChanges = false;
  3038. bool gPrintSkips = false;
  3039. static const char *spacer = " ";
  3040. static const char *YGSpacer(const unsigned long level) {
  3041. const size_t spacerLen = strlen(spacer);
  3042. if (level > spacerLen) {
  3043. return &spacer[0];
  3044. } else {
  3045. return &spacer[spacerLen - level];
  3046. }
  3047. }
  3048. static const char *YGMeasureModeName(const YGMeasureMode mode, const bool performLayout) {
  3049. const char *kMeasureModeNames[YGMeasureModeCount] = {"UNDEFINED", "EXACTLY", "AT_MOST"};
  3050. const char *kLayoutModeNames[YGMeasureModeCount] = {"LAY_UNDEFINED",
  3051. "LAY_EXACTLY",
  3052. "LAY_AT_"
  3053. "MOST"};
  3054. if (mode >= YGMeasureModeCount) {
  3055. return "";
  3056. }
  3057. return performLayout ? kLayoutModeNames[mode] : kMeasureModeNames[mode];
  3058. }
  3059. static inline bool YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(YGMeasureMode sizeMode,
  3060. float size,
  3061. float lastComputedSize) {
  3062. return sizeMode == YGMeasureModeExactly && YGFloatsEqual(size, lastComputedSize);
  3063. }
  3064. static inline bool YGMeasureModeOldSizeIsUnspecifiedAndStillFits(YGMeasureMode sizeMode,
  3065. float size,
  3066. YGMeasureMode lastSizeMode,
  3067. float lastComputedSize) {
  3068. return sizeMode == YGMeasureModeAtMost && lastSizeMode == YGMeasureModeUndefined &&
  3069. (size >= lastComputedSize || YGFloatsEqual(size, lastComputedSize));
  3070. }
  3071. static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(YGMeasureMode sizeMode,
  3072. float size,
  3073. YGMeasureMode lastSizeMode,
  3074. float lastSize,
  3075. float lastComputedSize) {
  3076. return lastSizeMode == YGMeasureModeAtMost &&
  3077. sizeMode == YGMeasureModeAtMost && !YGFloatIsUndefined(lastSize) &&
  3078. !YGFloatIsUndefined(size) && !YGFloatIsUndefined(lastComputedSize) &&
  3079. lastSize > size &&
  3080. (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
  3081. }
  3082. float YGRoundValueToPixelGrid(const float value,
  3083. const float pointScaleFactor,
  3084. const bool forceCeil,
  3085. const bool forceFloor) {
  3086. float scaledValue = value * pointScaleFactor;
  3087. float fractial = fmodf(scaledValue, 1.0f);
  3088. if (YGFloatsEqual(fractial, 0)) {
  3089. // First we check if the value is already rounded
  3090. scaledValue = scaledValue - fractial;
  3091. } else if (YGFloatsEqual(fractial, 1.0f)) {
  3092. scaledValue = scaledValue - fractial + 1.0f;
  3093. } else if (forceCeil) {
  3094. // Next we check if we need to use forced rounding
  3095. scaledValue = scaledValue - fractial + 1.0f;
  3096. } else if (forceFloor) {
  3097. scaledValue = scaledValue - fractial;
  3098. } else {
  3099. // Finally we just round the value
  3100. scaledValue = scaledValue - fractial +
  3101. (!YGFloatIsUndefined(fractial) &&
  3102. (fractial > 0.5f || YGFloatsEqual(fractial, 0.5f))
  3103. ? 1.0f
  3104. : 0.0f);
  3105. }
  3106. return (YGFloatIsUndefined(scaledValue) ||
  3107. YGFloatIsUndefined(pointScaleFactor))
  3108. ? YGUndefined
  3109. : scaledValue / pointScaleFactor;
  3110. }
  3111. bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
  3112. const float width,
  3113. const YGMeasureMode heightMode,
  3114. const float height,
  3115. const YGMeasureMode lastWidthMode,
  3116. const float lastWidth,
  3117. const YGMeasureMode lastHeightMode,
  3118. const float lastHeight,
  3119. const float lastComputedWidth,
  3120. const float lastComputedHeight,
  3121. const float marginRow,
  3122. const float marginColumn,
  3123. const YGConfigRef config) {
  3124. if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) ||
  3125. (!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) {
  3126. return false;
  3127. }
  3128. bool useRoundedComparison =
  3129. config != nullptr && config->pointScaleFactor != 0;
  3130. const float effectiveWidth =
  3131. useRoundedComparison ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false)
  3132. : width;
  3133. const float effectiveHeight =
  3134. useRoundedComparison ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false)
  3135. : height;
  3136. const float effectiveLastWidth =
  3137. useRoundedComparison
  3138. ? YGRoundValueToPixelGrid(lastWidth, config->pointScaleFactor, false, false)
  3139. : lastWidth;
  3140. const float effectiveLastHeight =
  3141. useRoundedComparison
  3142. ? YGRoundValueToPixelGrid(lastHeight, config->pointScaleFactor, false, false)
  3143. : lastHeight;
  3144. const bool hasSameWidthSpec =
  3145. lastWidthMode == widthMode && YGFloatsEqual(effectiveLastWidth, effectiveWidth);
  3146. const bool hasSameHeightSpec =
  3147. lastHeightMode == heightMode && YGFloatsEqual(effectiveLastHeight, effectiveHeight);
  3148. const bool widthIsCompatible =
  3149. hasSameWidthSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(widthMode,
  3150. width - marginRow,
  3151. lastComputedWidth) ||
  3152. YGMeasureModeOldSizeIsUnspecifiedAndStillFits(widthMode,
  3153. width - marginRow,
  3154. lastWidthMode,
  3155. lastComputedWidth) ||
  3156. YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
  3157. widthMode, width - marginRow, lastWidthMode, lastWidth, lastComputedWidth);
  3158. const bool heightIsCompatible =
  3159. hasSameHeightSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(heightMode,
  3160. height - marginColumn,
  3161. lastComputedHeight) ||
  3162. YGMeasureModeOldSizeIsUnspecifiedAndStillFits(heightMode,
  3163. height - marginColumn,
  3164. lastHeightMode,
  3165. lastComputedHeight) ||
  3166. YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
  3167. heightMode, height - marginColumn, lastHeightMode, lastHeight, lastComputedHeight);
  3168. return widthIsCompatible && heightIsCompatible;
  3169. }
  3170. //
  3171. // This is a wrapper around the YGNodelayoutImpl function. It determines
  3172. // whether the layout request is redundant and can be skipped.
  3173. //
  3174. // Parameters:
  3175. // Input parameters are the same as YGNodelayoutImpl (see above)
  3176. // Return parameter is true if layout was performed, false if skipped
  3177. //
  3178. bool YGLayoutNodeInternal(const YGNodeRef node,
  3179. const float availableWidth,
  3180. const float availableHeight,
  3181. const YGDirection ownerDirection,
  3182. const YGMeasureMode widthMeasureMode,
  3183. const YGMeasureMode heightMeasureMode,
  3184. const float ownerWidth,
  3185. const float ownerHeight,
  3186. const bool performLayout,
  3187. const char *reason,
  3188. const YGConfigRef config) {
  3189. YGLayout* layout = &node->getLayout();
  3190. gDepth++;
  3191. const bool needToVisitNode =
  3192. (node->isDirty() && layout->generationCount != gCurrentGenerationCount) ||
  3193. layout->lastOwnerDirection != ownerDirection;
  3194. if (needToVisitNode) {
  3195. // Invalidate the cached results.
  3196. layout->nextCachedMeasurementsIndex = 0;
  3197. layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1;
  3198. layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1;
  3199. layout->cachedLayout.computedWidth = -1;
  3200. layout->cachedLayout.computedHeight = -1;
  3201. }
  3202. YGCachedMeasurement* cachedResults = nullptr;
  3203. // Determine whether the results are already cached. We maintain a separate
  3204. // cache for layouts and measurements. A layout operation modifies the
  3205. // positions
  3206. // and dimensions for nodes in the subtree. The algorithm assumes that each
  3207. // node
  3208. // gets layed out a maximum of one time per tree layout, but multiple
  3209. // measurements
  3210. // may be required to resolve all of the flex dimensions.
  3211. // We handle nodes with measure functions specially here because they are the
  3212. // most
  3213. // expensive to measure, so it's worth avoiding redundant measurements if at
  3214. // all possible.
  3215. if (node->getMeasure() != nullptr) {
  3216. const float marginAxisRow = YGUnwrapFloatOptional(
  3217. node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
  3218. const float marginAxisColumn = YGUnwrapFloatOptional(
  3219. node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
  3220. // First, try to use the layout cache.
  3221. if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
  3222. availableWidth,
  3223. heightMeasureMode,
  3224. availableHeight,
  3225. layout->cachedLayout.widthMeasureMode,
  3226. layout->cachedLayout.availableWidth,
  3227. layout->cachedLayout.heightMeasureMode,
  3228. layout->cachedLayout.availableHeight,
  3229. layout->cachedLayout.computedWidth,
  3230. layout->cachedLayout.computedHeight,
  3231. marginAxisRow,
  3232. marginAxisColumn,
  3233. config)) {
  3234. cachedResults = &layout->cachedLayout;
  3235. } else {
  3236. // Try to use the measurement cache.
  3237. for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
  3238. if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
  3239. availableWidth,
  3240. heightMeasureMode,
  3241. availableHeight,
  3242. layout->cachedMeasurements[i].widthMeasureMode,
  3243. layout->cachedMeasurements[i].availableWidth,
  3244. layout->cachedMeasurements[i].heightMeasureMode,
  3245. layout->cachedMeasurements[i].availableHeight,
  3246. layout->cachedMeasurements[i].computedWidth,
  3247. layout->cachedMeasurements[i].computedHeight,
  3248. marginAxisRow,
  3249. marginAxisColumn,
  3250. config)) {
  3251. cachedResults = &layout->cachedMeasurements[i];
  3252. break;
  3253. }
  3254. }
  3255. }
  3256. } else if (performLayout) {
  3257. if (YGFloatsEqual(layout->cachedLayout.availableWidth, availableWidth) &&
  3258. YGFloatsEqual(layout->cachedLayout.availableHeight, availableHeight) &&
  3259. layout->cachedLayout.widthMeasureMode == widthMeasureMode &&
  3260. layout->cachedLayout.heightMeasureMode == heightMeasureMode) {
  3261. cachedResults = &layout->cachedLayout;
  3262. }
  3263. } else {
  3264. for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
  3265. if (YGFloatsEqual(layout->cachedMeasurements[i].availableWidth, availableWidth) &&
  3266. YGFloatsEqual(layout->cachedMeasurements[i].availableHeight, availableHeight) &&
  3267. layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode &&
  3268. layout->cachedMeasurements[i].heightMeasureMode == heightMeasureMode) {
  3269. cachedResults = &layout->cachedMeasurements[i];
  3270. break;
  3271. }
  3272. }
  3273. }
  3274. if (!needToVisitNode && cachedResults != nullptr) {
  3275. layout->measuredDimensions[YGDimensionWidth] = cachedResults->computedWidth;
  3276. layout->measuredDimensions[YGDimensionHeight] = cachedResults->computedHeight;
  3277. if (gPrintChanges && gPrintSkips) {
  3278. YGLog(node, YGLogLevelVerbose, "%s%d.{[skipped] ", YGSpacer(gDepth), gDepth);
  3279. if (node->getPrintFunc() != nullptr) {
  3280. node->getPrintFunc()(node);
  3281. }
  3282. YGLog(
  3283. node,
  3284. YGLogLevelVerbose,
  3285. "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n",
  3286. YGMeasureModeName(widthMeasureMode, performLayout),
  3287. YGMeasureModeName(heightMeasureMode, performLayout),
  3288. availableWidth,
  3289. availableHeight,
  3290. cachedResults->computedWidth,
  3291. cachedResults->computedHeight,
  3292. reason);
  3293. }
  3294. } else {
  3295. if (gPrintChanges) {
  3296. YGLog(
  3297. node,
  3298. YGLogLevelVerbose,
  3299. "%s%d.{%s",
  3300. YGSpacer(gDepth),
  3301. gDepth,
  3302. needToVisitNode ? "*" : "");
  3303. if (node->getPrintFunc() != nullptr) {
  3304. node->getPrintFunc()(node);
  3305. }
  3306. YGLog(
  3307. node,
  3308. YGLogLevelVerbose,
  3309. "wm: %s, hm: %s, aw: %f ah: %f %s\n",
  3310. YGMeasureModeName(widthMeasureMode, performLayout),
  3311. YGMeasureModeName(heightMeasureMode, performLayout),
  3312. availableWidth,
  3313. availableHeight,
  3314. reason);
  3315. }
  3316. YGNodelayoutImpl(node,
  3317. availableWidth,
  3318. availableHeight,
  3319. ownerDirection,
  3320. widthMeasureMode,
  3321. heightMeasureMode,
  3322. ownerWidth,
  3323. ownerHeight,
  3324. performLayout,
  3325. config);
  3326. if (gPrintChanges) {
  3327. YGLog(
  3328. node,
  3329. YGLogLevelVerbose,
  3330. "%s%d.}%s",
  3331. YGSpacer(gDepth),
  3332. gDepth,
  3333. needToVisitNode ? "*" : "");
  3334. if (node->getPrintFunc() != nullptr) {
  3335. node->getPrintFunc()(node);
  3336. }
  3337. YGLog(
  3338. node,
  3339. YGLogLevelVerbose,
  3340. "wm: %s, hm: %s, d: (%f, %f) %s\n",
  3341. YGMeasureModeName(widthMeasureMode, performLayout),
  3342. YGMeasureModeName(heightMeasureMode, performLayout),
  3343. layout->measuredDimensions[YGDimensionWidth],
  3344. layout->measuredDimensions[YGDimensionHeight],
  3345. reason);
  3346. }
  3347. layout->lastOwnerDirection = ownerDirection;
  3348. if (cachedResults == nullptr) {
  3349. if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) {
  3350. if (gPrintChanges) {
  3351. YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n");
  3352. }
  3353. layout->nextCachedMeasurementsIndex = 0;
  3354. }
  3355. YGCachedMeasurement *newCacheEntry;
  3356. if (performLayout) {
  3357. // Use the single layout cache entry.
  3358. newCacheEntry = &layout->cachedLayout;
  3359. } else {
  3360. // Allocate a new measurement cache entry.
  3361. newCacheEntry = &layout->cachedMeasurements[layout->nextCachedMeasurementsIndex];
  3362. layout->nextCachedMeasurementsIndex++;
  3363. }
  3364. newCacheEntry->availableWidth = availableWidth;
  3365. newCacheEntry->availableHeight = availableHeight;
  3366. newCacheEntry->widthMeasureMode = widthMeasureMode;
  3367. newCacheEntry->heightMeasureMode = heightMeasureMode;
  3368. newCacheEntry->computedWidth = layout->measuredDimensions[YGDimensionWidth];
  3369. newCacheEntry->computedHeight = layout->measuredDimensions[YGDimensionHeight];
  3370. }
  3371. }
  3372. if (performLayout) {
  3373. node->setLayoutDimension(
  3374. node->getLayout().measuredDimensions[YGDimensionWidth],
  3375. YGDimensionWidth);
  3376. node->setLayoutDimension(
  3377. node->getLayout().measuredDimensions[YGDimensionHeight],
  3378. YGDimensionHeight);
  3379. node->setHasNewLayout(true);
  3380. node->setDirty(false);
  3381. }
  3382. gDepth--;
  3383. layout->generationCount = gCurrentGenerationCount;
  3384. return (needToVisitNode || cachedResults == nullptr);
  3385. }
  3386. void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint) {
  3387. YGAssertWithConfig(config, pixelsInPoint >= 0.0f, "Scale factor should not be less than zero");
  3388. // We store points for Pixel as we will use it for rounding
  3389. if (pixelsInPoint == 0.0f) {
  3390. // Zero is used to skip rounding
  3391. config->pointScaleFactor = 0.0f;
  3392. } else {
  3393. config->pointScaleFactor = pixelsInPoint;
  3394. }
  3395. }
  3396. static void YGRoundToPixelGrid(const YGNodeRef node,
  3397. const float pointScaleFactor,
  3398. const float absoluteLeft,
  3399. const float absoluteTop) {
  3400. if (pointScaleFactor == 0.0f) {
  3401. return;
  3402. }
  3403. const float nodeLeft = node->getLayout().position[YGEdgeLeft];
  3404. const float nodeTop = node->getLayout().position[YGEdgeTop];
  3405. const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth];
  3406. const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight];
  3407. const float absoluteNodeLeft = absoluteLeft + nodeLeft;
  3408. const float absoluteNodeTop = absoluteTop + nodeTop;
  3409. const float absoluteNodeRight = absoluteNodeLeft + nodeWidth;
  3410. const float absoluteNodeBottom = absoluteNodeTop + nodeHeight;
  3411. // If a node has a custom measure function we never want to round down its size as this could
  3412. // lead to unwanted text truncation.
  3413. const bool textRounding = node->getNodeType() == YGNodeTypeText;
  3414. node->setLayoutPosition(
  3415. YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding),
  3416. YGEdgeLeft);
  3417. node->setLayoutPosition(
  3418. YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
  3419. YGEdgeTop);
  3420. // We multiply dimension by scale factor and if the result is close to the whole number, we don't
  3421. // have any fraction
  3422. // To verify if the result is close to whole number we want to check both floor and ceil numbers
  3423. const bool hasFractionalWidth = !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) &&
  3424. !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0);
  3425. const bool hasFractionalHeight = !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) &&
  3426. !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0);
  3427. node->setLayoutDimension(
  3428. YGRoundValueToPixelGrid(
  3429. absoluteNodeRight,
  3430. pointScaleFactor,
  3431. (textRounding && hasFractionalWidth),
  3432. (textRounding && !hasFractionalWidth)) -
  3433. YGRoundValueToPixelGrid(
  3434. absoluteNodeLeft, pointScaleFactor, false, textRounding),
  3435. YGDimensionWidth);
  3436. node->setLayoutDimension(
  3437. YGRoundValueToPixelGrid(
  3438. absoluteNodeBottom,
  3439. pointScaleFactor,
  3440. (textRounding && hasFractionalHeight),
  3441. (textRounding && !hasFractionalHeight)) -
  3442. YGRoundValueToPixelGrid(
  3443. absoluteNodeTop, pointScaleFactor, false, textRounding),
  3444. YGDimensionHeight);
  3445. const uint32_t childCount = YGNodeGetChildCount(node);
  3446. for (uint32_t i = 0; i < childCount; i++) {
  3447. YGRoundToPixelGrid(
  3448. YGNodeGetChild(node, i),
  3449. pointScaleFactor,
  3450. absoluteNodeLeft,
  3451. absoluteNodeTop);
  3452. }
  3453. }
  3454. void YGNodeCalculateLayout(
  3455. const YGNodeRef node,
  3456. const float ownerWidth,
  3457. const float ownerHeight,
  3458. const YGDirection ownerDirection) {
  3459. // Increment the generation count. This will force the recursive routine to
  3460. // visit
  3461. // all dirty nodes at least once. Subsequent visits will be skipped if the
  3462. // input
  3463. // parameters don't change.
  3464. gCurrentGenerationCount++;
  3465. node->resolveDimension();
  3466. float width = YGUndefined;
  3467. YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
  3468. if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) {
  3469. width = YGUnwrapFloatOptional(
  3470. YGResolveValue(
  3471. node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) +
  3472. node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
  3473. widthMeasureMode = YGMeasureModeExactly;
  3474. } else if (!YGResolveValue(
  3475. node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
  3476. .isUndefined()) {
  3477. width = YGUnwrapFloatOptional(YGResolveValue(
  3478. node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth));
  3479. widthMeasureMode = YGMeasureModeAtMost;
  3480. } else {
  3481. width = ownerWidth;
  3482. widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined
  3483. : YGMeasureModeExactly;
  3484. }
  3485. float height = YGUndefined;
  3486. YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
  3487. if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) {
  3488. height = YGUnwrapFloatOptional(
  3489. YGResolveValue(
  3490. node->getResolvedDimension(dim[YGFlexDirectionColumn]),
  3491. ownerHeight) +
  3492. node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
  3493. heightMeasureMode = YGMeasureModeExactly;
  3494. } else if (!YGResolveValue(
  3495. node->getStyle().maxDimensions[YGDimensionHeight],
  3496. ownerHeight)
  3497. .isUndefined()) {
  3498. height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight));
  3499. heightMeasureMode = YGMeasureModeAtMost;
  3500. } else {
  3501. height = ownerHeight;
  3502. heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined
  3503. : YGMeasureModeExactly;
  3504. }
  3505. if (YGLayoutNodeInternal(
  3506. node,
  3507. width,
  3508. height,
  3509. ownerDirection,
  3510. widthMeasureMode,
  3511. heightMeasureMode,
  3512. ownerWidth,
  3513. ownerHeight,
  3514. true,
  3515. "initial",
  3516. node->getConfig())) {
  3517. node->setPosition(
  3518. node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth);
  3519. YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
  3520. if (gPrintTree) {
  3521. YGNodePrint(
  3522. node,
  3523. (YGPrintOptions)(
  3524. YGPrintOptionsLayout | YGPrintOptionsChildren |
  3525. YGPrintOptionsStyle));
  3526. }
  3527. }
  3528. // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we
  3529. // aren't sure whether client's of yoga have gotten rid off this flag or not.
  3530. // So logging this in YGLayout would help to find out the call sites depending
  3531. // on this flag. This check would be removed once we are sure no one is
  3532. // dependent on this flag anymore. The flag
  3533. // `shouldDiffLayoutWithoutLegacyStretchBehaviour` in YGConfig will help to
  3534. // run experiments.
  3535. if (node->getConfig()->shouldDiffLayoutWithoutLegacyStretchBehaviour &&
  3536. node->didUseLegacyFlag()) {
  3537. const YGNodeRef originalNode = YGNodeDeepClone(node);
  3538. originalNode->resolveDimension();
  3539. // Recursively mark nodes as dirty
  3540. originalNode->markDirtyAndPropogateDownwards();
  3541. gCurrentGenerationCount++;
  3542. // Rerun the layout, and calculate the diff
  3543. originalNode->setAndPropogateUseLegacyFlag(false);
  3544. if (YGLayoutNodeInternal(
  3545. originalNode,
  3546. width,
  3547. height,
  3548. ownerDirection,
  3549. widthMeasureMode,
  3550. heightMeasureMode,
  3551. ownerWidth,
  3552. ownerHeight,
  3553. true,
  3554. "initial",
  3555. originalNode->getConfig())) {
  3556. originalNode->setPosition(
  3557. originalNode->getLayout().direction,
  3558. ownerWidth,
  3559. ownerHeight,
  3560. ownerWidth);
  3561. YGRoundToPixelGrid(
  3562. originalNode,
  3563. originalNode->getConfig()->pointScaleFactor,
  3564. 0.0f,
  3565. 0.0f);
  3566. // Set whether the two layouts are different or not.
  3567. node->setLayoutDoesLegacyFlagAffectsLayout(
  3568. !originalNode->isLayoutTreeEqualToNode(*node));
  3569. if (gPrintTree) {
  3570. YGNodePrint(
  3571. originalNode,
  3572. (YGPrintOptions)(
  3573. YGPrintOptionsLayout | YGPrintOptionsChildren |
  3574. YGPrintOptionsStyle));
  3575. }
  3576. }
  3577. YGConfigFreeRecursive(originalNode);
  3578. YGNodeFreeRecursive(originalNode);
  3579. }
  3580. }
  3581. void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
  3582. if (logger != nullptr) {
  3583. config->logger = logger;
  3584. } else {
  3585. #ifdef ANDROID
  3586. config->logger = &YGAndroidLog;
  3587. #else
  3588. config->logger = &YGDefaultLog;
  3589. #endif
  3590. }
  3591. }
  3592. void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
  3593. const YGConfigRef config,
  3594. const bool shouldDiffLayout) {
  3595. config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout;
  3596. }
  3597. static void YGVLog(const YGConfigRef config,
  3598. const YGNodeRef node,
  3599. YGLogLevel level,
  3600. const char *format,
  3601. va_list args) {
  3602. const YGConfigRef logConfig = config != nullptr ? config : YGConfigGetDefault();
  3603. logConfig->logger(logConfig, node, level, format, args);
  3604. if (level == YGLogLevelFatal) {
  3605. abort();
  3606. }
  3607. }
  3608. void YGLogWithConfig(const YGConfigRef config, YGLogLevel level, const char *format, ...) {
  3609. va_list args;
  3610. va_start(args, format);
  3611. YGVLog(config, nullptr, level, format, args);
  3612. va_end(args);
  3613. }
  3614. void YGLog(const YGNodeRef node, YGLogLevel level, const char *format, ...) {
  3615. va_list args;
  3616. va_start(args, format);
  3617. YGVLog(
  3618. node == nullptr ? nullptr : node->getConfig(), node, level, format, args);
  3619. va_end(args);
  3620. }
  3621. void YGAssert(const bool condition, const char *message) {
  3622. if (!condition) {
  3623. YGLog(nullptr, YGLogLevelFatal, "%s\n", message);
  3624. }
  3625. }
  3626. void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message) {
  3627. if (!condition) {
  3628. YGLog(node, YGLogLevelFatal, "%s\n", message);
  3629. }
  3630. }
  3631. void YGAssertWithConfig(const YGConfigRef config, const bool condition, const char *message) {
  3632. if (!condition) {
  3633. YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message);
  3634. }
  3635. }
  3636. void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
  3637. const YGExperimentalFeature feature,
  3638. const bool enabled) {
  3639. config->experimentalFeatures[feature] = enabled;
  3640. }
  3641. inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
  3642. const YGExperimentalFeature feature) {
  3643. return config->experimentalFeatures[feature];
  3644. }
  3645. void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
  3646. config->useWebDefaults = enabled;
  3647. }
  3648. void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config,
  3649. const bool useLegacyStretchBehaviour) {
  3650. config->useLegacyStretchBehaviour = useLegacyStretchBehaviour;
  3651. }
  3652. bool YGConfigGetUseWebDefaults(const YGConfigRef config) {
  3653. return config->useWebDefaults;
  3654. }
  3655. void YGConfigSetContext(const YGConfigRef config, void *context) {
  3656. config->context = context;
  3657. }
  3658. void *YGConfigGetContext(const YGConfigRef config) {
  3659. return config->context;
  3660. }
  3661. void YGConfigSetCloneNodeFunc(const YGConfigRef config, const YGCloneNodeFunc callback) {
  3662. config->cloneNodeCallback = callback;
  3663. }
  3664. static void YGTraverseChildrenPreOrder(const YGVector& children, const std::function<void(YGNodeRef node)>& f) {
  3665. for (YGNodeRef node : children) {
  3666. f(node);
  3667. YGTraverseChildrenPreOrder(node->getChildren(), f);
  3668. }
  3669. }
  3670. void YGTraversePreOrder(YGNodeRef const node, std::function<void(YGNodeRef node)>&& f) {
  3671. if (!node) {
  3672. return;
  3673. }
  3674. f(node);
  3675. YGTraverseChildrenPreOrder(node->getChildren(), f);
  3676. }