From 18aadc898c4db9327b0ea5d3aff2b7adf3a77f4f Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Fri, 2 Oct 2026 06:46:49 +0900 Subject: [PATCH 1/2] fix(layout): follow objects set as characters in a line reaching a band A line reaching a top-and-bottom object's band was refused when it held objects set as characters; Hancom moves it below the band like a line of text (an object no taller than the text not making it taller). An empty paragraph holding one object set as a character beside a square-wrapped object's band was refused; Hancom sets its line below the band, the whole width, when the object is wider than the room beside it, and beside it otherwise. Text with objects set as characters beside a square-wrapped object's band was laid out as if the band were not there. Hancom moves the line holding one wider than the room beside the object below the object, leaving the rest of the room empty; that is not followed yet, so such a paragraph is now refused instead. Seven Hancom-saved documents: a rectangle's band reached by a line holding a group, a picture, or a group alone, and by text; a picture's band beside a wide and a narrow table set as a character alone, and beside text holding such a table. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 9 +++++++ src/hwpx/layout/pages.py | 22 ++++++++++++++++-- .../pages_push_band_group_as_character.hwpx | Bin 0 -> 8316 bytes ...es_push_band_group_as_character_alone.hwpx | Bin 0 -> 8307 bytes .../pages_push_band_picture_as_character.hwpx | Bin 0 -> 8597 bytes .../hancom_saved/pages_push_band_text.hwpx | Bin 0 -> 8104 bytes ..._band_narrow_table_as_character_alone.hwpx | Bin 0 -> 8747 bytes ..._square_band_table_as_character_alone.hwpx | Bin 0 -> 8685 bytes ...re_band_table_as_character_among_text.hwpx | Bin 0 -> 9017 bytes tests/test_layout_page_estimate.py | 22 ++++++++++++++++++ 10 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/hancom_saved/pages_push_band_group_as_character.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_push_band_group_as_character_alone.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_push_band_picture_as_character.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_push_band_text.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_band_narrow_table_as_character_alone.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_band_table_as_character_alone.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_band_table_as_character_among_text.hwpx diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e92b3a2..67305997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,15 @@ 닿고, 칸의 다음 줄은 그 아래에서 이어진다. 위로 띄운 표는 문단 윗선에 선다. 그런 행이 쪽을 넘어 줄 사이에서 나뉠 때도 표는 그 높이의 한 줄로 센다. 글 앞에 둔 그런 표는 거기 닿는 첫 줄부터 표 아래로 보낸다. 한 문단에 표가 둘이면 한/글은 빈 줄을 아래 표 밑으로 보내므로 전처럼 캐시가 있어야 한다. +- 쪽 수 추정(실험, `estimate_pages`)이 위아래 개체의 띠에 닿는 줄에 글자처럼 둔 개체가 있으면 지원 밖 + (`a page break or another object beside a square-wrapped object`)으로 두던 것을 고친다. 한/글은 그런 줄도 글 줄처럼 + 띠 아래로 보낸다. 글자처럼 둔 개체가 줄 높이를 키우지 않으면 줄 높이는 글 높이 그대로다. +- 쪽 수 추정(실험, `estimate_pages`)이 어울림(SQUARE) 개체 곁 띠에 글자처럼 둔 개체 하나만 든 빈 문단을 지원 밖 + (`an object beside a square-wrapped object`)으로 두던 것을 고친다. 한/글은 개체가 곁 자리보다 넓으면 그 줄을 띠 + 아래로 보내 전체 폭에 두고, 좁으면 곁에 둔다. +- 쪽 수 추정(실험, `estimate_pages`)이 어울림 개체 곁 띠에서 글 사이에 글자처럼 둔 개체가 든 문단을 띠 없이 세던 + 것을 고친다. 한/글은 곁 자리보다 넓은 개체가 든 줄을 띠 아래로 보내는데, 이것은 아직 따르지 않아 지원 밖 + (`objects set as characters among text beside a square-wrapped object`)으로 둔다. - 쪽 수 추정(실험, `estimate_pages`)이 칸 단위로 나누는 흐르는 표(`pageBreak="CELL"`)에서 병합 칸으로 이어진 행들이 한 쪽보다 길면 "rows merged together taller than a page"로 거부하던 것을 고친다. 한/글은 쪽 끝마다 다시 나눈다. 칸마다 그 쪽에 들어가는 줄까지 두고 나머지는 다음 쪽 머리 행 아래로 넘기며, 넘긴 부분이 다시 diff --git a/src/hwpx/layout/pages.py b/src/hwpx/layout/pages.py index b12bf831..159440e4 100644 --- a/src/hwpx/layout/pages.py +++ b/src/hwpx/layout/pages.py @@ -1608,6 +1608,8 @@ def _paragraph(measure: _Measure, page: _Page, paragraph: Any, wrap: _Wrap | Non mixed = len(set(sizes)) > 1 or bool(end) or bool(head) looks = _char_styles(measure, paragraph, runs) if among or beside: + if wrap is not None: # the line holding one wider than the room beside it goes below the object + raise _Unsupported("objects set as characters among text beside a square-wrapped object") inline_text, inline_sizes, inline_looks, placed, marked = _inline_content(measure, paragraph, runs, anchored) if not cached: looks_or_none = inline_looks if len(set(inline_looks)) > 1 else None @@ -1738,9 +1740,10 @@ def _wrapped_paragraph(measure: _Measure, page: _Page, paragraph: Any, square = _square_object(objects, runs, page.column_width) pusher = _pushing_object(objects, _run_text(runs), page.column_width) shape = measure.shape(paragraph.get("paraPrIDRef")) + placed = [obj for obj in objects if obj.find(f"{HP}pos").get("treatAsChar") != "1"] if wrap is not None: wrap = wrap.lower(shape.prev) - if wrap is not None and (square is not None or pusher is not None or (wrap.push and objects) + if wrap is not None and (square is not None or pusher is not None or (wrap.push and placed) or _on(shape.flags, "pageBreakBefore") or paragraph.get("pageBreak") == "1" or paragraph.get("columnBreak") == "1"): raise _Unsupported("a page break or another object beside a square-wrapped object") @@ -1759,8 +1762,16 @@ def _wrapped_paragraph(measure: _Measure, page: _Page, paragraph: Any, if _local(pusher) == "tbl": # as tall as its rows tall += sum(row.height for row in _rows(measure, pusher)) - int(pusher.find(f"{HP}sz").get("height", 0)) return _push(para, _Wrap(top, top + tall, 0, push=True), starts=True) - if wrap is not None and wrap.push: + if wrap is not None and wrap.push: # objects set as characters on a line reaching it go below it with it return _push(_paragraph(measure, page, paragraph), wrap, starts=False) + if wrap is not None and objects and not placed and not _run_text(runs).strip(): + para = _paragraph(measure, page, paragraph) # one object set as a character, alone + if len(objects) > 1: + raise _Unsupported("objects set as characters beside a square-wrapped object") + if _object_extent(objects[0], measure)[0] > _room_beside(wrap, page.column_width - shape.left - shape.right): + return _push(para, replace(wrap, push=True), starts=False) # below the object, the whole width + beside = sum(1 for line in range(para.lines) if para.span(0, line) < wrap.bottom) + return replace(para, wrap_lines=beside), wrap.lower(para.span(0, para.lines) + para.next) starts = square is not None if square is not None: top = int(square.find(f"{HP}pos").get("vertOffset", 0)) @@ -1805,6 +1816,13 @@ def _pushing_object(objects: list[Any], text: str, column: int) -> Any: return obj +def _room_beside(wrap: _Wrap, width: int) -> int: + """How wide a line of *width* is beside a square-wrapped object's band: its wider piece when the text + goes on both sides.""" + + return max(wrap.split, width - wrap.cut - wrap.split) if wrap.split else width - wrap.cut + + def _push(para: _Para, band: _Wrap, *, starts: bool) -> tuple[_Para, _Wrap | None]: """*para* with the first line reaching a top-and-bottom object's *band* moved below it (the lines after follow), and the band as the next paragraph sees it (``None`` once a line went below it). diff --git a/tests/fixtures/hancom_saved/pages_push_band_group_as_character.hwpx b/tests/fixtures/hancom_saved/pages_push_band_group_as_character.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..1592ad66c1e164a9b01f90504b279e71b996fa71 GIT binary patch literal 8316 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_push_band_group_as_character_alone.hwpx b/tests/fixtures/hancom_saved/pages_push_band_group_as_character_alone.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..7d7b3407cb12ec7309711f3cda5479c3a1b6630f GIT binary patch literal 8307 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_push_band_picture_as_character.hwpx b/tests/fixtures/hancom_saved/pages_push_band_picture_as_character.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..2d5aa49969b7a16d646913a224e40599f945de46 GIT binary patch literal 8597 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 xgg-Zg-v~Qo|5J!B4(EI3ob?e*h|k>n;EQ literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_push_band_text.hwpx b/tests/fixtures/hancom_saved/pages_push_band_text.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..5008690ab2c21c0f04c6b0d3feea339f3e7434c9 GIT binary patch literal 8104 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 AivR!s literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_square_band_table_as_character_alone.hwpx b/tests/fixtures/hancom_saved/pages_square_band_table_as_character_alone.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..57f866a545c4f1cd0d80b8a699eaf11f241f6b70 GIT binary patch literal 8685 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_square_band_table_as_character_among_text.hwpx b/tests/fixtures/hancom_saved/pages_square_band_table_as_character_among_text.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..d679fe5306dcabd391a30dfea1ef1eec8d1f0502 GIT binary patch literal 9017 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 H?xFQR%G|T- literal 0 HcmV?d00001 diff --git a/tests/test_layout_page_estimate.py b/tests/test_layout_page_estimate.py index d6494e3e..a75ced0c 100644 --- a/tests/test_layout_page_estimate.py +++ b/tests/test_layout_page_estimate.py @@ -23,6 +23,17 @@ HH = "{http://www.hancom.co.kr/hwpml/2011/head}" FIXTURES = Path(__file__).parent / "fixtures" / "hancom_saved" HANCOM_PAGES = { + # A rectangle placed top and bottom 2000 down from an empty paragraph's top, 20000 x 8000 (one column + # 48188 wide): the next paragraph's line reaching it goes below it, the whole width, even holding objects + # set as characters (a group or a picture 44633 x 648, which do not make it taller than its text): + "pages_push_band_text": 1, # a character alone + "pages_push_band_group_as_character": 1, # a character, a group and a polygon in front of the text + "pages_push_band_picture_as_character": 1, + "pages_push_band_group_as_character_alone": 1, # the group and the polygon, no text + # A picture wrapped square from an empty paragraph's left, 41631 x 27112, leaving 6557 beside it; the + # next paragraph holds a table set as a character alone: + "pages_square_band_table_as_character_alone": 1, # 47058 wide: below the picture, the whole width + "pages_square_band_narrow_table_as_character_alone": 1, # 5000 wide: beside it, and the lines after "pages_fixed_width_spaces": 2, # rows of a syllable and a fixed-width space: a quarter em that hangs "pages_no_break_spaces": 2, # rows of "가나" and a no-break space: each is half an em and keeps the row # one word @@ -448,6 +459,17 @@ def test_without_line_caches_formfit_breaks_the_lines_the_same(name: str) -> Non _assert_like_hancom(estimate_pages(_without_caches(data)), data, HANCOM_PAGES[name]) +def test_objects_set_as_characters_among_text_beside_a_square_wrapped_object_are_not_followed() -> None: + # Text beside the picture wrapped square (as in pages_square_band_table_as_character_alone) with a table set + # as a character after it: Hancom sets the text in the room beside the picture and the table's line, wider + # than that room, below the picture, leaving the rest of the room empty. The estimate does not follow that. + data = (FIXTURES / "pages_square_band_table_as_character_among_text.hwpx").read_bytes() + + for source in (data, _without_caches(data)): + assert estimate_pages(source).unsupported == ( + "section 0: objects set as characters among text beside a square-wrapped object",) + + def test_a_typed_ideographic_space_is_not_a_fixed_width_one() -> None: # 맑은 고딕 10 pt cells of narrowing widths, laid out and saved by Hancom: rows of "가나다라마" each followed # by one or two ideographic spaces typed in the text (U+3000), or by fixed-width spaces (hp:fwSpace, which From 8ac3853e67686bda786afb154c4a72dcc56bf7f4 Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Fri, 2 Oct 2026 08:30:06 +0900 Subject: [PATCH 2/2] fix(layout): lay text with objects as characters out beside a square-wrapped object Text with objects set as characters beside a square-wrapped object's band, refused in the commit before, is now laid out as Hancom does: a line whose top is in the band is as wide as the room beside the object, and the first line holding an object wider than that room goes below the band, the whole width, leaving the rest of the room empty (the line before is spaced that much more, or the paragraph's first line starts that much lower). Without a layout cache _banded_object_lines breaks the lines so, every line taken as narrow at first until the narrow ones settle; with one, the cache's own positions are followed (_cached_jumps). Text on both sides of the object is still refused. Three more Hancom-saved documents: a narrow table and a picture among the text, and a table after a short band; the document of a wide table among text, refused before, is now a HANCOM_PAGES entry. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 5 +- src/hwpx/layout/pages.py | 78 ++++++++++++++++-- ..._narrow_table_as_character_among_text.hwpx | Bin 0 -> 9053 bytes ..._band_picture_as_character_among_text.hwpx | Bin 0 -> 8911 bytes ...table_as_character_below_a_short_band.hwpx | Bin 0 -> 8949 bytes tests/test_layout_page_estimate.py | 30 +++++-- 6 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 tests/fixtures/hancom_saved/pages_square_band_narrow_table_as_character_among_text.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_band_picture_as_character_among_text.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_square_band_table_as_character_below_a_short_band.hwpx diff --git a/CHANGELOG.md b/CHANGELOG.md index 67305997..d01789a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,9 @@ (`an object beside a square-wrapped object`)으로 두던 것을 고친다. 한/글은 개체가 곁 자리보다 넓으면 그 줄을 띠 아래로 보내 전체 폭에 두고, 좁으면 곁에 둔다. - 쪽 수 추정(실험, `estimate_pages`)이 어울림 개체 곁 띠에서 글 사이에 글자처럼 둔 개체가 든 문단을 띠 없이 세던 - 것을 고친다. 한/글은 곁 자리보다 넓은 개체가 든 줄을 띠 아래로 보내는데, 이것은 아직 따르지 않아 지원 밖 - (`objects set as characters among text beside a square-wrapped object`)으로 둔다. + 것을 고친다. 이제 띠 안에서 시작하는 줄은 곁 자리 폭으로 나눈다. 곁 자리보다 넓은 개체가 든 첫 줄은 한/글처럼 + 띠 아래로 보내 전체 폭에 두고, 곁의 남은 자리는 비운다. 글이 개체 양쪽에 놓이는 띠에서는 지원 밖 + (`objects set as characters among text beside a square-wrapped object`)이다. - 쪽 수 추정(실험, `estimate_pages`)이 칸 단위로 나누는 흐르는 표(`pageBreak="CELL"`)에서 병합 칸으로 이어진 행들이 한 쪽보다 길면 "rows merged together taller than a page"로 거부하던 것을 고친다. 한/글은 쪽 끝마다 다시 나눈다. 칸마다 그 쪽에 들어가는 줄까지 두고 나머지는 다음 쪽 머리 행 아래로 넘기며, 넘긴 부분이 다시 diff --git a/src/hwpx/layout/pages.py b/src/hwpx/layout/pages.py index 159440e4..aceeaf1b 100644 --- a/src/hwpx/layout/pages.py +++ b/src/hwpx/layout/pages.py @@ -1607,11 +1607,17 @@ def _paragraph(measure: _Measure, page: _Page, paragraph: Any, wrap: _Wrap | Non head = _head_size(measure, paragraph, sizes) mixed = len(set(sizes)) > 1 or bool(end) or bool(head) looks = _char_styles(measure, paragraph, runs) + lead = 0 # how far the paragraph's first line goes down below a square-wrapped object's band if among or beside: - if wrap is not None: # the line holding one wider than the room beside it goes below the object - raise _Unsupported("objects set as characters among text beside a square-wrapped object") inline_text, inline_sizes, inline_looks, placed, marked = _inline_content(measure, paragraph, runs, anchored) - if not cached: + if wrap is not None: + if beside or wrap.split or marked: + raise _Unsupported("objects set as characters among text beside a square-wrapped object") + looks_or_none = inline_looks if len(set(inline_looks)) > 1 else None + lines, lead = _banded_object_lines(measure, inline_text, widths, inline_sizes, style, shape, wrap, placed, + looks_or_none, end, head) + cached = _cached_jumps(paragraph, cached) if cached else lines + elif not cached: looks_or_none = inline_looks if len(set(inline_looks)) > 1 else None cached = _line_metrics(measure, inline_text, widths, inline_sizes, style, shape, placed, looks_or_none, marked, end, head) @@ -1643,8 +1649,9 @@ def _paragraph(measure: _Measure, page: _Page, paragraph: Any, wrap: _Wrap | Non notes = _anchored_notes(measure, runs, text, widths, size, style, page.column_width, sizes if mixed else None, looks) flags = shape.flags - para = _Para(count, size, pitch, shape.prev, shape.next, _on(flags, "pageBreakBefore"), _on(flags, "keepLines"), - _on(flags, "keepWithNext"), _on(flags, "widowOrphan"), paragraph.get("pageBreak") == "1", + para = _Para(count, size, pitch, shape.prev + lead, shape.next, _on(flags, "pageBreakBefore"), + _on(flags, "keepLines"), _on(flags, "keepWithNext"), _on(flags, "widowOrphan"), + paragraph.get("pageBreak") == "1", paragraph.get("columnBreak") == "1", table, notes, cached, anchor, wrap_anchor=around, hides=page.hide_empty and _holds_nothing(runs)) if reflow and text: @@ -1790,10 +1797,11 @@ def _wrapped_paragraph(measure: _Measure, page: _Page, paragraph: Any, raise _Unsupported("an object beside a square-wrapped object") if wrap is None: return para, None - beside = sum(1 for line in range(para.lines) if para.span(0, line) < wrap.bottom) + lead = para.prev - shape.prev # its first line moved below the band + beside = sum(1 for line in range(para.lines) if lead + para.span(0, line) < wrap.bottom) para = replace(para, wrap_lines=beside, wrap_bottom=wrap.bottom if starts else 0, wrap_fixed=bool(_cached_metrics(paragraph))) - return para, wrap.lower(para.span(0, para.lines) + para.next) + return para, wrap.lower(lead + para.span(0, para.lines) + para.next) def _pushing_object(objects: list[Any], text: str, column: int) -> Any: @@ -1894,6 +1902,62 @@ def _at_one_height(metrics: tuple[tuple[int, int], ...], firsts: set[int]) -> tu return tuple(lines) +def _banded_object_lines(measure: _Measure, text: str, widths: list[float], sizes: list[int], style: Any, + shape: _Shape, wrap: _Wrap, objects: dict[int, tuple[int, int]], looks: list[Any] | None, + end: int, head: int) -> tuple[tuple[tuple[int, int], ...], int]: + """(height, advance) of each line of text holding objects set as characters (*objects*: place -> width and + height) beside a square-wrapped object's band, and how far the first line goes down. A line whose top is in + the band is as wide as the room beside the object, but the first one holding an object wider than that room + goes below the band, the whole width, the rest of the room left empty (its line before spaced that much + more). Every line taken as narrow at first, the lines are broken again until the narrow ones settle.""" + + advances = {index: width for index, (width, _) in objects.items()} or None + mixed = sizes if len(set(sizes)) > 1 else None + narrow = set(range(len(text) + 1)) + for _ in range(8): + widths_by_line = [widths[min(line, 1)] - (wrap.cut if line in narrow else 0) + for line in range(min(max(narrow, default=0), len(text)) + 2)] + starts = measure.line_starts(text, widths_by_line, min(sizes), style, mixed, looks, advances) + metrics: list[tuple[int, int]] = [] + found: set[int] = set() + top = lead = 0 + for line, (start, stop) in enumerate(zip(starts, [*starts[1:], len(text)])): + span = range(start, stop) if stop > start else range(len(text) - 1, len(text)) + size = max([sizes[index] for index in span] + ([end] if stop == len(text) else []) + + ([head] if start == 0 else [])) + height = max([size] + [objects[index][1] for index in span if index in objects]) + pitch = _pitch(shape.kind, shape.value, size) + advance = pitch if shape.kind == "FIXED" else height + pitch - size + if top < wrap.bottom and top + height > wrap.top: + room = widths[min(line, 1)] - wrap.cut + if any(objects[index][0] > room for index in span if index in objects): # below the band + if metrics: + metrics[-1] = (metrics[-1][0], metrics[-1][1] + wrap.bottom - top) + else: + lead = wrap.bottom - top + top = wrap.bottom + else: + found.add(line) + metrics.append((height, advance)) + top += advance + if found == narrow: + return tuple(metrics), lead + narrow = found + raise _Unsupported("lines beside a square-wrapped object that do not settle") + + +def _cached_jumps(paragraph: Any, metrics: tuple[tuple[int, int], ...]) -> tuple[tuple[int, int], ...]: + """*metrics* from the paragraph's layout cache with each line spaced down to where the cache puts the next + one on its page when that is lower (a line Hancom moved below a square-wrapped object's band).""" + + tops = [int(segment.get("vertpos", 0)) for segment in paragraph.findall(f"{HP}linesegarray/{HP}lineseg")] + lines = list(metrics) + for line, (above, below) in enumerate(zip(tops, tops[1:])): + if line < len(lines) and below - above > lines[line][1]: + lines[line] = (lines[line][0], below - above) + return tuple(lines) + + # -- laying the paragraphs out --------------------------------------------------------------------- diff --git a/tests/fixtures/hancom_saved/pages_square_band_narrow_table_as_character_among_text.hwpx b/tests/fixtures/hancom_saved/pages_square_band_narrow_table_as_character_among_text.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..d87315956497766ea9fc97da814d1d6396e470e8 GIT binary patch literal 9053 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_square_band_picture_as_character_among_text.hwpx b/tests/fixtures/hancom_saved/pages_square_band_picture_as_character_among_text.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..3ad0a4d33534ceccd9e27cd94e1f57bbf14de747 GIT binary patch literal 8911 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 P@b4A;0BwUKA|U(^L_tov literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_square_band_table_as_character_below_a_short_band.hwpx b/tests/fixtures/hancom_saved/pages_square_band_table_as_character_below_a_short_band.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..6caab2a343d8a2cb06bcb4e124f012df94992d6e GIT binary patch literal 8949 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 Non _assert_like_hancom(estimate_pages(_without_caches(data)), data, HANCOM_PAGES[name]) -def test_objects_set_as_characters_among_text_beside_a_square_wrapped_object_are_not_followed() -> None: - # Text beside the picture wrapped square (as in pages_square_band_table_as_character_alone) with a table set - # as a character after it: Hancom sets the text in the room beside the picture and the table's line, wider - # than that room, below the picture, leaving the rest of the room empty. The estimate does not follow that. +def test_objects_set_as_characters_among_text_on_both_sides_of_a_square_wrapped_object_are_not_followed() -> None: + # The picture of pages_square_band_table_as_character_among_text moved 3000 from the column's left: text goes + # on both sides of it, each line in two pieces, and an object among it is not followed there. + out = io.BytesIO() data = (FIXTURES / "pages_square_band_table_as_character_among_text.hwpx").read_bytes() + with zipfile.ZipFile(io.BytesIO(data)) as source, zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as target: + for info in source.infolist(): + payload = source.read(info.filename) + if info.filename.startswith("Contents/section"): + root = etree.fromstring(payload) + square = next(pic for pic in root.iter(f"{HP}pic") if pic.get("textWrap") == "SQUARE") + square.find(f"{HP}pos").set("horzOffset", "3000") + payload = etree.tostring(root, xml_declaration=True, encoding="UTF-8", standalone=True) + target.writestr(info, payload) - for source in (data, _without_caches(data)): - assert estimate_pages(source).unsupported == ( - "section 0: objects set as characters among text beside a square-wrapped object",) + assert estimate_pages(_without_caches(out.getvalue())).unsupported == ( + "section 0: objects set as characters among text beside a square-wrapped object",) def test_a_typed_ideographic_space_is_not_a_fixed_width_one() -> None: