Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

### 고침

- 쪽 수 추정(실험, `estimate_pages`)이 표 칸 안에 위아래나 어울림으로 둔 그림·도형의 높이를 행 높이에 넣는다. 글 없는 칸
문단에서 문단 위를 기준으로 둔 것(글자처럼 두지 않은 것)이면, 칸이 그 개체의 아래 끝(바깥 여백 포함)까지 온다. 전에는 그
개체를 세지 않아 행을 한 줄 높이로 잡았다.
- 쪽 수 추정(실험, `estimate_pages`)이 병합 칸으로 묶인 행들이 쪽 바닥을 빈 높이 안에서만 넘을 때, 그 행들을 그 쪽 바닥에서
끝낸다. 모든 칸의 글이 바닥 위에 들어가고 남는 높이가 1282 이하면 다음 쪽으로 넘길 것이 없다. 전에는 표 윗 여백만 있는
빈 쪽이 하나 더 생겼다.
Expand Down
31 changes: 30 additions & 1 deletion src/hwpx/layout/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@
up from its paragraph's top stands at that top; the caches of a row Hancom split over a page end
start over at the next page's top, and are read as one run of lines, each line that goes back up
where it would stand in the unsplit cell, a first line below such a table with the room above it,
so the row splits again where it would). A flowing table's rows use
so the row splits again where it would). A picture or drawing placed top and bottom or wrapped
square from a cell paragraph holding no text makes the cell reach its foot (outer margins
included). A flowing table's rows use
the body only down to just above the page's foot (101 above it, or 2 in a table set not to be
adjusted), less the table's bottom outer margin: a row, or a cell line of a row split between its
lines, ending lower goes on to the next page (where the table goes on below its top outer margin;
Expand Down Expand Up @@ -530,9 +532,12 @@ def stack(self, paragraphs: list[Any], width: int, caches: bool) -> tuple[int, i
if cached: # the lines Hancom laid out, each as tall as it drew it
if pending is not None:
height += pending + shape.prev
top = height
height += sum(advance for _, advance in cached[:-1]) + cached[-1][0]
size, pitch = cached[-1]
pending = pitch - size + shape.next
if top + _objects_reach(runs) > height: # an object placed from the paragraph reaches lower
height, pending = top + _objects_reach(runs), shape.next
lines += len(cached)
continue
style = self.style(paragraph.get("paraPrIDRef"), refs, paragraph)
Expand All @@ -541,8 +546,11 @@ def stack(self, paragraphs: list[Any], width: int, caches: bool) -> tuple[int, i
)
if pending is not None:
height += pending + shape.prev
top = height
height += (count - 1) * pitch + size
pending = pitch - size + shape.next
if top + _objects_reach(runs) > height: # an object placed from the paragraph reaches lower
height, pending = top + _objects_reach(runs), shape.next
lines += count
return height, lines, pitch, size

Expand Down Expand Up @@ -1063,6 +1071,27 @@ def _check_section(section: Any) -> None:
raise _Unsupported("section settings (hp:secPr) after the first paragraph")


def _objects_reach(runs: list[Any]) -> int:
"""How far below the top of their paragraph in a cell, holding no text, the pictures and drawings placed
from it reach: top and bottom or square, not set as a character, their outer margins included (the cell
holds them, and its row grows to). Tables in a cell are laid out on their own."""

reach = 0
if _run_text(runs).strip(): # text goes on below such an object: not followed here
return reach
for obj in (child for run in runs for child in run):
name, pos = _local(obj), obj.find(f"{HP}pos")
if name not in _OBJECTS or name == "tbl" or pos is None or obj.find(f"{HP}sz") is None \
or pos.get("treatAsChar") == "1" or obj.get("textWrap") not in ("TOP_AND_BOTTOM", "SQUARE") \
or pos.get("vertRelTo") != "PARA" or pos.get("vertAlign", "TOP") != "TOP":
continue
offset = int(pos.get("vertOffset", 0))
if offset >= 1 << 31: # kept unsigned: one placed up
offset -= 1 << 32
reach = max(reach, offset + _extent(obj, "height"))
return reach


def _placed_objects(runs: list[Any]) -> list[Any]:
"""The objects of the runs."""

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions tests/test_layout_page_estimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@
"pages_table_caption_below_ends_100_above_page_foot": 2, # the last row and the caption below end 100
# above the foot: both go on
"pages_table_caption_below_ends_101_above_page_foot": 2, # 101 above it: they stay
"pages_table_cell_holding_a_drawing_top_and_bottom": 1, # a cell paragraph holding only a rectangle 10000
# tall placed top and bottom from it: the row is
# as tall as it with the cell's margins
"pages_table_as_character_cell_holding_a_drawing_top_and_bottom": 1, # in a table set as a character
"pages_table_cell_holding_a_drawing_500_down": 1, # 500 down from the paragraph's top
"pages_table_cell_holding_a_drawing_wrapped_square": 1, # wrapped square, narrow: the line beside it
"pages_table_cell_holding_a_picture_top_and_bottom": 1, # a picture
"pages_table_cell_holding_a_drawing_after_a_line": 1, # in the cell's second paragraph, after a line


"pages_table_joined_rows_end_at_the_foot": 2, # the last two rows joined by a merged cell reach 300 past the
# foot within the last one's room to spare: they end there,
# the paragraph after the table at the next page's top
Expand Down
Loading