1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285 |
- /**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * 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 "log.h"
- #include <float.h>
- #include <string.h>
- #include <algorithm>
- #include "Utils.h"
- #include "YGNode.h"
- #include "YGNodePrint.h"
- #include "Yoga-internal.h"
- #include "instrumentation.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) {
- return (a > b) ? a : b;
- }
- #endif
- #endif
- using namespace facebook::yoga;
- using detail::Log;
- namespace {
- size_t usedMeasureCacheEntries = YG_MAX_CACHED_RESULT_COUNT;
- }
- void YGSetUsedCachedEntries(size_t n) {
- usedMeasureCacheEntries =
- n == 0 || n > YG_MAX_CACHED_RESULT_COUNT ? YG_MAX_CACHED_RESULT_COUNT : n;
- }
- #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
- #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) {
- return facebook::yoga::isUndefined(value);
- }
- detail::CompactValue YGComputedEdgeValue(
- const YGStyle::Edges& edges,
- YGEdge edge,
- detail::CompactValue defaultValue) {
- if (!edges[edge].isUndefined()) {
- return edges[edge];
- }
- if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
- !edges[YGEdgeVertical].isUndefined()) {
- return edges[YGEdgeVertical];
- }
- if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart ||
- edge == YGEdgeEnd) &&
- !edges[YGEdgeHorizontal].isUndefined()) {
- return edges[YGEdgeHorizontal];
- }
- if (!edges[YGEdgeAll].isUndefined()) {
- return edges[YGEdgeAll];
- }
- if (edge == YGEdgeStart || edge == YGEdgeEnd) {
- return detail::CompactValue::ofUndefined();
- }
- return defaultValue;
- }
- void* YGNodeGetContext(YGNodeRef node) {
- return node->getContext();
- }
- void YGNodeSetContext(YGNodeRef node, void* context) {
- return node->setContext(context);
- }
- bool YGNodeHasMeasureFunc(YGNodeRef node) {
- return node->hasMeasureFunc();
- }
- void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
- node->setMeasureFunc(measureFunc);
- }
- bool YGNodeHasBaselineFunc(YGNodeRef node) {
- return node->hasBaselineFunc();
- }
- 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);
- }
- void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
- node->setPrintFunc(printFunc);
- }
- bool YGNodeGetHasNewLayout(YGNodeRef node) {
- return node->getHasNewLayout();
- }
- void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) {
- config->printTree = enabled;
- }
- 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 (auto* child : root->getChildren()) {
- YGConfigFreeRecursive(child);
- }
- }
- void YGNodeFreeRecursiveWithCleanupFunc(
- const YGNodeRef root,
- YGNodeCleanupFunc cleanup) {
- uint32_t skipped = 0;
- while (YGNodeGetChildCount(root) > skipped) {
- const YGNodeRef child = YGNodeGetChild(root, skipped);
- if (child->getOwner() != root) {
- // Don't free shared nodes that we don't own.
- skipped += 1;
- } else {
- YGNodeRemoveChild(root, child);
- YGNodeFreeRecursive(child);
- }
- }
- if (cleanup != nullptr) {
- cleanup(root);
- }
- YGNodeFree(root);
- }
- void YGNodeFreeRecursive(const YGNodeRef root) {
- return YGNodeFreeRecursiveWithCleanupFunc(root, nullptr);
- }
- void YGNodeReset(YGNodeRef node) {
- node->reset();
- }
- 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) {
- delete config;
- gConfigInstanceCount--;
- }
- void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) {
- memcpy(dest, src, sizeof(YGConfig));
- }
- void YGNodeSetIsReferenceBaseline(YGNodeRef node, bool isReferenceBaseline) {
- if (node->isReferenceBaseline() != isReferenceBaseline) {
- node->setIsReferenceBaseline(isReferenceBaseline);
- node->markDirtyAndPropogate();
- }
- }
- bool YGNodeIsReferenceBaseline(YGNodeRef node) {
- return node->isReferenceBaseline();
- }
- void YGNodeInsertChild(
- const YGNodeRef owner,
- const YGNodeRef child,
- const uint32_t index) {
- YGAssertWithNode(
- owner,
- child->getOwner() == nullptr,
- "Child already has a owner, it must be removed first.");
- YGAssertWithNode(
- owner,
- !owner->hasMeasureFunc(),
- "Cannot add child: Nodes with measure functions cannot have children.");
- owner->insertChild(child, index);
- child->setOwner(owner);
- owner->markDirtyAndPropogate();
- }
- void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) {
- if (YGNodeGetChildCount(owner) == 0) {
- // This is an empty set. Nothing to remove.
- return;
- }
- // Children may be shared between parents, which is indicated by not having an
- // owner. We only want to reset the child completely if it is owned
- // exclusively by one node.
- auto childOwner = excludedChild->getOwner();
- if (owner->removeChild(excludedChild)) {
- if (owner == childOwner) {
- excludedChild->setLayout({}); // layout is no longer valid
- excludedChild->setOwner(nullptr);
- }
- owner->markDirtyAndPropogate();
- }
- }
- 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->hasMeasureFunc(),
- "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.unwrap();
- }
- float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
- return node->getStyle().flexShrink.isUndefined()
- ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
- : kDefaultFlexShrink)
- : node->getStyle().flexShrink.unwrap();
- }
- namespace {
- struct Value {
- template <YGUnit U>
- static detail::CompactValue create(float value) {
- return detail::CompactValue::ofMaybe<U>(value);
- }
- };
- template <>
- inline detail::CompactValue Value::create<YGUnitUndefined>(float) {
- return detail::CompactValue::ofUndefined();
- }
- template <>
- inline detail::CompactValue Value::create<YGUnitAuto>(float) {
- return detail::CompactValue::ofAuto();
- }
- template <YGStyle::Dimensions YGStyle::*P>
- struct DimensionProp {
- template <YGDimension idx>
- static YGValue get(YGNodeRef node) {
- YGValue value = (node->getStyle().*P)[idx];
- if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) {
- value.value = YGUndefined;
- }
- return value;
- }
- template <YGDimension idx, YGUnit U>
- static void set(YGNodeRef node, float newValue) {
- auto value = Value::create<U>(newValue);
- if ((node->getStyle().*P)[idx] != value) {
- (node->getStyle().*P)[idx] = value;
- node->markDirtyAndPropogate();
- }
- }
- };
- } // namespace
- #define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
- type, name, paramName, instanceName) \
- void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
- auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(paramName); \
- if (node->getStyle().instanceName != value) { \
- node->getStyle().instanceName = value; \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Percent( \
- const YGNodeRef node, const type paramName) { \
- auto value = detail::CompactValue::ofMaybe<YGUnitPercent>(paramName); \
- if (node->getStyle().instanceName != value) { \
- node->getStyle().instanceName = value; \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \
- if (node->getStyle().instanceName != detail::CompactValue::ofAuto()) { \
- node->getStyle().instanceName = detail::CompactValue::ofAuto(); \
- node->markDirtyAndPropogate(); \
- } \
- }
- #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] != \
- detail::CompactValue::ofAuto()) { \
- node->getStyle().instanceName[edge] = detail::CompactValue::ofAuto(); \
- 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) { \
- auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(paramName); \
- if (node->getStyle().instanceName[edge] != value) { \
- node->getStyle().instanceName[edge] = value; \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- void YGNodeStyleSet##name##Percent( \
- const YGNodeRef node, const YGEdge edge, const float paramName) { \
- auto value = detail::CompactValue::ofMaybe<YGUnitPercent>(paramName); \
- if (node->getStyle().instanceName[edge] != value) { \
- node->getStyle().instanceName[edge] = value; \
- node->markDirtyAndPropogate(); \
- } \
- } \
- \
- 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 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]; \
- }
- #define YG_NODE_STYLE_SET(node, property, value) \
- if (node->getStyle().property != value) { \
- node->getStyle().property = value; \
- node->markDirtyAndPropogate(); \
- }
- void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) {
- YG_NODE_STYLE_SET(node, direction, value);
- }
- YGDirection YGNodeStyleGetDirection(const YGNodeRef node) {
- return node->getStyle().direction;
- }
- void YGNodeStyleSetFlexDirection(
- const YGNodeRef node,
- const YGFlexDirection flexDirection) {
- YG_NODE_STYLE_SET(node, flexDirection, flexDirection);
- }
- YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeRef node) {
- return node->getStyle().flexDirection;
- }
- void YGNodeStyleSetJustifyContent(
- const YGNodeRef node,
- const YGJustify justifyContent) {
- YG_NODE_STYLE_SET(node, justifyContent, justifyContent);
- }
- YGJustify YGNodeStyleGetJustifyContent(const YGNodeRef node) {
- return node->getStyle().justifyContent;
- }
- void YGNodeStyleSetAlignContent(
- const YGNodeRef node,
- const YGAlign alignContent) {
- YG_NODE_STYLE_SET(node, alignContent, alignContent);
- }
- YGAlign YGNodeStyleGetAlignContent(const YGNodeRef node) {
- return node->getStyle().alignContent;
- }
- void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) {
- YG_NODE_STYLE_SET(node, alignItems, alignItems);
- }
- YGAlign YGNodeStyleGetAlignItems(const YGNodeRef node) {
- return node->getStyle().alignItems;
- }
- void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) {
- YG_NODE_STYLE_SET(node, alignSelf, alignSelf);
- }
- YGAlign YGNodeStyleGetAlignSelf(const YGNodeRef node) {
- return node->getStyle().alignSelf;
- }
- void YGNodeStyleSetPositionType(
- const YGNodeRef node,
- const YGPositionType positionType) {
- YG_NODE_STYLE_SET(node, positionType, positionType);
- }
- YGPositionType YGNodeStyleGetPositionType(const YGNodeRef node) {
- return node->getStyle().positionType;
- }
- void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) {
- YG_NODE_STYLE_SET(node, flexWrap, flexWrap);
- }
- YGWrap YGNodeStyleGetFlexWrap(const YGNodeRef node) {
- return node->getStyle().flexWrap;
- }
- void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) {
- YG_NODE_STYLE_SET(node, overflow, overflow);
- }
- YGOverflow YGNodeStyleGetOverflow(const YGNodeRef node) {
- return node->getStyle().overflow;
- }
- void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) {
- YG_NODE_STYLE_SET(node, display, display);
- }
- YGDisplay YGNodeStyleGetDisplay(const YGNodeRef node) {
- return node->getStyle().display;
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
- if (node->getStyle().flex != flex) {
- node->getStyle().flex =
- YGFloatIsUndefined(flex) ? YGFloatOptional() : YGFloatOptional(flex);
- node->markDirtyAndPropogate();
- }
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- float YGNodeStyleGetFlex(const YGNodeRef node) {
- return node->getStyle().flex.isUndefined() ? YGUndefined
- : node->getStyle().flex.unwrap();
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
- if (node->getStyle().flexGrow != flexGrow) {
- node->getStyle().flexGrow = YGFloatIsUndefined(flexGrow)
- ? YGFloatOptional()
- : YGFloatOptional(flexGrow);
- node->markDirtyAndPropogate();
- }
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
- if (node->getStyle().flexShrink != flexShrink) {
- node->getStyle().flexShrink = YGFloatIsUndefined(flexShrink)
- ? YGFloatOptional()
- : YGFloatOptional(flexShrink);
- 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) {
- auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(flexBasis);
- if (node->getStyle().flexBasis != value) {
- node->getStyle().flexBasis = value;
- node->markDirtyAndPropogate();
- }
- }
- void YGNodeStyleSetFlexBasisPercent(
- const YGNodeRef node,
- const float flexBasisPercent) {
- auto value = detail::CompactValue::ofMaybe<YGUnitPercent>(flexBasisPercent);
- if (node->getStyle().flexBasis != value) {
- node->getStyle().flexBasis = value;
- node->markDirtyAndPropogate();
- }
- }
- void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
- if (node->getStyle().flexBasis != detail::CompactValue::ofAuto()) {
- node->getStyle().flexBasis = detail::CompactValue::ofAuto();
- 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) {
- auto value = detail::CompactValue::ofMaybe<YGUnitPoint>(border);
- if (node->getStyle().border[edge] != value) {
- node->getStyle().border[edge] = value;
- node->markDirtyAndPropogate();
- }
- }
- float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
- if (node->getStyle().border[edge].isUndefined() ||
- node->getStyle().border[edge].isAuto()) {
- // TODO(T26792433): Rather than returning YGUndefined, change the api to
- // return YGFloatOptional.
- return YGUndefined;
- }
- auto border = (YGValue) node->getStyle().border[edge];
- return border.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.unwrap();
- }
- // TODO(T26792433): Change the API to accept YGFloatOptional.
- void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
- if (node->getStyle().aspectRatio != aspectRatio) {
- node->getStyle().aspectRatio = YGFloatOptional(aspectRatio);
- 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]);
- void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) {
- DimensionProp<&YGStyle::minDimensions>::set<YGDimensionWidth, YGUnitPoint>(
- node, minWidth);
- }
- void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) {
- DimensionProp<&YGStyle::minDimensions>::set<YGDimensionWidth, YGUnitPercent>(
- node, minWidth);
- }
- YGValue YGNodeStyleGetMinWidth(const YGNodeRef node) {
- return DimensionProp<&YGStyle::minDimensions>::get<YGDimensionWidth>(node);
- };
- void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) {
- DimensionProp<&YGStyle::minDimensions>::set<YGDimensionHeight, YGUnitPoint>(
- node, minHeight);
- }
- void YGNodeStyleSetMinHeightPercent(
- const YGNodeRef node,
- const float minHeight) {
- DimensionProp<&YGStyle::minDimensions>::set<YGDimensionHeight, YGUnitPercent>(
- node, minHeight);
- }
- YGValue YGNodeStyleGetMinHeight(const YGNodeRef node) {
- return DimensionProp<&YGStyle::minDimensions>::get<YGDimensionHeight>(node);
- };
- void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) {
- DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionWidth, YGUnitPoint>(
- node, maxWidth);
- }
- void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) {
- DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionWidth, YGUnitPercent>(
- node, maxWidth);
- }
- YGValue YGNodeStyleGetMaxWidth(const YGNodeRef node) {
- return DimensionProp<&YGStyle::maxDimensions>::get<YGDimensionWidth>(node);
- };
- void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) {
- DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionHeight, YGUnitPoint>(
- node, maxHeight);
- }
- void YGNodeStyleSetMaxHeightPercent(
- const YGNodeRef node,
- const float maxHeight) {
- DimensionProp<&YGStyle::maxDimensions>::set<YGDimensionHeight, YGUnitPercent>(
- node, maxHeight);
- }
- YGValue YGNodeStyleGetMaxHeight(const YGNodeRef node) {
- return DimensionProp<&YGStyle::maxDimensions>::get<YGDimensionHeight>(node);
- };
- 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,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext);
- #ifdef DEBUG
- static void YGNodePrintInternal(
- const YGNodeRef node,
- const YGPrintOptions options) {
- std::string str;
- facebook::yoga::YGNodeToString(str, node, options, 0);
- Log::log(node, YGLogLevelDebug, nullptr, str.c_str());
- }
- void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {
- YGNodePrintInternal(node, options);
- }
- #endif
- 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 (node->getLeadingPaddingAndBorder(axis, widthSize) +
- node->getTrailingPaddingAndBorder(axis, widthSize))
- .unwrap();
- }
- 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, void* layoutContext) {
- if (node->hasBaselineFunc()) {
- const float baseline = marker::MarkerSection<YGMarkerBaselineFn>::wrap(
- node,
- &YGNode::baseline,
- node->getLayout().measuredDimensions[YGDimensionWidth],
- node->getLayout().measuredDimensions[YGDimensionHeight],
- layoutContext);
- 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 ||
- child->isReferenceBaseline()) {
- baselineChild = child;
- break;
- }
- if (baselineChild == nullptr) {
- baselineChild = child;
- }
- }
- if (baselineChild == nullptr) {
- return node->getLayout().measuredDimensions[YGDimensionHeight];
- }
- const float baseline = YGBaseline(baselineChild, layoutContext);
- 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]] +
- (node->getLeadingMargin(axis, widthSize) +
- node->getTrailingMargin(axis, widthSize))
- .unwrap();
- }
- 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 YGFloatOptional 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 >= YGFloatOptional{0} && value > max) {
- return max;
- }
- if (min >= YGFloatOptional{0} && value < min) {
- return min;
- }
- return 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(
- YGNodeBoundAxisWithinMinAndMax(
- node, axis, YGFloatOptional{value}, axisSize)
- .unwrap(),
- 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.unwrap())
- ? *size
- : maxSize.unwrap();
- break;
- case YGMeasureModeUndefined:
- if (!maxSize.isUndefined()) {
- *mode = YGMeasureModeAtMost;
- *size = maxSize.unwrap();
- }
- 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,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext) {
- 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;
- auto marginRow =
- child->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
- auto marginColumn =
- child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
- if (isRowStyleDimDefined) {
- childWidth =
- YGResolveValue(
- child->getResolvedDimension(YGDimensionWidth), ownerWidth)
- .unwrap() +
- marginRow;
- childWidthMeasureMode = YGMeasureModeExactly;
- }
- if (isColumnStyleDimDefined) {
- childHeight =
- YGResolveValue(
- child->getResolvedDimension(YGDimensionHeight), ownerHeight)
- .unwrap() +
- 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.unwrap();
- childHeightMeasureMode = YGMeasureModeExactly;
- } else if (
- isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
- childWidth = marginRow +
- (childHeight - marginColumn) *
- child->getStyle().aspectRatio.unwrap();
- 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.unwrap();
- 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.unwrap();
- 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,
- layoutMarkerData,
- layoutContext);
- 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,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext) {
- 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;
- auto marginRow = child->getMarginForAxis(YGFlexDirectionRow, width).unwrap();
- auto marginColumn =
- child->getMarginForAxis(YGFlexDirectionColumn, width).unwrap();
- if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
- childWidth =
- YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)
- .unwrap() +
- 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)) -
- (child->getLeadingPosition(YGFlexDirectionRow, width) +
- child->getTrailingPosition(YGFlexDirectionRow, width))
- .unwrap();
- childWidth =
- YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
- }
- }
- if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
- childHeight =
- YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)
- .unwrap() +
- 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)) -
- (child->getLeadingPosition(YGFlexDirectionColumn, height) +
- child->getTrailingPosition(YGFlexDirectionColumn, height))
- .unwrap();
- 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.unwrap();
- } else if (YGFloatIsUndefined(childHeight)) {
- childHeight = marginColumn +
- (childWidth - marginRow) / child->getStyle().aspectRatio.unwrap();
- }
- }
- }
- // 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,
- layoutMarkerData,
- layoutContext);
- childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] +
- child->getMarginForAxis(YGFlexDirectionRow, width).unwrap();
- childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] +
- child->getMarginForAxis(YGFlexDirectionColumn, width).unwrap();
- }
- YGLayoutNodeInternal(
- child,
- childWidth,
- childHeight,
- direction,
- YGMeasureModeExactly,
- YGMeasureModeExactly,
- childWidth,
- childHeight,
- true,
- "abs-layout",
- config,
- layoutMarkerData,
- layoutContext);
- if (child->isTrailingPosDefined(mainAxis) &&
- !child->isLeadingPositionDefined(mainAxis)) {
- child->setLayoutPosition(
- node->getLayout().measuredDimensions[dim[mainAxis]] -
- child->getLayout().measuredDimensions[dim[mainAxis]] -
- node->getTrailingBorder(mainAxis) -
- child->getTrailingMargin(mainAxis, width).unwrap() -
- child->getTrailingPosition(mainAxis, isMainAxisRow ? width : height)
- .unwrap(),
- 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) -
- child->getTrailingMargin(crossAxis, width).unwrap() -
- child
- ->getTrailingPosition(crossAxis, isMainAxisRow ? height : width)
- .unwrap(),
- 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,
- void* const layoutContext) {
- YGAssertWithNode(
- node,
- node->hasMeasureFunc(),
- "Expected node to have custom measure function");
- const float paddingAndBorderAxisRow =
- YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
- const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis(
- node, YGFlexDirectionColumn, availableWidth);
- const float marginAxisRow =
- node->getMarginForAxis(YGFlexDirectionRow, availableWidth).unwrap();
- const float marginAxisColumn =
- node->getMarginForAxis(YGFlexDirectionColumn, availableWidth).unwrap();
- // 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 = marker::MarkerSection<YGMarkerMeasure>::wrap(
- node,
- &YGNode::measure,
- innerWidth,
- widthMeasureMode,
- innerHeight,
- heightMeasureMode,
- layoutContext);
- 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 =
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
- const float marginAxisColumn =
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
- 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)) {
- auto marginAxisColumn =
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
- auto marginAxisRow =
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
- 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,
- void* layoutContext) {
- node->getLayout() = {};
- node->setLayoutDimension(0, 0);
- node->setLayoutDimension(0, 1);
- node->setHasNewLayout(true);
- node->iterChildrenAfterCloningIfNeeded(
- YGZeroOutLayoutRecursivly, layoutContext);
- }
- 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 = node->getMarginForAxis(direction, ownerDim).unwrap();
- 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.unwrap() - paddingAndBorder;
- const YGFloatOptional maxDimensionOptional =
- YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim);
- const float maxInnerDim = maxDimensionOptional.isUndefined()
- ? FLT_MAX
- : maxDimensionOptional.unwrap() - paddingAndBorder;
- availableInnerDim =
- YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
- }
- return availableInnerDim;
- }
- static float YGNodeComputeFlexBasisForChildren(
- const YGNodeRef node,
- const float availableInnerWidth,
- const float availableInnerHeight,
- YGMeasureMode widthMeasureMode,
- YGMeasureMode heightMeasureMode,
- YGDirection direction,
- YGFlexDirection mainAxis,
- const YGConfigRef config,
- bool performLayout,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext) {
- float totalOuterFlexBasis = 0.0f;
- 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, layoutContext);
- 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,
- layoutMarkerData,
- layoutContext);
- }
- totalOuterFlexBasis +=
- (child->getLayout().computedFlexBasis +
- child->getMarginForAxis(mainAxis, availableInnerWidth))
- .unwrap();
- }
- return totalOuterFlexBasis;
- }
- // 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->getChildren().size(); endOfLineIndex++) {
- const YGNodeRef child = node->getChild(endOfLineIndex);
- if (child->getStyle().display == YGDisplayNone ||
- child->getStyle().positionType == YGPositionTypeAbsolute) {
- continue;
- }
- child->setLineIndex(lineCount);
- const float childMarginMainAxis =
- child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap();
- const float flexBasisWithMinAndMaxConstraints =
- YGNodeBoundAxisWithinMinAndMax(
- child,
- mainAxis,
- child->getLayout().computedFlexBasis,
- mainAxisownerSize)
- .unwrap();
- // 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() *
- child->getLayout().computedFlexBasis.unwrap();
- }
- 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,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext) {
- 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 = YGNodeBoundAxisWithinMinAndMax(
- currentRelativeChild,
- mainAxis,
- currentRelativeChild->getLayout().computedFlexBasis,
- mainAxisownerSize)
- .unwrap();
- 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 =
- currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth)
- .unwrap();
- const float marginCross =
- currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth)
- .unwrap();
- float childCrossSize;
- float childMainSize = updatedMainSize + marginMain;
- YGMeasureMode childCrossMeasureMode;
- YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
- if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) {
- childCrossSize = isMainAxisRow ? (childMainSize - marginMain) /
- currentRelativeChild->getStyle().aspectRatio.unwrap()
- : (childMainSize - marginMain) *
- currentRelativeChild->getStyle().aspectRatio.unwrap();
- 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 =
- YGResolveValue(
- currentRelativeChild->getResolvedDimension(dim[crossAxis]),
- availableInnerCrossDim)
- .unwrap() +
- 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,
- layoutMarkerData,
- layoutContext);
- 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 =
- YGNodeBoundAxisWithinMinAndMax(
- currentRelativeChild,
- mainAxis,
- currentRelativeChild->getLayout().computedFlexBasis,
- mainAxisownerSize)
- .unwrap();
- 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
- // the first pass. 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/CSS-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,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext) {
- 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,
- layoutMarkerData,
- layoutContext);
- 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,
- void* const layoutContext) {
- const YGStyle& style = node->getStyle();
- const float leadingPaddingAndBorderMain =
- node->getLeadingPaddingAndBorder(mainAxis, ownerWidth).unwrap();
- const float trailingPaddingAndBorderMain =
- node->getTrailingPaddingAndBorder(mainAxis, ownerWidth).unwrap();
- // If we are using "at most" rules in the main axis, make sure that
- // remainingFreeSpace is 0 when min main dimension is not given
- if (measureModeMainDim == YGMeasureModeAtMost &&
- collectedFlexItemsValues.remainingFreeSpace > 0) {
- if (!style.minDimensions[dim[mainAxis]].isUndefined() &&
- !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
- .isUndefined()) {
- // This condition makes sure that if the size of main dimension(after
- // considering child nodes main dim, leading and trailing padding etc)
- // falls below min dimension, then the remainingFreeSpace is reassigned
- // considering the min dimension
- // `minAvailableMainDim` denotes minimum available space in which child
- // can be laid out, it will exclude space consumed by padding and border.
- const float minAvailableMainDim =
- YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
- .unwrap() -
- leadingPaddingAndBorderMain - trailingPaddingAndBorderMain;
- const float occupiedSpaceByChildNodes =
- availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace;
- collectedFlexItemsValues.remainingFreeSpace =
- YGFloatMax(0, minAvailableMainDim - occupiedSpaceByChildNodes);
- } 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;
- }
- }
- collectedFlexItemsValues.mainDim =
- leadingPaddingAndBorderMain + leadingMainDim;
- collectedFlexItemsValues.crossDim = 0;
- float maxAscentForCurrentLine = 0;
- float maxDescentForCurrentLine = 0;
- bool isNodeBaselineLayout = YGIsBaselineLayout(node);
- 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(
- child->getLeadingPosition(mainAxis, availableInnerMainDim)
- .unwrap() +
- node->getLeadingBorder(mainAxis) +
- child->getLeadingMargin(mainAxis, availableInnerWidth).unwrap(),
- 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 +
- child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap() +
- childLayout.computedFlexBasis.unwrap();
- 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);
- if (isNodeBaselineLayout) {
- // If the child is baseline aligned then the cross dimension is
- // calculated by adding maxAscent and maxDescent from the baseline.
- const float ascent = YGBaseline(child, layoutContext) +
- child
- ->getLeadingMargin(
- YGFlexDirectionColumn, availableInnerWidth)
- .unwrap();
- const float descent =
- child->getLayout().measuredDimensions[YGDimensionHeight] +
- child
- ->getMarginForAxis(
- YGFlexDirectionColumn, availableInnerWidth)
- .unwrap() -
- ascent;
- maxAscentForCurrentLine =
- YGFloatMax(maxAscentForCurrentLine, ascent);
- maxDescentForCurrentLine =
- YGFloatMax(maxDescentForCurrentLine, descent);
- } else {
- // The cross dimension is the max of the elements dimension since
- // there can only be one element in that cross dimension in the case
- // when the items are not baseline aligned
- 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 += trailingPaddingAndBorderMain;
- if (isNodeBaselineLayout) {
- collectedFlexItemsValues.crossDim =
- maxAscentForCurrentLine + maxDescentForCurrentLine;
- }
- }
- //
- // This is the main routine that implements a subset of the flexbox layout
- // algorithm described in the W3C CSS documentation:
- // https://www.w3.org/TR/CSS3-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/CSS3-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,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext) {
- 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");
- (performLayout ? layoutMarkerData.layouts : layoutMarkerData.measures) += 1;
- // 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(
- node->getLeadingMargin(flexRowDirection, ownerWidth).unwrap(),
- YGEdgeStart);
- node->setLayoutMargin(
- node->getTrailingMargin(flexRowDirection, ownerWidth).unwrap(),
- YGEdgeEnd);
- node->setLayoutMargin(
- node->getLeadingMargin(flexColumnDirection, ownerWidth).unwrap(),
- YGEdgeTop);
- node->setLayoutMargin(
- node->getTrailingMargin(flexColumnDirection, ownerWidth).unwrap(),
- 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(
- node->getLeadingPadding(flexRowDirection, ownerWidth).unwrap(),
- YGEdgeStart);
- node->setLayoutPadding(
- node->getTrailingPadding(flexRowDirection, ownerWidth).unwrap(),
- YGEdgeEnd);
- node->setLayoutPadding(
- node->getLeadingPadding(flexColumnDirection, ownerWidth).unwrap(),
- YGEdgeTop);
- node->setLayoutPadding(
- node->getTrailingPadding(flexColumnDirection, ownerWidth).unwrap(),
- YGEdgeBottom);
- if (node->hasMeasureFunc()) {
- YGNodeWithMeasureFuncSetMeasuredDimensions(
- node,
- availableWidth,
- availableHeight,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight,
- layoutContext);
- 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(layoutContext);
- // 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 =
- node->getLeadingPaddingAndBorder(crossAxis, ownerWidth).unwrap();
- 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 =
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
- const float marginAxisColumn =
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
- const float minInnerWidth =
- YGResolveValue(
- node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)
- .unwrap() -
- paddingAndBorderAxisRow;
- const float maxInnerWidth =
- YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
- .unwrap() -
- paddingAndBorderAxisRow;
- const float minInnerHeight =
- YGResolveValue(
- node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)
- .unwrap() -
- paddingAndBorderAxisColumn;
- const float maxInnerHeight =
- YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)
- .unwrap() -
- 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;
- // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
- float totalOuterFlexBasis = YGNodeComputeFlexBasisForChildren(
- node,
- availableInnerWidth,
- availableInnerHeight,
- widthMeasureMode,
- heightMeasureMode,
- direction,
- mainAxis,
- config,
- performLayout,
- layoutMarkerData,
- layoutContext);
- 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,
- layoutMarkerData,
- layoutContext);
- }
- 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,
- layoutContext);
- 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(
- child->getLeadingPosition(crossAxis, availableInnerCrossDim)
- .unwrap() +
- node->getLeadingBorder(crossAxis) +
- child->getLeadingMargin(crossAxis, availableInnerWidth)
- .unwrap(),
- 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) +
- child->getLeadingMargin(crossAxis, availableInnerWidth)
- .unwrap(),
- 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()
- ? child->getMarginForAxis(crossAxis, availableInnerWidth)
- .unwrap() +
- (isMainAxisRow ? childMainSize /
- child->getStyle().aspectRatio.unwrap()
- : childMainSize *
- child->getStyle().aspectRatio.unwrap())
- : collectedFlexItemsValues.crossDim;
- childMainSize +=
- child->getMarginForAxis(mainAxis, availableInnerWidth)
- .unwrap();
- 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;
- auto alignContent = node->getStyle().alignContent;
- auto crossAxisDoesNotGrow =
- alignContent != YGAlignStretch && isNodeFlexWrap;
- const YGMeasureMode childWidthMeasureMode =
- YGFloatIsUndefined(childWidth) ||
- (!isMainAxisRow && crossAxisDoesNotGrow)
- ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- const YGMeasureMode childHeightMeasureMode =
- YGFloatIsUndefined(childHeight) ||
- (isMainAxisRow && crossAxisDoesNotGrow)
- ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- YGLayoutNodeInternal(
- child,
- childWidth,
- childHeight,
- direction,
- childWidthMeasureMode,
- childHeightMeasureMode,
- availableInnerWidth,
- availableInnerHeight,
- true,
- "stretch",
- config,
- layoutMarkerData,
- layoutContext);
- }
- } 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
- // currentLead stores the size of the cross dim
- if (performLayout && (isNodeFlexWrap || YGIsBaselineLayout(node))) {
- float crossDimLead = 0;
- float currentLead = leadingPaddingAndBorderCross;
- if (!YGFloatIsUndefined(availableInnerCrossDim)) {
- const float remainingAlignContentDim =
- availableInnerCrossDim - totalLineCrossDim;
- 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]] +
- child->getMarginForAxis(crossAxis, availableInnerWidth)
- .unwrap());
- }
- if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
- const float ascent = YGBaseline(child, layoutContext) +
- child
- ->getLeadingMargin(
- YGFlexDirectionColumn, availableInnerWidth)
- .unwrap();
- const float descent =
- child->getLayout().measuredDimensions[YGDimensionHeight] +
- child
- ->getMarginForAxis(
- YGFlexDirectionColumn, availableInnerWidth)
- .unwrap() -
- 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 +
- child->getLeadingMargin(crossAxis, availableInnerWidth)
- .unwrap(),
- pos[crossAxis]);
- break;
- }
- case YGAlignFlexEnd: {
- child->setLayoutPosition(
- currentLead + lineHeight -
- child->getTrailingMargin(crossAxis, availableInnerWidth)
- .unwrap() -
- 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 +
- child->getLeadingMargin(crossAxis, availableInnerWidth)
- .unwrap(),
- 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] +
- child->getMarginForAxis(mainAxis, availableInnerWidth)
- .unwrap())
- : lineHeight;
- const float childHeight = !isMainAxisRow
- ? (child->getLayout()
- .measuredDimensions[YGDimensionHeight] +
- child->getMarginForAxis(crossAxis, availableInnerWidth)
- .unwrap())
- : 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,
- layoutMarkerData,
- layoutContext);
- }
- }
- break;
- }
- case YGAlignBaseline: {
- child->setLayoutPosition(
- currentLead + maxAscentForCurrentLine -
- YGBaseline(child, layoutContext) +
- child
- ->getLeadingPosition(
- YGFlexDirectionColumn, availableInnerCrossDim)
- .unwrap(),
- 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,
- YGNodeBoundAxisWithinMinAndMax(
- node,
- mainAxis,
- YGFloatOptional{maxLineMainDim},
- mainAxisownerSize)
- .unwrap()),
- 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,
- YGNodeBoundAxisWithinMinAndMax(
- node,
- crossAxis,
- YGFloatOptional{totalLineCrossDim +
- paddingAndBorderAxisCross},
- crossAxisownerSize)
- .unwrap()),
- 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,
- layoutMarkerData,
- layoutContext);
- }
- // 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 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) {
- constexpr auto N = enums::count<YGMeasureMode>();
- const char* kMeasureModeNames[N] = {"UNDEFINED", "EXACTLY", "AT_MOST"};
- const char* kLayoutModeNames[N] = {
- "LAY_UNDEFINED", "LAY_EXACTLY", "LAY_AT_MOST"};
- if (mode >= N) {
- 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;
- // We want to calculate `fractial` such that `floor(scaledValue) = scaledValue
- // - fractial`.
- float fractial = fmodf(scaledValue, 1.0f);
- if (fractial < 0) {
- // This branch is for handling negative numbers for `value`.
- //
- // Regarding `floor` and `ceil`. Note that for a number x, `floor(x) <= x <=
- // ceil(x)` even for negative numbers. Here are a couple of examples:
- // - x = 2.2: floor( 2.2) = 2, ceil( 2.2) = 3
- // - x = -2.2: floor(-2.2) = -3, ceil(-2.2) = -2
- //
- // Regarding `fmodf`. For fractional negative numbers, `fmodf` returns a
- // negative number. For example, `fmodf(-2.2) = -0.2`. However, we want
- // `fractial` to be the number such that subtracting it from `value` will
- // give us `floor(value)`. In the case of negative numbers, adding 1 to
- // `fmodf(value)` gives us this. Let's continue the example from above:
- // - fractial = fmodf(-2.2) = -0.2
- // - Add 1 to the fraction: fractial2 = fractial + 1 = -0.2 + 1 = 0.8
- // - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3
- ++fractial;
- }
- 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,
- YGMarkerLayoutData& layoutMarkerData,
- void* const layoutContext) {
- 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->hasMeasureFunc()) {
- const float marginAxisRow =
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
- const float marginAxisColumn =
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
- // 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;
- (performLayout ? layoutMarkerData.cachedLayouts
- : layoutMarkerData.cachedMeasures) += 1;
- if (gPrintChanges && gPrintSkips) {
- Log::log(
- node,
- YGLogLevelVerbose,
- nullptr,
- "%s%d.{[skipped] ",
- YGSpacer(gDepth),
- gDepth);
- node->print(layoutContext);
- Log::log(
- node,
- YGLogLevelVerbose,
- nullptr,
- "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) {
- Log::log(
- node,
- YGLogLevelVerbose,
- nullptr,
- "%s%d.{%s",
- YGSpacer(gDepth),
- gDepth,
- needToVisitNode ? "*" : "");
- node->print(layoutContext);
- Log::log(
- node,
- YGLogLevelVerbose,
- nullptr,
- "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,
- layoutMarkerData,
- layoutContext);
- if (gPrintChanges) {
- Log::log(
- node,
- YGLogLevelVerbose,
- nullptr,
- "%s%d.}%s",
- YGSpacer(gDepth),
- gDepth,
- needToVisitNode ? "*" : "");
- node->print(layoutContext);
- Log::log(
- node,
- YGLogLevelVerbose,
- nullptr,
- "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 + 1 >
- (uint32_t) layoutMarkerData.maxMeasureCache) {
- layoutMarkerData.maxMeasureCache =
- layout->nextCachedMeasurementsIndex + 1;
- }
- if (layout->nextCachedMeasurementsIndex == usedMeasureCacheEntries) {
- if (gPrintChanges) {
- Log::log(node, YGLogLevelVerbose, nullptr, "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 YGNodeCalculateLayoutWithContext(
- const YGNodeRef node,
- const float ownerWidth,
- const float ownerHeight,
- const YGDirection ownerDirection,
- void* layoutContext) {
- marker::MarkerSection<YGMarkerLayout> marker{node};
- // 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 =
- (YGResolveValue(
- node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) +
- node->getMarginForAxis(YGFlexDirectionRow, ownerWidth))
- .unwrap();
- widthMeasureMode = YGMeasureModeExactly;
- } else if (!YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
- .isUndefined()) {
- width = YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
- .unwrap();
- widthMeasureMode = YGMeasureModeAtMost;
- } else {
- width = ownerWidth;
- widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- }
- float height = YGUndefined;
- YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
- if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) {
- height = (YGResolveValue(
- node->getResolvedDimension(dim[YGFlexDirectionColumn]),
- ownerHeight) +
- node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth))
- .unwrap();
- heightMeasureMode = YGMeasureModeExactly;
- } else if (!YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight],
- ownerHeight)
- .isUndefined()) {
- height = YGResolveValue(
- node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)
- .unwrap();
- heightMeasureMode = YGMeasureModeAtMost;
- } else {
- height = ownerHeight;
- heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined
- : YGMeasureModeExactly;
- }
- if (YGLayoutNodeInternal(
- node,
- width,
- height,
- ownerDirection,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight,
- true,
- "initial",
- node->getConfig(),
- marker.data,
- layoutContext)) {
- node->setPosition(
- node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth);
- YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
- #ifdef DEBUG
- if (node->getConfig()->printTree) {
- YGNodePrint(
- node,
- (YGPrintOptions)(
- YGPrintOptionsLayout | YGPrintOptionsChildren |
- YGPrintOptionsStyle));
- }
- #endif
- }
- // 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);
- YGMarkerLayoutData layoutMarkerData;
- if (YGLayoutNodeInternal(
- originalNode,
- width,
- height,
- ownerDirection,
- widthMeasureMode,
- heightMeasureMode,
- ownerWidth,
- ownerHeight,
- true,
- "initial",
- originalNode->getConfig(),
- layoutMarkerData,
- layoutContext)) {
- 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.
- auto neededLegacyStretchBehaviour =
- !originalNode->isLayoutTreeEqualToNode(*node);
- node->setLayoutDoesLegacyFlagAffectsLayout(neededLegacyStretchBehaviour);
- #ifdef DEBUG
- if (originalNode->getConfig()->printTree) {
- YGNodePrint(
- originalNode,
- (YGPrintOptions)(
- YGPrintOptionsLayout | YGPrintOptionsChildren |
- YGPrintOptionsStyle));
- }
- #endif
- }
- YGConfigFreeRecursive(originalNode);
- YGNodeFreeRecursive(originalNode);
- }
- }
- void YGNodeCalculateLayout(
- const YGNodeRef node,
- const float ownerWidth,
- const float ownerHeight,
- const YGDirection ownerDirection) {
- YGNodeCalculateLayoutWithContext(
- node, ownerWidth, ownerHeight, ownerDirection, nullptr);
- }
- void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
- if (logger != nullptr) {
- config->setLogger(logger);
- } else {
- #ifdef ANDROID
- config->setLogger(&YGAndroidLog);
- #else
- config->setLogger(&YGDefaultLog);
- #endif
- }
- }
- void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
- const YGConfigRef config,
- const bool shouldDiffLayout) {
- config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout;
- }
- void YGAssert(const bool condition, const char* message) {
- if (!condition) {
- Log::log(YGNodeRef{nullptr}, YGLogLevelFatal, nullptr, "%s\n", message);
- }
- }
- void YGAssertWithNode(
- const YGNodeRef node,
- const bool condition,
- const char* message) {
- if (!condition) {
- Log::log(node, YGLogLevelFatal, nullptr, "%s\n", message);
- }
- }
- void YGAssertWithConfig(
- const YGConfigRef config,
- const bool condition,
- const char* message) {
- if (!condition) {
- Log::log(config, YGLogLevelFatal, nullptr, "%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->setCloneNodeCallback(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);
- }
|