diff --git a/CHANGELOG.md b/CHANGELOG.md index b9f926af..19c512b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,8 @@ - 쪽 수 추정(실험, `estimate_pages`)이 run의 `hp:switch` 안에 든 개체(차트와 그것을 대신하는 OLE 개체 등)가 있는 구역을 지원 밖으로 둔다(`an object in a switch (hp:switch)`). 한/글은 그런 개체도 자리를 차지해 곁의 줄을 좁히는데, 전에는 개체가 없는 것처럼 추정했다. +- FormFit과 쪽 수 추정이 묶음 빈칸(`hp:nbSpace`)에 장평만 적용하고 자간은 적용하지 않는다. 한/글이 그렇게 놓는다(9pt + 장평 120 %·자간 −12 %에서 536, 전에는 472). 공백과 고정폭 빈칸은 전과 같다. - FormFit과 쪽 수 추정에서 `!`의 반 em을 공백처럼 배치 단위(1/1800인치)로 내림한다. 9·11·13pt처럼 글자 크기의 4분의 1이 홀수인 크기에서 `!`가 4 넓게 잡혀, 그 뒤 탭 폭이 한/글보다 4 좁았다. - FormFit과 쪽 수 추정이 공백 뒤의 닫는 문장부호(`!`·`?`·`)`·`%`·`」`·`·` 등 줄 머리에 오지 않는 문자 모두)로 줄을 diff --git a/src/hwpx/form_fit/measure.py b/src/hwpx/form_fit/measure.py index 8646eb7b..479076b7 100644 --- a/src/hwpx/form_fit/measure.py +++ b/src/hwpx/form_fit/measure.py @@ -1269,7 +1269,8 @@ class TextStyle: the Hangul script's; ``scripts`` holds ``(script, 장평, 자간)`` for the Latin, symbol and Hanja scripts when the character shape gives them values of their own, and each glyph takes its script's (see :func:`glyph_script`). - A space keeps the Hangul 장평 and takes the Latin 자간. + A space keeps the Hangul 장평 and takes the Latin 자간; a no-break space + takes the 장평 and no 자간. ``break_non_latin_word`` works the reverse of its name in Hancom: ``BREAK_WORD`` (the default) keeps Hangul words whole and ``KEEP_WORD`` breaks between any two syllables; ``break_latin_word`` works as named. @@ -1499,7 +1500,8 @@ def char_advance(ch: str, font_pt: float, style: TextStyle | None = None) -> flo return float(height // _LAYOUT_UNIT // 4 * _LAYOUT_UNIT) ratio, spacing = _scaling(ch, style) if ch in _HALF_EM_SPACES and not style.use_font_space: - return _laid_out_space(height, ratio, spacing) + # a no-break space takes its 장평 but no 자간 + return _laid_out_space(height, ratio, 0.0 if ch == " " else spacing) face = style.hangul_face if cls == "hangul" else style.glyph_face if emoji: design, base = _EMOJI_UNITS, _ADVANCE_EM[cls] diff --git a/tests/fixtures/hancom_saved/formfit_space_scaling.hwpx b/tests/fixtures/hancom_saved/formfit_space_scaling.hwpx new file mode 100644 index 00000000..40aa9015 Binary files /dev/null and b/tests/fixtures/hancom_saved/formfit_space_scaling.hwpx differ diff --git a/tests/test_form_fit_hancom_rules.py b/tests/test_form_fit_hancom_rules.py index 04df723a..a255ac14 100644 --- a/tests/test_form_fit_hancom_rules.py +++ b/tests/test_form_fit_hancom_rules.py @@ -20,6 +20,7 @@ import pytest from hwpx.document import HwpxDocument +from hwpx.layout import pages as page_layout from hwpx.form_fit import ( FitEngine, FitPolicy, @@ -58,6 +59,7 @@ PARAGRAPH_MARGINS = Path(__file__).parent / "fixtures" / "hancom_saved" / "formfit_paragraph_margins.hwpx" PARAGRAPH_SPACING = Path(__file__).parent / "fixtures" / "hancom_saved" / "formfit_paragraph_spacing.hwpx" BOLD_ADVANCES = Path(__file__).parent / "fixtures" / "hancom_saved" / "formfit_bold_advances.hwpx" +SPACE_SCALING = Path(__file__).parent / "fixtures" / "hancom_saved" / "formfit_space_scaling.hwpx" CHARS = TextStyle(break_non_latin_word="KEEP_WORD") # Hancom 글자 단위 SPACE_RUNS = Path(__file__).parent / "fixtures" / "hancom_saved" / "formfit_space_runs.hwpx" @@ -417,6 +419,23 @@ def test_bold_glyphs_take_the_advances_hancom_lays_them_out_at() -> None: assert bold_seen +def test_a_no_break_space_takes_its_ratio_and_no_spacing() -> None: + # Hancom laid "가", three no-break spaces (hp:nbSpace), fixed-width spaces or spaces and a tab out at 9, 10 + # and 14 pt in 맑은 고딕 under several 장평 and 자간: the tab's width shows how wide the spaces are. A + # no-break space takes the 장평 but no 자간 (at 120 % and -12 % a 9 pt one is 536, not 472). + assert char_advance(" ", 9, TextStyle(ratio=120, spacing=-12)) == 536 + assert char_advance(" ", 9, TextStyle(ratio=120, spacing=-12)) == 472 + document = HwpxDocument.open(SPACE_SCALING) + for paragraph in document.oxml.sections[0].element.findall(f"{HP}p")[1:]: + runs = paragraph.findall(f"{HP}run") + ref = runs[0].get("charPrIDRef") + style = text_style_from_refs(document, paragraph.get("paraPrIDRef"), [ref]) + size = int(document.oxml.char_property(ref).attributes["height"]) / 100 + text = page_layout._run_text(runs) + x = sum(char_advance(ch, size, style) for ch in text[:text.index(" ")]) + assert round((x // 4000 + 1) * 4000 - x) == int(paragraph.find(f".//{HP}tab").get("width")) + + def test_a_hangul_syllable_takes_its_own_advance_where_the_font_gives_it_one() -> None: # 한컴 말랑말랑 Regular's font draws the syllables with a horizontal vowel (ㅗ ㅛ ㅜ ㅠ ㅡ) 820 of 1000 units # wide and the others 880; the faces whose syllables are all one width keep it.