Viewer: In multiple pages per screen mode, When paging back to a chapter we have just paged forward from return to the exact position we left from in terms of number of blank trailing pages displayed. Fixes #1856472 [Scrolling backwards at section boundaries causes incorrect page display](https://bugs.launchpad.net/calibre/+bug/1856472)

This commit is contained in:
Kovid Goyal 2019-12-16 22:56:58 +05:30
parent 018d673023
commit 034c22de8c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 50 additions and 15 deletions

View File

@ -10,7 +10,7 @@ from read_book.viewport import scroll_viewport
from utils import document_height, viewport_to_document
def flow_to_scroll_fraction(frac):
def flow_to_scroll_fraction(frac, on_initial_load):
scroll_viewport.scroll_to(0, document_height() * frac)

View File

@ -200,7 +200,7 @@ class IframeBoss:
unserialize_html(root_data, self.content_loaded, None, data.name)
def on_scroll_to_frac(self, data):
self.to_scroll_fraction(data.frac)
self.to_scroll_fraction(data.frac, False)
def handle_gesture(self, gesture):
if gesture.type is 'show-chrome':
@ -224,7 +224,7 @@ class IframeBoss:
if frag:
self.scroll_to_anchor(frag)
else:
self.to_scroll_fraction(0.0)
self.to_scroll_fraction(0.0, False)
def on_next_screen(self, data):
backwards = data.backwards
@ -277,7 +277,7 @@ class IframeBoss:
ipos = csi.initial_position
self.replace_history_on_next_cfi_update = ipos.replace_history or False
if ipos.type is 'frac':
self.to_scroll_fraction(ipos.frac)
self.to_scroll_fraction(ipos.frac, True)
elif ipos.type is 'anchor':
self.scroll_to_anchor(ipos.anchor)
elif ipos.type is 'ref':

View File

@ -11,7 +11,7 @@ from read_book.cfi import (
at_current as cfi_at_current, at_point as cfi_at_point,
scroll_to as cfi_scroll_to
)
from read_book.globals import get_boss
from read_book.globals import current_spine_item, get_boss
from read_book.settings import opts
from read_book.viewport import scroll_viewport
from utils import (
@ -132,7 +132,7 @@ def calc_columns_per_screen():
def layout(is_single_page, on_resize):
nonlocal _in_paged_mode, col_width, col_and_gap, screen_height, gap, screen_width, is_full_screen_layout, cols_per_screen
nonlocal _in_paged_mode, col_width, col_and_gap, screen_height, gap, screen_width, is_full_screen_layout, cols_per_screen, number_of_cols
body_style = window.getComputedStyle(document.body)
first_layout = not _in_paged_mode
cps = calc_columns_per_screen()
@ -263,8 +263,19 @@ def scroll_to_xpos(xpos, notify=False, duration=1000):
return
scroll_to_column(column_at(xpos), notify=notify, duration=duration)
def scroll_to_fraction(frac):
def scroll_to_previous_position():
fsd = next_spine_item.forward_scroll_data
next_spine_item.forward_scroll_data = None
if 0 < fsd.cols_left < cols_per_screen and cols_per_screen < number_of_cols:
scroll_to_column(fsd.current_col, duration=1000)
return True
def scroll_to_fraction(frac, on_initial_load):
# Scroll to the position represented by frac (number between 0 and 1)
if on_initial_load and frac is 1 and is_return() and scroll_to_previous_position():
return
xpos = Math.floor(scroll_viewport.paged_content_width() * frac)
scroll_to_xpos(xpos)
@ -283,6 +294,13 @@ def current_column_location():
c = column_at(current_scroll_offset() + 10)
return c * col_and_gap
def number_of_cols_left():
current_col = column_at(current_scroll_offset() + 10)
cols_left = number_of_cols - (current_col + cols_per_screen)
return Math.max(0, cols_left)
def next_screen_location():
# The position to scroll to for the next screen (which could contain
# more than one pages). Returns -1 if no further scrolling is possible.
@ -290,12 +308,8 @@ def next_screen_location():
return -1
cc = current_column_location()
ans = cc + screen_width
if cols_per_screen > 1:
current_col = column_at(current_scroll_offset() + 10)
ncols = (scroll_viewport.paged_content_width() + gap) // col_and_gap
cols_left = ncols - (current_col + cols_per_screen)
if cols_left < cols_per_screen:
return -1 # Only blank, dummy pages left
if cols_per_screen > 1 and 0 < number_of_cols_left() < cols_per_screen:
return -1 # Only blank, dummy pages left
limit = scroll_viewport.paged_content_width() - scroll_viewport.width()
if limit < col_and_gap:
return -1
@ -303,6 +317,7 @@ def next_screen_location():
ans = limit if Math.ceil(current_scroll_offset()) < limit else -1
return ans
def previous_screen_location():
# The position to scroll to for the previous screen (which could contain
# more than one pages). Returns -1 if no further scrolling is possible.
@ -316,6 +331,7 @@ def previous_screen_location():
ans = 0 if current_scroll_offset() > 15 else -1
return ans
def next_col_location():
# The position to scroll to for the next column (same as
# next_screen_location() if columns per screen == 1). Returns -1 if no
@ -330,6 +346,7 @@ def next_col_location():
ans = limit if Math.ceil(current_scroll_offset()) < limit else -1
return ans
def previous_col_location():
# The position to scroll to for the previous column (same as
# previous_screen_location() if columns per screen == 1). Returns -1 if
@ -342,6 +359,7 @@ def previous_col_location():
ans = 0 if Math.floor(current_scroll_offset()) > 0 else -1
return ans
def jump_to_anchor(name):
# Jump to the element identified by anchor name. Ensures that the left
# most column in the viewport is the column containing the start of the
@ -355,6 +373,7 @@ def jump_to_anchor(name):
return
scroll_to_elem(elem)
def scroll_to_elem(elem):
scroll_viewport.scroll_into_view(elem)
scroll_viewport.reset_transforms() # needed for viewport_to_document()
@ -459,6 +478,22 @@ def progress_frac(frac):
return Math.max(0, Math.min(window.pageYOffset / limit, 1))
def next_spine_item(backward):
if not backward:
csi = current_spine_item()
next_spine_item.forward_scroll_data = {
'cols_per_screen': cols_per_screen, 'cols_left': number_of_cols_left(),
'spine_index': csi.index, 'spine_name': csi.name, 'current_col': column_at(current_scroll_offset() + 10)
}
get_boss().send_message('next_spine_item', previous=backward)
def is_return():
fsd = next_spine_item.forward_scroll_data
csi = current_spine_item()
return fsd and fsd.cols_per_screen is cols_per_screen and fsd.spine_index is csi.index and fsd.spine_name is csi.name
def onwheel(evt):
if evt.deltaY:
backward = evt.deltaY < 0
@ -467,7 +502,7 @@ def onwheel(evt):
else:
x = previous_col_location() if backward else next_col_location()
if x is -1:
get_boss().send_message('next_spine_item', previous=backward)
next_spine_item(backward)
else:
scroll_to_xpos(x)
@ -481,7 +516,7 @@ def scroll_by_page(backward, by_screen):
if pos is -1:
# dont report human scroll since we dont know if a full page was
# scrolled or not
get_boss().send_message('next_spine_item', previous=backward)
next_spine_item(backward)
else:
if not backward:
scrolled_frac = (pages / number_of_cols) if number_of_cols > 0 else 0