feat: 標點半形 margin 後備模式+下游回饋修復
margin 後備(供缺 OpenType halt 之字型): - jiya.halfWidth: "halt"(預設)|"margin"。margin 以 width:0.5em+字身依墨色 偏側溢出定位,於 CSS 盒模型重現 halt 之半形 advance(真 0.5em;相鄰標點各 0.5em、合佔 1em,無負 margin 之鄰接疊加/單側重疊)。模式由 data-jz-halfwidth 子樹屬性決定(可逐區塊/逐 lang,含 halt-island 反置)。 - 偏側 inkBias 依字身墨色中心給 left/center/right/full;參考表據方正書宋 GBK 實測,consumer 可經 jiya.bias 逐 lang 逐字覆寫。 - _lang.css 字型堆疊僅作後備(全包 :where 零特異度、只命中帶 lang 屬性之元素、 不直接覆寫 jz-inner)→ 消費端 font-family 恆優先,標點隨之以消費端字型渲染。 - 新增 tools/measure-bias.py(量 glyph ink 中心、產偏側建議表)+ README 「字型適配工作流」。demo/fallback.html:方正書宋 GBK 對照 halt 失效 vs margin。 下游回饋修復: - 1a:adjacentLogicalChar 透明穿越 jz-jinze(同 jz-hws/樣式行內)→ pill 緊鄰 CJK 標點時,左緣間隙與作者空格剝除復原(jinze 先於 spacing 之交互)。 - 1b:CJK↔CJK 贅餘作者空格(含跨 inline 標籤)剝除、不留隙,與 CJK↔Latin 之 邊界正規化一致(DEL 哨符,全形空格 U+3000 不動)。 - 問題二:新增 justifyAtoms 選項;false → jz-char/jz-jinze 改 display:inline, 相容分頁器(Paged.js)對齊引擎(halt 半形與禁則 nowrap 保留)。 測試 43→49 全通過;dist 重建;README/ARCHITECTURE 同步更新契約。
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
// 這些常數以「regex 字元類片段」形式給出(已就 RegExp 字元類做必要轉義),
|
||||
// 故可直接 `new RegExp("[" + X + "]")`。
|
||||
|
||||
import type { LangClass } from "./locale.js";
|
||||
|
||||
/** CJK 表意文字/假名/注音等範圍(沿用並擴充 v1 之 PANGU_CJK)。 */
|
||||
export const CJK = (
|
||||
"⺀-⼀-" // CJK 部首補充 + 康熙部首
|
||||
@@ -118,3 +120,81 @@ export function blankSides(bdClass: string | null): { left: boolean; right: bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----- 字形偏側(ink bias)參考表 — margin 後備模式用(架構 §6.3/.feedback)-----
|
||||
//
|
||||
// 預設半形渲染用字型 OpenType `halt`:由字型按字形正確定位,無需知道字面偏側。
|
||||
// 但消費端字型未必含 halt(部分系統字型、特製字型)。此時改用「margin 後備模式」:
|
||||
// 以負 margin 收半形空白,**須知道每個標點字形之墨色偏側**才能收對側、不重疊:
|
||||
//
|
||||
// left 墨色偏左(空白在右) → 收右:margin-right: -0.5em
|
||||
// right 墨色偏右(空白在左) → 收左:margin-left: -0.5em
|
||||
// center 墨色居中(兩側各半空白) → 兩側各收:margin-left/right: -0.25em
|
||||
// full 無可壓縮空白(字面已佔滿全形) → 不收(維持全形)
|
||||
//
|
||||
// 下表為**參考預設**,依簡/繁字形慣例給出(簡體點號偏左下、繁體居中;!?恆
|
||||
// 居中;開類偏右、閉類偏左)。因實際字型字形多樣,消費端可經 options.jiya.bias
|
||||
// 逐 lang 逐字覆寫(見 README「margin 後備模式」一節)。
|
||||
//
|
||||
// 注意:此偏側表只在 margin 後備模式生效;halt 模式(預設)不讀它。
|
||||
|
||||
/** 字形墨色偏側。 */
|
||||
export type Bias = "left" | "center" | "right" | "full";
|
||||
|
||||
/** 逐 lang 逐字之偏側覆寫表(消費端傳入,覆寫參考預設)。 */
|
||||
export type BiasTable = Partial<Record<LangClass, Record<string, Bias>>>;
|
||||
|
||||
// 括號/引號偏側依**字身墨色中心**(margin 後備模式之 width:0.5em 盒內定位用)。
|
||||
// 經方正書宋 GBK 實測 glyph ink bbox:彎引號 “”‘’、角括號 「」、尖括號 〈〉 之墨色
|
||||
// 強偏一側(開類 inkcenter≈0.64–0.75 偏右、閉類≈0.25–0.37 偏左)→ 開 right、閉 left;
|
||||
// 圓/方/書名/六角括號 ()【】《》[]{}〔〕〖〗『』 墨色近中(≈0.38–0.62)→ center。
|
||||
// 偏側決定字身於 0.5em 半形盒內之左移量(right 移 0.5、center 移 0.25、left 不移),
|
||||
// 使墨色落於盒內、空白溢向外側而不與鄰字重疊。字型字身分布各異,消費端可經
|
||||
// options.jiya.bias 逐字覆寫(見 README「字型適配工作流」)。
|
||||
const BRACKET_OPEN_RIGHT = "「〈“‘"; // 開類中墨色強偏右者
|
||||
const BRACKET_CLOSE_LEFT = "」〉”’"; // 閉類中墨色強偏左者
|
||||
const BIAS_BRACKETS: Record<string, Bias> = (() =>
|
||||
{
|
||||
const t: Record<string, Bias> = {};
|
||||
for (const ch of BD_OPEN) { t[ch] = BRACKET_OPEN_RIGHT.indexOf(ch) >= 0 ? "right" : "center"; }
|
||||
for (const ch of BD_CLOSE) { t[ch] = BRACKET_CLOSE_LEFT.indexOf(ch) >= 0 ? "left" : "center"; }
|
||||
return t;
|
||||
})();
|
||||
|
||||
// 點號偏側因簡繁字形而異。簡體(GBK/宋體系)點號皆沉於左下角、墨色偏左、空白
|
||||
// 在右 → 全判 left(經方正書宋 GBK 實測:,、。;:!? 墨色 inkL≈0.1–0.18、
|
||||
// inkR≈0.58–0.68,一致偏左)。繁體(Noto/教育部字形)點號置中 → center。
|
||||
const BIAS_HANS: Record<string, Bias> = {
|
||||
",": "left", "、": "left", "。": "left",
|
||||
";": "left", ":": "left", "!": "left", "?": "left",
|
||||
};
|
||||
const BIAS_HANT: Record<string, Bias> = {
|
||||
",": "center", "、": "center", "。": "center",
|
||||
";": "center", ":": "center", "!": "center", "?": "center",
|
||||
};
|
||||
|
||||
const BIAS_DEFAULT: Record<LangClass, Record<string, Bias>> = {
|
||||
"zh-Hans": BIAS_HANS,
|
||||
"zh-Hant": BIAS_HANT,
|
||||
"ja": BIAS_HANT, // 日文點號慣例居中,沿用繁體表
|
||||
"other": BIAS_HANT,
|
||||
};
|
||||
|
||||
/**
|
||||
* 解析標點字元在某語言下之墨色偏側(margin 後備模式用)。
|
||||
* 優先序:消費端 overrides[langClass][ch] > 括號表 > 內建點號參考表。
|
||||
* 非可壓縮標點(間隔/連接號等)回傳 null(margin 模式不收)。
|
||||
*/
|
||||
export function inkBias(
|
||||
ch: string,
|
||||
langClass: LangClass,
|
||||
overrides?: BiasTable,
|
||||
): Bias | null
|
||||
{
|
||||
const ov = overrides ? overrides[langClass] : undefined;
|
||||
if (ov && ov[ch]) { return ov[ch]; }
|
||||
const bracket = BIAS_BRACKETS[ch];
|
||||
if (bracket) { return bracket; }
|
||||
const t = BIAS_DEFAULT[langClass] || BIAS_DEFAULT.other;
|
||||
return t[ch] || null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user