From ffde8d69995cba7951c38609bfa5ff9a1b25ca9a Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Thu, 1 Oct 2026 12:42:47 +0900 Subject: [PATCH 1/3] fix(layout): split rows joined by merged cells again at every page end In a flowing table split between cell lines, rows joined by a cell merged over them that stayed taller than a page after one split were refused. Hancom splits them again at each page end: every cell keeps the lines that fit on the page and the rest goes on below the next page's header rows, and a merged cell longer than its rows goes on alone after they end. The room a cell is declared beyond its text is cut at each page end like a row's, also once its text is all placed. _split_block now does that page after page; _block_rest returns what goes on (each row's height and each cell with the lines it has left) and _cell_rest measures one cell's rest. Only a cell no line of which fits a page is still refused. Five Hancom-saved fixtures: 100 one-line rows joined by a cell merged down all of them (three pages), 60 rows with a merged cell of 150 lines (four pages, the cell going on alone), rows of one and three lines (a row split between its lines), and eight rows joined by a cell declared 80000 tall, and by an empty one declared 75000 tall. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ++ src/hwpx/layout/pages.py | 92 ++++++++++++------ ..._joined_rows_over_pages_declared_cell.hwpx | Bin 0 -> 10815 bytes ...d_rows_over_pages_empty_declared_cell.hwpx | Bin 0 -> 9005 bytes ...pages_joined_rows_over_pages_label150.hwpx | Bin 0 -> 13126 bytes .../pages_joined_rows_over_pages_mixed.hwpx | Bin 0 -> 12062 bytes .../pages_joined_rows_over_pages_n100.hwpx | Bin 0 -> 12339 bytes tests/test_layout_page_estimate.py | 20 +++- 8 files changed, 82 insertions(+), 36 deletions(-) create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_over_pages_declared_cell.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_over_pages_empty_declared_cell.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_over_pages_label150.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_over_pages_mixed.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_over_pages_n100.hwpx diff --git a/CHANGELOG.md b/CHANGELOG.md index a2cdc978..c6613e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ ### 고침 +- 쪽 수 추정(실험, `estimate_pages`)이 칸 단위로 나누는 흐르는 표(`pageBreak="CELL"`)에서 병합 칸으로 이어진 + 행들이 한 쪽보다 길면 "rows merged together taller than a page"로 거부하던 것을 고친다. 한/글은 쪽 끝마다 + 다시 나눈다. 칸마다 그 쪽에 들어가는 줄까지 두고 나머지는 다음 쪽 머리 행 아래로 넘기며, 넘긴 부분이 다시 + 쪽보다 길면 그 쪽 끝에서 또 나눈다. 행들보다 긴 병합 칸은 행이 끝난 뒤에도 혼자 다음 쪽들로 이어진다. 글보다 + 높게 선언된 칸의 남는 높이도(글이 다 들어간 뒤에도) 쪽 끝마다 행처럼 잘려 이어진다. 어느 쪽에도 한 줄도 + 들어가지 않는 칸만 전처럼 거부한다. - 쪽 수 추정(실험, `estimate_pages`)이 병합 칸으로 묶인 행들이 쪽 바닥을 빈 높이 안에서만 넘을 때, 그 행들을 그 쪽 바닥에서 끝낸다. 모든 칸의 글이 바닥 위에 들어가고 남는 높이가 1282 이하면 다음 쪽으로 넘길 것이 없다. 전에는 표 윗 여백만 있는 빈 쪽이 하나 더 생겼다. diff --git a/src/hwpx/layout/pages.py b/src/hwpx/layout/pages.py index a2536c0a..e8a1638d 100644 --- a/src/hwpx/layout/pages.py +++ b/src/hwpx/layout/pages.py @@ -84,7 +84,8 @@ move to the next page as one, and in one split between cell lines each of their cells keeps the lines that fit and the rest go on, the rows from the one the page end falls in as tall as their cells' rest (a cell declared taller than its text, whose first line fits, is cut like such a row, - below). A table set as a character alone in a paragraph of a cell is one line as tall as it + below), a rest taller than a page split again at each page end the same way. A table set as a + character alone in a paragraph of a cell is one line as tall as it there, spaced like the text, and a row holding one splits between its cell's lines, each as tall as it is; a nested table among text, placed top and bottom or wrapped square is followed through the layout caches of its cell, as tall as Hancom drew it (down to such a table's foot; one placed @@ -123,8 +124,9 @@ across the column before any text; an object offset down, but a flowing table, or wrapped square stays on one page with the lines above or beside it), footnotes in such a paragraph, two tables starting past their -anchors on one page, rows merged together that do not fit under their table's anchor or on a -page, a nested table among text or not set as a character in a cell without such caches (in a table +anchors on one page, rows merged together that do not fit under their table's anchor, or on a +page in a table moved row by row (split between cell lines: a cell no line of which fits a page), +a nested table among text or not set as a character in a cell without such caches (in a table Hancom has not laid out as it is), a page break in a flowing row holding a table beside a taller cell, other objects placed on the page or the paper (but top and bottom from its top or bottom, a flowing table on their page keeping clear of them), and in a paragraph without such a cache ruby text @@ -1766,13 +1768,7 @@ def _flow_table(table: _FlowTable, frame: int, y: int, body: int) -> tuple[int, continue if table.mode == "CELL" and end > index and table.cells \ and y + sum(row.height for row in rows[index:end + 1]) > foot: # split cell by cell - rest = _block_rest(table, index, end, y, body) - if not rest: # every cell done above the page end, what it declares below dropped: they end there - y, index = body, end + 1 - continue - frame, y = frame + 1, header + rest - if y > foot: - raise _Unsupported("rows merged together taller than a page") + frame, y = _split_block(table, index, end, frame, y, body, header) index = end + 1 continue before, start = frame, y @@ -1789,12 +1785,38 @@ def _flow_table(table: _FlowTable, frame: int, y: int, body: int) -> tuple[int, return frame, y -def _block_rest(table: _FlowTable, first: int, last: int, top: int, body: int) -> int: - """How tall rows *first*..*last*, joined by merged cells, are on the next page when the page end +def _split_block(table: _FlowTable, first: int, last: int, frame: int, y: int, body: int, + header: int) -> tuple[int, int]: + """Rows *first*..*last*, joined by merged cells and starting at *y*, in a table split between cell + lines when the page end falls among them: each page keeps the lines that fit, and what is left goes on + below the next page's *header*, split again at that page's end until it fits. The frame and position + where they end.""" + + foot, before = body - table.cut, None + while True: + cut, heights, cells = _block_rest(table, first, last, y, body) + rest = sum(heights.values()) + if not rest: # every cell done above the page end, what it declares below dropped: they end there + return frame, body + if header + rest <= foot: + return frame + 1, header + rest + if before is not None and rest >= before: # nothing of it fits a page + raise _Unsupported("rows merged together taller than a page") + rows = list(table.rows) + for index, height in heights.items(): + rows[index] = replace(rows[index], height=height) + table, first, frame, y, before = replace(table, rows=rows, cells=tuple(cells)), cut, frame + 1, header, rest + + +def _block_rest(table: _FlowTable, first: int, last: int, top: int, + body: int) -> tuple[int, dict[int, int], list[tuple[int, int, _Row]]]: + """What goes on to the next page of rows *first*..*last*, joined by merged cells, when the page end falls among them in a table split between cell lines: every cell keeps the lines that fit above the page end and the rest go on. From the row the page end falls in, each row is as tall as the rest of its cells of one row (the rows after it whole), then each merged cell's rest, the one - ending first first, adds what its rows lack to the last of them.""" + ending first first, adds what its rows lack to the last of them. The row the page end falls in, + each row's height from it on, and the cells that go on, each as tall as its rest with the lines + it has left.""" rows, tops, y, foot = table.rows, {}, top, body - table.cut for index in range(first, last + 1): @@ -1803,34 +1825,42 @@ def _block_rest(table: _FlowTable, first: int, last: int, top: int, body: int) - cut = next(index for index in range(first, last + 1) if tops[index] + rows[index].height > foot) heights = dict.fromkeys(range(cut, last + 1), 0) rests: list[tuple[int, int, int]] = [] + cells: list[tuple[int, int, _Row]] = [] for start, span, cell in table.cells: end = start + span - 1 if start < first or start > last or end < cut: continue # another row, or done above the page end - if start > cut: # wholly on the next page - rest = cell.height - else: - fitting = 0 - while fitting < cell.lines and tops[start] + cell.margins + fitting * cell.pitch + cell.size <= foot: - fitting += 1 - if cell.spare and fitting: # its text starts above the page end: the declared room is cut like a row's - rest = tops[start] + cell.height - foot - if rest <= _SPARE_DROPPED: - continue - elif cell.spare: # none of it fits: it goes on whole - rest = cell.height - elif fitting == cell.lines: - continue - else: - rest = cell.margins + (cell.lines - fitting - 1) * cell.pitch + cell.size + part = (cell.height, cell.lines) if start > cut else _cell_rest(cell, tops[start], foot) + if part is None: + continue + rest, begin = part[0], max(start, cut) + cells.append((begin, end - begin + 1, replace(cell, height=rest, lines=part[1]))) if span == 1: heights[start] = max(heights[start], rest) else: - rests.append((max(start, cut), end, rest)) + rests.append((begin, end, rest)) for start, end, rest in sorted(rests, key=lambda item: (item[1], item[0])): lacking = rest - sum(heights[index] for index in range(start, end + 1)) heights[end] += max(lacking, 0) - return sum(heights.values()) + return cut, heights, cells + + +def _cell_rest(cell: _Row, top: int, foot: int) -> tuple[int, int] | None: + """How tall the part of a cell starting at *top* that goes on past the page end *foot* is, and how many + lines it holds; ``None`` when nothing of it goes on.""" + + fitting = 0 + while fitting < cell.lines and top + cell.margins + fitting * cell.pitch + cell.size <= foot: + fitting += 1 + if cell.spare and (fitting or not cell.lines): # its text (or what is left: none) starts above the page end: + # the declared room is cut like a row's + rest = top + cell.height - foot + return (rest, cell.lines - fitting) if rest > _SPARE_DROPPED else None + if cell.spare: # none of it fits: it goes on whole + return cell.height, cell.lines + if fitting == cell.lines: + return None + return cell.margins + (cell.lines - fitting - 1) * cell.pitch + cell.size, cell.lines - fitting def _flow_row(mode: str, row: _Row, frame: int, y: int, body: int, header: int, diff --git a/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_declared_cell.hwpx b/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_declared_cell.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..9767ddf99a2ebf8fadb3498a0d2fc30f0ea78bf8 GIT binary patch literal 10815 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 Zb!9nt$SMQ{^&Il}K-Q#Bkd9DL{|}~8fz|*3 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_empty_declared_cell.hwpx b/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_empty_declared_cell.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..cdf8379e240d67358cc92e71e25cb2ecbce50c96 GIT binary patch literal 9005 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_label150.hwpx b/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_label150.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..31e246ffe53bd3fae1a977d2dc7192657a4f1160 GIT binary patch literal 13126 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_mixed.hwpx b/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_mixed.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..0fc22cdf582606d7be48fd31178345687e5a6ace GIT binary patch literal 12062 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 I>E-GF0OgZ6QUCw| literal 0 HcmV?d00001 diff --git a/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_n100.hwpx b/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_n100.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..b4b88bd9b2df8c8f23948a760e553351879b3663 GIT binary patch literal 12339 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 literal 0 HcmV?d00001 diff --git a/tests/test_layout_page_estimate.py b/tests/test_layout_page_estimate.py index 6a2d67d0..15c727f5 100644 --- a/tests/test_layout_page_estimate.py +++ b/tests/test_layout_page_estimate.py @@ -70,6 +70,16 @@ # empty one spaced 562 before it "pages_hide_empty_lines_ending_the_document": 1, # two ending the document: no second page "pages_hide_empty_lines_off": 2, # two, the setting off: they start the next page + "pages_joined_rows_over_pages_n100": 3, # 100 one-line rows joined by a cell merged down all of them, + # split between cell lines: what is left is split again at + # each page end + "pages_joined_rows_over_pages_label150": 4, # 60 such rows and a merged cell of 150 lines: the cell + # goes on alone over the last two pages + "pages_joined_rows_over_pages_mixed": 3, # rows of one and three lines: a row split between its lines + "pages_joined_rows_over_pages_declared_cell": 3, # 8 rows joined by a cell declared 80000 tall, after 20 + # rows: its room cut at each page end, 10 rows after + "pages_joined_rows_over_pages_empty_declared_cell": 3, # an empty cell over 8 rows declared 75000 tall + # after 36 lines: cut over three pages "pages_table_row_split_a_first_line_not_fitting": 2, # the first 8 pt line of one cell fits, the 16 pt # line of the other does not: it goes on whole "pages_table_row_split_every_first_line_fitting": 2, # room for both: split after two 8 pt lines @@ -694,9 +704,9 @@ def _flowing_table_after(paragraphs: int, rows: int) -> tuple[HwpxDocument, obje return document, table -def test_rows_merged_together_taller_than_a_page_are_unsupported() -> None: - # The cell merged over rows 1-4 is declared 150000 tall: what is left of it after the page end - # does not fit on the next page either. +def test_a_merged_cell_declared_taller_than_two_pages_is_cut_at_each_page_end() -> None: + # The cell merged over rows 1-4 is declared 150000 tall: its room is cut 101 above each page's foot and + # the rest goes on, page after page (as in pages_joined_rows_over_pages_empty_declared_cell). document, table = _flowing_table_after(38, 6) table.merge_cells(1, 0, 4, 0) for cell in table.element.iter(f"{HP}tc"): @@ -706,8 +716,8 @@ def test_rows_merged_together_taller_than_a_page_are_unsupported() -> None: estimate = estimate_pages(document) - assert estimate.pages is None - assert estimate.unsupported == ("section 0: rows merged together taller than a page",) + assert estimate.unsupported == () + assert estimate.pages == 4 @pytest.mark.parametrize(("height", "rest"), [(20000, 13221), (8029, 0), (8061, 0), (8062, 1283), (8079, 1300)]) From 03bb1dfbfc25ad762560c0f8bf8294720f94a00c Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Thu, 1 Oct 2026 19:11:00 +0900 Subject: [PATCH 2/3] fix(layout): carry a declared row's lines over a page end at least as tall as they are When rows joined by a merged cell split between their lines and a cell declared taller than its text breaks at the page end, the part going on was its declared rest alone, and a rest no taller than a line was dropped even with lines still to go. Hancom makes that part as tall as the larger of the declared rest and the lines going on with the cell's margins, as it already does for a row of its own. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 ++- src/hwpx/layout/pages.py | 9 ++++++--- ..._joined_rows_declared_cut_in_a_later_row.hwpx | Bin 0 -> 9528 bytes ...ned_rows_declared_first_line_not_fitting.hwpx | Bin 0 -> 9490 bytes ...es_joined_rows_declared_rest_with_a_line.hwpx | Bin 0 -> 9549 bytes .../pages_joined_rows_text_height_split.hwpx | Bin 0 -> 9579 bytes tests/test_layout_page_estimate.py | 8 ++++++++ 7 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_declared_cut_in_a_later_row.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_declared_first_line_not_fitting.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_declared_rest_with_a_line.hwpx create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_text_height_split.hwpx diff --git a/CHANGELOG.md b/CHANGELOG.md index c6613e30..3ba551fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ 다시 나눈다. 칸마다 그 쪽에 들어가는 줄까지 두고 나머지는 다음 쪽 머리 행 아래로 넘기며, 넘긴 부분이 다시 쪽보다 길면 그 쪽 끝에서 또 나눈다. 행들보다 긴 병합 칸은 행이 끝난 뒤에도 혼자 다음 쪽들로 이어진다. 글보다 높게 선언된 칸의 남는 높이도(글이 다 들어간 뒤에도) 쪽 끝마다 행처럼 잘려 이어진다. 어느 쪽에도 한 줄도 - 들어가지 않는 칸만 전처럼 거부한다. + 들어가지 않는 칸만 전처럼 거부한다. 줄 사이에서 나뉜 선언 행의 다음 쪽 부분은 선언 높이의 나머지와, 이어지는 + 줄에 칸 위아래 여백을 더한 높이 가운데 큰 쪽이다. 이어지는 줄이 있으면 남은 높이가 낮아도 버리지 않는다. - 쪽 수 추정(실험, `estimate_pages`)이 병합 칸으로 묶인 행들이 쪽 바닥을 빈 높이 안에서만 넘을 때, 그 행들을 그 쪽 바닥에서 끝낸다. 모든 칸의 글이 바닥 위에 들어가고 남는 높이가 1282 이하면 다음 쪽으로 넘길 것이 없다. 전에는 표 윗 여백만 있는 빈 쪽이 하나 더 생겼다. diff --git a/src/hwpx/layout/pages.py b/src/hwpx/layout/pages.py index e8a1638d..b9f599d7 100644 --- a/src/hwpx/layout/pages.py +++ b/src/hwpx/layout/pages.py @@ -1853,9 +1853,12 @@ def _cell_rest(cell: _Row, top: int, foot: int) -> tuple[int, int] | None: while fitting < cell.lines and top + cell.margins + fitting * cell.pitch + cell.size <= foot: fitting += 1 if cell.spare and (fitting or not cell.lines): # its text (or what is left: none) starts above the page end: - # the declared room is cut like a row's - rest = top + cell.height - foot - return (rest, cell.lines - fitting) if rest > _SPARE_DROPPED else None + # the declared room is cut like a row's, and the lines that do not fit go on with it, which is then + # at least as tall as they are with the cell's margins + rest, left = top + cell.height - foot, cell.lines - fitting + if left: + return max(rest, cell.margins + (left - 1) * cell.pitch + cell.size), left + return (rest, 0) if rest > _SPARE_DROPPED else None if cell.spare: # none of it fits: it goes on whole return cell.height, cell.lines if fitting == cell.lines: diff --git a/tests/fixtures/hancom_saved/pages_joined_rows_declared_cut_in_a_later_row.hwpx b/tests/fixtures/hancom_saved/pages_joined_rows_declared_cut_in_a_later_row.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..ecf16d2a0cd2e03497933800e81cd4b56c8b658b GIT binary patch literal 9528 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 p{wEjz5e6(MOr{Wx}^m{`dgpp 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 literal 0 HcmV?d00001 diff --git a/tests/test_layout_page_estimate.py b/tests/test_layout_page_estimate.py index 15c727f5..84bae2b2 100644 --- a/tests/test_layout_page_estimate.py +++ b/tests/test_layout_page_estimate.py @@ -80,6 +80,14 @@ # rows: its room cut at each page end, 10 rows after "pages_joined_rows_over_pages_empty_declared_cell": 3, # an empty cell over 8 rows declared 75000 tall # after 36 lines: cut over three pages + # Rows 1-5 joined by a cell merged down them (4 lines), declared taller than their text, the page end + # falling among them: + "pages_joined_rows_declared_rest_with_a_line": 2, # in row 1: its rest is the line going on with the + # cell margins, taller than the declared rest + "pages_joined_rows_declared_cut_in_a_later_row": 2, # in row 2: its declared rest, taller than the line + "pages_joined_rows_declared_first_line_not_fitting": 2, # in row 3, before its first line: whole on the + # next page + "pages_joined_rows_text_height_split": 2, # in row 1, the rows as tall as their text: lines and margins "pages_table_row_split_a_first_line_not_fitting": 2, # the first 8 pt line of one cell fits, the 16 pt # line of the other does not: it goes on whole "pages_table_row_split_every_first_line_fitting": 2, # room for both: split after two 8 pt lines From 93c41bb5cfc5abfaad8808d692e127e46c9fdf68 Mon Sep 17 00:00:00 2001 From: airmang <38392618+airmang@users.noreply.github.com> Date: Thu, 1 Oct 2026 22:31:42 +0900 Subject: [PATCH 3/3] test(layout): check the merged cell declared 150000 tall against Hancom's saved layout The test of a cell merged over four rows and declared 150000 tall built its document and checked only the page count. It now reads the same document laid out and saved by Hancom, with and without its line caches: four pages, the cell's room cut at each page end, and the lines where Hancom put them. The table ends the document, so no line is on its last page and the HANCOM_PAGES helper does not apply. Co-Authored-By: Claude Opus 5.5 --- ...oined_rows_over_pages_declared_150000.hwpx | Bin 0 -> 8670 bytes tests/test_layout_page_estimate.py | 23 +++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 tests/fixtures/hancom_saved/pages_joined_rows_over_pages_declared_150000.hwpx diff --git a/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_declared_150000.hwpx b/tests/fixtures/hancom_saved/pages_joined_rows_over_pages_declared_150000.hwpx new file mode 100644 index 0000000000000000000000000000000000000000..9a1142e5552ad63dd90c710d200a1638c5db9a46 GIT binary patch literal 8670 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 Q^#bzsfy5*Q^5@e30Yptvd;kCd literal 0 HcmV?d00001 diff --git a/tests/test_layout_page_estimate.py b/tests/test_layout_page_estimate.py index 84bae2b2..de044416 100644 --- a/tests/test_layout_page_estimate.py +++ b/tests/test_layout_page_estimate.py @@ -713,19 +713,20 @@ def _flowing_table_after(paragraphs: int, rows: int) -> tuple[HwpxDocument, obje def test_a_merged_cell_declared_taller_than_two_pages_is_cut_at_each_page_end() -> None: - # The cell merged over rows 1-4 is declared 150000 tall: its room is cut 101 above each page's foot and - # the rest goes on, page after page (as in pages_joined_rows_over_pages_empty_declared_cell). - document, table = _flowing_table_after(38, 6) - table.merge_cells(1, 0, 4, 0) - for cell in table.element.iter(f"{HP}tc"): - span = cell.find(f"{HP}cellSpan") - if span is not None and span.get("rowSpan", "1") != "1": - cell.find(f"{HP}cellSz").set("height", "150000") + # After 38 lines, a flowing table of 6 rows whose cell merged over rows 1-4 is declared 150000 tall, laid + # out and saved by Hancom: the cell's room is cut 101 above each page's foot and the rest goes on, page + # after page, the last row ending the table (and the document) on page 4. No line of text is on that + # page, so the pages are checked here rather than in HANCOM_PAGES. + data = (FIXTURES / "pages_joined_rows_over_pages_declared_150000.hwpx").read_bytes() + hancom = _hancom_lines(data) - estimate = estimate_pages(document) + for source in (data, _without_caches(data)): + estimate = estimate_pages(source) + estimated = [[line.vertpos for line in lines] for lines in estimate.lines] - assert estimate.unsupported == () - assert estimate.pages == 4 + assert (estimate.unsupported, estimate.pages) == ((), 4) + assert len(estimated) == len(hancom) + assert [mine for mine, theirs in zip(estimated, hancom) if theirs] == [theirs for theirs in hancom if theirs] @pytest.mark.parametrize(("height", "rest"), [(20000, 13221), (8029, 0), (8061, 0), (8062, 1283), (8079, 1300)])