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 @@ -129,6 +129,9 @@
- 쪽 수 추정이 빼기 부호로 쓴 개체 오프셋(`vertOffset="-1500"`처럼, 한/글이 쓰는 부호 없는 32비트 꼴이 아닌 것)을 한/글처럼
0으로 읽는다. 한/글은 그런 값을 0으로 읽어 개체를 문단(또는 종이) 기준 자리에 그대로 그리고, 저장할 때 0으로 고쳐 쓴다.
전에는 그만큼 위(왼쪽)로 놓인 것으로 읽어 뒤 줄 자리가 한/글과 달랐다.
- 쪽 수 추정이 "다음 문단과 함께"가 이어진 문단들(사슬)을 한/글처럼 놓는다. 사슬 문단이 쪽 끝에서 넘치면 다른 문단처럼
나뉘고 그 앞 사슬은 남는다. 사슬 문단이 통째로 다음 쪽으로 가야 하면(다음 문단 첫 줄이나 표가 들어가지 않으면) 그 앞
사슬 전체가 함께 간다. 사슬 문단의 각주도 자리를 차지한다. 전에는 바로 다음 문단만 보았다.
- 쪽 수 추정이 글자처럼 취급한 그림을 그 효과까지 합친 크기로 놓는다. 빛남은 네 변에 반경만큼, 바깥 그림자는
그림(빛남 포함)을 방향으로 거리만큼 옮기고 반경만큼 넓힌 자리까지 차지해, 그 줄이 그만큼 높아진다. 전에는 효과를
세지 않아 줄과 쪽이 한/글보다 짧게 나왔다. 안쪽 그림자는 자리를 차지하지 않는다. 그림자의 흐림은 한/글처럼 화면
Expand Down
41 changes: 35 additions & 6 deletions src/hwpx/layout/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -3689,7 +3689,7 @@ def _chunk(self, index: int, paras: list[_Para], para: _Para, start: int, remain
if count < remaining:
count = self._keep_rules(para, start, remaining, count)
if count == remaining and para.keep_next and index + 1 < len(paras):
count = self._keep_with_next(para, paras[index + 1], start, remaining, count)
count = self._keep_with_next(para, paras[index + 1:], start, remaining, count)
return count

def _keep_rules(self, para: _Para, start: int, remaining: int, count: int) -> int:
Expand All @@ -3702,11 +3702,40 @@ def _keep_rules(self, para: _Para, start: int, remaining: int, count: int) -> in
return count - 1
return count

def _keep_with_next(self, para: _Para, following: _Para, start: int, remaining: int, count: int) -> int:
after = start + para.span(0, remaining) + para.next + following.prev
need = 2 if following.widow_orphan and following.lines > 1 else 1
if self._fits(after, need, following) < need and start != para.prev:
return 0
def _keep_with_next(self, para: _Para, following: list[_Para], start: int, remaining: int, count: int) -> int:
"""*count*, or 0 when the paragraph set to stay with the next has to go on to the next frame. Its last
line stays with the next paragraph's first line (two under the widow and orphan rule); so does each
paragraph after it set so too (a chain). A paragraph of the chain that reaches the frame's foot
splits there as any other, the chain before it staying; one that has to go on to the next frame
whole takes the whole chain before it along. A paragraph at the frame's top stays."""

if start == para.prev:
return count
saved, carry = list(self.page_notes), self.carry
try:
return self._chain_stays(para, following, start, remaining, count)
finally:
self.page_notes, self.carry = saved, carry

def _chain_stays(self, para: _Para, following: list[_Para], start: int, remaining: int, count: int) -> int:
for line in range(remaining): # the notes of the lines placed take room below the chain
height, many, _ = para.notes.get(line, (0, 0, 0))
self.page_notes = [self.page_notes[0] + height, self.page_notes[1] + many]
after = start + para.span(0, remaining) + para.next
for item in following:
after += item.prev
if not item.keep_next or item.table is not None or item.page_break or item.break_before \
or item is following[-1]:
need = 2 if item.widow_orphan and item.lines > 1 else 1
return count if self._fits(after, need, item) >= need else 0
fit = self._fits(after, item.lines, item)
if fit == item.lines:
after += item.span(0, item.lines) + item.next
for height, many, _ in item.notes.values():
self.page_notes = [self.page_notes[0] + height, self.page_notes[1] + many]
continue
# it splits at the foot, its first lines staying with the paragraph before; or it goes on whole
return count if fit and not item.keep_lines else 0
return count

def _fits(self, start: int, count: int, para: _Para, first: int = 0) -> int:
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
9 changes: 9 additions & 0 deletions tests/test_layout_page_estimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,15 @@
"pages_line_ends_200_above_page_foot": 2, # one ending 200 above it stays
"pages_line_ends_1_above_page_foot": 2, # and one ending 1 above it
"pages_line_ends_100_above_page_foot": 2, # and 100 above it: no room is kept below lines
# Documents of paragraphs, tables, pictures, shapes and footnotes whose paragraphs set to stay with the next
# follow each other (a chain): a paragraph of the chain reaching the page's foot splits there, the chain
# before it staying; one that has to go on to the next page whole (its next paragraph's first line, or a
# table, no longer fits) takes the whole chain before it along, footnotes of the chain taking their room.
"pages_keep_with_next_chain_goes_on": 2,
"pages_keep_with_next_chain_before_a_table": 4,
"pages_keep_with_next_chain_splits_at_the_foot": 2,
"pages_keep_with_next_chain_with_a_footnote": 7,
"pages_keep_with_next_chain_of_several_lines_goes_on": 2,
"pages_keep_keep_with_next": 3, # keep with next
"pages_columns_2_break": 4, # two columns and a column break
# Columns changing inside the section (10 pt lines spaced 160%): three lines in one column, a paragraph
Expand Down
Loading