Hide non-linear fragments

Add option to hide (skip) non-linear fragments, only working
in 1-page mode. Tweaks mostly to footer, toc and skim code
to make it clear(er) which pages belong to linear or non-linear
fragments.
This commit is contained in:
Jellby
2020-10-31 10:40:36 +01:00
committed by poire-z
parent f892d4559f
commit 5e3c554dd7
12 changed files with 600 additions and 60 deletions

View File

@@ -58,6 +58,11 @@ local CreDocument = Document:new{
default_css = "./data/cr3.css",
provider = "crengine",
provider_name = "Cool Reader Engine",
hide_nonlinear_flows = false,
flows = {},
page_in_flow = {},
last_linear_page = nil,
}
-- NuPogodi, 20.05.12: inspect the zipfile content
@@ -283,10 +288,188 @@ function CreDocument:updateColorRendering()
end
end
function CreDocument:setHideNonlinearFlows(hide_nonlinear_flows)
if hide_nonlinear_flows ~= self.hide_nonlinear_flows then
self.hide_nonlinear_flows = hide_nonlinear_flows
self._document:setIntProperty("crengine.doc.nonlinear.pagebreak.force", self.hide_nonlinear_flows and 1 or 0)
end
end
function CreDocument:getPageCount()
return self._document:getPages()
end
-- Whether the document has any non-linear flow to care about
function CreDocument:hasNonLinearFlows()
return self._document:hasNonLinearFlows()
end
-- Whether non-linear flows (if any) will be hidden
function CreDocument:hasHiddenFlows()
return self.flows[1] ~= nil
end
-- Get the next/prev page number, skipping non-linear flows,
-- i.e. the next/prev page that is either in the current
-- flow or in the linear flow (flow 0)
-- If "page" is 0, these give the initial and final linear pages
function CreDocument:getNextPage(page)
if self:hasHiddenFlows() then
if page < 0 or page >= self:getPageCount() then
return 0
elseif page == 0 then
return self:getFirstPageInFlow(0)
end
local flow = self:getPageFlow(page)
local start_page = page + 1
local end_page = self:getLastLinearPage()
local test_page = start_page
-- max to ensure at least one iteration
-- (in case the current flow goes after all linear pages)
while test_page <= math.max(end_page, start_page) do
local test_page_flow = self:getPageFlow(test_page)
if test_page_flow == flow or test_page_flow == 0 then
-- same flow as current, or linear flow, this is a "good" page
return test_page
elseif test_page_flow > 0 then
-- some other non-linear flow, skip all pages in this flow
test_page = test_page + self:getTotalPagesInFlow(test_page_flow)
else
-- went beyond the last page
break
end
end
return 0
else
return Document.getNextPage(self, page)
end
end
function CreDocument:getPrevPage(page)
if self:hasHiddenFlows() then
if page < 0 or page > self:getPageCount() then
return 0
elseif page == 0 then
return self:getLastLinearPage()
end
local flow = self:getPageFlow(page)
local start_page = page - 1
local end_page = self:getFirstPageInFlow(0)
local test_page = start_page
-- min to ensure at least one iteration
-- (in case the current flow goes before all linear pages)
while test_page >= math.min(end_page, start_page) do
local test_page_flow = self:getPageFlow(test_page)
if test_page_flow == flow or test_page_flow == 0 then
-- same flow as current, or linear flow, this is a "good" page
return test_page
elseif test_page_flow > 0 then
-- some other non-linear flow, skip all pages in this flow
test_page = self:getFirstPageInFlow(test_page_flow) - 1
else
-- went beyond the first page
break
end
end
return 0
else
return Document.getPrevPage(self, page)
end
end
function CreDocument:getPageFlow(page)
-- Only report non-linear pages if "hide_nonlinear_flows" is enabled, and in 1-page mode,
-- otherwise all pages are linear (flow 0)
if self.hide_nonlinear_flows and self._view_mode == self.PAGE_VIEW_MODE and self:getVisiblePageCount() == 1 then
return self._document:getPageFlow(page)
else
return 0
end
end
function CreDocument:getLastLinearPage()
return self.last_linear_page
end
function CreDocument:getFirstPageInFlow(flow)
return self.flows[flow][1]
end
function CreDocument:getTotalPagesInFlow(flow)
return self.flows[flow][2]
end
function CreDocument:getPageNumberInFlow(page)
if self:hasHiddenFlows() then
return self.page_in_flow[page]
else
return page
end
end
function CreDocument:cacheFlows()
-- Build the cache tables "flows" and "page_in_flow", if there are
-- any non-linear flows in the source document. Also set the value
-- of "last_linear_page", to possibly speed up counting in documents
-- with many non-linear pages at the end.
-- flows[i] contains {ini, num}, where ini is the first page in flow i,
-- and num is the total number of pages in the flow.
-- page_in_flow[i] contains the number of page i with its flow.
--
-- So, flows[0][1] is the first page in the linear flow,
-- and page_in_flow[flows[0][1]] must be 1, because it is the first
self.flows = {}
self.page_in_flow = {}
if self:hasNonLinearFlows() and self.hide_nonlinear_flows then
for i=1,self:getPageCount() do
local flow = self:getPageFlow(i)
if self.flows[flow] ~= nil then
self.flows[flow][2] = self.flows[flow][2]+1
else
self.flows[flow] = {i, 1}
end
self.page_in_flow[i] = self.flows[flow][2]
if flow == 0 then
self.last_linear_page = i
end
end
else
self.last_linear_page = self:getPageCount()
self.flows[0] = {1, self.last_linear_page}
end
end
function CreDocument:getTotalPagesLeft(page)
if self:hasHiddenFlows() then
local pages_left
local last_linear = self:getLastLinearPage()
if page > last_linear then
-- If beyond the last linear page, count only the pages in the current flow
local flow = self:getPageFlow(page)
pages_left = self:getTotalPagesInFlow(flow) - self:getPageNumberInFlow(page)
else
-- Otherwise, count all pages until the last linear,
-- except the flows that start (and end) between
-- the current page and the last linear
pages_left = last_linear - page
for flow, tab in ipairs(self.flows) do
-- tab[1] is the initial page of the flow
-- tab[2] is the total number of pages in the flow
if tab[1] > last_linear then
break
end
-- strict >, to make sure we include pages in the current flow
if tab[1] > page then
pages_left = pages_left - tab[2]
end
end
end
return pages_left
else
return Document.getTotalPagesLeft(self, page)
end
end
function CreDocument:getCoverPageImage()
-- no need to render document in order to get cover image
if not self:loadDocument() then
@@ -578,7 +761,7 @@ function CreDocument:gotoPos(pos)
end
function CreDocument:gotoPage(page)
logger.dbg("CreDocument: goto page", page)
logger.dbg("CreDocument: goto page", page, "flow", self:getPageFlow(page))
self._document:gotoPage(page)
end
@@ -766,6 +949,9 @@ function CreDocument:setViewMode(new_mode)
self._view_mode = self.PAGE_VIEW_MODE
end
self._document:setViewMode(self._view_mode)
if self.hide_nonlinear_flows then
self:cacheFlows()
end
end
end
@@ -1272,6 +1458,7 @@ function CreDocument:setupCallCache()
elseif name:sub(1,6) == "enable" then add_reset = true
elseif name == "zoomFont" then add_reset = true -- not used by koreader
elseif name == "resetCallCache" then add_reset = true
elseif name == "cacheFlows" then add_reset = true
-- These may have crengine do native highlight or unhighlight
-- (we could keep the original buffer and use a scratch buffer while
@@ -1313,6 +1500,11 @@ function CreDocument:setupCallCache()
elseif name == "getCacheFilePath" then no_wrap = true
elseif name == "getStatistics" then no_wrap = true
elseif name == "getNormalizedXPointer" then no_wrap = true
elseif name == "getNextPage" then no_wrap = true
elseif name == "getPrevPage" then no_wrap = true
elseif name == "getPageFlow" then no_wrap = true
elseif name == "getPageNumberInFlow" then no_wrap = true
elseif name == "getTotalPagesLeft" then no_wrap = true
-- Some get* have different results by page/pos
elseif name == "getLinkFromPosition" then cache_by_tag = true