fix: 修复行缘、切分还原与语言解析并同步文档

保留逐字 margin/jiya.bias 字体后备方案;补齐 demo 重排、量测边界说明及共享规则 1.0.1 反例向量。

验证:完整构建通过,Node 376 项、WKWebView 64 项及原生 demo 9 项通过;Firefox 仍暂缓。
This commit is contained in:
2026-10-03 21:15:54 +08:00
parent 024ad5da93
commit 3a4fa1c932
33 changed files with 983 additions and 140 deletions
+91
View File
@@ -352,6 +352,97 @@
});
layoutJz.revert(layoutFixture);
layoutJz.disconnect();
var auditRoot = document.createElement("section");
auditRoot.lang = "zh-Hant";
auditRoot.style.cssText = "font-size:20px;width:600px;text-align:left";
document.body.appendChild(auditRoot);
[ false, true ].forEach(function (orphan)
{
auditRoot.innerHTML = '<p>前甲「乙丙」</p>';
var edgeOwner = Juzhen.createJuzhen({ orphan: orphan, spacing: false, longWord: false });
edgeOwner.render(auditRoot);
record("同行 orphan 不製造行首,orphan=" + orphan,
!auditRoot.querySelector(".bd-open").classList.contains("jz-half-le"));
edgeOwner.revert(auditRoot);
edgeOwner.disconnect();
});
[ "inline", "inline-block", "contents", "block" ].forEach(function (display)
{
auditRoot.innerHTML = '<p>前甲<x-box style="display:' + display + '">「乙」</x-box>丙</p>';
var edgeOwner = Juzhen.createJuzhen({ isolateSelector: "x-box", orphan: false, spacing: false, longWord: false });
edgeOwner.render(auditRoot);
record("自訂隔離元素按物理行內流判斷,display=" + display,
Array.from(auditRoot.querySelectorAll("jz-char")).every(function (char)
{
return char.classList.contains("jz-half-le") === (display === "block");
}));
edgeOwner.revert(auditRoot);
edgeOwner.disconnect();
});
[ false, true ].forEach(function (hidden)
{
auditRoot.innerHTML = '<p>甲」<br' + (hidden ? ' style="display:none"' : '') + '>「乙</p>';
var edgeOwner = Juzhen.createJuzhen({ orphan: false, spacing: false, longWord: false });
edgeOwner.render(auditRoot);
record("BR 是強制行緣,hidden=" + hidden,
Array.from(auditRoot.querySelectorAll("jz-char")).every(function (char)
{
return char.classList.contains("jz-half-le") === !hidden;
}));
edgeOwner.revert(auditRoot);
edgeOwner.disconnect();
});
auditRoot.innerHTML = '<p><strong class="original">甲乙丙</strong>,丁</p>';
var splitOwner = Juzhen.createJuzhen({ orphan: false, spacing: false, longWord: false });
splitOwner.render(auditRoot);
var splitFragment = auditRoot.querySelector('[data-jz-kind="splitoff"]');
var inserted = document.createElement("strong");
inserted.className = "external";
inserted.textContent = "新";
splitFragment.before(inserted);
splitOwner.revert(auditRoot);
record("splitoff 不將邊界字移入外部同標籤兄弟",
inserted.textContent === "新" && splitFragment.textContent === "丙"
&& splitFragment.className === "original" && !splitFragment.hasAttribute("data-jz")
&& auditRoot.textContent === "甲乙新丙,丁");
splitOwner.disconnect();
auditRoot.innerHTML = '<p lang="zh-Hans-x-hant">甲,乙</p><p lang="zh-TW-x-hans">甲,乙</p><p lang="">甲,乙</p>';
var localeOwner = Juzhen.createJuzhen({ orphan: false, jinze: false });
localeOwner.render(auditRoot);
var localeChars = auditRoot.querySelectorAll("jz-char");
record("語言私用部分不覆寫 script/region,空值為未知",
localeChars[0].classList.contains("jz-half")
&& !localeChars[1].classList.contains("jz-half")
&& !localeChars[2].classList.contains("jz-half"));
localeOwner.revert(auditRoot);
localeOwner.disconnect();
var splitMatrixPass = true;
var splitOrders = [ [0,1,2], [0,2,1], [1,0,2], [1,2,0], [2,0,1], [2,1,0] ];
[ '<strong>甲乙丙丁</strong>,戊己', '「<strong>甲乙丙丁</strong>」',
'<strong><em>甲乙丙丁</em></strong>,戊己',
'<strong class="author" style="color:red">甲乙丙丁</strong>,戊己',
'<strong>甲乙𠀀\uDB40\uDD00丙丁</strong>,戊己',
'<strong data-jz="author" data-jz-kind="author">甲乙丙丁</strong>,戊己'
].forEach(function (html)
{
splitOrders.forEach(function (order)
{
auditRoot.innerHTML = '<p>' + html + '</p>';
var p = auditRoot.firstElementChild;
var original = p.innerHTML;
var owners = [
Juzhen.createJuzhen({ jiya: false, spacing: false, orphan: false, longWord: false }),
Juzhen.createJuzhen({ jiya: false, spacing: false, jinze: false, longWord: false }),
Juzhen.createJuzhen({ spacing: false, orphan: false, longWord: false })
];
owners.forEach(function (owner) { owner.render(p); });
order.forEach(function (index) { owners[index].revert(p); });
if (p.innerHTML !== original) { splitMatrixPass = false; }
owners.forEach(function (owner) { owner.disconnect(); });
});
});
record("私有切分來源鏈支援多實例六種回退順序,36 組合", splitMatrixPass);
auditRoot.remove();
var moduleFixture = document.getElementById("module-fixture");
var splitSurrogate = document.getElementById("surrogate-spacing");
[ "\uD840", "\uDC00", "\uDB40", "\uDD00" ].forEach(function (part, index)