Initial commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Replicate the (updated) reconstructFlexRow and report success + bail reasons + band impact."""
|
||||
import json, glob, os, sys, collections
|
||||
run = sys.argv[1] if len(sys.argv) > 1 else "compiler/output-dense/sample/.clone"
|
||||
caps = {}
|
||||
for f in sorted(glob.glob(os.path.join(run, "source/capture/dom-*.json"))):
|
||||
caps[int(os.path.basename(f)[4:-5])] = json.load(open(f))["root"]
|
||||
VPS = sorted(caps); BAND_VPS = [v for v in (375, 768, 1280, 1920) if v in VPS]
|
||||
acc = []
|
||||
def walkidx(n):
|
||||
n["_i"] = len(acc); acc.append(n); n["_kids"] = []
|
||||
for c in (n.get("children") or []):
|
||||
n["_kids"].append(len(acc)); walkidx(c)
|
||||
walkidx(caps[VPS[0]])
|
||||
N = len(acc)
|
||||
# per-vp flat lists aligned by index
|
||||
F = {vp: [] for vp in VPS}
|
||||
def flat(n, a):
|
||||
a.append(n)
|
||||
for c in (n.get("children") or []): flat(c, a)
|
||||
for vp in VPS: flat(caps[vp], F[vp])
|
||||
def pf(v):
|
||||
try: return float(str(v).replace("px", ""))
|
||||
except: return 0.0
|
||||
def CS(i, vp): return F[vp][i].get("computed") or {}
|
||||
def BB(i, vp): return F[vp][i].get("bbox") or {}
|
||||
def VIS(i, vp): return F[vp][i].get("visible")
|
||||
reasons = collections.Counter(); succ = 0; succ_items = 0; bands_removed = 0
|
||||
for i in range(N):
|
||||
c0 = CS(i, VPS[0]); disp = c0.get("display", "")
|
||||
if "flex" not in disp: continue
|
||||
if c0.get("flexDirection", "row") not in ("row", "row-reverse"): reasons["not_row"] += 1; continue
|
||||
if (c0.get("flexWrap") or "nowrap") != "nowrap": reasons["wrap"] += 1; continue
|
||||
info = []; bail = None
|
||||
for k in acc[i]["_kids"]:
|
||||
if not acc[k].get("tag"): continue
|
||||
ck = CS(k, VPS[0]); pos = ck.get("position", "static")
|
||||
if pos in ("absolute", "fixed"): continue
|
||||
if (ck.get("float") or "none") != "none": continue
|
||||
if ck.get("marginLeft") == "auto" or ck.get("marginRight") == "auto": bail = "auto_margin"; break
|
||||
if (ck.get("boxSizing") or "border-box") == "content-box": bail = "content_box"; break
|
||||
if pf(ck.get("flexGrow")) > 0: bail = "grow"; break
|
||||
basis = ck.get("flexBasis") or "auto"
|
||||
if basis != "auto" and not basis.endswith("px"): bail = "basis_pct"; break
|
||||
info.append((k, pf(ck.get("flexShrink")), pf(basis) if basis.endswith("px") else None,
|
||||
pf(ck.get("minWidth")) if (ck.get("minWidth") or "").endswith("px") else 0,
|
||||
pf(ck.get("maxWidth")) if (ck.get("maxWidth") or "").endswith("px") else float("inf")))
|
||||
if bail: reasons[bail] += 1; continue
|
||||
if not info: continue
|
||||
used = {}; margin = {}; cw = {}; gap = {}
|
||||
for vp in VPS:
|
||||
pcs = CS(i, vp); pb = BB(i, vp)
|
||||
cw[vp] = pb.get("width", 0) - pf(pcs.get("paddingLeft")) - pf(pcs.get("paddingRight"))
|
||||
gap[vp] = pf(pcs.get("columnGap") if pcs.get("columnGap") not in (None, "normal") else pcs.get("gap"))
|
||||
u = []; m = []
|
||||
for (k, sh, bp, mn, mx) in info:
|
||||
ck = CS(k, vp); hidden = (not VIS(k, vp)) or ck.get("display") == "none"
|
||||
u.append(None if hidden else BB(k, vp).get("width", 0)); m.append(0 if hidden else pf(ck.get("marginLeft")) + pf(ck.get("marginRight")))
|
||||
used[vp] = u; margin[vp] = m
|
||||
def slack(vp):
|
||||
vis = [j for j in range(len(info)) if used[vp][j] is not None]
|
||||
return cw[vp] - sum(used[vp][j] for j in vis) - (gap[vp] * max(0, len(vis) - 1) + sum(margin[vp][j] for j in vis))
|
||||
bases = []; ok = True
|
||||
for j, (k, sh, bp, mn, mx) in enumerate(info):
|
||||
if bp is not None: bases.append(bp); continue
|
||||
base = None
|
||||
for v in range(len(VPS) - 1, -1, -1):
|
||||
vp = VPS[v]
|
||||
if used[vp][j] is None: continue
|
||||
if slack(vp) >= -0.5: base = used[vp][j]; break
|
||||
if base is None: ok = False; break
|
||||
bases.append(base)
|
||||
if not ok: reasons["no_base"] += 1; continue
|
||||
bad = False
|
||||
for vp in VPS:
|
||||
vis = [j for j in range(len(info)) if used[vp][j] is not None]
|
||||
if not vis: continue
|
||||
hyp = [min(max(bases[j], info[j][3]), info[j][4]) for j in vis]
|
||||
gaps = gap[vp] * max(0, len(vis) - 1) + sum(margin[vp][j] for j in vis)
|
||||
free = cw[vp] - sum(hyp) - gaps
|
||||
sim = list(hyp)
|
||||
if free < -0.5:
|
||||
ts = sum(info[vis[k]][1] * hyp[k] for k in range(len(vis)))
|
||||
if ts > 0:
|
||||
for k in range(len(vis)): sim[k] = max(hyp[k] - abs(free) * (info[vis[k]][1] * hyp[k]) / ts, info[vis[k]][3])
|
||||
for k in range(len(vis)):
|
||||
if abs(sim[k] - used[vp][vis[k]]) > 1: bad = True
|
||||
if bad: reasons["sim_mismatch"] += 1; continue
|
||||
varies = [j for j in range(len(info)) if len([used[vp][j] for vp in VPS if used[vp][j] is not None]) >= 2 and max(x for vp in VPS if (x:=used[vp][j]) is not None) - min(x for vp in VPS if (x:=used[vp][j]) is not None) > 8]
|
||||
if not varies: reasons["no_variation"] += 1; continue
|
||||
succ += 1; succ_items += len(info)
|
||||
# estimate band variants removed: for each varying item, count distinct band-vp widths != base-vp
|
||||
for j in varies:
|
||||
bandw = set(round(used[vp][j]) for vp in BAND_VPS if used[vp][j] is not None)
|
||||
bands_removed += max(0, len(bandw) - 1)
|
||||
print(f"SUCCESS lines: {succ} items: {succ_items} est. width-band variants removed: ~{bands_removed}")
|
||||
for k, v in reasons.most_common(): print(f" bail {k:16} {v}")
|
||||
Reference in New Issue
Block a user