Make a fresh copy of a page.
(self, page: Page)
| 6118 | return prev_loc.chapter, prev_loc.page |
| 6119 | |
| 6120 | def reload_page(self, page: Page) -> Page: |
| 6121 | """Make a fresh copy of a page.""" |
| 6122 | old_annots = {} # copy annot references to here |
| 6123 | pno = page.number # save the page number |
| 6124 | for k, v in page._annot_refs.items(): # save the annot dictionary |
| 6125 | old_annots[k] = v |
| 6126 | |
| 6127 | # When we call `self.load_page()` below, it will end up in |
| 6128 | # fz_load_chapter_page(), which will return any matching page in the |
| 6129 | # document's list of non-ref-counted loaded pages, instead of actually |
| 6130 | # reloading the page. |
| 6131 | # |
| 6132 | # We want to assert that we have actually reloaded the fz_page, and not |
| 6133 | # simply returned the same `fz_page*` pointer from the document's list |
| 6134 | # of non-ref-counted loaded pages. |
| 6135 | # |
| 6136 | # So we first remove our reference to the `fz_page*`. This will |
| 6137 | # decrement .refs, and if .refs was 1, this is guaranteed to free the |
| 6138 | # `fz_page*` and remove it from the document's list if it was there. So |
| 6139 | # we are guaranteed that our returned `fz_page*` is from a genuine |
| 6140 | # reload, even if it happens to reuse the original block of memory. |
| 6141 | # |
| 6142 | # However if the original .refs is greater than one, there must be |
| 6143 | # other references to the `fz_page` somewhere, and we require that |
| 6144 | # these other references are not keeping the page in the document's |
| 6145 | # list. We check that we are returning a newly loaded page by |
| 6146 | # asserting that our returned `fz_page*` is different from the original |
| 6147 | # `fz_page*` - the original was not freed, so a new `fz_page` cannot |
| 6148 | # reuse the same block of memory. |
| 6149 | # |
| 6150 | |
| 6151 | refs_old = page.this.m_internal.refs |
| 6152 | m_internal_old = page.this.m_internal_value() |
| 6153 | |
| 6154 | page.this = None |
| 6155 | page._erase() # remove the page |
| 6156 | page = None |
| 6157 | TOOLS.store_shrink(100) |
| 6158 | page = self.load_page(pno) # reload the page |
| 6159 | |
| 6160 | # copy annot refs over to the new dictionary |
| 6161 | #page_proxy = weakref.proxy(page) |
| 6162 | for k, v in old_annots.items(): |
| 6163 | annot = old_annots[k] |
| 6164 | #annot.parent = page_proxy # refresh parent to new page |
| 6165 | page._annot_refs[k] = annot |
| 6166 | if refs_old == 1: |
| 6167 | # We know that `page.this = None` will have decremented the ref |
| 6168 | # count to zero so we are guaranteed that the new `fz_page` is a |
| 6169 | # new page even if it happens to have reused the same block of |
| 6170 | # memory. |
| 6171 | pass |
| 6172 | else: |
| 6173 | # Check that the new `fz_page*` is different from the original. |
| 6174 | m_internal_new = page.this.m_internal_value() |
| 6175 | assert m_internal_new != m_internal_old, \ |
| 6176 | f'{refs_old=} {m_internal_old=:#x} {m_internal_new=:#x}' |
| 6177 | return page |