// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
fn compute_spanned_max_track_size(
tracks : Array[Dimension],
snapshot : GridTrackSizingItemSnapshot,
) -> Double {
let mut space = 0.0
for i in 0.. 1 {
let start = snapshot.start[i]
let end = start + snapshot.span[i]
let mut crosses_flex = false
for j in start.. space {
space = snapshot.max_content_contribution[i]
}
}
}
space
}
///|
fn distribute_track_space_up_to_limits(
states : Array[GridTrack],
start : Int,
span : Int,
space : Double,
should_affect : (GridTrack) -> Bool,
limit_of : (GridTrack) -> Double,
eps : Double,
inf : Double,
) -> Double {
let mut remaining = space
while remaining > eps {
let mut growable = 0
for j in start..<(start + span) {
if should_affect(states[j]) &&
states[j].base_size + states[j].item_incurred_increase <
limit_of(states[j]) - eps {
growable = growable + 1
}
}
if growable == 0 {
return remaining
}
let mut min_room = inf
for j in start..<(start + span) {
if should_affect(states[j]) &&
states[j].base_size + states[j].item_incurred_increase <
limit_of(states[j]) - eps {
let room = limit_of(states[j]) -
states[j].base_size -
states[j].item_incurred_increase
if room < min_room {
min_room = room
}
}
}
let share = @util.min_double(min_room, remaining / growable.to_double())
if share <= 0.0 {
return remaining
}
for j in start..<(start + span) {
if should_affect(states[j]) &&
states[j].base_size + states[j].item_incurred_increase <
limit_of(states[j]) - eps {
states[j].item_incurred_increase = states[j].item_incurred_increase +
share
remaining = remaining - share
}
}
}
remaining
}
///|
fn distribute_item_space_to_base_size(
states : Array[GridTrack],
start : Int,
span : Int,
space : Double,
should_affect : (GridTrack) -> Bool,
limit_of : (GridTrack) -> Double,
contribution_type : IntrinsicContributionType,
percent_basis : Double?,
eps : Double,
inf : Double,
) -> Unit {
if space <= 0.0 || span <= 0 {
return
}
let mut used = 0.0
for j in start..<(start + span) {
used = used + states[j].base_size
}
let extra = space - used
if extra <= 0.0 {
return
}
let mut has_affected = false
for j in start..<(start + span) {
if should_affect(states[j]) {
has_affected = true
break
}
}
if !has_affected {
return
}
for j in start..<(start + span) {
states[j].item_incurred_increase = 0.0
}
let remaining = distribute_track_space_up_to_limits(
states, start, span, extra, should_affect, limit_of, eps, inf,
)
if remaining > eps {
let mut matching_affected = false
for j in start..<(start + span) {
let dimension = states[j].dimension
let matches_beyond = match contribution_type {
TrackMaximumContribution =>
track_has_max_content_or_fit_max(dimension) ||
track_min_sizing_kind(dimension) == 2
TrackMinimumContribution =>
track_has_intrinsic_max(dimension, percent_basis)
}
if should_affect(states[j]) && matches_beyond {
matching_affected = true
break
}
}
let beyond_filter = fn(state : GridTrack) -> Bool {
if matching_affected {
match contribution_type {
TrackMaximumContribution =>
track_has_max_content_or_fit_max(state.dimension) ||
track_min_sizing_kind(state.dimension) == 2
TrackMinimumContribution =>
track_has_intrinsic_max(state.dimension, percent_basis)
}
} else {
true
}
}
ignore(
distribute_track_space_up_to_limits(
states, start, span, remaining, beyond_filter, limit_of, eps, inf,
),
)
}
for j in start..<(start + span) {
if states[j].item_incurred_increase > states[j].base_size_planned_increase {
states[j].base_size_planned_increase = states[j].item_incurred_increase
}
states[j].item_incurred_increase = 0.0
}
}
///|
fn flush_track_base_size_increases(states : Array[GridTrack]) -> Unit {
for state in states {
state.base_size = state.base_size + state.base_size_planned_increase
state.base_size_planned_increase = 0.0
}
}
///|
fn apply_definite_max_floor(
states : Array[GridTrack],
percent_basis : Double?,
) -> Unit {
for state in states {
match state.dimension {
DimMinMax(_, max_d) =>
match max_d {
DimLength(v) => if v > state.base_size { state.base_size = v }
DimPercent(p) =>
match percent_basis {
Some(basis) => {
let v = basis * p
if v > state.base_size {
state.base_size = v
}
}
None => ()
}
_ => ()
}
_ => ()
}
}
}
///|
fn grid_track_base_sizes(states : Array[GridTrack]) -> Array[Double] {
let sizes : Array[Double] = []
for state in states {
sizes.push(state.base_size)
}
sizes
}
///|
fn compute_intrinsic_base_sizes_max_content(
tracks : Array[Dimension],
snapshot : GridTrackSizingItemSnapshot,
percent_basis : Double?,
) -> Array[Double] {
let count = tracks.length()
let inf = 1.0e30
let eps = 0.000001
let states : Array[GridTrack] = []
for i in 0.. max_span {
max_span = snapshot.span[i]
}
}
for span in 1..<(max_span + 1) {
for i in 0.. Double {
track_fit_content_limit(state.dimension, percent_basis, inf)
}
} else {
fn(_state : GridTrack) -> Double { inf }
}
distribute_item_space_to_base_size(
states,
s,
sp,
min_space,
fn(state : GridTrack) -> Bool {
track_has_intrinsic_min(state.dimension, percent_basis)
},
limit_of,
TrackMinimumContribution,
percent_basis,
eps,
inf,
)
}
}
flush_track_base_size_increases(states)
for span in 1..<(max_span + 1) {
for i in 0.. Double {
track_fit_content_limit(state.dimension, percent_basis, inf)
}
} else {
fn(_state : GridTrack) -> Double { inf }
}
distribute_item_space_to_base_size(
states,
s,
sp,
snapshot.min_content_contribution[i],
fn(state : GridTrack) -> Bool {
let kind = track_min_sizing_kind(state.dimension)
kind == 1 || kind == 2
},
limit_of,
TrackMinimumContribution,
percent_basis,
eps,
inf,
)
}
}
flush_track_base_size_increases(states)
for span in 1..<(max_span + 1) {
for i in 0.. Double { inf }
} else {
fn(state : GridTrack) -> Double {
track_fit_content_limit(state.dimension, percent_basis, inf)
}
}
distribute_item_space_to_base_size(
states,
s,
sp,
max_space,
fn(state : GridTrack) -> Bool {
track_min_sizing_kind(state.dimension) == affect_kind &&
!track_max_is_min_content(state.dimension)
},
limit_of,
TrackMaximumContribution,
percent_basis,
eps,
inf,
)
}
}
flush_track_base_size_increases(states)
for span in 1..<(max_span + 1) {
for i in 0.. Bool {
track_min_sizing_kind(state.dimension) == 2
},
fn(_state : GridTrack) -> Double { inf },
TrackMaximumContribution,
percent_basis,
eps,
inf,
)
}
}
flush_track_base_size_increases(states)
apply_definite_max_floor(states, percent_basis)
grid_track_base_sizes(states)
}
///|
fn compute_flexible_percent_max_content_track_sizes(
tracks : Array[Dimension],
snapshot : GridTrackSizingItemSnapshot,
) -> (Array[Double], Double)? {
let flex_space = compute_spanned_max_track_size(tracks, snapshot)
if flex_space <= 0.0 {
return None
}
let states : Array[GridTrack] = []
let mut fixed_used = 0.0
let mut flex_sum = 0.0
for track in tracks {
let state = grid_track_base_state(track, Some(flex_space))
match track {
DimLength(v) => fixed_used = fixed_used + v
DimPercent(p) => fixed_used = fixed_used + flex_space * p
DimMinMax(min_d, max_d) =>
match max_d {
DimFr(weight) => {
if weight > 0.0 {
flex_sum = flex_sum + weight
}
match min_d {
DimLength(v) => state.base_size = v
_ => ()
}
}
_ =>
match track_definite_len(track) {
Some(v) => fixed_used = fixed_used + v
None => ()
}
}
DimFr(weight) => if weight > 0.0 { flex_sum = flex_sum + weight }
_ => ()
}
states.push(state)
}
let remaining = @util.max_double(flex_space - fixed_used, 0.0)
if flex_sum > 0.0 {
for state in states {
let weight = track_flex_weight(state.dimension)
if weight > 0.0 {
state.base_size = @util.max_double(
state.base_size,
remaining * weight / flex_sum,
)
}
}
}
Some((grid_track_base_sizes(states), flex_space))
}
///|
fn compute_max_content_spanning_track_sizes(
tracks : Array[Dimension],
snapshot : GridTrackSizingItemSnapshot,
) -> (Array[Double], Double)? {
let mut has_spanning_item = false
let mut has_flexible_spanning_item = false
let mut has_intrinsic_spanning_item = false
for i in 0.. 1 {
has_spanning_item = true
if snapshot.crosses_flexible_track[i] {
has_flexible_spanning_item = true
}
if snapshot.crosses_intrinsic_track[i] {
has_intrinsic_spanning_item = true
}
}
}
if !has_spanning_item ||
(!has_flexible_spanning_item && !has_intrinsic_spanning_item) {
return None
}
let mut has_percent_track = false
let mut has_flexible_track = false
let mut has_intrinsic_track = false
for track in tracks {
if track_uses_percentage(track) {
has_percent_track = true
}
if track_has_flexible_max(track) {
has_flexible_track = true
}
if track_min_sizing_kind(track) != 0 {
has_intrinsic_track = true
}
}
if has_flexible_track && has_percent_track {
return compute_flexible_percent_max_content_track_sizes(tracks, snapshot)
}
if !has_intrinsic_track || has_flexible_track {
return None
}
let sizes1 = compute_intrinsic_base_sizes_max_content(tracks, snapshot, None)
let mut basis = 0.0
for size in sizes1 {
basis = basis + size
}
if has_percent_track {
let sizes2 = compute_intrinsic_base_sizes_max_content(
tracks,
snapshot,
Some(basis),
)
basis = 0.0
for size in sizes2 {
basis = basis + size
}
Some((sizes2, basis))
} else {
Some((sizes1, basis))
}
}