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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
## [2.8.8] - Not released yet
### Fixed
* text rendering when the first text on a page starts with a fallback glyph
* preserve boundary-neutral formatting during bidirectional text preprocessing
### Changed
* skip byte-for-byte compressed data comparison when zlib-ng is detected, regardless of OS

Expand Down
21 changes: 14 additions & 7 deletions fpdf/bidi.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ class BidiParagraph:
"text",
"base_direction",
"debug",
"preserve_bn_chars",
"base_embedding_level",
"characters",
)
Expand All @@ -548,6 +549,7 @@ def __init__(
text: str,
base_direction: Optional[TextDirection] = None,
debug: bool = False,
preserve_bn_chars: bool = False,
) -> None:
self.text = text
self.base_direction = (
Expand All @@ -556,6 +558,7 @@ def __init__(
else base_direction
)
self.debug = debug
self.preserve_bn_chars = preserve_bn_chars
self.base_embedding_level = (
0 if self.base_direction == TextDirection.LTR else 1
) # base level
Expand Down Expand Up @@ -701,13 +704,17 @@ def get_bidi_characters(self) -> None:

if new_bidi_class:
bidi_char.bidi_class = new_bidi_class
if bidi_char.bidi_class not in (
"RLE",
"LRE",
"RLO",
"LRO",
"PDF",
"BN",
if (
bidi_char.bidi_class
not in (
"RLE",
"LRE",
"RLO",
"LRO",
"PDF",
"BN",
)
or self.preserve_bn_chars
): # X9
if bidi_char.bidi_class == "B":
bidi_char.embedding_level = self.base_embedding_level
Expand Down
6 changes: 5 additions & 1 deletion fpdf/fpdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4332,7 +4332,11 @@ def _preload_bidirectional_text(
else auto_detect_base_direction(text)
)

paragraph = BidiParagraph(text=text, base_direction=paragraph_direction)
paragraph = BidiParagraph(
text=text,
base_direction=paragraph_direction,
preserve_bn_chars=True,
)
directional_segments = paragraph.get_bidi_fragments()
self.text_shaping["paragraph_direction"] = paragraph.base_direction

Expand Down
15 changes: 15 additions & 0 deletions test/text_shaping/test_bidirectional.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,18 @@ def test_bidi_get_string_width(tmp_path):
pdf.ln()
pdf.ln()
assert_pdf_equal(pdf, HERE / "bidi_get_string_width.pdf", tmp_path)


def test_bidi_preserves_bn_chars():
paragraph = BidiParagraph(
text="This is an in\u00adter\U000e007ana\u00adtion\u00adal",
base_direction=TextDirection.LTR,
preserve_bn_chars=True,
)

assert paragraph.get_bidi_fragments() == (
("This is an in\u00adter\U000e007ana\u00adtion\u00adal", TextDirection.LTR),
)
characters = [char.character for char in paragraph.get_characters()]
assert characters.count("\u00ad") == 3
assert characters.count("\U000e007a") == 1
26 changes: 26 additions & 0 deletions test/text_shaping/test_text_shaping.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pathlib import Path

from fpdf import FPDF
from fpdf.enums import MethodReturnValue
from fpdf.unicode_script import get_unicode_script, UnicodeScript
from test.conftest import assert_pdf_equal

Expand Down Expand Up @@ -181,6 +182,31 @@ def test_text_shaping_and_offset_rendering(tmp_path): # issue #1075
assert_pdf_equal(pdf, HERE / "text_shaping_and_offset_rendering.pdf", tmp_path)


def test_multi_cell_uses_soft_hyphen_with_text_shaping():
pdf = FPDF()
pdf.add_page()
pdf.add_font("Roboto", "", FONTS_DIR / "Roboto-Regular.ttf")
pdf.set_font("Roboto", size=12)
pdf.set_text_shaping(
use_shaping_engine=True,
direction="ltr",
script="latn",
language="eng",
)

lines = pdf.multi_cell(
w=50,
text="This is an in\u00adter\u00adna\u00adtion\u00adal\u00adiza\u00adtion example.",
dry_run=True,
output=MethodReturnValue.LINES,
)

assert lines == [
"This is an international-",
"ization example.",
]


def test_multilingual_string(tmp_path):
pdf = FPDF()
pdf.add_page()
Expand Down
Loading