diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index d196a48b1..389e2bb61 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -2781,7 +2781,6 @@ def cell( max_width=w, trailing_nl=False, ), - w, h, border, new_x=new_x, @@ -2794,7 +2793,6 @@ def cell( def _render_styled_text_line( self, text_line: TextLine, - w: float = None, h: float = None, border: Union[str, int] = 0, new_x: XPos = XPos.RIGHT, @@ -2817,8 +2815,6 @@ def _render_styled_text_line( Args: text_line (TextLine instance): Contains the (possibly empty) tuple of fragments to render. - w (float): Cell width. Default value: None, meaning to fit text width. - If 0, the cell extends up to the right margin. h (float): Cell height. Default value: None, meaning an height equal to the current font size. border: Indicates if borders must be drawn around the cell. @@ -2847,11 +2843,11 @@ def _render_styled_text_line( if padding is None: padding = Padding(0, 0, 0, 0) - - if padding.left == 0 and padding.right == 0: - horizontal_margin = self.c_margin - else: - horizontal_margin = 0 + l_c_margin = r_c_margin = 0 + if padding.left == 0: + l_c_margin = self.c_margin + if padding.right == 0: + r_c_margin = self.c_margin styled_txt_width = text_line.text_width if not styled_txt_width: @@ -2859,13 +2855,18 @@ def _render_styled_text_line( unscaled_width = frag.get_width(initial_cs=i != 0) styled_txt_width += unscaled_width - w = text_line.max_width + if w is None: + if not text_line.fragments: + raise ValueError( + "'text_line' must have fragments if 'text_line.text_width' is None" + ) + w = styled_txt_width + l_c_margin + r_c_margin + elif w == 0: + w = self.w - self.r_margin - self.x if center: - self.x = ( - self.w / 2 if align == Align.X else self.l_margin + (self.epw - w) / 2 - ) - if align == Align.X: + self.x = self.l_margin + (self.epw - w) / 2 + elif text_line.align == Align.X: self.x -= w / 2 max_font_size = 0 # how much height we need to accomodate. @@ -2922,16 +2923,16 @@ def _render_styled_text_line( last_used_color = self.fill_color if text_line.fragments: if text_line.align == Align.R: - dx = w - horizontal_margin - styled_txt_width + dx = w - l_c_margin - styled_txt_width elif text_line.align in [Align.C, Align.X]: dx = (w - styled_txt_width) / 2 else: - dx = horizontal_margin + dx = l_c_margin s_start += dx word_spacing = 0 if text_line.align == Align.J and text_line.number_of_spaces: word_spacing = ( - w - horizontal_margin - horizontal_margin - styled_txt_width + w - l_c_margin - r_c_margin - styled_txt_width ) / text_line.number_of_spaces sl.append( f"BT {(self.x + dx) * k:.2f} " @@ -3065,7 +3066,7 @@ def _render_styled_text_line( self.x = s_start + s_width elif new_x == XPos.WCONT: if s_width: - self.x = s_start + s_width - horizontal_margin + self.x = s_start + s_width - r_c_margin else: self.x = s_start elif new_x == XPos.CENTER: @@ -3392,10 +3393,11 @@ def multi_cell( center (bool): center the cell horizontally on the page. padding (float or Sequence): padding to apply around the text. Default value: 0. When one value is specified, it applies the same padding to all four sides. - When two values are specified, the first padding applies to the top and bottom, the second to the left and right. - When three values are specified, the first padding applies to the top, the second to the right and left, the third to the bottom. - When four values are specified, the paddings apply to the top, right, bottom, and left in that order (clockwise) - If padding for left and right ends up being non-zero then c_margin is ignored. + When two values are specified, the first padding applies to the top and bottom, the second to + the left and right. When three values are specified, the first padding applies to the top, + the second to the right and left, the third to the bottom. When four values are specified, + the paddings apply to the top, right, bottom, and left in that order (clockwise) + If padding for left or right ends up being non-zero then respective c_margin is ignored. Center overrides values for horizontal padding @@ -3493,8 +3495,13 @@ def multi_cell( # Apply padding to contents # decrease maximum allowed width by padding # shift the starting point by padding - w = w - padding.right - padding.left - maximum_allowed_width = w - 2 * self.c_margin + maximum_allowed_width = w = w - padding.right - padding.left + clearance_margins = [] + # If we don't have padding on either side, we need a clearance margin. + if not padding.left: + clearance_margins.append(self.c_margin) + if not padding.right: + clearance_margins.append(self.c_margin) self.x += padding.left self.y += padding.top @@ -3522,6 +3529,7 @@ def multi_cell( multi_line_break = MultiLineBreak( styled_text_fragments, maximum_allowed_width, + clearance_margins, align=align, print_sh=print_sh, wrapmode=wrapmode, @@ -3561,7 +3569,6 @@ def multi_cell( has_line_after = not is_last_line or should_render_bottom_blank_cell new_page = self._render_styled_text_line( text_line, - w, h=current_cell_height, border="".join( ( @@ -3593,7 +3600,6 @@ def multi_cell( max_width=w, trailing_nl=False, ), - w, h=h, border="".join( ( @@ -3696,16 +3702,17 @@ def write( multi_line_break = MultiLineBreak( styled_text_fragments, lambda h: max_width, + (self.c_margin, self.c_margin), print_sh=print_sh, wrapmode=wrapmode, ) # first line from current x position to right margin first_width = self.w - self.x - self.r_margin - max_width = first_width - 2 * self.c_margin + max_width = first_width text_line = multi_line_break.get_line() # remaining lines fill between margins full_width = self.w - self.l_margin - self.r_margin - max_width = full_width - 2 * self.c_margin + max_width = full_width while (text_line) is not None: text_lines.append(text_line) text_line = multi_line_break.get_line() @@ -3713,14 +3720,10 @@ def write( return False for text_line_index, text_line in enumerate(text_lines): - if text_line_index == 0: - line_width = first_width - else: - line_width = full_width + if text_line_index > 0: self.ln() new_page = self._render_styled_text_line( text_line, - line_width, h=h, border=0, new_x=XPos.WCONT, @@ -4196,11 +4199,18 @@ def ln(self, h=None): the amount passed as parameter. Args: - h (float): The height of the break. - By default, the value equals the height of the last printed cell. + h (float, optional): The height of the break. + By default, the value equals the height of the last printed cell, or absent that + the height of the current font. + If no 'h' is given, nothing has been written yet, and no font size is set, nothing happens. """ self.x = self.l_margin - self.y += self._lasth if h is None else h + if h: + self.y += h + elif self._lasth: + self.y += self._lasth + # elif self.font_size: + # self.y += self.font_size def get_x(self): """Returns the abscissa of the current position.""" @@ -4846,31 +4856,33 @@ def table(self, *args, **kwargs): Detailed usage documentation: https://py-pdf.github.io/fpdf2/Tables.html Args: - rows: optional. Sequence of rows (iterable) of str to initiate the table cells with text content - align (str, fpdf.enums.Align): optional, default to CENTER. Sets the table horizontal position relative to the page, - when it's not using the full page width - borders_layout (str, fpdf.enums.TableBordersLayout): optional, default to ALL. Control what cell borders are drawn + rows: optional. Sequence of rows (iterable) of str to initiate the table cells with text content. + align (str, fpdf.enums.Align): optional, default to CENTER. Sets the table horizontal position + relative to the page, when it's not using the full page width. + borders_layout (str, fpdf.enums.TableBordersLayout): optional, default to ALL. Control what cell + borders are drawn. cell_fill_color (int, tuple, fpdf.drawing.DeviceGray, fpdf.drawing.DeviceRGB): optional. - Defines the cells background color - cell_fill_mode (str, fpdf.enums.TableCellFillMode): optional. Defines which cells are filled with color in the background - col_widths (int, tuple): optional. Sets column width. Can be a single number or a sequence of numbers + Defines the cells background color. + cell_fill_mode (str, fpdf.enums.TableCellFillMode): optional. Defines which cells are filled + with color in the background. + col_widths (int, tuple): optional. Sets column width. Can be a single number or a sequence of numbers. first_row_as_headings (bool): optional, default to True. If False, the first row of the table - is not styled differently from the others - gutter_height (float): optional vertical space between rows - gutter_width (float): optional horizontal space between columns + is not styled differently from the others. + gutter_height (float): optional vertical space between rows. + gutter_width (float): optional horizontal space between columns. headings_style (fpdf.fonts.FontFace): optional, default to bold. Defines the visual style of the top headings row: size, color, emphasis... - line_height (number): optional. Defines how much vertical space a line of text will occupy - markdown (bool): optional, default to False. Enable markdown interpretation of cells textual content + line_height (number): optional. Defines how much vertical space a line of text will occupy. + markdown (bool): optional, default to False. Enable markdown interpretation of cells textual content. text_align (str, fpdf.enums.Align): optional, default to JUSTIFY. Control text alignment inside cells. - width (number): optional. Sets the table width + width (number): optional. Sets the table width. wrapmode (fpdf.enums.WrapMode): "WORD" for word based line wrapping (default), "CHAR" for character based line wrapping. padding (number, tuple, Padding): optional. Sets the cell padding. Can be a single number or a sequence of numbers, default:0 - If padding for left and right ends up being non-zero then c_margin is ignored. - outer_border_width (number): optional. The outer_border_width will trigger rendering of the outer border of - the table with the given width regardless of any other defined border styles. + If padding for left or right ends up being non-zero then the respective c_margin is ignored. + outer_border_width (number): optional. The outer_border_width will trigger rendering of the outer + border of the table with the given width regardless of any other defined border styles. """ table = Table(self, *args, **kwargs) yield table diff --git a/fpdf/html.py b/fpdf/html.py index 9129c920f..252be1044 100644 --- a/fpdf/html.py +++ b/fpdf/html.py @@ -25,7 +25,8 @@ # The pattern excludes the non-breaking spaces that are included in "\s". # We also exclude the OGHAM SPACE MARK for now, because while being a word seperator, # it is usually a graphically visible glyph. -_WS_CHARS = "".join(( +_WS_CHARS = "".join( + ( # "\u0009", # CHARACTER TABULATION # "\u000a", # LINE FEED # "\u000b", # LINE TABULATION @@ -53,7 +54,8 @@ # "\u202f", # NARROW NO-BREAK SPACE (keep) "\u205f", # MEDIUM MATHEMATICAL SPACE "\u3000", # IDEOGRAPHIC SPACE - )) + ) +) _WS_SUB_PAT = re.compile(f"[{_WS_CHARS}]+") COLOR_DICT = { @@ -285,8 +287,11 @@ def __init__( self.pdf._push_local_stack() # xpylint: disable=protected-access self._pre_formatted = False # preserve whitespace while True. - self._pre_started = False # nothing written yet to
, remove one initial nl.
+        self._pre_started = (
+            False  # nothing written yet to 
, remove one initial nl.
+        )
         self.follows_trailing_space = False  # The last write has ended with a space.
+        self.follows_heading = False  # We don't want extra space below a heading.
         self.href = ""
         self.align = ""
         self.font_stack = []
@@ -295,7 +300,7 @@ def __init__(
         self.font_color = tuple((255 * v for v in pdf.text_color.colors))
         self.heading_level = None
         self.heading_above = 0.2  # extra space above heading, relative to font size
-        self.heading_below = 0.2  # extra space below heading, relative to font size
+        self.heading_below = 0.4  # extra space below heading, relative to font size
         self._tags_stack = []
         self._column = self.pdf.text_column(skip_leading_spaces=True)
         self._paragraph = self._column.paragraph()
@@ -307,25 +312,30 @@ def __init__(
         self.td_th = None  # becomes a dict of attributes when processing / tags
         # "inserted" is a special attribute indicating that a cell has be inserted in self.table_row
 
-    def _new_paragraph(self, align=None, line_height=1.0, top_margin=0, bottom_margin=0):
+    def _new_paragraph(
+        self, align=None, line_height=1.0, top_margin=0, bottom_margin=0
+    ):
         self._end_paragraph()
         self.align = align or ""
-        if not top_margin:
+        if not top_margin and not self.follows_heading:
             top_margin = self.font_size / self.pdf.k
         self._paragraph = self._column.paragraph(
-                align=align,
-                line_height=line_height,
-                skip_leading_spaces=True,
-                top_margin=top_margin,
-                bottom_margin=bottom_margin,
-                )
+            align=align,
+            line_height=line_height,
+            skip_leading_spaces=True,
+            top_margin=top_margin,
+            bottom_margin=bottom_margin,
+        )
         self.follows_trailing_space = True
+        self.follows_heading = False
 
     def _end_paragraph(self):
         self.align = ""
         if self._paragraph:
             self._column.end_paragraph()
-            our_context = self.pdf._pop_local_stack()  # pylint: disable=protected-access
+            our_context = (
+                self.pdf._pop_local_stack()  # pylint: disable=protected-access
+            )
             self._column.render()
             self.pdf._push_local_stack(our_context)  # pylint: disable=protected-access
             self._paragraph = None
@@ -381,7 +391,7 @@ def handle_data(self, data):
         elif self.table is not None:
             # ignore anything else than td inside a table
             pass
-        elif self._pre_formatted: # pre blocks
+        elif self._pre_formatted:  # pre blocks
             s_nl = data.startswith("\n") and self._pre_started
             self._pre_started = False
             e_nl = data.endswith("\n")
@@ -389,7 +399,7 @@ def handle_data(self, data):
                 data = data[1:-1]
             elif s_nl:
                 data = data[1:]
-            #elif e_nl:
+            # elif e_nl:
             #    data = data[:-1]
             self._write_data(data)
         else:
@@ -410,6 +420,7 @@ def _write_data(self, data):
             self._write_paragraph(data)
 
     def handle_starttag(self, tag, attrs):
+        self._pre_started = False
         attrs = dict(attrs)
         LOGGER.debug("STARTTAG %s %s", tag, attrs)
         self._tags_stack.append(tag)
@@ -417,7 +428,7 @@ def handle_starttag(self, tag, attrs):
             self._write_paragraph("\n")
             tag = "b"
         if tag == "dd":
-            self._write_paragraph("\n"+"\u00a0" * self.dd_tag_indent)
+            self._write_paragraph("\n" + "\u00a0" * self.dd_tag_indent)
         if tag == "strong":
             tag = "b"
         if tag == "em":
@@ -448,6 +459,7 @@ def handle_starttag(self, tag, attrs):
                 line_height = None
             self._new_paragraph(align=align, line_height=line_height)
         if tag in self.heading_sizes:
+            prev_font_height = self.font_size / self.pdf.k
             self.font_stack.append((self.font_face, self.font_size, self.font_color))
             self.heading_level = int(tag[1:])
             hsize_pt = self.heading_sizes[tag]
@@ -459,10 +471,10 @@ def handle_starttag(self, tag, attrs):
             else:
                 align = None
             self._new_paragraph(
-                    align=align,
-                    top_margin=hsize + self.heading_above * hsize,
-                    bottom_margin=self.heading_below * hsize,
-                    )
+                align=align,
+                top_margin=prev_font_height + self.heading_above * hsize,
+                bottom_margin=self.heading_below * hsize,
+            )
             color = (
                 color_as_decimal(attrs["color"]) if "color" in attrs else (150, 0, 0)
             )
@@ -473,10 +485,10 @@ def handle_starttag(self, tag, attrs):
             self.pdf.add_page(same=True)
         if tag == "code":
             self.font_stack.append((self.font_face, self.font_size, self.font_color))
-            self.set_font(self.pre_code_font, 11)
+            self.set_font(self.pre_code_font, self.font_size)
         if tag == "pre":
             self.font_stack.append((self.font_face, self.font_size, self.font_color))
-            self.set_font(self.pre_code_font, 11)
+            self.set_font(self.pre_code_font, self.font_size)
             self._pre_formatted = True
             self._new_paragraph()
             self._pre_started = True
@@ -499,7 +511,7 @@ def handle_starttag(self, tag, attrs):
                 bullet += 1
                 self.bullet[self.indent - 1] = bullet
                 bullet = f"{bullet}. "
-            indent = '\u00a0' * self.li_tag_indent * self.indent
+            indent = "\u00a0" * self.li_tag_indent * self.indent
             self._write_paragraph(f"{indent}{bullet} ")
             self.set_text_color(*self.font_color)
         if tag == "font":
@@ -654,6 +666,7 @@ def handle_endtag(self, tag):
             self.set_font(face, size)
             self.set_text_color(*color)
             self._end_paragraph()
+            self.follows_heading = True  # We don't want extra space below a heading.
         if tag == "code":
             face, size, color = self.font_stack.pop()
             self.set_font(face, size)
@@ -734,7 +747,7 @@ def set_font(self, face=None, size=None, set_default=False):
         style = "".join(s for s in ("b", "i", "u") if self.style.get(s)).upper()
         LOGGER.debug(f"set_font: %s style=%s h={self.h:.2f}", self.font_face, style)
         prev_page = self.pdf.page
-        if not set_default: # make sure there's at least one font defined in the PDF.
+        if not set_default:  # make sure there's at least one font defined in the PDF.
             self.pdf.page = 0
         if (self.font_face, style) != (self.pdf.font_family, self.pdf.font_style):
             self.pdf.set_font(self.font_face, style, self.font_size)
diff --git a/fpdf/line_break.py b/fpdf/line_break.py
index 5e0748a04..e7188537e 100644
--- a/fpdf/line_break.py
+++ b/fpdf/line_break.py
@@ -502,6 +502,7 @@ def __init__(
         self,
         fragments: Sequence,
         max_width: Union[float, callable],
+        margins: Sequence,
         align: Align = Align.L,
         print_sh: bool = False,
         wrapmode: WrapMode = WrapMode.WORD,
@@ -518,10 +519,16 @@ def __init__(
                 applicable width for the line with the given height at the current
                 vertical position. The height is relevant in those cases where the
                 lateral boundaries of the enclosing TextRegion() are not vertical.
+            margins (sequence of floats): The extra clearance (usually FPDF.c_margin)
+                that may apply at the beginning and/or end of a line.
             align (Align): The horizontal alignment of the current text block.
             print_sh (bool): If True, a soft-hyphen will be rendered
                 normally, instead of triggering a line break. Default: False
             wrapmode (WrapMode): Selects word or character based wrapping.
+            line_height (float, optional): A multiplier relative to the font
+                size changing the vertical space occupied by a line of text. Default 1.0.
+            skip_leading_spaces (bool, optional): On each line, any space characters
+                at the beginning will be skipped. Default value: False.
         """
 
         self.fragments = fragments
@@ -529,6 +536,7 @@ def __init__(
             self.get_width = max_width
         else:
             self.get_width = lambda height: max_width
+        self.margins = margins
         self.align = align
         self.print_sh = print_sh
         self.wrapmode = wrapmode
@@ -550,17 +558,25 @@ def get_line(self):
         current_font_height = 0
 
         max_width = self.get_width(current_font_height)
+        # The full max width will be passed on via TextLine to FPDF._render_styled_text_line().
         current_line = CurrentLine(max_width=max_width, print_sh=self.print_sh)
+        # For line wrapping we need to use the reduced width.
+        for margin in self.margins:
+            max_width -= margin
 
         if self.skip_leading_spaces:
             # write_html() with TextColumns uses this, since it can't know in
             # advance where the lines will be broken.
             while self.fragment_index < len(self.fragments):
-                if self.character_index >= len(self.fragments[self.fragment_index].characters):
+                if self.character_index >= len(
+                    self.fragments[self.fragment_index].characters
+                ):
                     self.character_index = 0
                     self.fragment_index += 1
                     continue
-                character = self.fragments[self.fragment_index].characters[self.character_index]
+                character = self.fragments[self.fragment_index].characters[
+                    self.character_index
+                ]
                 if character == SPACE:
                     self.character_index += 1
                 else:
@@ -572,6 +588,9 @@ def get_line(self):
             if current_fragment.font_size > current_font_height:
                 current_font_height = current_fragment.font_size  # document units
                 max_width = self.get_width(current_font_height)
+                current_line.max_width = max_width
+                for margin in self.margins:
+                    max_width -= margin
 
             if self.character_index >= len(current_fragment.characters):
                 self.character_index = 0
diff --git a/fpdf/text_region.py b/fpdf/text_region.py
index 649c256fd..df37df00c 100644
--- a/fpdf/text_region.py
+++ b/fpdf/text_region.py
@@ -1,5 +1,5 @@
 import math
-from typing import NamedTuple, Any, Optional, Union, Sequence
+from typing import NamedTuple, Sequence
 
 from .errors import FPDFException
 from .enums import Align, XPos, YPos
@@ -28,15 +28,14 @@ def clear_text_region(self):
 
 class Paragraph:
     def __init__(
-            self,
-            region,
-            align=None,
-            line_height=None,
-            top_margin: float = 0,
-            bottom_margin: float = 0,
-            skip_leading_spaces: bool = False,
-            ):
-        print("New Paragraph")
+        self,
+        region,
+        align=None,
+        line_height=None,
+        top_margin: float = 0,
+        bottom_margin: float = 0,
+        skip_leading_spaces: bool = False,
+    ):
         self.region = region
         self.pdf = region.pdf
         if align:
@@ -57,14 +56,15 @@ def __enter__(self):
     def __exit__(self, exc_type, exc_value, traceback):
         self.region.end_paragraph()
 
-    def write(self, text: str, link=None):  # pylint: disable=unused-argument
+    def write(self, text: str, link=None):
         if not self.pdf.font_family:
             raise FPDFException("No font set, you need to call set_font() beforehand")
         normalized_string = self.pdf.normalize_text(text).replace("\r", "")
         # YYY _preload_font_styles() should accept a "link" argument.
         fragments = self.pdf._preload_font_styles(normalized_string, False)
-        for frag in fragments:
-            print("write:", frag.font.fontkey, f'"{text}"')
+        if link:
+            for frag in fragments:
+                frag.link = link
         self._text_fragments.extend(fragments)
 
     def ln(self, h=None):
@@ -81,11 +81,13 @@ def build_lines(self, print_sh):
         multi_line_break = MultiLineBreak(
             self._text_fragments,
             max_width=self.region.get_width,
+            margins=(self.pdf.c_margin, self.pdf.c_margin),
             align=self.align or self.region.align or Align.L,
             print_sh=print_sh,
             # wrapmode=self.wrapmode,
             line_height=self.line_height,
-            skip_leading_spaces=self.skip_leading_spaces or self.region.skip_leading_spaces,
+            skip_leading_spaces=self.skip_leading_spaces
+            or self.region.skip_leading_spaces,
         )
         self._text_fragments = []
         text_line = multi_line_break.get_line()
@@ -147,7 +149,11 @@ def _check_paragraph(self):
                 "Conflicts with active paragraph. Either close the current paragraph or write your text inside it."
             )
         if self._active_paragraph is None:
-            p = Paragraph(region=self, align=self.align, skip_leading_spaces=self.skip_leading_spaces)
+            p = Paragraph(
+                region=self,
+                align=self.align,
+                skip_leading_spaces=self.skip_leading_spaces,
+            )
             self._paragraphs.append(p)
             self._active_paragraph = "AUTO"
 
@@ -160,32 +166,31 @@ def ln(self, h=None):
         self._paragraphs[-1].ln(h)
 
     def paragraph(
-            self,
-            align=None,
-            line_height=None,
-            skip_leading_spaces: bool = False,
-            top_margin=0,
-            bottom_margin=0,
-            ):
+        self,
+        align=None,
+        line_height=None,
+        skip_leading_spaces: bool = False,
+        top_margin=0,
+        bottom_margin=0,
+    ):
         if self._active_paragraph == "EXPLICIT":
             raise FPDFException("Unable to nest paragraphs.")
         p = Paragraph(
-                region=self,
-                align=align or self.align,
-                line_height=line_height,
-                skip_leading_spaces=skip_leading_spaces or self.skip_leading_spaces,
-                top_margin=top_margin,
-                bottom_margin=bottom_margin,
-               )
+            region=self,
+            align=align or self.align,
+            line_height=line_height,
+            skip_leading_spaces=skip_leading_spaces or self.skip_leading_spaces,
+            top_margin=top_margin,
+            bottom_margin=bottom_margin,
+        )
         self._paragraphs.append(p)
         self._active_paragraph = "EXPLICIT"
         return p
 
     def end_paragraph(self):
-        print("Ending Paragraph")
         if not self._active_paragraph:
             raise FPDFException("No active paragraph to end.")
-        #self._paragraphs[-1].write("\n")
+        # self._paragraphs[-1].write("\n")
         self._active_paragraph = None
 
 
@@ -212,32 +217,31 @@ def _render_column_lines(
         rendered_lines = 0
         for tl_wrapper in text_lines:
             text_line = tl_wrapper.line
-#            print("Top-Margin:", tl_wrapper.paragraph.top_margin, tl_wrapper.first_line,
-#                    list(frag.string for frag in text_line.fragments))
             text_rendered = False
-            for i, frag in enumerate(text_line.fragments):
-                print("render Fragment:", frag.font.fontkey, i, f'"{frag.string}"')
+            for frag in text_line.fragments:
                 if frag.characters:
                     text_rendered = True
                     break
-            print(f"Tr:{text_rendered} fl:{tl_wrapper.first_line} tm:{tl_wrapper.paragraph.top_margin}")
-            if (text_rendered and tl_wrapper.first_line
-                    and tl_wrapper.paragraph.top_margin
-                    #and self.pdf.y > self.pdf.t_margin
-                    ):
-                print(f"top-margin moving y by {tl_wrapper.paragraph.top_margin}")
+            if (
+                text_rendered
+                and tl_wrapper.first_line
+                and tl_wrapper.paragraph.top_margin
+                and self.pdf.y > self.pdf.t_margin
+            ):
                 self.pdf.y += tl_wrapper.paragraph.top_margin
-            if self.pdf.y + text_line.height > bottom:
-                last_line_height = prev_line_height
-                break
+            else:
+                if self.pdf.y + text_line.height > bottom:
+                    last_line_height = prev_line_height
+                    break
             prev_line_height = last_line_height
             last_line_height = text_line.height
-            extents = self.current_x_extents(self.pdf.y, 0)
-            self.pdf.x = extents[0]
+            col_left, col_right = self.current_x_extents(self.pdf.y, 0)
+            # self.pdf.x = extents[0]
+            if self.pdf.x < col_left or self.pdf.x >= col_right:
+                self.pdf.x = col_left
             # Don't check the return, we never render past the bottom here.
             self.pdf._render_styled_text_line(
                 text_line,
-                w=text_line.max_width + 2 * self.pdf.c_margin,
                 h=text_line.height,
                 border=0,
                 new_x=XPos.LEFT,
@@ -247,8 +251,7 @@ def _render_column_lines(
             )
             if tl_wrapper.last_line:
                 margin = tl_wrapper.paragraph.bottom_margin
-                if (text_rendered and (self.pdf.y + margin) < bottom):
-                    print(f"bottom-margin moving y by {margin}")
+                if margin and text_rendered and (self.pdf.y + margin) < bottom:
                     self.pdf.y += tl_wrapper.paragraph.bottom_margin
             rendered_lines += 1
         if rendered_lines:
@@ -276,7 +279,7 @@ def get_width(self, height):
         start, end = self.current_x_extents(self.pdf.y, height)
         if self.pdf.x > start and self.pdf.x < end:
             start = self.pdf.x
-        res = end - start - 2 * self.pdf.c_margin
+        res = end - start
         return res
 
 
@@ -418,9 +421,10 @@ def current_x_extents(self, y, height):
 
 class LWrapper(NamedTuple):
     """Connects each TextLine with the Paragraph it was written to.
-        This allows to access paragraph specific attributes like
-        top/bottom margins when rendering the line.
+    This allows to access paragraph specific attributes like
+    top/bottom margins when rendering the line.
     """
+
     line: Sequence
     paragraph: Paragraph
     first_line: bool = False
diff --git a/test/html/html_bold_italic_underline.pdf b/test/html/html_bold_italic_underline.pdf
index 42a221c8e..7a705e4a1 100644
Binary files a/test/html/html_bold_italic_underline.pdf and b/test/html/html_bold_italic_underline.pdf differ
diff --git a/test/html/html_custom_heading_sizes.pdf b/test/html/html_custom_heading_sizes.pdf
index 696fccdf5..a4ae2c520 100644
Binary files a/test/html/html_custom_heading_sizes.pdf and b/test/html/html_custom_heading_sizes.pdf differ
diff --git a/test/html/html_custom_line_height.pdf b/test/html/html_custom_line_height.pdf
index 68dbebba8..dc4fb235a 100644
Binary files a/test/html/html_custom_line_height.pdf and b/test/html/html_custom_line_height.pdf differ
diff --git a/test/html/html_custom_pre_code_font.pdf b/test/html/html_custom_pre_code_font.pdf
index d222fc2b4..e31f3728c 100644
Binary files a/test/html/html_custom_pre_code_font.pdf and b/test/html/html_custom_pre_code_font.pdf differ
diff --git a/test/html/html_customize_ul.pdf b/test/html/html_customize_ul.pdf
index bca78fad6..4f48d561f 100644
Binary files a/test/html/html_customize_ul.pdf and b/test/html/html_customize_ul.pdf differ
diff --git a/test/html/html_description.pdf b/test/html/html_description.pdf
index de821eb21..e260238f3 100644
Binary files a/test/html/html_description.pdf and b/test/html/html_description.pdf differ
diff --git a/test/html/html_features.pdf b/test/html/html_features.pdf
index 2cc721830..32adf21a8 100644
Binary files a/test/html/html_features.pdf and b/test/html/html_features.pdf differ
diff --git a/test/html/html_font_color_name.pdf b/test/html/html_font_color_name.pdf
index 5ec87f609..0738d8c4c 100644
Binary files a/test/html/html_font_color_name.pdf and b/test/html/html_font_color_name.pdf differ
diff --git a/test/html/html_format_within_p.pdf b/test/html/html_format_within_p.pdf
new file mode 100644
index 000000000..29e600e68
Binary files /dev/null and b/test/html/html_format_within_p.pdf differ
diff --git a/test/html/html_heading_color_attribute.pdf b/test/html/html_heading_color_attribute.pdf
index 001167907..b755c0051 100644
Binary files a/test/html/html_heading_color_attribute.pdf and b/test/html/html_heading_color_attribute.pdf differ
diff --git a/test/html/html_heading_hebrew.pdf b/test/html/html_heading_hebrew.pdf
index fb0fa49a3..03dd0c4de 100644
Binary files a/test/html/html_heading_hebrew.pdf and b/test/html/html_heading_hebrew.pdf differ
diff --git a/test/html/html_headings_line_height.pdf b/test/html/html_headings_line_height.pdf
index 029e02422..8c82e9d04 100644
Binary files a/test/html/html_headings_line_height.pdf and b/test/html/html_headings_line_height.pdf differ
diff --git a/test/html/html_justify_paragraph.pdf b/test/html/html_justify_paragraph.pdf
index 8a5cc18c8..9ae0906c3 100644
Binary files a/test/html/html_justify_paragraph.pdf and b/test/html/html_justify_paragraph.pdf differ
diff --git a/test/html/html_preserve_initial_text_color.pdf b/test/html/html_preserve_initial_text_color.pdf
index 49c907349..7e7be5c77 100644
Binary files a/test/html/html_preserve_initial_text_color.pdf and b/test/html/html_preserve_initial_text_color.pdf differ
diff --git a/test/html/html_superscript.pdf b/test/html/html_superscript.pdf
index b409cf90c..bd1f0b2f7 100644
Binary files a/test/html/html_superscript.pdf and b/test/html/html_superscript.pdf differ
diff --git a/test/html/html_table_with_bgcolor.pdf b/test/html/html_table_with_bgcolor.pdf
index 1e608bb0d..ab085490a 100644
Binary files a/test/html/html_table_with_bgcolor.pdf and b/test/html/html_table_with_bgcolor.pdf differ
diff --git a/test/html/html_table_with_empty_cell_contents.pdf b/test/html/html_table_with_empty_cell_contents.pdf
index 448cc5f86..27f586687 100644
Binary files a/test/html/html_table_with_empty_cell_contents.pdf and b/test/html/html_table_with_empty_cell_contents.pdf differ
diff --git a/test/html/html_unorthodox_headings_hierarchy.pdf b/test/html/html_unorthodox_headings_hierarchy.pdf
index 510f8bfb2..643c5e733 100644
Binary files a/test/html/html_unorthodox_headings_hierarchy.pdf and b/test/html/html_unorthodox_headings_hierarchy.pdf differ
diff --git a/test/html/html_whitespace_handling.pdf b/test/html/html_whitespace_handling.pdf
index d19931d27..94be62640 100644
Binary files a/test/html/html_whitespace_handling.pdf and b/test/html/html_whitespace_handling.pdf differ
diff --git a/test/html/issue_156.pdf b/test/html/issue_156.pdf
index c85302f9d..83591c4c1 100644
Binary files a/test/html/issue_156.pdf and b/test/html/issue_156.pdf differ
diff --git a/test/html/test_html.py b/test/html/test_html.py
index 2312f0612..2254a5927 100644
--- a/test/html/test_html.py
+++ b/test/html/test_html.py
@@ -474,3 +474,19 @@ def test_html_heading_color_attribute(tmp_path):  # discussion 880
     """
     )
     assert_pdf_equal(pdf, HERE / "html_heading_color_attribute.pdf", tmp_path)
+
+
+def test_html_format_within_p(tmp_path):  # discussion 880
+    pdf = FPDF()
+    pdf.add_page()
+    pdf.set_font("times", size=18)
+    pdf.set_margins(20, 20, 100)
+    pdf.write_html(
+        """
+

This is a sample text that will be justified +in the PDF. This is a sample text that will be justified +in the PDF. This is a sample text that will be justified in the PDF. +This is a sample text that will be justified in the PDF.

+ """ + ) + assert_pdf_equal(pdf, HERE / "html_format_within_p.pdf", tmp_path) diff --git a/test/hyperlinks.pdf b/test/hyperlinks.pdf index 5c07722a6..938963127 100644 Binary files a/test/hyperlinks.pdf and b/test/hyperlinks.pdf differ diff --git a/test/internal_links.pdf b/test/internal_links.pdf index 87bf52572..5f7075bb6 100644 Binary files a/test/internal_links.pdf and b/test/internal_links.pdf differ diff --git a/test/layout/page_background.pdf b/test/layout/page_background.pdf index 5ea9552a4..41f8cdd15 100644 Binary files a/test/layout/page_background.pdf and b/test/layout/page_background.pdf differ diff --git a/test/link_to_other_document.pdf b/test/link_to_other_document.pdf index 98a46cbc3..4b7b35592 100644 Binary files a/test/link_to_other_document.pdf and b/test/link_to_other_document.pdf differ diff --git a/test/mirror_cell.pdf b/test/mirror_cell.pdf index 1bc99b823..aa2f194bd 100644 Binary files a/test/mirror_cell.pdf and b/test/mirror_cell.pdf differ diff --git a/test/outline/2_pages_outline.pdf b/test/outline/2_pages_outline.pdf index bb4756ec4..0ad4439b0 100644 Binary files a/test/outline/2_pages_outline.pdf and b/test/outline/2_pages_outline.pdf differ diff --git a/test/outline/custom_HTML2FPDF.pdf b/test/outline/custom_HTML2FPDF.pdf index d648f1e88..74972de2a 100644 Binary files a/test/outline/custom_HTML2FPDF.pdf and b/test/outline/custom_HTML2FPDF.pdf differ diff --git a/test/outline/html_toc.pdf b/test/outline/html_toc.pdf index 4676f76c3..e53938245 100644 Binary files a/test/outline/html_toc.pdf and b/test/outline/html_toc.pdf differ diff --git a/test/outline/html_toc_2_pages.pdf b/test/outline/html_toc_2_pages.pdf index c25d263f6..3bc00ad1e 100644 Binary files a/test/outline/html_toc_2_pages.pdf and b/test/outline/html_toc_2_pages.pdf differ diff --git a/test/outline/html_toc_with_h1_as_2nd_heading.pdf b/test/outline/html_toc_with_h1_as_2nd_heading.pdf index 0a1cb4259..e870151e8 100644 Binary files a/test/outline/html_toc_with_h1_as_2nd_heading.pdf and b/test/outline/html_toc_with_h1_as_2nd_heading.pdf differ diff --git a/test/outline/simple_outline.pdf b/test/outline/simple_outline.pdf index b9cbf7800..81d8d5e38 100644 Binary files a/test/outline/simple_outline.pdf and b/test/outline/simple_outline.pdf differ diff --git a/test/skew.pdf b/test/skew.pdf index 0f7fe9ef0..b18b0df60 100644 Binary files a/test/skew.pdf and b/test/skew.pdf differ diff --git a/test/table/multicell_with_padding.pdf b/test/table/multicell_with_padding.pdf index 2149b31c2..de31ef2c9 100644 Binary files a/test/table/multicell_with_padding.pdf and b/test/table/multicell_with_padding.pdf differ diff --git a/test/table/table_capture_font_settings.pdf b/test/table/table_capture_font_settings.pdf index 44087ce04..86336ecb9 100644 Binary files a/test/table/table_capture_font_settings.pdf and b/test/table/table_capture_font_settings.pdf differ diff --git a/test/table/table_colspan_and_padding_and_gutter_and_width.pdf b/test/table/table_colspan_and_padding_and_gutter_and_width.pdf index 72b119d2e..96dc5d26b 100644 Binary files a/test/table/table_colspan_and_padding_and_gutter_and_width.pdf and b/test/table/table_colspan_and_padding_and_gutter_and_width.pdf differ diff --git a/test/table/table_padding_per_cell.pdf b/test/table/table_padding_per_cell.pdf index d7f18d171..3279afc51 100644 Binary files a/test/table/table_padding_per_cell.pdf and b/test/table/table_padding_per_cell.pdf differ diff --git a/test/table/table_valign_per_cell.pdf b/test/table/table_valign_per_cell.pdf index 21eb31b33..35ce3f9d5 100644 Binary files a/test/table/table_valign_per_cell.pdf and b/test/table/table_valign_per_cell.pdf differ diff --git a/test/table/table_vertical_alignment.pdf b/test/table/table_vertical_alignment.pdf index 2d7a8a592..ee69f319d 100644 Binary files a/test/table/table_vertical_alignment.pdf and b/test/table/table_vertical_alignment.pdf differ diff --git a/test/table/table_with_cell_fill.pdf b/test/table/table_with_cell_fill.pdf index d18301721..ead010c2a 100644 Binary files a/test/table/table_with_cell_fill.pdf and b/test/table/table_with_cell_fill.pdf differ diff --git a/test/table/table_with_headings_styled.pdf b/test/table/table_with_headings_styled.pdf index 0eeec40f0..7a75f2e41 100644 Binary files a/test/table/table_with_headings_styled.pdf and b/test/table/table_with_headings_styled.pdf differ diff --git a/test/table/table_with_multiline_cells_and_images_padding_and_pagebreak.pdf b/test/table/table_with_multiline_cells_and_images_padding_and_pagebreak.pdf index 4ff9cb5ae..733f48f34 100644 Binary files a/test/table/table_with_multiline_cells_and_images_padding_and_pagebreak.pdf and b/test/table/table_with_multiline_cells_and_images_padding_and_pagebreak.pdf differ diff --git a/test/table/table_with_no_headers_nor_horizontal_lines.pdf b/test/table/table_with_no_headers_nor_horizontal_lines.pdf index d6768a295..59fb47cba 100644 Binary files a/test/table/table_with_no_headers_nor_horizontal_lines.pdf and b/test/table/table_with_no_headers_nor_horizontal_lines.pdf differ diff --git a/test/table/table_with_single_top_line_layout_and_page_break.pdf b/test/table/table_with_single_top_line_layout_and_page_break.pdf index ba62cb1da..242f3a012 100644 Binary files a/test/table/table_with_single_top_line_layout_and_page_break.pdf and b/test/table/table_with_single_top_line_layout_and_page_break.pdf differ diff --git a/test/table/test_table_padding.py b/test/table/test_table_padding.py index 8d64af3cb..90d0f093d 100644 --- a/test/table/test_table_padding.py +++ b/test/table/test_table_padding.py @@ -97,7 +97,6 @@ def test_multicell_return_value(tmp_path): padding=0, output=MethodReturnValue.PAGE_BREAK | MethodReturnValue.HEIGHT, ) - print(out) height_without_padding = out[1] pdf.x = 5 @@ -237,6 +236,8 @@ def test_table_vertical_alignment(tmp_path): # pdf.rect(0, pdf.t_margin, pdf.l_margin, pdf.eph) deathstyle = FontFace(color=black, fill_color=red) + # write_html() doesn't add a nl at the very top of the page anymore. + pdf.ln(0.1) for v in (VAlign.T, VAlign.M, VAlign.B): pdf.write_html("

Vertical alignment: {}

".format(v)) diff --git a/test/template/flextemplate_elements.pdf b/test/template/flextemplate_elements.pdf index ff2cfd978..c6eee5d2b 100644 Binary files a/test/template/flextemplate_elements.pdf and b/test/template/flextemplate_elements.pdf differ diff --git a/test/template/flextemplate_multipage.pdf b/test/template/flextemplate_multipage.pdf index 44bc3d81b..cc22a251e 100644 Binary files a/test/template/flextemplate_multipage.pdf and b/test/template/flextemplate_multipage.pdf differ diff --git a/test/template/flextemplate_rotation.pdf b/test/template/flextemplate_rotation.pdf index e86f5320f..6d9290634 100644 Binary files a/test/template/flextemplate_rotation.pdf and b/test/template/flextemplate_rotation.pdf differ diff --git a/test/template/template_multipage.pdf b/test/template/template_multipage.pdf index 289d27017..14a142e26 100644 Binary files a/test/template/template_multipage.pdf and b/test/template/template_multipage.pdf differ diff --git a/test/template/template_nominal_csv.pdf b/test/template/template_nominal_csv.pdf index af84d4463..6e805b2bf 100644 Binary files a/test/template/template_nominal_csv.pdf and b/test/template/template_nominal_csv.pdf differ diff --git a/test/template/template_nominal_hardcoded.pdf b/test/template/template_nominal_hardcoded.pdf index 6629a4a48..12f50ef17 100644 Binary files a/test/template/template_nominal_hardcoded.pdf and b/test/template/template_nominal_hardcoded.pdf differ diff --git a/test/text/test_cell.py b/test/text/test_cell.py index 2e3e39f4d..1611720df 100644 --- a/test/text/test_cell.py +++ b/test/text/test_cell.py @@ -143,7 +143,7 @@ def test_cell_missing_text_or_width(): pdf.cell() assert ( str(error.value) - == "A 'text_line' parameter with fragments must be provided if 'w' is None" + == "'text_line' must have fragments if 'text_line.text_width' is None" ) diff --git a/test/text/test_line_break.py b/test/text/test_line_break.py index 5301eb83c..76ede59cb 100644 --- a/test/text/test_line_break.py +++ b/test/text/test_line_break.py @@ -116,9 +116,9 @@ def test_no_fragments(): """ char_width = 6 test_width = char_width * 200 - multi_line_break = MultiLineBreak([], test_width) + multi_line_break = MultiLineBreak([], test_width, [0, 0]) assert multi_line_break.get_line() is None - multi_line_break = MultiLineBreak([], 100) + multi_line_break = MultiLineBreak([], 100, [0, 0]) assert multi_line_break.get_line() is None @@ -156,7 +156,7 @@ def _get_width(height): # pylint: disable=unused-argument for i, char in enumerate(text): alphabet["normal"][char] = char_width + i fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, _get_width) + multi_line_break = MultiLineBreak(fragments, _get_width, [0, 0]) # zero width returns empty line max_width = 0 @@ -215,7 +215,7 @@ def test_single_space_in_fragment(): fragments = [FxFragment(alphabet, text, _gs_normal, 1)] for char in text: alphabet["normal"][char] = char_width - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=fragments, @@ -248,7 +248,7 @@ def test_single_soft_hyphen_in_fragment(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = None assert res == exp @@ -270,7 +270,7 @@ def test_single_hard_hyphen_in_fragment(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=fragments, @@ -301,10 +301,12 @@ def test_real_hyphen_acts_differently_from_soft_hyphen(): soft_hyphen_line_break = MultiLineBreak( [FxFragment(alphabet, words_separated_by_soft_hyphen, _gs_normal, 1)], test_width, + [0, 0], ) hard_hyphen_line_break = MultiLineBreak( [FxFragment(alphabet, words_separated_by_hard_hyphen, _gs_normal, 1)], test_width, + [0, 0], ) hh_res = soft_hyphen_line_break.get_line() sh_res = hard_hyphen_line_break.get_line() @@ -333,7 +335,7 @@ def test_trailing_soft_hyphen(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment("hello", _gs_normal, 1)], @@ -368,7 +370,7 @@ def test_trailing_whitespace(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=fragments, @@ -403,7 +405,7 @@ def test_two_words_one_line(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=fragments, @@ -440,7 +442,7 @@ def test_two_words_one_line_justify(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width, align=Align.J) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0], align=Align.J) res = multi_line_break.get_line() exp = TextLine( fragments=fragments, @@ -475,7 +477,7 @@ def test_two_words_two_lines_break_by_space(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment("hello", _gs_normal, 1)], @@ -524,7 +526,7 @@ def test_two_words_two_lines_break_by_space_justify(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( @@ -574,7 +576,7 @@ def test_four_words_two_lines_break_by_space(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width_A) + multi_line_break = MultiLineBreak(fragments, test_width_A, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment(first_line_text, _gs_normal, 1)], @@ -625,7 +627,7 @@ def test_four_words_two_lines_break_by_space_justify(): for char in text: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width_A, align=Align.J) + multi_line_break = MultiLineBreak(fragments, test_width_A, [0, 0], align=Align.J) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment(first_line_text, _gs_normal, 1)], @@ -686,7 +688,7 @@ def test_break_fragment_into_two_lines(): def _get_width(height): # pylint: disable=unused-argument return max_width - multi_line_break = MultiLineBreak(fragments, _get_width) + multi_line_break = MultiLineBreak(fragments, _get_width, [0, 0]) max_width = test_width_A res = multi_line_break.get_line() exp = TextLine( @@ -753,7 +755,7 @@ def test_break_fragment_into_two_lines_justify(): def _get_width(height): # pylint: disable=unused-argument return max_width - multi_line_break = MultiLineBreak(fragments, _get_width, align=Align.J) + multi_line_break = MultiLineBreak(fragments, _get_width, [0, 0], align=Align.J) max_width = test_width_A res = multi_line_break.get_line() exp = TextLine( @@ -810,7 +812,7 @@ def test_soft_hyphen_break(): def _get_width(height): # pylint: disable=unused-argument return max_width - multi_line_break = MultiLineBreak(fragments, _get_width) + multi_line_break = MultiLineBreak(fragments, _get_width, [0, 0]) max_width = test_width res = multi_line_break.get_line() exp = TextLine( @@ -913,7 +915,7 @@ def test_soft_hyphen_break_justify(): for char in long_string: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, long_string, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width, align=Align.J) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0], align=Align.J) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment("ab cd\u002d", _gs_normal, 1)], @@ -967,7 +969,7 @@ def test_explicit_break(): for char in long_string: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, long_string, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment("a", _gs_normal, 1)], @@ -1033,7 +1035,7 @@ def test_explicit_break_justify(): for char in long_string: alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, long_string, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width, align=Align.J) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0], align=Align.J) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment("a", _gs_normal, 1)], @@ -1100,7 +1102,7 @@ def test_single_word_doesnt_fit_into_width(): # glyph space units alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, long_string, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0]) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment("abcde", _gs_normal, 1)], @@ -1169,7 +1171,7 @@ def test_single_word_doesnt_fit_into_width_justify(): # glyph space units alphabet["normal"][char] = char_width fragments = [FxFragment(alphabet, long_string, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, test_width, align=Align.J) + multi_line_break = MultiLineBreak(fragments, test_width, [0, 0], align=Align.J) res = multi_line_break.get_line() exp = TextLine( fragments=[Fragment("abcde", _gs_normal, 1)], @@ -1232,7 +1234,7 @@ def test_last_line_no_justify(): def _get_width(height): # pylint: disable=unused-argument return max_width - multi_line_break = MultiLineBreak(fragments, _get_width, align=Align.J) + multi_line_break = MultiLineBreak(fragments, _get_width, [0, 0], align=Align.J) max_width = char_width * 5 res = multi_line_break.get_line() exp = TextLine( @@ -1272,6 +1274,6 @@ def test_line_break_no_initial_newline(): # issue-847 alphabet = {"normal": {}} alphabet["normal"]["X"] = 4.7 fragments = [FxFragment(alphabet, text, _gs_normal, 1)] - multi_line_break = MultiLineBreak(fragments, 188) + multi_line_break = MultiLineBreak(fragments, 188, [0, 0]) text_line = multi_line_break.get_line() assert text_line.fragments diff --git a/test/text/test_render_styled.py b/test/text/test_render_styled.py index 7165067e6..58b2daf5e 100644 --- a/test/text/test_render_styled.py +++ b/test/text/test_render_styled.py @@ -78,7 +78,7 @@ def test_render_styled_newpos(tmp_path): newy = YPos.coerce(item[3]) # pylint: disable=protected-access frags = doc._preload_font_styles(s, False) - mlb = MultiLineBreak(frags, twidth * 1000 / doc.font_size, align=align) + mlb = MultiLineBreak(frags, twidth, [1, 1], align=align) line = mlb.get_line() if align == Align.J: # We need to manually rebuild our TextLine in order to force @@ -89,12 +89,11 @@ def test_render_styled_newpos(tmp_path): number_of_spaces=line.number_of_spaces, align=Align.J, height=0, - max_width=twidth * 1000 / doc.font_size, + max_width=line.max_width, trailing_nl=False, ) doc._render_styled_text_line( line, - twidth, border=1, new_x=newx, new_y=newy, diff --git a/test/text/test_varied_fragments.py b/test/text/test_varied_fragments.py index d64d9c283..5e34ca914 100644 --- a/test/text/test_varied_fragments.py +++ b/test/text/test_varied_fragments.py @@ -28,14 +28,12 @@ def _get_width(height): # pylint: disable=unused-argument return max_width text_lines = [] - multi_line_break = MultiLineBreak(frags, _get_width, align=align) + multi_line_break = MultiLineBreak(frags, _get_width, [1, 1], align=align) # first line from current x position to right margin - first_width = self.w - self.x - self.r_margin - max_width = first_width - 2 * self.c_margin + max_width = self.w - self.x - self.r_margin text_line = multi_line_break.get_line() # remaining lines fill between margins - full_width = self.w - self.l_margin - self.r_margin - max_width = full_width - 2 * self.c_margin + max_width = self.w - self.l_margin - self.r_margin while (text_line) is not None: text_lines.append(text_line) text_line = multi_line_break.get_line() @@ -45,14 +43,10 @@ def _get_width(height): # pylint: disable=unused-argument return self.ws = 0 # currently only left aligned, so no word spacing for text_line_index, text_line in enumerate(text_lines): - if text_line_index == 0: - line_width = first_width - else: - line_width = full_width + if text_line_index > 0: self.ln() self._render_styled_text_line( text_line, - line_width, h=None, border=0, new_x=XPos.WCONT, diff --git a/test/text_region/tcols_align.pdf b/test/text_region/tcols_align.pdf index 9077601d2..8dd22fb78 100644 Binary files a/test/text_region/tcols_align.pdf and b/test/text_region/tcols_align.pdf differ