Skip to content

Commit a6fe676

Browse files
committed
Rework / remove method reload_page
We previously refreshed a Page in memory by simulating navigating away to another page and returning. This has been necessary after certain updates or inserts of annotations and links. This fix basically replaces it with the feature provided by mupdf function pdf_sync_page(), which is now what Page method refresh() does. This is a tentative update yet: As MuPDF propagates calling pdf_sync_page(9 over time, we should reduce and eventually retire Page.refresh() and Document.reload_page().
1 parent 166b007 commit a6fe676

File tree

8 files changed

+9
-64
lines changed

8 files changed

+9
-64
lines changed

src/__init__.py

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5232,35 +5232,8 @@ def prev_location(self, page_id):
52325232

52335233
def reload_page(self, page: Page) -> Page:
52345234
"""Make a fresh copy of a page."""
5235-
old_annots = {} # copy annot references to here
52365235
pno = page.number # save the page number
5237-
for k, v in page._annot_refs.items(): # save the annot dictionary
5238-
old_annots[k] = v
5239-
5240-
# When we call `self.load_page()` below, it will end up in
5241-
# fz_load_chapter_page(), which will return any matching page in the
5242-
# document's list of non-ref-counted loaded pages, instead of actually
5243-
# reloading the page.
5244-
#
5245-
# We want to assert that we have actually reloaded the fz_page, and not
5246-
# simply returned the same `fz_page*` pointer from the document's list
5247-
# of non-ref-counted loaded pages.
5248-
#
5249-
# So we first remove our reference to the `fz_page*`. This will
5250-
# decrement .refs, and if .refs was 1, this is guaranteed to free the
5251-
# `fz_page*` and remove it from the document's list if it was there. So
5252-
# we are guaranteed that our returned `fz_page*` is from a genuine
5253-
# reload, even if it happens to reuse the original block of memory.
5254-
#
5255-
# However if the original .refs is greater than one, there must be
5256-
# other references to the `fz_page` somewhere, and we require that
5257-
# these other references are not keeping the page in the document's
5258-
# list. We check that we are returning a newly loaded page by
5259-
# asserting that our returned `fz_page*` is different from the original
5260-
# `fz_page*` - the original was not freed, so a new `fz_page` cannot
5261-
# reuse the same block of memory.
5262-
#
5263-
5236+
page.refresh() # synchronize links & annotations
52645237
refs_old = page.this.m_internal.refs
52655238
m_internal_old = page.this.m_internal_value()
52665239

@@ -5269,24 +5242,6 @@ def reload_page(self, page: Page) -> Page:
52695242
page = None
52705243
TOOLS.store_shrink(100)
52715244
page = self.load_page(pno) # reload the page
5272-
5273-
# copy annot refs over to the new dictionary
5274-
#page_proxy = weakref.proxy(page)
5275-
for k, v in old_annots.items():
5276-
annot = old_annots[k]
5277-
#annot.parent = page_proxy # refresh parent to new page
5278-
page._annot_refs[k] = annot
5279-
if refs_old == 1:
5280-
# We know that `page.this = None` will have decremented the ref
5281-
# count to zero so we are guaranteed that the new `fz_page` is a
5282-
# new page even if it happens to have reused the same block of
5283-
# memory.
5284-
pass
5285-
else:
5286-
# Check that the new `fz_page*` is different from the original.
5287-
m_internal_new = page.this.m_internal_value()
5288-
assert m_internal_new != m_internal_old, \
5289-
f'{refs_old=} {m_internal_old=:#x} {m_internal_new=:#x}'
52905245
return page
52915246

52925247
def resolve_link(self, uri=None, chapters=0):
@@ -9742,10 +9697,8 @@ def read_contents(self):
97429697
def refresh(self):
97439698
"""Refresh page after link/annot/widget updates."""
97449699
CheckParent(self)
9745-
doc = self.parent
9746-
page = doc.reload_page(self)
9747-
# fixme this looks wrong.
9748-
self.this = page
9700+
pdf_page = _as_pdf_page(self)
9701+
mupdf.pdf_sync_page(pdf_page)
97499702

97509703
@property
97519704
def rotation(self):

src/utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2244,6 +2244,7 @@ def insert_link(page: pymupdf.Page, lnk: dict, mark: bool = True) -> None:
22442244
if annot == "":
22452245
raise ValueError("link kind not supported")
22462246
page._addAnnot_FromString((annot,))
2247+
page.refresh()
22472248

22482249

22492250
def insert_textbox(
@@ -2494,6 +2495,8 @@ def rect_function(*args):
24942495
link["from"] *= mat
24952496
page.insert_link(link)
24962497

2498+
# ensure any new links are available
2499+
page.refresh()
24972500
return spare_height, scale
24982501

24992502

@@ -4271,6 +4274,7 @@ def center_rect(annot_rect, new_text, font, fsize):
42714274
)
42724275
fsize -= 0.5 # reduce font if unsuccessful
42734276
shape.commit() # append new contents object
4277+
page.refresh() # synchronize links and annotations
42744278
return True
42754279

42764280

tests/test_annots.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ def test_stamp():
151151
annot_xref = annot.xref
152152
page.load_annot(annot_id)
153153
page.load_annot(annot_xref)
154-
page = doc.reload_page(page)
155154

156155

157156
def test_image_stamp():

tests/test_general.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ def test_2957_1():
811811
page.apply_redactions()
812812

813813
# reload page to finalize updates
814-
page = doc.reload_page(page)
814+
#page = doc.reload_page(page)
815815

816816
# the two string must retain their positions (except rounding errors)
817817
rects1 = page.search_for("6e9f73dfb4384a2b8af6ebba")

tests/test_mupdf_regressions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def test_707727():
4444
page = doc[0]
4545
pix0 = page.get_pixmap()
4646
page.clean_contents(sanitize=True)
47-
page = doc.reload_page(page) # required to prevent re-use
47+
# page = doc.reload_page(page) # required to prevent re-use
4848
pix1 = page.get_pixmap()
4949
rms = gentle_compare.pixmaps_rms(pix0, pix1)
5050
print(f'{rms=}', flush=1)

tests/test_named_links.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ def test_2886():
2020
# insert this link in an arbitrary page & rect
2121
page = doc[-1]
2222
page.insert_link(link)
23-
# need this to update the internal MuPDF annotations array
24-
page = doc.reload_page(page)
2523

2624
# our new link must be the last in the following list
2725
links = page.get_links()

tests/test_textbox.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ def test_htmlbox1():
184184
spare_height, scale = page.insert_htmlbox(rect, text, rotate=rot, scale_low=0)
185185
assert spare_height == 0
186186
assert 0 < scale < 1
187-
page = doc.reload_page(page)
188187
link = page.get_links()[0] # extracts the links on the page
189188

190189
assert link["uri"] == "https://www.artifex.com"

tests/test_widgets.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -398,25 +398,19 @@ def test_4055():
398398
w.field_value = w.on_state()
399399
w.update()
400400

401-
page = doc.reload_page(page) # reload page to make sure we start fresh
402-
403401
# Round 2: confirm that fields contain the PDF's own on values
404402
for w in page.widgets(types=[2]):
405403
# confirm each value coincides with the "Yes" value
406404
assert w.field_value == w.on_state()
407405
w.field_value = False # switch to "Off" using False
408406
w.update()
409407

410-
page = doc.reload_page(page)
411-
412408
# Round 3: confirm that 'False' achieved "Off" values
413409
for w in page.widgets(types=[2]):
414410
assert w.field_value == "Off"
415411
w.field_value = True # use True for the next round
416412
w.update()
417413

418-
page = doc.reload_page(page)
419-
420414
# Round 4: confirm that setting to True also worked
421415
for w in page.widgets(types=[2]):
422416
assert w.field_value == w.on_state()
@@ -425,8 +419,6 @@ def test_4055():
425419
w.field_value = "Yes"
426420
w.update()
427421

428-
page = doc.reload_page(page)
429-
430422
# Round 5: final check: setting to "Yes" also does work
431423
for w in page.widgets(types=[2]):
432424
assert w.field_value == w.on_state()

0 commit comments

Comments
 (0)