From 7e04c97b70d8ef9bf3c5b7091952790809135456 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 2 Dec 2012 15:14:02 +0800 Subject: [PATCH 1/4] bug fix for PdfDocument:getUsedBBox when cache found, we should return cache.ubbox not cache.data --- frontend/document/pdfdocument.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/document/pdfdocument.lua b/frontend/document/pdfdocument.lua index 1dc1c9a06..7ad1c2a82 100644 --- a/frontend/document/pdfdocument.lua +++ b/frontend/document/pdfdocument.lua @@ -37,12 +37,15 @@ function PdfDocument:getUsedBBox(pageno) local hash = "pgubbox|"..self.file.."|"..pageno local cached = Cache:check(hash) if cached then - return cached.data + return cached.ubbox end local page = self._document:openPage(pageno) local used = {} used.x, used.y, used.w, used.h = page:getUsedBBox() - Cache:insert(hash, CacheItem:new{ used }) + --@TODO give size for cacheitem? 02.12 2012 (houqp) + Cache:insert(hash, CacheItem:new{ + ubbox = used, + }) page:close() return used end From 7b707ab367ba7eaa0312130fd99734b1f940a618 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 2 Dec 2012 17:09:32 +0800 Subject: [PATCH 2/4] add usedbbox support --- frontend/document/document.lua | 30 ++++++++++++++++++++++++++-- frontend/document/pdfdocument.lua | 2 +- frontend/ui/geometry.lua | 9 +++++++++ frontend/ui/reader/readerview.lua | 30 +++++++++++++++++++++------- frontend/ui/reader/readerzooming.lua | 8 +++++--- 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index bcd280a9d..cd73f22ef 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -124,6 +124,20 @@ function Document:getPageDimensions(pageno, zoom, rotation) return native_dimen end +function Document:getUsedBBoxDimensions(pageno, zoom, rotation) + ubbox = self:getUsedBBox(pageno) + ubbox_dimen = Geom:new{ + x = ubbox.x0, + y = ubbox.y0, + w = ubbox.x1 - ubbox.x0, + h = ubbox.y1 - ubbox.y0, + } + if zoom ~= 1 then + ubbox_dimen:transformByScale(zoom) + end + return ubbox_dimen +end + function Document:getToc() return self._document:getToc() end @@ -185,6 +199,14 @@ function Document:hintPage(pageno, zoom, rotation) self:renderPage(pageno, nil, zoom, rotation) end +--[[ +Draw page content to blitbuffer. +1. find tile in cache +2. if not found, call renderPage + +@target: target blitbuffer +@rect: visible_area inside document page +--]] function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, render_mode) local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation local hash_excerpt = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..tostring(rect) @@ -196,8 +218,12 @@ function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, render_mo tile = self:renderPage(pageno, rect, zoom, rotation, render_mode) end end - DEBUG("now painting", tile) - target:blitFrom(tile.bb, x, y, rect.x - tile.excerpt.x, rect.y - tile.excerpt.y, rect.w, rect.h) + DEBUG("now painting", tile, rect) + target:blitFrom(tile.bb, + x, y, + rect.x - tile.excerpt.x, + rect.y - tile.excerpt.y, + rect.w, rect.h) end function Document:drawCurrentView(target, x, y, rect, pos) diff --git a/frontend/document/pdfdocument.lua b/frontend/document/pdfdocument.lua index 7ad1c2a82..17d2eb4df 100644 --- a/frontend/document/pdfdocument.lua +++ b/frontend/document/pdfdocument.lua @@ -41,7 +41,7 @@ function PdfDocument:getUsedBBox(pageno) end local page = self._document:openPage(pageno) local used = {} - used.x, used.y, used.w, used.h = page:getUsedBBox() + used.x0, used.y0, used.x1, used.y1 = page:getUsedBBox() --@TODO give size for cacheitem? 02.12 2012 (houqp) Cache:insert(hash, CacheItem:new{ ubbox = used, diff --git a/frontend/ui/geometry.lua b/frontend/ui/geometry.lua index 1a45936a4..dfbace15d 100644 --- a/frontend/ui/geometry.lua +++ b/frontend/ui/geometry.lua @@ -65,6 +65,15 @@ function Geom:scaleBy(zx, zy) return self end +--[[ +this method also takes care of x and y +]]-- +function Geom:transformByScale(zx, zy) + self.x = self.x * zx + self.y = self.y * (zx or zy) + self:scaleBy(zx, zy) +end + --[[ enlarges or shrinks dimensions or rectangles diff --git a/frontend/ui/reader/readerview.lua b/frontend/ui/reader/readerview.lua index 42751c9ea..4e8a01eba 100644 --- a/frontend/ui/reader/readerview.lua +++ b/frontend/ui/reader/readerview.lua @@ -13,7 +13,9 @@ ReaderView = WidgetContainer:new{ -- DjVu page rendering mode (used in djvu.c:drawPage()) render_mode = 0, -- default to COLOR + -- visible area within current viewing page visible_area = Geom:new{x = 0, y = 0}, + -- dimen for current viewing page page_area = Geom:new{}, } @@ -56,12 +58,22 @@ function ReaderView:paintTo(bb, x, y) end function ReaderView:recalculate() + local page_size = nil if self.ui.document.info.has_pages then - local page_size = self.ui.document:getPageDimensions( - self.state.page, self.state.zoom, self.state.rotation) - -- TODO: bbox - self.page_area = page_size - + if not self.bbox then + self.page_area = self.ui.document:getPageDimensions( + self.state.page, + self.state.zoom, + self.state.rotation) + else + self.page_area = self.ui.document:getUsedBBoxDimensions( + self.state.page, + self.state.zoom, + self.state.rotation) + end + -- starts from left top of page_area + self.visible_area.x = self.page_area.x + self.visible_area.y = self.page_area.y -- reset our size self.visible_area:setSizeTo(self.dimen) -- and recalculate it according to page size @@ -80,8 +92,8 @@ function ReaderView:PanningUpdate(dx, dy) if self.visible_area ~= old then -- flag a repaint UIManager:setDirty(self.dialog) - DEBUG(self.page_area) - DEBUG(self.visible_area) + DEBUG("on pan: page_area", self.page_area) + DEBUG("on pan: visible_area", self.visible_area) end return true end @@ -111,6 +123,10 @@ function ReaderView:onZoomUpdate(zoom) self:recalculate() end +function ReaderView:onBBoxUpdate(bbox) + self.bbox = bbox +end + function ReaderView:onRotationUpdate(rotation) self.state.rotation = rotation self:recalculate() diff --git a/frontend/ui/reader/readerzooming.lua b/frontend/ui/reader/readerzooming.lua index ad891290d..b2a42f1a7 100644 --- a/frontend/ui/reader/readerzooming.lua +++ b/frontend/ui/reader/readerzooming.lua @@ -59,11 +59,13 @@ function ReaderZooming:setZoom() if self.zoom_mode == "content" or self.zoom_mode == "contentwidth" or self.zoom_mode == "contentheight" then - -- TODO: enable this, still incomplete - page_size = self.ui.document:getUsedBBox(self.current_page) - self.view:handleEvent(Event:new("BBoxUpdate", page_size)) + ubbox_dimen = self.ui.document:getUsedBBoxDimensions(self.current_page, 1) + --self.view:handleEvent(Event:new("BBoxUpdate", page_size)) + self.view:onBBoxUpdate(ubbox_dimen) + page_size = ubbox_dimen else -- otherwise, operate on full page + self.view:onBBoxUpdate(nil) page_size = self.ui.document:getNativePageDimensions(self.current_page) end -- calculate zoom value: From ae1c489a0fb94317bef1fa5a60b4d320af4f8ea6 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 3 Dec 2012 13:48:41 +0800 Subject: [PATCH 3/4] implement full pageturn by viewport for all modes * add notIntersectWith method for Geom * add math.roundAwayFromZero in geometry.lua * Readerview:recalculate now signals ViewRecalculate event. For now, this event is only usefull for ReaderPaging --- frontend/ui/geometry.lua | 30 +++++++++++++++ frontend/ui/reader/readerpaging.lua | 57 +++++++++++++++++++++++++++- frontend/ui/reader/readerview.lua | 3 +- frontend/ui/reader/readerzooming.lua | 33 ++++++++++------ 4 files changed, 108 insertions(+), 15 deletions(-) diff --git a/frontend/ui/geometry.lua b/frontend/ui/geometry.lua index dfbace15d..b50a07d85 100644 --- a/frontend/ui/geometry.lua +++ b/frontend/ui/geometry.lua @@ -137,6 +137,19 @@ function Geom:intersect(rect_b) return intersected end +--[[ +return true if self does not share any area with rect_b +]]-- +function Geom:notIntersectWith(rect_b) + if (self.x >= (rect_b.x + rect_b.w)) + or (self.y >= (rect_b.y + rect_b.h)) + or (rect_b.x >= (self.x + self.w)) + or (rect_b.y >= (self.y + self.h)) then + return true + end + return false +end + --[[ set size of dimension or rectangle to size of given dimension/rectangle ]]-- @@ -245,3 +258,20 @@ function Geom:offsetWithin(rect_b, dx, dy) self.y = rect_b.y + rect_b.h - self.h end end + + + + +--[[ +Simple math helper function +]]-- + +function math.roundAwayFromZero(num) + if num > 0 then + return math.ceil(num) + else + return math.floor(num) + end +end + + diff --git a/frontend/ui/reader/readerpaging.lua b/frontend/ui/reader/readerpaging.lua index c41481314..828ab6be1 100644 --- a/frontend/ui/reader/readerpaging.lua +++ b/frontend/ui/reader/readerpaging.lua @@ -1,6 +1,8 @@ ReaderPaging = InputContainer:new{ current_page = 0, - number_of_pages = 0 + number_of_pages = 0, + visible_area = nil, + page_area = nil, } function ReaderPaging:init() @@ -85,10 +87,21 @@ function ReaderPaging:onReadSettings(config) self:gotoPage(config:readSetting("last_page") or 1) end +function ReaderPaging:onZoomModeUpdate(new_mode) + -- we need to remember zoom mode to handle page turn event + self.zoom_mode = new_mode +end + function ReaderPaging:onPageUpdate(new_page_no) self.current_page = new_page_no end +function ReaderPaging:onViewRecalculate(visible_area, page_area) + -- we need to remember areas to handle page turn event + self.visible_area = visible_area + self.page_area = page_area +end + function ReaderPaging:onGotoPercent(percent) DEBUG("goto document offset in percent:", percent) local dest = math.floor(self.number_of_pages * percent / 100) @@ -102,7 +115,47 @@ end function ReaderPaging:onGotoPageRel(diff) DEBUG("goto relative page:", diff) - self:gotoPage(self.current_page + diff) + local new_va = self.visible_area:copy() + local x_pan_off, y_pan_off = 0, 0 + + if self.zoom_mode:find("width") then + y_pan_off = self.visible_area.h * diff + elseif self.zoom_mode:find("height") then + x_pan_off = self.visible_area.w * diff + else + -- must be fit content or page zoom mode + if self.visible_area.w == self.page_area.w then + y_pan_off = self.visible_area.h * diff + else + x_pan_off = self.visible_area.w * diff + end + end + + -- adjust offset to help with page turn decision + x_pan_off = math.roundAwayFromZero(x_pan_off) + y_pan_off = math.roundAwayFromZero(y_pan_off) + new_va.x = math.roundAwayFromZero(self.visible_area.x+x_pan_off) + new_va.y = math.roundAwayFromZero(self.visible_area.y+y_pan_off) + + if (new_va:notIntersectWith(self.page_area)) then + self:gotoPage(self.current_page + diff) + -- if we are going back to previous page, reset + -- view to bottom of previous page + if x_pan_off < 0 then + self.view:PanningUpdate(self.page_area.w, 0) + elseif y_pan_off < 0 then + self.view:PanningUpdate(0, self.page_area.h) + end + else + -- fit new view area into page area + new_va:offsetWithin(self.page_area, 0, 0) + self.view:PanningUpdate( + new_va.x - self.visible_area.x, + new_va.y - self.visible_area.y) + -- update self.visible_area + self.visible_area = new_va + end + return true end diff --git a/frontend/ui/reader/readerview.lua b/frontend/ui/reader/readerview.lua index 4e8a01eba..e0662c471 100644 --- a/frontend/ui/reader/readerview.lua +++ b/frontend/ui/reader/readerview.lua @@ -46,7 +46,6 @@ function ReaderView:paintTo(bb, x, y) self.state.zoom, self.state.rotation, self.render_mode) - self:recalculate() else self.ui.document:drawCurrentView( bb, @@ -81,6 +80,8 @@ function ReaderView:recalculate() else self.visible_area:setSizeTo(self.dimen) end + self.ui:handleEvent( + Event:new("ViewRecalculate", self.visible_area, self.page_area)) -- flag a repaint so self:paintTo will be called UIManager:setDirty(self.dialog) end diff --git a/frontend/ui/reader/readerzooming.lua b/frontend/ui/reader/readerzooming.lua index b2a42f1a7..f2324d175 100644 --- a/frontend/ui/reader/readerzooming.lua +++ b/frontend/ui/reader/readerzooming.lua @@ -2,35 +2,43 @@ ReaderZooming = InputContainer:new{ key_events = { ZoomIn = { { "Shift", Input.group.PgFwd }, - doc = "zoom in", event = "Zoom", args = "in" + doc = "zoom in", + event = "Zoom", args = "in" }, ZoomOut = { { "Shift", Input.group.PgBack }, - doc = "zoom out", event = "Zoom", args = "out" + doc = "zoom out", + event = "Zoom", args = "out" }, ZoomToFitPage = { { "A" }, - doc = "zoom to fit page", event = "SetZoomMode", args = "page" + doc = "zoom to fit page", + event = "SetZoomMode", args = "page" }, ZoomToFitContent = { { "Shift", "A" }, - doc = "zoom to fit content", event = "SetZoomMode", args = "content" + doc = "zoom to fit content", + event = "SetZoomMode", args = "content" }, ZoomToFitPageWidth = { { "S" }, - doc = "zoom to fit page width", event = "SetZoomMode", args = "pagewidth" + doc = "zoom to fit page width", + event = "SetZoomMode", args = "pagewidth" }, ZoomToFitContentWidth = { { "Shift", "S" }, - doc = "zoom to fit content width", event = "SetZoomMode", args = "contentwidth" + doc = "zoom to fit content width", + event = "SetZoomMode", args = "contentwidth" }, ZoomToFitPageHeight = { { "D" }, - doc = "zoom to fit page height", event = "SetZoomMode", args = "pageheight" + doc = "zoom to fit page height", + event = "SetZoomMode", args = "pageheight" }, ZoomToFitContentHeight = { { "Shift", "D" }, - doc = "zoom to fit content height", event = "SetZoomMode", args = "contentheight" + doc = "zoom to fit content height", + event = "SetZoomMode", args = "contentheight" }, }, zoom = 1.0, @@ -103,11 +111,12 @@ function ReaderZooming:onZoom(direction) return true end -function ReaderZooming:onSetZoomMode(what) - if self.zoom_mode ~= what then - DEBUG("setting zoom mode to", what) - self.zoom_mode = what +function ReaderZooming:onSetZoomMode(new_mode) + if self.zoom_mode ~= new_mode then + DEBUG("setting zoom mode to", new_mode) + self.zoom_mode = new_mode self:setZoom() + self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode)) end return true end From d077bafb6d189ccc7733531567cfb8fa210edc50 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 4 Dec 2012 15:19:50 +0800 Subject: [PATCH 4/4] fix bug no default zoom mode bug in readerpaging reported by @chrox, see #647 --- frontend/ui/reader/readerpaging.lua | 16 +++--- frontend/ui/reader/readerzooming.lua | 77 ++++++++++++++++++---------- frontend/ui/readerui.lua | 14 ++--- 3 files changed, 65 insertions(+), 42 deletions(-) diff --git a/frontend/ui/reader/readerpaging.lua b/frontend/ui/reader/readerpaging.lua index 828ab6be1..2fd6d864e 100644 --- a/frontend/ui/reader/readerpaging.lua +++ b/frontend/ui/reader/readerpaging.lua @@ -65,6 +65,14 @@ function ReaderPaging:init() self.number_of_pages = self.ui.document.info.number_of_pages end +function ReaderPaging:onReadSettings(config) + self:gotoPage(config:readSetting("last_page") or 1) +end + +function ReaderPaging:onCloseDocument() + self.ui.doc_settings:saveSetting("last_page", self.current_page) +end + -- wrapper for bounds checking function ReaderPaging:gotoPage(number) if number == self.current_page then @@ -83,10 +91,6 @@ function ReaderPaging:gotoPage(number) return true end -function ReaderPaging:onReadSettings(config) - self:gotoPage(config:readSetting("last_page") or 1) -end - function ReaderPaging:onZoomModeUpdate(new_mode) -- we need to remember zoom mode to handle page turn event self.zoom_mode = new_mode @@ -159,10 +163,6 @@ function ReaderPaging:onGotoPageRel(diff) return true end -function ReaderPaging:onCloseDocument() - self.ui.doc_settings:saveSetting("last_page", self.current_page) -end - function ReaderPaging:onTapForward() self:onGotoPageRel(1) return true diff --git a/frontend/ui/reader/readerzooming.lua b/frontend/ui/reader/readerzooming.lua index f2324d175..b7a911fbd 100644 --- a/frontend/ui/reader/readerzooming.lua +++ b/frontend/ui/reader/readerzooming.lua @@ -42,14 +42,32 @@ ReaderZooming = InputContainer:new{ }, }, zoom = 1.0, - zoom_mode = "free", + -- default to nil so we can trigger ZoomModeUpdate events on start up + zoom_mode = nil, + DEFAULT_ZOOM_MODE = "page", current_page = 1, rotation = 0 } +function ReaderZooming:onReadSettings(config) + -- @TODO config file from old code base uses globalzoom_mode + -- instead of zoom_mode, we need to handle this imcompatibility + -- 04.12 2012 (houqp) + local zoom_mode = config:readSetting("zoom_mode") + if not zoom_mode then + zoom_mode = self.DEFAULT_ZOOM_MODE + end + self:onSetZoomMode(zoom_mode) +end + +function ReaderZooming:onCloseDocument() + self.ui.doc_settings:saveSetting("zoom_mode", self.zoom_mode) +end + function ReaderZooming:onSetDimensions(dimensions) -- we were resized self.dimen = dimensions + self:setZoom() end function ReaderZooming:onRotationUpdate(rotation) @@ -57,11 +75,42 @@ function ReaderZooming:onRotationUpdate(rotation) self:setZoom() end +function ReaderZooming:onZoom(direction) + DEBUG("zoom", direction) + if direction == "in" then + self.zoom = self.zoom * 1.333333 + elseif direction == "out" then + self.zoom = self.zoom * 0.75 + end + DEBUG("zoom is now at", self.zoom) + self:onSetZoomMode("free") + self.view:onZoomUpdate(self.zoom) + return true +end + +function ReaderZooming:onSetZoomMode(new_mode) + if self.zoom_mode ~= new_mode then + DEBUG("setting zoom mode to", new_mode) + self.zoom_mode = new_mode + self:setZoom() + self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode)) + end + return true +end + +function ReaderZooming:onPageUpdate(new_page_no) + self.current_page = new_page_no + self:setZoom() +end + function ReaderZooming:setZoom() -- nothing to do in free zoom mode if self.zoom_mode == "free" then return end + if not self.dimen then + self.dimen = self.ui.dimen + end -- check if we're in bbox mode and work on bbox if that's the case local page_size = {} if self.zoom_mode == "content" @@ -98,30 +147,4 @@ function ReaderZooming:setZoom() self.view:onZoomUpdate(self.zoom) end -function ReaderZooming:onZoom(direction) - DEBUG("zoom", direction) - if direction == "in" then - self.zoom = self.zoom * 1.333333 - elseif direction == "out" then - self.zoom = self.zoom * 0.75 - end - DEBUG("zoom is now at", self.zoom) - self:onSetZoomMode("free") - self.view:onZoomUpdate(self.zoom) - return true -end -function ReaderZooming:onSetZoomMode(new_mode) - if self.zoom_mode ~= new_mode then - DEBUG("setting zoom mode to", new_mode) - self.zoom_mode = new_mode - self:setZoom() - self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode)) - end - return true -end - -function ReaderZooming:onPageUpdate(new_page_no) - self.current_page = new_page_no - self:setZoom() -end diff --git a/frontend/ui/readerui.lua b/frontend/ui/readerui.lua index fad05ace1..dc0a2c1a2 100644 --- a/frontend/ui/readerui.lua +++ b/frontend/ui/readerui.lua @@ -69,6 +69,13 @@ function ReaderUI:init() if self.document.info.has_pages then -- for page specific controller + -- if needed, insert a paging container + local pager = ReaderPaging:new{ + dialog = self.dialog, + view = self[1], + ui = self + } + table.insert(self, pager) -- zooming controller local zoomer = ReaderZooming:new{ dialog = self.dialog, @@ -83,13 +90,6 @@ function ReaderUI:init() ui = self } table.insert(self, panner) - -- if needed, insert a paging container - local pager = ReaderPaging:new{ - dialog = self.dialog, - view = self[1], - ui = self - } - table.insert(self, pager) else -- rolling controller local roller = ReaderRolling:new{