123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056 |
- /*
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the LICENSE
- * file in the root directory of this source tree.
- *
- */
- #include "Yoga.h"
- #include <float.h>
- #include <string.h>
- #include <algorithm>
- #include "Utils.h"
- #include "YGNode.h"
- #include "YGNodePrint.h"
- #include "Yoga-internal.h"
- #ifdef _MSC_VER
- #include <float.h>
- /* define fmaxf if < VC12 */
- #if _MSC_VER < 1800
- __forceinline const float fmaxf(const float a, const float b) {
- if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
- return (a > b) ? a : b;
- }
- return YGFloatIsUndefined(a) ? b : a;
- }
- #endif
- #endif
- #ifdef ANDROID
- static int YGAndroidLog(const YGConfigRef config,
- const YGNodeRef node,
- YGLogLevel level,
- const char *format,
- va_list args);
- #else
- static int YGDefaultLog(const YGConfigRef config,
- const YGNodeRef node,
- YGLogLevel level,
- const char *format,
- va_list args);
- #endif
- const YGValue YGValueZero = {0, YGUnitPoint};
- const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
- const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
- #ifdef ANDROID
- #include <android/log.h>
- static int YGAndroidLog(const YGConfigRef config,
- const YGNodeRef node,
- YGLogLevel level,
- const char *format,
- va_list args) {
- int androidLevel = YGLogLevelDebug;
- switch (level) {
- case YGLogLevelFatal:
- androidLevel = ANDROID_LOG_FATAL;
- break;
- case YGLogLevelError:
- androidLevel = ANDROID_LOG_ERROR;
- break;
- case YGLogLevelWarn:
- androidLevel = ANDROID_LOG_WARN;
- break;
- case YGLogLevelInfo:
- androidLevel = ANDROID_LOG_INFO;
- break;
- case YGLogLevelDebug:
- androidLevel = ANDROID_LOG_DEBUG;
- break;
- case YGLogLevelVerbose:
- androidLevel = ANDROID_LOG_VERBOSE;
- break;
- }
- const int result = __android_log_vprint(androidLevel, "yoga", format, args);
- return result;
- }
- #else
- #define YG_UNUSED(x) (void)(x);
- static int YGDefaultLog(const YGConfigRef config,
- const YGNodeRef node,
- YGLogLevel level,
- const char *format,
- va_list args) {
- YG_UNUSED(config);
- YG_UNUSED(node);
- switch (level) {
- case YGLogLevelError:
- case YGLogLevelFatal:
- return vfprintf(stderr, format, args);
- case YGLogLevelWarn:
- case YGLogLevelInfo:
- case YGLogLevelDebug:
- case YGLogLevelVerbose:
- default:
- return vprintf(format, args);
- }
- }
- #undef YG_UNUSED
- #endif
- bool YGFloatIsUndefined(const float value) {
- // Value of a float in the case of it being not defined is 10.1E20. Earlier
- // it used to be NAN, the benefit of which was that if NAN is involved in any
- // mathematical expression the result was NAN. But since we want to have
- // `-ffast-math` flag being used by compiler which assumes that the floating
- // point values are not NAN and Inf, we represent YGUndefined as 10.1E20. But
- // now if YGUndefined is involved in any mathematical operations this
- // value(10.1E20) would change. So the following check makes sure that if the
- // value is outside a range (-10E8, 10E8) then it is undefined.
- return value >= 10E8 || value <= -10E8;
- }
- const YGValue* YGComputedEdgeValue(
- const std::array<YGValue, YGEdgeCount>& edges,
- const YGEdge edge,
- const YGValue* const defaultValue) {
- if (edges[edge].unit != YGUnitUndefined) {
- return &edges[edge];
- }
- if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
- edges[YGEdgeVertical].unit != YGUnitUndefined) {
- return &edges[YGEdgeVertical];
- }
- if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart || edge == YGEdgeEnd) &&
- edges[YGEdgeHorizontal].unit != YGUnitUndefined) {
- return &edges[YGEdgeHorizontal];
- }
- if (edges[YGEdgeAll].unit != YGUnitUndefined) {
- return &edges[YGEdgeAll];
- }
- if (edge == YGEdgeStart || edge == YGEdgeEnd) {
- return &YGValueUndefined;
- }
- return defaultValue;
- }
- void* YGNodeGetContext(YGNodeRef node) {
- return node->getContext();
- }
- void YGNodeSetContext(YGNodeRef node, void* context) {
- return node->setContext(context);
- }
- YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node) {
- return node->getMeasure();
- }
- void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
- node->setMeasureFunc(measureFunc);
- }
- YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node) {
- return node->getBaseline();
- }
- void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) {
- node->setBaseLineFunc(baselineFunc);
- }
- YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) {
- return node->getDirtied();
- }
- void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) {
- node->setDirtiedFunc(dirtiedFunc);
- }
- YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node) {
- return node->getPrintFunc();
- }
- void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
- node->setPrintFunc(printFunc);
- }
- bool YGNodeGetHasNewLayout(YGNodeRef node) {
- return node->getHasNewLayout();
- }
- void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
- node->setHasNewLayout(hasNewLayout);
- }
- YGNodeType YGNodeGetNodeType(YGNodeRef node) {
- return node->getNodeType();
- }
- void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) {
- return node->setNodeType(nodeType);
- }
- bool YGNodeIsDirty(YGNodeRef node) {
- return node->isDirty();
- }
- bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) {
- return node->didUseLegacyFlag();
- }
- void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) {
- return node->markDirtyAndPropogateDownwards();
- }
- int32_t gNodeInstanceCount = 0;
- int32_t gConfigInstanceCount = 0;
- WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
- const YGNodeRef node = new YGNode();
- YGAssertWithConfig(
- config, node != nullptr, "Could not allocate memory for node");
- gNodeInstanceCount++;
- if (config->useWebDefaults) {
- node->setStyleFlexDirection(YGFlexDirectionRow);
- node->setStyleAlignContent(YGAlignStretch);
- }
- node->setConfig(config);
- return node;
- }
- YGConfigRef YGConfigGetDefault() {
- static YGConfigRef defaultConfig = YGConfigNew();
- return defaultConfig;
- }
- YGNodeRef YGNodeNew(void) {
- return YGNodeNewWithConfig(YGConfigGetDefault());
- }
- YGNodeRef YGNodeClone(YGNodeRef oldNode) {
- YGNodeRef node = new YGNode(*oldNode);
- YGAssertWithConfig(
- oldNode->getConfig(),
- node != nullptr,
- "Could not allocate memory for node");
- gNodeInstanceCount++;
- node->setOwner(nullptr);
- return node;
- }
- static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
- const YGConfigRef config = new YGConfig(oldConfig);
- YGAssert(config != nullptr, "Could not allocate memory for config");
- if (config == nullptr) {
- abort();
- }
- gConfigInstanceCount++;
- return config;
- }
- static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
- YGNodeRef node = YGNodeClone(oldNode);
- YGVector vec = YGVector();
- vec.reserve(oldNode->getChildren().size());
- YGNodeRef childNode = nullptr;
- for (auto& item : oldNode->getChildren()) {
- childNode = YGNodeDeepClone(item);
- childNode->setOwner(node);
- vec.push_back(childNode);
- }
- node->setChildren(vec);
- if (oldNode->getConfig() != nullptr) {
- node->setConfig(YGConfigClone(*(oldNode->getConfig())));
- }
- return node;
- }
- void YGNodeFree(const YGNodeRef node) {
- if (YGNodeRef owner = node->getOwner()) {
- owner->removeChild(node);
- node->setOwner(nullptr);
- }
- const uint32_t childCount = YGNodeGetChildCount(node);
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef child = YGNodeGetChild(node, i);
- child->setOwner(nullptr);
- }
- node->clearChildren();
- delete node;
- gNodeInstanceCount--;
- }
- static void YGConfigFreeRecursive(const YGNodeRef root) {
- if (root->getConfig() != nullptr) {
- gConfigInstanceCount--;
- delete root->getConfig();
- }
- // Delete configs recursively for childrens
- for (uint32_t i = 0; i < root->getChildrenCount(); ++i) {
- YGConfigFreeRecursive(root->getChild(i));
- }
- }
- void YGNodeFreeRecursive(const YGNodeRef root) {
- while (YGNodeGetChildCount(root) > 0) {
- const YGNodeRef child = YGNodeGetChild(root, 0);
- if (child->getOwner() != root) {
- // Don't free shared nodes that we don't own.
- break;
- }
- YGNodeRemoveChild(root, child);
- YGNodeFreeRecursive(child);
- }
- YGNodeFree(root);
- }
- void YGNodeReset(const YGNodeRef node) {
- YGAssertWithNode(node,
- YGNodeGetChildCount(node) == 0,
- "Cannot reset a node which still has children attached");
- YGAssertWithNode(
- node,
- node->getOwner() == nullptr,
- "Cannot reset a node still attached to a owner");
- node->clearChildren();
- const YGConfigRef config = node->getConfig();
- *node = YGNode();
- if (config->useWebDefaults) {
- node->setStyleFlexDirection(YGFlexDirectionRow);
- node->setStyleAlignContent(YGAlignStretch);
- }
- node->setConfig(config);
- }
- int32_t YGNodeGetInstanceCount(void) {
- return gNodeInstanceCount;
- }
- int32_t YGConfigGetInstanceCount(void) {
- return gConfigInstanceCount;
- }
- YGConfigRef YGConfigNew(void) {
- #ifdef ANDROID
- const YGConfigRef config = new YGConfig(YGAndroidLog);
- #else
- const YGConfigRef config = new YGConfig(YGDefaultLog);
- #endif
- gConfigInstanceCount++;
- return config;
- }
- void YGConfigFree(const YGConfigRef config) {
- free(config);
- gConfigInstanceCount--;
- }
- void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) {
- memcpy(dest, src, sizeof(YGConfig));
- }
- void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) {
- YGAssertWithNode(
- node,
- child->getOwner() == nullptr,
- "Child already has a owner, it must be removed first.");
- YGAssertWithNode(
- node,
- node->getMeasure() == nullptr,
- "Cannot add child: Nodes with measure functions cannot have children.");
- node->cloneChildrenIfNeeded();
- node->insertChild(child, index);
- YGNodeRef owner = child->getOwner() ? nullptr : node;
- child->setOwner(owner);
- node->markDirtyAndPropogate();
- }
- void YGNodeInsertSharedChild(
- const YGNodeRef node,
- const YGNodeRef child,
- const uint32_t index) {
- YGAssertWithNode(
- node,
- node->getMeasure() == nullptr,
- "Cannot add child: Nodes with measure functions cannot have children.");
- node->insertChild(child, index);
- child->setOwner(nullptr);
- node->markDirtyAndPropogate();
- }
- void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) {
- // This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode
- // that excludes a child.
- const uint32_t childCount = YGNodeGetChildCount(owner);
- if (childCount == 0) {
- // This is an empty set. Nothing to remove.
- return;
- }
- const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
- if (firstChild->getOwner() == owner) {
- // If the first child has this node as its owner, we assume that it is already unique.
- // We can now try to delete a child in this list.
- if (owner->removeChild(excludedChild)) {
- excludedChild->setLayout(
- YGNode().getLayout()); // layout is no longer valid
- excludedChild->setOwner(nullptr);
- owner->markDirtyAndPropogate();
- }
- return;
- }
- // Otherwise we have to clone the node list except for the child we're trying to delete.
- // We don't want to simply clone all children, because then the host will need to free
- // the clone of the child that was just deleted.
- const YGCloneNodeFunc cloneNodeCallback =
- owner->getConfig()->cloneNodeCallback;
- uint32_t nextInsertIndex = 0;
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef oldChild = owner->getChild(i);
- if (excludedChild == oldChild) {
- // Ignore the deleted child. Don't reset its layout or owner since it is still valid
- // in the other owner. However, since this owner has now changed, we need to mark it
- // as dirty.
- owner->markDirtyAndPropogate();
- continue;
- }
- YGNodeRef newChild = nullptr;
- if (cloneNodeCallback) {
- newChild = cloneNodeCallback(oldChild, owner, nextInsertIndex);
- }
- if (newChild == nullptr) {
- newChild = YGNodeClone(oldChild);
- }
- owner->replaceChild(newChild, nextInsertIndex);
- newChild->setOwner(owner);
- nextInsertIndex++;
- }
- while (nextInsertIndex < childCount) {
- owner->removeChild(nextInsertIndex);
- nextInsertIndex++;
- }
- }
- void YGNodeRemoveAllChildren(const YGNodeRef owner) {
- const uint32_t childCount = YGNodeGetChildCount(owner);
- if (childCount == 0) {
- // This is an empty set already. Nothing to do.
- return;
- }
- const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
- if (firstChild->getOwner() == owner) {
- // If the first child has this node as its owner, we assume that this child set is unique.
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef oldChild = YGNodeGetChild(owner, i);
- oldChild->setLayout(YGNode().getLayout()); // layout is no longer valid
- oldChild->setOwner(nullptr);
- }
- owner->clearChildren();
- owner->markDirtyAndPropogate();
- return;
- }
- // Otherwise, we are not the owner of the child set. We don't have to do anything to clear it.
- owner->setChildren(YGVector());
- owner->markDirtyAndPropogate();
- }
- static void YGNodeSetChildrenInternal(YGNodeRef const owner, const std::vector<YGNodeRef> &children)
- {
- if (!owner) {
- return;
- }
- if (children.size() == 0) {
- if (YGNodeGetChildCount(owner) > 0) {
- for (YGNodeRef const child : owner->getChildren()) {
- child->setLayout(YGLayout());
- child->setOwner(nullptr);
- }
- owner->setChildren(YGVector());
- owner->markDirtyAndPropogate();
- }
- } else {
- if (YGNodeGetChildCount(owner) > 0) {
- for (YGNodeRef const oldChild : owner->getChildren()) {
- // Our new children may have nodes in common with the old children. We don't reset these common nodes.
- if (std::find(children.begin(), children.end(), oldChild) == children.end()) {
- oldChild->setLayout(YGLayout());
- oldChild->setOwner(nullptr);
- }
- }
- }
- owner->setChildren(children);
- for (YGNodeRef child : children) {
- child->setOwner(owner);
- }
- owner->markDirtyAndPropogate();
- }
- }
- void YGNodeSetChildren(YGNodeRef const owner, const YGNodeRef c[], const uint32_t count) {
- const YGVector children = {c, c + count};
- YGNodeSetChildrenInternal(owner, children);
- }
- void YGNodeSetChildren(YGNodeRef const owner, const std::vector<YGNodeRef> &children)
- {
- YGNodeSetChildrenInternal(owner, children);
- }
- YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) {
- if (index < node->getChildren().size()) {
- return node->getChild(index);
- }
- return nullptr;
- }
- uint32_t YGNodeGetChildCount(const YGNodeRef node) {
- return static_cast<uint32_t>(node->getChildren().size());
- }
- YGNodeRef YGNodeGetOwner(const YGNodeRef node) {
- return node->getOwner();
- }
- YGNodeRef YGNodeGetParent(const YGNodeRef node) {
- return node->getOwner();
- }
- void YGNodeMarkDirty(const YGNodeRef node) {
- YGAssertWithNode(
- node,
- node->getMeasure() != nullptr,
- "Only leaf nodes with custom measure functions"
- "should manually mark themselves as dirty");
- node->markDirtyAndPropogate();
- }
- void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) {
- if (!(dstNode->getStyle() == srcNode->getStyle())) {
- dstNode->setStyle(srcNode->getStyle());
- dstNode->markDirtyAndPropogate();
- }
- }
- float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
- return node->getStyle().flexGrow.isUndefined()
- ? kDefaultFlexGrow
- : node->getStyle().flexGrow.getValue();
- }
- float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
- return node->getStyle().flexShrink.isUndefined()
- ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
- : kDefaultFlexShrink)
- : node->getStyle().flexShrink.getValue();
- }
- #define YG_NODE_STYLE_PROPERTY_SETTER_IMPL( \
- type, name, paramName, instanceName) \
- void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
- if (node->getStyle().instanceName != paramName) { \
- YGStyle style = node->getStyle(); \
- style.instanceName = paramName; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- }
- #define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
- type, name, paramName, instanceName) \
- void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
- }; \
- if ((node->getStyle().instanceName.value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName.unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName = value; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Percent( \
- const YGNodeRef node, const type paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
- }; \
- if ((node->getStyle().instanceName.value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName.unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- \
- style.instanceName = value; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- }
- #define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
- type, name, paramName, instanceName) \
- void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
- }; \
- if ((node->getStyle().instanceName.value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName.unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName = value; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Percent( \
- const YGNodeRef node, const type paramName) { \
- if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \
- node->getStyle().instanceName.unit != YGUnitPercent) { \
- YGStyle style = node->getStyle(); \
- style.instanceName.value = YGFloatSanitize(paramName); \
- style.instanceName.unit = \
- YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \
- if (node->getStyle().instanceName.unit != YGUnitAuto) { \
- YGStyle style = node->getStyle(); \
- style.instanceName.value = 0; \
- style.instanceName.unit = YGUnitAuto; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- }
- #define YG_NODE_STYLE_PROPERTY_IMPL(type, name, paramName, instanceName) \
- YG_NODE_STYLE_PROPERTY_SETTER_IMPL(type, name, paramName, instanceName) \
- \
- type YGNodeStyleGet##name(const YGNodeRef node) { \
- return node->getStyle().instanceName; \
- }
- #define YG_NODE_STYLE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName) \
- YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
- float, name, paramName, instanceName) \
- \
- type YGNodeStyleGet##name(const YGNodeRef node) { \
- YGValue value = node->getStyle().instanceName; \
- if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
- value.value = YGUndefined; \
- } \
- return value; \
- }
- #define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \
- type, name, paramName, instanceName) \
- YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
- float, name, paramName, instanceName) \
- \
- type YGNodeStyleGet##name(const YGNodeRef node) { \
- YGValue value = node->getStyle().instanceName; \
- if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
- value.value = YGUndefined; \
- } \
- return value; \
- }
- #define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \
- void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
- if (node->getStyle().instanceName[edge].unit != YGUnitAuto) { \
- YGStyle style = node->getStyle(); \
- style.instanceName[edge].value = 0; \
- style.instanceName[edge].unit = YGUnitAuto; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- }
- #define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL( \
- type, name, paramName, instanceName) \
- void YGNodeStyleSet##name( \
- const YGNodeRef node, const YGEdge edge, const float paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
- }; \
- if ((node->getStyle().instanceName[edge].value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName[edge].unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName[edge] = value; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Percent( \
- const YGNodeRef node, const YGEdge edge, const float paramName) { \
- YGValue value = { \
- YGFloatSanitize(paramName), \
- YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
- }; \
- if ((node->getStyle().instanceName[edge].value != value.value && \
- value.unit != YGUnitUndefined) || \
- node->getStyle().instanceName[edge].unit != value.unit) { \
- YGStyle style = node->getStyle(); \
- style.instanceName[edge] = value; \
- node->setStyle(style); \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- WIN_STRUCT(type) \
- YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \
- YGValue value = node->getStyle().instanceName[edge]; \
- if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
- value.value = YGUndefined; \
- } \
- return WIN_STRUCT_REF(value); \
- }
- #define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
- type YGNodeLayoutGet##name(const YGNodeRef node) { \
- return node->getLayout().instanceName; \
- }
- #define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \
- type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \
- YGAssertWithNode( \
- node, \
- edge <= YGEdgeEnd, \
- "Cannot get layout properties of multi-edge shorthands"); \
- \
- if (edge == YGEdgeLeft) { \
- if (node->getLayout().direction == YGDirectionRTL) { \
- return node->getLayout().instanceName[YGEdgeEnd]; \
- } else { \
- return node->getLayout().instanceName[YGEdgeStart]; \
- } \
- } \
- \
- if (edge == YGEdgeRight) { \
- if (node->getLayout().direction == YGDirectionRTL) { \
- return node->getLayout().instanceName[YGEdgeStart]; \
- } else { \
- return node->getLayout().instanceName[YGEdgeEnd]; \
- } \
- } \
- \
- return node->getLayout().instanceName[edge]; \
- }
- // YG_NODE_PROPERTY_IMPL(void *, Context, context, context);
- // YG_NODE_PROPERTY_IMPL(YGPrintFunc, PrintFunc, printFunc, print);
- // YG_NODE_PROPERTY_IMPL(bool, HasNewLayout, hasNewLayout, hasNewLayout);
- // YG_NODE_PROPERTY_IMPL(YGNodeType, NodeType, nodeType, nodeType);
- YG_NODE_STYLE_PROPERTY_IMPL(YGDirection, Direction, direction, direction);
- YG_NODE_STYLE_PROPERTY_IMPL(YGFlexDirection, FlexDirection, flexDirection, flexDirection);
- YG_NODE_STYLE_PROPERTY_IMPL(YGJustify, JustifyContent, justifyContent, justifyContent);
- YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignContent, alignContent, alignContent);
- YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignItems, alignItems, alignItems);
- YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignSelf, alignSelf, alignSelf);
- YG_NODE_STYLE_PROPERTY_IMPL(YGPositionType, PositionType, positionType, positionType);
- YG_NODE_STYLE_PROPERTY_IMPL(YGWrap, FlexWrap, flexWrap, flexWrap);
- YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow);
- YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display);
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
- if (node->getStyle().flex != flex) {
- YGStyle style = node->getStyle();
- if (YGFloatIsUndefined(flex)) {
- style.flex = YGFloatOptional();
- } else {
- style.flex = YGFloatOptional(flex);
- }
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- float YGNodeStyleGetFlex(const YGNodeRef node) {
- return node->getStyle().flex.isUndefined() ? YGUndefined
- : node->getStyle().flex.getValue();
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
- if (node->getStyle().flexGrow != flexGrow) {
- YGStyle style = node->getStyle();
- if (YGFloatIsUndefined(flexGrow)) {
- style.flexGrow = YGFloatOptional();
- } else {
- style.flexGrow = YGFloatOptional(flexGrow);
- }
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
- if (node->getStyle().flexShrink != flexShrink) {
- YGStyle style = node->getStyle();
- if (YGFloatIsUndefined(flexShrink)) {
- style.flexShrink = YGFloatOptional();
- } else {
- style.flexShrink = YGFloatOptional(flexShrink);
- }
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) {
- YGValue flexBasis = node->getStyle().flexBasis;
- if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) {
- // TODO(T26792433): Get rid off the use of YGUndefined at client side
- flexBasis.value = YGUndefined;
- }
- return flexBasis;
- }
- void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
- YGValue value = {
- YGFloatSanitize(flexBasis),
- YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint,
- };
- if ((node->getStyle().flexBasis.value != value.value &&
- value.unit != YGUnitUndefined) ||
- node->getStyle().flexBasis.unit != value.unit) {
- YGStyle style = node->getStyle();
- style.flexBasis = value;
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- void YGNodeStyleSetFlexBasisPercent(
- const YGNodeRef node,
- const float flexBasisPercent) {
- if (node->getStyle().flexBasis.value != flexBasisPercent ||
- node->getStyle().flexBasis.unit != YGUnitPercent) {
- YGStyle style = node->getStyle();
- style.flexBasis.value = YGFloatSanitize(flexBasisPercent);
- style.flexBasis.unit =
- YGFloatIsUndefined(flexBasisPercent) ? YGUnitAuto : YGUnitPercent;
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
- if (node->getStyle().flexBasis.unit != YGUnitAuto) {
- YGStyle style = node->getStyle();
- style.flexBasis.value = 0;
- style.flexBasis.unit = YGUnitAuto;
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position);
- YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin);
- YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin);
- YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding);
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetBorder(
- const YGNodeRef node,
- const YGEdge edge,
- const float border) {
- YGValue value = {
- YGFloatSanitize(border),
- YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint,
- };
- if ((node->getStyle().border[edge].value != value.value &&
- value.unit != YGUnitUndefined) ||
- node->getStyle().border[edge].unit != value.unit) {
- YGStyle style = node->getStyle();
- style.border[edge] = value;
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
- if (node->getStyle().border[edge].unit == YGUnitUndefined ||
- node->getStyle().border[edge].unit == YGUnitAuto) {
- // TODO(T26792433): Rather than returning YGUndefined, change the api to
- // return YGFloatOptional.
- return YGUndefined;
- }
- return node->getStyle().border[edge].value;
- }
- // Yoga specific properties, not compatible with flexbox specification
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- float YGNodeStyleGetAspectRatio(const YGNodeRef node) {
- const YGFloatOptional op = node->getStyle().aspectRatio;
- return op.isUndefined() ? YGUndefined : op.getValue();
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
- if (node->getStyle().aspectRatio != aspectRatio) {
- YGStyle style = node->getStyle();
- style.aspectRatio = YGFloatOptional(aspectRatio);
- node->setStyle(style);
- node->markDirtyAndPropogate();
- }
- }
- YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]);
- YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]);
- YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinWidth, minWidth, minDimensions[YGDimensionWidth]);
- YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinHeight, minHeight, minDimensions[YGDimensionHeight]);
- YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]);
- YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]);
- YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]);
- YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]);
- YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]);
- YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]);
- YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
- YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
- YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
- YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow);
- YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
- YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
- YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding);
- bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
- return node->getLayout().doesLegacyStretchFlagAffectsLayout;
- }
- uint32_t gCurrentGenerationCount = 0;
- bool YGLayoutNodeInternal(const YGNodeRef node,
- const float availableWidth,
- const float availableHeight,
- const YGDirection ownerDirection,
- const YGMeasureMode widthMeasureMode,
- const YGMeasureMode heightMeasureMode,
- const float ownerWidth,
- const float ownerHeight,
- const bool performLayout,
- const char *reason,
- const YGConfigRef config);
- static void YGNodePrintInternal(const YGNodeRef node,
- const YGPrintOptions options) {
- std::string str;
- facebook::yoga::YGNodeToString(&str, node, options, 0);
- YGLog(node, YGLogLevelDebug, str.c_str());
- }
- void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {
- YGNodePrintInternal(node, options);
- }
- const std::array<YGEdge, 4> leading = {
- {YGEdgeTop, YGEdgeBottom, YGEdgeLeft, YGEdgeRight}};
- const std::array<YGEdge, 4> trailing = {
- {YGEdgeBottom, YGEdgeTop, YGEdgeRight, YGEdgeLeft}};
- static const std::array<YGEdge, 4> pos = {{
- YGEdgeTop,
- YGEdgeBottom,
- YGEdgeLeft,
- YGEdgeRight,
- }};
- static const std::array<YGDimension, 4> dim = {
- {YGDimensionHeight, YGDimensionHeight, YGDimensionWidth, YGDimensionWidth}};
- static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node,
- const YGFlexDirection axis,
- const float widthSize) {
- return YGUnwrapFloatOptional(
- node->getLeadingPaddingAndBorder(axis, widthSize) +
- node->getTrailingPaddingAndBorder(axis, widthSize));
- }
- static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) {
- const YGAlign align = child->getStyle().alignSelf == YGAlignAuto
- ? node->getStyle().alignItems
- : child->getStyle().alignSelf;
- if (align == YGAlignBaseline &&
- YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
- return YGAlignFlexStart;
- }
- return align;
- }
- static float YGBaseline(const YGNodeRef node) {
- if (node->getBaseline() != nullptr) {
- const float baseline = node->getBaseline()(
- node,
- node->getLayout().measuredDimensions[YGDimensionWidth],
- node->getLayout().measuredDimensions[YGDimensionHeight]);
- YGAssertWithNode(node,
- !YGFloatIsUndefined(baseline),
- "Expect custom baseline function to not return NaN");
- return baseline;
- }
- YGNodeRef baselineChild = nullptr;
- const uint32_t childCount = YGNodeGetChildCount(node);
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef child = YGNodeGetChild(node, i);
- if (child->getLineIndex() > 0) {
- break;
- }
- if (child->getStyle().positionType == YGPositionTypeAbsolute) {
- continue;
- }
- if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
- baselineChild = child;
- break;
- }
- if (baselineChild == nullptr) {
- baselineChild = child;
- }
- }
- if (baselineChild == nullptr) {
- return node->getLayout().measuredDimensions[YGDimensionHeight];
- }
- const float baseline = YGBaseline(baselineChild);
- return baseline + baselineChild->getLayout().position[YGEdgeTop];
- }
- static bool YGIsBaselineLayout(const YGNodeRef node) {
- if (YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
- return false;
- }
- if (node->getStyle().alignItems == YGAlignBaseline) {
- return true;
- }
- const uint32_t childCount = YGNodeGetChildCount(node);
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef child = YGNodeGetChild(node, i);
- if (child->getStyle().positionType == YGPositionTypeRelative &&
- child->getStyle().alignSelf == YGAlignBaseline) {
- return true;
- }
- }
- return false;
- }
- static inline float YGNodeDimWithMargin(const YGNodeRef node,
- const YGFlexDirection axis,
- const float widthSize) {
- return node->getLayout().measuredDimensions[dim[axis]] +
- YGUnwrapFloatOptional(
- node->getLeadingMargin(axis, widthSize) +
- node->getTrailingMargin(axis, widthSize));
- }
- static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node,
- const YGFlexDirection axis,
- const float ownerSize) {
- bool isUndefined =
- YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value);
- return !(
- node->getResolvedDimension(dim[axis]).unit == YGUnitAuto ||
- node->getResolvedDimension(dim[axis]).unit == YGUnitUndefined ||
- (node->getResolvedDimension(dim[axis]).unit == YGUnitPoint &&
- !isUndefined && node->getResolvedDimension(dim[axis]).value < 0.0f) ||
- (node->getResolvedDimension(dim[axis]).unit == YGUnitPercent &&
- !isUndefined &&
- (node->getResolvedDimension(dim[axis]).value < 0.0f ||
- YGFloatIsUndefined(ownerSize))));
- }
- static inline bool YGNodeIsLayoutDimDefined(const YGNodeRef node, const YGFlexDirection axis) {
- const float value = node->getLayout().measuredDimensions[dim[axis]];
- return !YGFloatIsUndefined(value) && value >= 0.0f;
- }
- static YGFloatOptional YGNodeBoundAxisWithinMinAndMax(
- const YGNodeRef node,
- const YGFlexDirection& axis,
- const float& value,
- const float& axisSize) {
- YGFloatOptional min;
- YGFloatOptional max;
- if (YGFlexDirectionIsColumn(axis)) {
- min = YGResolveValue(
- node->getStyle().minDimensions[YGDimensionHeight], axisSize);
- max = YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight], axisSize);
- } else if (YGFlexDirectionIsRow(axis)) {
- min = YGResolveValue(
- node->getStyle().minDimensions[YGDimensionWidth], axisSize);
- max = YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], axisSize);
- }
- if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) {
- return max;
- }
- if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) {
- return min;
- }
- return YGFloatOptional(value);
- }
- // Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't go
- // below the
- // padding and border amount.
- static inline float YGNodeBoundAxis(const YGNodeRef node,
- const YGFlexDirection axis,
- const float value,
- const float axisSize,
- const float widthSize) {
- return YGFloatMax(
- YGUnwrapFloatOptional(
- YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)),
- YGNodePaddingAndBorderForAxis(node, axis, widthSize));
- }
- static void YGNodeSetChildTrailingPosition(const YGNodeRef node,
- const YGNodeRef child,
- const YGFlexDirection axis) {
- const float size = child->getLayout().measuredDimensions[dim[axis]];
- child->setLayoutPosition(
- node->getLayout().measuredDimensions[dim[axis]] - size -
- child->getLayout().position[pos[axis]],
- trailing[axis]);
- }
- static void YGConstrainMaxSizeForMode(const YGNodeRef node,
- const enum YGFlexDirection axis,
- const float ownerAxisSize,
- const float ownerWidth,
- YGMeasureMode *mode,
- float *size) {
- const YGFloatOptional maxSize =
- YGResolveValue(
- node->getStyle().maxDimensions[dim[axis]], ownerAxisSize) +
- YGFloatOptional(node->getMarginForAxis(axis, ownerWidth));
- switch (*mode) {
- case YGMeasureModeExactly:
- case YGMeasureModeAtMost:
- *size = (maxSize.isUndefined() || *size < maxSize.getValue())
- ? *size
- : maxSize.getValue();
- break;
- case YGMeasureModeUndefined:
- if (!maxSize.isUndefined()) {
- *mode = YGMeasureModeAtMost;
- *size = maxSize.getValue();
- }
- break;
- }
- }
- static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
- const YGNodeRef child,
- const float width,
- const YGMeasureMode widthMode,
- const float height,
- const float ownerWidth,
- const float ownerHeight,
- const YGMeasureMode heightMode,
- const YGDirection direction,
- const YGConfigRef config) {
- const YGFlexDirection mainAxis =
- YGResolveFlexDirection(node->getStyle().flexDirection, direction);
- const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
- const float mainAxisSize = isMainAxisRow ? width : height;
- const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
- float childWidth;
- float childHeight;
- YGMeasureMode childWidthMeasureMode;
- YGMeasureMode childHeightMeasureMode;
- const YGFloatOptional resolvedFlexBasis =
- YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize);
- const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth);
- const bool isColumnStyleDimDefined =
- YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight);
- if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) {
- if (child->getLayout().computedFlexBasis.isUndefined() ||
- (YGConfigIsExperimentalFeatureEnabled(
- child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
- child->getLayout().computedFlexBasisGeneration !=
- gCurrentGenerationCount)) {
- const YGFloatOptional& paddingAndBorder = YGFloatOptional(
- YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth));
- child->setLayoutComputedFlexBasis(
- YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder));
- }
- } else if (isMainAxisRow && isRowStyleDimDefined) {
- // The width is definite, so use that as the flex basis.
- const YGFloatOptional& paddingAndBorder = YGFloatOptional(
- YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth));
- child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
- YGResolveValue(
- child->getResolvedDimension(YGDimensionWidth), ownerWidth),
- paddingAndBorder));
- } else if (!isMainAxisRow && isColumnStyleDimDefined) {
- // The height is definite, so use that as the flex basis.
- const YGFloatOptional& paddingAndBorder =
- YGFloatOptional(YGNodePaddingAndBorderForAxis(
- child, YGFlexDirectionColumn, ownerWidth));
- child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
- YGResolveValue(
- child->getResolvedDimension(YGDimensionHeight), ownerHeight),
- paddingAndBorder));
- } else {
- // Compute the flex basis and hypothetical main size (i.e. the clamped
- // flex basis).
- childWidth = YGUndefined;
- childHeight = YGUndefined;
- childWidthMeasureMode = YGMeasureModeUndefined;
- childHeightMeasureMode = YGMeasureModeUndefined;
- const float& marginRow = YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- const float& marginColumn = YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
- if (isRowStyleDimDefined) {
- childWidth =
- YGUnwrapFloatOptional(YGResolveValue(
- child->getResolvedDimension(YGDimensionWidth), ownerWidth)) +
- marginRow;
- childWidthMeasureMode = YGMeasureModeExactly;
- }
- if (isColumnStyleDimDefined) {
- childHeight =
- YGUnwrapFloatOptional(YGResolveValue(
- child->getResolvedDimension(YGDimensionHeight), ownerHeight)) +
- marginColumn;
- childHeightMeasureMode = YGMeasureModeExactly;
- }
- // The W3C spec doesn't say anything about the 'overflow' property,
- // but all major browsers appear to implement the following logic.
- if ((!isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
- node->getStyle().overflow != YGOverflowScroll) {
- if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) {
- childWidth = width;
- childWidthMeasureMode = YGMeasureModeAtMost;
- }
- }
- if ((isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
- node->getStyle().overflow != YGOverflowScroll) {
- if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) {
- childHeight = height;
- childHeightMeasureMode = YGMeasureModeAtMost;
- }
- }
- if (!child->getStyle().aspectRatio.isUndefined()) {
- if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) {
- childHeight = marginColumn +
- (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
- childHeightMeasureMode = YGMeasureModeExactly;
- } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
- childWidth = marginRow +
- (childHeight - marginColumn) *
- child->getStyle().aspectRatio.getValue();
- childWidthMeasureMode = YGMeasureModeExactly;
- }
- }
- // If child has no defined size in the cross axis and is set to stretch,
- // set the cross
- // axis to be measured exactly with the available inner width
- const bool hasExactWidth = !YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly;
- const bool childWidthStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
- childWidthMeasureMode != YGMeasureModeExactly;
- if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) {
- childWidth = width;
- childWidthMeasureMode = YGMeasureModeExactly;
- if (!child->getStyle().aspectRatio.isUndefined()) {
- childHeight =
- (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
- childHeightMeasureMode = YGMeasureModeExactly;
- }
- }
- const bool hasExactHeight = !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly;
- const bool childHeightStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
- childHeightMeasureMode != YGMeasureModeExactly;
- if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && childHeightStretch) {
- childHeight = height;
- childHeightMeasureMode = YGMeasureModeExactly;
- if (!child->getStyle().aspectRatio.isUndefined()) {
- childWidth = (childHeight - marginColumn) *
- child->getStyle().aspectRatio.getValue();
- childWidthMeasureMode = YGMeasureModeExactly;
- }
- }
- YGConstrainMaxSizeForMode(
- child, YGFlexDirectionRow, ownerWidth, ownerWidth, &childWidthMeasureMode, &childWidth);
- YGConstrainMaxSizeForMode(child,
- YGFlexDirectionColumn,
- ownerHeight,
- ownerWidth,
- &childHeightMeasureMode,
- &childHeight);
- // Measure the child
- YGLayoutNodeInternal(child,
- childWidth,
- childHeight,
- direction,
- childWidthMeasureMode,
- childHeightMeasureMode,
- ownerWidth,
- ownerHeight,
- false,
- "measure",
- config);
- child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax(
- child->getLayout().measuredDimensions[dim[mainAxis]],
- YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))));
- }
- child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
- }
- static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
- const YGNodeRef child,
- const float width,
- const YGMeasureMode widthMode,
- const float height,
- const YGDirection direction,
- const YGConfigRef config) {
- const YGFlexDirection mainAxis =
- YGResolveFlexDirection(node->getStyle().flexDirection, direction);
- const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
- const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
- float childWidth = YGUndefined;
- float childHeight = YGUndefined;
- YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined;
- YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined;
- const float& marginRow =
- YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width));
- const float& marginColumn = YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionColumn, width));
- if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
- childWidth =
- YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)) +
- marginRow;
- } else {
- // If the child doesn't have a specified width, compute the width based
- // on the left/right
- // offsets if they're defined.
- if (child->isLeadingPositionDefined(YGFlexDirectionRow) &&
- child->isTrailingPosDefined(YGFlexDirectionRow)) {
- childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] -
- (node->getLeadingBorder(YGFlexDirectionRow) +
- node->getTrailingBorder(YGFlexDirectionRow)) -
- YGUnwrapFloatOptional(
- child->getLeadingPosition(YGFlexDirectionRow, width) +
- child->getTrailingPosition(YGFlexDirectionRow, width));
- childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
- }
- }
- if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
- childHeight =
- YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)) +
- marginColumn;
- } else {
- // If the child doesn't have a specified height, compute the height
- // based on the top/bottom
- // offsets if they're defined.
- if (child->isLeadingPositionDefined(YGFlexDirectionColumn) &&
- child->isTrailingPosDefined(YGFlexDirectionColumn)) {
- childHeight =
- node->getLayout().measuredDimensions[YGDimensionHeight] -
- (node->getLeadingBorder(YGFlexDirectionColumn) +
- node->getTrailingBorder(YGFlexDirectionColumn)) -
- YGUnwrapFloatOptional(
- child->getLeadingPosition(YGFlexDirectionColumn, height) +
- child->getTrailingPosition(YGFlexDirectionColumn, height));
- childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight, height, width);
- }
- }
- // Exactly one dimension needs to be defined for us to be able to do aspect ratio
- // calculation. One dimension being the anchor and the other being flexible.
- if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) {
- if (!child->getStyle().aspectRatio.isUndefined()) {
- if (YGFloatIsUndefined(childWidth)) {
- childWidth = marginRow +
- (childHeight - marginColumn) *
- child->getStyle().aspectRatio.getValue();
- } else if (YGFloatIsUndefined(childHeight)) {
- childHeight = marginColumn +
- (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
- }
- }
- }
- // If we're still missing one or the other dimension, measure the content.
- if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) {
- childWidthMeasureMode =
- YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly;
- childHeightMeasureMode =
- YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly;
- // If the size of the owner is defined then try to constrain the absolute child to that size
- // as well. This allows text within the absolute child to wrap to the size of its owner.
- // This is the same behavior as many browsers implement.
- if (!isMainAxisRow && YGFloatIsUndefined(childWidth) &&
- widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) &&
- width > 0) {
- childWidth = width;
- childWidthMeasureMode = YGMeasureModeAtMost;
- }
- YGLayoutNodeInternal(child,
- childWidth,
- childHeight,
- direction,
- childWidthMeasureMode,
- childHeightMeasureMode,
- childWidth,
- childHeight,
- false,
- "abs-measure",
- config);
- childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] +
- YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionRow, width));
- childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] +
- YGUnwrapFloatOptional(
- child->getMarginForAxis(YGFlexDirectionColumn, width));
- }
- YGLayoutNodeInternal(child,
- childWidth,
- childHeight,
- direction,
- YGMeasureModeExactly,
- YGMeasureModeExactly,
- childWidth,
- childHeight,
- true,
- "abs-layout",
- config);
- if (child->isTrailingPosDefined(mainAxis) &&
- !child->isLeadingPositionDefined(mainAxis)) {
- child->setLayoutPosition(
- node->getLayout().measuredDimensions[dim[mainAxis]] -
- child->getLayout().measuredDimensions[dim[mainAxis]] -
- node->getTrailingBorder(mainAxis) -
- YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) -
- YGUnwrapFloatOptional(child->getTrailingPosition(
- mainAxis, isMainAxisRow ? width : height)),
- leading[mainAxis]);
- } else if (
- !child->isLeadingPositionDefined(mainAxis) &&
- node->getStyle().justifyContent == YGJustifyCenter) {
- child->setLayoutPosition(
- (node->getLayout().measuredDimensions[dim[mainAxis]] -
- child->getLayout().measuredDimensions[dim[mainAxis]]) /
- 2.0f,
- leading[mainAxis]);
- } else if (
- !child->isLeadingPositionDefined(mainAxis) &&
- node->getStyle().justifyContent == YGJustifyFlexEnd) {
- child->setLayoutPosition(
- (node->getLayout().measuredDimensions[dim[mainAxis]] -
- child->getLayout().measuredDimensions[dim[mainAxis]]),
- leading[mainAxis]);
- }
- if (child->isTrailingPosDefined(crossAxis) &&
- !child->isLeadingPositionDefined(crossAxis)) {
- child->setLayoutPosition(
- node->getLayout().measuredDimensions[dim[crossAxis]] -
- child->getLayout().measuredDimensions[dim[crossAxis]] -
- node->getTrailingBorder(crossAxis) -
- YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) -
- YGUnwrapFloatOptional(child->getTrailingPosition(
- crossAxis, isMainAxisRow ? height : width)),
- leading[crossAxis]);
- } else if (
- !child->isLeadingPositionDefined(crossAxis) &&
- YGNodeAlignItem(node, child) == YGAlignCenter) {
- child->setLayoutPosition(
- (node->getLayout().measuredDimensions[dim[crossAxis]] -
- child->getLayout().measuredDimensions[dim[crossAxis]]) /
- 2.0f,
- leading[crossAxis]);
- } else if (
- !child->isLeadingPositionDefined(crossAxis) &&
- ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^
- (node->getStyle().flexWrap == YGWrapWrapReverse))) {
- child->setLayoutPosition(
- (node->getLayout().measuredDimensions[dim[crossAxis]] -
- child->getLayout().measuredDimensions[dim[crossAxis]]),
- leading[crossAxis]);
- }
- }
- static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node,
- const float availableWidth,
- const float availableHeight,
- const YGMeasureMode widthMeasureMode,
- const YGMeasureMode heightMeasureMode,
- const float ownerWidth,
- const float ownerHeight) {
- YGAssertWithNode(
- node,
- node->getMeasure() != nullptr,
- "Expected node to have custom measure function");
- const float paddingAndBorderAxisRow =
- YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
- const float paddingAndBorderAxisColumn =
- YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, availableWidth);
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, availableWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, availableWidth));
- // We want to make sure we don't call measure with negative size
- const float innerWidth = YGFloatIsUndefined(availableWidth)
- ? availableWidth
- : YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
- const float innerHeight = YGFloatIsUndefined(availableHeight)
- ? availableHeight
- : YGFloatMax(
- 0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
- if (widthMeasureMode == YGMeasureModeExactly &&
- heightMeasureMode == YGMeasureModeExactly) {
- // Don't bother sizing the text if both dimensions are already defined.
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionRow,
- availableWidth - marginAxisRow,
- ownerWidth,
- ownerWidth),
- YGDimensionWidth);
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionColumn,
- availableHeight - marginAxisColumn,
- ownerHeight,
- ownerWidth),
- YGDimensionHeight);
- } else {
- // Measure the text under the current constraints.
- const YGSize measuredSize = node->getMeasure()(
- node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode);
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionRow,
- (widthMeasureMode == YGMeasureModeUndefined ||
- widthMeasureMode == YGMeasureModeAtMost)
- ? measuredSize.width + paddingAndBorderAxisRow
- : availableWidth - marginAxisRow,
- ownerWidth,
- ownerWidth),
- YGDimensionWidth);
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionColumn,
- (heightMeasureMode == YGMeasureModeUndefined ||
- heightMeasureMode == YGMeasureModeAtMost)
- ? measuredSize.height + paddingAndBorderAxisColumn
- : availableHeight - marginAxisColumn,
- ownerHeight,
- ownerWidth),
- YGDimensionHeight);
- }
- }
- // For nodes with no children, use the available values if they were provided,
- // or the minimum size as indicated by the padding and border sizes.
- static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node,
- const float availableWidth,
- const float availableHeight,
- const YGMeasureMode widthMeasureMode,
- const YGMeasureMode heightMeasureMode,
- const float ownerWidth,
- const float ownerHeight) {
- const float paddingAndBorderAxisRow =
- YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth);
- const float paddingAndBorderAxisColumn =
- YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth);
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionRow,
- (widthMeasureMode == YGMeasureModeUndefined ||
- widthMeasureMode == YGMeasureModeAtMost)
- ? paddingAndBorderAxisRow
- : availableWidth - marginAxisRow,
- ownerWidth,
- ownerWidth),
- YGDimensionWidth);
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionColumn,
- (heightMeasureMode == YGMeasureModeUndefined ||
- heightMeasureMode == YGMeasureModeAtMost)
- ? paddingAndBorderAxisColumn
- : availableHeight - marginAxisColumn,
- ownerHeight,
- ownerWidth),
- YGDimensionHeight);
- }
- static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node,
- const float availableWidth,
- const float availableHeight,
- const YGMeasureMode widthMeasureMode,
- const YGMeasureMode heightMeasureMode,
- const float ownerWidth,
- const float ownerHeight) {
- if ((!YGFloatIsUndefined(availableWidth) &&
- widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
- (!YGFloatIsUndefined(availableHeight) &&
- heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
- (widthMeasureMode == YGMeasureModeExactly &&
- heightMeasureMode == YGMeasureModeExactly)) {
- const float& marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
- const float& marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionRow,
- YGFloatIsUndefined(availableWidth) ||
- (widthMeasureMode == YGMeasureModeAtMost &&
- availableWidth < 0.0f)
- ? 0.0f
- : availableWidth - marginAxisRow,
- ownerWidth,
- ownerWidth),
- YGDimensionWidth);
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionColumn,
- YGFloatIsUndefined(availableHeight) ||
- (heightMeasureMode == YGMeasureModeAtMost &&
- availableHeight < 0.0f)
- ? 0.0f
- : availableHeight - marginAxisColumn,
- ownerHeight,
- ownerWidth),
- YGDimensionHeight);
- return true;
- }
- return false;
- }
- static void YGZeroOutLayoutRecursivly(const YGNodeRef node) {
- memset(&(node->getLayout()), 0, sizeof(YGLayout));
- node->setHasNewLayout(true);
- node->cloneChildrenIfNeeded();
- const uint32_t childCount = YGNodeGetChildCount(node);
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef child = node->getChild(i);
- YGZeroOutLayoutRecursivly(child);
- }
- }
- static float YGNodeCalculateAvailableInnerDim(
- const YGNodeRef node,
- YGFlexDirection axis,
- float availableDim,
- float ownerDim) {
- YGFlexDirection direction =
- YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn;
- YGDimension dimension =
- YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight;
- const float margin =
- YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim));
- const float paddingAndBorder =
- YGNodePaddingAndBorderForAxis(node, direction, ownerDim);
- float availableInnerDim = availableDim - margin - paddingAndBorder;
- // Max dimension overrides predefined dimension value; Min dimension in turn
- // overrides both of the above
- if (!YGFloatIsUndefined(availableInnerDim)) {
- // We want to make sure our available height does not violate min and max
- // constraints
- const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim);
- const float minInnerDim = minDimensionOptional.isUndefined()
- ? 0.0f
- : minDimensionOptional.getValue() - paddingAndBorder;
- const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim) ;
- const float maxInnerDim = maxDimensionOptional.isUndefined()
- ? FLT_MAX
- : maxDimensionOptional.getValue() - paddingAndBorder;
- availableInnerDim =
- YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
- }
- return availableInnerDim;
- }
- static void YGNodeComputeFlexBasisForChildren(
- const YGNodeRef node,
- const float availableInnerWidth,
- const float availableInnerHeight,
- YGMeasureMode widthMeasureMode,
- YGMeasureMode heightMeasureMode,
- YGDirection direction,
- YGFlexDirection mainAxis,
- const YGConfigRef config,
- bool performLayout,
- float& totalOuterFlexBasis) {
- YGNodeRef singleFlexChild = nullptr;
- YGVector children = node->getChildren();
- YGMeasureMode measureModeMainDim =
- YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode;
- // If there is only one child with flexGrow + flexShrink it means we can set
- // the computedFlexBasis to 0 instead of measuring and shrinking / flexing the
- // child to exactly match the remaining space
- if (measureModeMainDim == YGMeasureModeExactly) {
- for (auto child : children) {
- if (child->isNodeFlexible()) {
- if (singleFlexChild != nullptr ||
- YGFloatsEqual(child->resolveFlexGrow(), 0.0f) ||
- YGFloatsEqual(child->resolveFlexShrink(), 0.0f)) {
- // There is already a flexible child, or this flexible child doesn't
- // have flexGrow and flexShrink, abort
- singleFlexChild = nullptr;
- break;
- } else {
- singleFlexChild = child;
- }
- }
- }
- }
- for (auto child : children) {
- child->resolveDimension();
- if (child->getStyle().display == YGDisplayNone) {
- YGZeroOutLayoutRecursivly(child);
- child->setHasNewLayout(true);
- child->setDirty(false);
- continue;
- }
- if (performLayout) {
- // Set the initial position (relative to the owner).
- const YGDirection childDirection = child->resolveDirection(direction);
- const float mainDim = YGFlexDirectionIsRow(mainAxis)
- ? availableInnerWidth
- : availableInnerHeight;
- const float crossDim = YGFlexDirectionIsRow(mainAxis)
- ? availableInnerHeight
- : availableInnerWidth;
- child->setPosition(
- childDirection, mainDim, crossDim, availableInnerWidth);
- }
- if (child->getStyle().positionType == YGPositionTypeAbsolute) {
- continue;
- }
- if (child == singleFlexChild) {
- child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
- child->setLayoutComputedFlexBasis(YGFloatOptional(0));
- } else {
- YGNodeComputeFlexBasisForChild(
- node,
- child,
- availableInnerWidth,
- widthMeasureMode,
- availableInnerHeight,
- availableInnerWidth,
- availableInnerHeight,
- heightMeasureMode,
- direction,
- config);
- }
- totalOuterFlexBasis += YGUnwrapFloatOptional(
- child->getLayout().computedFlexBasis +
- child->getMarginForAxis(mainAxis, availableInnerWidth));
- }
- }
- // This function assumes that all the children of node have their
- // computedFlexBasis properly computed(To do this use
- // YGNodeComputeFlexBasisForChildren function).
- // This function calculates YGCollectFlexItemsRowMeasurement
- static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
- const YGNodeRef& node,
- const YGDirection ownerDirection,
- const float mainAxisownerSize,
- const float availableInnerWidth,
- const float availableInnerMainDim,
- const uint32_t startOfLineIndex,
- const uint32_t lineCount) {
- YGCollectFlexItemsRowValues flexAlgoRowMeasurement = {};
- flexAlgoRowMeasurement.relativeChildren.reserve(node->getChildren().size());
- float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
- const YGFlexDirection mainAxis = YGResolveFlexDirection(
- node->getStyle().flexDirection, node->resolveDirection(ownerDirection));
- const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
- // Add items to the current line until it's full or we run out of items.
- uint32_t endOfLineIndex = startOfLineIndex;
- for (; endOfLineIndex < node->getChildrenCount(); endOfLineIndex++) {
- const YGNodeRef child = node->getChild(endOfLineIndex);
- if (child->getStyle().display == YGDisplayNone ||
- child->getStyle().positionType == YGPositionTypeAbsolute) {
- continue;
- }
- child->setLineIndex(lineCount);
- const float childMarginMainAxis = YGUnwrapFloatOptional(
- child->getMarginForAxis(mainAxis, availableInnerWidth));
- const float flexBasisWithMinAndMaxConstraints =
- YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
- child,
- mainAxis,
- YGUnwrapFloatOptional(child->getLayout().computedFlexBasis),
- mainAxisownerSize));
- // If this is a multi-line flow and this item pushes us over the
- // available size, we've
- // hit the end of the current line. Break out of the loop and lay out
- // the current line.
- if (sizeConsumedOnCurrentLineIncludingMinConstraint +
- flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
- availableInnerMainDim &&
- isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) {
- break;
- }
- sizeConsumedOnCurrentLineIncludingMinConstraint +=
- flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
- flexAlgoRowMeasurement.sizeConsumedOnCurrentLine +=
- flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
- flexAlgoRowMeasurement.itemsOnLine++;
- if (child->isNodeFlexible()) {
- flexAlgoRowMeasurement.totalFlexGrowFactors += child->resolveFlexGrow();
- // Unlike the grow factor, the shrink factor is scaled relative to the
- // child dimension.
- flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
- -child->resolveFlexShrink() *
- YGUnwrapFloatOptional(child->getLayout().computedFlexBasis);
- }
- flexAlgoRowMeasurement.relativeChildren.push_back(child);
- }
- // The total flex factor needs to be floored to 1.
- if (flexAlgoRowMeasurement.totalFlexGrowFactors > 0 &&
- flexAlgoRowMeasurement.totalFlexGrowFactors < 1) {
- flexAlgoRowMeasurement.totalFlexGrowFactors = 1;
- }
- // The total flex shrink factor needs to be floored to 1.
- if (flexAlgoRowMeasurement.totalFlexShrinkScaledFactors > 0 &&
- flexAlgoRowMeasurement.totalFlexShrinkScaledFactors < 1) {
- flexAlgoRowMeasurement.totalFlexShrinkScaledFactors = 1;
- }
- flexAlgoRowMeasurement.endOfLineIndex = endOfLineIndex;
- return flexAlgoRowMeasurement;
- }
- // It distributes the free space to the flexible items and ensures that the size
- // of the flex items abide the min and max constraints. At the end of this
- // function the child nodes would have proper size. Prior using this function
- // please ensure that YGDistributeFreeSpaceFirstPass is called.
- static float YGDistributeFreeSpaceSecondPass(
- YGCollectFlexItemsRowValues& collectedFlexItemsValues,
- const YGNodeRef node,
- const YGFlexDirection mainAxis,
- const YGFlexDirection crossAxis,
- const float mainAxisownerSize,
- const float availableInnerMainDim,
- const float availableInnerCrossDim,
- const float availableInnerWidth,
- const float availableInnerHeight,
- const bool flexBasisOverflows,
- const YGMeasureMode measureModeCrossDim,
- const bool performLayout,
- const YGConfigRef config) {
- float childFlexBasis = 0;
- float flexShrinkScaledFactor = 0;
- float flexGrowFactor = 0;
- float deltaFreeSpace = 0;
- const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
- const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
- for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
- childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
- currentRelativeChild,
- mainAxis,
- YGUnwrapFloatOptional(
- currentRelativeChild->getLayout().computedFlexBasis),
- mainAxisownerSize));
- float updatedMainSize = childFlexBasis;
- if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
- collectedFlexItemsValues.remainingFreeSpace < 0) {
- flexShrinkScaledFactor =
- -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
- // Is this child able to shrink?
- if (flexShrinkScaledFactor != 0) {
- float childSize;
- if (!YGFloatIsUndefined(
- collectedFlexItemsValues.totalFlexShrinkScaledFactors) &&
- collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
- childSize = childFlexBasis + flexShrinkScaledFactor;
- } else {
- childSize = childFlexBasis +
- (collectedFlexItemsValues.remainingFreeSpace /
- collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
- flexShrinkScaledFactor;
- }
- updatedMainSize = YGNodeBoundAxis(
- currentRelativeChild,
- mainAxis,
- childSize,
- availableInnerMainDim,
- availableInnerWidth);
- }
- } else if (
- !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
- collectedFlexItemsValues.remainingFreeSpace > 0) {
- flexGrowFactor = currentRelativeChild->resolveFlexGrow();
- // Is this child able to grow?
- if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
- updatedMainSize = YGNodeBoundAxis(
- currentRelativeChild,
- mainAxis,
- childFlexBasis +
- collectedFlexItemsValues.remainingFreeSpace /
- collectedFlexItemsValues.totalFlexGrowFactors *
- flexGrowFactor,
- availableInnerMainDim,
- availableInnerWidth);
- }
- }
- deltaFreeSpace += updatedMainSize - childFlexBasis;
- const float marginMain = YGUnwrapFloatOptional(
- currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth));
- const float marginCross = YGUnwrapFloatOptional(
- currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth));
- float childCrossSize;
- float childMainSize = updatedMainSize + marginMain;
- YGMeasureMode childCrossMeasureMode;
- YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
- if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) {
- childCrossSize = isMainAxisRow ? (childMainSize - marginMain) /
- currentRelativeChild->getStyle().aspectRatio.getValue()
- : (childMainSize - marginMain) *
- currentRelativeChild->getStyle().aspectRatio.getValue();
- childCrossMeasureMode = YGMeasureModeExactly;
- childCrossSize += marginCross;
- } else if (
- !YGFloatIsUndefined(availableInnerCrossDim) &&
- !YGNodeIsStyleDimDefined(
- currentRelativeChild, crossAxis, availableInnerCrossDim) &&
- measureModeCrossDim == YGMeasureModeExactly &&
- !(isNodeFlexWrap && flexBasisOverflows) &&
- YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
- currentRelativeChild->marginLeadingValue(crossAxis).unit !=
- YGUnitAuto &&
- currentRelativeChild->marginTrailingValue(crossAxis).unit !=
- YGUnitAuto) {
- childCrossSize = availableInnerCrossDim;
- childCrossMeasureMode = YGMeasureModeExactly;
- } else if (!YGNodeIsStyleDimDefined(
- currentRelativeChild, crossAxis, availableInnerCrossDim)) {
- childCrossSize = availableInnerCrossDim;
- childCrossMeasureMode = YGFloatIsUndefined(childCrossSize)
- ? YGMeasureModeUndefined
- : YGMeasureModeAtMost;
- } else {
- childCrossSize =
- YGUnwrapFloatOptional(YGResolveValue(
- currentRelativeChild->getResolvedDimension(dim[crossAxis]),
- availableInnerCrossDim)) +
- marginCross;
- const bool isLoosePercentageMeasurement =
- currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
- YGUnitPercent &&
- measureModeCrossDim != YGMeasureModeExactly;
- childCrossMeasureMode =
- YGFloatIsUndefined(childCrossSize) || isLoosePercentageMeasurement
- ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- }
- YGConstrainMaxSizeForMode(
- currentRelativeChild,
- mainAxis,
- availableInnerMainDim,
- availableInnerWidth,
- &childMainMeasureMode,
- &childMainSize);
- YGConstrainMaxSizeForMode(
- currentRelativeChild,
- crossAxis,
- availableInnerCrossDim,
- availableInnerWidth,
- &childCrossMeasureMode,
- &childCrossSize);
- const bool requiresStretchLayout =
- !YGNodeIsStyleDimDefined(
- currentRelativeChild, crossAxis, availableInnerCrossDim) &&
- YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
- currentRelativeChild->marginLeadingValue(crossAxis).unit !=
- YGUnitAuto &&
- currentRelativeChild->marginTrailingValue(crossAxis).unit != YGUnitAuto;
- const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
- const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
- const YGMeasureMode childWidthMeasureMode =
- isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
- const YGMeasureMode childHeightMeasureMode =
- !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
- // Recursively call the layout algorithm for this child with the updated
- // main size.
- YGLayoutNodeInternal(
- currentRelativeChild,
- childWidth,
- childHeight,
- node->getLayout().direction,
- childWidthMeasureMode,
- childHeightMeasureMode,
- availableInnerWidth,
- availableInnerHeight,
- performLayout && !requiresStretchLayout,
- "flex",
- config);
- node->setLayoutHadOverflow(
- node->getLayout().hadOverflow |
- currentRelativeChild->getLayout().hadOverflow);
- }
- return deltaFreeSpace;
- }
- // It distributes the free space to the flexible items.For those flexible items
- // whose min and max constraints are triggered, those flex item's clamped size
- // is removed from the remaingfreespace.
- static void YGDistributeFreeSpaceFirstPass(
- YGCollectFlexItemsRowValues& collectedFlexItemsValues,
- const YGFlexDirection mainAxis,
- const float mainAxisownerSize,
- const float availableInnerMainDim,
- const float availableInnerWidth) {
- float flexShrinkScaledFactor = 0;
- float flexGrowFactor = 0;
- float baseMainSize = 0;
- float boundMainSize = 0;
- float deltaFreeSpace = 0;
- for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
- float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
- currentRelativeChild,
- mainAxis,
- YGUnwrapFloatOptional(
- currentRelativeChild->getLayout().computedFlexBasis),
- mainAxisownerSize));
- if (collectedFlexItemsValues.remainingFreeSpace < 0) {
- flexShrinkScaledFactor =
- -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
- // Is this child able to shrink?
- if (!YGFloatIsUndefined(flexShrinkScaledFactor) &&
- flexShrinkScaledFactor != 0) {
- baseMainSize = childFlexBasis +
- collectedFlexItemsValues.remainingFreeSpace /
- collectedFlexItemsValues.totalFlexShrinkScaledFactors *
- flexShrinkScaledFactor;
- boundMainSize = YGNodeBoundAxis(
- currentRelativeChild,
- mainAxis,
- baseMainSize,
- availableInnerMainDim,
- availableInnerWidth);
- if (!YGFloatIsUndefined(baseMainSize) &&
- !YGFloatIsUndefined(boundMainSize) &&
- baseMainSize != boundMainSize) {
- // By excluding this item's size and flex factor from remaining,
- // this item's
- // min/max constraints should also trigger in the second pass
- // resulting in the
- // item's size calculation being identical in the first and second
- // passes.
- deltaFreeSpace += boundMainSize - childFlexBasis;
- collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
- flexShrinkScaledFactor;
- }
- }
- } else if (
- !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
- collectedFlexItemsValues.remainingFreeSpace > 0) {
- flexGrowFactor = currentRelativeChild->resolveFlexGrow();
- // Is this child able to grow?
- if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
- baseMainSize = childFlexBasis +
- collectedFlexItemsValues.remainingFreeSpace /
- collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
- boundMainSize = YGNodeBoundAxis(
- currentRelativeChild,
- mainAxis,
- baseMainSize,
- availableInnerMainDim,
- availableInnerWidth);
- if (!YGFloatIsUndefined(baseMainSize) &&
- !YGFloatIsUndefined(boundMainSize) &&
- baseMainSize != boundMainSize) {
- // By excluding this item's size and flex factor from remaining,
- // this item's
- // min/max constraints should also trigger in the second pass
- // resulting in the
- // item's size calculation being identical in the first and second
- // passes.
- deltaFreeSpace += boundMainSize - childFlexBasis;
- collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
- }
- }
- }
- }
- collectedFlexItemsValues.remainingFreeSpace -= deltaFreeSpace;
- }
- // Do two passes over the flex items to figure out how to distribute the
- // remaining space.
- // The first pass finds the items whose min/max constraints trigger,
- // freezes them at those
- // sizes, and excludes those sizes from the remaining space. The second
- // pass sets the size
- // of each flexible item. It distributes the remaining space amongst the
- // items whose min/max
- // constraints didn't trigger in pass 1. For the other items, it sets
- // their sizes by forcing
- // their min/max constraints to trigger again.
- //
- // This two pass approach for resolving min/max constraints deviates from
- // the spec. The
- // spec (https://www.w3.org/TR/YG-flexbox-1/#resolve-flexible-lengths)
- // describes a process
- // that needs to be repeated a variable number of times. The algorithm
- // implemented here
- // won't handle all cases but it was simpler to implement and it mitigates
- // performance
- // concerns because we know exactly how many passes it'll do.
- //
- // At the end of this function the child nodes would have the proper size
- // assigned to them.
- //
- static void YGResolveFlexibleLength(
- const YGNodeRef node,
- YGCollectFlexItemsRowValues& collectedFlexItemsValues,
- const YGFlexDirection mainAxis,
- const YGFlexDirection crossAxis,
- const float mainAxisownerSize,
- const float availableInnerMainDim,
- const float availableInnerCrossDim,
- const float availableInnerWidth,
- const float availableInnerHeight,
- const bool flexBasisOverflows,
- const YGMeasureMode measureModeCrossDim,
- const bool performLayout,
- const YGConfigRef config) {
- const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace;
- // First pass: detect the flex items whose min/max constraints trigger
- YGDistributeFreeSpaceFirstPass(
- collectedFlexItemsValues,
- mainAxis,
- mainAxisownerSize,
- availableInnerMainDim,
- availableInnerWidth);
- // Second pass: resolve the sizes of the flexible items
- const float distributedFreeSpace = YGDistributeFreeSpaceSecondPass(
- collectedFlexItemsValues,
- node,
- mainAxis,
- crossAxis,
- mainAxisownerSize,
- availableInnerMainDim,
- availableInnerCrossDim,
- availableInnerWidth,
- availableInnerHeight,
- flexBasisOverflows,
- measureModeCrossDim,
- performLayout,
- config);
- collectedFlexItemsValues.remainingFreeSpace =
- originalFreeSpace - distributedFreeSpace;
- }
- static void YGJustifyMainAxis(
- const YGNodeRef node,
- YGCollectFlexItemsRowValues& collectedFlexItemsValues,
- const uint32_t& startOfLineIndex,
- const YGFlexDirection& mainAxis,
- const YGFlexDirection& crossAxis,
- const YGMeasureMode& measureModeMainDim,
- const YGMeasureMode& measureModeCrossDim,
- const float& mainAxisownerSize,
- const float& ownerWidth,
- const float& availableInnerMainDim,
- const float& availableInnerCrossDim,
- const float& availableInnerWidth,
- const bool& performLayout) {
- const YGStyle style = node->getStyle();
- // If we are using "at most" rules in the main axis. Calculate the remaining
- // space when constraint by the min size defined for the main axis.
- if (measureModeMainDim == YGMeasureModeAtMost &&
- collectedFlexItemsValues.remainingFreeSpace > 0) {
- if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
- !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
- .isUndefined()) {
- collectedFlexItemsValues.remainingFreeSpace = YGFloatMax(
- 0,
- YGUnwrapFloatOptional(YGResolveValue(
- style.minDimensions[dim[mainAxis]], mainAxisownerSize)) -
- (availableInnerMainDim -
- collectedFlexItemsValues.remainingFreeSpace));
- } else {
- collectedFlexItemsValues.remainingFreeSpace = 0;
- }
- }
- int numberOfAutoMarginsOnCurrentLine = 0;
- for (uint32_t i = startOfLineIndex;
- i < collectedFlexItemsValues.endOfLineIndex;
- i++) {
- const YGNodeRef child = node->getChild(i);
- if (child->getStyle().positionType == YGPositionTypeRelative) {
- if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
- numberOfAutoMarginsOnCurrentLine++;
- }
- if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
- numberOfAutoMarginsOnCurrentLine++;
- }
- }
- }
- // In order to position the elements in the main axis, we have two
- // controls. The space between the beginning and the first element
- // and the space between each two elements.
- float leadingMainDim = 0;
- float betweenMainDim = 0;
- const YGJustify justifyContent = node->getStyle().justifyContent;
- if (numberOfAutoMarginsOnCurrentLine == 0) {
- switch (justifyContent) {
- case YGJustifyCenter:
- leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
- break;
- case YGJustifyFlexEnd:
- leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
- break;
- case YGJustifySpaceBetween:
- if (collectedFlexItemsValues.itemsOnLine > 1) {
- betweenMainDim =
- YGFloatMax(collectedFlexItemsValues.remainingFreeSpace, 0) /
- (collectedFlexItemsValues.itemsOnLine - 1);
- } else {
- betweenMainDim = 0;
- }
- break;
- case YGJustifySpaceEvenly:
- // Space is distributed evenly across all elements
- betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
- (collectedFlexItemsValues.itemsOnLine + 1);
- leadingMainDim = betweenMainDim;
- break;
- case YGJustifySpaceAround:
- // Space on the edges is half of the space between elements
- betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
- collectedFlexItemsValues.itemsOnLine;
- leadingMainDim = betweenMainDim / 2;
- break;
- case YGJustifyFlexStart:
- break;
- }
- }
- const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional(
- node->getLeadingPaddingAndBorder(mainAxis, ownerWidth));
- collectedFlexItemsValues.mainDim =
- leadingPaddingAndBorderMain + leadingMainDim;
- collectedFlexItemsValues.crossDim = 0;
- for (uint32_t i = startOfLineIndex;
- i < collectedFlexItemsValues.endOfLineIndex;
- i++) {
- const YGNodeRef child = node->getChild(i);
- const YGStyle childStyle = child->getStyle();
- const YGLayout childLayout = child->getLayout();
- if (childStyle.display == YGDisplayNone) {
- continue;
- }
- if (childStyle.positionType == YGPositionTypeAbsolute &&
- child->isLeadingPositionDefined(mainAxis)) {
- if (performLayout) {
- // In case the child is position absolute and has left/top being
- // defined, we override the position to whatever the user said
- // (and margin/border).
- child->setLayoutPosition(
- YGUnwrapFloatOptional(
- child->getLeadingPosition(mainAxis, availableInnerMainDim)) +
- node->getLeadingBorder(mainAxis) +
- YGUnwrapFloatOptional(
- child->getLeadingMargin(mainAxis, availableInnerWidth)),
- pos[mainAxis]);
- }
- } else {
- // Now that we placed the element, we need to update the variables.
- // We need to do that only for relative elements. Absolute elements
- // do not take part in that phase.
- if (childStyle.positionType == YGPositionTypeRelative) {
- if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
- collectedFlexItemsValues.mainDim +=
- collectedFlexItemsValues.remainingFreeSpace /
- numberOfAutoMarginsOnCurrentLine;
- }
- if (performLayout) {
- child->setLayoutPosition(
- childLayout.position[pos[mainAxis]] +
- collectedFlexItemsValues.mainDim,
- pos[mainAxis]);
- }
- if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
- collectedFlexItemsValues.mainDim +=
- collectedFlexItemsValues.remainingFreeSpace /
- numberOfAutoMarginsOnCurrentLine;
- }
- bool canSkipFlex =
- !performLayout && measureModeCrossDim == YGMeasureModeExactly;
- if (canSkipFlex) {
- // If we skipped the flex step, then we can't rely on the
- // measuredDims because
- // they weren't computed. This means we can't call
- // YGNodeDimWithMargin.
- collectedFlexItemsValues.mainDim += betweenMainDim +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- mainAxis, availableInnerWidth)) +
- YGUnwrapFloatOptional(childLayout.computedFlexBasis);
- collectedFlexItemsValues.crossDim = availableInnerCrossDim;
- } else {
- // The main dimension is the sum of all the elements dimension plus
- // the spacing.
- collectedFlexItemsValues.mainDim += betweenMainDim +
- YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
- // The cross dimension is the max of the elements dimension since
- // there can only be one element in that cross dimension.
- collectedFlexItemsValues.crossDim = YGFloatMax(
- collectedFlexItemsValues.crossDim,
- YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
- }
- } else if (performLayout) {
- child->setLayoutPosition(
- childLayout.position[pos[mainAxis]] +
- node->getLeadingBorder(mainAxis) + leadingMainDim,
- pos[mainAxis]);
- }
- }
- }
- collectedFlexItemsValues.mainDim += YGUnwrapFloatOptional(
- node->getTrailingPaddingAndBorder(mainAxis, ownerWidth));
- }
- //
- // This is the main routine that implements a subset of the flexbox layout
- // algorithm
- // described in the W3C YG documentation: https://www.w3.org/TR/YG3-flexbox/.
- //
- // Limitations of this algorithm, compared to the full standard:
- // * Display property is always assumed to be 'flex' except for Text nodes,
- // which
- // are assumed to be 'inline-flex'.
- // * The 'zIndex' property (or any form of z ordering) is not supported. Nodes
- // are
- // stacked in document order.
- // * The 'order' property is not supported. The order of flex items is always
- // defined
- // by document order.
- // * The 'visibility' property is always assumed to be 'visible'. Values of
- // 'collapse'
- // and 'hidden' are not supported.
- // * There is no support for forced breaks.
- // * It does not support vertical inline directions (top-to-bottom or
- // bottom-to-top text).
- //
- // Deviations from standard:
- // * Section 4.5 of the spec indicates that all flex items have a default
- // minimum
- // main size. For text blocks, for example, this is the width of the widest
- // word.
- // Calculating the minimum width is expensive, so we forego it and assume a
- // default
- // minimum main size of 0.
- // * Min/Max sizes in the main axis are not honored when resolving flexible
- // lengths.
- // * The spec indicates that the default value for 'flexDirection' is 'row',
- // but
- // the algorithm below assumes a default of 'column'.
- //
- // Input parameters:
- // - node: current node to be sized and layed out
- // - availableWidth & availableHeight: available size to be used for sizing
- // the node
- // or YGUndefined if the size is not available; interpretation depends on
- // layout
- // flags
- // - ownerDirection: the inline (text) direction within the owner
- // (left-to-right or
- // right-to-left)
- // - widthMeasureMode: indicates the sizing rules for the width (see below
- // for explanation)
- // - heightMeasureMode: indicates the sizing rules for the height (see below
- // for explanation)
- // - performLayout: specifies whether the caller is interested in just the
- // dimensions
- // of the node or it requires the entire node and its subtree to be layed
- // out
- // (with final positions)
- //
- // Details:
- // This routine is called recursively to lay out subtrees of flexbox
- // elements. It uses the
- // information in node.style, which is treated as a read-only input. It is
- // responsible for
- // setting the layout.direction and layout.measuredDimensions fields for the
- // input node as well
- // as the layout.position and layout.lineIndex fields for its child nodes.
- // The
- // layout.measuredDimensions field includes any border or padding for the
- // node but does
- // not include margins.
- //
- // The spec describes four different layout modes: "fill available", "max
- // content", "min
- // content",
- // and "fit content". Of these, we don't use "min content" because we don't
- // support default
- // minimum main sizes (see above for details). Each of our measure modes maps
- // to a layout mode
- // from the spec (https://www.w3.org/TR/YG3-sizing/#terms):
- // - YGMeasureModeUndefined: max content
- // - YGMeasureModeExactly: fill available
- // - YGMeasureModeAtMost: fit content
- //
- // When calling YGNodelayoutImpl and YGLayoutNodeInternal, if the caller passes
- // an available size of
- // undefined then it must also pass a measure mode of YGMeasureModeUndefined
- // in that dimension.
- //
- static void YGNodelayoutImpl(const YGNodeRef node,
- const float availableWidth,
- const float availableHeight,
- const YGDirection ownerDirection,
- const YGMeasureMode widthMeasureMode,
- const YGMeasureMode heightMeasureMode,
- const float ownerWidth,
- const float ownerHeight,
- const bool performLayout,
- const YGConfigRef config) {
- YGAssertWithNode(node,
- YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined
- : true,
- "availableWidth is indefinite so widthMeasureMode must be "
- "YGMeasureModeUndefined");
- YGAssertWithNode(node,
- YGFloatIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined
- : true,
- "availableHeight is indefinite so heightMeasureMode must be "
- "YGMeasureModeUndefined");
- // Set the resolved resolution in the node's layout.
- const YGDirection direction = node->resolveDirection(ownerDirection);
- node->setLayoutDirection(direction);
- const YGFlexDirection flexRowDirection = YGResolveFlexDirection(YGFlexDirectionRow, direction);
- const YGFlexDirection flexColumnDirection =
- YGResolveFlexDirection(YGFlexDirectionColumn, direction);
- node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getLeadingMargin(flexRowDirection, ownerWidth)),
- YGEdgeStart);
- node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getTrailingMargin(flexRowDirection, ownerWidth)),
- YGEdgeEnd);
- node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getLeadingMargin(flexColumnDirection, ownerWidth)),
- YGEdgeTop);
- node->setLayoutMargin(
- YGUnwrapFloatOptional(
- node->getTrailingMargin(flexColumnDirection, ownerWidth)),
- YGEdgeBottom);
- node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart);
- node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), YGEdgeEnd);
- node->setLayoutBorder(node->getLeadingBorder(flexColumnDirection), YGEdgeTop);
- node->setLayoutBorder(
- node->getTrailingBorder(flexColumnDirection), YGEdgeBottom);
- node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getLeadingPadding(flexRowDirection, ownerWidth)),
- YGEdgeStart);
- node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getTrailingPadding(flexRowDirection, ownerWidth)),
- YGEdgeEnd);
- node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getLeadingPadding(flexColumnDirection, ownerWidth)),
- YGEdgeTop);
- node->setLayoutPadding(
- YGUnwrapFloatOptional(
- node->getTrailingPadding(flexColumnDirection, ownerWidth)),
- YGEdgeBottom);
- if (node->getMeasure() != nullptr) {
- YGNodeWithMeasureFuncSetMeasuredDimensions(node,
- availableWidth,
- availableHeight,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight);
- return;
- }
- const uint32_t childCount = YGNodeGetChildCount(node);
- if (childCount == 0) {
- YGNodeEmptyContainerSetMeasuredDimensions(node,
- availableWidth,
- availableHeight,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight);
- return;
- }
- // If we're not being asked to perform a full layout we can skip the algorithm if we already know
- // the size
- if (!performLayout && YGNodeFixedSizeSetMeasuredDimensions(node,
- availableWidth,
- availableHeight,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight)) {
- return;
- }
- // At this point we know we're going to perform work. Ensure that each child has a mutable copy.
- node->cloneChildrenIfNeeded();
- // Reset layout flags, as they could have changed.
- node->setLayoutHadOverflow(false);
- // STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
- const YGFlexDirection mainAxis =
- YGResolveFlexDirection(node->getStyle().flexDirection, direction);
- const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
- const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
- const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
- const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
- const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
- const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional(
- node->getLeadingPaddingAndBorder(crossAxis, ownerWidth));
- const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth);
- const float paddingAndBorderAxisCross =
- YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth);
- YGMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
- YGMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
- const float paddingAndBorderAxisRow =
- isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross;
- const float paddingAndBorderAxisColumn =
- isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
- const float minInnerWidth =
- YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) -
- paddingAndBorderAxisRow;
- const float maxInnerWidth =
- YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) -
- paddingAndBorderAxisRow;
- const float minInnerHeight =
- YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) -
- paddingAndBorderAxisColumn;
- const float maxInnerHeight =
- YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) -
- paddingAndBorderAxisColumn;
- const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
- const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
- // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
- float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
- node, YGFlexDirectionRow, availableWidth, ownerWidth);
- float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
- node, YGFlexDirectionColumn, availableHeight, ownerHeight);
- float availableInnerMainDim =
- isMainAxisRow ? availableInnerWidth : availableInnerHeight;
- const float availableInnerCrossDim =
- isMainAxisRow ? availableInnerHeight : availableInnerWidth;
- float totalOuterFlexBasis = 0;
- // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
- YGNodeComputeFlexBasisForChildren(
- node,
- availableInnerWidth,
- availableInnerHeight,
- widthMeasureMode,
- heightMeasureMode,
- direction,
- mainAxis,
- config,
- performLayout,
- totalOuterFlexBasis);
- const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
- ? false
- : totalOuterFlexBasis > availableInnerMainDim;
- if (isNodeFlexWrap && flexBasisOverflows &&
- measureModeMainDim == YGMeasureModeAtMost) {
- measureModeMainDim = YGMeasureModeExactly;
- }
- // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
- // Indexes of children that represent the first and last items in the line.
- uint32_t startOfLineIndex = 0;
- uint32_t endOfLineIndex = 0;
- // Number of lines.
- uint32_t lineCount = 0;
- // Accumulated cross dimensions of all lines so far.
- float totalLineCrossDim = 0;
- // Max main dimension of all the lines.
- float maxLineMainDim = 0;
- YGCollectFlexItemsRowValues collectedFlexItemsValues;
- for (; endOfLineIndex < childCount;
- lineCount++, startOfLineIndex = endOfLineIndex) {
- collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues(
- node,
- ownerDirection,
- mainAxisownerSize,
- availableInnerWidth,
- availableInnerMainDim,
- startOfLineIndex,
- lineCount);
- endOfLineIndex = collectedFlexItemsValues.endOfLineIndex;
- // If we don't need to measure the cross axis, we can skip the entire flex
- // step.
- const bool canSkipFlex =
- !performLayout && measureModeCrossDim == YGMeasureModeExactly;
- // STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
- // Calculate the remaining available space that needs to be allocated.
- // If the main dimension size isn't known, it is computed based on
- // the line length, so there's no more space left to distribute.
- bool sizeBasedOnContent = false;
- // If we don't measure with exact main dimension we want to ensure we don't violate min and max
- if (measureModeMainDim != YGMeasureModeExactly) {
- if (!YGFloatIsUndefined(minInnerMainDim) &&
- collectedFlexItemsValues.sizeConsumedOnCurrentLine <
- minInnerMainDim) {
- availableInnerMainDim = minInnerMainDim;
- } else if (
- !YGFloatIsUndefined(maxInnerMainDim) &&
- collectedFlexItemsValues.sizeConsumedOnCurrentLine >
- maxInnerMainDim) {
- availableInnerMainDim = maxInnerMainDim;
- } else {
- if (!node->getConfig()->useLegacyStretchBehaviour &&
- ((YGFloatIsUndefined(
- collectedFlexItemsValues.totalFlexGrowFactors) &&
- collectedFlexItemsValues.totalFlexGrowFactors == 0) ||
- (YGFloatIsUndefined(node->resolveFlexGrow()) &&
- node->resolveFlexGrow() == 0))) {
- // If we don't have any children to flex or we can't flex the node
- // itself, space we've used is all space we need. Root node also
- // should be shrunk to minimum
- availableInnerMainDim =
- collectedFlexItemsValues.sizeConsumedOnCurrentLine;
- }
- if (node->getConfig()->useLegacyStretchBehaviour) {
- node->setLayoutDidUseLegacyFlag(true);
- }
- sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour;
- }
- }
- if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
- collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
- collectedFlexItemsValues.sizeConsumedOnCurrentLine;
- } else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
- // availableInnerMainDim is indefinite which means the node is being sized based on its
- // content.
- // sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for
- // its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
- collectedFlexItemsValues.remainingFreeSpace =
- -collectedFlexItemsValues.sizeConsumedOnCurrentLine;
- }
- if (!canSkipFlex) {
- YGResolveFlexibleLength(
- node,
- collectedFlexItemsValues,
- mainAxis,
- crossAxis,
- mainAxisownerSize,
- availableInnerMainDim,
- availableInnerCrossDim,
- availableInnerWidth,
- availableInnerHeight,
- flexBasisOverflows,
- measureModeCrossDim,
- performLayout,
- config);
- }
- node->setLayoutHadOverflow(
- node->getLayout().hadOverflow |
- (collectedFlexItemsValues.remainingFreeSpace < 0));
- // STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
- // At this point, all the children have their dimensions set in the main
- // axis.
- // Their dimensions are also set in the cross axis with the exception of
- // items
- // that are aligned "stretch". We need to compute these stretch values and
- // set the final positions.
- YGJustifyMainAxis(
- node,
- collectedFlexItemsValues,
- startOfLineIndex,
- mainAxis,
- crossAxis,
- measureModeMainDim,
- measureModeCrossDim,
- mainAxisownerSize,
- ownerWidth,
- availableInnerMainDim,
- availableInnerCrossDim,
- availableInnerWidth,
- performLayout);
- float containerCrossAxis = availableInnerCrossDim;
- if (measureModeCrossDim == YGMeasureModeUndefined ||
- measureModeCrossDim == YGMeasureModeAtMost) {
- // Compute the cross axis from the max cross dimension of the children.
- containerCrossAxis =
- YGNodeBoundAxis(
- node,
- crossAxis,
- collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
- crossAxisownerSize,
- ownerWidth) -
- paddingAndBorderAxisCross;
- }
- // If there's no flex wrap, the cross dimension is defined by the container.
- if (!isNodeFlexWrap && measureModeCrossDim == YGMeasureModeExactly) {
- collectedFlexItemsValues.crossDim = availableInnerCrossDim;
- }
- // Clamp to the min/max size specified on the container.
- collectedFlexItemsValues.crossDim =
- YGNodeBoundAxis(
- node,
- crossAxis,
- collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
- crossAxisownerSize,
- ownerWidth) -
- paddingAndBorderAxisCross;
- // STEP 7: CROSS-AXIS ALIGNMENT
- // We can skip child alignment if we're just measuring the container.
- if (performLayout) {
- for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
- const YGNodeRef child = node->getChild(i);
- if (child->getStyle().display == YGDisplayNone) {
- continue;
- }
- if (child->getStyle().positionType == YGPositionTypeAbsolute) {
- // If the child is absolutely positioned and has a
- // top/left/bottom/right set, override
- // all the previously computed positions to set it correctly.
- const bool isChildLeadingPosDefined =
- child->isLeadingPositionDefined(crossAxis);
- if (isChildLeadingPosDefined) {
- child->setLayoutPosition(
- YGUnwrapFloatOptional(child->getLeadingPosition(
- crossAxis, availableInnerCrossDim)) +
- node->getLeadingBorder(crossAxis) +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
- pos[crossAxis]);
- }
- // If leading position is not defined or calculations result in Nan, default to border + margin
- if (!isChildLeadingPosDefined ||
- YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) {
- child->setLayoutPosition(
- node->getLeadingBorder(crossAxis) +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
- pos[crossAxis]);
- }
- } else {
- float leadingCrossDim = leadingPaddingAndBorderCross;
- // For a relative children, we're either using alignItems (owner) or
- // alignSelf (child) in order to determine the position in the cross
- // axis
- const YGAlign alignItem = YGNodeAlignItem(node, child);
- // If the child uses align stretch, we need to lay it out one more
- // time, this time
- // forcing the cross-axis size to be the computed cross size for the
- // current line.
- if (alignItem == YGAlignStretch &&
- child->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
- child->marginTrailingValue(crossAxis).unit != YGUnitAuto) {
- // If the child defines a definite size for its cross axis, there's
- // no need to stretch.
- if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
- float childMainSize =
- child->getLayout().measuredDimensions[dim[mainAxis]];
- float childCrossSize =
- !child->getStyle().aspectRatio.isUndefined()
- ? ((YGUnwrapFloatOptional(child->getMarginForAxis(
- crossAxis, availableInnerWidth)) +
- (isMainAxisRow ? childMainSize /
- child->getStyle().aspectRatio.getValue()
- : childMainSize *
- child->getStyle().aspectRatio.getValue())))
- : collectedFlexItemsValues.crossDim;
- childMainSize += YGUnwrapFloatOptional(
- child->getMarginForAxis(mainAxis, availableInnerWidth));
- YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
- YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly;
- YGConstrainMaxSizeForMode(child,
- mainAxis,
- availableInnerMainDim,
- availableInnerWidth,
- &childMainMeasureMode,
- &childMainSize);
- YGConstrainMaxSizeForMode(child,
- crossAxis,
- availableInnerCrossDim,
- availableInnerWidth,
- &childCrossMeasureMode,
- &childCrossSize);
- const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
- const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
- const YGMeasureMode childWidthMeasureMode =
- YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- const YGMeasureMode childHeightMeasureMode =
- YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- YGLayoutNodeInternal(
- child,
- childWidth,
- childHeight,
- direction,
- childWidthMeasureMode,
- childHeightMeasureMode,
- availableInnerWidth,
- availableInnerHeight,
- true,
- "stretch",
- config);
- }
- } else {
- const float remainingCrossDim = containerCrossAxis -
- YGNodeDimWithMargin(child, crossAxis, availableInnerWidth);
- if (child->marginLeadingValue(crossAxis).unit == YGUnitAuto &&
- child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
- leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim / 2);
- } else if (
- child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
- // No-Op
- } else if (
- child->marginLeadingValue(crossAxis).unit == YGUnitAuto) {
- leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim);
- } else if (alignItem == YGAlignFlexStart) {
- // No-Op
- } else if (alignItem == YGAlignCenter) {
- leadingCrossDim += remainingCrossDim / 2;
- } else {
- leadingCrossDim += remainingCrossDim;
- }
- }
- // And we apply the position
- child->setLayoutPosition(
- child->getLayout().position[pos[crossAxis]] + totalLineCrossDim +
- leadingCrossDim,
- pos[crossAxis]);
- }
- }
- }
- totalLineCrossDim += collectedFlexItemsValues.crossDim;
- maxLineMainDim =
- YGFloatMax(maxLineMainDim, collectedFlexItemsValues.mainDim);
- }
- // STEP 8: MULTI-LINE CONTENT ALIGNMENT
- if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) &&
- !YGFloatIsUndefined(availableInnerCrossDim)) {
- const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
- float crossDimLead = 0;
- float currentLead = leadingPaddingAndBorderCross;
- switch (node->getStyle().alignContent) {
- case YGAlignFlexEnd:
- currentLead += remainingAlignContentDim;
- break;
- case YGAlignCenter:
- currentLead += remainingAlignContentDim / 2;
- break;
- case YGAlignStretch:
- if (availableInnerCrossDim > totalLineCrossDim) {
- crossDimLead = remainingAlignContentDim / lineCount;
- }
- break;
- case YGAlignSpaceAround:
- if (availableInnerCrossDim > totalLineCrossDim) {
- currentLead += remainingAlignContentDim / (2 * lineCount);
- if (lineCount > 1) {
- crossDimLead = remainingAlignContentDim / lineCount;
- }
- } else {
- currentLead += remainingAlignContentDim / 2;
- }
- break;
- case YGAlignSpaceBetween:
- if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) {
- crossDimLead = remainingAlignContentDim / (lineCount - 1);
- }
- break;
- case YGAlignAuto:
- case YGAlignFlexStart:
- case YGAlignBaseline:
- break;
- }
- uint32_t endIndex = 0;
- for (uint32_t i = 0; i < lineCount; i++) {
- const uint32_t startIndex = endIndex;
- uint32_t ii;
- // compute the line's height and find the endIndex
- float lineHeight = 0;
- float maxAscentForCurrentLine = 0;
- float maxDescentForCurrentLine = 0;
- for (ii = startIndex; ii < childCount; ii++) {
- const YGNodeRef child = node->getChild(ii);
- if (child->getStyle().display == YGDisplayNone) {
- continue;
- }
- if (child->getStyle().positionType == YGPositionTypeRelative) {
- if (child->getLineIndex() != i) {
- break;
- }
- if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
- lineHeight = YGFloatMax(
- lineHeight,
- child->getLayout().measuredDimensions[dim[crossAxis]] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- crossAxis, availableInnerWidth)));
- }
- if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
- const float ascent = YGBaseline(child) +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- YGFlexDirectionColumn, availableInnerWidth));
- const float descent =
- child->getLayout().measuredDimensions[YGDimensionHeight] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- YGFlexDirectionColumn, availableInnerWidth)) -
- ascent;
- maxAscentForCurrentLine =
- YGFloatMax(maxAscentForCurrentLine, ascent);
- maxDescentForCurrentLine =
- YGFloatMax(maxDescentForCurrentLine, descent);
- lineHeight = YGFloatMax(
- lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
- }
- }
- }
- endIndex = ii;
- lineHeight += crossDimLead;
- if (performLayout) {
- for (ii = startIndex; ii < endIndex; ii++) {
- const YGNodeRef child = node->getChild(ii);
- if (child->getStyle().display == YGDisplayNone) {
- continue;
- }
- if (child->getStyle().positionType == YGPositionTypeRelative) {
- switch (YGNodeAlignItem(node, child)) {
- case YGAlignFlexStart: {
- child->setLayoutPosition(
- currentLead +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
- pos[crossAxis]);
- break;
- }
- case YGAlignFlexEnd: {
- child->setLayoutPosition(
- currentLead + lineHeight -
- YGUnwrapFloatOptional(child->getTrailingMargin(
- crossAxis, availableInnerWidth)) -
- child->getLayout().measuredDimensions[dim[crossAxis]],
- pos[crossAxis]);
- break;
- }
- case YGAlignCenter: {
- float childHeight =
- child->getLayout().measuredDimensions[dim[crossAxis]];
- child->setLayoutPosition(
- currentLead + (lineHeight - childHeight) / 2,
- pos[crossAxis]);
- break;
- }
- case YGAlignStretch: {
- child->setLayoutPosition(
- currentLead +
- YGUnwrapFloatOptional(child->getLeadingMargin(
- crossAxis, availableInnerWidth)),
- pos[crossAxis]);
- // Remeasure child with the line height as it as been only measured with the
- // owners height yet.
- if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
- const float childWidth = isMainAxisRow
- ? (child->getLayout()
- .measuredDimensions[YGDimensionWidth] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- mainAxis, availableInnerWidth)))
- : lineHeight;
- const float childHeight = !isMainAxisRow
- ? (child->getLayout()
- .measuredDimensions[YGDimensionHeight] +
- YGUnwrapFloatOptional(child->getMarginForAxis(
- crossAxis, availableInnerWidth)))
- : lineHeight;
- if (!(YGFloatsEqual(
- childWidth,
- child->getLayout()
- .measuredDimensions[YGDimensionWidth]) &&
- YGFloatsEqual(
- childHeight,
- child->getLayout()
- .measuredDimensions[YGDimensionHeight]))) {
- YGLayoutNodeInternal(child,
- childWidth,
- childHeight,
- direction,
- YGMeasureModeExactly,
- YGMeasureModeExactly,
- availableInnerWidth,
- availableInnerHeight,
- true,
- "multiline-stretch",
- config);
- }
- }
- break;
- }
- case YGAlignBaseline: {
- child->setLayoutPosition(
- currentLead + maxAscentForCurrentLine - YGBaseline(child) +
- YGUnwrapFloatOptional(child->getLeadingPosition(
- YGFlexDirectionColumn, availableInnerCrossDim)),
- YGEdgeTop);
- break;
- }
- case YGAlignAuto:
- case YGAlignSpaceBetween:
- case YGAlignSpaceAround:
- break;
- }
- }
- }
- }
- currentLead += lineHeight;
- }
- }
- // STEP 9: COMPUTING FINAL DIMENSIONS
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionRow,
- availableWidth - marginAxisRow,
- ownerWidth,
- ownerWidth),
- YGDimensionWidth);
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- YGFlexDirectionColumn,
- availableHeight - marginAxisColumn,
- ownerHeight,
- ownerWidth),
- YGDimensionHeight);
- // If the user didn't specify a width or height for the node, set the
- // dimensions based on the children.
- if (measureModeMainDim == YGMeasureModeUndefined ||
- (node->getStyle().overflow != YGOverflowScroll &&
- measureModeMainDim == YGMeasureModeAtMost)) {
- // Clamp the size to the min/max size, if specified, and make sure it
- // doesn't go below the padding and border amount.
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node, mainAxis, maxLineMainDim, mainAxisownerSize, ownerWidth),
- dim[mainAxis]);
- } else if (
- measureModeMainDim == YGMeasureModeAtMost &&
- node->getStyle().overflow == YGOverflowScroll) {
- node->setLayoutMeasuredDimension(
- YGFloatMax(
- YGFloatMin(
- availableInnerMainDim + paddingAndBorderAxisMain,
- YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
- node, mainAxis, maxLineMainDim, mainAxisownerSize))),
- paddingAndBorderAxisMain),
- dim[mainAxis]);
- }
- if (measureModeCrossDim == YGMeasureModeUndefined ||
- (node->getStyle().overflow != YGOverflowScroll &&
- measureModeCrossDim == YGMeasureModeAtMost)) {
- // Clamp the size to the min/max size, if specified, and make sure it
- // doesn't go below the padding and border amount.
- node->setLayoutMeasuredDimension(
- YGNodeBoundAxis(
- node,
- crossAxis,
- totalLineCrossDim + paddingAndBorderAxisCross,
- crossAxisownerSize,
- ownerWidth),
- dim[crossAxis]);
- } else if (
- measureModeCrossDim == YGMeasureModeAtMost &&
- node->getStyle().overflow == YGOverflowScroll) {
- node->setLayoutMeasuredDimension(
- YGFloatMax(
- YGFloatMin(
- availableInnerCrossDim + paddingAndBorderAxisCross,
- YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
- node,
- crossAxis,
- totalLineCrossDim + paddingAndBorderAxisCross,
- crossAxisownerSize))),
- paddingAndBorderAxisCross),
- dim[crossAxis]);
- }
- // As we only wrapped in normal direction yet, we need to reverse the positions on wrap-reverse.
- if (performLayout && node->getStyle().flexWrap == YGWrapWrapReverse) {
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef child = YGNodeGetChild(node, i);
- if (child->getStyle().positionType == YGPositionTypeRelative) {
- child->setLayoutPosition(
- node->getLayout().measuredDimensions[dim[crossAxis]] -
- child->getLayout().position[pos[crossAxis]] -
- child->getLayout().measuredDimensions[dim[crossAxis]],
- pos[crossAxis]);
- }
- }
- }
- if (performLayout) {
- // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
- for (auto child : node->getChildren()) {
- if (child->getStyle().positionType != YGPositionTypeAbsolute) {
- continue;
- }
- YGNodeAbsoluteLayoutChild(
- node,
- child,
- availableInnerWidth,
- isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
- availableInnerHeight,
- direction,
- config);
- }
- // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
- const bool needsMainTrailingPos =
- mainAxis == YGFlexDirectionRowReverse || mainAxis == YGFlexDirectionColumnReverse;
- const bool needsCrossTrailingPos =
- crossAxis == YGFlexDirectionRowReverse || crossAxis == YGFlexDirectionColumnReverse;
- // Set trailing position if necessary.
- if (needsMainTrailingPos || needsCrossTrailingPos) {
- for (uint32_t i = 0; i < childCount; i++) {
- const YGNodeRef child = node->getChild(i);
- if (child->getStyle().display == YGDisplayNone) {
- continue;
- }
- if (needsMainTrailingPos) {
- YGNodeSetChildTrailingPosition(node, child, mainAxis);
- }
- if (needsCrossTrailingPos) {
- YGNodeSetChildTrailingPosition(node, child, crossAxis);
- }
- }
- }
- }
- }
- uint32_t gDepth = 0;
- bool gPrintTree = false;
- bool gPrintChanges = false;
- bool gPrintSkips = false;
- static const char *spacer = " ";
- static const char *YGSpacer(const unsigned long level) {
- const size_t spacerLen = strlen(spacer);
- if (level > spacerLen) {
- return &spacer[0];
- } else {
- return &spacer[spacerLen - level];
- }
- }
- static const char *YGMeasureModeName(const YGMeasureMode mode, const bool performLayout) {
- const char *kMeasureModeNames[YGMeasureModeCount] = {"UNDEFINED", "EXACTLY", "AT_MOST"};
- const char *kLayoutModeNames[YGMeasureModeCount] = {"LAY_UNDEFINED",
- "LAY_EXACTLY",
- "LAY_AT_"
- "MOST"};
- if (mode >= YGMeasureModeCount) {
- return "";
- }
- return performLayout ? kLayoutModeNames[mode] : kMeasureModeNames[mode];
- }
- static inline bool YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(YGMeasureMode sizeMode,
- float size,
- float lastComputedSize) {
- return sizeMode == YGMeasureModeExactly && YGFloatsEqual(size, lastComputedSize);
- }
- static inline bool YGMeasureModeOldSizeIsUnspecifiedAndStillFits(YGMeasureMode sizeMode,
- float size,
- YGMeasureMode lastSizeMode,
- float lastComputedSize) {
- return sizeMode == YGMeasureModeAtMost && lastSizeMode == YGMeasureModeUndefined &&
- (size >= lastComputedSize || YGFloatsEqual(size, lastComputedSize));
- }
- static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(YGMeasureMode sizeMode,
- float size,
- YGMeasureMode lastSizeMode,
- float lastSize,
- float lastComputedSize) {
- return lastSizeMode == YGMeasureModeAtMost &&
- sizeMode == YGMeasureModeAtMost && !YGFloatIsUndefined(lastSize) &&
- !YGFloatIsUndefined(size) && !YGFloatIsUndefined(lastComputedSize) &&
- lastSize > size &&
- (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
- }
- float YGRoundValueToPixelGrid(const float value,
- const float pointScaleFactor,
- const bool forceCeil,
- const bool forceFloor) {
- float scaledValue = value * pointScaleFactor;
- float fractial = fmodf(scaledValue, 1.0f);
- if (YGFloatsEqual(fractial, 0)) {
- // First we check if the value is already rounded
- scaledValue = scaledValue - fractial;
- } else if (YGFloatsEqual(fractial, 1.0f)) {
- scaledValue = scaledValue - fractial + 1.0f;
- } else if (forceCeil) {
- // Next we check if we need to use forced rounding
- scaledValue = scaledValue - fractial + 1.0f;
- } else if (forceFloor) {
- scaledValue = scaledValue - fractial;
- } else {
- // Finally we just round the value
- scaledValue = scaledValue - fractial +
- (!YGFloatIsUndefined(fractial) &&
- (fractial > 0.5f || YGFloatsEqual(fractial, 0.5f))
- ? 1.0f
- : 0.0f);
- }
- return (YGFloatIsUndefined(scaledValue) ||
- YGFloatIsUndefined(pointScaleFactor))
- ? YGUndefined
- : scaledValue / pointScaleFactor;
- }
- bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
- const float width,
- const YGMeasureMode heightMode,
- const float height,
- const YGMeasureMode lastWidthMode,
- const float lastWidth,
- const YGMeasureMode lastHeightMode,
- const float lastHeight,
- const float lastComputedWidth,
- const float lastComputedHeight,
- const float marginRow,
- const float marginColumn,
- const YGConfigRef config) {
- if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) ||
- (!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) {
- return false;
- }
- bool useRoundedComparison =
- config != nullptr && config->pointScaleFactor != 0;
- const float effectiveWidth =
- useRoundedComparison ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false)
- : width;
- const float effectiveHeight =
- useRoundedComparison ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false)
- : height;
- const float effectiveLastWidth =
- useRoundedComparison
- ? YGRoundValueToPixelGrid(lastWidth, config->pointScaleFactor, false, false)
- : lastWidth;
- const float effectiveLastHeight =
- useRoundedComparison
- ? YGRoundValueToPixelGrid(lastHeight, config->pointScaleFactor, false, false)
- : lastHeight;
- const bool hasSameWidthSpec =
- lastWidthMode == widthMode && YGFloatsEqual(effectiveLastWidth, effectiveWidth);
- const bool hasSameHeightSpec =
- lastHeightMode == heightMode && YGFloatsEqual(effectiveLastHeight, effectiveHeight);
- const bool widthIsCompatible =
- hasSameWidthSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(widthMode,
- width - marginRow,
- lastComputedWidth) ||
- YGMeasureModeOldSizeIsUnspecifiedAndStillFits(widthMode,
- width - marginRow,
- lastWidthMode,
- lastComputedWidth) ||
- YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
- widthMode, width - marginRow, lastWidthMode, lastWidth, lastComputedWidth);
- const bool heightIsCompatible =
- hasSameHeightSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(heightMode,
- height - marginColumn,
- lastComputedHeight) ||
- YGMeasureModeOldSizeIsUnspecifiedAndStillFits(heightMode,
- height - marginColumn,
- lastHeightMode,
- lastComputedHeight) ||
- YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
- heightMode, height - marginColumn, lastHeightMode, lastHeight, lastComputedHeight);
- return widthIsCompatible && heightIsCompatible;
- }
- //
- // This is a wrapper around the YGNodelayoutImpl function. It determines
- // whether the layout request is redundant and can be skipped.
- //
- // Parameters:
- // Input parameters are the same as YGNodelayoutImpl (see above)
- // Return parameter is true if layout was performed, false if skipped
- //
- bool YGLayoutNodeInternal(const YGNodeRef node,
- const float availableWidth,
- const float availableHeight,
- const YGDirection ownerDirection,
- const YGMeasureMode widthMeasureMode,
- const YGMeasureMode heightMeasureMode,
- const float ownerWidth,
- const float ownerHeight,
- const bool performLayout,
- const char *reason,
- const YGConfigRef config) {
- YGLayout* layout = &node->getLayout();
- gDepth++;
- const bool needToVisitNode =
- (node->isDirty() && layout->generationCount != gCurrentGenerationCount) ||
- layout->lastOwnerDirection != ownerDirection;
- if (needToVisitNode) {
- // Invalidate the cached results.
- layout->nextCachedMeasurementsIndex = 0;
- layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1;
- layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1;
- layout->cachedLayout.computedWidth = -1;
- layout->cachedLayout.computedHeight = -1;
- }
- YGCachedMeasurement* cachedResults = nullptr;
- // Determine whether the results are already cached. We maintain a separate
- // cache for layouts and measurements. A layout operation modifies the
- // positions
- // and dimensions for nodes in the subtree. The algorithm assumes that each
- // node
- // gets layed out a maximum of one time per tree layout, but multiple
- // measurements
- // may be required to resolve all of the flex dimensions.
- // We handle nodes with measure functions specially here because they are the
- // most
- // expensive to measure, so it's worth avoiding redundant measurements if at
- // all possible.
- if (node->getMeasure() != nullptr) {
- const float marginAxisRow = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- const float marginAxisColumn = YGUnwrapFloatOptional(
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
- // First, try to use the layout cache.
- if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
- availableWidth,
- heightMeasureMode,
- availableHeight,
- layout->cachedLayout.widthMeasureMode,
- layout->cachedLayout.availableWidth,
- layout->cachedLayout.heightMeasureMode,
- layout->cachedLayout.availableHeight,
- layout->cachedLayout.computedWidth,
- layout->cachedLayout.computedHeight,
- marginAxisRow,
- marginAxisColumn,
- config)) {
- cachedResults = &layout->cachedLayout;
- } else {
- // Try to use the measurement cache.
- for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
- if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
- availableWidth,
- heightMeasureMode,
- availableHeight,
- layout->cachedMeasurements[i].widthMeasureMode,
- layout->cachedMeasurements[i].availableWidth,
- layout->cachedMeasurements[i].heightMeasureMode,
- layout->cachedMeasurements[i].availableHeight,
- layout->cachedMeasurements[i].computedWidth,
- layout->cachedMeasurements[i].computedHeight,
- marginAxisRow,
- marginAxisColumn,
- config)) {
- cachedResults = &layout->cachedMeasurements[i];
- break;
- }
- }
- }
- } else if (performLayout) {
- if (YGFloatsEqual(layout->cachedLayout.availableWidth, availableWidth) &&
- YGFloatsEqual(layout->cachedLayout.availableHeight, availableHeight) &&
- layout->cachedLayout.widthMeasureMode == widthMeasureMode &&
- layout->cachedLayout.heightMeasureMode == heightMeasureMode) {
- cachedResults = &layout->cachedLayout;
- }
- } else {
- for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
- if (YGFloatsEqual(layout->cachedMeasurements[i].availableWidth, availableWidth) &&
- YGFloatsEqual(layout->cachedMeasurements[i].availableHeight, availableHeight) &&
- layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode &&
- layout->cachedMeasurements[i].heightMeasureMode == heightMeasureMode) {
- cachedResults = &layout->cachedMeasurements[i];
- break;
- }
- }
- }
- if (!needToVisitNode && cachedResults != nullptr) {
- layout->measuredDimensions[YGDimensionWidth] = cachedResults->computedWidth;
- layout->measuredDimensions[YGDimensionHeight] = cachedResults->computedHeight;
- if (gPrintChanges && gPrintSkips) {
- YGLog(node, YGLogLevelVerbose, "%s%d.{[skipped] ", YGSpacer(gDepth), gDepth);
- if (node->getPrintFunc() != nullptr) {
- node->getPrintFunc()(node);
- }
- YGLog(
- node,
- YGLogLevelVerbose,
- "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n",
- YGMeasureModeName(widthMeasureMode, performLayout),
- YGMeasureModeName(heightMeasureMode, performLayout),
- availableWidth,
- availableHeight,
- cachedResults->computedWidth,
- cachedResults->computedHeight,
- reason);
- }
- } else {
- if (gPrintChanges) {
- YGLog(
- node,
- YGLogLevelVerbose,
- "%s%d.{%s",
- YGSpacer(gDepth),
- gDepth,
- needToVisitNode ? "*" : "");
- if (node->getPrintFunc() != nullptr) {
- node->getPrintFunc()(node);
- }
- YGLog(
- node,
- YGLogLevelVerbose,
- "wm: %s, hm: %s, aw: %f ah: %f %s\n",
- YGMeasureModeName(widthMeasureMode, performLayout),
- YGMeasureModeName(heightMeasureMode, performLayout),
- availableWidth,
- availableHeight,
- reason);
- }
- YGNodelayoutImpl(node,
- availableWidth,
- availableHeight,
- ownerDirection,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight,
- performLayout,
- config);
- if (gPrintChanges) {
- YGLog(
- node,
- YGLogLevelVerbose,
- "%s%d.}%s",
- YGSpacer(gDepth),
- gDepth,
- needToVisitNode ? "*" : "");
- if (node->getPrintFunc() != nullptr) {
- node->getPrintFunc()(node);
- }
- YGLog(
- node,
- YGLogLevelVerbose,
- "wm: %s, hm: %s, d: (%f, %f) %s\n",
- YGMeasureModeName(widthMeasureMode, performLayout),
- YGMeasureModeName(heightMeasureMode, performLayout),
- layout->measuredDimensions[YGDimensionWidth],
- layout->measuredDimensions[YGDimensionHeight],
- reason);
- }
- layout->lastOwnerDirection = ownerDirection;
- if (cachedResults == nullptr) {
- if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) {
- if (gPrintChanges) {
- YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n");
- }
- layout->nextCachedMeasurementsIndex = 0;
- }
- YGCachedMeasurement *newCacheEntry;
- if (performLayout) {
- // Use the single layout cache entry.
- newCacheEntry = &layout->cachedLayout;
- } else {
- // Allocate a new measurement cache entry.
- newCacheEntry = &layout->cachedMeasurements[layout->nextCachedMeasurementsIndex];
- layout->nextCachedMeasurementsIndex++;
- }
- newCacheEntry->availableWidth = availableWidth;
- newCacheEntry->availableHeight = availableHeight;
- newCacheEntry->widthMeasureMode = widthMeasureMode;
- newCacheEntry->heightMeasureMode = heightMeasureMode;
- newCacheEntry->computedWidth = layout->measuredDimensions[YGDimensionWidth];
- newCacheEntry->computedHeight = layout->measuredDimensions[YGDimensionHeight];
- }
- }
- if (performLayout) {
- node->setLayoutDimension(
- node->getLayout().measuredDimensions[YGDimensionWidth],
- YGDimensionWidth);
- node->setLayoutDimension(
- node->getLayout().measuredDimensions[YGDimensionHeight],
- YGDimensionHeight);
- node->setHasNewLayout(true);
- node->setDirty(false);
- }
- gDepth--;
- layout->generationCount = gCurrentGenerationCount;
- return (needToVisitNode || cachedResults == nullptr);
- }
- void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint) {
- YGAssertWithConfig(config, pixelsInPoint >= 0.0f, "Scale factor should not be less than zero");
- // We store points for Pixel as we will use it for rounding
- if (pixelsInPoint == 0.0f) {
- // Zero is used to skip rounding
- config->pointScaleFactor = 0.0f;
- } else {
- config->pointScaleFactor = pixelsInPoint;
- }
- }
- static void YGRoundToPixelGrid(const YGNodeRef node,
- const float pointScaleFactor,
- const float absoluteLeft,
- const float absoluteTop) {
- if (pointScaleFactor == 0.0f) {
- return;
- }
- const float nodeLeft = node->getLayout().position[YGEdgeLeft];
- const float nodeTop = node->getLayout().position[YGEdgeTop];
- const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth];
- const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight];
- const float absoluteNodeLeft = absoluteLeft + nodeLeft;
- const float absoluteNodeTop = absoluteTop + nodeTop;
- const float absoluteNodeRight = absoluteNodeLeft + nodeWidth;
- const float absoluteNodeBottom = absoluteNodeTop + nodeHeight;
- // If a node has a custom measure function we never want to round down its size as this could
- // lead to unwanted text truncation.
- const bool textRounding = node->getNodeType() == YGNodeTypeText;
- node->setLayoutPosition(
- YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding),
- YGEdgeLeft);
- node->setLayoutPosition(
- YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
- YGEdgeTop);
- // We multiply dimension by scale factor and if the result is close to the whole number, we don't
- // have any fraction
- // To verify if the result is close to whole number we want to check both floor and ceil numbers
- const bool hasFractionalWidth = !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) &&
- !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0);
- const bool hasFractionalHeight = !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) &&
- !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0);
- node->setLayoutDimension(
- YGRoundValueToPixelGrid(
- absoluteNodeRight,
- pointScaleFactor,
- (textRounding && hasFractionalWidth),
- (textRounding && !hasFractionalWidth)) -
- YGRoundValueToPixelGrid(
- absoluteNodeLeft, pointScaleFactor, false, textRounding),
- YGDimensionWidth);
- node->setLayoutDimension(
- YGRoundValueToPixelGrid(
- absoluteNodeBottom,
- pointScaleFactor,
- (textRounding && hasFractionalHeight),
- (textRounding && !hasFractionalHeight)) -
- YGRoundValueToPixelGrid(
- absoluteNodeTop, pointScaleFactor, false, textRounding),
- YGDimensionHeight);
- const uint32_t childCount = YGNodeGetChildCount(node);
- for (uint32_t i = 0; i < childCount; i++) {
- YGRoundToPixelGrid(
- YGNodeGetChild(node, i),
- pointScaleFactor,
- absoluteNodeLeft,
- absoluteNodeTop);
- }
- }
- void YGNodeCalculateLayout(
- const YGNodeRef node,
- const float ownerWidth,
- const float ownerHeight,
- const YGDirection ownerDirection) {
- // Increment the generation count. This will force the recursive routine to
- // visit
- // all dirty nodes at least once. Subsequent visits will be skipped if the
- // input
- // parameters don't change.
- gCurrentGenerationCount++;
- node->resolveDimension();
- float width = YGUndefined;
- YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
- if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) {
- width = YGUnwrapFloatOptional(
- YGResolveValue(
- node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) +
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
- widthMeasureMode = YGMeasureModeExactly;
- } else if (!YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
- .isUndefined()) {
- width = YGUnwrapFloatOptional(YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth));
- widthMeasureMode = YGMeasureModeAtMost;
- } else {
- width = ownerWidth;
- widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- }
- float height = YGUndefined;
- YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
- if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) {
- height = YGUnwrapFloatOptional(
- YGResolveValue(
- node->getResolvedDimension(dim[YGFlexDirectionColumn]),
- ownerHeight) +
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
- heightMeasureMode = YGMeasureModeExactly;
- } else if (!YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight],
- ownerHeight)
- .isUndefined()) {
- height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight));
- heightMeasureMode = YGMeasureModeAtMost;
- } else {
- height = ownerHeight;
- heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- }
- if (YGLayoutNodeInternal(
- node,
- width,
- height,
- ownerDirection,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight,
- true,
- "initial",
- node->getConfig())) {
- node->setPosition(
- node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth);
- YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
- if (gPrintTree) {
- YGNodePrint(
- node,
- (YGPrintOptions)(
- YGPrintOptionsLayout | YGPrintOptionsChildren |
- YGPrintOptionsStyle));
- }
- }
- // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we
- // aren't sure whether client's of yoga have gotten rid off this flag or not.
- // So logging this in YGLayout would help to find out the call sites depending
- // on this flag. This check would be removed once we are sure no one is
- // dependent on this flag anymore. The flag
- // `shouldDiffLayoutWithoutLegacyStretchBehaviour` in YGConfig will help to
- // run experiments.
- if (node->getConfig()->shouldDiffLayoutWithoutLegacyStretchBehaviour &&
- node->didUseLegacyFlag()) {
- const YGNodeRef originalNode = YGNodeDeepClone(node);
- originalNode->resolveDimension();
- // Recursively mark nodes as dirty
- originalNode->markDirtyAndPropogateDownwards();
- gCurrentGenerationCount++;
- // Rerun the layout, and calculate the diff
- originalNode->setAndPropogateUseLegacyFlag(false);
- if (YGLayoutNodeInternal(
- originalNode,
- width,
- height,
- ownerDirection,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight,
- true,
- "initial",
- originalNode->getConfig())) {
- originalNode->setPosition(
- originalNode->getLayout().direction,
- ownerWidth,
- ownerHeight,
- ownerWidth);
- YGRoundToPixelGrid(
- originalNode,
- originalNode->getConfig()->pointScaleFactor,
- 0.0f,
- 0.0f);
- // Set whether the two layouts are different or not.
- node->setLayoutDoesLegacyFlagAffectsLayout(
- !originalNode->isLayoutTreeEqualToNode(*node));
- if (gPrintTree) {
- YGNodePrint(
- originalNode,
- (YGPrintOptions)(
- YGPrintOptionsLayout | YGPrintOptionsChildren |
- YGPrintOptionsStyle));
- }
- }
- YGConfigFreeRecursive(originalNode);
- YGNodeFreeRecursive(originalNode);
- }
- }
- void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
- if (logger != nullptr) {
- config->logger = logger;
- } else {
- #ifdef ANDROID
- config->logger = &YGAndroidLog;
- #else
- config->logger = &YGDefaultLog;
- #endif
- }
- }
- void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
- const YGConfigRef config,
- const bool shouldDiffLayout) {
- config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout;
- }
- static void YGVLog(const YGConfigRef config,
- const YGNodeRef node,
- YGLogLevel level,
- const char *format,
- va_list args) {
- const YGConfigRef logConfig = config != nullptr ? config : YGConfigGetDefault();
- logConfig->logger(logConfig, node, level, format, args);
- if (level == YGLogLevelFatal) {
- abort();
- }
- }
- void YGLogWithConfig(const YGConfigRef config, YGLogLevel level, const char *format, ...) {
- va_list args;
- va_start(args, format);
- YGVLog(config, nullptr, level, format, args);
- va_end(args);
- }
- void YGLog(const YGNodeRef node, YGLogLevel level, const char *format, ...) {
- va_list args;
- va_start(args, format);
- YGVLog(
- node == nullptr ? nullptr : node->getConfig(), node, level, format, args);
- va_end(args);
- }
- void YGAssert(const bool condition, const char *message) {
- if (!condition) {
- YGLog(nullptr, YGLogLevelFatal, "%s\n", message);
- }
- }
- void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message) {
- if (!condition) {
- YGLog(node, YGLogLevelFatal, "%s\n", message);
- }
- }
- void YGAssertWithConfig(const YGConfigRef config, const bool condition, const char *message) {
- if (!condition) {
- YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message);
- }
- }
- void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
- const YGExperimentalFeature feature,
- const bool enabled) {
- config->experimentalFeatures[feature] = enabled;
- }
- inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
- const YGExperimentalFeature feature) {
- return config->experimentalFeatures[feature];
- }
- void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
- config->useWebDefaults = enabled;
- }
- void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config,
- const bool useLegacyStretchBehaviour) {
- config->useLegacyStretchBehaviour = useLegacyStretchBehaviour;
- }
- bool YGConfigGetUseWebDefaults(const YGConfigRef config) {
- return config->useWebDefaults;
- }
- void YGConfigSetContext(const YGConfigRef config, void *context) {
- config->context = context;
- }
- void *YGConfigGetContext(const YGConfigRef config) {
- return config->context;
- }
- void YGConfigSetCloneNodeFunc(const YGConfigRef config, const YGCloneNodeFunc callback) {
- config->cloneNodeCallback = callback;
- }
- static void YGTraverseChildrenPreOrder(const YGVector& children, const std::function<void(YGNodeRef node)>& f) {
- for (YGNodeRef node : children) {
- f(node);
- YGTraverseChildrenPreOrder(node->getChildren(), f);
- }
- }
- void YGTraversePreOrder(YGNodeRef const node, std::function<void(YGNodeRef node)>&& f) {
- if (!node) {
- return;
- }
- f(node);
- YGTraverseChildrenPreOrder(node->getChildren(), f);
- }
|