Skip to content

JM_new_lineart_device_Device.__init__ omits call parentheses on use_virtual_*_text, disabling SWIG director text callbacks #5238

Open

Description

@codeCraft-Ritik

Description of the bug


Description of the bug *

In src/__init__.py, JM_new_lineart_device_Device is the Python lineart device (subclassing SWIG's mupdf.FzDevice2) used by Page.get_cdrawings() when g_use_extra is disabled or fallback is active.

To enable Python callbacks from the C++ device, __init__ must activate virtual dispatch by calling self.use_virtual_<method>(). On lines 24400–24402, self.use_virtual_fill_text, self.use_virtual_stroke_text, and self.use_virtual_ignore_text are written without parentheses (). In contrast, JM_new_texttrace_device (lines 24474–24476) correctly invokes them with ().

Because these statements evaluate to uncalled method references:

  1. SWIG director virtual method hooks are never registered with the C++ FzDevice2 lineart device.
  2. MuPDF's rendering engine skips Python callbacks (fill_text = jm_increase_seqno, stroke_text = jm_increase_seqno, ignore_text = jm_increase_seqno).
  3. self.seqno is never incremented when text operations occur between drawing operations. Consequently, vector drawing items (path dictionaries) following text receive incorrect sequence numbers, breaking drawing sequence order and z-index determination.

How to reproduce the bug


Highlight in Code

src/__init__.py:24395-24405:

24395:         self.use_virtual_clip_image_mask()
24396:         self.use_virtual_clip_stroke_path()
24397:         self.use_virtual_clip_stroke_text()
24398:         self.use_virtual_clip_text()
24399:         
24400: >>>>>   self.use_virtual_fill_text        # BUG: Missing call parentheses ()
24401: >>>>>   self.use_virtual_stroke_text      # BUG: Missing call parentheses ()
24402: >>>>>   self.use_virtual_ignore_text      # BUG: Missing call parentheses ()
24403:         
24404:         self.use_virtual_fill_shade()
24405:         self.use_virtual_fill_image()

Steps & Reproduction Code

import pymupdf
import inspect

# Inspect source of JM_new_lineart_device_Device.__init__:
lines, _ = inspect.getsourcelines(pymupdf.JM_new_lineart_device_Device.__init__)
uncalled = [
    l.strip()
    for l in lines
    if l.strip() in (
        "self.use_virtual_fill_text",
        "self.use_virtual_stroke_text",
        "self.use_virtual_ignore_text",
    )
]
print("Uncalled virtual method statements:", uncalled)
assert len(uncalled) == 3

# When running a page with text and drawings with g_use_extra = False:
pymupdf.g_use_extra = False
doc = pymupdf.open()
page = doc.new_page()
page.draw_rect([10, 10, 100, 100], color=(1, 0, 0))
page.insert_text([50, 50], "Sample Text")
page.draw_rect([150, 150, 200, 200], color=(0, 1, 0))

drawings = page.get_cdrawings()
for d in drawings:
    print("Drawing rect:", d["rect"], "seqno:", d["seqno"])

Expected Behavior

use_virtual_fill_text(), use_virtual_stroke_text(), and use_virtual_ignore_text() should be called with () so that SWIG dispatches MuPDF's text callbacks to Python to advance self.seqno.

Actual Behavior

The statements evaluate to unused method objects, SWIG vtable interception is not enabled for text operations, and seqno fails to advance on text.

Suggested Fix

--- a/src/__init__.py
+++ b/src/__init__.py
@@ -24400,3 +24400,3 @@ class JM_new_lineart_device_Device(mupdf.FzDevice2):
-        self.use_virtual_fill_text
-        self.use_virtual_stroke_text
-        self.use_virtual_ignore_text
+        self.use_virtual_fill_text()
+        self.use_virtual_stroke_text()
+        self.use_virtual_ignore_text()

PyMuPDF version

2.1

Operating system

Windows

Python version

3.14

Activity

  1. self-assigned this
    on Nov 2, 2026
  2. added a commit that references this issue on Nov 5, 2026
    a8d6dbf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugfix developedrelease schedule to be determined

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions