Yet another workaround for broken getBoundingClientRect. Fixes #2038672 [E-book viewer: clicking on a ToC item jumps to an incorrect position](https://bugs.launchpad.net/calibre/+bug/2038672)

Use a range to ge tthe rect instead more efficient than our offset based
JS function.
This commit is contained in:
Kovid Goyal 2023-10-17 08:01:28 +05:30
parent 33d9e13cd9
commit 3efaad9553
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -115,7 +115,7 @@ def fit_images():
img_tags = document.getElementsByTagName('img') img_tags = document.getElementsByTagName('img')
bounding_rects = v'[]' bounding_rects = v'[]'
for img_tag in img_tags: for img_tag in img_tags:
bounding_rects.push(img_tag.getBoundingClientRect()) bounding_rects.push(get_bounding_client_rect(img_tag))
maxb = screen_block maxb = screen_block
for i in range(img_tags.length): for i in range(img_tags.length):
img = img_tags[i] img = img_tags[i]
@ -331,9 +331,9 @@ def layout(is_single_page, on_resize):
if not is_full_screen_layout: if not is_full_screen_layout:
has_no_more_than_two_columns = (scroll_viewport.paged_content_inline_size() < 2*screen_inline + 10) has_no_more_than_two_columns = (scroll_viewport.paged_content_inline_size() < 2*screen_inline + 10)
if has_no_more_than_two_columns and single_screen: if has_no_more_than_two_columns and single_screen:
if only_img and imgs.length and imgs[0].getBoundingClientRect().left < screen_inline: if only_img and imgs.length and get_bounding_client_rect(imgs[0]).left < screen_inline:
is_full_screen_layout = True is_full_screen_layout = True
if has_svg and svgs.length == 1 and svgs[0].getBoundingClientRect().left < screen_inline: if has_svg and svgs.length == 1 and get_bounding_client_rect(svgs[0]).left < screen_inline:
is_full_screen_layout = True is_full_screen_layout = True
if is_full_screen_layout and only_img and cols_per_screen > 1: if is_full_screen_layout and only_img and cols_per_screen > 1:
cols_per_screen = 1 cols_per_screen = 1
@ -533,7 +533,7 @@ def scroll_to_elem(elem):
# mode, this position can be inaccurate, see # mode, this position can be inaccurate, see
# https://bugs.launchpad.net/calibre/+bug/1132641 for a test case. # https://bugs.launchpad.net/calibre/+bug/1132641 for a test case.
# The usual symptom of the inaccuracy is br.top is highly negative. # The usual symptom of the inaccuracy is br.top is highly negative.
br = elem.getBoundingClientRect() br = get_bounding_client_rect(elem)
if br.top < -100: if br.top < -100:
# This only works because of the preceding call to # This only works because of the preceding call to
# elem.scrollIntoView(). However, in some cases it gives # elem.scrollIntoView(). However, in some cases it gives
@ -848,18 +848,14 @@ def handle_gesture(gesture):
scroll_by_page(False, False) scroll_by_page(False, False)
def get_bounding_client_rect_using_offset_properties(elem): def get_bounding_client_rect(elem):
ans = {'left': 0, 'top': 0, 'width': elem.offsetWidth, 'height': elem.offsetHeight, 'x': 0, 'y': 0} br = elem.getBoundingClientRect()
while elem: if br.width is 0 and br.height is 0:
ans.left += elem.offsetLeft # getBoundingClientRect() fails sometimes, see https://bugs.launchpad.net/calibre/+bug/2037543
ans.top += elem.offsetTop r = document.createRange()
elem = elem.offsetParent r.selectNodeContents(elem)
ans.left -= window.scrollX br = r.getBoundingClientRect()
ans.top -= window.scrollY return br
ans.right = ans.left + ans.width
ans.bottom = ans.top + ans.height
ans.x, ans.y = ans.left, ans.top
return ans
anchor_funcs = { anchor_funcs = {
@ -867,10 +863,7 @@ anchor_funcs = {
if not elem: if not elem:
return 0 return 0
elem = scrollable_element(elem) elem = scrollable_element(elem)
br = elem.getBoundingClientRect() br = get_bounding_client_rect(elem)
if br.left is 0 and br.top is 0 and br.width is 0 and br.height is 0:
# getBoundingClientRect() fails sometimes, see https://bugs.launchpad.net/calibre/+bug/2037543
br = get_bounding_client_rect_using_offset_properties(elem)
pos = scroll_viewport.viewport_to_document_inline( pos = scroll_viewport.viewport_to_document_inline(
scroll_viewport.rect_inline_start(br)) scroll_viewport.rect_inline_start(br))
return column_at(pos) return column_at(pos)