@@ -549,7 +549,25 @@ def __parse_text(self):
549549 self ._text , - 1 , "\000 "
550550 )
551551
552- def divide (self , layout , width , height , dpi_x , dpi_y ):
552+ def divide (
553+ self ,
554+ layout ,
555+ width ,
556+ height ,
557+ dpi_x ,
558+ dpi_y ,
559+ force_split = False ,
560+ allow_overflow = False ,
561+ ):
562+ # bug 6324: 'force_split' (set when moving this paragraph whole to the
563+ # next page would make no progress -- a wrapping cell on the last line of
564+ # a page, or the paginator's no-progress guard) overrides the "keep a
565+ # short cell paragraph together" rule below, so at least its first lines
566+ # render here instead of the cell being dropped. 'allow_overflow' is the
567+ # stronger signal the paginator's no-progress guard adds when even a
568+ # fresh empty page cannot hold the content: only then may a line that
569+ # does not fit be placed here (accepting overflow) rather than moved --
570+ # otherwise pagination would loop forever.
553571 self .__parse_text ()
554572
555573 l_margin = self ._style .get_left_margin () * dpi_x / 2.54
@@ -615,9 +633,22 @@ def divide(self, layout, width, height, dpi_x, dpi_y):
615633
616634 # we need to cut paragraph:
617635
636+ # bug 6324: place this paragraph as-is on the current page, accepting
637+ # overflow. Used only when the paginator's no-progress guard has
638+ # established the page is already as large as it will get (a single line
639+ # taller than a whole page); the alternative is dropping the line or
640+ # looping forever.
641+ def _place_whole ():
642+ para_h = layout_height + spacing + t_margin + (2 * v_padding )
643+ if height - para_h > b_margin :
644+ para_h += b_margin
645+ return (self , None ), para_h
646+
618647 # 1. if paragraph part of a cell, we do not divide if only small part,
619- # of paragraph can be shown, instead move to next page
620- if line_count < 4 and self ._parent ._type == "CELL" :
648+ # of paragraph can be shown, instead move to next page -- UNLESS the
649+ # caller forced a split (bug 6324: the row/page is already as large as it
650+ # gets, so moving whole would drop the cell or loop).
651+ if not force_split and line_count < 4 and self ._parent ._type == "CELL" :
621652 return (None , self ), 0
622653
623654 lineiter = layout .get_iter ()
@@ -627,14 +658,22 @@ def divide(self, layout, width, height, dpi_x, dpi_y):
627658 # 2. if nothing fits, move to next page without split
628659 # there is a spacing above and under the text
629660 if linerange [1 ] - linerange [0 ] + 2.0 * spacing > text_height * Pango .SCALE :
630- return (None , self ), 0
661+ if not force_split :
662+ return (None , self ), 0
663+ # bug 6324: forced, but not even the first line fits here. If it is
664+ # the only line and moving makes no progress (allow_overflow), place
665+ # it here (overflow); otherwise move it to the next page.
666+ if lineiter .at_last_line ():
667+ return _place_whole () if allow_overflow else ((None , self ), 0 )
631668
632669 # 3. split the paragraph
633670 startheight = linerange [0 ]
634671 endheight = linerange [1 ]
635672 splitline = - 1
636673 if lineiter .at_last_line ():
637674 # only one line of text that does not fit
675+ if force_split and allow_overflow :
676+ return _place_whole ()
638677 return (None , self ), 0
639678
640679 while not lineiter .at_last_line ():
@@ -647,6 +686,8 @@ def divide(self, layout, width, height, dpi_x, dpi_y):
647686 break
648687 endheight = linerange [1 ]
649688 if splitline == - 1 :
689+ if force_split and allow_overflow :
690+ return _place_whole ()
650691 print ("CairoDoc STRANGE " )
651692 return (None , self ), 0
652693 # we split at splitline
@@ -843,7 +884,16 @@ class GtkDocTable(GtkDocBaseElement):
843884 _type = "TABLE"
844885 _allowed_children = ["ROW" ]
845886
846- def divide (self , layout , width , height , dpi_x , dpi_y ):
887+ def divide (
888+ self ,
889+ layout ,
890+ width ,
891+ height ,
892+ dpi_x ,
893+ dpi_y ,
894+ force_split = False ,
895+ allow_overflow = False ,
896+ ):
847897 # calculate real table width
848898 table_width = width * self ._style .get_width () / 100
849899
@@ -852,7 +902,33 @@ def divide(self, layout, width, height, dpi_x, dpi_y):
852902 row_index = 0
853903 while row_index < len (self ._children ):
854904 row = self ._children [row_index ]
855- (r1 , r2 ), row_height = row .divide (layout , table_width , height , dpi_x , dpi_y )
905+ # bug 6324: only the FIRST row can legitimately be forced (it is the
906+ # one sitting at the top of an already-full/empty page); later rows
907+ # have committed rows above them and may still be kept together.
908+ (r1 , r2 ), row_height = row .divide (
909+ layout ,
910+ table_width ,
911+ height ,
912+ dpi_x ,
913+ dpi_y ,
914+ force_split and row_index == 0 ,
915+ allow_overflow and row_index == 0 ,
916+ )
917+ if r1 is None :
918+ # bug 6324: the row could place none of its content here and asks
919+ # to move whole to the next page (keep-together). Hand it and
920+ # every following row to a continuation table so the row is not
921+ # duplicated across the break. If rows above it already fit that
922+ # is real progress; if NOTHING fits, return the continuation only
923+ # (first half None) so the paginator moves it to a fresh page --
924+ # where, if it still does not fit, allow_overflow guarantees it is
925+ # placed rather than looping.
926+ new_table = GtkDocTable (self ._style )
927+ list (map (new_table .add_child , self ._children [row_index :]))
928+ del self ._children [row_index :]
929+ if not self ._children :
930+ return (None , new_table ), 0
931+ return (self , new_table ), table_height
856932 if r2 is not None :
857933 # break the table in two parts
858934 break
@@ -900,10 +976,20 @@ class GtkDocTableRow(GtkDocBaseElement):
900976 _type = "ROW"
901977 _allowed_children = ["CELL" ]
902978
903- def divide (self , layout , width , height , dpi_x , dpi_y ):
979+ def divide (
980+ self ,
981+ layout ,
982+ width ,
983+ height ,
984+ dpi_x ,
985+ dpi_y ,
986+ force_split = False ,
987+ allow_overflow = False ,
988+ ):
904989 # the highest cell gives the height of the row
905990 cell_heights = []
906991 dividedrow = False
992+ cell_split = False
907993 cell_width_iter = self ._style .__iter__ ()
908994 new_row = GtkDocTableRow (self ._style )
909995 for cell in self ._children :
@@ -914,12 +1000,41 @@ def divide(self, layout, width, height, dpi_x, dpi_y):
9141000 (c1 , c2 ), cell_height = cell .divide (
9151001 layout , cell_width , height , dpi_x , dpi_y
9161002 )
1003+ if c1 is None and not force_split and not cell_split :
1004+ # bug 6324: this cell can place none of its content in the space
1005+ # left, no earlier cell in the row has committed content yet, and
1006+ # we are allowed to move the whole row to the next page (where it
1007+ # gets a full page of room). Keep the row together and move it
1008+ # whole rather than tearing this cell -- leaving it blank here
1009+ # while its text lands on a later page (the reported defect).
1010+ return (None , self ), 0
1011+ if c1 is None :
1012+ # bug 6324: either an earlier cell already split across the page
1013+ # boundary (cell_split -- so the row spans the break and cannot
1014+ # move whole), or the paginator forced the split (force_split --
1015+ # the page is already as large as it will get). Force this cell
1016+ # to split too so its first lines render here beside its rowmates
1017+ # instead of a blank cell. Overflow of an UNSPLITTABLE cell (an
1018+ # image taller than the room left) is permitted only under
1019+ # allow_overflow -- the paginator's genuine no-progress signal --
1020+ # so a merely-torn row lets such a cell move to the next page
1021+ # intact rather than clipping it here.
1022+ (c1 , c2 ), cell_height = cell .divide (
1023+ layout ,
1024+ cell_width ,
1025+ height ,
1026+ dpi_x ,
1027+ dpi_y ,
1028+ force_split = True ,
1029+ allow_overflow = allow_overflow ,
1030+ )
9171031 cell_heights .append (cell_height )
9181032 if c2 is None :
9191033 emptycell = GtkDocTableCell (c1 ._style , c1 .get_span ())
9201034 new_row .add_child (emptycell )
9211035 else :
9221036 dividedrow = True
1037+ cell_split = True
9231038 new_row .add_child (c2 )
9241039
9251040 # save height [inch] of the row to be able to draw exact cell border
@@ -976,7 +1091,16 @@ def __init__(self, style, span=1):
9761091 def get_span (self ):
9771092 return self ._span
9781093
979- def divide (self , layout , width , height , dpi_x , dpi_y ):
1094+ def divide (
1095+ self ,
1096+ layout ,
1097+ width ,
1098+ height ,
1099+ dpi_x ,
1100+ dpi_y ,
1101+ force_split = False ,
1102+ allow_overflow = False ,
1103+ ):
9801104 h_padding = self ._style .get_padding () * dpi_x / 2.54
9811105 v_padding = self ._style .get_padding () * dpi_y / 2.54
9821106
@@ -993,8 +1117,28 @@ def divide(self, layout, width, height, dpi_x, dpi_y):
9931117 for child in self ._children :
9941118 if new_cell is None :
9951119 (e1 , e2 ), child_height = child .divide (
996- layout , width , available_height , dpi_x , dpi_y
1120+ layout ,
1121+ width ,
1122+ available_height ,
1123+ dpi_x ,
1124+ dpi_y ,
1125+ force_split ,
1126+ allow_overflow ,
9971127 )
1128+ # bug 6324: the cell's first child could place none of its
1129+ # content in the room left (a short paragraph hitting the
1130+ # keep-together rule). When we were NOT forced, report that by
1131+ # returning the cell INTACT (None, self) so the caller
1132+ # (GtkDocTableRow.divide) can move the whole row or force a
1133+ # split -- do not fall through to the truncation below, which
1134+ # empties the cell and leaves it blank while its content is
1135+ # carried away. When we WERE forced, fall through: a splittable
1136+ # child has split (e1 set) and an unsplittable one that still
1137+ # will not fit (e1 None, e2 the child) is carried to a
1138+ # continuation cell here -- blank on this page, intact on the
1139+ # next -- rather than dropped.
1140+ if e1 is None and e2 is not None and childnr == 0 and not force_split :
1141+ return (None , self ), 0
9981142 cell_height += child_height
9991143 available_height -= child_height
10001144 if e2 is not None :
@@ -1084,16 +1228,32 @@ def __init__(self, style, filename, width, height, crop=None):
10841228 self ._height = height
10851229 self ._crop = crop
10861230
1087- def divide (self , layout , width , height , dpi_x , dpi_y ):
1231+ def divide (
1232+ self ,
1233+ layout ,
1234+ width ,
1235+ height ,
1236+ dpi_x ,
1237+ dpi_y ,
1238+ force_split = False ,
1239+ allow_overflow = False ,
1240+ ):
10881241 img_width = self ._width * dpi_x / 2.54
10891242 img_height = self ._height * dpi_y / 2.54
10901243
10911244 # image can't be divided, a new page must begin
10921245 # if it can't fit on the current one
10931246 if img_height <= height :
10941247 return (self , None ), img_height
1095- else :
1096- return (None , self ), 0
1248+ # bug 6324: an image can never be split. Under allow_overflow the
1249+ # paginator has established the page is already as large as it will get
1250+ # (an image taller than a whole page -- moving again would loop forever),
1251+ # so place it here accepting overflow. A merely-forced split (force_split
1252+ # without allow_overflow, e.g. a torn row whose sibling cell split) must
1253+ # NOT clip a fitting image here -- it moves to the next page intact.
1254+ if allow_overflow :
1255+ return (self , None ), img_height
1256+ return (None , self ), 0
10971257
10981258 def draw (self , cr , layout , width , dpi_x , dpi_y ):
10991259 from gi .repository import Gtk , Gdk
@@ -1150,7 +1310,16 @@ class GtkDocFrame(GtkDocBaseElement):
11501310 _type = "FRAME"
11511311 _allowed_children = ["LINE" , "POLYGON" , "BOX" , "TEXT" ]
11521312
1153- def divide (self , layout , width , height , dpi_x , dpi_y ):
1313+ def divide (
1314+ self ,
1315+ layout ,
1316+ width ,
1317+ height ,
1318+ dpi_x ,
1319+ dpi_y ,
1320+ force_split = False ,
1321+ allow_overflow = False ,
1322+ ):
11541323 frame_width = round (self ._style .width * dpi_x / 2.54 )
11551324 frame_height = round (self ._style .height * dpi_y / 2.54 )
11561325 t_margin = self ._style .spacing [2 ] * dpi_y / 2.54
@@ -1162,6 +1331,12 @@ def divide(self, layout, width, height, dpi_x, dpi_y):
11621331 return (self , None ), frame_height + t_margin + b_margin
11631332 elif frame_height + t_margin <= height :
11641333 return (self , None ), height
1334+ # bug 6324: a frame taller than a whole page cannot be split. Under
1335+ # allow_overflow the paginator has established the page is already as
1336+ # large as it will get, so place it here (overflow) rather than loop
1337+ # forever; a merely-forced split moves it to the next page intact.
1338+ elif allow_overflow :
1339+ return (self , None ), height
11651340 else :
11661341 return (None , self ), 0
11671342
@@ -1796,10 +1971,34 @@ def paginate(self, layout, page_width, page_height, dpi_x, dpi_y):
17961971 # this is a self._doc where nothing has been added. Empty page.
17971972 return True
17981973 elem = self ._elements_to_paginate .pop (0 )
1974+ # bug 6324: is the current page still empty? (an empty page always has
1975+ # the full page_height available). Captured BEFORE dividing so the
1976+ # no-progress guard below can tell "nothing fit on a fresh page" (a loop)
1977+ # from "nothing fit in the room left below other content" (normal).
1978+ page_is_empty = len (self ._pages [len (self ._pages ) - 1 ].get_children ()) == 0
17991979 (e1 , e2 ), e1_h = elem .divide (
18001980 layout , page_width , self ._available_height , dpi_x , dpi_y
18011981 )
18021982
1983+ # bug 6324: the element placed nothing (e1 is None) yet asked to be
1984+ # carried to the next page (e2) -- and the current page is ALREADY empty.
1985+ # Moving it to yet another empty page makes no progress, so
1986+ # paginate_document's `while not paginate()` loop would spin forever.
1987+ # Re-divide the CONTINUATION (e2, which holds the content -- a table hands
1988+ # back its rows there and empties itself when nothing fits) forcing the
1989+ # split AND allowing overflow of anything unsplittable, so pagination
1990+ # places what it can here and always advances.
1991+ if e1 is None and e2 is not None and page_is_empty :
1992+ (e1 , e2 ), e1_h = e2 .divide (
1993+ layout ,
1994+ page_width ,
1995+ self ._available_height ,
1996+ dpi_x ,
1997+ dpi_y ,
1998+ force_split = True ,
1999+ allow_overflow = True ,
2000+ )
2001+
18032002 # if (part of) it fits on current page add it
18042003 if e1 is not None :
18052004 self ._pages [len (self ._pages ) - 1 ].add_child (e1 )
0 commit comments