@alchemy.run/sigil 0.0.0-alpha.1 → 0.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +299 -299
- package/dist/ansi.d.ts +223 -0
- package/dist/ansi.js +2 -0
- package/dist/{devtools-QpCMm9JH.mjs → devtools-BhYGjb7h.js} +1 -1
- package/dist/index-DDVME65c.d.ts +919 -0
- package/dist/index.d.ts +1657 -0
- package/dist/index.js +4643 -0
- package/dist/sgr-CMfEpjSk.d.ts +91 -0
- package/dist/truncate-CBiyyZzw.js +2156 -0
- package/dist/yoga-5jKhYCJC.js +3465 -0
- package/dist/yoga.d.ts +2 -0
- package/dist/yoga.js +2 -0
- package/package.json +37 -17
- package/src/ansi/chalk.ts +179 -0
- package/src/ansi/cursor.ts +48 -0
- package/src/ansi/east-asian-width.ts +215 -0
- package/src/ansi/escapes.ts +128 -0
- package/src/ansi/index.ts +27 -0
- package/src/ansi/sgr.ts +237 -0
- package/src/ansi/slice.ts +43 -0
- package/src/ansi/string-width.ts +236 -0
- package/src/ansi/strip.ts +33 -0
- package/src/ansi/supports-color.ts +213 -0
- package/src/ansi/tokenize.ts +453 -0
- package/src/ansi/truncate.ts +194 -0
- package/src/ansi/widest-line.ts +12 -0
- package/src/ansi/wrap.ts +766 -0
- package/src/ansi-tokenizer.ts +510 -0
- package/src/auto-bind.ts +41 -0
- package/src/boxes.ts +100 -0
- package/src/code-excerpt.ts +39 -0
- package/src/colorize.ts +60 -0
- package/src/components/AccessibilityContext.ts +5 -0
- package/src/components/AnimationContext.ts +24 -0
- package/src/components/App.tsx +781 -0
- package/src/components/AppContext.ts +111 -0
- package/src/components/BackgroundContext.ts +8 -0
- package/src/components/Box.tsx +116 -0
- package/src/components/CursorContext.ts +19 -0
- package/src/components/ErrorBoundary.tsx +38 -0
- package/src/components/ErrorOverview.tsx +133 -0
- package/src/components/FocusContext.ts +30 -0
- package/src/components/Newline.tsx +15 -0
- package/src/components/Spacer.tsx +10 -0
- package/src/components/Static.tsx +59 -0
- package/src/components/StderrContext.ts +26 -0
- package/src/components/StdinContext.ts +49 -0
- package/src/components/StdoutContext.ts +28 -0
- package/src/components/Text.tsx +144 -0
- package/src/components/Transform.tsx +37 -0
- package/src/cursor-position.ts +103 -0
- package/src/devtools-window-polyfill.ts +73 -0
- package/src/devtools.ts +43 -0
- package/src/dom.ts +292 -0
- package/src/get-max-width.ts +11 -0
- package/src/global.d.ts +36 -0
- package/src/hooks/use-animation.ts +142 -0
- package/src/hooks/use-app.ts +8 -0
- package/src/hooks/use-box-metrics.ts +134 -0
- package/src/hooks/use-cursor.ts +33 -0
- package/src/hooks/use-focus-manager.ts +62 -0
- package/src/hooks/use-focus.ts +83 -0
- package/src/hooks/use-input.ts +267 -0
- package/src/hooks/use-is-screen-reader-enabled.ts +12 -0
- package/src/hooks/use-paste.ts +78 -0
- package/src/hooks/use-stderr.ts +8 -0
- package/src/hooks/use-stdin.ts +10 -0
- package/src/hooks/use-stdout.ts +8 -0
- package/src/hooks/use-window-size.ts +41 -0
- package/src/indent-string.ts +16 -0
- package/src/index.ts +44 -0
- package/src/ink.tsx +1506 -0
- package/src/input-parser.ts +283 -0
- package/src/instances.ts +9 -0
- package/src/is-in-ci.ts +7 -0
- package/src/kitty-keyboard.ts +57 -0
- package/src/log-update.ts +370 -0
- package/src/measure-element.ts +62 -0
- package/src/measure-text.ts +31 -0
- package/src/output.ts +308 -0
- package/src/parse-keypress.ts +516 -0
- package/src/parse-stack-line.ts +139 -0
- package/src/patch-console.ts +62 -0
- package/src/quick-lru.ts +85 -0
- package/src/reconciler.ts +451 -0
- package/src/render-background.ts +38 -0
- package/src/render-border.ts +134 -0
- package/src/render-node-to-output.ts +191 -0
- package/src/render-to-string.ts +131 -0
- package/src/render.ts +276 -0
- package/src/renderer.ts +73 -0
- package/src/sanitize-ansi.ts +33 -0
- package/src/signal-exit.ts +107 -0
- package/src/squash-text-nodes.ts +40 -0
- package/src/stream.ts +30 -0
- package/src/styles.ts +748 -0
- package/src/terminal-size.ts +57 -0
- package/src/throttle.ts +73 -0
- package/src/types.ts +15 -0
- package/src/utils.ts +40 -0
- package/src/wrap-text.ts +50 -0
- package/src/write-synchronized.ts +9 -0
- package/src/yoga/config.ts +57 -0
- package/src/yoga/core/absoluteLayout.ts +626 -0
- package/src/yoga/core/baseline.ts +66 -0
- package/src/yoga/core/cache.ts +136 -0
- package/src/yoga/core/calculateLayout.ts +2920 -0
- package/src/yoga/core/config.ts +104 -0
- package/src/yoga/core/flexLine.ts +177 -0
- package/src/yoga/core/helpers.ts +293 -0
- package/src/yoga/core/layoutResults.ts +167 -0
- package/src/yoga/core/node.ts +611 -0
- package/src/yoga/core/numeric.ts +44 -0
- package/src/yoga/core/pixelGrid.ts +151 -0
- package/src/yoga/core/style.ts +887 -0
- package/src/yoga/core/types.ts +224 -0
- package/src/yoga/generated/YGEnums.ts +263 -0
- package/src/yoga/index.ts +19 -0
- package/src/yoga/node.ts +1140 -0
- package/dist/index.d.mts +0 -2379
- package/dist/index.mjs +0 -10072
|
@@ -0,0 +1,2920 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Derived from Yoga. See THIRD_PARTY_NOTICES.md.
|
|
3
|
+
|
|
4
|
+
// Port of yoga/algorithm/CalculateLayout.cpp. The event system and
|
|
5
|
+
// LayoutPassReason-keyed instrumentation are reduced to plain counters.
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
Align,
|
|
9
|
+
Dimension,
|
|
10
|
+
Direction,
|
|
11
|
+
Display,
|
|
12
|
+
Edge,
|
|
13
|
+
Errata,
|
|
14
|
+
ExperimentalFeature,
|
|
15
|
+
FlexDirection,
|
|
16
|
+
Gutter,
|
|
17
|
+
Justify,
|
|
18
|
+
MeasureMode,
|
|
19
|
+
Overflow,
|
|
20
|
+
PositionType,
|
|
21
|
+
Wrap,
|
|
22
|
+
} from "../generated/YGEnums.ts";
|
|
23
|
+
import { layoutAbsoluteDescendants } from "./absoluteLayout.ts";
|
|
24
|
+
import { calculateBaseline, isBaselineLayout } from "./baseline.ts";
|
|
25
|
+
import { canUseCachedMeasurement } from "./cache.ts";
|
|
26
|
+
import { type FlexLine, calculateFlexLine } from "./flexLine.ts";
|
|
27
|
+
import {
|
|
28
|
+
PhysicalEdge,
|
|
29
|
+
SizingMode,
|
|
30
|
+
boundAxis,
|
|
31
|
+
boundAxisWithinMinAndMax,
|
|
32
|
+
dimension,
|
|
33
|
+
fallbackAlignment,
|
|
34
|
+
fallbackJustification,
|
|
35
|
+
flexStartEdge,
|
|
36
|
+
isColumn,
|
|
37
|
+
isRow,
|
|
38
|
+
measureMode,
|
|
39
|
+
needsTrailingPosition,
|
|
40
|
+
paddingAndBorderForAxis,
|
|
41
|
+
resolveChildAlignment,
|
|
42
|
+
resolveCrossDirection,
|
|
43
|
+
resolveDirection,
|
|
44
|
+
setChildTrailingPosition,
|
|
45
|
+
} from "./helpers.ts";
|
|
46
|
+
import { CachedMeasurement, LayoutResults } from "./layoutResults.ts";
|
|
47
|
+
import type { Node } from "./node.ts";
|
|
48
|
+
import { isDefined, isUndefined, inexactEquals, maxOrDefined, minOrDefined } from "./numeric.ts";
|
|
49
|
+
import { roundLayoutResultsToPixelGrid } from "./pixelGrid.ts";
|
|
50
|
+
import type { Style } from "./style.ts";
|
|
51
|
+
import type { StyleLength } from "./types.ts";
|
|
52
|
+
|
|
53
|
+
export const LayoutPassReason = {
|
|
54
|
+
Initial: 0,
|
|
55
|
+
AbsLayout: 1,
|
|
56
|
+
Stretch: 2,
|
|
57
|
+
MultilineStretch: 3,
|
|
58
|
+
FlexLayout: 4,
|
|
59
|
+
MeasureChild: 5,
|
|
60
|
+
AbsMeasureChild: 6,
|
|
61
|
+
FlexMeasure: 7,
|
|
62
|
+
} as const;
|
|
63
|
+
export type LayoutPassReason = (typeof LayoutPassReason)[keyof typeof LayoutPassReason];
|
|
64
|
+
|
|
65
|
+
export interface LayoutData {
|
|
66
|
+
layouts: number;
|
|
67
|
+
measures: number;
|
|
68
|
+
maxMeasureCache: number;
|
|
69
|
+
cachedLayouts: number;
|
|
70
|
+
cachedMeasures: number;
|
|
71
|
+
measureCallbacks: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function newLayoutData(): LayoutData {
|
|
75
|
+
return {
|
|
76
|
+
layouts: 0,
|
|
77
|
+
measures: 0,
|
|
78
|
+
maxMeasureCache: 0,
|
|
79
|
+
cachedLayouts: 0,
|
|
80
|
+
cachedMeasures: 0,
|
|
81
|
+
measureCallbacks: 0,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let gCurrentGenerationCount = 0;
|
|
86
|
+
|
|
87
|
+
function hasAutoHorizontalMargin(style: Style): boolean {
|
|
88
|
+
for (const direction of [Direction.LTR, Direction.RTL]) {
|
|
89
|
+
if (
|
|
90
|
+
style.flexStartMarginIsAuto(FlexDirection.Row, direction) ||
|
|
91
|
+
style.flexEndMarginIsAuto(FlexDirection.Row, direction)
|
|
92
|
+
) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function isColumnStretchEdge(owner: Node | null, child: Node | null): boolean {
|
|
100
|
+
if (owner === null || child === null) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const ownerStyle = owner.style;
|
|
104
|
+
const childStyle = child.style;
|
|
105
|
+
const childWidth = child.getProcessedDimension(Dimension.Width);
|
|
106
|
+
return (
|
|
107
|
+
ownerStyle.display() === Display.Flex &&
|
|
108
|
+
isColumn(ownerStyle.flexDirection()) &&
|
|
109
|
+
ownerStyle.flexWrap() === Wrap.NoWrap &&
|
|
110
|
+
childStyle.positionType() !== PositionType.Absolute &&
|
|
111
|
+
!isDefined(childStyle.aspectRatio()) &&
|
|
112
|
+
(childWidth.isAuto() || childWidth.isUndefined()) &&
|
|
113
|
+
!hasAutoHorizontalMargin(childStyle) &&
|
|
114
|
+
resolveChildAlignment(owner, child) === Align.Stretch
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isInColumnStretchScrollSubtree(node: Node): boolean {
|
|
119
|
+
let current: Node | null = node;
|
|
120
|
+
while (current !== null) {
|
|
121
|
+
let owner: Node | null = current.owner;
|
|
122
|
+
while (owner !== null && owner.style.display() === Display.Contents) {
|
|
123
|
+
owner = owner.owner;
|
|
124
|
+
}
|
|
125
|
+
if (owner === null || !isColumnStretchEdge(owner, current)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
if (owner.style.overflow() === Overflow.Scroll) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
current = owner;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isNonZeroLength(length: StyleLength): boolean {
|
|
137
|
+
return length.isAuto() || (isDefined(length.value) && length.value !== 0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function hasNonZeroVerticalSpacing(style: Style): boolean {
|
|
141
|
+
const verticalEdges = [Edge.Top, Edge.Bottom, Edge.Vertical, Edge.All];
|
|
142
|
+
for (const edge of verticalEdges) {
|
|
143
|
+
if (
|
|
144
|
+
isNonZeroLength(style.margin(edge)) ||
|
|
145
|
+
isNonZeroLength(style.padding(edge)) ||
|
|
146
|
+
isNonZeroLength(style.border(edge))
|
|
147
|
+
) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function hasPercentageLength(style: Style): boolean {
|
|
155
|
+
const edges = [
|
|
156
|
+
Edge.Left,
|
|
157
|
+
Edge.Top,
|
|
158
|
+
Edge.Right,
|
|
159
|
+
Edge.Bottom,
|
|
160
|
+
Edge.Start,
|
|
161
|
+
Edge.End,
|
|
162
|
+
Edge.Horizontal,
|
|
163
|
+
Edge.Vertical,
|
|
164
|
+
Edge.All,
|
|
165
|
+
];
|
|
166
|
+
for (const edge of edges) {
|
|
167
|
+
if (
|
|
168
|
+
style.margin(edge).isPercent() ||
|
|
169
|
+
style.position(edge).isPercent() ||
|
|
170
|
+
style.padding(edge).isPercent() ||
|
|
171
|
+
style.border(edge).isPercent()
|
|
172
|
+
) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for (const dim of [Dimension.Width, Dimension.Height]) {
|
|
178
|
+
if (
|
|
179
|
+
style.dimension(dim).isPercent() ||
|
|
180
|
+
style.minDimension(dim).isPercent() ||
|
|
181
|
+
style.maxDimension(dim).isPercent()
|
|
182
|
+
) {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
style.flexBasis().isPercent() ||
|
|
189
|
+
style.gap(Gutter.Column).isPercent() ||
|
|
190
|
+
style.gap(Gutter.Row).isPercent() ||
|
|
191
|
+
style.gap(Gutter.All).isPercent()
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function hasNonZeroFlex(node: Node): boolean {
|
|
196
|
+
const style = node.style;
|
|
197
|
+
const flex = style.flex();
|
|
198
|
+
const flexGrow = style.flexGrow();
|
|
199
|
+
const flexShrink = style.flexShrink();
|
|
200
|
+
const config = node.config;
|
|
201
|
+
const canGrow = isDefined(flexGrow) ? flexGrow !== 0 : isDefined(flex) && flex > 0;
|
|
202
|
+
const canShrink = isDefined(flexShrink)
|
|
203
|
+
? flexShrink !== 0
|
|
204
|
+
: config.useWebDefaults() || (isDefined(flex) && flex < 0);
|
|
205
|
+
return canGrow || canShrink;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function isHeightFitContentIndependent(node: Node): boolean {
|
|
209
|
+
const style = node.style;
|
|
210
|
+
const height = style.dimension(Dimension.Height);
|
|
211
|
+
const flexBasis = style.flexBasis();
|
|
212
|
+
const hasRelativePercentPosition =
|
|
213
|
+
style.position(Edge.Top).isPercent() ||
|
|
214
|
+
style.position(Edge.Bottom).isPercent() ||
|
|
215
|
+
style.position(Edge.Vertical).isPercent() ||
|
|
216
|
+
style.position(Edge.All).isPercent();
|
|
217
|
+
return (
|
|
218
|
+
!node.hasMeasureFunc() &&
|
|
219
|
+
!node.hasBaselineFunc() &&
|
|
220
|
+
!node.isReferenceBaseline_ &&
|
|
221
|
+
(height.isAuto() || height.isUndefined()) &&
|
|
222
|
+
style.minDimension(Dimension.Height).isUndefined() &&
|
|
223
|
+
style.maxDimension(Dimension.Height).isUndefined() &&
|
|
224
|
+
(flexBasis.isAuto() || flexBasis.isUndefined()) &&
|
|
225
|
+
!hasNonZeroFlex(node) &&
|
|
226
|
+
style.boxSizing() === 0 /* BoxSizing.BorderBox */ &&
|
|
227
|
+
!isDefined(style.aspectRatio()) &&
|
|
228
|
+
style.positionType() !== PositionType.Absolute &&
|
|
229
|
+
style.overflow() !== Overflow.Scroll &&
|
|
230
|
+
style.display() === Display.Flex &&
|
|
231
|
+
isColumn(style.flexDirection()) &&
|
|
232
|
+
style.alignItems() === Align.Stretch &&
|
|
233
|
+
(style.alignSelf() === Align.Auto || style.alignSelf() === Align.Stretch) &&
|
|
234
|
+
style.justifyContent() === Justify.FlexStart &&
|
|
235
|
+
style.flexWrap() === Wrap.NoWrap &&
|
|
236
|
+
!style.gap(Gutter.All).isDefined() &&
|
|
237
|
+
!style.gap(Gutter.Row).isDefined() &&
|
|
238
|
+
!hasRelativePercentPosition &&
|
|
239
|
+
!hasNonZeroVerticalSpacing(style) &&
|
|
240
|
+
!hasPercentageLength(style)
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function canSkipHeightFitContent(root: Node | null): boolean {
|
|
245
|
+
if (root === null) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const maxPendingNodes = 64;
|
|
250
|
+
const stack: Node[] = [root];
|
|
251
|
+
while (stack.length > 0) {
|
|
252
|
+
const node = stack.pop()!;
|
|
253
|
+
if (!isHeightFitContentIndependent(node)) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
for (const child of node.getLayoutChildren()) {
|
|
257
|
+
if (stack.length === maxPendingNodes) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
stack.push(child);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
interface ModeAndSize {
|
|
267
|
+
mode: SizingMode;
|
|
268
|
+
size: number;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Reusable in/out pairs for constrainMaxSizeForMode. Their values are always
|
|
272
|
+
// copied out before any recursion into calculateLayoutInternal, so a single
|
|
273
|
+
// pair per (width, height) role is safe despite the recursive algorithm.
|
|
274
|
+
const scratchModeA: ModeAndSize = { mode: SizingMode.StretchFit, size: 0 };
|
|
275
|
+
const scratchModeB: ModeAndSize = { mode: SizingMode.StretchFit, size: 0 };
|
|
276
|
+
|
|
277
|
+
export function constrainMaxSizeForMode(
|
|
278
|
+
node: Node,
|
|
279
|
+
direction: Direction,
|
|
280
|
+
axis: FlexDirection,
|
|
281
|
+
ownerAxisSize: number,
|
|
282
|
+
ownerWidth: number,
|
|
283
|
+
modeAndSize: ModeAndSize,
|
|
284
|
+
): void {
|
|
285
|
+
const maxSize =
|
|
286
|
+
node.style.resolvedMaxDimension(direction, dimension(axis), ownerAxisSize, ownerWidth) +
|
|
287
|
+
node.style.computeMarginForAxis(axis, ownerWidth);
|
|
288
|
+
switch (modeAndSize.mode) {
|
|
289
|
+
case SizingMode.StretchFit:
|
|
290
|
+
case SizingMode.FitContent:
|
|
291
|
+
modeAndSize.size =
|
|
292
|
+
isUndefined(maxSize) || modeAndSize.size < maxSize ? modeAndSize.size : maxSize;
|
|
293
|
+
break;
|
|
294
|
+
case SizingMode.MaxContent:
|
|
295
|
+
if (isDefined(maxSize)) {
|
|
296
|
+
modeAndSize.mode = SizingMode.FitContent;
|
|
297
|
+
modeAndSize.size = maxSize;
|
|
298
|
+
}
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function computeFlexBasisForChild(
|
|
304
|
+
node: Node,
|
|
305
|
+
child: Node,
|
|
306
|
+
width: number,
|
|
307
|
+
widthMode: SizingMode,
|
|
308
|
+
height: number,
|
|
309
|
+
ownerWidth: number,
|
|
310
|
+
ownerHeight: number,
|
|
311
|
+
heightMode: SizingMode,
|
|
312
|
+
direction: Direction,
|
|
313
|
+
layoutMarkerData: LayoutData,
|
|
314
|
+
depth: number,
|
|
315
|
+
generationCount: number,
|
|
316
|
+
): void {
|
|
317
|
+
const mainAxis = resolveDirection(node.style.flexDirection(), direction);
|
|
318
|
+
const isMainAxisRow = isRow(mainAxis);
|
|
319
|
+
const mainAxisSize = isMainAxisRow ? width : height;
|
|
320
|
+
const mainAxisOwnerSize = isMainAxisRow ? ownerWidth : ownerHeight;
|
|
321
|
+
|
|
322
|
+
let childWidth = NaN;
|
|
323
|
+
let childHeight = NaN;
|
|
324
|
+
let childWidthSizingMode: SizingMode;
|
|
325
|
+
let childHeightSizingMode: SizingMode;
|
|
326
|
+
|
|
327
|
+
const resolvedFlexBasis = child.resolveFlexBasis(
|
|
328
|
+
direction,
|
|
329
|
+
mainAxis,
|
|
330
|
+
mainAxisOwnerSize,
|
|
331
|
+
ownerWidth,
|
|
332
|
+
);
|
|
333
|
+
const isRowStyleDimDefined = child.hasDefiniteLength(Dimension.Width, ownerWidth);
|
|
334
|
+
const isColumnStyleDimDefined = child.hasDefiniteLength(Dimension.Height, ownerHeight);
|
|
335
|
+
|
|
336
|
+
const fixFlexBasisFitContent = node.config.isExperimentalFeatureEnabled(
|
|
337
|
+
ExperimentalFeature.FixFlexBasisFitContent,
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
const useResolvedFlexBasis = isDefined(resolvedFlexBasis) && isDefined(mainAxisSize);
|
|
341
|
+
|
|
342
|
+
if (useResolvedFlexBasis) {
|
|
343
|
+
if (
|
|
344
|
+
isUndefined(child.layout.computedFlexBasis) ||
|
|
345
|
+
(child.config.isExperimentalFeatureEnabled(ExperimentalFeature.WebFlexBasis) &&
|
|
346
|
+
child.layout.computedFlexBasisGeneration !== generationCount)
|
|
347
|
+
) {
|
|
348
|
+
const paddingAndBorder = paddingAndBorderForAxis(child, mainAxis, direction, ownerWidth);
|
|
349
|
+
child.setLayoutComputedFlexBasis(maxOrDefined(resolvedFlexBasis, paddingAndBorder));
|
|
350
|
+
}
|
|
351
|
+
} else if (isMainAxisRow && isRowStyleDimDefined) {
|
|
352
|
+
// The width is definite, so use that as the flex basis.
|
|
353
|
+
const paddingAndBorder = paddingAndBorderForAxis(
|
|
354
|
+
child,
|
|
355
|
+
FlexDirection.Row,
|
|
356
|
+
direction,
|
|
357
|
+
ownerWidth,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
child.setLayoutComputedFlexBasis(
|
|
361
|
+
maxOrDefined(
|
|
362
|
+
child.getResolvedDimension(direction, Dimension.Width, ownerWidth, ownerWidth),
|
|
363
|
+
paddingAndBorder,
|
|
364
|
+
),
|
|
365
|
+
);
|
|
366
|
+
} else if (!isMainAxisRow && isColumnStyleDimDefined) {
|
|
367
|
+
// The height is definite, so use that as the flex basis.
|
|
368
|
+
const paddingAndBorder = paddingAndBorderForAxis(
|
|
369
|
+
child,
|
|
370
|
+
FlexDirection.Column,
|
|
371
|
+
direction,
|
|
372
|
+
ownerWidth,
|
|
373
|
+
);
|
|
374
|
+
child.setLayoutComputedFlexBasis(
|
|
375
|
+
maxOrDefined(
|
|
376
|
+
child.getResolvedDimension(direction, Dimension.Height, ownerHeight, ownerWidth),
|
|
377
|
+
paddingAndBorder,
|
|
378
|
+
),
|
|
379
|
+
);
|
|
380
|
+
} else {
|
|
381
|
+
// Compute the flex basis and hypothetical main size (i.e. the clamped flex
|
|
382
|
+
// basis).
|
|
383
|
+
childWidthSizingMode = SizingMode.MaxContent;
|
|
384
|
+
childHeightSizingMode = SizingMode.MaxContent;
|
|
385
|
+
|
|
386
|
+
const marginRow = child.style.computeMarginForAxis(FlexDirection.Row, ownerWidth);
|
|
387
|
+
const marginColumn = child.style.computeMarginForAxis(FlexDirection.Column, ownerWidth);
|
|
388
|
+
|
|
389
|
+
if (isRowStyleDimDefined) {
|
|
390
|
+
childWidth =
|
|
391
|
+
child.getResolvedDimension(direction, Dimension.Width, ownerWidth, ownerWidth) + marginRow;
|
|
392
|
+
childWidthSizingMode = SizingMode.StretchFit;
|
|
393
|
+
}
|
|
394
|
+
if (isColumnStyleDimDefined) {
|
|
395
|
+
childHeight =
|
|
396
|
+
child.getResolvedDimension(direction, Dimension.Height, ownerHeight, ownerWidth) +
|
|
397
|
+
marginColumn;
|
|
398
|
+
childHeightSizingMode = SizingMode.StretchFit;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// The W3C spec doesn't say anything about the 'overflow' property, but all
|
|
402
|
+
// major browsers appear to implement the following logic.
|
|
403
|
+
if (
|
|
404
|
+
(!isMainAxisRow && node.style.overflow() === Overflow.Scroll) ||
|
|
405
|
+
node.style.overflow() !== Overflow.Scroll
|
|
406
|
+
) {
|
|
407
|
+
if (isUndefined(childWidth) && isDefined(width)) {
|
|
408
|
+
childWidth = width;
|
|
409
|
+
childWidthSizingMode = SizingMode.FitContent;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// A zero-intrinsic-height column subtree has the same layout with an
|
|
414
|
+
// unbounded height, allowing its measurement cache to survive unrelated
|
|
415
|
+
// size changes elsewhere in a vertical scroll subtree.
|
|
416
|
+
const parentDoesNotScroll = node.style.overflow() !== Overflow.Scroll;
|
|
417
|
+
let applyHeightFitContent = isMainAxisRow || parentDoesNotScroll;
|
|
418
|
+
if (fixFlexBasisFitContent) {
|
|
419
|
+
const childHadOverflow = child.isDirty() && child.layout.hadOverflow();
|
|
420
|
+
const hasHeightIndependentSubtree =
|
|
421
|
+
!isMainAxisRow &&
|
|
422
|
+
parentDoesNotScroll &&
|
|
423
|
+
isUndefined(childHeight) &&
|
|
424
|
+
isDefined(height) &&
|
|
425
|
+
isColumnStretchEdge(node, child) &&
|
|
426
|
+
isInColumnStretchScrollSubtree(node) &&
|
|
427
|
+
canSkipHeightFitContent(child);
|
|
428
|
+
if (hasHeightIndependentSubtree && childHadOverflow) {
|
|
429
|
+
child.setLayoutHadOverflow(false);
|
|
430
|
+
}
|
|
431
|
+
if (hasHeightIndependentSubtree) {
|
|
432
|
+
applyHeightFitContent = false;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (applyHeightFitContent && isUndefined(childHeight) && isDefined(height)) {
|
|
436
|
+
childHeight = height;
|
|
437
|
+
childHeightSizingMode = SizingMode.FitContent;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const childStyle = child.style;
|
|
441
|
+
if (isDefined(childStyle.aspectRatio())) {
|
|
442
|
+
if (!isMainAxisRow && childWidthSizingMode === SizingMode.StretchFit) {
|
|
443
|
+
childHeight = marginColumn + (childWidth - marginRow) / childStyle.aspectRatio();
|
|
444
|
+
childHeightSizingMode = SizingMode.StretchFit;
|
|
445
|
+
} else if (isMainAxisRow && childHeightSizingMode === SizingMode.StretchFit) {
|
|
446
|
+
childWidth = marginRow + (childHeight - marginColumn) * childStyle.aspectRatio();
|
|
447
|
+
childWidthSizingMode = SizingMode.StretchFit;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// If child has no defined size in the cross axis and is set to stretch,
|
|
452
|
+
// set the cross axis to be measured exactly with the available inner width
|
|
453
|
+
|
|
454
|
+
const hasExactWidth = isDefined(width) && widthMode === SizingMode.StretchFit;
|
|
455
|
+
const childWidthStretch =
|
|
456
|
+
resolveChildAlignment(node, child) === Align.Stretch &&
|
|
457
|
+
childWidthSizingMode !== SizingMode.StretchFit;
|
|
458
|
+
if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) {
|
|
459
|
+
childWidth = width;
|
|
460
|
+
childWidthSizingMode = SizingMode.StretchFit;
|
|
461
|
+
if (isDefined(childStyle.aspectRatio())) {
|
|
462
|
+
childHeight = (childWidth - marginRow) / childStyle.aspectRatio();
|
|
463
|
+
childHeightSizingMode = SizingMode.StretchFit;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const hasExactHeight = isDefined(height) && heightMode === SizingMode.StretchFit;
|
|
468
|
+
const childHeightStretch =
|
|
469
|
+
resolveChildAlignment(node, child) === Align.Stretch &&
|
|
470
|
+
childHeightSizingMode !== SizingMode.StretchFit;
|
|
471
|
+
if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && childHeightStretch) {
|
|
472
|
+
childHeight = height;
|
|
473
|
+
childHeightSizingMode = SizingMode.StretchFit;
|
|
474
|
+
|
|
475
|
+
if (isDefined(childStyle.aspectRatio())) {
|
|
476
|
+
childWidth = (childHeight - marginColumn) * childStyle.aspectRatio();
|
|
477
|
+
childWidthSizingMode = SizingMode.StretchFit;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const widthModeAndSize = scratchModeA;
|
|
482
|
+
widthModeAndSize.mode = childWidthSizingMode;
|
|
483
|
+
widthModeAndSize.size = childWidth;
|
|
484
|
+
constrainMaxSizeForMode(
|
|
485
|
+
child,
|
|
486
|
+
direction,
|
|
487
|
+
FlexDirection.Row,
|
|
488
|
+
ownerWidth,
|
|
489
|
+
ownerWidth,
|
|
490
|
+
widthModeAndSize,
|
|
491
|
+
);
|
|
492
|
+
const heightModeAndSize = scratchModeB;
|
|
493
|
+
heightModeAndSize.mode = childHeightSizingMode;
|
|
494
|
+
heightModeAndSize.size = childHeight;
|
|
495
|
+
constrainMaxSizeForMode(
|
|
496
|
+
child,
|
|
497
|
+
direction,
|
|
498
|
+
FlexDirection.Column,
|
|
499
|
+
ownerHeight,
|
|
500
|
+
ownerWidth,
|
|
501
|
+
heightModeAndSize,
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
// Measure the child
|
|
505
|
+
calculateLayoutInternal(
|
|
506
|
+
child,
|
|
507
|
+
widthModeAndSize.size,
|
|
508
|
+
heightModeAndSize.size,
|
|
509
|
+
direction,
|
|
510
|
+
widthModeAndSize.mode,
|
|
511
|
+
heightModeAndSize.mode,
|
|
512
|
+
ownerWidth,
|
|
513
|
+
ownerHeight,
|
|
514
|
+
false,
|
|
515
|
+
LayoutPassReason.MeasureChild,
|
|
516
|
+
layoutMarkerData,
|
|
517
|
+
depth,
|
|
518
|
+
generationCount,
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
child.setLayoutComputedFlexBasis(
|
|
522
|
+
maxOrDefined(
|
|
523
|
+
child.layout.measuredDimension(dimension(mainAxis)),
|
|
524
|
+
paddingAndBorderForAxis(child, mainAxis, direction, ownerWidth),
|
|
525
|
+
),
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
child.setLayoutComputedFlexBasisGeneration(generationCount);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function measureNodeWithMeasureFunc(
|
|
532
|
+
node: Node,
|
|
533
|
+
direction: Direction,
|
|
534
|
+
availableWidth: number,
|
|
535
|
+
availableHeight: number,
|
|
536
|
+
widthSizingMode: SizingMode,
|
|
537
|
+
heightSizingMode: SizingMode,
|
|
538
|
+
ownerWidth: number,
|
|
539
|
+
ownerHeight: number,
|
|
540
|
+
layoutMarkerData: LayoutData,
|
|
541
|
+
): void {
|
|
542
|
+
if (widthSizingMode === SizingMode.MaxContent) {
|
|
543
|
+
availableWidth = NaN;
|
|
544
|
+
}
|
|
545
|
+
if (heightSizingMode === SizingMode.MaxContent) {
|
|
546
|
+
availableHeight = NaN;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const layout = node.layout;
|
|
550
|
+
const paddingAndBorderAxisRow =
|
|
551
|
+
layout.padding(PhysicalEdge.Left) +
|
|
552
|
+
layout.padding(PhysicalEdge.Right) +
|
|
553
|
+
layout.border(PhysicalEdge.Left) +
|
|
554
|
+
layout.border(PhysicalEdge.Right);
|
|
555
|
+
const paddingAndBorderAxisColumn =
|
|
556
|
+
layout.padding(PhysicalEdge.Top) +
|
|
557
|
+
layout.padding(PhysicalEdge.Bottom) +
|
|
558
|
+
layout.border(PhysicalEdge.Top) +
|
|
559
|
+
layout.border(PhysicalEdge.Bottom);
|
|
560
|
+
|
|
561
|
+
// We want to make sure we don't call measure with negative size
|
|
562
|
+
const innerWidth = isUndefined(availableWidth)
|
|
563
|
+
? availableWidth
|
|
564
|
+
: maxOrDefined(0, availableWidth - paddingAndBorderAxisRow);
|
|
565
|
+
const innerHeight = isUndefined(availableHeight)
|
|
566
|
+
? availableHeight
|
|
567
|
+
: maxOrDefined(0, availableHeight - paddingAndBorderAxisColumn);
|
|
568
|
+
|
|
569
|
+
if (widthSizingMode === SizingMode.StretchFit && heightSizingMode === SizingMode.StretchFit) {
|
|
570
|
+
// Don't bother sizing the text if both dimensions are already defined.
|
|
571
|
+
node.setLayoutMeasuredDimension(
|
|
572
|
+
boundAxis(node, FlexDirection.Row, direction, availableWidth, ownerWidth, ownerWidth),
|
|
573
|
+
Dimension.Width,
|
|
574
|
+
);
|
|
575
|
+
node.setLayoutMeasuredDimension(
|
|
576
|
+
boundAxis(node, FlexDirection.Column, direction, availableHeight, ownerHeight, ownerWidth),
|
|
577
|
+
Dimension.Height,
|
|
578
|
+
);
|
|
579
|
+
} else {
|
|
580
|
+
// Measure the text under the current constraints.
|
|
581
|
+
const measuredSize = node.measure(
|
|
582
|
+
innerWidth,
|
|
583
|
+
measureMode(widthSizingMode),
|
|
584
|
+
innerHeight,
|
|
585
|
+
measureMode(heightSizingMode),
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
layoutMarkerData.measureCallbacks += 1;
|
|
589
|
+
|
|
590
|
+
node.setLayoutMeasuredDimension(
|
|
591
|
+
boundAxis(
|
|
592
|
+
node,
|
|
593
|
+
FlexDirection.Row,
|
|
594
|
+
direction,
|
|
595
|
+
widthSizingMode === SizingMode.MaxContent || widthSizingMode === SizingMode.FitContent
|
|
596
|
+
? measuredSize.width + paddingAndBorderAxisRow
|
|
597
|
+
: availableWidth,
|
|
598
|
+
ownerWidth,
|
|
599
|
+
ownerWidth,
|
|
600
|
+
),
|
|
601
|
+
Dimension.Width,
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
node.setLayoutMeasuredDimension(
|
|
605
|
+
boundAxis(
|
|
606
|
+
node,
|
|
607
|
+
FlexDirection.Column,
|
|
608
|
+
direction,
|
|
609
|
+
heightSizingMode === SizingMode.MaxContent || heightSizingMode === SizingMode.FitContent
|
|
610
|
+
? measuredSize.height + paddingAndBorderAxisColumn
|
|
611
|
+
: availableHeight,
|
|
612
|
+
ownerHeight,
|
|
613
|
+
ownerWidth,
|
|
614
|
+
),
|
|
615
|
+
Dimension.Height,
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// For nodes with no children, use the available values if they were provided,
|
|
621
|
+
// or the minimum size as indicated by the padding and border sizes.
|
|
622
|
+
function measureNodeWithoutChildren(
|
|
623
|
+
node: Node,
|
|
624
|
+
direction: Direction,
|
|
625
|
+
availableWidth: number,
|
|
626
|
+
availableHeight: number,
|
|
627
|
+
widthSizingMode: SizingMode,
|
|
628
|
+
heightSizingMode: SizingMode,
|
|
629
|
+
ownerWidth: number,
|
|
630
|
+
ownerHeight: number,
|
|
631
|
+
): void {
|
|
632
|
+
const layout = node.layout;
|
|
633
|
+
|
|
634
|
+
let width = availableWidth;
|
|
635
|
+
if (widthSizingMode === SizingMode.MaxContent || widthSizingMode === SizingMode.FitContent) {
|
|
636
|
+
width =
|
|
637
|
+
layout.padding(PhysicalEdge.Left) +
|
|
638
|
+
layout.padding(PhysicalEdge.Right) +
|
|
639
|
+
layout.border(PhysicalEdge.Left) +
|
|
640
|
+
layout.border(PhysicalEdge.Right);
|
|
641
|
+
}
|
|
642
|
+
node.setLayoutMeasuredDimension(
|
|
643
|
+
boundAxis(node, FlexDirection.Row, direction, width, ownerWidth, ownerWidth),
|
|
644
|
+
Dimension.Width,
|
|
645
|
+
);
|
|
646
|
+
|
|
647
|
+
let height = availableHeight;
|
|
648
|
+
if (heightSizingMode === SizingMode.MaxContent || heightSizingMode === SizingMode.FitContent) {
|
|
649
|
+
height =
|
|
650
|
+
layout.padding(PhysicalEdge.Top) +
|
|
651
|
+
layout.padding(PhysicalEdge.Bottom) +
|
|
652
|
+
layout.border(PhysicalEdge.Top) +
|
|
653
|
+
layout.border(PhysicalEdge.Bottom);
|
|
654
|
+
}
|
|
655
|
+
node.setLayoutMeasuredDimension(
|
|
656
|
+
boundAxis(node, FlexDirection.Column, direction, height, ownerHeight, ownerWidth),
|
|
657
|
+
Dimension.Height,
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function isFixedSize(dim: number, sizingMode: SizingMode): boolean {
|
|
662
|
+
return (
|
|
663
|
+
sizingMode === SizingMode.StretchFit ||
|
|
664
|
+
(isDefined(dim) && sizingMode === SizingMode.FitContent && dim <= 0)
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
function measureNodeWithFixedSize(
|
|
669
|
+
node: Node,
|
|
670
|
+
direction: Direction,
|
|
671
|
+
availableWidth: number,
|
|
672
|
+
availableHeight: number,
|
|
673
|
+
widthSizingMode: SizingMode,
|
|
674
|
+
heightSizingMode: SizingMode,
|
|
675
|
+
ownerWidth: number,
|
|
676
|
+
ownerHeight: number,
|
|
677
|
+
): boolean {
|
|
678
|
+
if (
|
|
679
|
+
isFixedSize(availableWidth, widthSizingMode) &&
|
|
680
|
+
isFixedSize(availableHeight, heightSizingMode)
|
|
681
|
+
) {
|
|
682
|
+
node.setLayoutMeasuredDimension(
|
|
683
|
+
boundAxis(
|
|
684
|
+
node,
|
|
685
|
+
FlexDirection.Row,
|
|
686
|
+
direction,
|
|
687
|
+
isUndefined(availableWidth) ||
|
|
688
|
+
(widthSizingMode === SizingMode.FitContent && availableWidth < 0)
|
|
689
|
+
? 0
|
|
690
|
+
: availableWidth,
|
|
691
|
+
ownerWidth,
|
|
692
|
+
ownerWidth,
|
|
693
|
+
),
|
|
694
|
+
Dimension.Width,
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
node.setLayoutMeasuredDimension(
|
|
698
|
+
boundAxis(
|
|
699
|
+
node,
|
|
700
|
+
FlexDirection.Column,
|
|
701
|
+
direction,
|
|
702
|
+
isUndefined(availableHeight) ||
|
|
703
|
+
(heightSizingMode === SizingMode.FitContent && availableHeight < 0)
|
|
704
|
+
? 0
|
|
705
|
+
: availableHeight,
|
|
706
|
+
ownerHeight,
|
|
707
|
+
ownerWidth,
|
|
708
|
+
),
|
|
709
|
+
Dimension.Height,
|
|
710
|
+
);
|
|
711
|
+
return true;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export function zeroOutLayoutRecursively(node: Node): void {
|
|
718
|
+
node.layout = new LayoutResults();
|
|
719
|
+
node.setLayoutDimension(0, Dimension.Width);
|
|
720
|
+
node.setLayoutDimension(0, Dimension.Height);
|
|
721
|
+
node.hasNewLayout_ = true;
|
|
722
|
+
|
|
723
|
+
node.cloneChildrenIfNeeded();
|
|
724
|
+
for (const child of node.children) {
|
|
725
|
+
zeroOutLayoutRecursively(child);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
export function cleanupContentsNodesRecursively(node: Node, didPerformLayout: boolean): void {
|
|
730
|
+
if (node.hasContentsChildren()) {
|
|
731
|
+
node.cloneContentsChildrenIfNeeded();
|
|
732
|
+
for (const child of node.children) {
|
|
733
|
+
if (child.style.display() === Display.Contents) {
|
|
734
|
+
child.layout = new LayoutResults();
|
|
735
|
+
child.setLayoutDimension(0, Dimension.Width);
|
|
736
|
+
child.setLayoutDimension(0, Dimension.Height);
|
|
737
|
+
if (didPerformLayout) {
|
|
738
|
+
child.hasNewLayout_ = true;
|
|
739
|
+
}
|
|
740
|
+
child.setDirty(false);
|
|
741
|
+
child.cloneChildrenIfNeeded();
|
|
742
|
+
|
|
743
|
+
cleanupContentsNodesRecursively(child, didPerformLayout);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
export function calculateAvailableInnerDimension(
|
|
750
|
+
node: Node,
|
|
751
|
+
direction: Direction,
|
|
752
|
+
dim: Dimension,
|
|
753
|
+
availableDim: number,
|
|
754
|
+
paddingAndBorder: number,
|
|
755
|
+
ownerDim: number,
|
|
756
|
+
ownerWidth: number,
|
|
757
|
+
): number {
|
|
758
|
+
let availableInnerDim = availableDim - paddingAndBorder;
|
|
759
|
+
// Max dimension overrides predefined dimension value; Min dimension in turn
|
|
760
|
+
// overrides both of the above
|
|
761
|
+
if (isDefined(availableInnerDim)) {
|
|
762
|
+
// We want to make sure our available height does not violate min and max
|
|
763
|
+
// constraints
|
|
764
|
+
const minDimensionOptional = node.style.resolvedMinDimension(
|
|
765
|
+
direction,
|
|
766
|
+
dim,
|
|
767
|
+
ownerDim,
|
|
768
|
+
ownerWidth,
|
|
769
|
+
);
|
|
770
|
+
const minInnerDim = isUndefined(minDimensionOptional)
|
|
771
|
+
? 0
|
|
772
|
+
: minDimensionOptional - paddingAndBorder;
|
|
773
|
+
|
|
774
|
+
const maxDimensionOptional = node.style.resolvedMaxDimension(
|
|
775
|
+
direction,
|
|
776
|
+
dim,
|
|
777
|
+
ownerDim,
|
|
778
|
+
ownerWidth,
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
const maxInnerDim = isUndefined(maxDimensionOptional)
|
|
782
|
+
? Number.MAX_VALUE
|
|
783
|
+
: maxDimensionOptional - paddingAndBorder;
|
|
784
|
+
availableInnerDim = maxOrDefined(minOrDefined(availableInnerDim, maxInnerDim), minInnerDim);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
return availableInnerDim;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function computeFlexBasisForChildren(
|
|
791
|
+
node: Node,
|
|
792
|
+
layoutChildren: readonly Node[],
|
|
793
|
+
availableInnerWidth: number,
|
|
794
|
+
availableInnerHeight: number,
|
|
795
|
+
ownerWidth: number,
|
|
796
|
+
ownerHeight: number,
|
|
797
|
+
widthSizingMode: SizingMode,
|
|
798
|
+
heightSizingMode: SizingMode,
|
|
799
|
+
direction: Direction,
|
|
800
|
+
mainAxis: FlexDirection,
|
|
801
|
+
performLayout: boolean,
|
|
802
|
+
layoutMarkerData: LayoutData,
|
|
803
|
+
depth: number,
|
|
804
|
+
generationCount: number,
|
|
805
|
+
): number {
|
|
806
|
+
let totalOuterFlexBasis = 0;
|
|
807
|
+
let singleFlexChild: Node | null = null;
|
|
808
|
+
const sizingModeMainDim = isRow(mainAxis) ? widthSizingMode : heightSizingMode;
|
|
809
|
+
// If there is only one child with flexGrow + flexShrink it means we can set
|
|
810
|
+
// the computedFlexBasis to 0 instead of measuring and shrinking / flexing
|
|
811
|
+
// the child to exactly match the remaining space
|
|
812
|
+
if (sizingModeMainDim === SizingMode.StretchFit) {
|
|
813
|
+
for (const child of layoutChildren) {
|
|
814
|
+
if (child.isNodeFlexible()) {
|
|
815
|
+
if (
|
|
816
|
+
singleFlexChild !== null ||
|
|
817
|
+
inexactEquals(child.resolveFlexGrow(), 0) ||
|
|
818
|
+
inexactEquals(child.resolveFlexShrink(), 0)
|
|
819
|
+
) {
|
|
820
|
+
// There is already a flexible child, or this flexible child doesn't
|
|
821
|
+
// have flexGrow and flexShrink, abort
|
|
822
|
+
singleFlexChild = null;
|
|
823
|
+
break;
|
|
824
|
+
} else {
|
|
825
|
+
singleFlexChild = child;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
for (const child of layoutChildren) {
|
|
832
|
+
child.processDimensions();
|
|
833
|
+
if (child.style.display() === Display.None) {
|
|
834
|
+
// Only mutate display: none children during layout passes. Zeroing them
|
|
835
|
+
// out during measure-only passes contributes nothing to the
|
|
836
|
+
// measurement, but sets `hasNewLayout` on nodes the parent's layout
|
|
837
|
+
// pass may never visit.
|
|
838
|
+
if (performLayout) {
|
|
839
|
+
zeroOutLayoutRecursively(child);
|
|
840
|
+
child.hasNewLayout_ = true;
|
|
841
|
+
child.setDirty(false);
|
|
842
|
+
}
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
if (performLayout) {
|
|
846
|
+
// Set the initial position (relative to the owner).
|
|
847
|
+
const childDirection = child.resolveDirection(direction);
|
|
848
|
+
child.setPositionFromStyle(childDirection, availableInnerWidth, availableInnerHeight);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if (child.style.positionType() === PositionType.Absolute) {
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
854
|
+
if (child === singleFlexChild) {
|
|
855
|
+
child.setLayoutComputedFlexBasisGeneration(generationCount);
|
|
856
|
+
child.setLayoutComputedFlexBasis(0);
|
|
857
|
+
} else {
|
|
858
|
+
computeFlexBasisForChild(
|
|
859
|
+
node,
|
|
860
|
+
child,
|
|
861
|
+
availableInnerWidth,
|
|
862
|
+
widthSizingMode,
|
|
863
|
+
availableInnerHeight,
|
|
864
|
+
ownerWidth,
|
|
865
|
+
ownerHeight,
|
|
866
|
+
heightSizingMode,
|
|
867
|
+
direction,
|
|
868
|
+
layoutMarkerData,
|
|
869
|
+
depth,
|
|
870
|
+
generationCount,
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
totalOuterFlexBasis +=
|
|
875
|
+
child.layout.computedFlexBasis +
|
|
876
|
+
child.style.computeMarginForAxis(mainAxis, availableInnerWidth);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
return totalOuterFlexBasis;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Returns the min-content size of `node` along `requestedAxis`, used by CSS
|
|
883
|
+
// Flexbox §4.5 automatic minimum sizing. See CalculateLayout.cpp for the full
|
|
884
|
+
// description of the algorithm.
|
|
885
|
+
function computeMinContentMainSize(
|
|
886
|
+
node: Node,
|
|
887
|
+
requestedAxis: FlexDirection,
|
|
888
|
+
ownerDirection: Direction,
|
|
889
|
+
ownerWidth: number,
|
|
890
|
+
// oxlint-disable-next-line oxc/only-used-in-recursion -- kept for call-site parity with upstream Yoga
|
|
891
|
+
ownerHeight: number,
|
|
892
|
+
): number {
|
|
893
|
+
const wantRow = isRow(requestedAxis);
|
|
894
|
+
|
|
895
|
+
if (node.hasMeasureFunc()) {
|
|
896
|
+
// Fall back to the regular measure function with `AtMost 0`, which text
|
|
897
|
+
// measurers naturally answer with longest-word width.
|
|
898
|
+
const size = node.measure(
|
|
899
|
+
wantRow ? 0 : NaN,
|
|
900
|
+
wantRow ? MeasureMode.AtMost : MeasureMode.Undefined,
|
|
901
|
+
wantRow ? NaN : 0,
|
|
902
|
+
wantRow ? MeasureMode.Undefined : MeasureMode.AtMost,
|
|
903
|
+
);
|
|
904
|
+
// Add the leaf's own padding and border, like the container branch below.
|
|
905
|
+
const leafDirection = node.resolveDirection(ownerDirection);
|
|
906
|
+
const paddingAndBorder =
|
|
907
|
+
node.style.computeFlexStartPaddingAndBorder(requestedAxis, leafDirection, ownerWidth) +
|
|
908
|
+
node.style.computeFlexEndPaddingAndBorder(requestedAxis, leafDirection, ownerWidth);
|
|
909
|
+
return (wantRow ? size.width : size.height) + paddingAndBorder;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
if (node.getChildCount() === 0) {
|
|
913
|
+
return 0;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
const direction = node.resolveDirection(ownerDirection);
|
|
917
|
+
const nodeMainAxis = resolveDirection(node.style.flexDirection(), direction);
|
|
918
|
+
const nodeCrossAxis = resolveCrossDirection(nodeMainAxis, direction);
|
|
919
|
+
|
|
920
|
+
let mainTotal = 0;
|
|
921
|
+
let crossMax = 0;
|
|
922
|
+
|
|
923
|
+
for (let i = 0; i < node.getChildCount(); i++) {
|
|
924
|
+
const child = node.getChild(i);
|
|
925
|
+
if (
|
|
926
|
+
child.style.display() === Display.None ||
|
|
927
|
+
child.style.positionType() === PositionType.Absolute
|
|
928
|
+
) {
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
let childMain = computeMinContentMainSize(
|
|
933
|
+
child,
|
|
934
|
+
nodeMainAxis,
|
|
935
|
+
direction,
|
|
936
|
+
ownerWidth,
|
|
937
|
+
ownerHeight,
|
|
938
|
+
);
|
|
939
|
+
childMain += child.style.computeMarginForAxis(nodeMainAxis, ownerWidth);
|
|
940
|
+
|
|
941
|
+
let childCross = computeMinContentMainSize(
|
|
942
|
+
child,
|
|
943
|
+
nodeCrossAxis,
|
|
944
|
+
direction,
|
|
945
|
+
ownerWidth,
|
|
946
|
+
ownerHeight,
|
|
947
|
+
);
|
|
948
|
+
childCross += child.style.computeMarginForAxis(nodeCrossAxis, ownerWidth);
|
|
949
|
+
|
|
950
|
+
mainTotal += childMain;
|
|
951
|
+
crossMax = Math.max(crossMax, childCross);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
mainTotal +=
|
|
955
|
+
node.style.computeFlexStartPaddingAndBorder(nodeMainAxis, direction, ownerWidth) +
|
|
956
|
+
node.style.computeFlexEndPaddingAndBorder(nodeMainAxis, direction, ownerWidth);
|
|
957
|
+
crossMax +=
|
|
958
|
+
node.style.computeFlexStartPaddingAndBorder(nodeCrossAxis, direction, ownerWidth) +
|
|
959
|
+
node.style.computeFlexEndPaddingAndBorder(nodeCrossAxis, direction, ownerWidth);
|
|
960
|
+
|
|
961
|
+
const nodeMainIsRow = isRow(nodeMainAxis);
|
|
962
|
+
const widthMin = nodeMainIsRow ? mainTotal : crossMax;
|
|
963
|
+
const heightMin = nodeMainIsRow ? crossMax : mainTotal;
|
|
964
|
+
return wantRow ? widthMin : heightMin;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Computes the CSS Flexbox §4.5 automatic minimum main-axis size for `child`.
|
|
968
|
+
// Returns NaN when no auto-min applies; 0 when the item's own
|
|
969
|
+
// `overflow != visible` (the spec's per-item escape hatch); or a concrete
|
|
970
|
+
// floor otherwise. See https://www.w3.org/TR/css-flexbox-1/#min-size-auto.
|
|
971
|
+
function computeAutoMinMainSize(
|
|
972
|
+
child: Node,
|
|
973
|
+
mainAxis: FlexDirection,
|
|
974
|
+
direction: Direction,
|
|
975
|
+
ownerMainAxisSize: number,
|
|
976
|
+
ownerWidth: number,
|
|
977
|
+
ownerHeight: number,
|
|
978
|
+
): number {
|
|
979
|
+
if (child.hasErrata(Errata.MinSizeUndefinedInsteadOfAuto)) {
|
|
980
|
+
return NaN;
|
|
981
|
+
}
|
|
982
|
+
if (child.style.display() === Display.None) {
|
|
983
|
+
return NaN;
|
|
984
|
+
}
|
|
985
|
+
// Explicit `min-{w,h}` (including `0`) wins over auto. This is the
|
|
986
|
+
// CSS-spec opt-out (§4.5).
|
|
987
|
+
if (child.style.minDimension(dimension(mainAxis)).isDefined()) {
|
|
988
|
+
return NaN;
|
|
989
|
+
}
|
|
990
|
+
// Per CSS §4.5: a flex item whose own `overflow` is not `visible` gets
|
|
991
|
+
// auto-min = 0 (let scroll/clip handle overflow rather than enforce a
|
|
992
|
+
// content-based minimum).
|
|
993
|
+
if (child.style.overflow() !== Overflow.Visible) {
|
|
994
|
+
return 0;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
const mainDim = dimension(mainAxis);
|
|
998
|
+
const crossDim = isRow(mainAxis) ? Dimension.Height : Dimension.Width;
|
|
999
|
+
const isMainAxisRow = isRow(mainAxis);
|
|
1000
|
+
|
|
1001
|
+
// Specified size suggestion: the resolved main-axis style dimension.
|
|
1002
|
+
const specifiedMain = child.getResolvedDimension(
|
|
1003
|
+
direction,
|
|
1004
|
+
mainDim,
|
|
1005
|
+
ownerMainAxisSize,
|
|
1006
|
+
ownerWidth,
|
|
1007
|
+
);
|
|
1008
|
+
|
|
1009
|
+
// Transferred size suggestion: cross × aspect-ratio, if both are definite.
|
|
1010
|
+
let transferredMain = NaN;
|
|
1011
|
+
const aspectRatio = child.style.aspectRatio();
|
|
1012
|
+
if (isDefined(aspectRatio)) {
|
|
1013
|
+
const crossOwner = isMainAxisRow ? ownerHeight : ownerWidth;
|
|
1014
|
+
const crossResolved = child.getResolvedDimension(direction, crossDim, crossOwner, ownerWidth);
|
|
1015
|
+
if (isDefined(crossResolved)) {
|
|
1016
|
+
transferredMain = isMainAxisRow ? crossResolved * aspectRatio : crossResolved / aspectRatio;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// Content size suggestion: probe via min-content recursion.
|
|
1021
|
+
const contentMain = computeMinContentMainSize(
|
|
1022
|
+
child,
|
|
1023
|
+
mainAxis,
|
|
1024
|
+
direction,
|
|
1025
|
+
ownerWidth,
|
|
1026
|
+
ownerHeight,
|
|
1027
|
+
);
|
|
1028
|
+
|
|
1029
|
+
// Combine per §4.5: floor = min(content, specified) when specified is
|
|
1030
|
+
// definite; otherwise floor = min(content, transferred) when transferred
|
|
1031
|
+
// applies; else floor = content.
|
|
1032
|
+
let floor = contentMain;
|
|
1033
|
+
if (isDefined(specifiedMain)) {
|
|
1034
|
+
if (isUndefined(floor) || specifiedMain < floor) {
|
|
1035
|
+
floor = specifiedMain;
|
|
1036
|
+
}
|
|
1037
|
+
} else if (isDefined(transferredMain)) {
|
|
1038
|
+
if (isUndefined(floor) || transferredMain < floor) {
|
|
1039
|
+
floor = transferredMain;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// §4.5: cap by the max main size.
|
|
1044
|
+
const maxMain = child.style.resolvedMaxDimension(
|
|
1045
|
+
direction,
|
|
1046
|
+
mainDim,
|
|
1047
|
+
ownerMainAxisSize,
|
|
1048
|
+
ownerWidth,
|
|
1049
|
+
);
|
|
1050
|
+
if (isDefined(maxMain) && floor > maxMain) {
|
|
1051
|
+
floor = maxMain;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if (isUndefined(floor) || floor < 0) {
|
|
1055
|
+
floor = 0;
|
|
1056
|
+
}
|
|
1057
|
+
return floor;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// boundAxis with an additional lower bound from `child`'s cached
|
|
1061
|
+
// `computedAutoMinMainSize`, applied on the main axis only.
|
|
1062
|
+
function boundAxisWithAutoMin(
|
|
1063
|
+
child: Node,
|
|
1064
|
+
axis: FlexDirection,
|
|
1065
|
+
direction: Direction,
|
|
1066
|
+
value: number,
|
|
1067
|
+
axisSize: number,
|
|
1068
|
+
widthSize: number,
|
|
1069
|
+
): number {
|
|
1070
|
+
let bounded = boundAxis(child, axis, direction, value, axisSize, widthSize);
|
|
1071
|
+
const autoMin = child.layout.computedAutoMinMainSize;
|
|
1072
|
+
if (isDefined(autoMin) && bounded < autoMin) {
|
|
1073
|
+
bounded = autoMin;
|
|
1074
|
+
}
|
|
1075
|
+
return bounded;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// It distributes the free space to the flexible items and ensures that the
|
|
1079
|
+
// size of the flex items abide the min and max constraints. At the end of this
|
|
1080
|
+
// function the child nodes would have proper size. Prior using this function
|
|
1081
|
+
// please ensure that distributeFreeSpaceFirstPass is called.
|
|
1082
|
+
function distributeFreeSpaceSecondPass(
|
|
1083
|
+
flexLine: FlexLine,
|
|
1084
|
+
node: Node,
|
|
1085
|
+
mainAxis: FlexDirection,
|
|
1086
|
+
crossAxis: FlexDirection,
|
|
1087
|
+
direction: Direction,
|
|
1088
|
+
ownerWidth: number,
|
|
1089
|
+
mainAxisOwnerSize: number,
|
|
1090
|
+
availableInnerMainDim: number,
|
|
1091
|
+
availableInnerCrossDim: number,
|
|
1092
|
+
availableInnerWidth: number,
|
|
1093
|
+
availableInnerHeight: number,
|
|
1094
|
+
mainAxisOverflows: boolean,
|
|
1095
|
+
sizingModeCrossDim: SizingMode,
|
|
1096
|
+
performLayout: boolean,
|
|
1097
|
+
layoutMarkerData: LayoutData,
|
|
1098
|
+
depth: number,
|
|
1099
|
+
generationCount: number,
|
|
1100
|
+
): number {
|
|
1101
|
+
let childFlexBasis = 0;
|
|
1102
|
+
let flexShrinkScaledFactor = 0;
|
|
1103
|
+
let flexGrowFactor = 0;
|
|
1104
|
+
let deltaFreeSpace = 0;
|
|
1105
|
+
const isMainAxisRow = isRow(mainAxis);
|
|
1106
|
+
const isNodeFlexWrap = node.style.flexWrap() !== Wrap.NoWrap;
|
|
1107
|
+
|
|
1108
|
+
for (const currentLineChild of flexLine.itemsInFlow) {
|
|
1109
|
+
childFlexBasis = boundAxisWithinMinAndMax(
|
|
1110
|
+
currentLineChild,
|
|
1111
|
+
direction,
|
|
1112
|
+
mainAxis,
|
|
1113
|
+
currentLineChild.layout.computedFlexBasis,
|
|
1114
|
+
mainAxisOwnerSize,
|
|
1115
|
+
ownerWidth,
|
|
1116
|
+
);
|
|
1117
|
+
let updatedMainSize = childFlexBasis;
|
|
1118
|
+
|
|
1119
|
+
if (isDefined(flexLine.layout.remainingFreeSpace) && flexLine.layout.remainingFreeSpace < 0) {
|
|
1120
|
+
flexShrinkScaledFactor = -currentLineChild.resolveFlexShrink() * childFlexBasis;
|
|
1121
|
+
// Is this child able to shrink?
|
|
1122
|
+
if (flexShrinkScaledFactor !== 0) {
|
|
1123
|
+
let childSize = NaN;
|
|
1124
|
+
|
|
1125
|
+
if (
|
|
1126
|
+
isDefined(flexLine.layout.totalFlexShrinkScaledFactors) &&
|
|
1127
|
+
flexLine.layout.totalFlexShrinkScaledFactors === 0
|
|
1128
|
+
) {
|
|
1129
|
+
childSize = childFlexBasis + flexShrinkScaledFactor;
|
|
1130
|
+
} else {
|
|
1131
|
+
childSize =
|
|
1132
|
+
childFlexBasis +
|
|
1133
|
+
(flexLine.layout.remainingFreeSpace / flexLine.layout.totalFlexShrinkScaledFactors) *
|
|
1134
|
+
flexShrinkScaledFactor;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
updatedMainSize = boundAxisWithAutoMin(
|
|
1138
|
+
currentLineChild,
|
|
1139
|
+
mainAxis,
|
|
1140
|
+
direction,
|
|
1141
|
+
childSize,
|
|
1142
|
+
availableInnerMainDim,
|
|
1143
|
+
availableInnerWidth,
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
} else if (
|
|
1147
|
+
isDefined(flexLine.layout.remainingFreeSpace) &&
|
|
1148
|
+
flexLine.layout.remainingFreeSpace > 0
|
|
1149
|
+
) {
|
|
1150
|
+
flexGrowFactor = currentLineChild.resolveFlexGrow();
|
|
1151
|
+
|
|
1152
|
+
// Is this child able to grow?
|
|
1153
|
+
if (!Number.isNaN(flexGrowFactor) && flexGrowFactor !== 0) {
|
|
1154
|
+
updatedMainSize = boundAxisWithAutoMin(
|
|
1155
|
+
currentLineChild,
|
|
1156
|
+
mainAxis,
|
|
1157
|
+
direction,
|
|
1158
|
+
childFlexBasis +
|
|
1159
|
+
(flexLine.layout.remainingFreeSpace / flexLine.layout.totalFlexGrowFactors) *
|
|
1160
|
+
flexGrowFactor,
|
|
1161
|
+
availableInnerMainDim,
|
|
1162
|
+
availableInnerWidth,
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
deltaFreeSpace += updatedMainSize - childFlexBasis;
|
|
1168
|
+
|
|
1169
|
+
const marginMain = currentLineChild.style.computeMarginForAxis(mainAxis, availableInnerWidth);
|
|
1170
|
+
const marginCross = currentLineChild.style.computeMarginForAxis(crossAxis, availableInnerWidth);
|
|
1171
|
+
|
|
1172
|
+
let childCrossSize = NaN;
|
|
1173
|
+
const childMainSize = updatedMainSize + marginMain;
|
|
1174
|
+
let childCrossSizingMode: SizingMode;
|
|
1175
|
+
const childMainSizingMode = SizingMode.StretchFit;
|
|
1176
|
+
|
|
1177
|
+
// These are pure reads repeated below; evaluate once per child.
|
|
1178
|
+
const crossDim = dimension(crossAxis);
|
|
1179
|
+
const hasDefiniteCrossLength = currentLineChild.hasDefiniteLength(
|
|
1180
|
+
crossDim,
|
|
1181
|
+
availableInnerCrossDim,
|
|
1182
|
+
);
|
|
1183
|
+
const childAlignment = resolveChildAlignment(node, currentLineChild);
|
|
1184
|
+
const crossStartMarginIsAuto = currentLineChild.style.flexStartMarginIsAuto(
|
|
1185
|
+
crossAxis,
|
|
1186
|
+
direction,
|
|
1187
|
+
);
|
|
1188
|
+
const crossEndMarginIsAuto = currentLineChild.style.flexEndMarginIsAuto(crossAxis, direction);
|
|
1189
|
+
|
|
1190
|
+
const childStyle = currentLineChild.style;
|
|
1191
|
+
if (isDefined(childStyle.aspectRatio())) {
|
|
1192
|
+
childCrossSize = isMainAxisRow
|
|
1193
|
+
? (childMainSize - marginMain) / childStyle.aspectRatio()
|
|
1194
|
+
: (childMainSize - marginMain) * childStyle.aspectRatio();
|
|
1195
|
+
childCrossSizingMode = SizingMode.StretchFit;
|
|
1196
|
+
|
|
1197
|
+
childCrossSize += marginCross;
|
|
1198
|
+
} else if (
|
|
1199
|
+
!Number.isNaN(availableInnerCrossDim) &&
|
|
1200
|
+
!hasDefiniteCrossLength &&
|
|
1201
|
+
sizingModeCrossDim === SizingMode.StretchFit &&
|
|
1202
|
+
!(isNodeFlexWrap && mainAxisOverflows) &&
|
|
1203
|
+
childAlignment === Align.Stretch &&
|
|
1204
|
+
!crossStartMarginIsAuto &&
|
|
1205
|
+
!crossEndMarginIsAuto
|
|
1206
|
+
) {
|
|
1207
|
+
childCrossSize = availableInnerCrossDim;
|
|
1208
|
+
childCrossSizingMode = SizingMode.StretchFit;
|
|
1209
|
+
} else if (!hasDefiniteCrossLength) {
|
|
1210
|
+
childCrossSize = availableInnerCrossDim;
|
|
1211
|
+
childCrossSizingMode = isUndefined(childCrossSize)
|
|
1212
|
+
? SizingMode.MaxContent
|
|
1213
|
+
: SizingMode.FitContent;
|
|
1214
|
+
} else {
|
|
1215
|
+
childCrossSize =
|
|
1216
|
+
currentLineChild.getResolvedDimension(
|
|
1217
|
+
direction,
|
|
1218
|
+
crossDim,
|
|
1219
|
+
availableInnerCrossDim,
|
|
1220
|
+
availableInnerWidth,
|
|
1221
|
+
) + marginCross;
|
|
1222
|
+
const isLoosePercentageMeasurement =
|
|
1223
|
+
currentLineChild.getProcessedDimension(crossDim).isPercent() &&
|
|
1224
|
+
sizingModeCrossDim !== SizingMode.StretchFit;
|
|
1225
|
+
childCrossSizingMode =
|
|
1226
|
+
isUndefined(childCrossSize) || isLoosePercentageMeasurement
|
|
1227
|
+
? SizingMode.MaxContent
|
|
1228
|
+
: SizingMode.StretchFit;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
const mainModeAndSize = scratchModeA;
|
|
1232
|
+
mainModeAndSize.mode = childMainSizingMode;
|
|
1233
|
+
mainModeAndSize.size = childMainSize;
|
|
1234
|
+
constrainMaxSizeForMode(
|
|
1235
|
+
currentLineChild,
|
|
1236
|
+
direction,
|
|
1237
|
+
mainAxis,
|
|
1238
|
+
availableInnerMainDim,
|
|
1239
|
+
availableInnerWidth,
|
|
1240
|
+
mainModeAndSize,
|
|
1241
|
+
);
|
|
1242
|
+
const crossModeAndSize = scratchModeB;
|
|
1243
|
+
crossModeAndSize.mode = childCrossSizingMode;
|
|
1244
|
+
crossModeAndSize.size = childCrossSize;
|
|
1245
|
+
constrainMaxSizeForMode(
|
|
1246
|
+
currentLineChild,
|
|
1247
|
+
direction,
|
|
1248
|
+
crossAxis,
|
|
1249
|
+
availableInnerCrossDim,
|
|
1250
|
+
availableInnerWidth,
|
|
1251
|
+
crossModeAndSize,
|
|
1252
|
+
);
|
|
1253
|
+
|
|
1254
|
+
const requiresStretchLayout =
|
|
1255
|
+
!hasDefiniteCrossLength &&
|
|
1256
|
+
childAlignment === Align.Stretch &&
|
|
1257
|
+
!crossStartMarginIsAuto &&
|
|
1258
|
+
!crossEndMarginIsAuto;
|
|
1259
|
+
|
|
1260
|
+
const childWidth = isMainAxisRow ? mainModeAndSize.size : crossModeAndSize.size;
|
|
1261
|
+
const childHeight = !isMainAxisRow ? mainModeAndSize.size : crossModeAndSize.size;
|
|
1262
|
+
|
|
1263
|
+
const childWidthSizingMode = isMainAxisRow ? mainModeAndSize.mode : crossModeAndSize.mode;
|
|
1264
|
+
const childHeightSizingMode = !isMainAxisRow ? mainModeAndSize.mode : crossModeAndSize.mode;
|
|
1265
|
+
|
|
1266
|
+
const isLayoutPass = performLayout && !requiresStretchLayout;
|
|
1267
|
+
// Recursively call the layout algorithm for this child with the updated
|
|
1268
|
+
// main size.
|
|
1269
|
+
calculateLayoutInternal(
|
|
1270
|
+
currentLineChild,
|
|
1271
|
+
childWidth,
|
|
1272
|
+
childHeight,
|
|
1273
|
+
node.layout.direction(),
|
|
1274
|
+
childWidthSizingMode,
|
|
1275
|
+
childHeightSizingMode,
|
|
1276
|
+
availableInnerWidth,
|
|
1277
|
+
availableInnerHeight,
|
|
1278
|
+
isLayoutPass,
|
|
1279
|
+
isLayoutPass ? LayoutPassReason.FlexLayout : LayoutPassReason.FlexMeasure,
|
|
1280
|
+
layoutMarkerData,
|
|
1281
|
+
depth,
|
|
1282
|
+
generationCount,
|
|
1283
|
+
);
|
|
1284
|
+
node.setLayoutHadOverflow(node.layout.hadOverflow() || currentLineChild.layout.hadOverflow());
|
|
1285
|
+
}
|
|
1286
|
+
return deltaFreeSpace;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// It distributes the free space to the flexible items. For those flexible
|
|
1290
|
+
// items whose min and max constraints are triggered, those flex item's clamped
|
|
1291
|
+
// size is removed from the remaining free space.
|
|
1292
|
+
function distributeFreeSpaceFirstPass(
|
|
1293
|
+
flexLine: FlexLine,
|
|
1294
|
+
direction: Direction,
|
|
1295
|
+
mainAxis: FlexDirection,
|
|
1296
|
+
ownerWidth: number,
|
|
1297
|
+
mainAxisOwnerSize: number,
|
|
1298
|
+
availableInnerMainDim: number,
|
|
1299
|
+
availableInnerWidth: number,
|
|
1300
|
+
): void {
|
|
1301
|
+
let flexShrinkScaledFactor = 0;
|
|
1302
|
+
let flexGrowFactor = 0;
|
|
1303
|
+
let baseMainSize = 0;
|
|
1304
|
+
let boundMainSize = 0;
|
|
1305
|
+
let deltaFreeSpace = 0;
|
|
1306
|
+
|
|
1307
|
+
for (const currentLineChild of flexLine.itemsInFlow) {
|
|
1308
|
+
const childFlexBasis = boundAxisWithinMinAndMax(
|
|
1309
|
+
currentLineChild,
|
|
1310
|
+
direction,
|
|
1311
|
+
mainAxis,
|
|
1312
|
+
currentLineChild.layout.computedFlexBasis,
|
|
1313
|
+
mainAxisOwnerSize,
|
|
1314
|
+
ownerWidth,
|
|
1315
|
+
);
|
|
1316
|
+
|
|
1317
|
+
if (flexLine.layout.remainingFreeSpace < 0) {
|
|
1318
|
+
flexShrinkScaledFactor = -currentLineChild.resolveFlexShrink() * childFlexBasis;
|
|
1319
|
+
|
|
1320
|
+
// Is this child able to shrink?
|
|
1321
|
+
if (isDefined(flexShrinkScaledFactor) && flexShrinkScaledFactor !== 0) {
|
|
1322
|
+
baseMainSize =
|
|
1323
|
+
childFlexBasis +
|
|
1324
|
+
(flexLine.layout.remainingFreeSpace / flexLine.layout.totalFlexShrinkScaledFactors) *
|
|
1325
|
+
flexShrinkScaledFactor;
|
|
1326
|
+
boundMainSize = boundAxisWithAutoMin(
|
|
1327
|
+
currentLineChild,
|
|
1328
|
+
mainAxis,
|
|
1329
|
+
direction,
|
|
1330
|
+
baseMainSize,
|
|
1331
|
+
availableInnerMainDim,
|
|
1332
|
+
availableInnerWidth,
|
|
1333
|
+
);
|
|
1334
|
+
if (isDefined(baseMainSize) && isDefined(boundMainSize) && baseMainSize !== boundMainSize) {
|
|
1335
|
+
// By excluding this item's size and flex factor from remaining,
|
|
1336
|
+
// this item's min/max constraints should also trigger in the second
|
|
1337
|
+
// pass resulting in the item's size calculation being identical in
|
|
1338
|
+
// the first and second passes.
|
|
1339
|
+
deltaFreeSpace += boundMainSize - childFlexBasis;
|
|
1340
|
+
flexLine.layout.totalFlexShrinkScaledFactors -=
|
|
1341
|
+
-currentLineChild.resolveFlexShrink() * currentLineChild.layout.computedFlexBasis;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
} else if (
|
|
1345
|
+
isDefined(flexLine.layout.remainingFreeSpace) &&
|
|
1346
|
+
flexLine.layout.remainingFreeSpace > 0
|
|
1347
|
+
) {
|
|
1348
|
+
flexGrowFactor = currentLineChild.resolveFlexGrow();
|
|
1349
|
+
|
|
1350
|
+
// Is this child able to grow?
|
|
1351
|
+
if (isDefined(flexGrowFactor) && flexGrowFactor !== 0) {
|
|
1352
|
+
baseMainSize =
|
|
1353
|
+
childFlexBasis +
|
|
1354
|
+
(flexLine.layout.remainingFreeSpace / flexLine.layout.totalFlexGrowFactors) *
|
|
1355
|
+
flexGrowFactor;
|
|
1356
|
+
boundMainSize = boundAxis(
|
|
1357
|
+
currentLineChild,
|
|
1358
|
+
mainAxis,
|
|
1359
|
+
direction,
|
|
1360
|
+
baseMainSize,
|
|
1361
|
+
availableInnerMainDim,
|
|
1362
|
+
availableInnerWidth,
|
|
1363
|
+
);
|
|
1364
|
+
|
|
1365
|
+
if (isDefined(baseMainSize) && isDefined(boundMainSize) && baseMainSize !== boundMainSize) {
|
|
1366
|
+
// By excluding this item's size and flex factor from remaining,
|
|
1367
|
+
// this item's min/max constraints should also trigger in the second
|
|
1368
|
+
// pass resulting in the item's size calculation being identical in
|
|
1369
|
+
// the first and second passes.
|
|
1370
|
+
deltaFreeSpace += boundMainSize - childFlexBasis;
|
|
1371
|
+
flexLine.layout.totalFlexGrowFactors -= flexGrowFactor;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
flexLine.layout.remainingFreeSpace -= deltaFreeSpace;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// Do two passes over the flex items to figure out how to distribute the
|
|
1380
|
+
// remaining space.
|
|
1381
|
+
//
|
|
1382
|
+
// The first pass finds the items whose min/max constraints trigger, freezes
|
|
1383
|
+
// them at those sizes, and excludes those sizes from the remaining space.
|
|
1384
|
+
//
|
|
1385
|
+
// The second pass sets the size of each flexible item. It distributes the
|
|
1386
|
+
// remaining space amongst the items whose min/max constraints didn't trigger
|
|
1387
|
+
// in the first pass. For the other items, it sets their sizes by forcing
|
|
1388
|
+
// their min/max constraints to trigger again.
|
|
1389
|
+
//
|
|
1390
|
+
// This two pass approach for resolving min/max constraints deviates from the
|
|
1391
|
+
// spec. The spec (https://www.w3.org/TR/CSS-flexbox-1/#resolve-flexible-lengths)
|
|
1392
|
+
// describes a process that needs to be repeated a variable number of times.
|
|
1393
|
+
// The algorithm implemented here won't handle all cases but it was simpler to
|
|
1394
|
+
// implement and it mitigates performance concerns because we know exactly how
|
|
1395
|
+
// many passes it'll do.
|
|
1396
|
+
//
|
|
1397
|
+
// At the end of this function the child nodes would have the proper size
|
|
1398
|
+
// assigned to them.
|
|
1399
|
+
//
|
|
1400
|
+
function resolveFlexibleLength(
|
|
1401
|
+
node: Node,
|
|
1402
|
+
flexLine: FlexLine,
|
|
1403
|
+
mainAxis: FlexDirection,
|
|
1404
|
+
crossAxis: FlexDirection,
|
|
1405
|
+
direction: Direction,
|
|
1406
|
+
ownerWidth: number,
|
|
1407
|
+
mainAxisOwnerSize: number,
|
|
1408
|
+
availableInnerMainDim: number,
|
|
1409
|
+
availableInnerCrossDim: number,
|
|
1410
|
+
availableInnerWidth: number,
|
|
1411
|
+
availableInnerHeight: number,
|
|
1412
|
+
mainAxisOverflows: boolean,
|
|
1413
|
+
sizingModeCrossDim: SizingMode,
|
|
1414
|
+
performLayout: boolean,
|
|
1415
|
+
layoutMarkerData: LayoutData,
|
|
1416
|
+
depth: number,
|
|
1417
|
+
generationCount: number,
|
|
1418
|
+
): void {
|
|
1419
|
+
const originalFreeSpace = flexLine.layout.remainingFreeSpace;
|
|
1420
|
+
|
|
1421
|
+
// CSS Flexbox §4.5: compute each item's automatic minimum main-axis size
|
|
1422
|
+
// up front so the bounding helpers below can floor shrunk values.
|
|
1423
|
+
if (!node.hasErrata(Errata.MinSizeUndefinedInsteadOfAuto)) {
|
|
1424
|
+
for (const currentLineChild of flexLine.itemsInFlow) {
|
|
1425
|
+
currentLineChild.layout.computedAutoMinMainSize = computeAutoMinMainSize(
|
|
1426
|
+
currentLineChild,
|
|
1427
|
+
mainAxis,
|
|
1428
|
+
direction,
|
|
1429
|
+
mainAxisOwnerSize,
|
|
1430
|
+
availableInnerWidth,
|
|
1431
|
+
availableInnerHeight,
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
} else {
|
|
1435
|
+
for (const currentLineChild of flexLine.itemsInFlow) {
|
|
1436
|
+
currentLineChild.layout.computedAutoMinMainSize = NaN;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// First pass: detect the flex items whose min/max constraints trigger
|
|
1441
|
+
distributeFreeSpaceFirstPass(
|
|
1442
|
+
flexLine,
|
|
1443
|
+
direction,
|
|
1444
|
+
mainAxis,
|
|
1445
|
+
ownerWidth,
|
|
1446
|
+
mainAxisOwnerSize,
|
|
1447
|
+
availableInnerMainDim,
|
|
1448
|
+
availableInnerWidth,
|
|
1449
|
+
);
|
|
1450
|
+
|
|
1451
|
+
// Second pass: resolve the sizes of the flexible items
|
|
1452
|
+
const distributedFreeSpace = distributeFreeSpaceSecondPass(
|
|
1453
|
+
flexLine,
|
|
1454
|
+
node,
|
|
1455
|
+
mainAxis,
|
|
1456
|
+
crossAxis,
|
|
1457
|
+
direction,
|
|
1458
|
+
ownerWidth,
|
|
1459
|
+
mainAxisOwnerSize,
|
|
1460
|
+
availableInnerMainDim,
|
|
1461
|
+
availableInnerCrossDim,
|
|
1462
|
+
availableInnerWidth,
|
|
1463
|
+
availableInnerHeight,
|
|
1464
|
+
mainAxisOverflows,
|
|
1465
|
+
sizingModeCrossDim,
|
|
1466
|
+
performLayout,
|
|
1467
|
+
layoutMarkerData,
|
|
1468
|
+
depth,
|
|
1469
|
+
generationCount,
|
|
1470
|
+
);
|
|
1471
|
+
|
|
1472
|
+
flexLine.layout.remainingFreeSpace = originalFreeSpace - distributedFreeSpace;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
function justifyMainAxis(
|
|
1476
|
+
node: Node,
|
|
1477
|
+
flexLine: FlexLine,
|
|
1478
|
+
mainAxis: FlexDirection,
|
|
1479
|
+
crossAxis: FlexDirection,
|
|
1480
|
+
direction: Direction,
|
|
1481
|
+
sizingModeMainDim: SizingMode,
|
|
1482
|
+
sizingModeCrossDim: SizingMode,
|
|
1483
|
+
mainAxisOwnerSize: number,
|
|
1484
|
+
ownerWidth: number,
|
|
1485
|
+
availableInnerMainDim: number,
|
|
1486
|
+
availableInnerCrossDim: number,
|
|
1487
|
+
availableInnerWidth: number,
|
|
1488
|
+
performLayout: boolean,
|
|
1489
|
+
): void {
|
|
1490
|
+
const style = node.style;
|
|
1491
|
+
|
|
1492
|
+
const leadingPaddingAndBorderMain = node.style.computeFlexStartPaddingAndBorder(
|
|
1493
|
+
mainAxis,
|
|
1494
|
+
direction,
|
|
1495
|
+
ownerWidth,
|
|
1496
|
+
);
|
|
1497
|
+
const trailingPaddingAndBorderMain = node.style.computeFlexEndPaddingAndBorder(
|
|
1498
|
+
mainAxis,
|
|
1499
|
+
direction,
|
|
1500
|
+
ownerWidth,
|
|
1501
|
+
);
|
|
1502
|
+
|
|
1503
|
+
const gap = node.style.computeGapForAxis(mainAxis, availableInnerMainDim);
|
|
1504
|
+
// If we are using "at most" rules in the main axis, make sure that
|
|
1505
|
+
// remainingFreeSpace is 0 when min main dimension is not given
|
|
1506
|
+
if (sizingModeMainDim === SizingMode.FitContent && flexLine.layout.remainingFreeSpace > 0) {
|
|
1507
|
+
if (
|
|
1508
|
+
style.minDimension(dimension(mainAxis)).isDefined() &&
|
|
1509
|
+
isDefined(
|
|
1510
|
+
style.resolvedMinDimension(direction, dimension(mainAxis), mainAxisOwnerSize, ownerWidth),
|
|
1511
|
+
)
|
|
1512
|
+
) {
|
|
1513
|
+
// This condition makes sure that if the size of main dimension(after
|
|
1514
|
+
// considering child nodes main dim, leading and trailing padding etc)
|
|
1515
|
+
// falls below min dimension, then the remainingFreeSpace is reassigned
|
|
1516
|
+
// considering the min dimension
|
|
1517
|
+
|
|
1518
|
+
// `minAvailableMainDim` denotes minimum available space in which child
|
|
1519
|
+
// can be laid out, it will exclude space consumed by padding and border.
|
|
1520
|
+
const minAvailableMainDim =
|
|
1521
|
+
style.resolvedMinDimension(direction, dimension(mainAxis), mainAxisOwnerSize, ownerWidth) -
|
|
1522
|
+
leadingPaddingAndBorderMain -
|
|
1523
|
+
trailingPaddingAndBorderMain;
|
|
1524
|
+
const occupiedSpaceByChildNodes = availableInnerMainDim - flexLine.layout.remainingFreeSpace;
|
|
1525
|
+
flexLine.layout.remainingFreeSpace = maxOrDefined(
|
|
1526
|
+
0,
|
|
1527
|
+
minAvailableMainDim - occupiedSpaceByChildNodes,
|
|
1528
|
+
);
|
|
1529
|
+
} else {
|
|
1530
|
+
flexLine.layout.remainingFreeSpace = 0;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// In order to position the elements in the main axis, we have two controls.
|
|
1535
|
+
// The space between the beginning and the first element and the space
|
|
1536
|
+
// between each two elements.
|
|
1537
|
+
let leadingMainDim = 0;
|
|
1538
|
+
let betweenMainDim = gap;
|
|
1539
|
+
const justifyContent =
|
|
1540
|
+
flexLine.layout.remainingFreeSpace >= 0
|
|
1541
|
+
? node.style.justifyContent()
|
|
1542
|
+
: fallbackJustification(node.style.justifyContent());
|
|
1543
|
+
|
|
1544
|
+
if (flexLine.numberOfAutoMargins === 0) {
|
|
1545
|
+
switch (justifyContent) {
|
|
1546
|
+
case Justify.Start:
|
|
1547
|
+
case Justify.End:
|
|
1548
|
+
case Justify.Auto:
|
|
1549
|
+
// No-Op
|
|
1550
|
+
break;
|
|
1551
|
+
case Justify.Stretch:
|
|
1552
|
+
// No-Op
|
|
1553
|
+
break;
|
|
1554
|
+
case Justify.Center:
|
|
1555
|
+
leadingMainDim = flexLine.layout.remainingFreeSpace / 2;
|
|
1556
|
+
break;
|
|
1557
|
+
case Justify.FlexEnd:
|
|
1558
|
+
leadingMainDim = flexLine.layout.remainingFreeSpace;
|
|
1559
|
+
break;
|
|
1560
|
+
case Justify.SpaceBetween:
|
|
1561
|
+
if (flexLine.itemsInFlow.length > 1) {
|
|
1562
|
+
betweenMainDim += flexLine.layout.remainingFreeSpace / (flexLine.itemsInFlow.length - 1);
|
|
1563
|
+
}
|
|
1564
|
+
break;
|
|
1565
|
+
case Justify.SpaceEvenly:
|
|
1566
|
+
// Space is distributed evenly across all elements
|
|
1567
|
+
leadingMainDim = flexLine.layout.remainingFreeSpace / (flexLine.itemsInFlow.length + 1);
|
|
1568
|
+
betweenMainDim += leadingMainDim;
|
|
1569
|
+
break;
|
|
1570
|
+
case Justify.SpaceAround:
|
|
1571
|
+
// Space on the edges is half of the space between elements
|
|
1572
|
+
leadingMainDim = (0.5 * flexLine.layout.remainingFreeSpace) / flexLine.itemsInFlow.length;
|
|
1573
|
+
betweenMainDim += leadingMainDim * 2;
|
|
1574
|
+
break;
|
|
1575
|
+
case Justify.FlexStart:
|
|
1576
|
+
break;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
flexLine.layout.mainDim = leadingPaddingAndBorderMain + leadingMainDim;
|
|
1581
|
+
flexLine.layout.crossDim = 0;
|
|
1582
|
+
|
|
1583
|
+
let maxAscentForCurrentLine = 0;
|
|
1584
|
+
let maxDescentForCurrentLine = 0;
|
|
1585
|
+
const isNodeBaselineLayout = isBaselineLayout(node);
|
|
1586
|
+
for (const child of flexLine.itemsInFlow) {
|
|
1587
|
+
const childLayout = child.layout;
|
|
1588
|
+
if (
|
|
1589
|
+
child.style.flexStartMarginIsAuto(mainAxis, direction) &&
|
|
1590
|
+
flexLine.layout.remainingFreeSpace > 0
|
|
1591
|
+
) {
|
|
1592
|
+
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / flexLine.numberOfAutoMargins;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
if (performLayout) {
|
|
1596
|
+
child.setLayoutPosition(
|
|
1597
|
+
childLayout.position(flexStartEdge(mainAxis)) + flexLine.layout.mainDim,
|
|
1598
|
+
flexStartEdge(mainAxis),
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
if (child !== flexLine.itemsInFlow[flexLine.itemsInFlow.length - 1]) {
|
|
1603
|
+
flexLine.layout.mainDim += betweenMainDim;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
if (
|
|
1607
|
+
child.style.flexEndMarginIsAuto(mainAxis, direction) &&
|
|
1608
|
+
flexLine.layout.remainingFreeSpace > 0
|
|
1609
|
+
) {
|
|
1610
|
+
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace / flexLine.numberOfAutoMargins;
|
|
1611
|
+
}
|
|
1612
|
+
const canSkipFlex = !performLayout && sizingModeCrossDim === SizingMode.StretchFit;
|
|
1613
|
+
if (canSkipFlex) {
|
|
1614
|
+
// If we skipped the flex step, then we can't rely on the measuredDims
|
|
1615
|
+
// because they weren't computed. This means we can't call
|
|
1616
|
+
// dimensionWithMargin.
|
|
1617
|
+
flexLine.layout.mainDim +=
|
|
1618
|
+
child.style.computeMarginForAxis(mainAxis, availableInnerWidth) +
|
|
1619
|
+
boundAxisWithinMinAndMax(
|
|
1620
|
+
child,
|
|
1621
|
+
direction,
|
|
1622
|
+
mainAxis,
|
|
1623
|
+
childLayout.computedFlexBasis,
|
|
1624
|
+
mainAxisOwnerSize,
|
|
1625
|
+
ownerWidth,
|
|
1626
|
+
);
|
|
1627
|
+
flexLine.layout.crossDim = availableInnerCrossDim;
|
|
1628
|
+
} else {
|
|
1629
|
+
// The main dimension is the sum of all the elements dimension plus
|
|
1630
|
+
// the spacing.
|
|
1631
|
+
flexLine.layout.mainDim += child.dimensionWithMargin(mainAxis, availableInnerWidth);
|
|
1632
|
+
|
|
1633
|
+
if (isNodeBaselineLayout) {
|
|
1634
|
+
// If the child is baseline aligned then the cross dimension is
|
|
1635
|
+
// calculated by adding maxAscent and maxDescent from the baseline.
|
|
1636
|
+
const ascent =
|
|
1637
|
+
calculateBaseline(child) +
|
|
1638
|
+
child.style.computeFlexStartMargin(FlexDirection.Column, direction, availableInnerWidth);
|
|
1639
|
+
const descent =
|
|
1640
|
+
child.layout.measuredDimension(Dimension.Height) +
|
|
1641
|
+
child.style.computeMarginForAxis(FlexDirection.Column, availableInnerWidth) -
|
|
1642
|
+
ascent;
|
|
1643
|
+
|
|
1644
|
+
maxAscentForCurrentLine = maxOrDefined(maxAscentForCurrentLine, ascent);
|
|
1645
|
+
maxDescentForCurrentLine = maxOrDefined(maxDescentForCurrentLine, descent);
|
|
1646
|
+
} else {
|
|
1647
|
+
// The cross dimension is the max of the elements dimension since
|
|
1648
|
+
// there can only be one element in that cross dimension in the case
|
|
1649
|
+
// when the items are not baseline aligned
|
|
1650
|
+
flexLine.layout.crossDim = maxOrDefined(
|
|
1651
|
+
flexLine.layout.crossDim,
|
|
1652
|
+
child.dimensionWithMargin(crossAxis, availableInnerWidth),
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
flexLine.layout.mainDim += trailingPaddingAndBorderMain;
|
|
1658
|
+
|
|
1659
|
+
if (isNodeBaselineLayout) {
|
|
1660
|
+
flexLine.layout.crossDim = maxAscentForCurrentLine + maxDescentForCurrentLine;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
//
|
|
1665
|
+
// This is the main routine that implements a subset of the flexbox layout
|
|
1666
|
+
// algorithm described in the W3C CSS documentation:
|
|
1667
|
+
// https://www.w3.org/TR/CSS3-flexbox/. See CalculateLayout.cpp for the list of
|
|
1668
|
+
// limitations and deviations from the standard.
|
|
1669
|
+
//
|
|
1670
|
+
function calculateLayoutImpl(
|
|
1671
|
+
node: Node,
|
|
1672
|
+
availableWidth: number,
|
|
1673
|
+
availableHeight: number,
|
|
1674
|
+
ownerDirection: Direction,
|
|
1675
|
+
widthSizingMode: SizingMode,
|
|
1676
|
+
heightSizingMode: SizingMode,
|
|
1677
|
+
ownerWidth: number,
|
|
1678
|
+
ownerHeight: number,
|
|
1679
|
+
performLayout: boolean,
|
|
1680
|
+
_reason: LayoutPassReason,
|
|
1681
|
+
layoutMarkerData: LayoutData,
|
|
1682
|
+
depth: number,
|
|
1683
|
+
generationCount: number,
|
|
1684
|
+
): void {
|
|
1685
|
+
if (isUndefined(availableWidth) && widthSizingMode !== SizingMode.MaxContent) {
|
|
1686
|
+
throw new Error(
|
|
1687
|
+
"availableWidth is indefinite so widthSizingMode must be SizingMode::MaxContent",
|
|
1688
|
+
);
|
|
1689
|
+
}
|
|
1690
|
+
if (isUndefined(availableHeight) && heightSizingMode !== SizingMode.MaxContent) {
|
|
1691
|
+
throw new Error(
|
|
1692
|
+
"availableHeight is indefinite so heightSizingMode must be SizingMode::MaxContent",
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
if (performLayout) {
|
|
1697
|
+
layoutMarkerData.layouts += 1;
|
|
1698
|
+
} else {
|
|
1699
|
+
layoutMarkerData.measures += 1;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// Set the resolved resolution in the node's layout.
|
|
1703
|
+
const direction = node.resolveDirection(ownerDirection);
|
|
1704
|
+
node.setLayoutDirection(direction);
|
|
1705
|
+
const fixFlexBasisFitContent = node.config.isExperimentalFeatureEnabled(
|
|
1706
|
+
ExperimentalFeature.FixFlexBasisFitContent,
|
|
1707
|
+
);
|
|
1708
|
+
if (fixFlexBasisFitContent && performLayout) {
|
|
1709
|
+
node.setLayoutHadOverflow(false);
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
const flexRowDirection = resolveDirection(FlexDirection.Row, direction);
|
|
1713
|
+
const flexColumnDirection = resolveDirection(FlexDirection.Column, direction);
|
|
1714
|
+
|
|
1715
|
+
const startEdge = direction === Direction.LTR ? PhysicalEdge.Left : PhysicalEdge.Right;
|
|
1716
|
+
const endEdge = direction === Direction.LTR ? PhysicalEdge.Right : PhysicalEdge.Left;
|
|
1717
|
+
|
|
1718
|
+
const marginRowLeading = node.style.computeInlineStartMargin(
|
|
1719
|
+
flexRowDirection,
|
|
1720
|
+
direction,
|
|
1721
|
+
ownerWidth,
|
|
1722
|
+
);
|
|
1723
|
+
node.setLayoutMargin(marginRowLeading, startEdge);
|
|
1724
|
+
const marginRowTrailing = node.style.computeInlineEndMargin(
|
|
1725
|
+
flexRowDirection,
|
|
1726
|
+
direction,
|
|
1727
|
+
ownerWidth,
|
|
1728
|
+
);
|
|
1729
|
+
node.setLayoutMargin(marginRowTrailing, endEdge);
|
|
1730
|
+
const marginColumnLeading = node.style.computeInlineStartMargin(
|
|
1731
|
+
flexColumnDirection,
|
|
1732
|
+
direction,
|
|
1733
|
+
ownerWidth,
|
|
1734
|
+
);
|
|
1735
|
+
node.setLayoutMargin(marginColumnLeading, PhysicalEdge.Top);
|
|
1736
|
+
const marginColumnTrailing = node.style.computeInlineEndMargin(
|
|
1737
|
+
flexColumnDirection,
|
|
1738
|
+
direction,
|
|
1739
|
+
ownerWidth,
|
|
1740
|
+
);
|
|
1741
|
+
node.setLayoutMargin(marginColumnTrailing, PhysicalEdge.Bottom);
|
|
1742
|
+
|
|
1743
|
+
const marginAxisRow = marginRowLeading + marginRowTrailing;
|
|
1744
|
+
const marginAxisColumn = marginColumnLeading + marginColumnTrailing;
|
|
1745
|
+
|
|
1746
|
+
node.setLayoutBorder(node.style.computeInlineStartBorder(flexRowDirection, direction), startEdge);
|
|
1747
|
+
node.setLayoutBorder(node.style.computeInlineEndBorder(flexRowDirection, direction), endEdge);
|
|
1748
|
+
node.setLayoutBorder(
|
|
1749
|
+
node.style.computeInlineStartBorder(flexColumnDirection, direction),
|
|
1750
|
+
PhysicalEdge.Top,
|
|
1751
|
+
);
|
|
1752
|
+
node.setLayoutBorder(
|
|
1753
|
+
node.style.computeInlineEndBorder(flexColumnDirection, direction),
|
|
1754
|
+
PhysicalEdge.Bottom,
|
|
1755
|
+
);
|
|
1756
|
+
|
|
1757
|
+
node.setLayoutPadding(
|
|
1758
|
+
node.style.computeInlineStartPadding(flexRowDirection, direction, ownerWidth),
|
|
1759
|
+
startEdge,
|
|
1760
|
+
);
|
|
1761
|
+
node.setLayoutPadding(
|
|
1762
|
+
node.style.computeInlineEndPadding(flexRowDirection, direction, ownerWidth),
|
|
1763
|
+
endEdge,
|
|
1764
|
+
);
|
|
1765
|
+
node.setLayoutPadding(
|
|
1766
|
+
node.style.computeInlineStartPadding(flexColumnDirection, direction, ownerWidth),
|
|
1767
|
+
PhysicalEdge.Top,
|
|
1768
|
+
);
|
|
1769
|
+
node.setLayoutPadding(
|
|
1770
|
+
node.style.computeInlineEndPadding(flexColumnDirection, direction, ownerWidth),
|
|
1771
|
+
PhysicalEdge.Bottom,
|
|
1772
|
+
);
|
|
1773
|
+
|
|
1774
|
+
if (node.hasMeasureFunc()) {
|
|
1775
|
+
measureNodeWithMeasureFunc(
|
|
1776
|
+
node,
|
|
1777
|
+
direction,
|
|
1778
|
+
availableWidth - marginAxisRow,
|
|
1779
|
+
availableHeight - marginAxisColumn,
|
|
1780
|
+
widthSizingMode,
|
|
1781
|
+
heightSizingMode,
|
|
1782
|
+
ownerWidth,
|
|
1783
|
+
ownerHeight,
|
|
1784
|
+
layoutMarkerData,
|
|
1785
|
+
);
|
|
1786
|
+
|
|
1787
|
+
// Clean and update all display: contents nodes with a direct path to the
|
|
1788
|
+
// current node as they will not be traversed
|
|
1789
|
+
cleanupContentsNodesRecursively(node, performLayout);
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
const layoutChildren = node.getLayoutChildren();
|
|
1794
|
+
const childCount = layoutChildren.length;
|
|
1795
|
+
if (childCount === 0) {
|
|
1796
|
+
measureNodeWithoutChildren(
|
|
1797
|
+
node,
|
|
1798
|
+
direction,
|
|
1799
|
+
availableWidth - marginAxisRow,
|
|
1800
|
+
availableHeight - marginAxisColumn,
|
|
1801
|
+
widthSizingMode,
|
|
1802
|
+
heightSizingMode,
|
|
1803
|
+
ownerWidth,
|
|
1804
|
+
ownerHeight,
|
|
1805
|
+
);
|
|
1806
|
+
|
|
1807
|
+
// Clean and update all display: contents nodes with a direct path to the
|
|
1808
|
+
// current node as they will not be traversed
|
|
1809
|
+
cleanupContentsNodesRecursively(node, performLayout);
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
// If we're not being asked to perform a full layout we can skip the
|
|
1814
|
+
// algorithm if we already know the size
|
|
1815
|
+
if (
|
|
1816
|
+
!performLayout &&
|
|
1817
|
+
measureNodeWithFixedSize(
|
|
1818
|
+
node,
|
|
1819
|
+
direction,
|
|
1820
|
+
availableWidth - marginAxisRow,
|
|
1821
|
+
availableHeight - marginAxisColumn,
|
|
1822
|
+
widthSizingMode,
|
|
1823
|
+
heightSizingMode,
|
|
1824
|
+
ownerWidth,
|
|
1825
|
+
ownerHeight,
|
|
1826
|
+
)
|
|
1827
|
+
) {
|
|
1828
|
+
// Clean and update all display: contents nodes with a direct path to the
|
|
1829
|
+
// current node as they will not be traversed
|
|
1830
|
+
cleanupContentsNodesRecursively(node, /* didPerformLayout */ false);
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// At this point we know we're going to perform work. Ensure that each child
|
|
1835
|
+
// has a mutable copy.
|
|
1836
|
+
node.cloneChildrenIfNeeded();
|
|
1837
|
+
if (!fixFlexBasisFitContent || !performLayout) {
|
|
1838
|
+
node.setLayoutHadOverflow(false);
|
|
1839
|
+
}
|
|
1840
|
+
// Clean and update all display: contents nodes with a direct path to the
|
|
1841
|
+
// current node as they will not be traversed
|
|
1842
|
+
cleanupContentsNodesRecursively(node, performLayout);
|
|
1843
|
+
|
|
1844
|
+
// STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
|
|
1845
|
+
const mainAxis = resolveDirection(node.style.flexDirection(), direction);
|
|
1846
|
+
const crossAxis = resolveCrossDirection(mainAxis, direction);
|
|
1847
|
+
const isMainAxisRow = isRow(mainAxis);
|
|
1848
|
+
const isNodeFlexWrap = node.style.flexWrap() !== Wrap.NoWrap;
|
|
1849
|
+
|
|
1850
|
+
const mainAxisOwnerSize = isMainAxisRow ? ownerWidth : ownerHeight;
|
|
1851
|
+
const crossAxisOwnerSize = isMainAxisRow ? ownerHeight : ownerWidth;
|
|
1852
|
+
|
|
1853
|
+
const paddingAndBorderAxisMain = paddingAndBorderForAxis(node, mainAxis, direction, ownerWidth);
|
|
1854
|
+
const paddingAndBorderAxisCross = paddingAndBorderForAxis(node, crossAxis, direction, ownerWidth);
|
|
1855
|
+
const leadingPaddingAndBorderCross = node.style.computeFlexStartPaddingAndBorder(
|
|
1856
|
+
crossAxis,
|
|
1857
|
+
direction,
|
|
1858
|
+
ownerWidth,
|
|
1859
|
+
);
|
|
1860
|
+
|
|
1861
|
+
let sizingModeMainDim = isMainAxisRow ? widthSizingMode : heightSizingMode;
|
|
1862
|
+
const sizingModeCrossDim = isMainAxisRow ? heightSizingMode : widthSizingMode;
|
|
1863
|
+
|
|
1864
|
+
const paddingAndBorderAxisRow = isMainAxisRow
|
|
1865
|
+
? paddingAndBorderAxisMain
|
|
1866
|
+
: paddingAndBorderAxisCross;
|
|
1867
|
+
const paddingAndBorderAxisColumn = isMainAxisRow
|
|
1868
|
+
? paddingAndBorderAxisCross
|
|
1869
|
+
: paddingAndBorderAxisMain;
|
|
1870
|
+
|
|
1871
|
+
// STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
|
|
1872
|
+
|
|
1873
|
+
const availableInnerWidth = calculateAvailableInnerDimension(
|
|
1874
|
+
node,
|
|
1875
|
+
direction,
|
|
1876
|
+
Dimension.Width,
|
|
1877
|
+
availableWidth - marginAxisRow,
|
|
1878
|
+
paddingAndBorderAxisRow,
|
|
1879
|
+
ownerWidth,
|
|
1880
|
+
ownerWidth,
|
|
1881
|
+
);
|
|
1882
|
+
const availableInnerHeight = calculateAvailableInnerDimension(
|
|
1883
|
+
node,
|
|
1884
|
+
direction,
|
|
1885
|
+
Dimension.Height,
|
|
1886
|
+
availableHeight - marginAxisColumn,
|
|
1887
|
+
paddingAndBorderAxisColumn,
|
|
1888
|
+
ownerHeight,
|
|
1889
|
+
ownerWidth,
|
|
1890
|
+
);
|
|
1891
|
+
|
|
1892
|
+
let availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight;
|
|
1893
|
+
const availableInnerCrossDim = isMainAxisRow ? availableInnerHeight : availableInnerWidth;
|
|
1894
|
+
|
|
1895
|
+
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
|
|
1896
|
+
|
|
1897
|
+
// Computed basis + margins + gap
|
|
1898
|
+
let totalMainDim = 0;
|
|
1899
|
+
totalMainDim += computeFlexBasisForChildren(
|
|
1900
|
+
node,
|
|
1901
|
+
layoutChildren,
|
|
1902
|
+
availableInnerWidth,
|
|
1903
|
+
availableInnerHeight,
|
|
1904
|
+
availableInnerWidth,
|
|
1905
|
+
availableInnerHeight,
|
|
1906
|
+
widthSizingMode,
|
|
1907
|
+
heightSizingMode,
|
|
1908
|
+
direction,
|
|
1909
|
+
mainAxis,
|
|
1910
|
+
performLayout,
|
|
1911
|
+
layoutMarkerData,
|
|
1912
|
+
depth,
|
|
1913
|
+
generationCount,
|
|
1914
|
+
);
|
|
1915
|
+
|
|
1916
|
+
if (childCount > 1) {
|
|
1917
|
+
totalMainDim +=
|
|
1918
|
+
node.style.computeGapForAxis(mainAxis, availableInnerMainDim) * (childCount - 1);
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
const mainAxisOverflows =
|
|
1922
|
+
sizingModeMainDim !== SizingMode.MaxContent && totalMainDim > availableInnerMainDim;
|
|
1923
|
+
|
|
1924
|
+
if (isNodeFlexWrap && mainAxisOverflows && sizingModeMainDim === SizingMode.FitContent) {
|
|
1925
|
+
sizingModeMainDim = SizingMode.StretchFit;
|
|
1926
|
+
}
|
|
1927
|
+
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
|
1928
|
+
|
|
1929
|
+
// Index of the first child of the current line.
|
|
1930
|
+
let startOfLineIndex = 0;
|
|
1931
|
+
|
|
1932
|
+
// Number of lines.
|
|
1933
|
+
let lineCount = 0;
|
|
1934
|
+
|
|
1935
|
+
// Accumulated cross dimensions of all lines so far.
|
|
1936
|
+
let totalLineCrossDim = 0;
|
|
1937
|
+
|
|
1938
|
+
const crossAxisGap = node.style.computeGapForAxis(crossAxis, availableInnerCrossDim);
|
|
1939
|
+
|
|
1940
|
+
// Max main dimension of all the lines.
|
|
1941
|
+
let maxLineMainDim = 0;
|
|
1942
|
+
const flexLine = (node.layout.flexLine ??= {
|
|
1943
|
+
itemsInFlow: [],
|
|
1944
|
+
sizeConsumed: 0,
|
|
1945
|
+
numberOfAutoMargins: 0,
|
|
1946
|
+
endIndex: 0,
|
|
1947
|
+
layout: {
|
|
1948
|
+
totalFlexGrowFactors: 0,
|
|
1949
|
+
totalFlexShrinkScaledFactors: 0,
|
|
1950
|
+
remainingFreeSpace: 0,
|
|
1951
|
+
mainDim: 0,
|
|
1952
|
+
crossDim: 0,
|
|
1953
|
+
},
|
|
1954
|
+
});
|
|
1955
|
+
const lineStarts = (node.layout.flexLineStarts ??= []);
|
|
1956
|
+
for (; startOfLineIndex < layoutChildren.length; lineCount++) {
|
|
1957
|
+
lineStarts[lineCount] = startOfLineIndex;
|
|
1958
|
+
calculateFlexLine(
|
|
1959
|
+
node,
|
|
1960
|
+
ownerDirection,
|
|
1961
|
+
ownerWidth,
|
|
1962
|
+
mainAxisOwnerSize,
|
|
1963
|
+
availableInnerWidth,
|
|
1964
|
+
availableInnerMainDim,
|
|
1965
|
+
layoutChildren,
|
|
1966
|
+
startOfLineIndex,
|
|
1967
|
+
lineCount,
|
|
1968
|
+
flexLine,
|
|
1969
|
+
);
|
|
1970
|
+
startOfLineIndex = flexLine.endIndex;
|
|
1971
|
+
|
|
1972
|
+
// If we don't need to measure the cross axis, we can skip the entire flex
|
|
1973
|
+
// step.
|
|
1974
|
+
const canSkipFlex = !performLayout && sizingModeCrossDim === SizingMode.StretchFit;
|
|
1975
|
+
|
|
1976
|
+
// STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
|
|
1977
|
+
// Calculate the remaining available space that needs to be allocated. If
|
|
1978
|
+
// the main dimension size isn't known, it is computed based on the line
|
|
1979
|
+
// length, so there's no more space left to distribute.
|
|
1980
|
+
|
|
1981
|
+
let sizeBasedOnContent = false;
|
|
1982
|
+
// If we don't measure with exact main dimension we want to ensure we don't
|
|
1983
|
+
// violate min and max
|
|
1984
|
+
if (sizingModeMainDim !== SizingMode.StretchFit) {
|
|
1985
|
+
const style = node.style;
|
|
1986
|
+
const minInnerWidth =
|
|
1987
|
+
style.resolvedMinDimension(direction, Dimension.Width, ownerWidth, ownerWidth) -
|
|
1988
|
+
paddingAndBorderAxisRow;
|
|
1989
|
+
const maxInnerWidth =
|
|
1990
|
+
style.resolvedMaxDimension(direction, Dimension.Width, ownerWidth, ownerWidth) -
|
|
1991
|
+
paddingAndBorderAxisRow;
|
|
1992
|
+
const minInnerHeight =
|
|
1993
|
+
style.resolvedMinDimension(direction, Dimension.Height, ownerHeight, ownerWidth) -
|
|
1994
|
+
paddingAndBorderAxisColumn;
|
|
1995
|
+
const maxInnerHeight =
|
|
1996
|
+
style.resolvedMaxDimension(direction, Dimension.Height, ownerHeight, ownerWidth) -
|
|
1997
|
+
paddingAndBorderAxisColumn;
|
|
1998
|
+
|
|
1999
|
+
const minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
|
|
2000
|
+
const maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
|
|
2001
|
+
|
|
2002
|
+
if (isDefined(minInnerMainDim) && flexLine.sizeConsumed < minInnerMainDim) {
|
|
2003
|
+
availableInnerMainDim = minInnerMainDim;
|
|
2004
|
+
} else if (isDefined(maxInnerMainDim) && flexLine.sizeConsumed > maxInnerMainDim) {
|
|
2005
|
+
availableInnerMainDim = maxInnerMainDim;
|
|
2006
|
+
} else {
|
|
2007
|
+
const useLegacyStretchBehaviour = node.hasErrata(Errata.StretchFlexBasis);
|
|
2008
|
+
|
|
2009
|
+
if (
|
|
2010
|
+
!useLegacyStretchBehaviour &&
|
|
2011
|
+
((isDefined(flexLine.layout.totalFlexGrowFactors) &&
|
|
2012
|
+
flexLine.layout.totalFlexGrowFactors === 0) ||
|
|
2013
|
+
(isDefined(node.resolveFlexGrow()) && node.resolveFlexGrow() === 0))
|
|
2014
|
+
) {
|
|
2015
|
+
// If we don't have any children to flex or we can't flex the node
|
|
2016
|
+
// itself, space we've used is all space we need. Root node also
|
|
2017
|
+
// should be shrunk to minimum
|
|
2018
|
+
availableInnerMainDim = flexLine.sizeConsumed;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
sizeBasedOnContent = !useLegacyStretchBehaviour;
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
if (!sizeBasedOnContent && isDefined(availableInnerMainDim)) {
|
|
2026
|
+
flexLine.layout.remainingFreeSpace = availableInnerMainDim - flexLine.sizeConsumed;
|
|
2027
|
+
} else if (flexLine.sizeConsumed < 0) {
|
|
2028
|
+
// availableInnerMainDim is indefinite which means the node is being
|
|
2029
|
+
// sized based on its content. sizeConsumed is negative which means
|
|
2030
|
+
// the node will allocate 0 points for its content. Consequently,
|
|
2031
|
+
// remainingFreeSpace is 0 - sizeConsumed.
|
|
2032
|
+
flexLine.layout.remainingFreeSpace = -flexLine.sizeConsumed;
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
if (!canSkipFlex) {
|
|
2036
|
+
resolveFlexibleLength(
|
|
2037
|
+
node,
|
|
2038
|
+
flexLine,
|
|
2039
|
+
mainAxis,
|
|
2040
|
+
crossAxis,
|
|
2041
|
+
direction,
|
|
2042
|
+
ownerWidth,
|
|
2043
|
+
mainAxisOwnerSize,
|
|
2044
|
+
availableInnerMainDim,
|
|
2045
|
+
availableInnerCrossDim,
|
|
2046
|
+
availableInnerWidth,
|
|
2047
|
+
availableInnerHeight,
|
|
2048
|
+
mainAxisOverflows,
|
|
2049
|
+
sizingModeCrossDim,
|
|
2050
|
+
performLayout,
|
|
2051
|
+
layoutMarkerData,
|
|
2052
|
+
depth,
|
|
2053
|
+
generationCount,
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
node.setLayoutHadOverflow(node.layout.hadOverflow() || flexLine.layout.remainingFreeSpace < 0);
|
|
2058
|
+
|
|
2059
|
+
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
|
2060
|
+
|
|
2061
|
+
// At this point, all the children have their dimensions set in the main
|
|
2062
|
+
// axis. Their dimensions are also set in the cross axis with the exception
|
|
2063
|
+
// of items that are aligned "stretch". We need to compute these stretch
|
|
2064
|
+
// values and set the final positions.
|
|
2065
|
+
|
|
2066
|
+
justifyMainAxis(
|
|
2067
|
+
node,
|
|
2068
|
+
flexLine,
|
|
2069
|
+
mainAxis,
|
|
2070
|
+
crossAxis,
|
|
2071
|
+
direction,
|
|
2072
|
+
sizingModeMainDim,
|
|
2073
|
+
sizingModeCrossDim,
|
|
2074
|
+
mainAxisOwnerSize,
|
|
2075
|
+
ownerWidth,
|
|
2076
|
+
availableInnerMainDim,
|
|
2077
|
+
availableInnerCrossDim,
|
|
2078
|
+
availableInnerWidth,
|
|
2079
|
+
performLayout,
|
|
2080
|
+
);
|
|
2081
|
+
|
|
2082
|
+
let containerCrossAxis = availableInnerCrossDim;
|
|
2083
|
+
if (
|
|
2084
|
+
sizingModeCrossDim === SizingMode.MaxContent ||
|
|
2085
|
+
sizingModeCrossDim === SizingMode.FitContent
|
|
2086
|
+
) {
|
|
2087
|
+
// Compute the cross axis from the max cross dimension of the children.
|
|
2088
|
+
containerCrossAxis =
|
|
2089
|
+
boundAxis(
|
|
2090
|
+
node,
|
|
2091
|
+
crossAxis,
|
|
2092
|
+
direction,
|
|
2093
|
+
flexLine.layout.crossDim + paddingAndBorderAxisCross,
|
|
2094
|
+
crossAxisOwnerSize,
|
|
2095
|
+
ownerWidth,
|
|
2096
|
+
) - paddingAndBorderAxisCross;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
// If there's no flex wrap, the cross dimension is defined by the
|
|
2100
|
+
// container.
|
|
2101
|
+
if (!isNodeFlexWrap && sizingModeCrossDim === SizingMode.StretchFit) {
|
|
2102
|
+
flexLine.layout.crossDim = availableInnerCrossDim;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
// As-per https://www.w3.org/TR/css-flexbox-1/#cross-sizing, the
|
|
2106
|
+
// cross-size of the line within a single-line container should be bound
|
|
2107
|
+
// to min/max constraints before alignment within the line. In a
|
|
2108
|
+
// multi-line container, affecting alignment between the lines.
|
|
2109
|
+
if (!isNodeFlexWrap) {
|
|
2110
|
+
flexLine.layout.crossDim =
|
|
2111
|
+
boundAxis(
|
|
2112
|
+
node,
|
|
2113
|
+
crossAxis,
|
|
2114
|
+
direction,
|
|
2115
|
+
flexLine.layout.crossDim + paddingAndBorderAxisCross,
|
|
2116
|
+
crossAxisOwnerSize,
|
|
2117
|
+
ownerWidth,
|
|
2118
|
+
) - paddingAndBorderAxisCross;
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// STEP 7: CROSS-AXIS ALIGNMENT
|
|
2122
|
+
// We can skip child alignment if we're just measuring the container.
|
|
2123
|
+
if (performLayout) {
|
|
2124
|
+
for (const child of flexLine.itemsInFlow) {
|
|
2125
|
+
let leadingCrossDim = leadingPaddingAndBorderCross;
|
|
2126
|
+
|
|
2127
|
+
// For a relative children, we're either using alignItems (owner) or
|
|
2128
|
+
// alignSelf (child) in order to determine the position in the cross
|
|
2129
|
+
// axis
|
|
2130
|
+
const alignItem = resolveChildAlignment(node, child);
|
|
2131
|
+
|
|
2132
|
+
// If the child uses align stretch, we need to lay it out one more
|
|
2133
|
+
// time, this time forcing the cross-axis size to be the computed
|
|
2134
|
+
// cross size for the current line.
|
|
2135
|
+
if (
|
|
2136
|
+
alignItem === Align.Stretch &&
|
|
2137
|
+
!child.style.flexStartMarginIsAuto(crossAxis, direction) &&
|
|
2138
|
+
!child.style.flexEndMarginIsAuto(crossAxis, direction)
|
|
2139
|
+
) {
|
|
2140
|
+
// If the child defines a definite size for its cross axis, there's
|
|
2141
|
+
// no need to stretch.
|
|
2142
|
+
if (!child.hasDefiniteLength(dimension(crossAxis), availableInnerCrossDim)) {
|
|
2143
|
+
let childMainSize = child.layout.measuredDimension(dimension(mainAxis));
|
|
2144
|
+
const childStyle = child.style;
|
|
2145
|
+
const childCrossSize = isDefined(childStyle.aspectRatio())
|
|
2146
|
+
? child.style.computeMarginForAxis(crossAxis, availableInnerWidth) +
|
|
2147
|
+
(isMainAxisRow
|
|
2148
|
+
? childMainSize / childStyle.aspectRatio()
|
|
2149
|
+
: childMainSize * childStyle.aspectRatio())
|
|
2150
|
+
: flexLine.layout.crossDim;
|
|
2151
|
+
|
|
2152
|
+
childMainSize += child.style.computeMarginForAxis(mainAxis, availableInnerWidth);
|
|
2153
|
+
|
|
2154
|
+
const childMainModeAndSize = scratchModeA;
|
|
2155
|
+
childMainModeAndSize.mode = SizingMode.StretchFit;
|
|
2156
|
+
childMainModeAndSize.size = childMainSize;
|
|
2157
|
+
constrainMaxSizeForMode(
|
|
2158
|
+
child,
|
|
2159
|
+
direction,
|
|
2160
|
+
mainAxis,
|
|
2161
|
+
availableInnerMainDim,
|
|
2162
|
+
availableInnerWidth,
|
|
2163
|
+
childMainModeAndSize,
|
|
2164
|
+
);
|
|
2165
|
+
const childCrossModeAndSize = scratchModeB;
|
|
2166
|
+
childCrossModeAndSize.mode = SizingMode.StretchFit;
|
|
2167
|
+
childCrossModeAndSize.size = childCrossSize;
|
|
2168
|
+
constrainMaxSizeForMode(
|
|
2169
|
+
child,
|
|
2170
|
+
direction,
|
|
2171
|
+
crossAxis,
|
|
2172
|
+
availableInnerCrossDim,
|
|
2173
|
+
availableInnerWidth,
|
|
2174
|
+
childCrossModeAndSize,
|
|
2175
|
+
);
|
|
2176
|
+
|
|
2177
|
+
const childWidth = isMainAxisRow
|
|
2178
|
+
? childMainModeAndSize.size
|
|
2179
|
+
: childCrossModeAndSize.size;
|
|
2180
|
+
const childHeight = !isMainAxisRow
|
|
2181
|
+
? childMainModeAndSize.size
|
|
2182
|
+
: childCrossModeAndSize.size;
|
|
2183
|
+
|
|
2184
|
+
const alignContent = node.style.alignContent();
|
|
2185
|
+
const crossAxisDoesNotGrow = alignContent !== Align.Stretch && isNodeFlexWrap;
|
|
2186
|
+
const childWidthSizingMode =
|
|
2187
|
+
isUndefined(childWidth) || (!isMainAxisRow && crossAxisDoesNotGrow)
|
|
2188
|
+
? SizingMode.MaxContent
|
|
2189
|
+
: SizingMode.StretchFit;
|
|
2190
|
+
const childHeightSizingMode =
|
|
2191
|
+
isUndefined(childHeight) || (isMainAxisRow && crossAxisDoesNotGrow)
|
|
2192
|
+
? SizingMode.MaxContent
|
|
2193
|
+
: SizingMode.StretchFit;
|
|
2194
|
+
|
|
2195
|
+
calculateLayoutInternal(
|
|
2196
|
+
child,
|
|
2197
|
+
childWidth,
|
|
2198
|
+
childHeight,
|
|
2199
|
+
direction,
|
|
2200
|
+
childWidthSizingMode,
|
|
2201
|
+
childHeightSizingMode,
|
|
2202
|
+
availableInnerWidth,
|
|
2203
|
+
availableInnerHeight,
|
|
2204
|
+
true,
|
|
2205
|
+
LayoutPassReason.Stretch,
|
|
2206
|
+
layoutMarkerData,
|
|
2207
|
+
depth,
|
|
2208
|
+
generationCount,
|
|
2209
|
+
);
|
|
2210
|
+
}
|
|
2211
|
+
} else {
|
|
2212
|
+
const remainingCrossDim =
|
|
2213
|
+
containerCrossAxis - child.dimensionWithMargin(crossAxis, availableInnerWidth);
|
|
2214
|
+
|
|
2215
|
+
if (
|
|
2216
|
+
child.style.flexStartMarginIsAuto(crossAxis, direction) &&
|
|
2217
|
+
child.style.flexEndMarginIsAuto(crossAxis, direction)
|
|
2218
|
+
) {
|
|
2219
|
+
leadingCrossDim += maxOrDefined(0, remainingCrossDim / 2);
|
|
2220
|
+
} else if (child.style.flexEndMarginIsAuto(crossAxis, direction)) {
|
|
2221
|
+
// No-Op
|
|
2222
|
+
} else if (child.style.flexStartMarginIsAuto(crossAxis, direction)) {
|
|
2223
|
+
leadingCrossDim += maxOrDefined(0, remainingCrossDim);
|
|
2224
|
+
} else if (alignItem === Align.FlexStart) {
|
|
2225
|
+
// No-Op
|
|
2226
|
+
} else if (alignItem === Align.Center) {
|
|
2227
|
+
leadingCrossDim += remainingCrossDim / 2;
|
|
2228
|
+
} else {
|
|
2229
|
+
leadingCrossDim += remainingCrossDim;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
// And we apply the position
|
|
2233
|
+
child.setLayoutPosition(
|
|
2234
|
+
child.layout.position(flexStartEdge(crossAxis)) + totalLineCrossDim + leadingCrossDim,
|
|
2235
|
+
flexStartEdge(crossAxis),
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
const appliedCrossGap = lineCount !== 0 ? crossAxisGap : 0;
|
|
2241
|
+
totalLineCrossDim += flexLine.layout.crossDim + appliedCrossGap;
|
|
2242
|
+
maxLineMainDim = maxOrDefined(maxLineMainDim, flexLine.layout.mainDim);
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
|
|
2246
|
+
// currentLead stores the size of the cross dim
|
|
2247
|
+
if (performLayout && (isNodeFlexWrap || isBaselineLayout(node))) {
|
|
2248
|
+
let leadPerLine = 0;
|
|
2249
|
+
let currentLead = leadingPaddingAndBorderCross;
|
|
2250
|
+
let extraSpacePerLine = 0;
|
|
2251
|
+
|
|
2252
|
+
const unclampedCrossDim =
|
|
2253
|
+
sizingModeCrossDim === SizingMode.StretchFit
|
|
2254
|
+
? availableInnerCrossDim + paddingAndBorderAxisCross
|
|
2255
|
+
: node.hasDefiniteLength(dimension(crossAxis), crossAxisOwnerSize)
|
|
2256
|
+
? node.getResolvedDimension(
|
|
2257
|
+
direction,
|
|
2258
|
+
dimension(crossAxis),
|
|
2259
|
+
crossAxisOwnerSize,
|
|
2260
|
+
ownerWidth,
|
|
2261
|
+
)
|
|
2262
|
+
: totalLineCrossDim + paddingAndBorderAxisCross;
|
|
2263
|
+
|
|
2264
|
+
const innerCrossDim =
|
|
2265
|
+
boundAxis(node, crossAxis, direction, unclampedCrossDim, crossAxisOwnerSize, ownerWidth) -
|
|
2266
|
+
paddingAndBorderAxisCross;
|
|
2267
|
+
|
|
2268
|
+
const remainingAlignContentDim = innerCrossDim - totalLineCrossDim;
|
|
2269
|
+
|
|
2270
|
+
const alignContent =
|
|
2271
|
+
remainingAlignContentDim >= 0
|
|
2272
|
+
? node.style.alignContent()
|
|
2273
|
+
: fallbackAlignment(node.style.alignContent());
|
|
2274
|
+
|
|
2275
|
+
switch (alignContent) {
|
|
2276
|
+
case Align.Start:
|
|
2277
|
+
case Align.End:
|
|
2278
|
+
// No-Op
|
|
2279
|
+
break;
|
|
2280
|
+
case Align.FlexEnd:
|
|
2281
|
+
currentLead += remainingAlignContentDim;
|
|
2282
|
+
break;
|
|
2283
|
+
case Align.Center:
|
|
2284
|
+
currentLead += remainingAlignContentDim / 2;
|
|
2285
|
+
break;
|
|
2286
|
+
case Align.Stretch:
|
|
2287
|
+
extraSpacePerLine = remainingAlignContentDim / lineCount;
|
|
2288
|
+
break;
|
|
2289
|
+
case Align.SpaceAround:
|
|
2290
|
+
currentLead += remainingAlignContentDim / (2 * lineCount);
|
|
2291
|
+
leadPerLine = remainingAlignContentDim / lineCount;
|
|
2292
|
+
break;
|
|
2293
|
+
case Align.SpaceEvenly:
|
|
2294
|
+
currentLead += remainingAlignContentDim / (lineCount + 1);
|
|
2295
|
+
leadPerLine = remainingAlignContentDim / (lineCount + 1);
|
|
2296
|
+
break;
|
|
2297
|
+
case Align.SpaceBetween:
|
|
2298
|
+
if (lineCount > 1) {
|
|
2299
|
+
leadPerLine = remainingAlignContentDim / (lineCount - 1);
|
|
2300
|
+
}
|
|
2301
|
+
break;
|
|
2302
|
+
case Align.Auto:
|
|
2303
|
+
case Align.FlexStart:
|
|
2304
|
+
case Align.Baseline:
|
|
2305
|
+
break;
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
for (let i = 0; i < lineCount; i++) {
|
|
2309
|
+
const lineStart = lineStarts[i]!;
|
|
2310
|
+
|
|
2311
|
+
// compute the line's height and find the endIndex
|
|
2312
|
+
let lineHeight = 0;
|
|
2313
|
+
let maxAscentForCurrentLine = 0;
|
|
2314
|
+
let maxDescentForCurrentLine = 0;
|
|
2315
|
+
let endIndex = lineStart;
|
|
2316
|
+
for (let ii = lineStart; ii < layoutChildren.length; ii++) {
|
|
2317
|
+
const child = layoutChildren[ii]!;
|
|
2318
|
+
if (child.style.display() === Display.None) {
|
|
2319
|
+
endIndex = ii + 1;
|
|
2320
|
+
continue;
|
|
2321
|
+
}
|
|
2322
|
+
if (child.style.positionType() !== PositionType.Absolute) {
|
|
2323
|
+
if (child.lineIndex !== i) {
|
|
2324
|
+
break;
|
|
2325
|
+
}
|
|
2326
|
+
if (child.isLayoutDimensionDefined(crossAxis)) {
|
|
2327
|
+
lineHeight = maxOrDefined(
|
|
2328
|
+
lineHeight,
|
|
2329
|
+
child.layout.measuredDimension(dimension(crossAxis)) +
|
|
2330
|
+
child.style.computeMarginForAxis(crossAxis, availableInnerWidth),
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
if (resolveChildAlignment(node, child) === Align.Baseline) {
|
|
2334
|
+
const ascent =
|
|
2335
|
+
calculateBaseline(child) +
|
|
2336
|
+
child.style.computeFlexStartMargin(
|
|
2337
|
+
FlexDirection.Column,
|
|
2338
|
+
direction,
|
|
2339
|
+
availableInnerWidth,
|
|
2340
|
+
);
|
|
2341
|
+
const descent =
|
|
2342
|
+
child.layout.measuredDimension(Dimension.Height) +
|
|
2343
|
+
child.style.computeMarginForAxis(FlexDirection.Column, availableInnerWidth) -
|
|
2344
|
+
ascent;
|
|
2345
|
+
maxAscentForCurrentLine = maxOrDefined(maxAscentForCurrentLine, ascent);
|
|
2346
|
+
maxDescentForCurrentLine = maxOrDefined(maxDescentForCurrentLine, descent);
|
|
2347
|
+
lineHeight = maxOrDefined(
|
|
2348
|
+
lineHeight,
|
|
2349
|
+
maxAscentForCurrentLine + maxDescentForCurrentLine,
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
endIndex = ii + 1;
|
|
2354
|
+
}
|
|
2355
|
+
currentLead += i !== 0 ? crossAxisGap : 0;
|
|
2356
|
+
lineHeight += extraSpacePerLine;
|
|
2357
|
+
|
|
2358
|
+
for (let ii = lineStart; ii < endIndex; ii++) {
|
|
2359
|
+
const child = layoutChildren[ii]!;
|
|
2360
|
+
if (child.style.display() === Display.None) {
|
|
2361
|
+
continue;
|
|
2362
|
+
}
|
|
2363
|
+
if (child.style.positionType() !== PositionType.Absolute) {
|
|
2364
|
+
switch (resolveChildAlignment(node, child)) {
|
|
2365
|
+
case Align.Start:
|
|
2366
|
+
case Align.End:
|
|
2367
|
+
// Not yet implemented
|
|
2368
|
+
break;
|
|
2369
|
+
case Align.FlexStart: {
|
|
2370
|
+
child.setLayoutPosition(
|
|
2371
|
+
currentLead +
|
|
2372
|
+
child.style.computeFlexStartPosition(crossAxis, direction, availableInnerWidth),
|
|
2373
|
+
flexStartEdge(crossAxis),
|
|
2374
|
+
);
|
|
2375
|
+
break;
|
|
2376
|
+
}
|
|
2377
|
+
case Align.FlexEnd: {
|
|
2378
|
+
child.setLayoutPosition(
|
|
2379
|
+
currentLead +
|
|
2380
|
+
lineHeight -
|
|
2381
|
+
child.style.computeFlexEndMargin(crossAxis, direction, availableInnerWidth) -
|
|
2382
|
+
child.layout.measuredDimension(dimension(crossAxis)),
|
|
2383
|
+
flexStartEdge(crossAxis),
|
|
2384
|
+
);
|
|
2385
|
+
break;
|
|
2386
|
+
}
|
|
2387
|
+
case Align.Center: {
|
|
2388
|
+
const childHeight = child.layout.measuredDimension(dimension(crossAxis));
|
|
2389
|
+
|
|
2390
|
+
child.setLayoutPosition(
|
|
2391
|
+
currentLead + (lineHeight - childHeight) / 2,
|
|
2392
|
+
flexStartEdge(crossAxis),
|
|
2393
|
+
);
|
|
2394
|
+
break;
|
|
2395
|
+
}
|
|
2396
|
+
case Align.Stretch: {
|
|
2397
|
+
child.setLayoutPosition(
|
|
2398
|
+
currentLead +
|
|
2399
|
+
child.style.computeFlexStartMargin(crossAxis, direction, availableInnerWidth),
|
|
2400
|
+
flexStartEdge(crossAxis),
|
|
2401
|
+
);
|
|
2402
|
+
|
|
2403
|
+
// Remeasure child with the line height as it as been only
|
|
2404
|
+
// measured with the owners height yet.
|
|
2405
|
+
if (!child.hasDefiniteLength(dimension(crossAxis), availableInnerCrossDim)) {
|
|
2406
|
+
const childWidth = isMainAxisRow
|
|
2407
|
+
? child.layout.measuredDimension(Dimension.Width) +
|
|
2408
|
+
child.style.computeMarginForAxis(mainAxis, availableInnerWidth)
|
|
2409
|
+
: leadPerLine + lineHeight;
|
|
2410
|
+
|
|
2411
|
+
const childHeight = !isMainAxisRow
|
|
2412
|
+
? child.layout.measuredDimension(Dimension.Height) +
|
|
2413
|
+
child.style.computeMarginForAxis(crossAxis, availableInnerWidth)
|
|
2414
|
+
: leadPerLine + lineHeight;
|
|
2415
|
+
|
|
2416
|
+
if (
|
|
2417
|
+
!(
|
|
2418
|
+
inexactEquals(childWidth, child.layout.measuredDimension(Dimension.Width)) &&
|
|
2419
|
+
inexactEquals(childHeight, child.layout.measuredDimension(Dimension.Height))
|
|
2420
|
+
)
|
|
2421
|
+
) {
|
|
2422
|
+
calculateLayoutInternal(
|
|
2423
|
+
child,
|
|
2424
|
+
childWidth,
|
|
2425
|
+
childHeight,
|
|
2426
|
+
direction,
|
|
2427
|
+
SizingMode.StretchFit,
|
|
2428
|
+
SizingMode.StretchFit,
|
|
2429
|
+
availableInnerWidth,
|
|
2430
|
+
availableInnerHeight,
|
|
2431
|
+
true,
|
|
2432
|
+
LayoutPassReason.MultilineStretch,
|
|
2433
|
+
layoutMarkerData,
|
|
2434
|
+
depth,
|
|
2435
|
+
generationCount,
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
break;
|
|
2440
|
+
}
|
|
2441
|
+
case Align.Baseline: {
|
|
2442
|
+
child.setLayoutPosition(
|
|
2443
|
+
currentLead +
|
|
2444
|
+
maxAscentForCurrentLine -
|
|
2445
|
+
calculateBaseline(child) +
|
|
2446
|
+
child.style.computeFlexStartPosition(
|
|
2447
|
+
FlexDirection.Column,
|
|
2448
|
+
direction,
|
|
2449
|
+
availableInnerCrossDim,
|
|
2450
|
+
),
|
|
2451
|
+
PhysicalEdge.Top,
|
|
2452
|
+
);
|
|
2453
|
+
|
|
2454
|
+
break;
|
|
2455
|
+
}
|
|
2456
|
+
case Align.Auto:
|
|
2457
|
+
case Align.SpaceBetween:
|
|
2458
|
+
case Align.SpaceAround:
|
|
2459
|
+
case Align.SpaceEvenly:
|
|
2460
|
+
break;
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
currentLead = currentLead + leadPerLine + lineHeight;
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
// STEP 9: COMPUTING FINAL DIMENSIONS
|
|
2470
|
+
|
|
2471
|
+
node.setLayoutMeasuredDimension(
|
|
2472
|
+
boundAxis(
|
|
2473
|
+
node,
|
|
2474
|
+
FlexDirection.Row,
|
|
2475
|
+
direction,
|
|
2476
|
+
availableWidth - marginAxisRow,
|
|
2477
|
+
ownerWidth,
|
|
2478
|
+
ownerWidth,
|
|
2479
|
+
),
|
|
2480
|
+
Dimension.Width,
|
|
2481
|
+
);
|
|
2482
|
+
|
|
2483
|
+
node.setLayoutMeasuredDimension(
|
|
2484
|
+
boundAxis(
|
|
2485
|
+
node,
|
|
2486
|
+
FlexDirection.Column,
|
|
2487
|
+
direction,
|
|
2488
|
+
availableHeight - marginAxisColumn,
|
|
2489
|
+
ownerHeight,
|
|
2490
|
+
ownerWidth,
|
|
2491
|
+
),
|
|
2492
|
+
Dimension.Height,
|
|
2493
|
+
);
|
|
2494
|
+
|
|
2495
|
+
// If the user didn't specify a width or height for the node, set the
|
|
2496
|
+
// dimensions based on the children.
|
|
2497
|
+
if (
|
|
2498
|
+
sizingModeMainDim === SizingMode.MaxContent ||
|
|
2499
|
+
(node.style.overflow() !== Overflow.Scroll && sizingModeMainDim === SizingMode.FitContent)
|
|
2500
|
+
) {
|
|
2501
|
+
// Clamp the size to the min/max size, if specified, and make sure it
|
|
2502
|
+
// doesn't go below the padding and border amount.
|
|
2503
|
+
node.setLayoutMeasuredDimension(
|
|
2504
|
+
boundAxis(node, mainAxis, direction, maxLineMainDim, mainAxisOwnerSize, ownerWidth),
|
|
2505
|
+
dimension(mainAxis),
|
|
2506
|
+
);
|
|
2507
|
+
} else if (
|
|
2508
|
+
sizingModeMainDim === SizingMode.FitContent &&
|
|
2509
|
+
node.style.overflow() === Overflow.Scroll
|
|
2510
|
+
) {
|
|
2511
|
+
node.setLayoutMeasuredDimension(
|
|
2512
|
+
maxOrDefined(
|
|
2513
|
+
minOrDefined(
|
|
2514
|
+
availableInnerMainDim + paddingAndBorderAxisMain,
|
|
2515
|
+
boundAxisWithinMinAndMax(
|
|
2516
|
+
node,
|
|
2517
|
+
direction,
|
|
2518
|
+
mainAxis,
|
|
2519
|
+
maxLineMainDim,
|
|
2520
|
+
mainAxisOwnerSize,
|
|
2521
|
+
ownerWidth,
|
|
2522
|
+
),
|
|
2523
|
+
),
|
|
2524
|
+
paddingAndBorderAxisMain,
|
|
2525
|
+
),
|
|
2526
|
+
dimension(mainAxis),
|
|
2527
|
+
);
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
if (
|
|
2531
|
+
sizingModeCrossDim === SizingMode.MaxContent ||
|
|
2532
|
+
(node.style.overflow() !== Overflow.Scroll && sizingModeCrossDim === SizingMode.FitContent)
|
|
2533
|
+
) {
|
|
2534
|
+
// Clamp the size to the min/max size, if specified, and make sure it
|
|
2535
|
+
// doesn't go below the padding and border amount.
|
|
2536
|
+
node.setLayoutMeasuredDimension(
|
|
2537
|
+
boundAxis(
|
|
2538
|
+
node,
|
|
2539
|
+
crossAxis,
|
|
2540
|
+
direction,
|
|
2541
|
+
totalLineCrossDim + paddingAndBorderAxisCross,
|
|
2542
|
+
crossAxisOwnerSize,
|
|
2543
|
+
ownerWidth,
|
|
2544
|
+
),
|
|
2545
|
+
dimension(crossAxis),
|
|
2546
|
+
);
|
|
2547
|
+
} else if (
|
|
2548
|
+
sizingModeCrossDim === SizingMode.FitContent &&
|
|
2549
|
+
node.style.overflow() === Overflow.Scroll
|
|
2550
|
+
) {
|
|
2551
|
+
node.setLayoutMeasuredDimension(
|
|
2552
|
+
maxOrDefined(
|
|
2553
|
+
minOrDefined(
|
|
2554
|
+
availableInnerCrossDim + paddingAndBorderAxisCross,
|
|
2555
|
+
boundAxisWithinMinAndMax(
|
|
2556
|
+
node,
|
|
2557
|
+
direction,
|
|
2558
|
+
crossAxis,
|
|
2559
|
+
totalLineCrossDim + paddingAndBorderAxisCross,
|
|
2560
|
+
crossAxisOwnerSize,
|
|
2561
|
+
ownerWidth,
|
|
2562
|
+
),
|
|
2563
|
+
),
|
|
2564
|
+
paddingAndBorderAxisCross,
|
|
2565
|
+
),
|
|
2566
|
+
dimension(crossAxis),
|
|
2567
|
+
);
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
// As we only wrapped in normal direction yet, we need to reverse the
|
|
2571
|
+
// positions on wrap-reverse.
|
|
2572
|
+
if (performLayout && node.style.flexWrap() === Wrap.WrapReverse) {
|
|
2573
|
+
for (const child of node.getLayoutChildren()) {
|
|
2574
|
+
if (child.style.positionType() !== PositionType.Absolute) {
|
|
2575
|
+
child.setLayoutPosition(
|
|
2576
|
+
node.layout.measuredDimension(dimension(crossAxis)) -
|
|
2577
|
+
child.layout.position(flexStartEdge(crossAxis)) -
|
|
2578
|
+
child.layout.measuredDimension(dimension(crossAxis)),
|
|
2579
|
+
flexStartEdge(crossAxis),
|
|
2580
|
+
);
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
if (performLayout) {
|
|
2586
|
+
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
|
2587
|
+
const needsMainTrailingPos = needsTrailingPosition(mainAxis);
|
|
2588
|
+
const needsCrossTrailingPos = needsTrailingPosition(crossAxis);
|
|
2589
|
+
|
|
2590
|
+
if (needsMainTrailingPos || needsCrossTrailingPos) {
|
|
2591
|
+
for (const child of node.getLayoutChildren()) {
|
|
2592
|
+
// Absolute children will be handled by their containing block since we
|
|
2593
|
+
// cannot guarantee that their positions are set when their parents are
|
|
2594
|
+
// done with layout.
|
|
2595
|
+
if (
|
|
2596
|
+
child.style.display() === Display.None ||
|
|
2597
|
+
child.style.positionType() === PositionType.Absolute
|
|
2598
|
+
) {
|
|
2599
|
+
continue;
|
|
2600
|
+
}
|
|
2601
|
+
if (needsMainTrailingPos) {
|
|
2602
|
+
setChildTrailingPosition(node, child, mainAxis);
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
if (needsCrossTrailingPos) {
|
|
2606
|
+
setChildTrailingPosition(node, child, crossAxis);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
|
2612
|
+
// Let the containing block layout its absolute descendants.
|
|
2613
|
+
if (
|
|
2614
|
+
node.style.positionType() !== PositionType.Static ||
|
|
2615
|
+
node.alwaysFormsContainingBlock ||
|
|
2616
|
+
depth === 1
|
|
2617
|
+
) {
|
|
2618
|
+
layoutAbsoluteDescendants(
|
|
2619
|
+
node,
|
|
2620
|
+
node,
|
|
2621
|
+
isMainAxisRow ? sizingModeMainDim : sizingModeCrossDim,
|
|
2622
|
+
direction,
|
|
2623
|
+
layoutMarkerData,
|
|
2624
|
+
depth,
|
|
2625
|
+
generationCount,
|
|
2626
|
+
0,
|
|
2627
|
+
0,
|
|
2628
|
+
availableInnerWidth,
|
|
2629
|
+
availableInnerHeight,
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
//
|
|
2636
|
+
// This is a wrapper around the calculateLayoutImpl function. It determines
|
|
2637
|
+
// whether the layout request is redundant and can be skipped.
|
|
2638
|
+
//
|
|
2639
|
+
// Parameters:
|
|
2640
|
+
// Input parameters are the same as calculateLayoutImpl (see above)
|
|
2641
|
+
// Return parameter is true if layout was performed, false if skipped
|
|
2642
|
+
//
|
|
2643
|
+
export function calculateLayoutInternal(
|
|
2644
|
+
node: Node,
|
|
2645
|
+
availableWidth: number,
|
|
2646
|
+
availableHeight: number,
|
|
2647
|
+
ownerDirection: Direction,
|
|
2648
|
+
widthSizingMode: SizingMode,
|
|
2649
|
+
heightSizingMode: SizingMode,
|
|
2650
|
+
ownerWidth: number,
|
|
2651
|
+
ownerHeight: number,
|
|
2652
|
+
performLayout: boolean,
|
|
2653
|
+
reason: LayoutPassReason,
|
|
2654
|
+
layoutMarkerData: LayoutData,
|
|
2655
|
+
depth: number,
|
|
2656
|
+
generationCount: number,
|
|
2657
|
+
): boolean {
|
|
2658
|
+
// An indefinite available size can only be measured as max-content. Yoga's
|
|
2659
|
+
// callers normally preserve this invariant, but combinations of nested
|
|
2660
|
+
// intrinsic sizing, aspect ratios, and flex constraints can lose the mode
|
|
2661
|
+
// while propagating an indefinite size. Normalize it here so the public API
|
|
2662
|
+
// remains total for otherwise valid style combinations.
|
|
2663
|
+
if (isUndefined(availableWidth)) {
|
|
2664
|
+
widthSizingMode = SizingMode.MaxContent;
|
|
2665
|
+
}
|
|
2666
|
+
if (isUndefined(availableHeight)) {
|
|
2667
|
+
heightSizingMode = SizingMode.MaxContent;
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
const layout = node.layout;
|
|
2671
|
+
|
|
2672
|
+
depth++;
|
|
2673
|
+
|
|
2674
|
+
const needToVisitNode =
|
|
2675
|
+
(node.isDirty() && layout.generationCount !== generationCount) ||
|
|
2676
|
+
layout.configVersion !== node.config.getVersion() ||
|
|
2677
|
+
layout.lastOwnerDirection !== ownerDirection;
|
|
2678
|
+
|
|
2679
|
+
if (needToVisitNode) {
|
|
2680
|
+
// Invalidate the cached results.
|
|
2681
|
+
layout.nextCachedMeasurementsIndex = 0;
|
|
2682
|
+
layout.cachedLayout.availableWidth = -1;
|
|
2683
|
+
layout.cachedLayout.availableHeight = -1;
|
|
2684
|
+
layout.cachedLayout.widthSizingMode = SizingMode.MaxContent;
|
|
2685
|
+
layout.cachedLayout.heightSizingMode = SizingMode.MaxContent;
|
|
2686
|
+
layout.cachedLayout.computedWidth = -1;
|
|
2687
|
+
layout.cachedLayout.computedHeight = -1;
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
let cachedResults: CachedMeasurement | null = null;
|
|
2691
|
+
|
|
2692
|
+
// Determine whether the results are already cached. We maintain a separate
|
|
2693
|
+
// cache for layouts and measurements. A layout operation modifies the
|
|
2694
|
+
// positions and dimensions for nodes in the subtree. The algorithm assumes
|
|
2695
|
+
// that each node gets laid out a maximum of one time per tree layout, but
|
|
2696
|
+
// multiple measurements may be required to resolve all of the flex
|
|
2697
|
+
// dimensions. We handle nodes with measure functions specially here because
|
|
2698
|
+
// they are the most expensive to measure, so it's worth avoiding redundant
|
|
2699
|
+
// measurements if at all possible.
|
|
2700
|
+
if (node.hasMeasureFunc()) {
|
|
2701
|
+
const marginAxisRow = node.style.computeMarginForAxis(FlexDirection.Row, ownerWidth);
|
|
2702
|
+
const marginAxisColumn = node.style.computeMarginForAxis(FlexDirection.Column, ownerWidth);
|
|
2703
|
+
|
|
2704
|
+
// First, try to use the layout cache.
|
|
2705
|
+
if (
|
|
2706
|
+
canUseCachedMeasurement(
|
|
2707
|
+
widthSizingMode,
|
|
2708
|
+
availableWidth,
|
|
2709
|
+
heightSizingMode,
|
|
2710
|
+
availableHeight,
|
|
2711
|
+
layout.cachedLayout.widthSizingMode,
|
|
2712
|
+
layout.cachedLayout.availableWidth,
|
|
2713
|
+
layout.cachedLayout.heightSizingMode,
|
|
2714
|
+
layout.cachedLayout.availableHeight,
|
|
2715
|
+
layout.cachedLayout.computedWidth,
|
|
2716
|
+
layout.cachedLayout.computedHeight,
|
|
2717
|
+
marginAxisRow,
|
|
2718
|
+
marginAxisColumn,
|
|
2719
|
+
node.config,
|
|
2720
|
+
)
|
|
2721
|
+
) {
|
|
2722
|
+
cachedResults = layout.cachedLayout;
|
|
2723
|
+
} else {
|
|
2724
|
+
// Try to use the measurement cache.
|
|
2725
|
+
for (let i = 0; i < layout.nextCachedMeasurementsIndex; i++) {
|
|
2726
|
+
if (
|
|
2727
|
+
canUseCachedMeasurement(
|
|
2728
|
+
widthSizingMode,
|
|
2729
|
+
availableWidth,
|
|
2730
|
+
heightSizingMode,
|
|
2731
|
+
availableHeight,
|
|
2732
|
+
layout.cachedMeasurements[i]!.widthSizingMode,
|
|
2733
|
+
layout.cachedMeasurements[i]!.availableWidth,
|
|
2734
|
+
layout.cachedMeasurements[i]!.heightSizingMode,
|
|
2735
|
+
layout.cachedMeasurements[i]!.availableHeight,
|
|
2736
|
+
layout.cachedMeasurements[i]!.computedWidth,
|
|
2737
|
+
layout.cachedMeasurements[i]!.computedHeight,
|
|
2738
|
+
marginAxisRow,
|
|
2739
|
+
marginAxisColumn,
|
|
2740
|
+
node.config,
|
|
2741
|
+
)
|
|
2742
|
+
) {
|
|
2743
|
+
cachedResults = layout.cachedMeasurements[i]!;
|
|
2744
|
+
break;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
} else if (performLayout) {
|
|
2749
|
+
if (
|
|
2750
|
+
inexactEquals(layout.cachedLayout.availableWidth, availableWidth) &&
|
|
2751
|
+
inexactEquals(layout.cachedLayout.availableHeight, availableHeight) &&
|
|
2752
|
+
layout.cachedLayout.widthSizingMode === widthSizingMode &&
|
|
2753
|
+
layout.cachedLayout.heightSizingMode === heightSizingMode
|
|
2754
|
+
) {
|
|
2755
|
+
cachedResults = layout.cachedLayout;
|
|
2756
|
+
}
|
|
2757
|
+
} else {
|
|
2758
|
+
for (let i = 0; i < layout.nextCachedMeasurementsIndex; i++) {
|
|
2759
|
+
if (
|
|
2760
|
+
inexactEquals(layout.cachedMeasurements[i]!.availableWidth, availableWidth) &&
|
|
2761
|
+
inexactEquals(layout.cachedMeasurements[i]!.availableHeight, availableHeight) &&
|
|
2762
|
+
layout.cachedMeasurements[i]!.widthSizingMode === widthSizingMode &&
|
|
2763
|
+
layout.cachedMeasurements[i]!.heightSizingMode === heightSizingMode
|
|
2764
|
+
) {
|
|
2765
|
+
cachedResults = layout.cachedMeasurements[i]!;
|
|
2766
|
+
break;
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
if (!needToVisitNode && cachedResults !== null) {
|
|
2772
|
+
layout.setMeasuredDimension(Dimension.Width, cachedResults.computedWidth);
|
|
2773
|
+
layout.setMeasuredDimension(Dimension.Height, cachedResults.computedHeight);
|
|
2774
|
+
|
|
2775
|
+
if (performLayout) {
|
|
2776
|
+
layoutMarkerData.cachedLayouts += 1;
|
|
2777
|
+
} else {
|
|
2778
|
+
layoutMarkerData.cachedMeasures += 1;
|
|
2779
|
+
}
|
|
2780
|
+
} else {
|
|
2781
|
+
calculateLayoutImpl(
|
|
2782
|
+
node,
|
|
2783
|
+
availableWidth,
|
|
2784
|
+
availableHeight,
|
|
2785
|
+
ownerDirection,
|
|
2786
|
+
widthSizingMode,
|
|
2787
|
+
heightSizingMode,
|
|
2788
|
+
ownerWidth,
|
|
2789
|
+
ownerHeight,
|
|
2790
|
+
performLayout,
|
|
2791
|
+
reason,
|
|
2792
|
+
layoutMarkerData,
|
|
2793
|
+
depth,
|
|
2794
|
+
generationCount,
|
|
2795
|
+
);
|
|
2796
|
+
|
|
2797
|
+
layout.lastOwnerDirection = ownerDirection;
|
|
2798
|
+
layout.configVersion = node.config.getVersion();
|
|
2799
|
+
|
|
2800
|
+
if (cachedResults === null) {
|
|
2801
|
+
layoutMarkerData.maxMeasureCache = Math.max(
|
|
2802
|
+
layoutMarkerData.maxMeasureCache,
|
|
2803
|
+
layout.nextCachedMeasurementsIndex + 1,
|
|
2804
|
+
);
|
|
2805
|
+
|
|
2806
|
+
if (layout.nextCachedMeasurementsIndex === LayoutResults.MaxCachedMeasurements) {
|
|
2807
|
+
layout.nextCachedMeasurementsIndex = 0;
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
let newCacheEntry;
|
|
2811
|
+
if (performLayout) {
|
|
2812
|
+
// Use the single layout cache entry.
|
|
2813
|
+
newCacheEntry = layout.cachedLayout;
|
|
2814
|
+
} else {
|
|
2815
|
+
// Allocate a new measurement cache entry.
|
|
2816
|
+
newCacheEntry = layout.cachedMeasurements[layout.nextCachedMeasurementsIndex] ??=
|
|
2817
|
+
new CachedMeasurement();
|
|
2818
|
+
layout.nextCachedMeasurementsIndex++;
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
newCacheEntry.availableWidth = availableWidth;
|
|
2822
|
+
newCacheEntry.availableHeight = availableHeight;
|
|
2823
|
+
newCacheEntry.widthSizingMode = widthSizingMode;
|
|
2824
|
+
newCacheEntry.heightSizingMode = heightSizingMode;
|
|
2825
|
+
newCacheEntry.computedWidth = layout.measuredDimension(Dimension.Width);
|
|
2826
|
+
newCacheEntry.computedHeight = layout.measuredDimension(Dimension.Height);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
if (performLayout) {
|
|
2831
|
+
node.setLayoutDimension(node.layout.measuredDimension(Dimension.Width), Dimension.Width);
|
|
2832
|
+
node.setLayoutDimension(node.layout.measuredDimension(Dimension.Height), Dimension.Height);
|
|
2833
|
+
|
|
2834
|
+
node.hasNewLayout_ = true;
|
|
2835
|
+
node.setDirty(false);
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
layout.generationCount = generationCount;
|
|
2839
|
+
|
|
2840
|
+
return needToVisitNode || cachedResults === null;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
export function calculateLayout(
|
|
2844
|
+
node: Node,
|
|
2845
|
+
ownerWidth: number,
|
|
2846
|
+
ownerHeight: number,
|
|
2847
|
+
ownerDirection: Direction,
|
|
2848
|
+
): void {
|
|
2849
|
+
const markerData = newLayoutData();
|
|
2850
|
+
|
|
2851
|
+
// Increment the generation count. This will force the recursive routine to
|
|
2852
|
+
// visit all dirty nodes at least once. Subsequent visits will be skipped if
|
|
2853
|
+
// the input parameters don't change.
|
|
2854
|
+
const currentGenerationCount = ++gCurrentGenerationCount;
|
|
2855
|
+
node.processDimensions();
|
|
2856
|
+
const direction = node.resolveDirection(ownerDirection);
|
|
2857
|
+
let width = NaN;
|
|
2858
|
+
let widthSizingMode: SizingMode = SizingMode.MaxContent;
|
|
2859
|
+
const style = node.style;
|
|
2860
|
+
if (node.hasDefiniteLength(Dimension.Width, ownerWidth)) {
|
|
2861
|
+
width =
|
|
2862
|
+
node.getResolvedDimension(direction, dimension(FlexDirection.Row), ownerWidth, ownerWidth) +
|
|
2863
|
+
node.style.computeMarginForAxis(FlexDirection.Row, ownerWidth);
|
|
2864
|
+
widthSizingMode = SizingMode.StretchFit;
|
|
2865
|
+
} else if (
|
|
2866
|
+
isDefined(style.resolvedMaxDimension(direction, Dimension.Width, ownerWidth, ownerWidth))
|
|
2867
|
+
) {
|
|
2868
|
+
width = style.resolvedMaxDimension(direction, Dimension.Width, ownerWidth, ownerWidth);
|
|
2869
|
+
widthSizingMode = SizingMode.FitContent;
|
|
2870
|
+
} else {
|
|
2871
|
+
width = ownerWidth;
|
|
2872
|
+
widthSizingMode = isUndefined(width) ? SizingMode.MaxContent : SizingMode.StretchFit;
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2875
|
+
let height = NaN;
|
|
2876
|
+
let heightSizingMode: SizingMode = SizingMode.MaxContent;
|
|
2877
|
+
if (node.hasDefiniteLength(Dimension.Height, ownerHeight)) {
|
|
2878
|
+
height =
|
|
2879
|
+
node.getResolvedDimension(
|
|
2880
|
+
direction,
|
|
2881
|
+
dimension(FlexDirection.Column),
|
|
2882
|
+
ownerHeight,
|
|
2883
|
+
ownerWidth,
|
|
2884
|
+
) + node.style.computeMarginForAxis(FlexDirection.Column, ownerWidth);
|
|
2885
|
+
heightSizingMode = SizingMode.StretchFit;
|
|
2886
|
+
} else if (
|
|
2887
|
+
isDefined(style.resolvedMaxDimension(direction, Dimension.Height, ownerHeight, ownerWidth))
|
|
2888
|
+
) {
|
|
2889
|
+
height = style.resolvedMaxDimension(direction, Dimension.Height, ownerHeight, ownerWidth);
|
|
2890
|
+
heightSizingMode = SizingMode.FitContent;
|
|
2891
|
+
} else {
|
|
2892
|
+
height = ownerHeight;
|
|
2893
|
+
heightSizingMode = isUndefined(height) ? SizingMode.MaxContent : SizingMode.StretchFit;
|
|
2894
|
+
}
|
|
2895
|
+
const generationCount = node.config.isExperimentalFeatureEnabled(
|
|
2896
|
+
ExperimentalFeature.FixFlexBasisFitContent,
|
|
2897
|
+
)
|
|
2898
|
+
? currentGenerationCount
|
|
2899
|
+
: gCurrentGenerationCount;
|
|
2900
|
+
if (
|
|
2901
|
+
calculateLayoutInternal(
|
|
2902
|
+
node,
|
|
2903
|
+
width,
|
|
2904
|
+
height,
|
|
2905
|
+
ownerDirection,
|
|
2906
|
+
widthSizingMode,
|
|
2907
|
+
heightSizingMode,
|
|
2908
|
+
ownerWidth,
|
|
2909
|
+
ownerHeight,
|
|
2910
|
+
true,
|
|
2911
|
+
LayoutPassReason.Initial,
|
|
2912
|
+
markerData,
|
|
2913
|
+
0, // tree root
|
|
2914
|
+
generationCount,
|
|
2915
|
+
)
|
|
2916
|
+
) {
|
|
2917
|
+
node.setPositionFromStyle(node.layout.direction(), ownerWidth, ownerHeight);
|
|
2918
|
+
roundLayoutResultsToPixelGrid(node, 0, 0);
|
|
2919
|
+
}
|
|
2920
|
+
}
|