├── .gitignore ├── LICENSE ├── Readme.md ├── docs └── screenshot.png ├── main.cpp ├── objects ├── flex │ ├── flexconfig.cpp │ ├── flexconfig.h │ ├── flexnode.cpp │ └── flexnode.h ├── flexbackend.cpp └── flexbackend.h ├── qml-flex.pro ├── qml.qrc ├── qml ├── Flex.qml ├── example.qml └── main.qml └── third_party └── yoga ├── CompactValue.h ├── Utils.cpp ├── Utils.h ├── YGConfig.cpp ├── YGConfig.h ├── YGEnums.cpp ├── YGEnums.h ├── YGFloatOptional.h ├── YGLayout.cpp ├── YGLayout.h ├── YGMacros.h ├── YGMarker.cpp ├── YGMarker.h ├── YGNode.cpp ├── YGNode.h ├── YGNodePrint.cpp ├── YGNodePrint.h ├── YGStyle.cpp ├── YGStyle.h ├── YGValue.cpp ├── YGValue.h ├── Yoga-internal.h ├── Yoga.cpp ├── Yoga.h ├── event ├── event.cpp └── event.h ├── instrumentation.h ├── log.cpp ├── log.h └── util ├── BUCK ├── SingleWriterValueList.cpp ├── SingleWriterValueList.h └── SingleWriterValueListTest.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Petr Tripolsky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # QML flex layout 2 | 3 | Qt quick layout system is real ugly. It would be much more convenient to use flexbox for positioning elements. This repository contains a set of qt quick bindings to the [Yoga](https://github.com/facebook/yoga) layout engine from React Native for rendering flexbox. 4 | 5 | ![Screenshot](docs/screenshot.png) 6 | 7 | ``` 8 | import QtQuick 2.5 9 | import QtQuick.Window 2.0 10 | 11 | Window { 12 | visible: true 13 | height: 400 14 | width: 675 15 | Rectangle { 16 | anchors.fill: parent 17 | color: "cyan" 18 | Flex { 19 | height: parent.height 20 | width: parent.width 21 | 22 | flexDirection: "row" 23 | flexWrap: "wrap" 24 | justifyContent: "spaceAround" 25 | alignItems: "center" 26 | alignSelf: "center" 27 | alignContent: "stretch" 28 | 29 | Rectangle { color: "green"; height: 150; width: 150 } 30 | Rectangle { color: "green"; height: 150; width: 150 } 31 | Rectangle { color: "green"; height: 150; width: 150 } 32 | Rectangle { color: "green"; height: 150; width: 150 } 33 | Rectangle { color: "green"; height: 150; width: 150 } 34 | Rectangle { color: "green"; height: 150; width: 150 } 35 | Rectangle { color: "green"; height: 150; width: 150 } 36 | } 37 | } 38 | } 39 | 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripolskypetr/qml-flexbox/677a1287df8c1a5d6c35f33705be251828daf901/docs/screenshot.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "objects/flexbackend.h" 6 | 7 | using namespace Quite::Objects; 8 | using namespace Quite::Objects::Flex; 9 | 10 | /*****************************************************************************/ 11 | 12 | int main(int argc, char *argv[]) { 13 | QGuiApplication app(argc, argv); 14 | 15 | qmlRegisterType( 16 | "com.tripolskypetr.quitejs", 17 | 1, 0, 18 | "FlexBackend" 19 | ); 20 | 21 | QQmlApplicationEngine engine; 22 | engine.load(QUrl( 23 | QStringLiteral("qrc:/qml/example.qml")) 24 | ); 25 | 26 | return app.exec(); 27 | } 28 | 29 | /*****************************************************************************/ 30 | -------------------------------------------------------------------------------- /objects/flex/flexconfig.cpp: -------------------------------------------------------------------------------- 1 | #include "flexconfig.h" 2 | 3 | namespace Quite { 4 | namespace Objects { 5 | namespace Flex { 6 | 7 | /*****************************************************************************/ 8 | 9 | FlexConfig::FlexConfig(QObject *parent) 10 | : QObject(parent) { 11 | qDebug() << "FlexConfig ctor"; 12 | config = YGConfigNew(); 13 | } 14 | 15 | /*---------------------------------------------------------------------------*/ 16 | 17 | FlexConfig::~FlexConfig() { 18 | qDebug() << "FlexConfig dtor"; 19 | YGConfigFree(config); 20 | } 21 | 22 | /*---------------------------------------------------------------------------*/ 23 | 24 | YGConfigRef FlexConfig::getConfig() const { 25 | return config; 26 | } 27 | 28 | /*****************************************************************************/ 29 | 30 | } // namespace Flex 31 | } // namespace Objects 32 | } // namespace Quite 33 | -------------------------------------------------------------------------------- /objects/flex/flexconfig.h: -------------------------------------------------------------------------------- 1 | #ifndef FLEXCONFIG_H 2 | #define FLEXCONFIG_H 3 | 4 | #include 5 | #include 6 | 7 | #include "third_party/yoga/Yoga.h" 8 | 9 | namespace Quite { 10 | namespace Objects { 11 | namespace Flex { 12 | 13 | /*****************************************************************************/ 14 | 15 | class FlexConfig : public QObject { 16 | Q_OBJECT 17 | private: 18 | YGConfigRef config; 19 | public: 20 | explicit FlexConfig(QObject* parent = nullptr); 21 | virtual ~FlexConfig(); 22 | YGConfigRef getConfig() const; 23 | }; 24 | 25 | /*****************************************************************************/ 26 | 27 | } // namespace Flex 28 | } // namespace Objects 29 | } // namespace Quite 30 | 31 | #endif // FLEXCONFIG_H 32 | -------------------------------------------------------------------------------- /objects/flex/flexnode.cpp: -------------------------------------------------------------------------------- 1 | #include "flexnode.h" 2 | 3 | namespace Quite { 4 | namespace Objects { 5 | namespace Flex { 6 | 7 | /*****************************************************************************/ 8 | 9 | FlexNode::FlexNode(FlexConfig* config, QObject* parent) 10 | : QObject(parent) { 11 | qDebug() << "FlexNode ctor"; 12 | node = YGNodeNewWithConfig(config->getConfig()); 13 | this->config = config; 14 | } 15 | 16 | /*---------------------------------------------------------------------------*/ 17 | 18 | FlexNode::~FlexNode() { 19 | qDebug() << "FlexNode dtor"; 20 | YGNodeFree(node); 21 | } 22 | 23 | /*---------------------------------------------------------------------------*/ 24 | 25 | YGNodeRef FlexNode::getNode() { 26 | return node; 27 | } 28 | 29 | /*---------------------------------------------------------------------------*/ 30 | 31 | void FlexNode::appendChildren(QVariant children) { 32 | QJSValue child = qvariant_cast(children); 33 | std::vector tmp; 34 | if (child.isUndefined()) { 35 | qCritical() << "FlexNode appendChildren child undefined"; 36 | } else if(!child.isArray()) { 37 | qCritical() << "FlexNode appendChildren child is not array"; 38 | } else { 39 | const int length = child.property("length").toInt(); 40 | for (int i = 0; i != length; i++) { 41 | FlexNode* node = nullptr; 42 | if(!tryCast(child.property(i), node)) { 43 | qCritical() << "FlexNode appendChildren child is not qobject"; 44 | return; 45 | } else { 46 | node->setParent(this); 47 | tmp.push_back(node->getNode()); 48 | } 49 | } 50 | YGNodeSetChildren(this->node,tmp); 51 | } 52 | } 53 | 54 | /*---------------------------------------------------------------------------*/ 55 | 56 | void FlexNode::setFlexGrow(int v) { 57 | YGNodeStyleSetFlexGrow(node, static_cast(v)); 58 | } 59 | 60 | /*---------------------------------------------------------------------------*/ 61 | 62 | int FlexNode::getFlexGrow() { 63 | return static_cast(YGNodeStyleGetFlexGrow(node)); 64 | } 65 | 66 | /*---------------------------------------------------------------------------*/ 67 | 68 | int FlexNode::getFlexShrink() { 69 | return static_cast(YGNodeStyleGetFlexShrink(node)); 70 | } 71 | 72 | /*---------------------------------------------------------------------------*/ 73 | 74 | void FlexNode::setFlexShrink(int v){ 75 | YGNodeStyleSetFlexShrink(node, static_cast(v)); 76 | } 77 | 78 | /*---------------------------------------------------------------------------*/ 79 | 80 | void FlexNode::setHeight(int points) { 81 | YGNodeStyleSetHeight(node, static_cast(points)); 82 | } 83 | 84 | /*---------------------------------------------------------------------------*/ 85 | 86 | int FlexNode::getHeight() { 87 | return static_cast(YGNodeStyleGetHeight(node).value); 88 | } 89 | 90 | /*---------------------------------------------------------------------------*/ 91 | 92 | void FlexNode::setMinHeight(int point) { 93 | YGNodeStyleSetMinHeight(node, static_cast(point)); 94 | } 95 | 96 | /*---------------------------------------------------------------------------*/ 97 | 98 | int FlexNode::getWidth() { 99 | return static_cast(YGNodeStyleGetWidth(node).value); 100 | } 101 | 102 | /*---------------------------------------------------------------------------*/ 103 | 104 | int FlexNode::getMinWidth() { 105 | return static_cast(YGNodeStyleGetMinWidth(node).value); 106 | } 107 | 108 | /*---------------------------------------------------------------------------*/ 109 | 110 | int FlexNode::getMinHeight() { 111 | return static_cast(YGNodeStyleGetMinHeight(node).value); 112 | } 113 | 114 | /*---------------------------------------------------------------------------*/ 115 | 116 | void FlexNode::setWidth(int points) { 117 | YGNodeStyleSetWidth(node, static_cast(points)); 118 | } 119 | 120 | /*---------------------------------------------------------------------------*/ 121 | 122 | void FlexNode::setMinWidth(int point) { 123 | YGNodeStyleSetMinWidth(node, static_cast(point)); 124 | } 125 | 126 | /*---------------------------------------------------------------------------*/ 127 | 128 | void FlexNode::setDisplayNone() { 129 | YGNodeStyleSetDisplay(node, YGDisplayNone); 130 | } 131 | 132 | /*---------------------------------------------------------------------------*/ 133 | 134 | void FlexNode::setDisplayFlex() { 135 | YGNodeStyleSetDisplay(node, YGDisplayFlex); 136 | } 137 | 138 | /*---------------------------------------------------------------------------*/ 139 | 140 | void FlexNode::setFlexDirectionRow() { 141 | YGNodeStyleSetFlexDirection(node, YGFlexDirectionRow); 142 | } 143 | 144 | /*---------------------------------------------------------------------------*/ 145 | 146 | void FlexNode::setFlexDirectionRowReverse() { 147 | YGNodeStyleSetFlexDirection(node, YGFlexDirectionRowReverse); 148 | } 149 | 150 | /*---------------------------------------------------------------------------*/ 151 | 152 | void FlexNode::setFlexDirectionColumn() { 153 | YGNodeStyleSetFlexDirection(node, YGFlexDirectionColumn); 154 | } 155 | 156 | /*---------------------------------------------------------------------------*/ 157 | 158 | void FlexNode::setFlexDirectionColumnReverse() { 159 | YGNodeStyleSetFlexDirection(node, YGFlexDirectionColumnReverse); 160 | } 161 | 162 | /*---------------------------------------------------------------------------*/ 163 | 164 | void FlexNode::setJustifyFlexStart() { 165 | YGNodeStyleSetJustifyContent(node, YGJustifyFlexStart); 166 | } 167 | 168 | /*---------------------------------------------------------------------------*/ 169 | 170 | void FlexNode::setJustifyCenter() { 171 | YGNodeStyleSetJustifyContent(node, YGJustifyCenter); 172 | } 173 | 174 | /*---------------------------------------------------------------------------*/ 175 | 176 | void FlexNode::setJustifyFlexEnd(){ 177 | YGNodeStyleSetJustifyContent(node, YGJustifyFlexEnd); 178 | } 179 | 180 | /*---------------------------------------------------------------------------*/ 181 | 182 | void FlexNode::setJustifySpaceBetween() { 183 | YGNodeStyleSetJustifyContent(node, YGJustifySpaceBetween); 184 | } 185 | 186 | /*---------------------------------------------------------------------------*/ 187 | 188 | void FlexNode::setAlignContentAuto() { 189 | YGNodeStyleSetAlignContent(node, YGAlignAuto); 190 | } 191 | 192 | /*---------------------------------------------------------------------------*/ 193 | 194 | void FlexNode::setAlignContentCenter() { 195 | YGNodeStyleSetAlignContent(node, YGAlignCenter); 196 | } 197 | 198 | /*---------------------------------------------------------------------------*/ 199 | 200 | void FlexNode::setAlignContentFlexEnd() { 201 | YGNodeStyleSetAlignContent(node, YGAlignFlexEnd); 202 | } 203 | 204 | /*---------------------------------------------------------------------------*/ 205 | 206 | void FlexNode::setAlignContentStretch() { 207 | YGNodeStyleSetAlignContent(node, YGAlignStretch); 208 | } 209 | 210 | /*---------------------------------------------------------------------------*/ 211 | 212 | void FlexNode::setAlignContentBaseline() { 213 | YGNodeStyleSetAlignContent(node, YGAlignBaseline); 214 | } 215 | 216 | /*---------------------------------------------------------------------------*/ 217 | 218 | void FlexNode::setAlignContentFlexStart() { 219 | YGNodeStyleSetAlignContent(node, YGAlignFlexStart); 220 | } 221 | 222 | /*---------------------------------------------------------------------------*/ 223 | 224 | void FlexNode::setAlignContentSpaceAround() { 225 | YGNodeStyleSetAlignContent(node, YGAlignSpaceAround); 226 | } 227 | 228 | /*---------------------------------------------------------------------------*/ 229 | 230 | void FlexNode::setAlignContentSpaceBetween() { 231 | YGNodeStyleSetAlignContent(node, YGAlignSpaceBetween); 232 | } 233 | 234 | /*---------------------------------------------------------------------------*/ 235 | 236 | void FlexNode::setAlignItemsAuto() { 237 | YGNodeStyleSetAlignItems(node, YGAlignAuto); 238 | } 239 | 240 | /*---------------------------------------------------------------------------*/ 241 | 242 | void FlexNode::setAlignItemsCenter() { 243 | YGNodeStyleSetAlignItems(node, YGAlignCenter); 244 | } 245 | 246 | /*---------------------------------------------------------------------------*/ 247 | 248 | void FlexNode::setAlignItemsFlexEnd() { 249 | YGNodeStyleSetAlignItems(node, YGAlignFlexEnd); 250 | } 251 | 252 | /*---------------------------------------------------------------------------*/ 253 | 254 | void FlexNode::setAlignItemsStretch() { 255 | YGNodeStyleSetAlignItems(node, YGAlignStretch); 256 | } 257 | 258 | /*---------------------------------------------------------------------------*/ 259 | 260 | void FlexNode::setAlignItemsBaseline() { 261 | YGNodeStyleSetAlignItems(node, YGAlignBaseline); 262 | } 263 | 264 | /*---------------------------------------------------------------------------*/ 265 | 266 | void FlexNode::setAlignItemsFlexStart() { 267 | YGNodeStyleSetAlignItems(node, YGAlignFlexStart); 268 | } 269 | 270 | /*---------------------------------------------------------------------------*/ 271 | 272 | void FlexNode::setAlignItemsSpaceAround() { 273 | YGNodeStyleSetAlignItems(node, YGAlignSpaceAround); 274 | } 275 | 276 | /*---------------------------------------------------------------------------*/ 277 | 278 | void FlexNode::setAlignItemsSpaceBetween() { 279 | YGNodeStyleSetAlignItems(node, YGAlignSpaceBetween); 280 | } 281 | 282 | /*---------------------------------------------------------------------------*/ 283 | 284 | void FlexNode::setAlignSelfAuto() { 285 | YGNodeStyleSetAlignSelf(node, YGAlignAuto); 286 | } 287 | 288 | /*---------------------------------------------------------------------------*/ 289 | 290 | void FlexNode::setAlignSelfCenter() { 291 | YGNodeStyleSetAlignSelf(node, YGAlignCenter); 292 | } 293 | 294 | /*---------------------------------------------------------------------------*/ 295 | 296 | void FlexNode::setAlignSelfFlexEnd() { 297 | YGNodeStyleSetAlignSelf(node, YGAlignFlexEnd); 298 | } 299 | 300 | /*---------------------------------------------------------------------------*/ 301 | 302 | void FlexNode::setAlignSelfStretch() { 303 | YGNodeStyleSetAlignSelf(node, YGAlignStretch); 304 | } 305 | 306 | /*---------------------------------------------------------------------------*/ 307 | 308 | void FlexNode::setAlignSelfBaseline() { 309 | YGNodeStyleSetAlignSelf(node, YGAlignBaseline); 310 | } 311 | 312 | /*---------------------------------------------------------------------------*/ 313 | 314 | void FlexNode::setAlignSelfFlexStart() { 315 | YGNodeStyleSetAlignSelf(node, YGAlignFlexStart); 316 | } 317 | 318 | /*---------------------------------------------------------------------------*/ 319 | 320 | void FlexNode::setAlignSelfSpaceAround(){ 321 | YGNodeStyleSetAlignSelf(node, YGAlignSpaceAround); 322 | } 323 | 324 | /*---------------------------------------------------------------------------*/ 325 | 326 | void FlexNode::setAlignSelfSpaceBetween() { 327 | YGNodeStyleSetAlignSelf(node, YGAlignSpaceBetween); 328 | } 329 | 330 | /*---------------------------------------------------------------------------*/ 331 | 332 | void FlexNode::setWrap() { 333 | YGNodeStyleSetFlexWrap(node, YGWrapWrap); 334 | } 335 | 336 | /*---------------------------------------------------------------------------*/ 337 | 338 | void FlexNode::setNoWrap() { 339 | YGNodeStyleSetFlexWrap(node, YGWrapNoWrap); 340 | } 341 | 342 | /*---------------------------------------------------------------------------*/ 343 | 344 | void FlexNode::setWrapReverser() { 345 | YGNodeStyleSetFlexWrap(node, YGWrapWrapReverse); 346 | } 347 | 348 | /*---------------------------------------------------------------------------*/ 349 | 350 | void FlexNode::setMarginTop(int point) { 351 | YGNodeStyleSetMargin(node, YGEdgeTop, static_cast(point)); 352 | } 353 | 354 | /*---------------------------------------------------------------------------*/ 355 | 356 | int FlexNode::getMarginTop() { 357 | return static_cast(YGNodeStyleGetMargin(node, YGEdgeTop).value); 358 | } 359 | 360 | /*---------------------------------------------------------------------------*/ 361 | 362 | void FlexNode::setMarginLeft(int point) { 363 | YGNodeStyleSetMargin(node, YGEdgeLeft, static_cast(point)); 364 | } 365 | 366 | /*---------------------------------------------------------------------------*/ 367 | 368 | int FlexNode::getMarginLeft() { 369 | return static_cast(YGNodeStyleGetMargin(node, YGEdgeLeft).value); 370 | } 371 | 372 | /*---------------------------------------------------------------------------*/ 373 | 374 | void FlexNode::setMarginRight(int point) { 375 | YGNodeStyleSetMargin(node, YGEdgeRight, static_cast(point)); 376 | } 377 | 378 | /*---------------------------------------------------------------------------*/ 379 | 380 | int FlexNode::getMarginRight() { 381 | return static_cast(YGNodeStyleGetMargin(node, YGEdgeRight).value); 382 | } 383 | 384 | /*---------------------------------------------------------------------------*/ 385 | 386 | void FlexNode::setMarginBottom(int point) { 387 | YGNodeStyleSetMargin(node, YGEdgeBottom, static_cast(point)); 388 | } 389 | 390 | /*---------------------------------------------------------------------------*/ 391 | 392 | int FlexNode::getPaddingTop() { 393 | return static_cast(YGNodeStyleGetPadding(node, YGEdgeTop).value); 394 | } 395 | 396 | /*---------------------------------------------------------------------------*/ 397 | 398 | int FlexNode::getMarginBottom() { 399 | return static_cast(YGNodeStyleGetMargin(node, YGEdgeBottom).value); 400 | } 401 | 402 | /*---------------------------------------------------------------------------*/ 403 | 404 | void FlexNode::setPaddingTop(int point) { 405 | YGNodeStyleSetPadding( 406 | node, 407 | YGEdgeTop, 408 | static_cast(point) 409 | ); 410 | } 411 | 412 | /*---------------------------------------------------------------------------*/ 413 | 414 | int FlexNode::getPaddingLeft() { 415 | return static_cast(YGNodeStyleGetPadding(node, YGEdgeLeft).value); 416 | } 417 | 418 | /*---------------------------------------------------------------------------*/ 419 | 420 | void FlexNode::setPaddingLeft(int point) { 421 | YGNodeStyleSetPadding( 422 | node, 423 | YGEdgeLeft, 424 | static_cast(point) 425 | ); 426 | } 427 | 428 | /*---------------------------------------------------------------------------*/ 429 | 430 | int FlexNode::getPaddingRight() { 431 | return static_cast(YGNodeStyleGetPadding(node, YGEdgeRight).value); 432 | } 433 | 434 | /*---------------------------------------------------------------------------*/ 435 | 436 | void FlexNode::setPaddingRight(int point) { 437 | YGNodeStyleSetPadding( 438 | node, 439 | YGEdgeRight, 440 | static_cast(point) 441 | ); 442 | } 443 | 444 | /*---------------------------------------------------------------------------*/ 445 | 446 | int FlexNode::getPaddingBottom() { 447 | return static_cast(YGNodeStyleGetPadding(node, YGEdgeBottom).value); 448 | } 449 | 450 | /*---------------------------------------------------------------------------*/ 451 | 452 | void FlexNode::setPaddingBottom(int point) { 453 | YGNodeStyleSetPadding( 454 | node, 455 | YGEdgeBottom, 456 | static_cast(point) 457 | ); 458 | } 459 | 460 | 461 | /*---------------------------------------------------------------------------*/ 462 | 463 | void FlexNode::calculateLayoutLtr(int width, int height) { 464 | YGNodeCalculateLayout( 465 | node, 466 | static_cast(width), 467 | static_cast(height), 468 | YGDirectionLTR 469 | ); 470 | } 471 | 472 | /*---------------------------------------------------------------------------*/ 473 | 474 | bool FlexNode::tryCast(QJSValue src, FlexNode*& dst) { 475 | if(!src.isQObject()) { 476 | return false; 477 | } else { 478 | dst = qobject_cast(src.toQObject()); 479 | return dst!=nullptr; 480 | } 481 | } 482 | 483 | /*---------------------------------------------------------------------------*/ 484 | 485 | void FlexNode::calculateLayoutRtl(int width, int height) { 486 | YGNodeCalculateLayout( 487 | node, 488 | static_cast(width), 489 | static_cast(height), 490 | YGDirectionRTL 491 | ); 492 | } 493 | 494 | /*---------------------------------------------------------------------------*/ 495 | 496 | int FlexNode::getLayoutHeight() { 497 | return static_cast(YGNodeLayoutGetHeight(node)); 498 | } 499 | 500 | /*---------------------------------------------------------------------------*/ 501 | 502 | int FlexNode::getLayoutWidth() { 503 | return static_cast(YGNodeLayoutGetWidth(node)); 504 | } 505 | 506 | /*---------------------------------------------------------------------------*/ 507 | 508 | int FlexNode::getLayoutTop() { 509 | return static_cast(YGNodeLayoutGetTop(node)); 510 | } 511 | 512 | /*---------------------------------------------------------------------------*/ 513 | 514 | int FlexNode::getLayoutLeft() { 515 | return static_cast(YGNodeLayoutGetLeft(node)); 516 | } 517 | 518 | /*---------------------------------------------------------------------------*/ 519 | 520 | int FlexNode::getLayoutRight() { 521 | return static_cast(YGNodeLayoutGetRight(node)); 522 | } 523 | 524 | /*---------------------------------------------------------------------------*/ 525 | 526 | int FlexNode::getLayoutBottom() { 527 | return static_cast(YGNodeLayoutGetBottom(node)); 528 | } 529 | 530 | /*---------------------------------------------------------------------------*/ 531 | 532 | void FlexNode::setJustifySpaceAround() { 533 | YGNodeStyleSetJustifyContent(node, YGJustifySpaceAround); 534 | } 535 | 536 | /*---------------------------------------------------------------------------*/ 537 | 538 | void FlexNode::setJustifySpaceEvenly() { 539 | YGNodeStyleSetJustifyContent(node, YGJustifySpaceEvenly); 540 | } 541 | 542 | /*****************************************************************************/ 543 | 544 | } // namespace Flex 545 | } // namespace Objects 546 | } // namespace Quite 547 | 548 | -------------------------------------------------------------------------------- /objects/flex/flexnode.h: -------------------------------------------------------------------------------- 1 | #ifndef FLEXNODE_H 2 | #define FLEXNODE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "objects/flex/flexconfig.h" 10 | #include "third_party/yoga/Yoga.h" 11 | 12 | namespace Quite { 13 | namespace Objects { 14 | namespace Flex { 15 | 16 | /*****************************************************************************/ 17 | 18 | class FlexNode : public QObject { 19 | Q_OBJECT 20 | 21 | Q_PROPERTY(int flexShrink READ getFlexShrink WRITE setFlexShrink) 22 | Q_PROPERTY(int flexGrow READ getFlexGrow WRITE setFlexGrow) 23 | 24 | Q_PROPERTY(int minHeight READ getHeight WRITE setHeight) 25 | Q_PROPERTY(int height READ getHeight WRITE setHeight) 26 | Q_PROPERTY(int minWidth READ getWidth WRITE setWidth) 27 | Q_PROPERTY(int width READ getWidth WRITE setWidth) 28 | 29 | Q_PROPERTY(int marginTop READ getMarginTop WRITE setMarginTop) 30 | Q_PROPERTY(int marginLeft READ getMarginLeft WRITE setMarginLeft) 31 | Q_PROPERTY(int marginRight READ getMarginRight WRITE setMarginRight) 32 | Q_PROPERTY(int marginBottom READ getMarginBottom WRITE setMarginBottom) 33 | 34 | Q_PROPERTY(int paddingTop READ getPaddingTop WRITE setPaddingTop) 35 | Q_PROPERTY(int paddingLeft READ getPaddingLeft WRITE setPaddingLeft) 36 | Q_PROPERTY(int paddingRight READ getPaddingRight WRITE setPaddingRight) 37 | Q_PROPERTY(int paddingBottom READ getPaddingBottom WRITE setPaddingBottom) 38 | 39 | Q_PROPERTY(int layoutTop READ getLayoutTop) 40 | Q_PROPERTY(int layoutLeft READ getLayoutLeft) 41 | Q_PROPERTY(int layoutRight READ getLayoutRight) 42 | Q_PROPERTY(int layoutBottom READ getLayoutBottom) 43 | 44 | private: 45 | YGNodeRef node; 46 | FlexConfig* config; 47 | public: 48 | FlexNode(FlexConfig* config, QObject* parent = nullptr); 49 | virtual ~FlexNode(); 50 | YGNodeRef getNode(); 51 | public slots: 52 | /* child */ 53 | Q_INVOKABLE void appendChildren(QVariant children); 54 | /* flex */ 55 | int getFlexGrow(); 56 | int getFlexShrink(); 57 | void setFlexGrow(int v); 58 | void setFlexShrink(int v); 59 | /* height */ 60 | int getHeight(); 61 | int getMinHeight(); 62 | void setHeight(int point); 63 | void setMinHeight(int point); 64 | /* width */ 65 | int getWidth(); 66 | int getMinWidth(); 67 | void setWidth(int point); 68 | void setMinWidth(int point); 69 | /* display */ 70 | Q_INVOKABLE void setDisplayNone(); 71 | Q_INVOKABLE void setDisplayFlex(); 72 | /* flex-direction */ 73 | Q_INVOKABLE void setFlexDirectionRow(); 74 | Q_INVOKABLE void setFlexDirectionColumn(); 75 | Q_INVOKABLE void setFlexDirectionRowReverse(); 76 | Q_INVOKABLE void setFlexDirectionColumnReverse(); 77 | /* justify-content */ 78 | Q_INVOKABLE void setJustifyCenter(); 79 | Q_INVOKABLE void setJustifyFlexEnd(); 80 | Q_INVOKABLE void setJustifyFlexStart(); 81 | Q_INVOKABLE void setJustifySpaceAround(); 82 | Q_INVOKABLE void setJustifySpaceEvenly(); 83 | Q_INVOKABLE void setJustifySpaceBetween(); 84 | /* align-content */ 85 | Q_INVOKABLE void setAlignContentAuto(); 86 | Q_INVOKABLE void setAlignContentCenter(); 87 | Q_INVOKABLE void setAlignContentFlexEnd(); 88 | Q_INVOKABLE void setAlignContentStretch(); 89 | Q_INVOKABLE void setAlignContentBaseline(); 90 | Q_INVOKABLE void setAlignContentFlexStart(); 91 | Q_INVOKABLE void setAlignContentSpaceAround(); 92 | Q_INVOKABLE void setAlignContentSpaceBetween(); 93 | /* align-items */ 94 | Q_INVOKABLE void setAlignItemsAuto(); 95 | Q_INVOKABLE void setAlignItemsCenter(); 96 | Q_INVOKABLE void setAlignItemsFlexEnd(); 97 | Q_INVOKABLE void setAlignItemsStretch(); 98 | Q_INVOKABLE void setAlignItemsBaseline(); 99 | Q_INVOKABLE void setAlignItemsFlexStart(); 100 | Q_INVOKABLE void setAlignItemsSpaceAround(); 101 | Q_INVOKABLE void setAlignItemsSpaceBetween(); 102 | /* align-self */ 103 | Q_INVOKABLE void setAlignSelfAuto(); 104 | Q_INVOKABLE void setAlignSelfCenter(); 105 | Q_INVOKABLE void setAlignSelfFlexEnd(); 106 | Q_INVOKABLE void setAlignSelfStretch(); 107 | Q_INVOKABLE void setAlignSelfBaseline(); 108 | Q_INVOKABLE void setAlignSelfFlexStart(); 109 | Q_INVOKABLE void setAlignSelfSpaceAround(); 110 | Q_INVOKABLE void setAlignSelfSpaceBetween(); 111 | /* flex-wrap */ 112 | Q_INVOKABLE void setWrap(); 113 | Q_INVOKABLE void setNoWrap(); 114 | Q_INVOKABLE void setWrapReverser(); 115 | /* margin */ 116 | int getMarginTop(); 117 | int getMarginLeft(); 118 | int getMarginRight(); 119 | int getMarginBottom(); 120 | void setMarginTop(int point); 121 | void setMarginLeft(int point); 122 | void setMarginRight(int point); 123 | void setMarginBottom(int point); 124 | /* padding */ 125 | int getPaddingTop(); 126 | int getPaddingLeft(); 127 | int getPaddingRight(); 128 | int getPaddingBottom(); 129 | void setPaddingTop(int point); 130 | void setPaddingLeft(int point); 131 | void setPaddingRight(int point); 132 | void setPaddingBottom(int point); 133 | /* calculate */ 134 | int getLayoutTop(); 135 | int getLayoutLeft(); 136 | int getLayoutRight(); 137 | int getLayoutWidth(); 138 | int getLayoutBottom(); 139 | int getLayoutHeight(); 140 | Q_INVOKABLE void calculateLayoutRtl(int width, int height); 141 | Q_INVOKABLE void calculateLayoutLtr(int width, int height); 142 | private: 143 | static bool tryCast(QJSValue src, FlexNode*& dst); 144 | }; 145 | 146 | /*****************************************************************************/ 147 | 148 | } // namespace Flex 149 | } // namespace Objects 150 | } // namespace Quite 151 | 152 | #endif // FLEXNODE_H 153 | -------------------------------------------------------------------------------- /objects/flexbackend.cpp: -------------------------------------------------------------------------------- 1 | #include "flexbackend.h" 2 | 3 | namespace Quite { 4 | namespace Objects { 5 | 6 | /*****************************************************************************/ 7 | 8 | FlexBackend::FlexBackend(QObject *parent) 9 | : QObject(parent) { 10 | qDebug() << "FlexBackend ctor"; 11 | config = new FlexConfig(this); 12 | } 13 | 14 | /*---------------------------------------------------------------------------*/ 15 | 16 | FlexBackend::~FlexBackend() { 17 | qDebug() << "FlexBackend dtor"; 18 | } 19 | 20 | /*---------------------------------------------------------------------------*/ 21 | 22 | QVariant FlexBackend::createNode(QVariant config) { 23 | FlexConfig* object = qvariant_cast(config); 24 | QVariant result; 25 | if (object==nullptr) { 26 | qCritical() << "FlexBackend createNode config not flexconfig*"; 27 | } else { 28 | result = QVariant::fromValue(new FlexNode(object, this)); 29 | } 30 | return result; 31 | } 32 | 33 | /*---------------------------------------------------------------------------*/ 34 | 35 | void FlexBackend::collectGarbage(QVariant rootNode) { 36 | FlexNode* node = qvariant_cast(rootNode); 37 | if (node==nullptr) { 38 | qCritical() << "FlexBackend collectGarbage node to FlexNode*"; 39 | } else { 40 | node->deleteLater(); 41 | } 42 | } 43 | 44 | /*---------------------------------------------------------------------------*/ 45 | 46 | QVariant FlexBackend::createConfig() { 47 | return QVariant::fromValue(new FlexConfig(this)); 48 | } 49 | 50 | /*---------------------------------------------------------------------------*/ 51 | 52 | QVariant FlexBackend::createNode() { 53 | return QVariant::fromValue(new FlexNode(config, this)); 54 | } 55 | 56 | /*****************************************************************************/ 57 | 58 | } // namespace Objects 59 | } // namespace Quite 60 | -------------------------------------------------------------------------------- /objects/flexbackend.h: -------------------------------------------------------------------------------- 1 | #ifndef FLEXBACKEND_H 2 | #define FLEXBACKEND_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "objects/flex/flexconfig.h" 10 | #include "objects/flex/flexnode.h" 11 | 12 | #include "third_party/yoga/Yoga.h" 13 | 14 | using namespace Quite::Objects::Flex; 15 | 16 | namespace Quite { 17 | namespace Objects { 18 | 19 | /*****************************************************************************/ 20 | 21 | class FlexBackend : public QObject { 22 | Q_OBJECT 23 | private: 24 | FlexConfig* config; 25 | public: 26 | explicit FlexBackend(QObject* parent = nullptr); 27 | virtual ~FlexBackend(); 28 | public slots: 29 | QVariant createConfig(); 30 | QVariant createNode(); 31 | QVariant createNode(QVariant config); 32 | void collectGarbage(QVariant rootNode); 33 | }; 34 | 35 | /*****************************************************************************/ 36 | 37 | } // namespace Objects 38 | } // namespace Quite 39 | 40 | #endif // FLEXBACKEND_H 41 | -------------------------------------------------------------------------------- /qml-flex.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += qml quick 4 | CONFIG += c++11 5 | 6 | SOURCES += main.cpp \ 7 | third_party/yoga/log.cpp \ 8 | third_party/yoga/Utils.cpp \ 9 | third_party/yoga/YGConfig.cpp \ 10 | third_party/yoga/YGEnums.cpp \ 11 | third_party/yoga/YGLayout.cpp \ 12 | third_party/yoga/YGMarker.cpp \ 13 | third_party/yoga/YGNode.cpp \ 14 | third_party/yoga/YGNodePrint.cpp \ 15 | third_party/yoga/YGStyle.cpp \ 16 | third_party/yoga/YGValue.cpp \ 17 | third_party/yoga/Yoga.cpp \ 18 | objects/flexbackend.cpp \ 19 | objects/flex/flexnode.cpp \ 20 | objects/flex/flexconfig.cpp 21 | 22 | RESOURCES += \ 23 | qml.qrc 24 | 25 | # Additional import path used to resolve QML modules in Qt Creator's code model 26 | QML_IMPORT_PATH = 27 | 28 | # Additional import path used to resolve QML modules just for Qt Quick Designer 29 | QML_DESIGNER_IMPORT_PATH = 30 | 31 | # The following define makes your compiler emit warnings if you use 32 | # any feature of Qt which as been marked deprecated (the exact warnings 33 | # depend on your compiler). Please consult the documentation of the 34 | # deprecated API in order to know how to port your code away from it. 35 | DEFINES += QT_DEPRECATED_WARNINGS 36 | 37 | # You can also make your code fail to compile if you use deprecated APIs. 38 | # In order to do so, uncomment the following line. 39 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 40 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 41 | 42 | # Default rules for deployment. 43 | qnx: target.path = /tmp/$${TARGET}/bin 44 | else: unix:!android: target.path = /opt/$${TARGET}/bin 45 | !isEmpty(target.path): INSTALLS += target 46 | 47 | HEADERS += \ 48 | third_party/yoga/CompactValue.h \ 49 | third_party/yoga/instrumentation.h \ 50 | third_party/yoga/log.h \ 51 | third_party/yoga/Utils.h \ 52 | third_party/yoga/YGConfig.h \ 53 | third_party/yoga/YGEnums.h \ 54 | third_party/yoga/YGFloatOptional.h \ 55 | third_party/yoga/YGLayout.h \ 56 | third_party/yoga/YGMacros.h \ 57 | third_party/yoga/YGMarker.h \ 58 | third_party/yoga/YGNode.h \ 59 | third_party/yoga/YGNodePrint.h \ 60 | third_party/yoga/YGStyle.h \ 61 | third_party/yoga/YGValue.h \ 62 | third_party/yoga/Yoga.h \ 63 | third_party/yoga/Yoga-internal.h \ 64 | objects/flexbackend.h \ 65 | objects/flex/flexnode.h \ 66 | objects/flex/flexconfig.h 67 | -------------------------------------------------------------------------------- /qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | qml/main.qml 4 | qml/Flex.qml 5 | qml/example.qml 6 | 7 | 8 | -------------------------------------------------------------------------------- /qml/Flex.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.10 2 | import QtQuick.Layouts 1.1 3 | import com.tripolskypetr.quitejs 1.0 4 | 5 | Item { 6 | id: flex 7 | 8 | property int minHeight: 0 9 | property int minWidth: 0 10 | 11 | property int flexShrink: 0 12 | property int flexGrow: 0 13 | 14 | property int marginTop: 0 15 | property int marginLeft: 0 16 | property int marginRight: 0 17 | property int marginBottom: 0 18 | 19 | property int paddingTop: 0 20 | property int paddingLeft: 0 21 | property int paddingRight: 0 22 | property int paddingBottom: 0 23 | 24 | property string alignContent: "auto" 25 | property string alignItems: "auto" 26 | property string alignSelf: "auto" 27 | 28 | property string justifyContent: "spaceBetween" 29 | 30 | property string display: "flex" 31 | 32 | property string flexWrap: "noWrap" 33 | 34 | property string flexDirection: "row" 35 | 36 | FlexBackend{ id: backend } 37 | 38 | function isFlex(child) { 39 | if (typeof child.flexShrink === 'undefined') { 40 | return false; 41 | } else if (typeof child.flexGrow === 'undefined') { 42 | return false; 43 | } else if (typeof child.minHeight === 'undefined') { 44 | return false; 45 | } else if (typeof child.minWidth === 'undefined') { 46 | return false; 47 | } else if (typeof child.marginTop === 'undefined') { 48 | return false; 49 | } else if (typeof child.marginLeft === 'undefined') { 50 | return false; 51 | } else if (typeof child.marginRight === 'undefined') { 52 | return false; 53 | } else if (typeof child.marginBottom === 'undefined') { 54 | return false; 55 | } else if (typeof child.paddingTop === 'undefined') { 56 | return false; 57 | } else if (typeof child.paddingLeft === 'undefined') { 58 | return false; 59 | } else if (typeof child.paddingRight === 'undefined') { 60 | return false; 61 | } else if (typeof child.paddingBottom === 'undefined') { 62 | return false; 63 | } else if (typeof child.alignContent === 'undefined') { 64 | return false; 65 | } else if (typeof child.alignItems === 'undefined') { 66 | return false; 67 | } else if (typeof child.alignSelf === 'undefined') { 68 | return false; 69 | } else if (typeof child.justifyContent === 'undefined') { 70 | return false; 71 | } else if (typeof child.display === 'undefined') { 72 | return false; 73 | } else if (typeof child.flexWrap === 'undefined') { 74 | return false; 75 | } else if (typeof child.flexDirection === 'undefined') { 76 | return false; 77 | } else { 78 | return true; 79 | } 80 | } 81 | 82 | function setAlignContent(child, node) { 83 | var align = child.alignContent; 84 | if (align === "auto") { 85 | node.setAlignContentAuto(); 86 | } else if (align === "flexStart") { 87 | node.setAlignContentFlexStart(); 88 | } else if (align === "center") { 89 | node.setAlignContentCenter(); 90 | } else if (align === "flexEnd") { 91 | node.setAlignContentFlexEnd(); 92 | } else if (align === "stretch") { 93 | node.setAlignContentStretch(); 94 | } else if (align === "baseline") { 95 | node.setAlignContentBaseline(); 96 | } else if (align === "spaceBetween") { 97 | node.setAlignContentSpaceBetween(); 98 | } else if (align === "spaceAround") { 99 | node.setAlignContentSpaceAround(); 100 | } else { 101 | throw "setAlignContent invalid param"; 102 | } 103 | } 104 | 105 | function setAlignItems(child, node) { 106 | var align = child.alignItems; 107 | if (align === "auto") { 108 | node.setAlignItemsAuto(); 109 | } else if (align === "flexStart") { 110 | node.setAlignItemsFlexStart(); 111 | } else if (align === "center") { 112 | node.setAlignItemsCenter(); 113 | } else if (align === "flexEnd") { 114 | node.setAlignItemsFlexEnd(); 115 | } else if (align === "stretch") { 116 | node.setAlignItemsStretch(); 117 | } else if (align === "baseline") { 118 | node.setAlignItemsBaseline(); 119 | } else if (align === "spaceBetween") { 120 | node.setAlignItemsSpaceBetween(); 121 | } else if (align === "spaceAround") { 122 | node.setAlignItemsSpaceAround(); 123 | } else { 124 | throw "setAlignItems invalid param"; 125 | } 126 | } 127 | 128 | function setAlignSelf(child, node) { 129 | var align = child.alignSelf; 130 | if (align === "auto") { 131 | node.setAlignSelfAuto(); 132 | } else if (align === "flexStart") { 133 | node.setAlignSelfFlexStart(); 134 | } else if (align === "center") { 135 | node.setAlignSelfCenter(); 136 | } else if (align === "flexEnd") { 137 | node.setAlignSelfFlexEnd(); 138 | } else if (align === "stretch") { 139 | node.setAlignSelfStretch(); 140 | } else if (align === "baseline") { 141 | node.setAlignSelfBaseline(); 142 | } else if (align === "spaceBetween") { 143 | node.setAlignSelfSpaceBetween(); 144 | } else if (align === "spaceAround") { 145 | node.setAlignSelfSpaceAround(); 146 | } else { 147 | throw "setAlignSelf invalid param"; 148 | } 149 | } 150 | 151 | function setDisplay(child, node) { 152 | var display = child.display; 153 | if (display==="flex") { 154 | node.setDisplayFlex(); 155 | } else if (display==="none") { 156 | node.setDisplayNone(); 157 | } else { 158 | throw "setDisplay invalid param"; 159 | } 160 | } 161 | 162 | function setJustifyContent(child, node) { 163 | var justify = child.justifyContent; 164 | if (justify==="center") { 165 | node.setJustifyCenter(); 166 | } else if (justify==="flexEnd") { 167 | node.setJustifyFlexEnd(); 168 | } else if (justify==="flexStart") { 169 | node.setJustifyFlexStart(); 170 | } else if (justify==="spaceAround") { 171 | node.setJustifySpaceAround(); 172 | } else if (justify==="spaceEvenly") { 173 | node.setJustifySpaceEvenly(); 174 | } else if (justify==="spaceBetween") { 175 | node.setJustifySpaceBetween(); 176 | } else { 177 | throw "setJustifyContent invalid param"; 178 | } 179 | } 180 | 181 | function setFlexWrap(child, node) { 182 | var wrap = child.flexWrap; 183 | if (wrap==="wrap") { 184 | node.setWrap(); 185 | } else if (wrap==="noWrap") { 186 | node.setNoWrap(); 187 | } else if (wrap==="wrapReverser") { 188 | node.setWrapReverser(); 189 | } else { 190 | throw "setFlexWrap invalid param"; 191 | } 192 | } 193 | 194 | function setFlexDirection(child, node) { 195 | var direction = child.flexDirection; 196 | if (direction==="row") { 197 | node.setFlexDirectionRow(); 198 | } else if (direction==="column") { 199 | node.setFlexDirectionColumn(); 200 | } else if (direction==="rowReverse") { 201 | node.setFlexDirectionRowReverse(); 202 | } else if (direction==="columnReverse") { 203 | node.setFlexDirectionColumnReverse(); 204 | } else { 205 | throw "setFlexDirection invalid param"; 206 | } 207 | } 208 | 209 | function setOtherNodeProps(child, node) { 210 | node.minHeight = child.minHeight; 211 | node.minWidth = child.minWidth; 212 | node.flexShrink = child.flexShrink; 213 | node.flexGrow = child.flexGrow; 214 | 215 | node.marginTop = child.marginTop; 216 | node.marginLeft = child.marginLeft; 217 | node.marginRight = child.marginRight; 218 | node.marginBottom = child.marginBottom; 219 | 220 | node.paddingTop = child.paddingTop; 221 | node.paddingLeft = child.paddingLeft; 222 | node.paddingRight = child.paddingRight; 223 | node.paddingBottom = child.paddingBottom; 224 | 225 | node.height = child.height; 226 | node.width = child.width; 227 | } 228 | 229 | function setDefaultNodeProps(child, node) { 230 | node.minHeight = 9999; 231 | node.minWidth = 0; 232 | node.flexShrink = 0; 233 | node.flexGrow = 0; 234 | 235 | node.marginTop = 0; 236 | node.marginLeft = 0; 237 | node.marginRight = 0; 238 | node.marginBottom = 0; 239 | 240 | node.paddingTop = 0; 241 | node.paddingLeft = 0; 242 | node.paddingRight = 0; 243 | node.paddingBottom = 0; 244 | 245 | node.height = child.height; 246 | node.width = child.width; 247 | 248 | node.setDisplayFlex(); 249 | 250 | node.setAlignSelfAuto(); 251 | node.setAlignItemsAuto(); 252 | node.setAlignContentAuto(); 253 | 254 | node.setJustifySpaceBetween(); 255 | node.setNoWrap(); 256 | 257 | node.setFlexDirectionRow(); 258 | } 259 | 260 | function processNode(child, node) { 261 | setOtherNodeProps(child, node, true); 262 | setJustifyContent(child, node); 263 | setFlexDirection(child, node); 264 | setAlignContent(child, node); 265 | setAlignItems(child, node); 266 | setAlignSelf(child, node); 267 | setFlexWrap(child, node); 268 | setDisplay(child, node); 269 | } 270 | 271 | function updatePositions() { 272 | if (flex.height!=0&&flex.width!=0) { 273 | var rootNode = backend.createNode(); 274 | processNode(flex, rootNode); 275 | var nodes = [] 276 | var node = {} 277 | var child = {} 278 | var i = 0; 279 | for (i=0;i!==flex.children.length;i++) { 280 | node = backend.createNode(); 281 | child = flex.children[i]; 282 | if (isFlex(child)) { 283 | processNode(child, node); 284 | } else { 285 | setDefaultNodeProps(child, node); 286 | } 287 | nodes.push(node); 288 | } 289 | rootNode.appendChildren(nodes); 290 | rootNode.calculateLayoutLtr(flex.width, flex.height); 291 | /* console.log(JSON.stringify({root: rootNode})); */ 292 | for (i=0;i!==flex.children.length;i++) { 293 | node = nodes[i]; 294 | flex.children[i].x = node.getLayoutLeft(); 295 | flex.children[i].y = node.getLayoutTop(); 296 | flex.children[i].width = node.getLayoutWidth(); 297 | flex.children[i].height = node.getLayoutHeight(); 298 | /* console.log(JSON.stringify(node)); */ 299 | } 300 | backend.collectGarbage(rootNode); 301 | return true; 302 | } else { 303 | return false; 304 | } 305 | } 306 | 307 | onChildrenChanged: updatePositions(); 308 | onWidthChanged: updatePositions(); 309 | onHeightChanged: updatePositions(); 310 | } 311 | -------------------------------------------------------------------------------- /qml/example.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | import QtQuick.Window 2.0 3 | 4 | Window { 5 | visible: true 6 | height: 400 7 | width: 675 8 | Rectangle { 9 | anchors.fill: parent 10 | color: "cyan" 11 | Flex { 12 | height: parent.height 13 | width: parent.width 14 | flexDirection: "row" 15 | flexWrap: "wrap" 16 | justifyContent: "spaceAround" 17 | alignItems: "center" 18 | alignSelf: "center" 19 | alignContent: "stretch" 20 | Rectangle { color: "green"; height: 150; width: 150 } 21 | Rectangle { color: "green"; height: 150; width: 150 } 22 | Rectangle { color: "green"; height: 150; width: 150 } 23 | Rectangle { color: "green"; height: 150; width: 150 } 24 | Rectangle { color: "green"; height: 150; width: 150 } 25 | Rectangle { color: "green"; height: 150; width: 150 } 26 | Rectangle { color: "green"; height: 150; width: 150 } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /qml/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | import QtQuick.Window 2.0 3 | 4 | Window { 5 | visible: true 6 | 7 | /* 8 | * Layout Wrapper. Do not delete if you are using 9 | * layout tools other than flexbox 10 | * anchors.fill, Layout.fillHeight, Layout.fillWidth... 11 | */ 12 | Item { 13 | anchors.fill: parent 14 | 15 | Flex { 16 | height: parent.height 17 | width: parent.width 18 | alignSelf: "center" 19 | justifyContent: "center" 20 | Text { height: 15; width: 15; text: "1" } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /third_party/yoga/CompactValue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include "YGValue.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | static_assert( 16 | std::numeric_limits::is_iec559, 17 | "facebook::yoga::detail::CompactValue only works with IEEE754 floats"); 18 | 19 | #ifdef YOGA_COMPACT_VALUE_TEST 20 | #define VISIBLE_FOR_TESTING public: 21 | #else 22 | #define VISIBLE_FOR_TESTING private: 23 | #endif 24 | 25 | namespace facebook { 26 | namespace yoga { 27 | namespace detail { 28 | 29 | // This class stores YGValue in 32 bits. 30 | // - The value does not matter for Undefined and Auto. NaNs are used for their 31 | // representation. 32 | // - To differentiate between Point and Percent, one exponent bit is used. 33 | // Supported the range [0x40, 0xbf] (0xbf is inclusive for point, but 34 | // exclusive for percent). 35 | // - Value ranges: 36 | // points: 1.08420217e-19f to 36893485948395847680 37 | // 0x00000000 0x3fffffff 38 | // percent: 1.08420217e-19f to 18446742974197923840 39 | // 0x40000000 0x7f7fffff 40 | // - Zero is supported, negative zero is not 41 | // - values outside of the representable range are clamped 42 | class CompactValue { 43 | friend constexpr bool operator==(CompactValue, CompactValue) noexcept; 44 | 45 | public: 46 | static constexpr auto LOWER_BOUND = 1.08420217e-19f; 47 | static constexpr auto UPPER_BOUND_POINT = 36893485948395847680.0f; 48 | static constexpr auto UPPER_BOUND_PERCENT = 18446742974197923840.0f; 49 | 50 | template 51 | static CompactValue of(float value) noexcept { 52 | if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) { 53 | constexpr auto zero = 54 | Unit == YGUnitPercent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT; 55 | return {Payload{zero}}; 56 | } 57 | 58 | constexpr auto upperBound = 59 | Unit == YGUnitPercent ? UPPER_BOUND_PERCENT : UPPER_BOUND_POINT; 60 | if (value > upperBound || value < -upperBound) { 61 | value = copysignf(upperBound, value); 62 | } 63 | 64 | uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0; 65 | auto data = Payload{value}; 66 | data.repr -= BIAS; 67 | data.repr |= unitBit; 68 | return {data}; 69 | } 70 | 71 | template 72 | static CompactValue ofMaybe(float value) noexcept { 73 | return std::isnan(value) || std::isinf(value) ? ofUndefined() 74 | : of(value); 75 | } 76 | 77 | static constexpr CompactValue ofZero() noexcept { 78 | return CompactValue{Payload{ZERO_BITS_POINT}}; 79 | } 80 | 81 | static constexpr CompactValue ofUndefined() noexcept { 82 | return CompactValue{}; 83 | } 84 | 85 | static constexpr CompactValue ofAuto() noexcept { 86 | return CompactValue{Payload{AUTO_BITS}}; 87 | } 88 | 89 | constexpr CompactValue() noexcept 90 | : payload_(std::numeric_limits::quiet_NaN()) {} 91 | 92 | CompactValue(const YGValue& x) noexcept : payload_(uint32_t{0}) { 93 | switch (x.unit) { 94 | case YGUnitUndefined: 95 | *this = ofUndefined(); 96 | break; 97 | case YGUnitAuto: 98 | *this = ofAuto(); 99 | break; 100 | case YGUnitPoint: 101 | *this = of(x.value); 102 | break; 103 | case YGUnitPercent: 104 | *this = of(x.value); 105 | break; 106 | } 107 | } 108 | 109 | operator YGValue() const noexcept { 110 | switch (payload_.repr) { 111 | case AUTO_BITS: 112 | return YGValueAuto; 113 | case ZERO_BITS_POINT: 114 | return YGValue{0.0f, YGUnitPoint}; 115 | case ZERO_BITS_PERCENT: 116 | return YGValue{0.0f, YGUnitPercent}; 117 | } 118 | 119 | if (std::isnan(payload_.value)) { 120 | return YGValueUndefined; 121 | } 122 | 123 | auto data = payload_; 124 | data.repr &= ~PERCENT_BIT; 125 | data.repr += BIAS; 126 | 127 | return YGValue{data.value, 128 | payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint}; 129 | } 130 | 131 | bool isUndefined() const noexcept { 132 | return ( 133 | payload_.repr != AUTO_BITS && payload_.repr != ZERO_BITS_POINT && 134 | payload_.repr != ZERO_BITS_PERCENT && std::isnan(payload_.value)); 135 | } 136 | 137 | bool isAuto() const noexcept { return payload_.repr == AUTO_BITS; } 138 | 139 | private: 140 | union Payload { 141 | float value; 142 | uint32_t repr; 143 | Payload() = delete; 144 | constexpr Payload(uint32_t r) : repr(r) {} 145 | constexpr Payload(float v) : value(v) {} 146 | }; 147 | 148 | static constexpr uint32_t BIAS = 0x20000000; 149 | static constexpr uint32_t PERCENT_BIT = 0x40000000; 150 | 151 | // these are signaling NaNs with specific bit pattern as payload they will be 152 | // silenced whenever going through an FPU operation on ARM + x86 153 | static constexpr uint32_t AUTO_BITS = 0x7faaaaaa; 154 | static constexpr uint32_t ZERO_BITS_POINT = 0x7f8f0f0f; 155 | static constexpr uint32_t ZERO_BITS_PERCENT = 0x7f80f0f0; 156 | 157 | constexpr CompactValue(Payload data) noexcept : payload_(data) {} 158 | 159 | Payload payload_; 160 | 161 | VISIBLE_FOR_TESTING uint32_t repr() { return payload_.repr; } 162 | }; 163 | 164 | template <> 165 | CompactValue CompactValue::of(float) noexcept = delete; 166 | template <> 167 | CompactValue CompactValue::of(float) noexcept = delete; 168 | template <> 169 | CompactValue CompactValue::ofMaybe(float) noexcept = delete; 170 | template <> 171 | CompactValue CompactValue::ofMaybe(float) noexcept = delete; 172 | 173 | constexpr bool operator==(CompactValue a, CompactValue b) noexcept { 174 | return a.payload_.repr == b.payload_.repr; 175 | } 176 | 177 | constexpr bool operator!=(CompactValue a, CompactValue b) noexcept { 178 | return !(a == b); 179 | } 180 | 181 | } // namespace detail 182 | } // namespace yoga 183 | } // namespace facebook 184 | -------------------------------------------------------------------------------- /third_party/yoga/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "Utils.h" 8 | 9 | using namespace facebook; 10 | 11 | YGFlexDirection YGFlexDirectionCross( 12 | const YGFlexDirection flexDirection, 13 | const YGDirection direction) { 14 | return YGFlexDirectionIsColumn(flexDirection) 15 | ? YGResolveFlexDirection(YGFlexDirectionRow, direction) 16 | : YGFlexDirectionColumn; 17 | } 18 | 19 | float YGFloatMax(const float a, const float b) { 20 | if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { 21 | return fmaxf(a, b); 22 | } 23 | return yoga::isUndefined(a) ? b : a; 24 | } 25 | 26 | float YGFloatMin(const float a, const float b) { 27 | if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { 28 | return fminf(a, b); 29 | } 30 | 31 | return yoga::isUndefined(a) ? b : a; 32 | } 33 | 34 | bool YGValueEqual(const YGValue& a, const YGValue& b) { 35 | if (a.unit != b.unit) { 36 | return false; 37 | } 38 | 39 | if (a.unit == YGUnitUndefined || 40 | (yoga::isUndefined(a.value) && yoga::isUndefined(b.value))) { 41 | return true; 42 | } 43 | 44 | return fabs(a.value - b.value) < 0.0001f; 45 | } 46 | 47 | bool YGFloatsEqual(const float a, const float b) { 48 | if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { 49 | return fabs(a - b) < 0.0001f; 50 | } 51 | return yoga::isUndefined(a) && yoga::isUndefined(b); 52 | } 53 | 54 | float YGFloatSanitize(const float val) { 55 | return yoga::isUndefined(val) ? 0 : val; 56 | } 57 | 58 | YGFloatOptional YGFloatOptionalMax(YGFloatOptional op1, YGFloatOptional op2) { 59 | if (op1 >= op2) { 60 | return op1; 61 | } 62 | if (op2 > op1) { 63 | return op2; 64 | } 65 | return op1.isUndefined() ? op2 : op1; 66 | } 67 | -------------------------------------------------------------------------------- /third_party/yoga/Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | #include "YGNode.h" 9 | #include "Yoga-internal.h" 10 | #include "CompactValue.h" 11 | 12 | // This struct is an helper model to hold the data for step 4 of flexbox algo, 13 | // which is collecting the flex items in a line. 14 | // 15 | // - itemsOnLine: Number of items which can fit in a line considering the 16 | // available Inner dimension, the flex items computed flexbasis and their 17 | // margin. It may be different than the difference between start and end 18 | // indicates because we skip over absolute-positioned items. 19 | // 20 | // - sizeConsumedOnCurrentLine: It is accumulation of the dimensions and margin 21 | // of all the children on the current line. This will be used in order to 22 | // either set the dimensions of the node if none already exist or to compute 23 | // the remaining space left for the flexible children. 24 | // 25 | // - totalFlexGrowFactors: total flex grow factors of flex items which are to be 26 | // layed in the current line 27 | // 28 | // - totalFlexShrinkFactors: total flex shrink factors of flex items which are 29 | // to be layed in the current line 30 | // 31 | // - endOfLineIndex: Its the end index of the last flex item which was examined 32 | // and it may or may not be part of the current line(as it may be absolutely 33 | // positioned or inculding it may have caused to overshoot availableInnerDim) 34 | // 35 | // - relativeChildren: Maintain a vector of the child nodes that can shrink 36 | // and/or grow. 37 | 38 | struct YGCollectFlexItemsRowValues { 39 | uint32_t itemsOnLine; 40 | float sizeConsumedOnCurrentLine; 41 | float totalFlexGrowFactors; 42 | float totalFlexShrinkScaledFactors; 43 | uint32_t endOfLineIndex; 44 | std::vector relativeChildren; 45 | float remainingFreeSpace; 46 | // The size of the mainDim for the row after considering size, padding, margin 47 | // and border of flex items. This is used to calculate maxLineDim after going 48 | // through all the rows to decide on the main axis size of owner. 49 | float mainDim; 50 | // The size of the crossDim for the row after considering size, padding, 51 | // margin and border of flex items. Used for calculating containers crossSize. 52 | float crossDim; 53 | }; 54 | 55 | bool YGValueEqual(const YGValue& a, const YGValue& b); 56 | inline bool YGValueEqual( 57 | facebook::yoga::detail::CompactValue a, 58 | facebook::yoga::detail::CompactValue b) { 59 | return YGValueEqual((YGValue) a, (YGValue) b); 60 | } 61 | 62 | // This custom float equality function returns true if either absolute 63 | // difference between two floats is less than 0.0001f or both are undefined. 64 | bool YGFloatsEqual(const float a, const float b); 65 | 66 | float YGFloatMax(const float a, const float b); 67 | 68 | YGFloatOptional YGFloatOptionalMax( 69 | const YGFloatOptional op1, 70 | const YGFloatOptional op2); 71 | 72 | float YGFloatMin(const float a, const float b); 73 | 74 | // This custom float comparision function compares the array of float with 75 | // YGFloatsEqual, as the default float comparision operator will not work(Look 76 | // at the comments of YGFloatsEqual function). 77 | template 78 | bool YGFloatArrayEqual( 79 | const std::array& val1, 80 | const std::array& val2) { 81 | bool areEqual = true; 82 | for (std::size_t i = 0; i < size && areEqual; ++i) { 83 | areEqual = YGFloatsEqual(val1[i], val2[i]); 84 | } 85 | return areEqual; 86 | } 87 | 88 | // This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise 89 | float YGFloatSanitize(const float val); 90 | 91 | YGFlexDirection YGFlexDirectionCross( 92 | const YGFlexDirection flexDirection, 93 | const YGDirection direction); 94 | 95 | inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) { 96 | return flexDirection == YGFlexDirectionRow || 97 | flexDirection == YGFlexDirectionRowReverse; 98 | } 99 | 100 | inline YGFloatOptional YGResolveValue( 101 | const YGValue value, 102 | const float ownerSize) { 103 | switch (value.unit) { 104 | case YGUnitPoint: 105 | return YGFloatOptional{value.value}; 106 | case YGUnitPercent: 107 | return YGFloatOptional{value.value * ownerSize * 0.01f}; 108 | default: 109 | return YGFloatOptional{}; 110 | } 111 | } 112 | 113 | inline YGFloatOptional YGResolveValue( 114 | yoga::detail::CompactValue value, 115 | float ownerSize) { 116 | return YGResolveValue((YGValue) value, ownerSize); 117 | } 118 | 119 | inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) { 120 | return flexDirection == YGFlexDirectionColumn || 121 | flexDirection == YGFlexDirectionColumnReverse; 122 | } 123 | 124 | inline YGFlexDirection YGResolveFlexDirection( 125 | const YGFlexDirection flexDirection, 126 | const YGDirection direction) { 127 | if (direction == YGDirectionRTL) { 128 | if (flexDirection == YGFlexDirectionRow) { 129 | return YGFlexDirectionRowReverse; 130 | } else if (flexDirection == YGFlexDirectionRowReverse) { 131 | return YGFlexDirectionRow; 132 | } 133 | } 134 | 135 | return flexDirection; 136 | } 137 | 138 | inline YGFloatOptional YGResolveValueMargin( 139 | yoga::detail::CompactValue value, 140 | const float ownerSize) { 141 | return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize); 142 | } 143 | -------------------------------------------------------------------------------- /third_party/yoga/YGConfig.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGConfig.h" 8 | 9 | YGConfig::YGConfig(YGLogger logger) : cloneNodeCallback_{nullptr} { 10 | logger_.noContext = logger; 11 | loggerUsesContext_ = false; 12 | } 13 | 14 | void YGConfig::log( 15 | YGConfig* config, 16 | YGNode* node, 17 | YGLogLevel logLevel, 18 | void* logContext, 19 | const char* format, 20 | va_list args) { 21 | if (loggerUsesContext_) { 22 | logger_.withContext(config, node, logLevel, logContext, format, args); 23 | } else { 24 | logger_.noContext(config, node, logLevel, format, args); 25 | } 26 | } 27 | 28 | YGNodeRef YGConfig::cloneNode( 29 | YGNodeRef node, 30 | YGNodeRef owner, 31 | int childIndex, 32 | void* cloneContext) { 33 | YGNodeRef clone = nullptr; 34 | if (cloneNodeCallback_.noContext != nullptr) { 35 | clone = cloneNodeUsesContext_ 36 | ? cloneNodeCallback_.withContext(node, owner, childIndex, cloneContext) 37 | : cloneNodeCallback_.noContext(node, owner, childIndex); 38 | } 39 | if (clone == nullptr) { 40 | clone = YGNodeClone(node); 41 | } 42 | return clone; 43 | } 44 | -------------------------------------------------------------------------------- /third_party/yoga/YGConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | #include "YGMarker.h" 9 | #include "Yoga-internal.h" 10 | #include "Yoga.h" 11 | 12 | struct YGConfig { 13 | using LogWithContextFn = int (*)( 14 | YGConfigRef config, 15 | YGNodeRef node, 16 | YGLogLevel level, 17 | void* context, 18 | const char* format, 19 | va_list args); 20 | using CloneWithContextFn = YGNodeRef (*)( 21 | YGNodeRef node, 22 | YGNodeRef owner, 23 | int childIndex, 24 | void* cloneContext); 25 | 26 | private: 27 | union { 28 | CloneWithContextFn withContext; 29 | YGCloneNodeFunc noContext; 30 | } cloneNodeCallback_; 31 | union { 32 | LogWithContextFn withContext; 33 | YGLogger noContext; 34 | } logger_; 35 | bool cloneNodeUsesContext_; 36 | bool loggerUsesContext_; 37 | 38 | public: 39 | bool useWebDefaults = false; 40 | bool useLegacyStretchBehaviour = false; 41 | bool shouldDiffLayoutWithoutLegacyStretchBehaviour = false; 42 | bool printTree = false; 43 | float pointScaleFactor = 1.0f; 44 | std::array()> 45 | experimentalFeatures = {}; 46 | void* context = nullptr; 47 | YGMarkerCallbacks markerCallbacks = {nullptr, nullptr}; 48 | 49 | YGConfig(YGLogger logger); 50 | void log(YGConfig*, YGNode*, YGLogLevel, void*, const char*, va_list); 51 | void setLogger(YGLogger logger) { 52 | logger_.noContext = logger; 53 | loggerUsesContext_ = false; 54 | } 55 | void setLogger(LogWithContextFn logger) { 56 | logger_.withContext = logger; 57 | loggerUsesContext_ = true; 58 | } 59 | void setLogger(std::nullptr_t) { setLogger(YGLogger{nullptr}); } 60 | 61 | YGNodeRef cloneNode( 62 | YGNodeRef node, 63 | YGNodeRef owner, 64 | int childIndex, 65 | void* cloneContext); 66 | void setCloneNodeCallback(YGCloneNodeFunc cloneNode) { 67 | cloneNodeCallback_.noContext = cloneNode; 68 | cloneNodeUsesContext_ = false; 69 | } 70 | void setCloneNodeCallback(CloneWithContextFn cloneNode) { 71 | cloneNodeCallback_.withContext = cloneNode; 72 | cloneNodeUsesContext_ = true; 73 | } 74 | void setCloneNodeCallback(std::nullptr_t) { 75 | setCloneNodeCallback(YGCloneNodeFunc{nullptr}); 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /third_party/yoga/YGEnums.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGEnums.h" 8 | 9 | const char* YGAlignToString(const YGAlign value) { 10 | switch (value) { 11 | case YGAlignAuto: 12 | return "auto"; 13 | case YGAlignFlexStart: 14 | return "flex-start"; 15 | case YGAlignCenter: 16 | return "center"; 17 | case YGAlignFlexEnd: 18 | return "flex-end"; 19 | case YGAlignStretch: 20 | return "stretch"; 21 | case YGAlignBaseline: 22 | return "baseline"; 23 | case YGAlignSpaceBetween: 24 | return "space-between"; 25 | case YGAlignSpaceAround: 26 | return "space-around"; 27 | } 28 | return "unknown"; 29 | } 30 | 31 | const char* YGDimensionToString(const YGDimension value) { 32 | switch (value) { 33 | case YGDimensionWidth: 34 | return "width"; 35 | case YGDimensionHeight: 36 | return "height"; 37 | } 38 | return "unknown"; 39 | } 40 | 41 | const char* YGDirectionToString(const YGDirection value) { 42 | switch (value) { 43 | case YGDirectionInherit: 44 | return "inherit"; 45 | case YGDirectionLTR: 46 | return "ltr"; 47 | case YGDirectionRTL: 48 | return "rtl"; 49 | } 50 | return "unknown"; 51 | } 52 | 53 | const char* YGDisplayToString(const YGDisplay value) { 54 | switch (value) { 55 | case YGDisplayFlex: 56 | return "flex"; 57 | case YGDisplayNone: 58 | return "none"; 59 | } 60 | return "unknown"; 61 | } 62 | 63 | const char* YGEdgeToString(const YGEdge value) { 64 | switch (value) { 65 | case YGEdgeLeft: 66 | return "left"; 67 | case YGEdgeTop: 68 | return "top"; 69 | case YGEdgeRight: 70 | return "right"; 71 | case YGEdgeBottom: 72 | return "bottom"; 73 | case YGEdgeStart: 74 | return "start"; 75 | case YGEdgeEnd: 76 | return "end"; 77 | case YGEdgeHorizontal: 78 | return "horizontal"; 79 | case YGEdgeVertical: 80 | return "vertical"; 81 | case YGEdgeAll: 82 | return "all"; 83 | } 84 | return "unknown"; 85 | } 86 | 87 | const char* YGExperimentalFeatureToString(const YGExperimentalFeature value) { 88 | switch (value) { 89 | case YGExperimentalFeatureWebFlexBasis: 90 | return "web-flex-basis"; 91 | } 92 | return "unknown"; 93 | } 94 | 95 | const char* YGFlexDirectionToString(const YGFlexDirection value) { 96 | switch (value) { 97 | case YGFlexDirectionColumn: 98 | return "column"; 99 | case YGFlexDirectionColumnReverse: 100 | return "column-reverse"; 101 | case YGFlexDirectionRow: 102 | return "row"; 103 | case YGFlexDirectionRowReverse: 104 | return "row-reverse"; 105 | } 106 | return "unknown"; 107 | } 108 | 109 | const char* YGJustifyToString(const YGJustify value) { 110 | switch (value) { 111 | case YGJustifyFlexStart: 112 | return "flex-start"; 113 | case YGJustifyCenter: 114 | return "center"; 115 | case YGJustifyFlexEnd: 116 | return "flex-end"; 117 | case YGJustifySpaceBetween: 118 | return "space-between"; 119 | case YGJustifySpaceAround: 120 | return "space-around"; 121 | case YGJustifySpaceEvenly: 122 | return "space-evenly"; 123 | } 124 | return "unknown"; 125 | } 126 | 127 | const char* YGLogLevelToString(const YGLogLevel value) { 128 | switch (value) { 129 | case YGLogLevelError: 130 | return "error"; 131 | case YGLogLevelWarn: 132 | return "warn"; 133 | case YGLogLevelInfo: 134 | return "info"; 135 | case YGLogLevelDebug: 136 | return "debug"; 137 | case YGLogLevelVerbose: 138 | return "verbose"; 139 | case YGLogLevelFatal: 140 | return "fatal"; 141 | } 142 | return "unknown"; 143 | } 144 | 145 | const char* YGMeasureModeToString(const YGMeasureMode value) { 146 | switch (value) { 147 | case YGMeasureModeUndefined: 148 | return "undefined"; 149 | case YGMeasureModeExactly: 150 | return "exactly"; 151 | case YGMeasureModeAtMost: 152 | return "at-most"; 153 | } 154 | return "unknown"; 155 | } 156 | 157 | const char* YGNodeTypeToString(const YGNodeType value) { 158 | switch (value) { 159 | case YGNodeTypeDefault: 160 | return "default"; 161 | case YGNodeTypeText: 162 | return "text"; 163 | } 164 | return "unknown"; 165 | } 166 | 167 | const char* YGOverflowToString(const YGOverflow value) { 168 | switch (value) { 169 | case YGOverflowVisible: 170 | return "visible"; 171 | case YGOverflowHidden: 172 | return "hidden"; 173 | case YGOverflowScroll: 174 | return "scroll"; 175 | } 176 | return "unknown"; 177 | } 178 | 179 | const char* YGPositionTypeToString(const YGPositionType value) { 180 | switch (value) { 181 | case YGPositionTypeRelative: 182 | return "relative"; 183 | case YGPositionTypeAbsolute: 184 | return "absolute"; 185 | } 186 | return "unknown"; 187 | } 188 | 189 | const char* YGPrintOptionsToString(const YGPrintOptions value) { 190 | switch (value) { 191 | case YGPrintOptionsLayout: 192 | return "layout"; 193 | case YGPrintOptionsStyle: 194 | return "style"; 195 | case YGPrintOptionsChildren: 196 | return "children"; 197 | } 198 | return "unknown"; 199 | } 200 | 201 | const char* YGUnitToString(const YGUnit value) { 202 | switch (value) { 203 | case YGUnitUndefined: 204 | return "undefined"; 205 | case YGUnitPoint: 206 | return "point"; 207 | case YGUnitPercent: 208 | return "percent"; 209 | case YGUnitAuto: 210 | return "auto"; 211 | } 212 | return "unknown"; 213 | } 214 | 215 | const char* YGWrapToString(const YGWrap value) { 216 | switch (value) { 217 | case YGWrapNoWrap: 218 | return "no-wrap"; 219 | case YGWrapWrap: 220 | return "wrap"; 221 | case YGWrapWrapReverse: 222 | return "wrap-reverse"; 223 | } 224 | return "unknown"; 225 | } 226 | -------------------------------------------------------------------------------- /third_party/yoga/YGEnums.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include "YGMacros.h" 10 | 11 | #ifdef __cplusplus 12 | namespace facebook { 13 | namespace yoga { 14 | namespace enums { 15 | 16 | template 17 | constexpr int count(); // can't use `= delete` due to a defect in clang < 3.9 18 | 19 | namespace detail { 20 | template 21 | constexpr int n() { 22 | return sizeof...(xs); 23 | } 24 | } // namespace detail 25 | 26 | } // namespace enums 27 | } // namespace yoga 28 | } // namespace facebook 29 | #endif 30 | 31 | #define YG_ENUM_DECL(NAME, ...) \ 32 | typedef YG_ENUM_BEGIN(NAME){__VA_ARGS__} YG_ENUM_END(NAME); \ 33 | WIN_EXPORT const char* NAME##ToString(NAME); 34 | 35 | #ifdef __cplusplus 36 | #define YG_ENUM_SEQ_DECL(NAME, ...) \ 37 | YG_ENUM_DECL(NAME, __VA_ARGS__) \ 38 | YG_EXTERN_C_END \ 39 | namespace facebook { \ 40 | namespace yoga { \ 41 | namespace enums { \ 42 | template <> \ 43 | constexpr int count() { \ 44 | return detail::n<__VA_ARGS__>(); \ 45 | } \ 46 | } \ 47 | } \ 48 | } \ 49 | YG_EXTERN_C_BEGIN 50 | #else 51 | #define YG_ENUM_SEQ_DECL YG_ENUM_DECL 52 | #endif 53 | 54 | YG_EXTERN_C_BEGIN 55 | 56 | YG_ENUM_SEQ_DECL( 57 | YGAlign, 58 | YGAlignAuto, 59 | YGAlignFlexStart, 60 | YGAlignCenter, 61 | YGAlignFlexEnd, 62 | YGAlignStretch, 63 | YGAlignBaseline, 64 | YGAlignSpaceBetween, 65 | YGAlignSpaceAround); 66 | 67 | YG_ENUM_SEQ_DECL(YGDimension, YGDimensionWidth, YGDimensionHeight) 68 | 69 | YG_ENUM_SEQ_DECL( 70 | YGDirection, 71 | YGDirectionInherit, 72 | YGDirectionLTR, 73 | YGDirectionRTL) 74 | 75 | YG_ENUM_SEQ_DECL(YGDisplay, YGDisplayFlex, YGDisplayNone) 76 | 77 | YG_ENUM_SEQ_DECL( 78 | YGEdge, 79 | YGEdgeLeft, 80 | YGEdgeTop, 81 | YGEdgeRight, 82 | YGEdgeBottom, 83 | YGEdgeStart, 84 | YGEdgeEnd, 85 | YGEdgeHorizontal, 86 | YGEdgeVertical, 87 | YGEdgeAll) 88 | 89 | YG_ENUM_SEQ_DECL(YGExperimentalFeature, YGExperimentalFeatureWebFlexBasis) 90 | 91 | YG_ENUM_SEQ_DECL( 92 | YGFlexDirection, 93 | YGFlexDirectionColumn, 94 | YGFlexDirectionColumnReverse, 95 | YGFlexDirectionRow, 96 | YGFlexDirectionRowReverse) 97 | 98 | YG_ENUM_SEQ_DECL( 99 | YGJustify, 100 | YGJustifyFlexStart, 101 | YGJustifyCenter, 102 | YGJustifyFlexEnd, 103 | YGJustifySpaceBetween, 104 | YGJustifySpaceAround, 105 | YGJustifySpaceEvenly) 106 | 107 | YG_ENUM_SEQ_DECL( 108 | YGLogLevel, 109 | YGLogLevelError, 110 | YGLogLevelWarn, 111 | YGLogLevelInfo, 112 | YGLogLevelDebug, 113 | YGLogLevelVerbose, 114 | YGLogLevelFatal) 115 | 116 | YG_ENUM_SEQ_DECL( 117 | YGMeasureMode, 118 | YGMeasureModeUndefined, 119 | YGMeasureModeExactly, 120 | YGMeasureModeAtMost) 121 | 122 | YG_ENUM_SEQ_DECL(YGNodeType, YGNodeTypeDefault, YGNodeTypeText) 123 | 124 | YG_ENUM_SEQ_DECL( 125 | YGOverflow, 126 | YGOverflowVisible, 127 | YGOverflowHidden, 128 | YGOverflowScroll) 129 | 130 | YG_ENUM_SEQ_DECL(YGPositionType, YGPositionTypeRelative, YGPositionTypeAbsolute) 131 | 132 | YG_ENUM_DECL( 133 | YGPrintOptions, 134 | YGPrintOptionsLayout = 1, 135 | YGPrintOptionsStyle = 2, 136 | YGPrintOptionsChildren = 4) 137 | 138 | YG_ENUM_SEQ_DECL( 139 | YGUnit, 140 | YGUnitUndefined, 141 | YGUnitPoint, 142 | YGUnitPercent, 143 | YGUnitAuto) 144 | 145 | YG_ENUM_SEQ_DECL(YGWrap, YGWrapNoWrap, YGWrapWrap, YGWrapWrapReverse) 146 | 147 | YG_EXTERN_C_END 148 | 149 | #undef YG_ENUM_DECL 150 | #undef YG_ENUM_SEQ_DECL 151 | -------------------------------------------------------------------------------- /third_party/yoga/YGFloatOptional.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include "Yoga-internal.h" 12 | 13 | struct YGFloatOptional { 14 | private: 15 | float value_ = std::numeric_limits::quiet_NaN(); 16 | 17 | public: 18 | explicit constexpr YGFloatOptional(float value) : value_(value) {} 19 | constexpr YGFloatOptional() = default; 20 | 21 | // returns the wrapped value, or a value x with YGIsUndefined(x) == true 22 | constexpr float unwrap() const { return value_; } 23 | 24 | bool isUndefined() const { return std::isnan(value_); } 25 | }; 26 | 27 | // operators take YGFloatOptional by value, as it is a 32bit value 28 | 29 | inline bool operator==(YGFloatOptional lhs, YGFloatOptional rhs) { 30 | return lhs.unwrap() == rhs.unwrap() || 31 | (lhs.isUndefined() && rhs.isUndefined()); 32 | } 33 | inline bool operator!=(YGFloatOptional lhs, YGFloatOptional rhs) { 34 | return !(lhs == rhs); 35 | } 36 | 37 | inline bool operator==(YGFloatOptional lhs, float rhs) { 38 | return lhs == YGFloatOptional{rhs}; 39 | } 40 | inline bool operator!=(YGFloatOptional lhs, float rhs) { 41 | return !(lhs == rhs); 42 | } 43 | 44 | inline bool operator==(float lhs, YGFloatOptional rhs) { 45 | return rhs == lhs; 46 | } 47 | inline bool operator!=(float lhs, YGFloatOptional rhs) { 48 | return !(lhs == rhs); 49 | } 50 | 51 | inline YGFloatOptional operator+(YGFloatOptional lhs, YGFloatOptional rhs) { 52 | return YGFloatOptional{lhs.unwrap() + rhs.unwrap()}; 53 | } 54 | 55 | inline bool operator>(YGFloatOptional lhs, YGFloatOptional rhs) { 56 | return lhs.unwrap() > rhs.unwrap(); 57 | } 58 | 59 | inline bool operator<(YGFloatOptional lhs, YGFloatOptional rhs) { 60 | return lhs.unwrap() < rhs.unwrap(); 61 | } 62 | 63 | inline bool operator>=(YGFloatOptional lhs, YGFloatOptional rhs) { 64 | return lhs > rhs || lhs == rhs; 65 | } 66 | 67 | inline bool operator<=(YGFloatOptional lhs, YGFloatOptional rhs) { 68 | return lhs < rhs || lhs == rhs; 69 | } 70 | -------------------------------------------------------------------------------- /third_party/yoga/YGLayout.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGLayout.h" 8 | #include "Utils.h" 9 | 10 | using namespace facebook; 11 | 12 | bool YGLayout::operator==(YGLayout layout) const { 13 | bool isEqual = YGFloatArrayEqual(position, layout.position) && 14 | YGFloatArrayEqual(dimensions, layout.dimensions) && 15 | YGFloatArrayEqual(margin, layout.margin) && 16 | YGFloatArrayEqual(border, layout.border) && 17 | YGFloatArrayEqual(padding, layout.padding) && 18 | direction == layout.direction && hadOverflow == layout.hadOverflow && 19 | lastOwnerDirection == layout.lastOwnerDirection && 20 | nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex && 21 | cachedLayout == layout.cachedLayout && 22 | computedFlexBasis == layout.computedFlexBasis; 23 | 24 | for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) { 25 | isEqual = isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i]; 26 | } 27 | 28 | if (!yoga::isUndefined(measuredDimensions[0]) || 29 | !yoga::isUndefined(layout.measuredDimensions[0])) { 30 | isEqual = 31 | isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]); 32 | } 33 | if (!yoga::isUndefined(measuredDimensions[1]) || 34 | !yoga::isUndefined(layout.measuredDimensions[1])) { 35 | isEqual = 36 | isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]); 37 | } 38 | 39 | return isEqual; 40 | } 41 | -------------------------------------------------------------------------------- /third_party/yoga/YGLayout.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | #include "YGFloatOptional.h" 9 | #include "Yoga-internal.h" 10 | 11 | struct YGLayout { 12 | std::array position = {}; 13 | std::array dimensions = {{YGUndefined, YGUndefined}}; 14 | std::array margin = {}; 15 | std::array border = {}; 16 | std::array padding = {}; 17 | YGDirection direction : 2; 18 | bool didUseLegacyFlag : 1; 19 | bool doesLegacyStretchFlagAffectsLayout : 1; 20 | bool hadOverflow : 1; 21 | 22 | uint32_t computedFlexBasisGeneration = 0; 23 | YGFloatOptional computedFlexBasis = {}; 24 | 25 | // Instead of recomputing the entire layout every single time, we cache some 26 | // information to break early when nothing changed 27 | uint32_t generationCount = 0; 28 | YGDirection lastOwnerDirection = (YGDirection) -1; 29 | 30 | uint32_t nextCachedMeasurementsIndex = 0; 31 | std::array 32 | cachedMeasurements = {}; 33 | std::array measuredDimensions = {{YGUndefined, YGUndefined}}; 34 | 35 | YGCachedMeasurement cachedLayout = YGCachedMeasurement(); 36 | 37 | YGLayout() 38 | : direction(YGDirectionInherit), 39 | didUseLegacyFlag(false), 40 | doesLegacyStretchFlagAffectsLayout(false), 41 | hadOverflow(false) {} 42 | 43 | bool operator==(YGLayout layout) const; 44 | bool operator!=(YGLayout layout) const { return !(*this == layout); } 45 | }; 46 | -------------------------------------------------------------------------------- /third_party/yoga/YGMacros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | #define YG_EXTERN_C_BEGIN extern "C" { 11 | #define YG_EXTERN_C_END } 12 | #else 13 | #define YG_EXTERN_C_BEGIN 14 | #define YG_EXTERN_C_END 15 | #endif 16 | 17 | #ifdef _WINDLL 18 | #define WIN_EXPORT __declspec(dllexport) 19 | #else 20 | #define WIN_EXPORT 21 | #endif 22 | 23 | #ifdef NS_ENUM 24 | // Cannot use NSInteger as NSInteger has a different size than int (which is the 25 | // default type of a enum). Therefor when linking the Yoga C library into obj-c 26 | // the header is a missmatch for the Yoga ABI. 27 | #define YG_ENUM_BEGIN(name) NS_ENUM(int, name) 28 | #define YG_ENUM_END(name) 29 | #else 30 | #define YG_ENUM_BEGIN(name) enum name 31 | #define YG_ENUM_END(name) name 32 | #endif 33 | 34 | #ifdef __GNUC__ 35 | #define YG_DEPRECATED __attribute__((deprecated)) 36 | #elif defined(_MSC_VER) 37 | #define YG_DEPRECATED __declspec(deprecated) 38 | #elif __cplusplus >= 201402L 39 | #if defined(__has_cpp_attribute) 40 | #if __has_cpp_attribute(deprecated) 41 | #define YG_DEPRECATED [[deprecated]] 42 | #endif 43 | #endif 44 | #endif 45 | -------------------------------------------------------------------------------- /third_party/yoga/YGMarker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGMarker.h" 8 | #include "YGConfig.h" 9 | 10 | void YGConfigSetMarkerCallbacks( 11 | YGConfigRef config, 12 | YGMarkerCallbacks markerCallbacks) { 13 | config->markerCallbacks = markerCallbacks; 14 | } 15 | -------------------------------------------------------------------------------- /third_party/yoga/YGMarker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include "YGMacros.h" 10 | 11 | YG_EXTERN_C_BEGIN 12 | 13 | typedef struct YGNode* YGNodeRef; 14 | typedef struct YGConfig* YGConfigRef; 15 | 16 | typedef YG_ENUM_BEGIN(YGMarker){ 17 | YGMarkerLayout, 18 | YGMarkerMeasure, 19 | YGMarkerBaselineFn, 20 | } YG_ENUM_END(YGMarker); 21 | 22 | typedef struct { 23 | int layouts; 24 | int measures; 25 | int maxMeasureCache; 26 | int cachedLayouts; 27 | int cachedMeasures; 28 | int measureCallbacks; 29 | } YGMarkerLayoutData; 30 | 31 | typedef struct { 32 | bool _unused; 33 | } YGMarkerNoData; 34 | 35 | typedef union { 36 | YGMarkerLayoutData* layout; 37 | YGMarkerNoData* noData; 38 | } YGMarkerData; 39 | 40 | typedef struct { 41 | // accepts marker type, a node ref, and marker data (depends on marker type) 42 | // can return a handle or id that Yoga will pass to endMarker 43 | void* (*startMarker)(YGMarker, YGNodeRef, YGMarkerData); 44 | // accepts marker type, a node ref, marker data, and marker id as returned by 45 | // startMarker 46 | void (*endMarker)(YGMarker, YGNodeRef, YGMarkerData, void* id); 47 | } YGMarkerCallbacks; 48 | 49 | void YGConfigSetMarkerCallbacks(YGConfigRef, YGMarkerCallbacks); 50 | 51 | YG_EXTERN_C_END 52 | 53 | #ifdef __cplusplus 54 | 55 | namespace facebook { 56 | namespace yoga { 57 | namespace marker { 58 | namespace detail { 59 | 60 | template 61 | struct MarkerData; 62 | 63 | template <> 64 | struct MarkerData { 65 | using type = YGMarkerLayoutData; 66 | static type*& get(YGMarkerData& d) { return d.layout; } 67 | }; 68 | 69 | struct NoMarkerData { 70 | using type = YGMarkerNoData; 71 | static type*& get(YGMarkerData& d) { return d.noData; } 72 | }; 73 | 74 | template <> 75 | struct MarkerData : NoMarkerData {}; 76 | 77 | template <> 78 | struct MarkerData : NoMarkerData {}; 79 | 80 | } // namespace detail 81 | 82 | template 83 | typename detail::MarkerData::type* data(YGMarkerData d) { 84 | return detail::MarkerData::get(d); 85 | } 86 | 87 | } // namespace marker 88 | } // namespace yoga 89 | } // namespace facebook 90 | 91 | #endif // __cplusplus 92 | -------------------------------------------------------------------------------- /third_party/yoga/YGNode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGNode.h" 8 | #include 9 | #include 10 | #include "CompactValue.h" 11 | #include "Utils.h" 12 | 13 | using namespace facebook; 14 | using facebook::yoga::detail::CompactValue; 15 | 16 | YGNode::YGNode(YGNode&& node) { 17 | context_ = node.context_; 18 | hasNewLayout_ = node.hasNewLayout_; 19 | isReferenceBaseline_ = node.isReferenceBaseline_; 20 | isDirty_ = node.isDirty_; 21 | nodeType_ = node.nodeType_; 22 | measureUsesContext_ = node.measureUsesContext_; 23 | baselineUsesContext_ = node.baselineUsesContext_; 24 | printUsesContext_ = node.printUsesContext_; 25 | useWebDefaults_ = node.useWebDefaults_; 26 | measure_ = node.measure_; 27 | baseline_ = node.baseline_; 28 | print_ = node.print_; 29 | dirtied_ = node.dirtied_; 30 | style_ = node.style_; 31 | layout_ = node.layout_; 32 | lineIndex_ = node.lineIndex_; 33 | owner_ = node.owner_; 34 | children_ = std::move(node.children_); 35 | config_ = node.config_; 36 | resolvedDimensions_ = node.resolvedDimensions_; 37 | for (auto c : children_) { 38 | c->setOwner(c); 39 | } 40 | } 41 | 42 | YGNode::YGNode(const YGNode& node, YGConfigRef config) : YGNode{node} { 43 | config_ = config; 44 | if (config->useWebDefaults) { 45 | useWebDefaults(); 46 | } 47 | } 48 | 49 | void YGNode::print(void* printContext) { 50 | if (print_.noContext != nullptr) { 51 | if (printUsesContext_) { 52 | print_.withContext(this, printContext); 53 | } else { 54 | print_.noContext(this); 55 | } 56 | } 57 | } 58 | 59 | YGFloatOptional YGNode::getLeadingPosition( 60 | const YGFlexDirection axis, 61 | const float axisSize) const { 62 | if (YGFlexDirectionIsRow(axis)) { 63 | auto leadingPosition = YGComputedEdgeValue( 64 | style_.position(), YGEdgeStart, CompactValue::ofUndefined()); 65 | if (!leadingPosition.isUndefined()) { 66 | return YGResolveValue(leadingPosition, axisSize); 67 | } 68 | } 69 | 70 | auto leadingPosition = YGComputedEdgeValue( 71 | style_.position(), leading[axis], CompactValue::ofUndefined()); 72 | 73 | return leadingPosition.isUndefined() 74 | ? YGFloatOptional{0} 75 | : YGResolveValue(leadingPosition, axisSize); 76 | } 77 | 78 | YGFloatOptional YGNode::getTrailingPosition( 79 | const YGFlexDirection axis, 80 | const float axisSize) const { 81 | if (YGFlexDirectionIsRow(axis)) { 82 | auto trailingPosition = YGComputedEdgeValue( 83 | style_.position(), YGEdgeEnd, CompactValue::ofUndefined()); 84 | if (!trailingPosition.isUndefined()) { 85 | return YGResolveValue(trailingPosition, axisSize); 86 | } 87 | } 88 | 89 | auto trailingPosition = YGComputedEdgeValue( 90 | style_.position(), trailing[axis], CompactValue::ofUndefined()); 91 | 92 | return trailingPosition.isUndefined() 93 | ? YGFloatOptional{0} 94 | : YGResolveValue(trailingPosition, axisSize); 95 | } 96 | 97 | bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { 98 | return (YGFlexDirectionIsRow(axis) && 99 | !YGComputedEdgeValue( 100 | style_.position(), YGEdgeStart, CompactValue::ofUndefined()) 101 | .isUndefined()) || 102 | !YGComputedEdgeValue( 103 | style_.position(), leading[axis], CompactValue::ofUndefined()) 104 | .isUndefined(); 105 | } 106 | 107 | bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const { 108 | return (YGFlexDirectionIsRow(axis) && 109 | !YGComputedEdgeValue( 110 | style_.position(), YGEdgeEnd, CompactValue::ofUndefined()) 111 | .isUndefined()) || 112 | !YGComputedEdgeValue( 113 | style_.position(), trailing[axis], CompactValue::ofUndefined()) 114 | .isUndefined(); 115 | } 116 | 117 | YGFloatOptional YGNode::getLeadingMargin( 118 | const YGFlexDirection axis, 119 | const float widthSize) const { 120 | if (YGFlexDirectionIsRow(axis) && 121 | !style_.margin()[YGEdgeStart].isUndefined()) { 122 | return YGResolveValueMargin(style_.margin()[YGEdgeStart], widthSize); 123 | } 124 | 125 | return YGResolveValueMargin( 126 | YGComputedEdgeValue( 127 | style_.margin(), leading[axis], CompactValue::ofZero()), 128 | widthSize); 129 | } 130 | 131 | YGFloatOptional YGNode::getTrailingMargin( 132 | const YGFlexDirection axis, 133 | const float widthSize) const { 134 | if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) { 135 | return YGResolveValueMargin(style_.margin()[YGEdgeEnd], widthSize); 136 | } 137 | 138 | return YGResolveValueMargin( 139 | YGComputedEdgeValue( 140 | style_.margin(), trailing[axis], CompactValue::ofZero()), 141 | widthSize); 142 | } 143 | 144 | YGFloatOptional YGNode::getMarginForAxis( 145 | const YGFlexDirection axis, 146 | const float widthSize) const { 147 | return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize); 148 | } 149 | 150 | YGSize YGNode::measure( 151 | float width, 152 | YGMeasureMode widthMode, 153 | float height, 154 | YGMeasureMode heightMode, 155 | void* layoutContext) { 156 | 157 | return measureUsesContext_ 158 | ? measure_.withContext( 159 | this, width, widthMode, height, heightMode, layoutContext) 160 | : measure_.noContext(this, width, widthMode, height, heightMode); 161 | } 162 | 163 | float YGNode::baseline(float width, float height, void* layoutContext) { 164 | return baselineUsesContext_ 165 | ? baseline_.withContext(this, width, height, layoutContext) 166 | : baseline_.noContext(this, width, height); 167 | } 168 | 169 | // Setters 170 | 171 | void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) { 172 | if (measureFunc.noContext == nullptr) { 173 | // TODO: t18095186 Move nodeType to opt-in function and mark appropriate 174 | // places in Litho 175 | nodeType_ = YGNodeTypeDefault; 176 | } else { 177 | YGAssertWithNode( 178 | this, 179 | children_.size() == 0, 180 | "Cannot set measure function: Nodes with measure functions cannot have " 181 | "children."); 182 | // TODO: t18095186 Move nodeType to opt-in function and mark appropriate 183 | // places in Litho 184 | setNodeType(YGNodeTypeText); 185 | } 186 | 187 | measure_ = measureFunc; 188 | } 189 | 190 | void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) { 191 | measureUsesContext_ = false; 192 | decltype(YGNode::measure_) m; 193 | m.noContext = measureFunc; 194 | setMeasureFunc(m); 195 | } 196 | 197 | void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) { 198 | measureUsesContext_ = true; 199 | decltype(YGNode::measure_) m; 200 | m.withContext = measureFunc; 201 | setMeasureFunc(m); 202 | } 203 | 204 | void YGNode::replaceChild(YGNodeRef child, uint32_t index) { 205 | children_[index] = child; 206 | } 207 | 208 | void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) { 209 | std::replace(children_.begin(), children_.end(), oldChild, newChild); 210 | } 211 | 212 | void YGNode::insertChild(YGNodeRef child, uint32_t index) { 213 | children_.insert(children_.begin() + index, child); 214 | } 215 | 216 | void YGNode::setDirty(bool isDirty) { 217 | if (isDirty == isDirty_) { 218 | return; 219 | } 220 | isDirty_ = isDirty; 221 | if (isDirty && dirtied_) { 222 | dirtied_(this); 223 | } 224 | } 225 | 226 | bool YGNode::removeChild(YGNodeRef child) { 227 | std::vector::iterator p = 228 | std::find(children_.begin(), children_.end(), child); 229 | if (p != children_.end()) { 230 | children_.erase(p); 231 | return true; 232 | } 233 | return false; 234 | } 235 | 236 | void YGNode::removeChild(uint32_t index) { 237 | children_.erase(children_.begin() + index); 238 | } 239 | 240 | void YGNode::setLayoutDirection(YGDirection direction) { 241 | layout_.direction = direction; 242 | } 243 | 244 | void YGNode::setLayoutMargin(float margin, int index) { 245 | layout_.margin[index] = margin; 246 | } 247 | 248 | void YGNode::setLayoutBorder(float border, int index) { 249 | layout_.border[index] = border; 250 | } 251 | 252 | void YGNode::setLayoutPadding(float padding, int index) { 253 | layout_.padding[index] = padding; 254 | } 255 | 256 | void YGNode::setLayoutLastOwnerDirection(YGDirection direction) { 257 | layout_.lastOwnerDirection = direction; 258 | } 259 | 260 | void YGNode::setLayoutComputedFlexBasis( 261 | const YGFloatOptional computedFlexBasis) { 262 | layout_.computedFlexBasis = computedFlexBasis; 263 | } 264 | 265 | void YGNode::setLayoutPosition(float position, int index) { 266 | layout_.position[index] = position; 267 | } 268 | 269 | void YGNode::setLayoutComputedFlexBasisGeneration( 270 | uint32_t computedFlexBasisGeneration) { 271 | layout_.computedFlexBasisGeneration = computedFlexBasisGeneration; 272 | } 273 | 274 | void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) { 275 | layout_.measuredDimensions[index] = measuredDimension; 276 | } 277 | 278 | void YGNode::setLayoutHadOverflow(bool hadOverflow) { 279 | layout_.hadOverflow = hadOverflow; 280 | } 281 | 282 | void YGNode::setLayoutDimension(float dimension, int index) { 283 | layout_.dimensions[index] = dimension; 284 | } 285 | 286 | // If both left and right are defined, then use left. Otherwise return +left or 287 | // -right depending on which is defined. 288 | YGFloatOptional YGNode::relativePosition( 289 | const YGFlexDirection axis, 290 | const float axisSize) const { 291 | if (isLeadingPositionDefined(axis)) { 292 | return getLeadingPosition(axis, axisSize); 293 | } 294 | 295 | YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize); 296 | if (!trailingPosition.isUndefined()) { 297 | trailingPosition = YGFloatOptional{-1 * trailingPosition.unwrap()}; 298 | } 299 | return trailingPosition; 300 | } 301 | 302 | void YGNode::setPosition( 303 | const YGDirection direction, 304 | const float mainSize, 305 | const float crossSize, 306 | const float ownerWidth) { 307 | /* Root nodes should be always layouted as LTR, so we don't return negative 308 | * values. */ 309 | const YGDirection directionRespectingRoot = 310 | owner_ != nullptr ? direction : YGDirectionLTR; 311 | const YGFlexDirection mainAxis = 312 | YGResolveFlexDirection(style_.flexDirection(), directionRespectingRoot); 313 | const YGFlexDirection crossAxis = 314 | YGFlexDirectionCross(mainAxis, directionRespectingRoot); 315 | 316 | const YGFloatOptional relativePositionMain = 317 | relativePosition(mainAxis, mainSize); 318 | const YGFloatOptional relativePositionCross = 319 | relativePosition(crossAxis, crossSize); 320 | 321 | setLayoutPosition( 322 | (getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), 323 | leading[mainAxis]); 324 | setLayoutPosition( 325 | (getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), 326 | trailing[mainAxis]); 327 | setLayoutPosition( 328 | (getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross) 329 | .unwrap(), 330 | leading[crossAxis]); 331 | setLayoutPosition( 332 | (getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross) 333 | .unwrap(), 334 | trailing[crossAxis]); 335 | } 336 | 337 | YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const { 338 | if (YGFlexDirectionIsRow(axis) && 339 | !style_.margin()[YGEdgeStart].isUndefined()) { 340 | return style_.margin()[YGEdgeStart]; 341 | } else { 342 | return style_.margin()[leading[axis]]; 343 | } 344 | } 345 | 346 | YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const { 347 | if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) { 348 | return style_.margin()[YGEdgeEnd]; 349 | } else { 350 | return style_.margin()[trailing[axis]]; 351 | } 352 | } 353 | 354 | YGValue YGNode::resolveFlexBasisPtr() const { 355 | YGValue flexBasis = style_.flexBasis(); 356 | if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) { 357 | return flexBasis; 358 | } 359 | if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { 360 | return useWebDefaults_ ? YGValueAuto : YGValueZero; 361 | } 362 | return YGValueAuto; 363 | } 364 | 365 | void YGNode::resolveDimension() { 366 | using namespace yoga; 367 | const YGStyle& style = getStyle(); 368 | for (auto dim : {YGDimensionWidth, YGDimensionHeight}) { 369 | if (!style.maxDimensions()[dim].isUndefined() && 370 | YGValueEqual(style.maxDimensions()[dim], style.minDimensions()[dim])) { 371 | resolvedDimensions_[dim] = style.maxDimensions()[dim]; 372 | } else { 373 | resolvedDimensions_[dim] = style.dimensions()[dim]; 374 | } 375 | } 376 | } 377 | 378 | YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) { 379 | if (style_.direction() == YGDirectionInherit) { 380 | return ownerDirection > YGDirectionInherit ? ownerDirection 381 | : YGDirectionLTR; 382 | } else { 383 | return style_.direction(); 384 | } 385 | } 386 | 387 | void YGNode::clearChildren() { 388 | children_.clear(); 389 | children_.shrink_to_fit(); 390 | } 391 | 392 | // Other Methods 393 | 394 | void YGNode::cloneChildrenIfNeeded(void* cloneContext) { 395 | iterChildrenAfterCloningIfNeeded([](YGNodeRef, void*) {}, cloneContext); 396 | } 397 | 398 | void YGNode::markDirtyAndPropogate() { 399 | if (!isDirty_) { 400 | setDirty(true); 401 | setLayoutComputedFlexBasis(YGFloatOptional()); 402 | if (owner_) { 403 | owner_->markDirtyAndPropogate(); 404 | } 405 | } 406 | } 407 | 408 | void YGNode::markDirtyAndPropogateDownwards() { 409 | isDirty_ = true; 410 | for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) { 411 | childNode->markDirtyAndPropogateDownwards(); 412 | }); 413 | } 414 | 415 | float YGNode::resolveFlexGrow() const { 416 | // Root nodes flexGrow should always be 0 417 | if (owner_ == nullptr) { 418 | return 0.0; 419 | } 420 | if (!style_.flexGrow().isUndefined()) { 421 | return style_.flexGrow().unwrap(); 422 | } 423 | if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { 424 | return style_.flex().unwrap(); 425 | } 426 | return kDefaultFlexGrow; 427 | } 428 | 429 | float YGNode::resolveFlexShrink() const { 430 | if (owner_ == nullptr) { 431 | return 0.0; 432 | } 433 | if (!style_.flexShrink().isUndefined()) { 434 | return style_.flexShrink().unwrap(); 435 | } 436 | if (!useWebDefaults_ && !style_.flex().isUndefined() && 437 | style_.flex().unwrap() < 0.0f) { 438 | return -style_.flex().unwrap(); 439 | } 440 | return useWebDefaults_ ? kWebDefaultFlexShrink : kDefaultFlexShrink; 441 | } 442 | 443 | bool YGNode::isNodeFlexible() { 444 | return ( 445 | (style_.positionType() == YGPositionTypeRelative) && 446 | (resolveFlexGrow() != 0 || resolveFlexShrink() != 0)); 447 | } 448 | 449 | float YGNode::getLeadingBorder(const YGFlexDirection axis) const { 450 | YGValue leadingBorder; 451 | if (YGFlexDirectionIsRow(axis) && 452 | !style_.border()[YGEdgeStart].isUndefined()) { 453 | leadingBorder = style_.border()[YGEdgeStart]; 454 | if (leadingBorder.value >= 0) { 455 | return leadingBorder.value; 456 | } 457 | } 458 | 459 | leadingBorder = YGComputedEdgeValue( 460 | style_.border(), leading[axis], CompactValue::ofZero()); 461 | return YGFloatMax(leadingBorder.value, 0.0f); 462 | } 463 | 464 | float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const { 465 | YGValue trailingBorder; 466 | if (YGFlexDirectionIsRow(flexDirection) && 467 | !style_.border()[YGEdgeEnd].isUndefined()) { 468 | trailingBorder = style_.border()[YGEdgeEnd]; 469 | if (trailingBorder.value >= 0.0f) { 470 | return trailingBorder.value; 471 | } 472 | } 473 | 474 | trailingBorder = YGComputedEdgeValue( 475 | style_.border(), trailing[flexDirection], CompactValue::ofZero()); 476 | return YGFloatMax(trailingBorder.value, 0.0f); 477 | } 478 | 479 | YGFloatOptional YGNode::getLeadingPadding( 480 | const YGFlexDirection axis, 481 | const float widthSize) const { 482 | const YGFloatOptional paddingEdgeStart = 483 | YGResolveValue(style_.padding()[YGEdgeStart], widthSize); 484 | if (YGFlexDirectionIsRow(axis) && 485 | !style_.padding()[YGEdgeStart].isUndefined() && 486 | !paddingEdgeStart.isUndefined() && paddingEdgeStart.unwrap() >= 0.0f) { 487 | return paddingEdgeStart; 488 | } 489 | 490 | YGFloatOptional resolvedValue = YGResolveValue( 491 | YGComputedEdgeValue( 492 | style_.padding(), leading[axis], CompactValue::ofZero()), 493 | widthSize); 494 | return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); 495 | } 496 | 497 | YGFloatOptional YGNode::getTrailingPadding( 498 | const YGFlexDirection axis, 499 | const float widthSize) const { 500 | const YGFloatOptional paddingEdgeEnd = 501 | YGResolveValue(style_.padding()[YGEdgeEnd], widthSize); 502 | if (YGFlexDirectionIsRow(axis) && paddingEdgeEnd >= YGFloatOptional{0.0f}) { 503 | return paddingEdgeEnd; 504 | } 505 | 506 | YGFloatOptional resolvedValue = YGResolveValue( 507 | YGComputedEdgeValue( 508 | style_.padding(), trailing[axis], CompactValue::ofZero()), 509 | widthSize); 510 | 511 | return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f)); 512 | } 513 | 514 | YGFloatOptional YGNode::getLeadingPaddingAndBorder( 515 | const YGFlexDirection axis, 516 | const float widthSize) const { 517 | return getLeadingPadding(axis, widthSize) + 518 | YGFloatOptional(getLeadingBorder(axis)); 519 | } 520 | 521 | YGFloatOptional YGNode::getTrailingPaddingAndBorder( 522 | const YGFlexDirection axis, 523 | const float widthSize) const { 524 | return getTrailingPadding(axis, widthSize) + 525 | YGFloatOptional(getTrailingBorder(axis)); 526 | } 527 | 528 | bool YGNode::didUseLegacyFlag() { 529 | bool didUseLegacyFlag = layout_.didUseLegacyFlag; 530 | if (didUseLegacyFlag) { 531 | return true; 532 | } 533 | for (const auto& child : children_) { 534 | if (child->layout_.didUseLegacyFlag) { 535 | didUseLegacyFlag = true; 536 | break; 537 | } 538 | } 539 | return didUseLegacyFlag; 540 | } 541 | 542 | void YGNode::setLayoutDoesLegacyFlagAffectsLayout( 543 | bool doesLegacyFlagAffectsLayout) { 544 | layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout; 545 | } 546 | 547 | void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) { 548 | layout_.didUseLegacyFlag = didUseLegacyFlag; 549 | } 550 | 551 | bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const { 552 | if (children_.size() != node.children_.size()) { 553 | return false; 554 | } 555 | if (layout_ != node.layout_) { 556 | return false; 557 | } 558 | if (children_.size() == 0) { 559 | return true; 560 | } 561 | 562 | bool isLayoutTreeEqual = true; 563 | YGNodeRef otherNodeChildren = nullptr; 564 | for (std::vector::size_type i = 0; i < children_.size(); ++i) { 565 | otherNodeChildren = node.children_[i]; 566 | isLayoutTreeEqual = 567 | children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren); 568 | if (!isLayoutTreeEqual) { 569 | return false; 570 | } 571 | } 572 | return isLayoutTreeEqual; 573 | } 574 | 575 | void YGNode::reset() { 576 | YGAssertWithNode( 577 | this, 578 | children_.size() == 0, 579 | "Cannot reset a node which still has children attached"); 580 | YGAssertWithNode( 581 | this, owner_ == nullptr, "Cannot reset a node still attached to a owner"); 582 | 583 | clearChildren(); 584 | 585 | auto webDefaults = useWebDefaults_; 586 | *this = YGNode{getConfig()}; 587 | if (webDefaults) { 588 | useWebDefaults(); 589 | } 590 | } 591 | -------------------------------------------------------------------------------- /third_party/yoga/YGNode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | #include 9 | #include 10 | #include "CompactValue.h" 11 | #include "YGConfig.h" 12 | #include "YGLayout.h" 13 | #include "YGStyle.h" 14 | #include "YGMacros.h" 15 | #include "Yoga-internal.h" 16 | 17 | YGConfigRef YGConfigGetDefault(); 18 | 19 | struct YGNode { 20 | using MeasureWithContextFn = 21 | YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*); 22 | using BaselineWithContextFn = float (*)(YGNode*, float, float, void*); 23 | using PrintWithContextFn = void (*)(YGNode*, void*); 24 | 25 | private: 26 | void* context_ = nullptr; 27 | bool hasNewLayout_ : 1; 28 | bool isReferenceBaseline_ : 1; 29 | bool isDirty_ : 1; 30 | YGNodeType nodeType_ : 1; 31 | bool measureUsesContext_ : 1; 32 | bool baselineUsesContext_ : 1; 33 | bool printUsesContext_ : 1; 34 | bool useWebDefaults_ : 1; 35 | uint8_t reserved_ = 0; 36 | union { 37 | YGMeasureFunc noContext; 38 | MeasureWithContextFn withContext; 39 | } measure_ = {nullptr}; 40 | union { 41 | YGBaselineFunc noContext; 42 | BaselineWithContextFn withContext; 43 | } baseline_ = {nullptr}; 44 | union { 45 | YGPrintFunc noContext; 46 | PrintWithContextFn withContext; 47 | } print_ = {nullptr}; 48 | YGDirtiedFunc dirtied_ = nullptr; 49 | YGStyle style_ = {}; 50 | YGLayout layout_ = {}; 51 | uint32_t lineIndex_ = 0; 52 | YGNodeRef owner_ = nullptr; 53 | YGVector children_ = {}; 54 | YGConfigRef config_; 55 | std::array resolvedDimensions_ = { 56 | {YGValueUndefined, YGValueUndefined}}; 57 | 58 | YGFloatOptional relativePosition( 59 | const YGFlexDirection axis, 60 | const float axisSize) const; 61 | 62 | void setMeasureFunc(decltype(measure_)); 63 | void setBaselineFunc(decltype(baseline_)); 64 | 65 | void useWebDefaults() { 66 | useWebDefaults_ = true; 67 | style_.flexDirection() = YGFlexDirectionRow; 68 | style_.alignContent() = YGAlignStretch; 69 | } 70 | 71 | // DANGER DANGER DANGER! 72 | // If the the node assigned to has children, we'd either have to deallocate 73 | // them (potentially incorrect) or ignore them (danger of leaks). Only ever 74 | // use this after checking that there are no children. 75 | // DO NOT CHANGE THE VISIBILITY OF THIS METHOD! 76 | YGNode& operator=(YGNode&&) = default; 77 | 78 | using CompactValue = facebook::yoga::detail::CompactValue; 79 | 80 | public: 81 | YGNode() : YGNode{YGConfigGetDefault()} {} 82 | explicit YGNode(const YGConfigRef config) 83 | : hasNewLayout_{true}, 84 | isReferenceBaseline_{false}, 85 | isDirty_{false}, 86 | nodeType_{YGNodeTypeDefault}, 87 | measureUsesContext_{false}, 88 | baselineUsesContext_{false}, 89 | printUsesContext_{false}, 90 | useWebDefaults_{config->useWebDefaults}, 91 | config_{config} { 92 | if (useWebDefaults_) { 93 | useWebDefaults(); 94 | } 95 | }; 96 | ~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree 97 | 98 | YGNode(YGNode&&); 99 | 100 | // Does not expose true value semantics, as children are not cloned eagerly. 101 | // Should we remove this? 102 | YGNode(const YGNode& node) = default; 103 | 104 | // for RB fabric 105 | YGNode(const YGNode& node, YGConfigRef config); 106 | 107 | // assignment means potential leaks of existing children, or alternatively 108 | // freeing unowned memory, double free, or freeing stack memory. 109 | YGNode& operator=(const YGNode&) = delete; 110 | 111 | // Getters 112 | void* getContext() const { return context_; } 113 | 114 | uint8_t& reserved() { return reserved_; } 115 | uint8_t reserved() const { return reserved_; } 116 | 117 | void print(void*); 118 | 119 | bool getHasNewLayout() const { return hasNewLayout_; } 120 | 121 | YGNodeType getNodeType() const { return nodeType_; } 122 | 123 | bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; } 124 | 125 | YGSize measure(float, YGMeasureMode, float, YGMeasureMode, void*); 126 | 127 | bool hasBaselineFunc() const noexcept { 128 | return baseline_.noContext != nullptr; 129 | } 130 | 131 | float baseline(float width, float height, void* layoutContext); 132 | 133 | YGDirtiedFunc getDirtied() const { return dirtied_; } 134 | 135 | // For Performance reasons passing as reference. 136 | YGStyle& getStyle() { return style_; } 137 | 138 | const YGStyle& getStyle() const { return style_; } 139 | 140 | // For Performance reasons passing as reference. 141 | YGLayout& getLayout() { return layout_; } 142 | 143 | const YGLayout& getLayout() const { return layout_; } 144 | 145 | uint32_t getLineIndex() const { return lineIndex_; } 146 | 147 | bool isReferenceBaseline() { return isReferenceBaseline_; } 148 | 149 | // returns the YGNodeRef that owns this YGNode. An owner is used to identify 150 | // the YogaTree that a YGNode belongs to. This method will return the parent 151 | // of the YGNode when a YGNode only belongs to one YogaTree or nullptr when 152 | // the YGNode is shared between two or more YogaTrees. 153 | YGNodeRef getOwner() const { return owner_; } 154 | 155 | // Deprecated, use getOwner() instead. 156 | YGNodeRef getParent() const { return getOwner(); } 157 | 158 | const YGVector& getChildren() const { return children_; } 159 | 160 | // Applies a callback to all children, after cloning them if they are not 161 | // owned. 162 | template 163 | void iterChildrenAfterCloningIfNeeded(T callback, void* cloneContext) { 164 | int i = 0; 165 | for (YGNodeRef& child : children_) { 166 | if (child->getOwner() != this) { 167 | child = config_->cloneNode(child, this, i, cloneContext); 168 | child->setOwner(this); 169 | } 170 | i += 1; 171 | 172 | callback(child, cloneContext); 173 | } 174 | } 175 | 176 | YGNodeRef getChild(uint32_t index) const { return children_.at(index); } 177 | 178 | YGConfigRef getConfig() const { return config_; } 179 | 180 | bool isDirty() const { return isDirty_; } 181 | 182 | std::array getResolvedDimensions() const { 183 | return resolvedDimensions_; 184 | } 185 | 186 | YGValue getResolvedDimension(int index) const { 187 | return resolvedDimensions_[index]; 188 | } 189 | 190 | // Methods related to positions, margin, padding and border 191 | YGFloatOptional getLeadingPosition( 192 | const YGFlexDirection axis, 193 | const float axisSize) const; 194 | bool isLeadingPositionDefined(const YGFlexDirection axis) const; 195 | bool isTrailingPosDefined(const YGFlexDirection axis) const; 196 | YGFloatOptional getTrailingPosition( 197 | const YGFlexDirection axis, 198 | const float axisSize) const; 199 | YGFloatOptional getLeadingMargin( 200 | const YGFlexDirection axis, 201 | const float widthSize) const; 202 | YGFloatOptional getTrailingMargin( 203 | const YGFlexDirection axis, 204 | const float widthSize) const; 205 | float getLeadingBorder(const YGFlexDirection flexDirection) const; 206 | float getTrailingBorder(const YGFlexDirection flexDirection) const; 207 | YGFloatOptional getLeadingPadding( 208 | const YGFlexDirection axis, 209 | const float widthSize) const; 210 | YGFloatOptional getTrailingPadding( 211 | const YGFlexDirection axis, 212 | const float widthSize) const; 213 | YGFloatOptional getLeadingPaddingAndBorder( 214 | const YGFlexDirection axis, 215 | const float widthSize) const; 216 | YGFloatOptional getTrailingPaddingAndBorder( 217 | const YGFlexDirection axis, 218 | const float widthSize) const; 219 | YGFloatOptional getMarginForAxis( 220 | const YGFlexDirection axis, 221 | const float widthSize) const; 222 | // Setters 223 | 224 | void setContext(void* context) { context_ = context; } 225 | 226 | void setPrintFunc(YGPrintFunc printFunc) { 227 | print_.noContext = printFunc; 228 | printUsesContext_ = false; 229 | } 230 | void setPrintFunc(PrintWithContextFn printFunc) { 231 | print_.withContext = printFunc; 232 | printUsesContext_ = true; 233 | } 234 | void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); } 235 | 236 | void setHasNewLayout(bool hasNewLayout) { hasNewLayout_ = hasNewLayout; } 237 | 238 | void setNodeType(YGNodeType nodeType) { nodeType_ = nodeType; } 239 | 240 | void setMeasureFunc(YGMeasureFunc measureFunc); 241 | void setMeasureFunc(MeasureWithContextFn); 242 | void setMeasureFunc(std::nullptr_t) { 243 | return setMeasureFunc(YGMeasureFunc{nullptr}); 244 | } 245 | 246 | void setBaselineFunc(YGBaselineFunc baseLineFunc) { 247 | baselineUsesContext_ = false; 248 | baseline_.noContext = baseLineFunc; 249 | } 250 | void setBaselineFunc(BaselineWithContextFn baseLineFunc) { 251 | baselineUsesContext_ = true; 252 | baseline_.withContext = baseLineFunc; 253 | } 254 | void setBaselineFunc(std::nullptr_t) { 255 | return setBaselineFunc(YGBaselineFunc{nullptr}); 256 | } 257 | 258 | void setDirtiedFunc(YGDirtiedFunc dirtiedFunc) { dirtied_ = dirtiedFunc; } 259 | 260 | void setStyle(const YGStyle& style) { style_ = style; } 261 | 262 | void setLayout(const YGLayout& layout) { layout_ = layout; } 263 | 264 | void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; } 265 | 266 | void setIsReferenceBaseline(bool isReferenceBaseline) { 267 | isReferenceBaseline_ = isReferenceBaseline; 268 | } 269 | 270 | void setOwner(YGNodeRef owner) { owner_ = owner; } 271 | 272 | void setChildren(const YGVector& children) { children_ = children; } 273 | 274 | // TODO: rvalue override for setChildren 275 | 276 | YG_DEPRECATED void setConfig(YGConfigRef config) { config_ = config; } 277 | 278 | void setDirty(bool isDirty); 279 | void setLayoutLastOwnerDirection(YGDirection direction); 280 | void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis); 281 | void setLayoutComputedFlexBasisGeneration( 282 | uint32_t computedFlexBasisGeneration); 283 | void setLayoutMeasuredDimension(float measuredDimension, int index); 284 | void setLayoutHadOverflow(bool hadOverflow); 285 | void setLayoutDimension(float dimension, int index); 286 | void setLayoutDirection(YGDirection direction); 287 | void setLayoutMargin(float margin, int index); 288 | void setLayoutBorder(float border, int index); 289 | void setLayoutPadding(float padding, int index); 290 | void setLayoutPosition(float position, int index); 291 | void setPosition( 292 | const YGDirection direction, 293 | const float mainSize, 294 | const float crossSize, 295 | const float ownerWidth); 296 | void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout); 297 | void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag); 298 | void markDirtyAndPropogateDownwards(); 299 | 300 | // Other methods 301 | YGValue marginLeadingValue(const YGFlexDirection axis) const; 302 | YGValue marginTrailingValue(const YGFlexDirection axis) const; 303 | YGValue resolveFlexBasisPtr() const; 304 | void resolveDimension(); 305 | YGDirection resolveDirection(const YGDirection ownerDirection); 306 | void clearChildren(); 307 | /// Replaces the occurrences of oldChild with newChild 308 | void replaceChild(YGNodeRef oldChild, YGNodeRef newChild); 309 | void replaceChild(YGNodeRef child, uint32_t index); 310 | void insertChild(YGNodeRef child, uint32_t index); 311 | /// Removes the first occurrence of child 312 | bool removeChild(YGNodeRef child); 313 | void removeChild(uint32_t index); 314 | 315 | void cloneChildrenIfNeeded(void*); 316 | void markDirtyAndPropogate(); 317 | float resolveFlexGrow() const; 318 | float resolveFlexShrink() const; 319 | bool isNodeFlexible(); 320 | bool didUseLegacyFlag(); 321 | bool isLayoutTreeEqualToNode(const YGNode& node) const; 322 | void reset(); 323 | }; 324 | -------------------------------------------------------------------------------- /third_party/yoga/YGNodePrint.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #ifdef DEBUG 8 | #include "YGNodePrint.h" 9 | #include 10 | #include "YGEnums.h" 11 | #include "YGNode.h" 12 | #include "Yoga-internal.h" 13 | #include "Utils.h" 14 | 15 | namespace facebook { 16 | namespace yoga { 17 | typedef std::string string; 18 | 19 | static void indent(string& base, uint32_t level) { 20 | for (uint32_t i = 0; i < level; ++i) { 21 | base.append(" "); 22 | } 23 | } 24 | 25 | static bool areFourValuesEqual(const YGStyle::Edges& four) { 26 | return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) && 27 | YGValueEqual(four[0], four[3]); 28 | } 29 | 30 | static void appendFormatedString(string& str, const char* fmt, ...) { 31 | va_list args; 32 | va_start(args, fmt); 33 | va_list argsCopy; 34 | va_copy(argsCopy, args); 35 | std::vector buf(1 + vsnprintf(NULL, 0, fmt, args)); 36 | va_end(args); 37 | vsnprintf(buf.data(), buf.size(), fmt, argsCopy); 38 | va_end(argsCopy); 39 | string result = string(buf.begin(), buf.end() - 1); 40 | str.append(result); 41 | } 42 | 43 | static void appendFloatOptionalIfDefined( 44 | string& base, 45 | const string key, 46 | const YGFloatOptional num) { 47 | if (!num.isUndefined()) { 48 | appendFormatedString(base, "%s: %g; ", key.c_str(), num.unwrap()); 49 | } 50 | } 51 | 52 | static void appendNumberIfNotUndefined( 53 | string& base, 54 | const string key, 55 | const YGValue number) { 56 | if (number.unit != YGUnitUndefined) { 57 | if (number.unit == YGUnitAuto) { 58 | base.append(key + ": auto; "); 59 | } else { 60 | string unit = number.unit == YGUnitPoint ? "px" : "%%"; 61 | appendFormatedString( 62 | base, "%s: %g%s; ", key.c_str(), number.value, unit.c_str()); 63 | } 64 | } 65 | } 66 | 67 | static void appendNumberIfNotAuto( 68 | string& base, 69 | const string& key, 70 | const YGValue number) { 71 | if (number.unit != YGUnitAuto) { 72 | appendNumberIfNotUndefined(base, key, number); 73 | } 74 | } 75 | 76 | static void appendNumberIfNotZero( 77 | string& base, 78 | const string& str, 79 | const YGValue number) { 80 | if (number.unit == YGUnitAuto) { 81 | base.append(str + ": auto; "); 82 | } else if (!YGFloatsEqual(number.value, 0)) { 83 | appendNumberIfNotUndefined(base, str, number); 84 | } 85 | } 86 | 87 | static void appendEdges( 88 | string& base, 89 | const string& key, 90 | const YGStyle::Edges& edges) { 91 | if (areFourValuesEqual(edges)) { 92 | appendNumberIfNotZero(base, key, edges[YGEdgeLeft]); 93 | } else { 94 | for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) { 95 | string str = key + "-" + YGEdgeToString(static_cast(edge)); 96 | appendNumberIfNotZero(base, str, edges[edge]); 97 | } 98 | } 99 | } 100 | 101 | static void appendEdgeIfNotUndefined( 102 | string& base, 103 | const string& str, 104 | const YGStyle::Edges& edges, 105 | const YGEdge edge) { 106 | appendNumberIfNotUndefined( 107 | base, 108 | str, 109 | YGComputedEdgeValue(edges, edge, detail::CompactValue::ofUndefined())); 110 | } 111 | 112 | void YGNodeToString( 113 | std::string& str, 114 | YGNodeRef node, 115 | YGPrintOptions options, 116 | uint32_t level) { 117 | indent(str, level); 118 | appendFormatedString(str, "
getLayout().dimensions[YGDimensionWidth]); 124 | appendFormatedString( 125 | str, "height: %g; ", node->getLayout().dimensions[YGDimensionHeight]); 126 | appendFormatedString( 127 | str, "top: %g; ", node->getLayout().position[YGEdgeTop]); 128 | appendFormatedString( 129 | str, "left: %g;", node->getLayout().position[YGEdgeLeft]); 130 | appendFormatedString(str, "\" "); 131 | } 132 | 133 | if (options & YGPrintOptionsStyle) { 134 | appendFormatedString(str, "style=\""); 135 | const auto& style = node->getStyle(); 136 | if (style.flexDirection() != YGNode().getStyle().flexDirection()) { 137 | appendFormatedString( 138 | str, 139 | "flex-direction: %s; ", 140 | YGFlexDirectionToString(style.flexDirection())); 141 | } 142 | if (style.justifyContent() != YGNode().getStyle().justifyContent()) { 143 | appendFormatedString( 144 | str, 145 | "justify-content: %s; ", 146 | YGJustifyToString(style.justifyContent())); 147 | } 148 | if (style.alignItems() != YGNode().getStyle().alignItems()) { 149 | appendFormatedString( 150 | str, "align-items: %s; ", YGAlignToString(style.alignItems())); 151 | } 152 | if (style.alignContent() != YGNode().getStyle().alignContent()) { 153 | appendFormatedString( 154 | str, "align-content: %s; ", YGAlignToString(style.alignContent())); 155 | } 156 | if (style.alignSelf() != YGNode().getStyle().alignSelf()) { 157 | appendFormatedString( 158 | str, "align-self: %s; ", YGAlignToString(style.alignSelf())); 159 | } 160 | appendFloatOptionalIfDefined(str, "flex-grow", style.flexGrow()); 161 | appendFloatOptionalIfDefined(str, "flex-shrink", style.flexShrink()); 162 | appendNumberIfNotAuto(str, "flex-basis", style.flexBasis()); 163 | appendFloatOptionalIfDefined(str, "flex", style.flex()); 164 | 165 | if (style.flexWrap() != YGNode().getStyle().flexWrap()) { 166 | appendFormatedString( 167 | str, "flex-wrap: %s; ", YGWrapToString(style.flexWrap())); 168 | } 169 | 170 | if (style.overflow() != YGNode().getStyle().overflow()) { 171 | appendFormatedString( 172 | str, "overflow: %s; ", YGOverflowToString(style.overflow())); 173 | } 174 | 175 | if (style.display() != YGNode().getStyle().display()) { 176 | appendFormatedString( 177 | str, "display: %s; ", YGDisplayToString(style.display())); 178 | } 179 | appendEdges(str, "margin", style.margin()); 180 | appendEdges(str, "padding", style.padding()); 181 | appendEdges(str, "border", style.border()); 182 | 183 | appendNumberIfNotAuto(str, "width", style.dimensions()[YGDimensionWidth]); 184 | appendNumberIfNotAuto(str, "height", style.dimensions()[YGDimensionHeight]); 185 | appendNumberIfNotAuto( 186 | str, "max-width", style.maxDimensions()[YGDimensionWidth]); 187 | appendNumberIfNotAuto( 188 | str, "max-height", style.maxDimensions()[YGDimensionHeight]); 189 | appendNumberIfNotAuto( 190 | str, "min-width", style.minDimensions()[YGDimensionWidth]); 191 | appendNumberIfNotAuto( 192 | str, "min-height", style.minDimensions()[YGDimensionHeight]); 193 | 194 | if (style.positionType() != YGNode().getStyle().positionType()) { 195 | appendFormatedString( 196 | str, "position: %s; ", YGPositionTypeToString(style.positionType())); 197 | } 198 | 199 | appendEdgeIfNotUndefined(str, "left", style.position(), YGEdgeLeft); 200 | appendEdgeIfNotUndefined(str, "right", style.position(), YGEdgeRight); 201 | appendEdgeIfNotUndefined(str, "top", style.position(), YGEdgeTop); 202 | appendEdgeIfNotUndefined(str, "bottom", style.position(), YGEdgeBottom); 203 | appendFormatedString(str, "\" "); 204 | 205 | if (node->hasMeasureFunc()) { 206 | appendFormatedString(str, "has-custom-measure=\"true\""); 207 | } 208 | } 209 | appendFormatedString(str, ">"); 210 | 211 | const uint32_t childCount = static_cast(node->getChildren().size()); 212 | if (options & YGPrintOptionsChildren && childCount > 0) { 213 | for (uint32_t i = 0; i < childCount; i++) { 214 | appendFormatedString(str, "\n"); 215 | YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1); 216 | } 217 | appendFormatedString(str, "\n"); 218 | indent(str, level); 219 | } 220 | appendFormatedString(str, "
"); 221 | } 222 | } // namespace yoga 223 | } // namespace facebook 224 | #endif 225 | -------------------------------------------------------------------------------- /third_party/yoga/YGNodePrint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #ifdef DEBUG 8 | #pragma once 9 | #include 10 | 11 | #include "Yoga.h" 12 | 13 | namespace facebook { 14 | namespace yoga { 15 | 16 | void YGNodeToString( 17 | std::string& str, 18 | YGNodeRef node, 19 | YGPrintOptions options, 20 | uint32_t level); 21 | 22 | } // namespace yoga 23 | } // namespace facebook 24 | #endif 25 | -------------------------------------------------------------------------------- /third_party/yoga/YGStyle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGStyle.h" 8 | #include "Utils.h" 9 | 10 | // Yoga specific properties, not compatible with flexbox specification 11 | bool operator==(const YGStyle& lhs, const YGStyle& rhs) { 12 | bool areNonFloatValuesEqual = lhs.direction() == rhs.direction() && 13 | lhs.flexDirection() == rhs.flexDirection() && 14 | lhs.justifyContent() == rhs.justifyContent() && 15 | lhs.alignContent() == rhs.alignContent() && 16 | lhs.alignItems() == rhs.alignItems() && 17 | lhs.alignSelf() == rhs.alignSelf() && 18 | lhs.positionType() == rhs.positionType() && 19 | lhs.flexWrap() == rhs.flexWrap() && lhs.overflow() == rhs.overflow() && 20 | lhs.display() == rhs.display() && 21 | YGValueEqual(lhs.flexBasis(), rhs.flexBasis()) && 22 | lhs.margin() == rhs.margin() && lhs.position() == rhs.position() && 23 | lhs.padding() == rhs.padding() && lhs.border() == rhs.border() && 24 | lhs.dimensions() == rhs.dimensions() && 25 | lhs.minDimensions() == rhs.minDimensions() && 26 | lhs.maxDimensions() == rhs.maxDimensions(); 27 | 28 | areNonFloatValuesEqual = areNonFloatValuesEqual && 29 | lhs.flex().isUndefined() == rhs.flex().isUndefined(); 30 | if (areNonFloatValuesEqual && !lhs.flex().isUndefined() && 31 | !rhs.flex().isUndefined()) { 32 | areNonFloatValuesEqual = areNonFloatValuesEqual && lhs.flex() == rhs.flex(); 33 | } 34 | 35 | areNonFloatValuesEqual = areNonFloatValuesEqual && 36 | lhs.flexGrow().isUndefined() == rhs.flexGrow().isUndefined(); 37 | if (areNonFloatValuesEqual && !lhs.flexGrow().isUndefined()) { 38 | areNonFloatValuesEqual = 39 | areNonFloatValuesEqual && lhs.flexGrow() == rhs.flexGrow(); 40 | } 41 | 42 | areNonFloatValuesEqual = areNonFloatValuesEqual && 43 | lhs.flexShrink().isUndefined() == rhs.flexShrink().isUndefined(); 44 | if (areNonFloatValuesEqual && !rhs.flexShrink().isUndefined()) { 45 | areNonFloatValuesEqual = 46 | areNonFloatValuesEqual && lhs.flexShrink() == rhs.flexShrink(); 47 | } 48 | 49 | if (!(lhs.aspectRatio().isUndefined() && rhs.aspectRatio().isUndefined())) { 50 | areNonFloatValuesEqual = 51 | areNonFloatValuesEqual && lhs.aspectRatio() == rhs.aspectRatio(); 52 | } 53 | 54 | return areNonFloatValuesEqual; 55 | } 56 | -------------------------------------------------------------------------------- /third_party/yoga/YGStyle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "CompactValue.h" 14 | #include "YGEnums.h" 15 | #include "YGFloatOptional.h" 16 | #include "Yoga-internal.h" 17 | #include "Yoga.h" 18 | 19 | #if !defined(ENUM_BITFIELDS_NOT_SUPPORTED) 20 | #define BITFIELD_ENUM_SIZED(num) : num 21 | #else 22 | #define BITFIELD_ENUM_SIZED(num) 23 | #endif 24 | 25 | #define BITFIELD_ACCESSORS(FIELD) \ 26 | decltype(FIELD##_) get_##FIELD() const { return FIELD##_; } \ 27 | void set_##FIELD(decltype(FIELD##_) x) { FIELD##_ = x; } 28 | 29 | #define BITFIELD_REF(FIELD) \ 30 | BitfieldRef< \ 31 | decltype(FIELD##_), \ 32 | &YGStyle::get_##FIELD, \ 33 | &YGStyle::set_##FIELD, \ 34 | FIELD##Bit> 35 | 36 | class YGStyle { 37 | template 38 | using Values = 39 | facebook::yoga::detail::Values()>; 40 | using CompactValue = facebook::yoga::detail::CompactValue; 41 | 42 | static constexpr uint64_t allBits(int fromBit, int toBit) { 43 | return fromBit < toBit 44 | ? (uint64_t{1} << fromBit) | allBits(fromBit + 1, toBit) 45 | : 0; 46 | } 47 | 48 | public: 49 | using Dimensions = Values; 50 | using Edges = Values; 51 | 52 | template 53 | struct Ref { 54 | YGStyle& style; 55 | operator T() const { return style.*Prop; } 56 | Ref& operator=(T value) { 57 | style.*Prop = value; 58 | style.assignedProps_.set(PropBit); 59 | return *this; 60 | } 61 | }; 62 | 63 | template YGStyle::*Prop, int PropBit> 64 | struct IdxRef { 65 | struct Ref { 66 | YGStyle& style; 67 | Idx idx; 68 | operator CompactValue() const { return (style.*Prop)[idx]; } 69 | operator YGValue() const { return (style.*Prop)[idx]; } 70 | Ref& operator=(CompactValue value) { 71 | (style.*Prop)[idx] = value; 72 | style.assignedProps_.set(PropBit + idx); 73 | return *this; 74 | } 75 | }; 76 | 77 | YGStyle& style; 78 | IdxRef& operator=(const Values& values) { 79 | style.*Prop = values; 80 | style.assignedProps_ |= 81 | allBits(PropBit, PropBit + facebook::yoga::enums::count()); 82 | return *this; 83 | } 84 | operator const Values&() const { return style.*Prop; } 85 | Ref operator[](Idx idx) { return {style, idx}; } 86 | CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; } 87 | }; 88 | 89 | template < 90 | typename T, 91 | T (YGStyle::*Get)() const, 92 | void (YGStyle::*Set)(T), 93 | int PropBit> 94 | struct BitfieldRef { 95 | YGStyle& style; 96 | 97 | operator T() const { return (style.*Get)(); } 98 | BitfieldRef& operator=(T x) { 99 | (style.*Set)(x); 100 | style.assignedProps_.set(PropBit); 101 | return *this; 102 | } 103 | }; 104 | 105 | YGStyle() 106 | : direction_(YGDirectionInherit), 107 | flexDirection_(YGFlexDirectionColumn), 108 | justifyContent_(YGJustifyFlexStart), 109 | alignContent_(YGAlignFlexStart), 110 | alignItems_(YGAlignStretch), 111 | alignSelf_(YGAlignAuto), 112 | positionType_(YGPositionTypeRelative), 113 | flexWrap_(YGWrapNoWrap), 114 | overflow_(YGOverflowVisible), 115 | display_(YGDisplayFlex) {} 116 | ~YGStyle() = default; 117 | 118 | static constexpr int directionBit = 0; 119 | static constexpr int flexDirectionBit = directionBit + 1; 120 | static constexpr int justifyContentBit = flexDirectionBit + 1; 121 | static constexpr int alignContentBit = justifyContentBit + 1; 122 | static constexpr int alignItemsBit = alignContentBit + 1; 123 | static constexpr int alignSelfBit = alignItemsBit + 1; 124 | static constexpr int positionTypeBit = alignSelfBit + 1; 125 | static constexpr int flexWrapBit = positionTypeBit + 1; 126 | static constexpr int overflowBit = flexWrapBit + 1; 127 | static constexpr int displayBit = overflowBit + 1; 128 | static constexpr int flexBit = displayBit + 1; 129 | static constexpr int flexGrowBit = flexBit + 1; 130 | static constexpr int flexShrinkBit = flexGrowBit + 1; 131 | static constexpr int flexBasisBit = flexShrinkBit + 1; 132 | static constexpr int marginBit = flexBasisBit + 1; 133 | static constexpr int positionBit = 134 | marginBit + facebook::yoga::enums::count(); 135 | static constexpr int paddingBit = 136 | positionBit + facebook::yoga::enums::count(); 137 | static constexpr int borderBit = 138 | paddingBit + facebook::yoga::enums::count(); 139 | static constexpr int dimensionsBit = 140 | borderBit + facebook::yoga::enums::count(); 141 | static constexpr int maxDimensionsBit = 142 | dimensionsBit + facebook::yoga::enums::count(); 143 | static constexpr int minDimensionsBit = 144 | maxDimensionsBit + facebook::yoga::enums::count(); 145 | static constexpr int aspectRatioBit = 146 | minDimensionsBit + facebook::yoga::enums::count(); 147 | 148 | static constexpr int numStyles = aspectRatioBit + 1; 149 | 150 | private: 151 | std::bitset assignedProps_; 152 | 153 | /* Some platforms don't support enum bitfields, 154 | so please use BITFIELD_ENUM_SIZED(BITS_COUNT) */ 155 | YGDirection direction_ BITFIELD_ENUM_SIZED(2); 156 | YGFlexDirection flexDirection_ BITFIELD_ENUM_SIZED(2); 157 | YGJustify justifyContent_ BITFIELD_ENUM_SIZED(3); 158 | YGAlign alignContent_ BITFIELD_ENUM_SIZED(3); 159 | YGAlign alignItems_ BITFIELD_ENUM_SIZED(3); 160 | YGAlign alignSelf_ BITFIELD_ENUM_SIZED(3); 161 | YGPositionType positionType_ BITFIELD_ENUM_SIZED(1); 162 | YGWrap flexWrap_ BITFIELD_ENUM_SIZED(2); 163 | YGOverflow overflow_ BITFIELD_ENUM_SIZED(2); 164 | YGDisplay display_ BITFIELD_ENUM_SIZED(1); 165 | YGFloatOptional flex_ = {}; 166 | YGFloatOptional flexGrow_ = {}; 167 | YGFloatOptional flexShrink_ = {}; 168 | CompactValue flexBasis_ = CompactValue::ofAuto(); 169 | Edges margin_ = {}; 170 | Edges position_ = {}; 171 | Edges padding_ = {}; 172 | Edges border_ = {}; 173 | Dimensions dimensions_{CompactValue::ofAuto()}; 174 | Dimensions minDimensions_ = {}; 175 | Dimensions maxDimensions_ = {}; 176 | // Yoga specific properties, not compatible with flexbox specification 177 | YGFloatOptional aspectRatio_ = {}; 178 | 179 | BITFIELD_ACCESSORS(direction) 180 | BITFIELD_ACCESSORS(flexDirection) 181 | BITFIELD_ACCESSORS(justifyContent) 182 | BITFIELD_ACCESSORS(alignContent); 183 | BITFIELD_ACCESSORS(alignItems); 184 | BITFIELD_ACCESSORS(alignSelf); 185 | BITFIELD_ACCESSORS(positionType); 186 | BITFIELD_ACCESSORS(flexWrap); 187 | BITFIELD_ACCESSORS(overflow); 188 | BITFIELD_ACCESSORS(display); 189 | 190 | public: 191 | const decltype(assignedProps_)& assignedProps() const { 192 | return assignedProps_; 193 | } 194 | 195 | // for library users needing a type 196 | using ValueRepr = std::remove_reference::type; 197 | 198 | YGDirection direction() const { return direction_; } 199 | BITFIELD_REF(direction) direction() { return {*this}; } 200 | 201 | YGFlexDirection flexDirection() const { return flexDirection_; } 202 | BITFIELD_REF(flexDirection) flexDirection() { return {*this}; } 203 | 204 | YGJustify justifyContent() const { return justifyContent_; } 205 | BITFIELD_REF(justifyContent) justifyContent() { return {*this}; } 206 | 207 | YGAlign alignContent() const { return alignContent_; } 208 | BITFIELD_REF(alignContent) alignContent() { return {*this}; } 209 | 210 | YGAlign alignItems() const { return alignItems_; } 211 | BITFIELD_REF(alignItems) alignItems() { return {*this}; } 212 | 213 | YGAlign alignSelf() const { return alignSelf_; } 214 | BITFIELD_REF(alignSelf) alignSelf() { return {*this}; } 215 | 216 | YGPositionType positionType() const { return positionType_; } 217 | BITFIELD_REF(positionType) positionType() { return {*this}; } 218 | 219 | YGWrap flexWrap() const { return flexWrap_; } 220 | BITFIELD_REF(flexWrap) flexWrap() { return {*this}; } 221 | 222 | YGOverflow overflow() const { return overflow_; } 223 | BITFIELD_REF(overflow) overflow() { return {*this}; } 224 | 225 | YGDisplay display() const { return display_; } 226 | BITFIELD_REF(display) display() { return {*this}; } 227 | 228 | YGFloatOptional flex() const { return flex_; } 229 | Ref flex() { return {*this}; } 230 | 231 | YGFloatOptional flexGrow() const { return flexGrow_; } 232 | Ref flexGrow() { 233 | return {*this}; 234 | } 235 | 236 | YGFloatOptional flexShrink() const { return flexShrink_; } 237 | Ref flexShrink() { 238 | return {*this}; 239 | } 240 | 241 | CompactValue flexBasis() const { return flexBasis_; } 242 | Ref flexBasis() { 243 | return {*this}; 244 | } 245 | 246 | const Edges& margin() const { return margin_; } 247 | IdxRef margin() { return {*this}; } 248 | 249 | const Edges& position() const { return position_; } 250 | IdxRef position() { 251 | return {*this}; 252 | } 253 | 254 | const Edges& padding() const { return padding_; } 255 | IdxRef padding() { return {*this}; } 256 | 257 | const Edges& border() const { return border_; } 258 | IdxRef border() { return {*this}; } 259 | 260 | const Dimensions& dimensions() const { return dimensions_; } 261 | IdxRef dimensions() { 262 | return {*this}; 263 | } 264 | 265 | const Dimensions& minDimensions() const { return minDimensions_; } 266 | IdxRef 267 | minDimensions() { 268 | return {*this}; 269 | } 270 | 271 | const Dimensions& maxDimensions() const { return maxDimensions_; } 272 | IdxRef 273 | maxDimensions() { 274 | return {*this}; 275 | } 276 | 277 | // Yoga specific properties, not compatible with flexbox specification 278 | YGFloatOptional aspectRatio() const { return aspectRatio_; } 279 | Ref aspectRatio() { 280 | return {*this}; 281 | } 282 | }; 283 | 284 | bool operator==(const YGStyle& lhs, const YGStyle& rhs); 285 | inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) { 286 | return !(lhs == rhs); 287 | } 288 | 289 | #undef BITFIELD_ENUM_SIZED 290 | #undef BITFIELD_ACCESSORS 291 | #undef BITFIELD_REF 292 | -------------------------------------------------------------------------------- /third_party/yoga/YGValue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGValue.h" 8 | 9 | const YGValue YGValueZero = {0, YGUnitPoint}; 10 | const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; 11 | const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; 12 | -------------------------------------------------------------------------------- /third_party/yoga/YGValue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include 10 | #include "YGEnums.h" 11 | #include "YGMacros.h" 12 | 13 | YG_EXTERN_C_BEGIN 14 | 15 | // Not defined in MSVC++ 16 | #ifndef NAN 17 | static const uint32_t __nan = 0x7fc00000; 18 | #define NAN (*(const float*) __nan) 19 | #endif 20 | 21 | #define YGUndefined NAN 22 | 23 | typedef struct YGValue { 24 | float value; 25 | YGUnit unit; 26 | } YGValue; 27 | 28 | extern const YGValue YGValueAuto; 29 | extern const YGValue YGValueUndefined; 30 | extern const YGValue YGValueZero; 31 | 32 | YG_EXTERN_C_END 33 | 34 | #ifdef __cplusplus 35 | 36 | inline bool operator==(const YGValue& lhs, const YGValue& rhs) { 37 | if (lhs.unit != rhs.unit) { 38 | return false; 39 | } 40 | 41 | switch (lhs.unit) { 42 | case YGUnitUndefined: 43 | case YGUnitAuto: 44 | return true; 45 | case YGUnitPoint: 46 | case YGUnitPercent: 47 | return lhs.value == rhs.value; 48 | } 49 | 50 | return false; 51 | } 52 | 53 | inline bool operator!=(const YGValue& lhs, const YGValue& rhs) { 54 | return !(lhs == rhs); 55 | } 56 | 57 | inline YGValue operator-(const YGValue& value) { 58 | return {-value.value, value.unit}; 59 | } 60 | 61 | namespace facebook { 62 | namespace yoga { 63 | namespace literals { 64 | 65 | inline YGValue operator"" _pt(long double value) { 66 | return YGValue{static_cast(value), YGUnitPoint}; 67 | } 68 | inline YGValue operator"" _pt(unsigned long long value) { 69 | return operator"" _pt(static_cast(value)); 70 | } 71 | 72 | inline YGValue operator"" _percent(long double value) { 73 | return YGValue{static_cast(value), YGUnitPercent}; 74 | } 75 | inline YGValue operator"" _percent(unsigned long long value) { 76 | return operator"" _percent(static_cast(value)); 77 | } 78 | 79 | } // namespace literals 80 | } // namespace yoga 81 | } // namespace facebook 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /third_party/yoga/Yoga-internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "CompactValue.h" 13 | #include "Yoga.h" 14 | 15 | using YGVector = std::vector; 16 | 17 | YG_EXTERN_C_BEGIN 18 | 19 | void YGNodeCalculateLayoutWithContext( 20 | YGNodeRef node, 21 | float availableWidth, 22 | float availableHeight, 23 | YGDirection ownerDirection, 24 | void* layoutContext); 25 | 26 | YG_EXTERN_C_END 27 | 28 | namespace facebook { 29 | namespace yoga { 30 | 31 | inline bool isUndefined(float value) { 32 | return std::isnan(value); 33 | } 34 | 35 | } // namespace yoga 36 | } // namespace facebook 37 | 38 | using namespace facebook; 39 | 40 | extern const std::array trailing; 41 | extern const std::array leading; 42 | extern const YGValue YGValueUndefined; 43 | extern const YGValue YGValueAuto; 44 | extern const YGValue YGValueZero; 45 | 46 | struct YGCachedMeasurement { 47 | float availableWidth; 48 | float availableHeight; 49 | YGMeasureMode widthMeasureMode; 50 | YGMeasureMode heightMeasureMode; 51 | 52 | float computedWidth; 53 | float computedHeight; 54 | 55 | YGCachedMeasurement() 56 | : availableWidth(0), 57 | availableHeight(0), 58 | widthMeasureMode((YGMeasureMode) -1), 59 | heightMeasureMode((YGMeasureMode) -1), 60 | computedWidth(-1), 61 | computedHeight(-1) {} 62 | 63 | bool operator==(YGCachedMeasurement measurement) const { 64 | bool isEqual = widthMeasureMode == measurement.widthMeasureMode && 65 | heightMeasureMode == measurement.heightMeasureMode; 66 | 67 | if (!yoga::isUndefined(availableWidth) || 68 | !yoga::isUndefined(measurement.availableWidth)) { 69 | isEqual = isEqual && availableWidth == measurement.availableWidth; 70 | } 71 | if (!yoga::isUndefined(availableHeight) || 72 | !yoga::isUndefined(measurement.availableHeight)) { 73 | isEqual = isEqual && availableHeight == measurement.availableHeight; 74 | } 75 | if (!yoga::isUndefined(computedWidth) || 76 | !yoga::isUndefined(measurement.computedWidth)) { 77 | isEqual = isEqual && computedWidth == measurement.computedWidth; 78 | } 79 | if (!yoga::isUndefined(computedHeight) || 80 | !yoga::isUndefined(measurement.computedHeight)) { 81 | isEqual = isEqual && computedHeight == measurement.computedHeight; 82 | } 83 | 84 | return isEqual; 85 | } 86 | }; 87 | 88 | // This value was chosen based on empirical data: 89 | // 98% of analyzed layouts require less than 8 entries. 90 | #define YG_MAX_CACHED_RESULT_COUNT 8 91 | 92 | namespace facebook { 93 | namespace yoga { 94 | namespace detail { 95 | 96 | template 97 | class Values { 98 | private: 99 | std::array values_; 100 | 101 | public: 102 | Values() = default; 103 | explicit Values(const YGValue& defaultValue) noexcept { 104 | values_.fill(defaultValue); 105 | } 106 | 107 | const CompactValue& operator[](size_t i) const noexcept { return values_[i]; } 108 | CompactValue& operator[](size_t i) noexcept { return values_[i]; } 109 | 110 | template 111 | YGValue get() const noexcept { 112 | return std::get(values_); 113 | } 114 | 115 | template 116 | void set(YGValue& value) noexcept { 117 | std::get(values_) = value; 118 | } 119 | 120 | template 121 | void set(YGValue&& value) noexcept { 122 | set(value); 123 | } 124 | 125 | bool operator==(const Values& other) const noexcept { 126 | for (size_t i = 0; i < Size; ++i) { 127 | if (values_[i] != other.values_[i]) { 128 | return false; 129 | } 130 | } 131 | return true; 132 | } 133 | 134 | Values& operator=(const Values& other) = default; 135 | }; 136 | 137 | } // namespace detail 138 | } // namespace yoga 139 | } // namespace facebook 140 | 141 | static const float kDefaultFlexGrow = 0.0f; 142 | static const float kDefaultFlexShrink = 0.0f; 143 | static const float kWebDefaultFlexShrink = 1.0f; 144 | 145 | extern bool YGFloatsEqual(const float a, const float b); 146 | extern facebook::yoga::detail::CompactValue YGComputedEdgeValue( 147 | const facebook::yoga::detail::Values< 148 | facebook::yoga::enums::count()>& edges, 149 | YGEdge edge, 150 | facebook::yoga::detail::CompactValue defaultValue); 151 | -------------------------------------------------------------------------------- /third_party/yoga/Yoga.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifndef __cplusplus 17 | #include 18 | #endif 19 | 20 | #include "YGEnums.h" 21 | #include "YGMacros.h" 22 | #include "YGValue.h" 23 | 24 | YG_EXTERN_C_BEGIN 25 | 26 | typedef struct YGSize { 27 | float width; 28 | float height; 29 | } YGSize; 30 | 31 | typedef struct YGConfig* YGConfigRef; 32 | 33 | typedef struct YGNode* YGNodeRef; 34 | typedef const struct YGNode* YGNodeConstRef; 35 | 36 | typedef YGSize (*YGMeasureFunc)( 37 | YGNodeRef node, 38 | float width, 39 | YGMeasureMode widthMode, 40 | float height, 41 | YGMeasureMode heightMode); 42 | typedef float (*YGBaselineFunc)(YGNodeRef node, float width, float height); 43 | typedef void (*YGDirtiedFunc)(YGNodeRef node); 44 | typedef void (*YGPrintFunc)(YGNodeRef node); 45 | typedef void (*YGNodeCleanupFunc)(YGNodeRef node); 46 | typedef int (*YGLogger)( 47 | YGConfigRef config, 48 | YGNodeRef node, 49 | YGLogLevel level, 50 | const char* format, 51 | va_list args); 52 | typedef YGNodeRef ( 53 | *YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex); 54 | 55 | // YGNode 56 | WIN_EXPORT YGNodeRef YGNodeNew(void); 57 | WIN_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigRef config); 58 | WIN_EXPORT YGNodeRef YGNodeClone(YGNodeRef node); 59 | WIN_EXPORT void YGNodeFree(YGNodeRef node); 60 | WIN_EXPORT void YGNodeFreeRecursiveWithCleanupFunc( 61 | YGNodeRef node, 62 | YGNodeCleanupFunc cleanup); 63 | WIN_EXPORT void YGNodeFreeRecursive(YGNodeRef node); 64 | WIN_EXPORT void YGNodeReset(YGNodeRef node); 65 | 66 | WIN_EXPORT void YGNodeInsertChild( 67 | YGNodeRef node, 68 | YGNodeRef child, 69 | uint32_t index); 70 | 71 | WIN_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child); 72 | WIN_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node); 73 | WIN_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, uint32_t index); 74 | WIN_EXPORT YGNodeRef YGNodeGetOwner(YGNodeRef node); 75 | WIN_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node); 76 | WIN_EXPORT uint32_t YGNodeGetChildCount(YGNodeRef node); 77 | WIN_EXPORT void YGNodeSetChildren( 78 | YGNodeRef owner, 79 | const YGNodeRef children[], 80 | uint32_t count); 81 | 82 | WIN_EXPORT void YGNodeSetIsReferenceBaseline( 83 | YGNodeRef node, 84 | bool isReferenceBaseline); 85 | 86 | WIN_EXPORT bool YGNodeIsReferenceBaseline(YGNodeRef node); 87 | 88 | WIN_EXPORT void YGNodeCalculateLayout( 89 | YGNodeRef node, 90 | float availableWidth, 91 | float availableHeight, 92 | YGDirection ownerDirection); 93 | 94 | // Mark a node as dirty. Only valid for nodes with a custom measure function 95 | // set. 96 | // 97 | // Yoga knows when to mark all other nodes as dirty but because nodes with 98 | // measure functions depend on information not known to Yoga they must perform 99 | // this dirty marking manually. 100 | WIN_EXPORT void YGNodeMarkDirty(YGNodeRef node); 101 | 102 | // Marks the current node and all its descendants as dirty. 103 | // 104 | // Intended to be used for Uoga benchmarks. Don't use in production, as calling 105 | // `YGCalculateLayout` will cause the recalculation of each and every node. 106 | WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(YGNodeRef node); 107 | 108 | WIN_EXPORT void YGNodePrint(YGNodeRef node, YGPrintOptions options); 109 | 110 | WIN_EXPORT bool YGFloatIsUndefined(float value); 111 | 112 | WIN_EXPORT bool YGNodeCanUseCachedMeasurement( 113 | YGMeasureMode widthMode, 114 | float width, 115 | YGMeasureMode heightMode, 116 | float height, 117 | YGMeasureMode lastWidthMode, 118 | float lastWidth, 119 | YGMeasureMode lastHeightMode, 120 | float lastHeight, 121 | float lastComputedWidth, 122 | float lastComputedHeight, 123 | float marginRow, 124 | float marginColumn, 125 | YGConfigRef config); 126 | 127 | WIN_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeRef srcNode); 128 | 129 | WIN_EXPORT void* YGNodeGetContext(YGNodeRef node); 130 | WIN_EXPORT void YGNodeSetContext(YGNodeRef node, void* context); 131 | void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled); 132 | bool YGNodeHasMeasureFunc(YGNodeRef node); 133 | WIN_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc); 134 | bool YGNodeHasBaselineFunc(YGNodeRef node); 135 | void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc); 136 | YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node); 137 | void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc); 138 | void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc); 139 | WIN_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node); 140 | WIN_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout); 141 | YGNodeType YGNodeGetNodeType(YGNodeRef node); 142 | void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType); 143 | WIN_EXPORT bool YGNodeIsDirty(YGNodeRef node); 144 | bool YGNodeLayoutGetDidUseLegacyFlag(YGNodeRef node); 145 | 146 | WIN_EXPORT void YGNodeStyleSetDirection(YGNodeRef node, YGDirection direction); 147 | WIN_EXPORT YGDirection YGNodeStyleGetDirection(YGNodeConstRef node); 148 | 149 | WIN_EXPORT void YGNodeStyleSetFlexDirection( 150 | YGNodeRef node, 151 | YGFlexDirection flexDirection); 152 | WIN_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(YGNodeConstRef node); 153 | 154 | WIN_EXPORT void YGNodeStyleSetJustifyContent( 155 | YGNodeRef node, 156 | YGJustify justifyContent); 157 | WIN_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node); 158 | 159 | WIN_EXPORT void YGNodeStyleSetAlignContent( 160 | YGNodeRef node, 161 | YGAlign alignContent); 162 | WIN_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node); 163 | 164 | WIN_EXPORT void YGNodeStyleSetAlignItems(YGNodeRef node, YGAlign alignItems); 165 | WIN_EXPORT YGAlign YGNodeStyleGetAlignItems(YGNodeConstRef node); 166 | 167 | WIN_EXPORT void YGNodeStyleSetAlignSelf(YGNodeRef node, YGAlign alignSelf); 168 | WIN_EXPORT YGAlign YGNodeStyleGetAlignSelf(YGNodeConstRef node); 169 | 170 | WIN_EXPORT void YGNodeStyleSetPositionType( 171 | YGNodeRef node, 172 | YGPositionType positionType); 173 | WIN_EXPORT YGPositionType YGNodeStyleGetPositionType(YGNodeConstRef node); 174 | 175 | WIN_EXPORT void YGNodeStyleSetFlexWrap(YGNodeRef node, YGWrap flexWrap); 176 | WIN_EXPORT YGWrap YGNodeStyleGetFlexWrap(YGNodeConstRef node); 177 | 178 | WIN_EXPORT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow); 179 | WIN_EXPORT YGOverflow YGNodeStyleGetOverflow(YGNodeConstRef node); 180 | 181 | WIN_EXPORT void YGNodeStyleSetDisplay(YGNodeRef node, YGDisplay display); 182 | WIN_EXPORT YGDisplay YGNodeStyleGetDisplay(YGNodeConstRef node); 183 | 184 | WIN_EXPORT void YGNodeStyleSetFlex(YGNodeRef node, float flex); 185 | WIN_EXPORT float YGNodeStyleGetFlex(YGNodeConstRef node); 186 | 187 | WIN_EXPORT void YGNodeStyleSetFlexGrow(YGNodeRef node, float flexGrow); 188 | WIN_EXPORT float YGNodeStyleGetFlexGrow(YGNodeConstRef node); 189 | 190 | WIN_EXPORT void YGNodeStyleSetFlexShrink(YGNodeRef node, float flexShrink); 191 | WIN_EXPORT float YGNodeStyleGetFlexShrink(YGNodeConstRef node); 192 | 193 | WIN_EXPORT void YGNodeStyleSetFlexBasis(YGNodeRef node, float flexBasis); 194 | WIN_EXPORT void YGNodeStyleSetFlexBasisPercent(YGNodeRef node, float flexBasis); 195 | WIN_EXPORT void YGNodeStyleSetFlexBasisAuto(YGNodeRef node); 196 | WIN_EXPORT YGValue YGNodeStyleGetFlexBasis(YGNodeConstRef node); 197 | 198 | WIN_EXPORT void YGNodeStyleSetPosition( 199 | YGNodeRef node, 200 | YGEdge edge, 201 | float position); 202 | WIN_EXPORT void YGNodeStyleSetPositionPercent( 203 | YGNodeRef node, 204 | YGEdge edge, 205 | float position); 206 | WIN_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge); 207 | 208 | WIN_EXPORT void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float margin); 209 | WIN_EXPORT void YGNodeStyleSetMarginPercent( 210 | YGNodeRef node, 211 | YGEdge edge, 212 | float margin); 213 | WIN_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge); 214 | WIN_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge); 215 | 216 | WIN_EXPORT void YGNodeStyleSetPadding( 217 | YGNodeRef node, 218 | YGEdge edge, 219 | float padding); 220 | WIN_EXPORT void YGNodeStyleSetPaddingPercent( 221 | YGNodeRef node, 222 | YGEdge edge, 223 | float padding); 224 | WIN_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge); 225 | 226 | WIN_EXPORT void YGNodeStyleSetBorder(YGNodeRef node, YGEdge edge, float border); 227 | WIN_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge); 228 | 229 | WIN_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width); 230 | WIN_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float width); 231 | WIN_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node); 232 | WIN_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node); 233 | 234 | WIN_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float height); 235 | WIN_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float height); 236 | WIN_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node); 237 | WIN_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node); 238 | 239 | WIN_EXPORT void YGNodeStyleSetMinWidth(YGNodeRef node, float minWidth); 240 | WIN_EXPORT void YGNodeStyleSetMinWidthPercent(YGNodeRef node, float minWidth); 241 | WIN_EXPORT YGValue YGNodeStyleGetMinWidth(YGNodeConstRef node); 242 | 243 | WIN_EXPORT void YGNodeStyleSetMinHeight(YGNodeRef node, float minHeight); 244 | WIN_EXPORT void YGNodeStyleSetMinHeightPercent(YGNodeRef node, float minHeight); 245 | WIN_EXPORT YGValue YGNodeStyleGetMinHeight(YGNodeConstRef node); 246 | 247 | WIN_EXPORT void YGNodeStyleSetMaxWidth(YGNodeRef node, float maxWidth); 248 | WIN_EXPORT void YGNodeStyleSetMaxWidthPercent(YGNodeRef node, float maxWidth); 249 | WIN_EXPORT YGValue YGNodeStyleGetMaxWidth(YGNodeConstRef node); 250 | 251 | WIN_EXPORT void YGNodeStyleSetMaxHeight(YGNodeRef node, float maxHeight); 252 | WIN_EXPORT void YGNodeStyleSetMaxHeightPercent(YGNodeRef node, float maxHeight); 253 | WIN_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef node); 254 | 255 | // Yoga specific properties, not compatible with flexbox specification Aspect 256 | // ratio control the size of the undefined dimension of a node. Aspect ratio is 257 | // encoded as a floating point value width/height. e.g. A value of 2 leads to a 258 | // node with a width twice the size of its height while a value of 0.5 gives the 259 | // opposite effect. 260 | // 261 | // - On a node with a set width/height aspect ratio control the size of the 262 | // unset dimension 263 | // - On a node with a set flex basis aspect ratio controls the size of the node 264 | // in the cross axis if unset 265 | // - On a node with a measure function aspect ratio works as though the measure 266 | // function measures the flex basis 267 | // - On a node with flex grow/shrink aspect ratio controls the size of the node 268 | // in the cross axis if unset 269 | // - Aspect ratio takes min/max dimensions into account 270 | WIN_EXPORT void YGNodeStyleSetAspectRatio(YGNodeRef node, float aspectRatio); 271 | WIN_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node); 272 | 273 | WIN_EXPORT float YGNodeLayoutGetLeft(YGNodeRef node); 274 | WIN_EXPORT float YGNodeLayoutGetTop(YGNodeRef node); 275 | WIN_EXPORT float YGNodeLayoutGetRight(YGNodeRef node); 276 | WIN_EXPORT float YGNodeLayoutGetBottom(YGNodeRef node); 277 | WIN_EXPORT float YGNodeLayoutGetWidth(YGNodeRef node); 278 | WIN_EXPORT float YGNodeLayoutGetHeight(YGNodeRef node); 279 | WIN_EXPORT YGDirection YGNodeLayoutGetDirection(YGNodeRef node); 280 | WIN_EXPORT bool YGNodeLayoutGetHadOverflow(YGNodeRef node); 281 | bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(YGNodeRef node); 282 | 283 | // Get the computed values for these nodes after performing layout. If they were 284 | // set using point values then the returned value will be the same as 285 | // YGNodeStyleGetXXX. However if they were set using a percentage value then the 286 | // returned value is the computed value used during layout. 287 | WIN_EXPORT float YGNodeLayoutGetMargin(YGNodeRef node, YGEdge edge); 288 | WIN_EXPORT float YGNodeLayoutGetBorder(YGNodeRef node, YGEdge edge); 289 | WIN_EXPORT float YGNodeLayoutGetPadding(YGNodeRef node, YGEdge edge); 290 | 291 | WIN_EXPORT void YGConfigSetLogger(YGConfigRef config, YGLogger logger); 292 | WIN_EXPORT void YGAssert(bool condition, const char* message); 293 | WIN_EXPORT void YGAssertWithNode( 294 | YGNodeRef node, 295 | bool condition, 296 | const char* message); 297 | WIN_EXPORT void YGAssertWithConfig( 298 | YGConfigRef config, 299 | bool condition, 300 | const char* message); 301 | // Set this to number of pixels in 1 point to round calculation results If you 302 | // want to avoid rounding - set PointScaleFactor to 0 303 | WIN_EXPORT void YGConfigSetPointScaleFactor( 304 | YGConfigRef config, 305 | float pixelsInPoint); 306 | void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour( 307 | YGConfigRef config, 308 | bool shouldDiffLayout); 309 | 310 | // Yoga previously had an error where containers would take the maximum space 311 | // possible instead of the minimum like they are supposed to. In practice this 312 | // resulted in implicit behaviour similar to align-self: stretch; Because this 313 | // was such a long-standing bug we must allow legacy users to switch back to 314 | // this behaviour. 315 | WIN_EXPORT void YGConfigSetUseLegacyStretchBehaviour( 316 | YGConfigRef config, 317 | bool useLegacyStretchBehaviour); 318 | 319 | // YGConfig 320 | WIN_EXPORT YGConfigRef YGConfigNew(void); 321 | WIN_EXPORT void YGConfigFree(YGConfigRef config); 322 | WIN_EXPORT void YGConfigCopy(YGConfigRef dest, YGConfigRef src); 323 | WIN_EXPORT int32_t YGConfigGetInstanceCount(void); 324 | 325 | WIN_EXPORT void YGConfigSetExperimentalFeatureEnabled( 326 | YGConfigRef config, 327 | YGExperimentalFeature feature, 328 | bool enabled); 329 | WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled( 330 | YGConfigRef config, 331 | YGExperimentalFeature feature); 332 | 333 | // Using the web defaults is the prefered configuration for new projects. Usage 334 | // of non web defaults should be considered as legacy. 335 | WIN_EXPORT void YGConfigSetUseWebDefaults(YGConfigRef config, bool enabled); 336 | WIN_EXPORT bool YGConfigGetUseWebDefaults(YGConfigRef config); 337 | 338 | WIN_EXPORT void YGConfigSetCloneNodeFunc( 339 | YGConfigRef config, 340 | YGCloneNodeFunc callback); 341 | 342 | // Export only for C# 343 | WIN_EXPORT YGConfigRef YGConfigGetDefault(void); 344 | 345 | WIN_EXPORT void YGConfigSetContext(YGConfigRef config, void* context); 346 | WIN_EXPORT void* YGConfigGetContext(YGConfigRef config); 347 | 348 | WIN_EXPORT float YGRoundValueToPixelGrid( 349 | float value, 350 | float pointScaleFactor, 351 | bool forceCeil, 352 | bool forceFloor); 353 | 354 | YG_EXTERN_C_END 355 | 356 | #ifdef __cplusplus 357 | 358 | #include 359 | #include 360 | 361 | // Calls f on each node in the tree including the given node argument. 362 | void YGTraversePreOrder( 363 | YGNodeRef node, 364 | std::function&& f); 365 | 366 | void YGNodeSetChildren(YGNodeRef owner, const std::vector& children); 367 | 368 | #endif 369 | -------------------------------------------------------------------------------- /third_party/yoga/event/event.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "event.h" 8 | #include 9 | #include 10 | #include 11 | 12 | namespace facebook { 13 | namespace yoga { 14 | 15 | namespace { 16 | 17 | struct Node { 18 | std::function subscriber = nullptr; 19 | Node* next = nullptr; 20 | 21 | Node(std::function&& subscriber) 22 | : subscriber{std::move(subscriber)} {} 23 | }; 24 | 25 | std::atomic subscribers{nullptr}; 26 | 27 | Node* push(Node* newHead) { 28 | Node* oldHead; 29 | do { 30 | oldHead = subscribers.load(std::memory_order_relaxed); 31 | if (newHead != nullptr) { 32 | newHead->next = oldHead; 33 | } 34 | } while (!subscribers.compare_exchange_weak( 35 | oldHead, newHead, std::memory_order_release, std::memory_order_relaxed)); 36 | return oldHead; 37 | } 38 | 39 | } // namespace 40 | 41 | void Event::reset() { 42 | auto head = push(nullptr); 43 | while (head != nullptr) { 44 | auto current = head; 45 | head = head->next; 46 | delete current; 47 | } 48 | } 49 | 50 | void Event::subscribe(std::function&& subscriber) { 51 | push(new Node{std::move(subscriber)}); 52 | } 53 | 54 | void Event::publish(const YGNode& node, Type eventType, const Data& eventData) { 55 | for (auto subscriber = subscribers.load(std::memory_order_relaxed); 56 | subscriber != nullptr; 57 | subscriber = subscriber->next) { 58 | subscriber->subscriber(node, eventType, eventData); 59 | } 60 | } 61 | 62 | } // namespace yoga 63 | } // namespace facebook 64 | -------------------------------------------------------------------------------- /third_party/yoga/event/event.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include "third_party/yoga/YGEnums.h" 12 | #include "third_party/yoga/YGMarker.h" 13 | 14 | struct YGConfig; 15 | struct YGNode; 16 | 17 | namespace facebook { 18 | namespace yoga { 19 | 20 | enum LayoutType : int { 21 | kLayout = 0, 22 | kMeasure = 1, 23 | kCachedLayout = 2, 24 | kCachedMeasure = 3 25 | }; 26 | 27 | struct Event { 28 | enum Type { 29 | NodeAllocation, 30 | NodeDeallocation, 31 | NodeLayout, 32 | LayoutPassStart, 33 | LayoutPassEnd, 34 | MeasureCallbackStart, 35 | MeasureCallbackEnd, 36 | }; 37 | class Data; 38 | using Subscriber = void(const YGNode&, Type, Data); 39 | using Subscribers = std::vector>; 40 | 41 | template 42 | struct TypedData {}; 43 | 44 | class Data { 45 | const void* data_; 46 | 47 | public: 48 | template 49 | Data(const TypedData& data) : data_{&data} {} 50 | 51 | template 52 | const TypedData& get() const { 53 | return *static_cast*>(data_); 54 | }; 55 | }; 56 | 57 | static void reset(); 58 | 59 | static void subscribe(std::function&& subscriber); 60 | 61 | template 62 | static void publish(const YGNode& node, const TypedData& eventData = {}) { 63 | #ifdef YG_ENABLE_EVENTS 64 | publish(node, E, Data{eventData}); 65 | #endif 66 | } 67 | 68 | template 69 | static void publish(const YGNode* node, const TypedData& eventData = {}) { 70 | publish(*node, eventData); 71 | } 72 | 73 | private: 74 | static void publish(const YGNode&, Type, const Data&); 75 | }; 76 | 77 | template <> 78 | struct Event::TypedData { 79 | YGConfig* config; 80 | }; 81 | 82 | template <> 83 | struct Event::TypedData { 84 | YGConfig* config; 85 | }; 86 | 87 | template <> 88 | struct Event::TypedData { 89 | void* layoutContext; 90 | }; 91 | 92 | template <> 93 | struct Event::TypedData { 94 | void* layoutContext; 95 | YGMarkerLayoutData* layoutData; 96 | }; 97 | 98 | template <> 99 | struct Event::TypedData { 100 | void* layoutContext; 101 | float width; 102 | YGMeasureMode widthMeasureMode; 103 | float height; 104 | YGMeasureMode heightMeasureMode; 105 | float measuredWidth; 106 | float measuredHeight; 107 | }; 108 | 109 | template <> 110 | struct Event::TypedData { 111 | LayoutType layoutType; 112 | void* layoutContext; 113 | }; 114 | 115 | } // namespace yoga 116 | } // namespace facebook 117 | -------------------------------------------------------------------------------- /third_party/yoga/instrumentation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "YGConfig.h" 8 | #include "YGMarker.h" 9 | #include "YGNode.h" 10 | 11 | namespace facebook { 12 | namespace yoga { 13 | namespace marker { 14 | 15 | template 16 | class MarkerSection { 17 | private: 18 | using Data = detail::MarkerData; 19 | 20 | public: 21 | MarkerSection(YGNodeRef node) : MarkerSection{node, node->getConfig()} {} 22 | void end() { 23 | if (endMarker_) { 24 | endMarker_(MarkerType, node_, markerData(&data), userData_); 25 | endMarker_ = nullptr; 26 | } 27 | } 28 | ~MarkerSection() { end(); } 29 | 30 | typename Data::type data = {}; 31 | 32 | template 33 | static Ret wrap( 34 | YGNodeRef node, 35 | Ret (YGNode::*method)(Args...), 36 | Args... args) { 37 | MarkerSection section{node}; 38 | return (node->*method)(std::forward(args)...); 39 | } 40 | 41 | private: 42 | decltype(YGMarkerCallbacks{}.endMarker) endMarker_; 43 | YGNodeRef node_; 44 | void* userData_; 45 | 46 | MarkerSection(YGNodeRef node, YGConfigRef config) 47 | : MarkerSection{node, config ? &config->markerCallbacks : nullptr} {} 48 | MarkerSection(YGNodeRef node, YGMarkerCallbacks* callbacks) 49 | : endMarker_{callbacks ? callbacks->endMarker : nullptr}, 50 | node_{node}, 51 | userData_{ 52 | callbacks && callbacks->startMarker 53 | ? callbacks->startMarker(MarkerType, node, markerData(&data)) 54 | : nullptr} {} 55 | 56 | static YGMarkerData markerData(typename Data::type* d) { 57 | YGMarkerData markerData = {}; 58 | Data::get(markerData) = d; 59 | return markerData; 60 | } 61 | }; 62 | 63 | } // namespace marker 64 | } // namespace yoga 65 | } // namespace facebook 66 | -------------------------------------------------------------------------------- /third_party/yoga/log.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "log.h" 8 | 9 | #include "Yoga.h" 10 | #include "YGConfig.h" 11 | #include "YGNode.h" 12 | 13 | namespace facebook { 14 | namespace yoga { 15 | namespace detail { 16 | 17 | namespace { 18 | 19 | void vlog( 20 | YGConfig* config, 21 | YGNode* node, 22 | YGLogLevel level, 23 | void* context, 24 | const char* format, 25 | va_list args) { 26 | YGConfig* logConfig = config != nullptr ? config : YGConfigGetDefault(); 27 | logConfig->log(logConfig, node, level, context, format, args); 28 | 29 | if (level == YGLogLevelFatal) { 30 | abort(); 31 | } 32 | } 33 | } // namespace 34 | 35 | void Log::log( 36 | YGNode* node, 37 | YGLogLevel level, 38 | void* context, 39 | const char* format, 40 | ...) noexcept { 41 | va_list args; 42 | va_start(args, format); 43 | vlog( 44 | node == nullptr ? nullptr : node->getConfig(), 45 | node, 46 | level, 47 | context, 48 | format, 49 | args); 50 | va_end(args); 51 | } 52 | 53 | void Log::log( 54 | YGConfig* config, 55 | YGLogLevel level, 56 | void* context, 57 | const char* format, 58 | ...) noexcept { 59 | va_list args; 60 | va_start(args, format); 61 | vlog(config, nullptr, level, context, format, args); 62 | va_end(args); 63 | } 64 | 65 | } // namespace detail 66 | } // namespace yoga 67 | } // namespace facebook 68 | -------------------------------------------------------------------------------- /third_party/yoga/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #pragma once 8 | 9 | #include "YGEnums.h" 10 | 11 | struct YGNode; 12 | struct YGConfig; 13 | 14 | namespace facebook { 15 | namespace yoga { 16 | 17 | namespace detail { 18 | 19 | struct Log { 20 | static void log( 21 | YGNode* node, 22 | YGLogLevel level, 23 | void*, 24 | const char* message, 25 | ...) noexcept; 26 | 27 | static void log( 28 | YGConfig* config, 29 | YGLogLevel level, 30 | void*, 31 | const char* format, 32 | ...) noexcept; 33 | }; 34 | 35 | } // namespace detail 36 | } // namespace yoga 37 | } // namespace facebook 38 | -------------------------------------------------------------------------------- /third_party/yoga/util/BUCK: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | load("//tools/build_defs/oss:yoga_defs.bzl", "GTEST_TARGET", "LIBRARY_COMPILER_FLAGS", "yoga_cxx_library", "yoga_cxx_test") 6 | 7 | _TESTS = glob(["*Test.cpp"]) 8 | 9 | yoga_cxx_library( 10 | name = "util", 11 | srcs = glob( 12 | ["*.cpp"], 13 | exclude = _TESTS, 14 | ), 15 | header_namespace = "yoga/util", 16 | exported_headers = glob(["*.h"]), 17 | compiler_flags = LIBRARY_COMPILER_FLAGS, 18 | tests = [":test"], 19 | visibility = ["PUBLIC"], 20 | ) 21 | 22 | yoga_cxx_test( 23 | name = "test", 24 | srcs = _TESTS, 25 | compiler_flags = LIBRARY_COMPILER_FLAGS, 26 | deps = [ 27 | ":util", 28 | GTEST_TARGET, 29 | ], 30 | ) 31 | -------------------------------------------------------------------------------- /third_party/yoga/util/SingleWriterValueList.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include "SingleWriterValueList.h" 8 | 9 | namespace facebook { 10 | namespace yoga { 11 | namespace detail { 12 | 13 | void* FreeList::getRaw() { 14 | if (free_.size() == 0) 15 | return nullptr; 16 | 17 | auto ptr = free_.top(); 18 | free_.pop(); 19 | return ptr; 20 | } 21 | 22 | void FreeList::put(std::mutex& mutex, void* ptr) { 23 | std::lock_guard lock{mutex}; 24 | free_.push(ptr); 25 | } 26 | 27 | FreeList::FreeList() = default; 28 | FreeList::~FreeList() = default; 29 | 30 | } // namespace detail 31 | } // namespace yoga 32 | } // namespace facebook 33 | -------------------------------------------------------------------------------- /third_party/yoga/util/SingleWriterValueList.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace facebook { 15 | namespace yoga { 16 | 17 | namespace detail { 18 | 19 | class FreeList { 20 | std::stack free_; 21 | void* getRaw(); 22 | 23 | public: 24 | FreeList(); 25 | ~FreeList(); 26 | 27 | void put(std::mutex&, void*); 28 | 29 | template 30 | T* get() { 31 | return static_cast(getRaw()); 32 | } 33 | }; 34 | 35 | } // namespace detail 36 | 37 | /// SingleWriterValueList is a data structure that holds a list of values. Each 38 | /// value can be borrowed for exclusive writing, and will not be exposed to 39 | /// another borrower until returned. 40 | /// Additionaly, the whole list of values can be accessed for reading via const 41 | /// iterators. Read consistency depends on CPU internals, i.e. whether values 42 | /// are written to memory atomically. 43 | /// 44 | /// A typical usage scenario would be a set of threads, where each thread 45 | /// borrows a value for lock free writing, e.g. as a thread local variable. This 46 | /// avoids the usage of atomics, or locking of shared memory, which both can 47 | /// lead to increased latency due to CPU cache flushes and waits. 48 | /// 49 | /// Values are heap allocated (via forward_list), which typically will avoid 50 | /// multiple values being allocated in the same CPU cache line, which would also 51 | /// lead to cache flushing. 52 | /// 53 | /// SingleWriterValueList never deallocates, to guarantee the validity of 54 | /// references and iterators. However, memory returned by a borrower can be 55 | /// borrowed again. 56 | /// 57 | /// SingleWriterValueList supports return policies as second template parameter, 58 | /// i.e. an optional mutation of values after a borrower returns them. The 59 | /// default policy is to do nothing. SingleWriterValueList::resetPolicy is a 60 | /// convenience method that will move assign the default value of a type. 61 | /// 62 | /// Example: 63 | /// 64 | /// static SingleWriterValueList counters; 65 | /// thread_local auto localCounter = counters.borrow(); 66 | /// 67 | /// /* per thread */ 68 | /// localCounter =+ n; 69 | /// 70 | /// /* anywhere */ 71 | /// std::accumulate(counters.begin(), counters.end(), 0); 72 | /// 73 | template 74 | class SingleWriterValueList { 75 | std::forward_list values_{}; 76 | std::mutex acquireMutex_{}; 77 | detail::FreeList freeValuesList_{}; 78 | 79 | T* allocValue() { 80 | values_.emplace_front(); 81 | return &values_.front(); 82 | } 83 | 84 | void returnRef(T* value) { 85 | if (ReturnPolicy != nullptr) { 86 | ReturnPolicy(*value); 87 | } 88 | freeValuesList_.put(acquireMutex_, value); 89 | } 90 | 91 | public: 92 | using const_iterator = decltype(values_.cbegin()); 93 | 94 | /// RAII representation of a single value, borrowed for exclusive writing. 95 | /// Instances cannot be copied, and will return the borrowed value to the 96 | /// owner upon destruction. 97 | class Borrowed { 98 | T* value_; 99 | SingleWriterValueList* owner_; 100 | 101 | public: 102 | Borrowed(T* value, SingleWriterValueList* owner) 103 | : value_{value}, owner_{owner} {} 104 | ~Borrowed() { 105 | if (owner_ != nullptr && value_ != nullptr) { 106 | owner_->returnRef(value_); 107 | } 108 | } 109 | 110 | Borrowed(Borrowed&& other) = default; 111 | Borrowed& operator=(Borrowed&& other) = default; 112 | 113 | // no copies allowed 114 | Borrowed(const Borrowed&) = delete; 115 | Borrowed& operator=(const Borrowed&) = delete; 116 | 117 | T& get() { return *value_; } 118 | T& operator*() { return get(); } 119 | }; 120 | 121 | Borrowed borrow() { 122 | std::lock_guard lock{acquireMutex_}; 123 | T* value = freeValuesList_.get(); 124 | return {value != nullptr ? value : allocValue(), this}; 125 | } 126 | 127 | const_iterator cbegin() const { return values_.cbegin(); }; 128 | const_iterator cend() const { return values_.cend(); }; 129 | const_iterator begin() const { return cbegin(); }; 130 | const_iterator end() const { return cend(); }; 131 | 132 | static void resetPolicy(T& value) { value = std::move(T{}); } 133 | }; 134 | 135 | } // namespace yoga 136 | } // namespace facebook 137 | -------------------------------------------------------------------------------- /third_party/yoga/util/SingleWriterValueListTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the LICENSE 5 | * file in the root directory of this source tree. 6 | */ 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace facebook { 15 | namespace yoga { 16 | 17 | static_assert( 18 | !std::is_copy_constructible>::value, 19 | "SingleWriterValueList must not be copyable"); 20 | static_assert( 21 | !std::is_copy_assignable>::value, 22 | "SingleWriterValueList must not be copyable"); 23 | static_assert( 24 | !std::is_copy_constructible::Borrowed>::value, 25 | "SingleWriterValueList::Borrowed must not be copyable"); 26 | static_assert( 27 | !std::is_copy_assignable::Borrowed>::value, 28 | "SingleWriterValueList::Borrowed must not be copyable"); 29 | static_assert( 30 | std::is_move_constructible::Borrowed>::value, 31 | "SingleWriterValueList::Borrowed must be movable"); 32 | static_assert( 33 | std::is_move_assignable::Borrowed>::value, 34 | "SingleWriterValueList::Borrowed must be movable"); 35 | 36 | TEST(SingleWriterValueList, borrowsAreExclusive) { 37 | SingleWriterValueList x{}; 38 | 39 | auto a = x.borrow(); 40 | auto b = x.borrow(); 41 | 42 | ASSERT_NE(&a.get(), &b.get()); 43 | } 44 | 45 | TEST(SingleWriterValueList, borrowsSupportDereference) { 46 | SingleWriterValueList x{}; 47 | 48 | auto a = x.borrow(); 49 | *a = 123; 50 | 51 | ASSERT_EQ(*a, 123); 52 | } 53 | 54 | TEST(SingleWriterValueList, borrowsHaveGetMethod) { 55 | SingleWriterValueList x{}; 56 | 57 | auto a = x.borrow(); 58 | a.get() = 123; 59 | 60 | ASSERT_EQ(a.get(), 123); 61 | } 62 | 63 | TEST(SingleWriterValueList, exposesBorrowsViaIterator) { 64 | SingleWriterValueList x{}; 65 | 66 | auto a = x.borrow(); 67 | auto b = x.borrow(); 68 | 69 | *a = 12; 70 | *b = 34; 71 | 72 | int sum = 0; 73 | for (auto& i : x) { 74 | sum += i; 75 | } 76 | ASSERT_EQ(sum, 12 + 34); 77 | } 78 | 79 | TEST(SingleWriterValueList, exposesBorrowsViaConstIterator) { 80 | SingleWriterValueList x{}; 81 | 82 | auto a = x.borrow(); 83 | auto b = x.borrow(); 84 | 85 | *a = 12; 86 | *b = 34; 87 | 88 | ASSERT_EQ(std::accumulate(x.cbegin(), x.cend(), 0), 12 + 34); 89 | } 90 | 91 | TEST(SingleWriterValueList, doesNotDeallocateReturnedBorrows) { 92 | SingleWriterValueList x{}; 93 | 94 | std::unordered_set values; 95 | { 96 | auto a = x.borrow(); 97 | auto b = x.borrow(); 98 | values.insert(&a.get()); 99 | values.insert(&b.get()); 100 | } 101 | 102 | auto it = x.begin(); 103 | 104 | ASSERT_NE(it, x.end()); 105 | ASSERT_NE(values.find(&*it), values.end()); 106 | 107 | ASSERT_NE(++it, x.end()); 108 | ASSERT_NE(values.find(&*it), values.end()); 109 | } 110 | 111 | TEST(SingleWriterValueList, reusesReturnedBorrows) { 112 | SingleWriterValueList x{}; 113 | 114 | int* firstBorrow; 115 | { 116 | auto a = x.borrow(); 117 | firstBorrow = &a.get(); 118 | } 119 | 120 | auto b = x.borrow(); 121 | 122 | ASSERT_EQ(&b.get(), firstBorrow); 123 | } 124 | 125 | TEST(SingleWriterValueList, keepsValuesAfterReturning) { 126 | SingleWriterValueList x{}; 127 | 128 | { 129 | auto a = x.borrow(); 130 | *a = 123; 131 | } 132 | 133 | ASSERT_EQ(*x.begin(), 123); 134 | } 135 | 136 | static void addOne(int& v) { 137 | v += 1; 138 | } 139 | 140 | TEST(SingleWriterValueList, allowsCustomReturnPolicy) { 141 | SingleWriterValueList x{}; 142 | 143 | { 144 | auto a = x.borrow(); 145 | *a = 123; 146 | } 147 | 148 | ASSERT_EQ(*x.begin(), 124); 149 | } 150 | 151 | TEST(SingleWriterValueList, hasConvenienceResetPolicy) { 152 | SingleWriterValueList::resetPolicy> x{}; 153 | 154 | { 155 | auto a = x.borrow(); 156 | *a = 123; 157 | } 158 | 159 | ASSERT_EQ(*x.begin(), 0); 160 | } 161 | 162 | } // namespace yoga 163 | } // namespace facebook 164 | --------------------------------------------------------------------------------