From 3dbf9877bc68268e7969e3f81f0b3108b87bda29 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Thu, 8 Mar 2012 23:28:16 +0800 Subject: [PATCH 01/28] add: 90 degree rotation support demo for issue #51 --- filechooser.lua | 18 +++++++++++++----- filesearcher.lua | 12 ++++++++++++ keys.lua | 34 ++++++++++++++++++++-------------- reader.lua | 12 ++++++++---- unireader.lua | 34 ++++++++++++++++++++++++++++++++-- 5 files changed, 85 insertions(+), 25 deletions(-) diff --git a/filechooser.lua b/filechooser.lua index c70b12613..865a0147f 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -200,11 +200,19 @@ function FileChooser:choose(ypos, height) pagedirty = true elseif ev.code == KEY_S then -- invoke search input keywords = InputBox:input(height-100, 100, "Search:") - if keywords then -- display search result according to keywords - FileSearcher:init( self.path ) - file = FileSearcher:choose(ypos, height, keywords) - if file then - return file + if keywords then + -- call FileSearcher + --[[ + This might looks a little bit dirty for using callback. + But I cannot come up with a better solution for renewing + the height arguemtn according to screen rotation mode. + + The callback might also be useful for calling system + settings menu in the future. + --]] + return nil, function() + FileSearcher:init( self.path ) + FileSearcher:choose(ypos, height, keywords) end end pagedirty = true diff --git a/filesearcher.lua b/filesearcher.lua index 814865d51..667f787f9 100644 --- a/filesearcher.lua +++ b/filesearcher.lua @@ -262,8 +262,20 @@ function FileSearcher:choose(ypos, height, keywords) elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then file_entry = self.result[perpage*(self.page-1)+self.current] file_full_path = file_entry.dir .. "/" .. file_entry.name + + -- rotation mode might be changed while reading, so + -- record height_percent here + local height_percent = height/fb.bb:getHeight() openFile(file_full_path) + --reset height and item index if screen has been rotated + local old_perpage = perpage + height = math.floor(fb.bb:getHeight()*height_percent) + perpage = math.floor(height / self.spacing) - 2 + self.current = (old_perpage * (self.page - 1) + + self.current) % perpage + self.page = math.floor(self.items / perpage) + 1 + pagedirty = true elseif ev.code == KEY_BACK or ev.code == KEY_HOME then return nil diff --git a/keys.lua b/keys.lua index a04c72e33..f7c6fe25a 100644 --- a/keys.lua +++ b/keys.lua @@ -178,26 +178,32 @@ function set_emu_keycodes() KEY_VMINUS = 96 -- F12 end +--@TODO rotation does not fit in key module, we should move it +-- to some other module in the future. 08.03 2012 +rotation_mode = {"Up","Right","Down","Left"} + function getRotationMode() --[[ return code for four kinds of rotation mode: - 0 for no rotation, + 0 for no rotation, 1 for landscape with bottom on the right side of screen, etc. - 2 - +-----------+ - | +-------+ | - | | | | - | | | | - | | | | - 3 | | | | 1 - | | | | - | | | | - | +-------+ | - | | - +-----------+ - 0 + 2 + +--------------+ + | +----------+ | + | | | | + | | Freedom! | | + | | | | + | | | | + 3 | | | | 1 + | | | | + | | | | + | +----------+ | + | | + | | + +--------------+ + 0 --]] if KEY_FW_DOWN == 116 then -- in EMU mode always return 0 return 0 diff --git a/reader.lua b/reader.lua index da64c633c..9d07f9d92 100755 --- a/reader.lua +++ b/reader.lua @@ -131,11 +131,15 @@ if ARGV[optind] and lfs.attributes(ARGV[optind], "mode") == "directory" then local running = true FileChooser:setPath(ARGV[optind]) while running do - local file = FileChooser:choose(0,height) - if file ~= nil then - running = openFile(file) + local file, callback = FileChooser:choose(0,height) + if callback then + callback() else - running = false + if file ~= nil then + running = openFile(file) + else + running = false + end end end elseif ARGV[optind] and lfs.attributes(ARGV[optind], "mode") == "file" then diff --git a/unireader.lua b/unireader.lua index c14f3e134..ef6adeffa 100644 --- a/unireader.lua +++ b/unireader.lua @@ -526,6 +526,28 @@ function UniReader:setrotate(rotate) self:goto(self.pageno) end +-- @ orien: 1 for clockwise rotate, -1 for anti-clockwise +function UniReader:screenRotate(orien) + if orien == "clockwise" then + orien = 1 + elseif orien == "anticlockwise" then + orien = -1 + else + return + end + + fb:close() + local mode = rotation_mode[(getRotationMode()+1*orien)%4 + 1] + os.execute("lipc-send-event -r 3 com.lab126.hal orientation"..mode) + fb = einkfb.open("/dev/fb0") + width, height = fb:getSize() + + self:clearcache() + --@TODO write a sleep in util module to replace it 08.03 2012 + os.execute("sleep 2") + self:goto(self.pageno) +end + function UniReader:cleanUpTOCTitle(title) return title:gsub("\13", "") end @@ -688,9 +710,17 @@ function UniReader:inputloop() self:showJumpStack() end elseif ev.code == KEY_J then - self:setrotate( self.globalrotate + 10 ) + if Keys.shiftmode then + self:screenRotate("anticlockwise") + else + self:setrotate( self.globalrotate + 10 ) + end elseif ev.code == KEY_K then - self:setrotate( self.globalrotate - 10 ) + if Keys.shiftmode then + self:screenRotate("clockwise") + else + self:setrotate( self.globalrotate - 10 ) + end elseif ev.code == KEY_HOME then if Keys.shiftmode or Keys.altmode then -- signal quit From d2aaf15dce328402eee84d4ed282a6b07ac9a5f3 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Fri, 9 Mar 2012 09:40:46 +0800 Subject: [PATCH 02/28] add: screen.lua * move rotation mode to global variable, now check rotation with Screen.cur_rotation_mode * move screenRotate to screen module so other UIs can use it. --- keys.lua | 43 ++++--------------------------------------- reader.lua | 3 +++ unireader.lua | 13 +------------ 3 files changed, 8 insertions(+), 51 deletions(-) diff --git a/keys.lua b/keys.lua index f7c6fe25a..d6a3854af 100644 --- a/keys.lua +++ b/keys.lua @@ -178,41 +178,6 @@ function set_emu_keycodes() KEY_VMINUS = 96 -- F12 end ---@TODO rotation does not fit in key module, we should move it --- to some other module in the future. 08.03 2012 -rotation_mode = {"Up","Right","Down","Left"} - -function getRotationMode() - --[[ - return code for four kinds of rotation mode: - - 0 for no rotation, - 1 for landscape with bottom on the right side of screen, etc. - - 2 - +--------------+ - | +----------+ | - | | | | - | | Freedom! | | - | | | | - | | | | - 3 | | | | 1 - | | | | - | | | | - | +----------+ | - | | - | | - +--------------+ - 0 - --]] - if KEY_FW_DOWN == 116 then -- in EMU mode always return 0 - return 0 - end - orie_fd = assert(io.open("/sys/module/eink_fb_hal_broads/parameters/bs_orientation", "r")) - updown_fd = assert(io.open("/sys/module/eink_fb_hal_broads/parameters/bs_upside_down", "r")) - mode = orie_fd:read() + (updown_fd:read() * 2) - return mode -end function adjustKeyEvents(ev) if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then @@ -231,9 +196,9 @@ function adjustKeyEvents(ev) -- adjust five way key according to rotation mode local code = ev.code - if getRotationMode() == 0 then + if Screen.cur_rotation_mode == 1 then return code - elseif getRotationMode() == 1 then + elseif Screen.cur_rotation_mode == 2 then if code == KEY_FW_UP then return KEY_FW_RIGHT elseif code == KEY_FW_RIGHT then @@ -245,7 +210,7 @@ function adjustKeyEvents(ev) else return code end - elseif getRotationMode() == 2 then + elseif Screen.cur_rotation_mode == 3 then if code == KEY_FW_UP then return KEY_FW_DOWN elseif code == KEY_FW_RIGHT then @@ -257,7 +222,7 @@ function adjustKeyEvents(ev) else return code end - elseif getRotationMode() == 3 then + elseif Screen.cur_rotation_mode == 4 then if code == KEY_FW_UP then return KEY_FW_LEFT elseif code == KEY_FW_RIGHT then diff --git a/reader.lua b/reader.lua index 9d07f9d92..27ab1d335 100755 --- a/reader.lua +++ b/reader.lua @@ -22,6 +22,7 @@ require "pdfreader" require "djvureader" require "filechooser" require "settings" +require "screen" -- option parsing: longopts = { @@ -111,6 +112,8 @@ end fb = einkfb.open("/dev/fb0") width, height = fb:getSize() +-- read current rotation mode +Screen:updateRotationMode() -- set up reader's setting: font reader_settings = DocSettings:open(".reader") diff --git a/unireader.lua b/unireader.lua index ef6adeffa..ab04978be 100644 --- a/unireader.lua +++ b/unireader.lua @@ -528,18 +528,7 @@ end -- @ orien: 1 for clockwise rotate, -1 for anti-clockwise function UniReader:screenRotate(orien) - if orien == "clockwise" then - orien = 1 - elseif orien == "anticlockwise" then - orien = -1 - else - return - end - - fb:close() - local mode = rotation_mode[(getRotationMode()+1*orien)%4 + 1] - os.execute("lipc-send-event -r 3 com.lab126.hal orientation"..mode) - fb = einkfb.open("/dev/fb0") + Screen:screenRotate(orien) width, height = fb:getSize() self:clearcache() From f45671a7471a9279b655644ec4aa4ff9cbc62dd7 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Fri, 9 Mar 2012 09:44:22 +0800 Subject: [PATCH 03/28] fix: add screen.lua forgot to add it in previous commit :( --- screen.lua | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 screen.lua diff --git a/screen.lua b/screen.lua new file mode 100644 index 000000000..db5ccf4fe --- /dev/null +++ b/screen.lua @@ -0,0 +1,74 @@ +--[[ + Copyright (C) 2011 Hans-Werner Hilse + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +]]-- + +--[[ +Codes for rotation modes: + +1 for no rotation, +2 for landscape with bottom on the right side of screen, etc. + + 3 + +--------------+ + | +----------+ | + | | | | + | | Freedom! | | + | | | | + | | | | + 4 | | | | 2 + | | | | + | | | | + | +----------+ | + | | + | | + +--------------+ + 1 +--]] + + +Screen = { + rotation_modes = {"Up","Right","Down","Left"}, + cur_rotation_mode = 1, +} + +-- @ orien: 1 for clockwise rotate, -1 for anti-clockwise +function Screen:screenRotate(orien) + if orien == "clockwise" then + orien = 1 + elseif orien == "anticlockwise" then + orien = -1 + else + return + end + + fb:close() + self.cur_rotation_mode = (self.cur_rotation_mode-1 + 1*orien)%4 + 1 + local mode = self.rotation_modes[self.cur_rotation_mode] + os.execute("lipc-send-event -r 3 com.lab126.hal orientation"..mode) + fb = einkfb.open("/dev/fb0") +end + +function Screen:updateRotationMode() + if KEY_FW_DOWN == 116 then -- in EMU mode always set to 1 + self.cur_rotation_mode = 1 + else + orie_fd = assert(io.open("/sys/module/eink_fb_hal_broads/parameters/bs_orientation", "r")) + updown_fd = assert(io.open("/sys/module/eink_fb_hal_broads/parameters/bs_upside_down", "r")) + self.cur_rotation_mode = orie_fd:read() + (updown_fd:read() * 2) + 1 + end +end + + From 70b7e029d383e33df8fb4c3a00547d4069e7dd53 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Fri, 9 Mar 2012 10:41:31 +0800 Subject: [PATCH 04/28] mod: only get usedBBox in fit to content mode make fit to page mode a little bit faster --- unireader.lua | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/unireader.lua b/unireader.lua index ab04978be..92dd4805a 100644 --- a/unireader.lua +++ b/unireader.lua @@ -199,13 +199,17 @@ function UniReader:setzoom(page) local dc = self.newDC() local pwidth, pheight = page:getSize(self.nulldc) print("# page::getSize "..pwidth.."*"..pheight); - local x0, y0, x1, y1 = page:getUsedBBox() - if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then - x0 = 0 - y0 = 0 - x1 = pwidth - y1 = pheight + local x0, y0, x1, y1 = 0, 0, pwidth, pheight + + -- only get usedBBox in fit to content mode + if self.globalzoommode <= self.ZOOM_FIT_TO_CONTENT and + self.globalzoommode >= self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN then + x0, y0, x1, y1 = page:getUsedBBox() + if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then + x0, y0, x1, y1 = 0, 0, pwidth, pheight + end end + -- clamp to page BBox if x0 < 0 then x0 = 0 end if x1 > pwidth then x1 = pwidth end From f795bda6e07b90e4fe89015f2509be436914fb21 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Fri, 9 Mar 2012 14:06:05 +0800 Subject: [PATCH 05/28] mod: read cache settings from .reader.kpdfview.lua --- unireader.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/unireader.lua b/unireader.lua index 92dd4805a..2394f270a 100644 --- a/unireader.lua +++ b/unireader.lua @@ -132,6 +132,16 @@ function UniReader:initGlobalSettings(settings) if pan_overlap_vertical then self.pan_overlap_vertical = pan_overlap_vertical end + + local cache_max_memsize = settings:readsetting("cache_max_memsize") + if cache_max_memsize then + self.cache_max_memsize = cache_max_memsize + end + + local cache_max_ttl = settings:readsetting("cache_max_ttl") + if cache_max_ttl then + self.cache_max_ttl = cache_max_ttl + end end -- guarantee that we have enough memory in cache @@ -858,7 +868,6 @@ function UniReader:inputloop() self.settings:savesetting("last_page", self.pageno) self.settings:savesetting("gamma", self.globalgamma) self.settings:savesetting("jumpstack", self.jump_stack) - --self.settings:savesetting("pan_overlap_vertical", self.pan_overlap_vertical) self.settings:savesetting("bbox", self.bbox) self.settings:savesetting("globalzoom", self.globalzoom) self.settings:savesetting("globalzoommode", self.globalzoommode) From 319826c3855913a62586d2e7af1d4abf0ba3150d Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Fri, 9 Mar 2012 18:34:56 +0800 Subject: [PATCH 06/28] mod: screen rotation implemented by ioctl Now you get a instance rotate :) With only one bug. I have to restore to previous rotation state of the native system after exists. Because the native system does poll the new rotation state that changed by ioctl. Currently, I don't know how to force the native system to detect the changes. --- einkfb.c | 24 ++++++++++++++++++++++++ keys.lua | 31 +++++++++++++++++-------------- reader.lua | 5 +++++ screen.lua | 27 ++++++++++++++------------- unireader.lua | 7 ++----- 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/einkfb.c b/einkfb.c index 77cb5c867..4abb81b23 100644 --- a/einkfb.c +++ b/einkfb.c @@ -180,6 +180,29 @@ static int einkUpdate(lua_State *L) { return 0; } +/* NOTICE!!! You must close and reopen framebuffer after called this method. + * Otherwise, screen resolution will not be updated! */ +static int einkSetOrientation(lua_State *L) { +#ifndef EMULATE_READER + FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb"); + int mode = luaL_optint(L, 2, 0); + + if (mode < 0 || mode > 3) { + return luaL_error(L, "Wrong rotation mode %d given!", mode); + } + + /* ioctl has a different definition for rotation mode. */ + if (mode == 1) + mode = 2; + else if (mode == 2) + mode = 1; + + ioctl(fb->fd, FBIO_EINK_SET_DISPLAY_ORIENTATION, mode); +#endif + return 0; +} + + static const struct luaL_reg einkfb_func[] = { {"open", openFrameBuffer}, {NULL, NULL} @@ -189,6 +212,7 @@ static const struct luaL_reg einkfb_meth[] = { {"close", closeFrameBuffer}, {"__gc", closeFrameBuffer}, {"refresh", einkUpdate}, + {"setOrientation", einkSetOrientation}, {"getSize", getSize}, {NULL, NULL} }; diff --git a/keys.lua b/keys.lua index d6a3854af..cc630f09e 100644 --- a/keys.lua +++ b/keys.lua @@ -196,9 +196,9 @@ function adjustKeyEvents(ev) -- adjust five way key according to rotation mode local code = ev.code - if Screen.cur_rotation_mode == 1 then + if Screen.cur_rotation_mode == 0 then return code - elseif Screen.cur_rotation_mode == 2 then + elseif Screen.cur_rotation_mode == 1 then if code == KEY_FW_UP then return KEY_FW_RIGHT elseif code == KEY_FW_RIGHT then @@ -210,19 +210,19 @@ function adjustKeyEvents(ev) else return code end + elseif Screen.cur_rotation_mode == 2 then + if code == KEY_FW_UP then + return KEY_FW_DOWN + elseif code == KEY_FW_RIGHT then + return KEY_FW_LEFT + elseif code == KEY_FW_DOWN then + return KEY_FW_UP + elseif code == KEY_FW_LEFT then + return KEY_FW_RIGHT + else + return code + end elseif Screen.cur_rotation_mode == 3 then - if code == KEY_FW_UP then - return KEY_FW_DOWN - elseif code == KEY_FW_RIGHT then - return KEY_FW_LEFT - elseif code == KEY_FW_DOWN then - return KEY_FW_UP - elseif code == KEY_FW_LEFT then - return KEY_FW_RIGHT - else - return code - end - elseif Screen.cur_rotation_mode == 4 then if code == KEY_FW_UP then return KEY_FW_LEFT elseif code == KEY_FW_RIGHT then @@ -235,4 +235,7 @@ function adjustKeyEvents(ev) return code end end + -- This should not happen. + print("# Unrecognizable rotation mode "..Screen.cur_rotation_mode.."!") + return nil end diff --git a/reader.lua b/reader.lua index 27ab1d335..ae48c575e 100755 --- a/reader.lua +++ b/reader.lua @@ -114,6 +114,7 @@ fb = einkfb.open("/dev/fb0") width, height = fb:getSize() -- read current rotation mode Screen:updateRotationMode() +origin_rotation_mode = Screen.cur_rotation_mode -- set up reader's setting: font reader_settings = DocSettings:open(".reader") @@ -158,6 +159,10 @@ end reader_settings:savesetting("cfont", FontChooser.cfont) reader_settings:close() +-- @TODO dirty workaround, find a way to force native system poll +-- screen orientation and upside down mode 09.03 2012 +fb:setOrientation(origin_rotation_mode) + input.closeAll() --os.execute('test -e /proc/keypad && echo "send '..KEY_HOME..'" > /proc/keypad ') if optarg["d"] ~= "emu" then diff --git a/screen.lua b/screen.lua index db5ccf4fe..d587166d6 100644 --- a/screen.lua +++ b/screen.lua @@ -21,53 +21,54 @@ Codes for rotation modes: 1 for no rotation, 2 for landscape with bottom on the right side of screen, etc. - 3 + 2 +--------------+ | +----------+ | | | | | | | Freedom! | | | | | | | | | | - 4 | | | | 2 + 3 | | | | 1 | | | | | | | | | +----------+ | | | | | +--------------+ - 1 + 0 --]] Screen = { - rotation_modes = {"Up","Right","Down","Left"}, - cur_rotation_mode = 1, + cur_rotation_mode = 0, } -- @ orien: 1 for clockwise rotate, -1 for anti-clockwise function Screen:screenRotate(orien) if orien == "clockwise" then - orien = 1 - elseif orien == "anticlockwise" then orien = -1 + elseif orien == "anticlockwise" then + orien = 1 else return end + self.cur_rotation_mode = (self.cur_rotation_mode + orien) % 4 + fb:setOrientation(self.cur_rotation_mode) fb:close() - self.cur_rotation_mode = (self.cur_rotation_mode-1 + 1*orien)%4 + 1 - local mode = self.rotation_modes[self.cur_rotation_mode] - os.execute("lipc-send-event -r 3 com.lab126.hal orientation"..mode) + --local mode = self.rotation_modes[self.cur_rotation_mode] + --self.cur_rotation_mode = (self.cur_rotation_mode-1 + 1*orien)%4 + 1 + --os.execute("lipc-send-event -r 3 com.lab126.hal orientation"..mode) fb = einkfb.open("/dev/fb0") end function Screen:updateRotationMode() - if KEY_FW_DOWN == 116 then -- in EMU mode always set to 1 - self.cur_rotation_mode = 1 + if KEY_FW_DOWN == 116 then -- in EMU mode always set to 0 + self.cur_rotation_mode = 0 else orie_fd = assert(io.open("/sys/module/eink_fb_hal_broads/parameters/bs_orientation", "r")) updown_fd = assert(io.open("/sys/module/eink_fb_hal_broads/parameters/bs_upside_down", "r")) - self.cur_rotation_mode = orie_fd:read() + (updown_fd:read() * 2) + 1 + self.cur_rotation_mode = orie_fd:read() + (updown_fd:read() * 2) end end diff --git a/unireader.lua b/unireader.lua index 2394f270a..ac777cf5f 100644 --- a/unireader.lua +++ b/unireader.lua @@ -544,10 +544,7 @@ end function UniReader:screenRotate(orien) Screen:screenRotate(orien) width, height = fb:getSize() - self:clearcache() - --@TODO write a sleep in util module to replace it 08.03 2012 - os.execute("sleep 2") self:goto(self.pageno) end @@ -714,13 +711,13 @@ function UniReader:inputloop() end elseif ev.code == KEY_J then if Keys.shiftmode then - self:screenRotate("anticlockwise") + self:screenRotate("clockwise") else self:setrotate( self.globalrotate + 10 ) end elseif ev.code == KEY_K then if Keys.shiftmode then - self:screenRotate("clockwise") + self:screenRotate("anticlockwise") else self:setrotate( self.globalrotate - 10 ) end From 5237ba947d0efd0e5d1eb5a562d754350a2c1ee9 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Fri, 9 Mar 2012 18:45:55 +0800 Subject: [PATCH 07/28] fix: typo --- screen.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/screen.lua b/screen.lua index d587166d6..158d20a63 100644 --- a/screen.lua +++ b/screen.lua @@ -21,7 +21,7 @@ Codes for rotation modes: 1 for no rotation, 2 for landscape with bottom on the right side of screen, etc. - 2 + 2 +--------------+ | +----------+ | | | | | @@ -35,7 +35,7 @@ Codes for rotation modes: | | | | +--------------+ - 0 + 0 --]] @@ -54,6 +54,7 @@ function Screen:screenRotate(orien) end self.cur_rotation_mode = (self.cur_rotation_mode + orien) % 4 + -- you have to reopen framebuffer after rotate fb:setOrientation(self.cur_rotation_mode) fb:close() --local mode = self.rotation_modes[self.cur_rotation_mode] From f95231d789ad33cbbd5e8e257ecfc36cf75df14f Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 10 Mar 2012 16:41:23 +0800 Subject: [PATCH 08/28] add: status bar in reading menu & font.lua * Since fontchooser is replaced by selectmenu, it is no longer needed. So I rewrite it into font.lua module which can cache faces that shared among all UIs. * add progressBar method in graphics.lua to draw reading progress. * add reading progress information in reading menu. It is just a demo. Should be clean up in next release when the real reading menu is out. :) --- filechooser.lua | 46 +++++++++++------------------------------ filesearcher.lua | 53 ++++++++++++------------------------------------ font.lua | 47 ++++++++++++++++++++++++++++++++++++++++++ graphics.lua | 22 ++++++++++++++++++++ reader.lua | 5 ++--- screen.lua | 6 ++---- selectmenu.lua | 51 +++++++++++++++------------------------------- unireader.lua | 34 +++++++++++++++++++++++++++++++ 8 files changed, 148 insertions(+), 116 deletions(-) create mode 100644 font.lua diff --git a/filechooser.lua b/filechooser.lua index 865a0147f..ae24642c2 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -1,26 +1,13 @@ require "rendertext" require "keys" require "graphics" -require "fontchooser" +require "font" require "filesearcher" require "inputbox" require "selectmenu" FileChooser = { -- Class vars: - -- font for displaying toc item names - fsize = 25, - face = nil, - fhash = nil, - --face = freetype.newBuiltinFace("sans", 25), - --fhash = "s25", - - -- font for paging display - ffsize = 16, - fface = nil, - ffhash = nil, - --sface = freetype.newBuiltinFace("sans", 16), - --sfhash = "s16", -- spacing between lines spacing = 40, @@ -93,17 +80,6 @@ function FileChooser:setPath(newPath) end end -function FileChooser:updateFont() - if self.fhash ~= FontChooser.cfont..self.fsize then - self.face = freetype.newBuiltinFace(FontChooser.cfont, self.fsize) - self.fhash = FontChooser.cfont..self.fsize - end - if self.ffhash ~= FontChooser.ffont..self.ffsize then - self.fface = freetype.newBuiltinFace(FontChooser.ffont, self.ffsize) - self.ffhash = FontChooser.ffont..self.ffsize - end -end - function FileChooser:choose(ypos, height) local perpage = math.floor(height / self.spacing) - 2 local pagedirty = true @@ -139,7 +115,9 @@ function FileChooser:choose(ypos, height) end while true do - self:updateFont() + local cface, cfhash= Font:getFaceAndHash(25) + local fface, ffhash = Font:getFaceAndHash(16, Font.ffont) + if pagedirty then fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0) local c @@ -147,17 +125,17 @@ function FileChooser:choose(ypos, height) local i = (self.page - 1) * perpage + c if i <= #self.dirs then -- resembles display in midnight commander: adds "/" prefix for directories - renderUtf8Text(fb.bb, 39, ypos + self.spacing*c, self.face, self.fhash, "/", true) - renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, self.face, self.fhash, self.dirs[i], true) + renderUtf8Text(fb.bb, 39, ypos + self.spacing*c, cface, cfhash, "/", true) + renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, cface, cfhash, self.dirs[i], true) elseif i <= self.items then - renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, self.face, self.fhash, self.files[i-#self.dirs], true) + renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, cface, cfhash, self.files[i-#self.dirs], true) end end - renderUtf8Text(fb.bb, 5, ypos + self.spacing * perpage + 42, self.fface, self.ffhash, + renderUtf8Text(fb.bb, 5, ypos + self.spacing * perpage + 42, fface, ffhash, "Page "..self.page.." of "..(math.floor(self.items / perpage)+1), true) local msg = self.exception_message and self.exception_message:match("[^%:]+:%d+: (.*)") or "Path: "..self.path self.exception_message = nil - renderUtf8Text(fb.bb, 5, ypos + self.spacing * (perpage+1) + 27, self.fface, self.ffhash, msg, true) + renderUtf8Text(fb.bb, 5, ypos + self.spacing * (perpage+1) + 27, fface, ffhash, msg, true) markerdirty = true end if markerdirty then @@ -190,12 +168,12 @@ function FileChooser:choose(ypos, height) elseif ev.code == KEY_F then -- invoke fontchooser menu fonts_menu = SelectMenu:new{ menu_title = "Fonts Menu", - item_array = FontChooser.fonts, + item_array = Font.fonts, } local re = fonts_menu:choose(0, height) if re then - FontChooser.cfont = FontChooser.fonts[re] - FontChooser:init() + Font.cfont = Font.fonts[re] + Font:update() end pagedirty = true elseif ev.code == KEY_S then -- invoke search input diff --git a/filesearcher.lua b/filesearcher.lua index 667f787f9..0d8153cd4 100644 --- a/filesearcher.lua +++ b/filesearcher.lua @@ -1,22 +1,9 @@ require "rendertext" require "keys" require "graphics" -require "fontchooser" +require "font" FileSearcher = { - -- font for displaying toc item names - fsize = 25, - face = nil, - fhash = nil, - -- font for page title - tfsize = 30, - tface = nil, - tfhash = nil, - -- font for paging display - ffsize = 16, - fface = nil, - ffhash = nil, - -- title height title_H = 45, -- spacing between lines @@ -70,23 +57,6 @@ function FileSearcher:setPath(newPath) return true end -function FileSearcher:updateFont() - if self.fhash ~= FontChooser.cfont..self.fsize then - self.face = freetype.newBuiltinFace(FontChooser.cfont, self.fsize) - self.fhash = FontChooser.cfont..self.fsize - end - - if self.tfhash ~= FontChooser.tfont..self.tfsize then - self.tface = freetype.newBuiltinFace(FontChooser.tfont, self.tfsize) - self.tfhash = FontChooser.tfont..self.tfsize - end - - if self.ffhash ~= FontChooser.ffont..self.ffsize then - self.fface = freetype.newBuiltinFace(FontChooser.ffont, self.ffsize) - self.ffhash = FontChooser.ffont..self.ffsize - end -end - function FileSearcher:setSearchResult(keywords) self.result = {} if keywords == " " then -- one space to show all files @@ -153,22 +123,25 @@ function FileSearcher:choose(ypos, height, keywords) end while true do - self:updateFont() + local cface, cfhash = Font:getFaceAndHash(22) + local tface, tfhash = Font:getFaceAndHash(25, Font.tfont) + local fface, ffhash = Font:getFaceAndHash(16, Font.ffont) + if pagedirty then markerdirty = true fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0) -- draw menu title - renderUtf8Text(fb.bb, 30, ypos + self.title_H, self.tface, self.tfhash, + renderUtf8Text(fb.bb, 30, ypos + self.title_H, tface, tfhash, "Search Result for: "..keywords, true) -- draw results local c if self.items == 0 then -- nothing found y = ypos + self.title_H + self.spacing * 2 - renderUtf8Text(fb.bb, 20, y, self.face, self.fhash, + renderUtf8Text(fb.bb, 20, y, cface, cfhash, "Sorry, no match found.", true) - renderUtf8Text(fb.bb, 20, y + self.spacing, self.face, self.fhash, + renderUtf8Text(fb.bb, 20, y + self.spacing, cface, cfhash, "Please try a different keyword.", true) markerdirty = false else -- found something, draw it @@ -176,7 +149,7 @@ function FileSearcher:choose(ypos, height, keywords) local i = (self.page - 1) * perpage + c if i <= self.items then y = ypos + self.title_H + (self.spacing * c) - renderUtf8Text(fb.bb, 50, y, self.face, self.fhash, + renderUtf8Text(fb.bb, 50, y, cface, cfhash, self.result[i].name, true) end end @@ -186,7 +159,7 @@ function FileSearcher:choose(ypos, height, keywords) y = ypos + self.title_H + (self.spacing * perpage) + self.foot_H x = (fb.bb:getWidth() / 2) - 50 all_page = (math.floor(self.items / perpage)+1) - renderUtf8Text(fb.bb, x, y, self.fface, self.ffhash, + renderUtf8Text(fb.bb, x, y, fface, ffhash, "Page "..self.page.." of "..all_page, true) end @@ -251,12 +224,12 @@ function FileSearcher:choose(ypos, height, keywords) elseif ev.code == KEY_F then -- invoke fontchooser menu fonts_menu = SelectMenu:new{ menu_title = "Fonts Menu", - item_array = FontChooser.fonts, + item_array = Font.fonts, } local re = fonts_menu:choose(0, height) if re then - FontChooser.cfont = FontChooser.fonts[re] - FontChooser:init() + Font.cfont = Font.fonts[re] + Font:update() end pagedirty = true elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then diff --git a/font.lua b/font.lua new file mode 100644 index 000000000..9aadbb3b7 --- /dev/null +++ b/font.lua @@ -0,0 +1,47 @@ + +Font = { + -- default font for menu contents + cfont = "sans", + -- default font for title + tfont = "Helvetica-BoldOblique", + -- default font for footer + ffont = "sans", + + -- built in fonts + fonts = {"sans", "cjk", "mono", + "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", + "Helvetica", "Helvetica-Oblique", "Helvetica-BoldOblique", + "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",}, + + -- face table + faces = {}, +} + +function Font:getFaceAndHash(size, font) + if not font then + -- default to content font + font = self.cfont + end + + local face = self.faces[font..size] + -- build face if not found + if not face then + for _k,_v in ipairs(self.fonts) do + if font == _v then + face = freetype.newBuiltinFace(font, size) + self.faces[font..size] = face + end + end + if not face then + print("#! Font "..font.." not supported!!") + return nil + end + end + return face, font..size +end + +function Font:update() + self.faces = {} + clearglyphcache() +end + diff --git a/graphics.lua b/graphics.lua index e4b16efac..1ebb13cce 100644 --- a/graphics.lua +++ b/graphics.lua @@ -5,3 +5,25 @@ blitbuffer.paintBorder = function (bb, x, y, w, h, bw, c) bb:paintRect(x, y+bw, bw, h - 2*bw, c) bb:paintRect(x+w-bw, y+bw, bw, h - 2*bw, c) end + +--[[ +Draw a progress bar according to following args: + +@x: start position in x axis +@y: start position in y axis +@w: width for progress bar +@h: height for progress bar +@load_m_w: width margin for loading bar +@load_m_h: height margin for loading bar +@load_percent: progress in percent +@c: color for loading bar +--]] +blitbuffer.progressBar = function (bb, x, y, w, h, + load_m_w, load_m_h, load_percent, c) + if load_m_h*2 > h then + load_m_h = h/2 + end + blitbuffer.paintBorder(fb.bb, x, y, w, h, 2, 15) + fb.bb:paintRect(x+load_m_w, y+load_m_h, + (w-2*load_m_w)*load_percent, (h-2*load_m_h), c) +end diff --git a/reader.lua b/reader.lua index ae48c575e..9c18d3cee 100755 --- a/reader.lua +++ b/reader.lua @@ -103,7 +103,6 @@ else input.open("/dev/input/event2") set_k3_keycodes() end - end if optarg["G"] ~= nil then @@ -120,7 +119,7 @@ origin_rotation_mode = Screen.cur_rotation_mode reader_settings = DocSettings:open(".reader") r_cfont = reader_settings:readsetting("cfont") if r_cfont ~=nil then - FontChooser.cfont = r_cfont + Font.cfont = r_cfont end -- initialize global settings shared among all readers @@ -156,7 +155,7 @@ end -- save reader settings -reader_settings:savesetting("cfont", FontChooser.cfont) +reader_settings:savesetting("cfont", Font.cfont) reader_settings:close() -- @TODO dirty workaround, find a way to force native system poll diff --git a/screen.lua b/screen.lua index 158d20a63..24923a2e7 100644 --- a/screen.lua +++ b/screen.lua @@ -43,7 +43,8 @@ Screen = { cur_rotation_mode = 0, } --- @ orien: 1 for clockwise rotate, -1 for anti-clockwise +-- @orien: 1 for clockwise rotate, -1 for anti-clockwise +-- Remember to reread screen resolution after this function call function Screen:screenRotate(orien) if orien == "clockwise" then orien = -1 @@ -57,9 +58,6 @@ function Screen:screenRotate(orien) -- you have to reopen framebuffer after rotate fb:setOrientation(self.cur_rotation_mode) fb:close() - --local mode = self.rotation_modes[self.cur_rotation_mode] - --self.cur_rotation_mode = (self.cur_rotation_mode-1 + 1*orien)%4 + 1 - --os.execute("lipc-send-event -r 3 com.lab126.hal orientation"..mode) fb = einkfb.open("/dev/fb0") end diff --git a/selectmenu.lua b/selectmenu.lua index 32728e9ab..ec9f35a56 100644 --- a/selectmenu.lua +++ b/selectmenu.lua @@ -1,21 +1,15 @@ require "rendertext" require "keys" require "graphics" -require "fontchooser" +require "font" SelectMenu = { -- font for displaying item names fsize = 22, - face = nil, - fhash = nil, -- font for page title tfsize = 25, - tface = nil, - tfhash = nil, -- font for paging display ffsize = 16, - fface = nil, - ffhash = nil, -- font for item shortcut sface = freetype.newBuiltinFace("mono", 22), sfhash = "mono22", @@ -59,23 +53,6 @@ function SelectMenu:new(o) return o end -function SelectMenu:updateFont() - if self.fhash ~= FontChooser.cfont..self.fsize then - self.face = freetype.newBuiltinFace(FontChooser.cfont, self.fsize) - self.fhash = FontChooser.cfont..self.fsize - end - - if self.tfhash ~= FontChooser.tfont..self.tfsize then - self.tface = freetype.newBuiltinFace(FontChooser.tfont, self.tfsize) - self.tfhash = FontChooser.tfont..self.tfsize - end - - if self.ffhash ~= FontChooser.ffont..self.ffsize then - self.fface = freetype.newBuiltinFace(FontChooser.ffont, self.ffsize) - self.ffhash = FontChooser.ffont..self.ffsize - end -end - function SelectMenu:getItemIndexByShortCut(c, perpage) if c == nil then return end -- unused key for _k,_v in ipairs(self.item_shortcuts) do @@ -92,7 +69,6 @@ function SelectMenu:choose(ypos, height) local perpage = math.floor(height / self.spacing) - 2 local pagedirty = true local markerdirty = false - self:updateFont() local prevItem = function () if self.current == 1 then @@ -126,25 +102,28 @@ function SelectMenu:choose(ypos, height) self.last_shortcut = 0 while true do + local cface, cfhash = Font:getFaceAndHash(22) + local tface, tfhash = Font:getFaceAndHash(25, Font.tfont) + local fface, ffhash = Font:getFaceAndHash(16, Font.ffont) + if pagedirty then markerdirty = true -- draw menu title fb.bb:paintRect(0, ypos, fb.bb:getWidth(), self.title_H + 10, 0) fb.bb:paintRect(10, ypos + 10, fb.bb:getWidth() - 20, self.title_H, 5) - x = 20 - y = ypos + self.title_H - renderUtf8Text(fb.bb, x, y, self.tface, self.tfhash, - self.menu_title, true) + local x = 20 + local y = ypos + self.title_H + renderUtf8Text(fb.bb, x, y, tface, tfhash, self.menu_title, true) -- draw items fb.bb:paintRect(0, ypos + self.title_H + 10, fb.bb:getWidth(), height - self.title_H, 0) if self.items == 0 then y = ypos + self.title_H + (self.spacing * 2) - renderUtf8Text(fb.bb, 30, y, self.face, self.fhash, + renderUtf8Text(fb.bb, 30, y, cface, cfhash, "Oops... Bad news for you:", true) y = y + self.spacing - renderUtf8Text(fb.bb, 30, y, self.face, self.fhash, + renderUtf8Text(fb.bb, 30, y, cface, cfhash, self.no_item_msg, true) markerdirty = false else @@ -160,8 +139,10 @@ function SelectMenu:choose(ypos, height) else fb.bb:paintRect(10, y-22, 29, 29, 3) end - if self.item_shortcuts[c] ~= nil and string.len(self.item_shortcuts[c]) == 3 then - renderUtf8Text(fb.bb, 13, y, self.fface, self.ffhash, + if self.item_shortcuts[c] ~= nil and + string.len(self.item_shortcuts[c]) == 3 then + -- print "Del", "Sym and "Ent" + renderUtf9Text(fb.bb, 13, y, fface, ffhash, self.item_shortcuts[c], true) else renderUtf8Text(fb.bb, 18, y, self.sface, self.sfhash, @@ -170,7 +151,7 @@ function SelectMenu:choose(ypos, height) self.last_shortcut = c - renderUtf8Text(fb.bb, 50, y, self.face, self.fhash, + renderUtf8Text(fb.bb, 50, y, cface, cfhash, self.item_array[i], true) end end @@ -179,7 +160,7 @@ function SelectMenu:choose(ypos, height) -- draw footer y = ypos + self.title_H + (self.spacing * perpage) + self.foot_H + 5 x = (fb.bb:getWidth() / 2) - 50 - renderUtf8Text(fb.bb, x, y, self.fface, self.ffhash, + renderUtf8Text(fb.bb, x, y, fface, ffhash, "Page "..self.page.." of "..(math.floor(self.items / perpage)+1), true) end diff --git a/unireader.lua b/unireader.lua index ac777cf5f..75e592e1f 100644 --- a/unireader.lua +++ b/unireader.lua @@ -620,6 +620,37 @@ function UniReader:showJumpStack() end end +function UniReader:showMenu() + local ypos = height - 50 + local load_percent = (self.pageno / self.doc:getPages()) + + fb.bb:paintRect(0, ypos, width, 50, 0) + + ypos = ypos + 15 + local face, fhash = Font:getFaceAndHash(22) + local cur_section = self:getTOCTitleByPage(self.pageno) + if cur_section ~= "" then + cur_section = "Section: "..cur_section + end + renderUtf8Text(fb.bb, 10, ypos+6, face, fhash, + "Page: "..self.pageno.."/"..self.doc:getPages().. + " "..cur_section, true) + + ypos = ypos + 15 + blitbuffer.progressBar(fb.bb, 10, ypos, width-20, 15, + 5, 4, load_percent, 8) + fb:refresh(1) + while 1 do + local ev = input.waitForEvent() + ev.code = adjustKeyEvents(ev) + if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.code == KEY_BACK or ev.code == KEY_MENU then + return + end + end + end +end + function UniReader:odd_even(number) print("## odd_even "..number) if number % 2 == 1 then @@ -746,6 +777,9 @@ function UniReader:inputloop() elseif ev.code == KEY_Z and Keys.altmode then self.bbox.enabled = not self.bbox.enabled; print("# bbox override: ", self.bbox.enabled); + elseif ev.code == KEY_MENU then + self:showMenu() + self:goto(self.pageno) end -- switch to ZOOM_BY_VALUE to enable panning on fiveway move From 3a6aaedb9f177fec58771971eb5a4d94913543a1 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 10 Mar 2012 18:05:34 +0800 Subject: [PATCH 09/28] rm: fontchooser.lua --- fontchooser.lua | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 fontchooser.lua diff --git a/fontchooser.lua b/fontchooser.lua deleted file mode 100644 index 96e192319..000000000 --- a/fontchooser.lua +++ /dev/null @@ -1,20 +0,0 @@ - -FontChooser = { - -- font name for menu contents - cfont = "sans", - -- font name for title - tfont = "Helvetica-BoldOblique", - -- font name for footer - ffont = "sans", - - -- state buffer - fonts = {"sans", "cjk", "mono", - "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", - "Helvetica", "Helvetica-Oblique", "Helvetica-BoldOblique", - "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",}, -} - -function FontChooser:init() - clearglyphcache() -end - From 738925550348ff7d18a1c16ada876a12c7d0e665 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 10 Mar 2012 18:20:03 +0800 Subject: [PATCH 10/28] fix: handle last section in getTOCTitleByPage() --- unireader.lua | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/unireader.lua b/unireader.lua index 75e592e1f..be9f32bbc 100644 --- a/unireader.lua +++ b/unireader.lua @@ -561,13 +561,20 @@ function UniReader:getTOCTitleByPage(pageno) -- build toc when needed. self:fillTOC() end - - for _k,_v in ipairs(self.toc) do - if _v.page >= pageno then - return self:cleanUpTOCTitle(_v.title) - end + + -- no table of content + if #self.toc == 0 then + return "" end - return "" + + local pre_entry = self.toc[1] + for _k,_v in ipairs(self.toc) do + if _v.page > pageno then + break + end + pre_entry = _v + end + return self:cleanUpTOCTitle(pre_entry.title) end function UniReader:showTOC() From 09610d966e2c2e3d5478ca10875c55a1d5d8a49a Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sat, 10 Mar 2012 14:09:12 +0100 Subject: [PATCH 11/28] fix typo --- selectmenu.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selectmenu.lua b/selectmenu.lua index ec9f35a56..fd8116dc0 100644 --- a/selectmenu.lua +++ b/selectmenu.lua @@ -142,7 +142,7 @@ function SelectMenu:choose(ypos, height) if self.item_shortcuts[c] ~= nil and string.len(self.item_shortcuts[c]) == 3 then -- print "Del", "Sym and "Ent" - renderUtf9Text(fb.bb, 13, y, fface, ffhash, + renderUtf8Text(fb.bb, 13, y, fface, ffhash, self.item_shortcuts[c], true) else renderUtf8Text(fb.bb, 18, y, self.sface, self.sfhash, From 636297270723a0147239c7d457ec625d10d8b28d Mon Sep 17 00:00:00 2001 From: German Caro Date: Sat, 10 Mar 2012 21:43:55 -0300 Subject: [PATCH 12/28] Testing how git and github works and add support to djvu TOC --- djvu.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/djvu.c b/djvu.c index 1d9daa231..8f61f107f 100644 --- a/djvu.c +++ b/djvu.c @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include #include #include "string.h" @@ -119,15 +120,67 @@ static int getNumberOfPages(lua_State *L) { return 1; } -/* not supported yet, so return empty table */ +static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth) { + depth++; + + miniexp_t lista = miniexp_cdr(r); // go inside bookmars in the list + + int length = miniexp_length(r); + int counter = 0; + char page_number[6]; + + while(counter < length-1) { + lua_pushnumber(L, *count); + lua_newtable(L); + lua_pushstring(L, "page"); + + strcpy(page_number,miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))))); + + page_number[0]= '0'; //page numbers appear as #11, set # to 0 so strtol works + +// printf("string: %i:\n", strtol(page_number,NULL, 10)); + + lua_pushnumber(L, strtol(page_number,NULL, 10)); + lua_settable(L, -3); + + lua_pushstring(L, "depth"); + lua_pushnumber(L, depth); + lua_settable(L, -3); + lua_pushstring(L, "title"); + + lua_pushstring(L, miniexp_to_str(miniexp_car(miniexp_nth(counter, lista)))); + + lua_settable(L, -3); + + lua_settable(L, -3); + + + (*count)++; + + if (miniexp_length(miniexp_cdr(miniexp_nth(counter, lista))) > 1) { + walkTableOfContent(L, miniexp_cdr(miniexp_nth(counter,lista)), count, depth); + } + counter++; + + } + return 0; +} + + static int getTableOfContent(lua_State *L) { - /*int count = 1;*/ + int count = 1; DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); /*ol = djvu_load_outline(doc->doc_ref);*/ + miniexp_t r; + while ((r=ddjvu_document_get_outline(doc->doc_ref))==miniexp_dummy) + handle(L, doc->context, True); + + //printf("lista: %s\n", miniexp_to_str(miniexp_car(miniexp_nth(1, miniexp_cdr(r))))); lua_newtable(L); - /*walkTableOfContent(L, ol, &count, 0);*/ + walkTableOfContent(L, r, &count, 0); + return 1; } From ab056e2e157f4d02fbacb18ca5eba97a558ff003 Mon Sep 17 00:00:00 2001 From: German Caro Date: Sat, 10 Mar 2012 21:43:55 -0300 Subject: [PATCH 13/28] Add support to djvu TOC --- djvu.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/djvu.c b/djvu.c index 1d9daa231..8f61f107f 100644 --- a/djvu.c +++ b/djvu.c @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include #include #include "string.h" @@ -119,15 +120,67 @@ static int getNumberOfPages(lua_State *L) { return 1; } -/* not supported yet, so return empty table */ +static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth) { + depth++; + + miniexp_t lista = miniexp_cdr(r); // go inside bookmars in the list + + int length = miniexp_length(r); + int counter = 0; + char page_number[6]; + + while(counter < length-1) { + lua_pushnumber(L, *count); + lua_newtable(L); + lua_pushstring(L, "page"); + + strcpy(page_number,miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))))); + + page_number[0]= '0'; //page numbers appear as #11, set # to 0 so strtol works + +// printf("string: %i:\n", strtol(page_number,NULL, 10)); + + lua_pushnumber(L, strtol(page_number,NULL, 10)); + lua_settable(L, -3); + + lua_pushstring(L, "depth"); + lua_pushnumber(L, depth); + lua_settable(L, -3); + lua_pushstring(L, "title"); + + lua_pushstring(L, miniexp_to_str(miniexp_car(miniexp_nth(counter, lista)))); + + lua_settable(L, -3); + + lua_settable(L, -3); + + + (*count)++; + + if (miniexp_length(miniexp_cdr(miniexp_nth(counter, lista))) > 1) { + walkTableOfContent(L, miniexp_cdr(miniexp_nth(counter,lista)), count, depth); + } + counter++; + + } + return 0; +} + + static int getTableOfContent(lua_State *L) { - /*int count = 1;*/ + int count = 1; DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); /*ol = djvu_load_outline(doc->doc_ref);*/ + miniexp_t r; + while ((r=ddjvu_document_get_outline(doc->doc_ref))==miniexp_dummy) + handle(L, doc->context, True); + + //printf("lista: %s\n", miniexp_to_str(miniexp_car(miniexp_nth(1, miniexp_cdr(r))))); lua_newtable(L); - /*walkTableOfContent(L, ol, &count, 0);*/ + walkTableOfContent(L, r, &count, 0); + return 1; } From c074f19b0ff847e22d66b6db3068c2c12db1fcb5 Mon Sep 17 00:00:00 2001 From: German Caro Date: Sat, 10 Mar 2012 22:06:49 -0300 Subject: [PATCH 14/28] Re-indented using tabs --- djvu.c | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/djvu.c b/djvu.c index 8f61f107f..3ab7d64d6 100644 --- a/djvu.c +++ b/djvu.c @@ -121,29 +121,29 @@ static int getNumberOfPages(lua_State *L) { } static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth) { - depth++; + depth++; - miniexp_t lista = miniexp_cdr(r); // go inside bookmars in the list + miniexp_t lista = miniexp_cdr(r); // go inside bookmars in the list - int length = miniexp_length(r); - int counter = 0; - char page_number[6]; + int length = miniexp_length(r); + int counter = 0; + char page_number[6]; - while(counter < length-1) { - lua_pushnumber(L, *count); - lua_newtable(L); - lua_pushstring(L, "page"); + while(counter < length-1) { + lua_pushnumber(L, *count); + lua_newtable(L); + lua_pushstring(L, "page"); - strcpy(page_number,miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))))); + strcpy(page_number,miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))))); - page_number[0]= '0'; //page numbers appear as #11, set # to 0 so strtol works + page_number[0]= '0'; //page numbers appear as #11, set # to 0 so strtol works -// printf("string: %i:\n", strtol(page_number,NULL, 10)); +// printf("string: %i:\n", strtol(page_number,NULL, 10)); - lua_pushnumber(L, strtol(page_number,NULL, 10)); - lua_settable(L, -3); + lua_pushnumber(L, strtol(page_number,NULL, 10)); + lua_settable(L, -3); - lua_pushstring(L, "depth"); + lua_pushstring(L, "depth"); lua_pushnumber(L, depth); lua_settable(L, -3); lua_pushstring(L, "title"); @@ -155,15 +155,15 @@ static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth) lua_settable(L, -3); - (*count)++; + (*count)++; - if (miniexp_length(miniexp_cdr(miniexp_nth(counter, lista))) > 1) { - walkTableOfContent(L, miniexp_cdr(miniexp_nth(counter,lista)), count, depth); - } - counter++; + if (miniexp_length(miniexp_cdr(miniexp_nth(counter, lista))) > 1) { + walkTableOfContent(L, miniexp_cdr(miniexp_nth(counter,lista)), count, depth); + } + counter++; - } - return 0; + } + return 0; } @@ -172,11 +172,11 @@ static int getTableOfContent(lua_State *L) { DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); /*ol = djvu_load_outline(doc->doc_ref);*/ - miniexp_t r; - while ((r=ddjvu_document_get_outline(doc->doc_ref))==miniexp_dummy) - handle(L, doc->context, True); + miniexp_t r; + while ((r=ddjvu_document_get_outline(doc->doc_ref))==miniexp_dummy) + handle(L, doc->context, True); - //printf("lista: %s\n", miniexp_to_str(miniexp_car(miniexp_nth(1, miniexp_cdr(r))))); + //printf("lista: %s\n", miniexp_to_str(miniexp_car(miniexp_nth(1, miniexp_cdr(r))))); lua_newtable(L); walkTableOfContent(L, r, &count, 0); From 7ee77dee5cdb390bc068f1e4915595d94ced9a7a Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 11 Mar 2012 02:20:44 +0100 Subject: [PATCH 15/28] removed duplicate code --- unireader.lua | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/unireader.lua b/unireader.lua index be9f32bbc..987eee400 100644 --- a/unireader.lua +++ b/unireader.lua @@ -798,15 +798,6 @@ function UniReader:inputloop() self.globalzoommode = self.ZOOM_BY_VALUE end - -- switch to ZOOM_BY_VALUE to enable panning on fiveway move - if ev.code == KEY_FW_LEFT - or ev.code == KEY_FW_RIGHT - or ev.code == KEY_FW_UP - or ev.code == KEY_FW_DOWN - then - self.globalzoommode = self.ZOOM_BY_VALUE - end - if self.globalzoommode == self.ZOOM_BY_VALUE then local x local y @@ -844,7 +835,7 @@ function UniReader:inputloop() self.offset_x = 0 end elseif ev.code == KEY_FW_RIGHT then - print("# KEY_FW_RIGHT "..self.offset_x.." - "..x.." < "..self.min_offset_x); + print("# KEY_FW_RIGHT "..self.offset_x.." - "..x.." < "..self.min_offset_x.." - "..self.pan_margin); self.offset_x = self.offset_x - x if self.pan_by_page then if self.offset_x < self.min_offset_x - self.pan_margin and self.pageno < self.doc:getPages() then From 72c032e7db2c526069159484ac84c1d6eed52455 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 11 Mar 2012 09:44:05 +0800 Subject: [PATCH 16/28] fix: adjust page number in toc djvulibre counts page number starts from 0, while kpdfview starts from 1. --- djvu.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/djvu.c b/djvu.c index 3ab7d64d6..d2b804662 100644 --- a/djvu.c +++ b/djvu.c @@ -132,47 +132,40 @@ static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth) while(counter < length-1) { lua_pushnumber(L, *count); lua_newtable(L); + lua_pushstring(L, "page"); - strcpy(page_number,miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))))); - - page_number[0]= '0'; //page numbers appear as #11, set # to 0 so strtol works - -// printf("string: %i:\n", strtol(page_number,NULL, 10)); - - lua_pushnumber(L, strtol(page_number,NULL, 10)); + /* page numbers appear as #11, set # to 0 so strtol works */ + page_number[0]= '0'; + lua_pushnumber(L, strtol(page_number, NULL, 10)+1); lua_settable(L, -3); lua_pushstring(L, "depth"); lua_pushnumber(L, depth); lua_settable(L, -3); + lua_pushstring(L, "title"); - lua_pushstring(L, miniexp_to_str(miniexp_car(miniexp_nth(counter, lista)))); - lua_settable(L, -3); lua_settable(L, -3); - (*count)++; if (miniexp_length(miniexp_cdr(miniexp_nth(counter, lista))) > 1) { - walkTableOfContent(L, miniexp_cdr(miniexp_nth(counter,lista)), count, depth); + walkTableOfContent(L, miniexp_cdr(miniexp_nth(counter, lista)), count, depth); } counter++; - } return 0; } static int getTableOfContent(lua_State *L) { + DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); + miniexp_t r; int count = 1; - DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); - /*ol = djvu_load_outline(doc->doc_ref);*/ - miniexp_t r; while ((r=ddjvu_document_get_outline(doc->doc_ref))==miniexp_dummy) handle(L, doc->context, True); From b7c04ada1af010943fe63a44fd7ba36b451acf81 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 11 Mar 2012 15:46:25 +0800 Subject: [PATCH 17/28] mod: clean up in inputbox.lua --- inputbox.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/inputbox.lua b/inputbox.lua index ef5cdfc4a..6e3fc6667 100644 --- a/inputbox.lua +++ b/inputbox.lua @@ -25,8 +25,6 @@ InputBox = { function InputBox:setDefaultInput(text) self.input_string = "" self:addString(text) - --renderUtf8Text(fb.bb, self.input_start_x, self.input_start_y, - --self.face, self.fhash, text, true) --self.input_cur_x = self.input_start_x + (string.len(text) * self.fwidth) --self.input_string = text end @@ -181,19 +179,21 @@ function InputBox:input(ypos, height, title, d_text) elseif ev.code == KEY_PGBCK then elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then if self.input_string == "" then - return nil - else - return self.input_string + self.input_string = nil end + break elseif ev.code == KEY_DEL then self:delChar() elseif ev.code == KEY_BACK then - return nil + self.input_string = nil + break end --local nsecs, nusecs = util.gettime() --local dur = (nsecs - secs) * 1000000 + nusecs - usecs --print("E: T="..ev.type.." V="..ev.value.." C="..ev.code.." DUR="..dur) - end - end + end -- if + end -- while + + return self.input_string end From d8a58e87644e13327af00be2525df71a8fdd52b2 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 11 Mar 2012 23:55:42 +0100 Subject: [PATCH 18/28] revert 70b7e029d383e33df8fb4c3a00547d4069e7dd53 It's not that simple since ZOOM_FIT_TO_CONTENT_HALF_WIDTH also needs bounding boxes, and this seems like over-optimization which seems to be bug infested especially because it deals with negative numbers so code just *looks* wrong --- unireader.lua | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/unireader.lua b/unireader.lua index 987eee400..c96a4f14a 100644 --- a/unireader.lua +++ b/unireader.lua @@ -209,17 +209,13 @@ function UniReader:setzoom(page) local dc = self.newDC() local pwidth, pheight = page:getSize(self.nulldc) print("# page::getSize "..pwidth.."*"..pheight); - local x0, y0, x1, y1 = 0, 0, pwidth, pheight - - -- only get usedBBox in fit to content mode - if self.globalzoommode <= self.ZOOM_FIT_TO_CONTENT and - self.globalzoommode >= self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN then - x0, y0, x1, y1 = page:getUsedBBox() - if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then - x0, y0, x1, y1 = 0, 0, pwidth, pheight - end + local x0, y0, x1, y1 = page:getUsedBBox() + if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then + x0 = 0 + y0 = 0 + x1 = pwidth + y1 = pheight end - -- clamp to page BBox if x0 < 0 then x0 = 0 end if x1 > pwidth then x1 = pwidth end From 5fae18298a39a5c30c4602847ca2572511ff9a0a Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 12 Mar 2012 13:59:19 +0800 Subject: [PATCH 19/28] add: goto input box in reader --- unireader.lua | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/unireader.lua b/unireader.lua index c96a4f14a..7cb243b6f 100644 --- a/unireader.lua +++ b/unireader.lua @@ -209,13 +209,17 @@ function UniReader:setzoom(page) local dc = self.newDC() local pwidth, pheight = page:getSize(self.nulldc) print("# page::getSize "..pwidth.."*"..pheight); - local x0, y0, x1, y1 = page:getUsedBBox() - if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then - x0 = 0 - y0 = 0 - x1 = pwidth - y1 = pheight + local x0, y0, x1, y1 = 0, 0, pwidth, pheight + + -- only get usedBBox in fit to content mode + if self.globalzoommode <= self.ZOOM_FIT_TO_CONTENT and + self.globalzoommode >= self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN then + x0, y0, x1, y1 = page:getUsedBBox() + if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then + x0, y0, x1, y1 = 0, 0, pwidth, pheight + end end + -- clamp to page BBox if x0 < 0 then x0 = 0 end if x1 > pwidth then x1 = pwidth end @@ -735,6 +739,17 @@ function UniReader:inputloop() else self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN) end + elseif ev.code == KEY_G then + local page = InputBox:input(height-100, 100, "Page:") + -- convert string to number + if not pcall(function () page = page + 0 end) then + page = self.pageno + else + if page < 1 or page > self.doc:getPages() then + page = self.pageno + end + end + self:goto(page) elseif ev.code == KEY_T then self:showTOC() elseif ev.code == KEY_B then From 0e914c5fda9fd17a28d9a2408dd167028b8790a4 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 12 Mar 2012 19:48:24 +0800 Subject: [PATCH 20/28] revert 70b7e029d383e33df8fb4c3a00547d4069e7dd53 again commit 5fae18298a39a5c30c4602847ca2572511ff9a0a mistakenly reverted d8a58e87644e13327af00be2525df71a8fdd52b2, in which commit 70b7e029d383e33df8fb4c3a00547d4069e7dd53 was reverted. --- unireader.lua | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/unireader.lua b/unireader.lua index 7cb243b6f..435f0d1aa 100644 --- a/unireader.lua +++ b/unireader.lua @@ -209,17 +209,13 @@ function UniReader:setzoom(page) local dc = self.newDC() local pwidth, pheight = page:getSize(self.nulldc) print("# page::getSize "..pwidth.."*"..pheight); - local x0, y0, x1, y1 = 0, 0, pwidth, pheight - - -- only get usedBBox in fit to content mode - if self.globalzoommode <= self.ZOOM_FIT_TO_CONTENT and - self.globalzoommode >= self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN then - x0, y0, x1, y1 = page:getUsedBBox() - if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then - x0, y0, x1, y1 = 0, 0, pwidth, pheight - end + local x0, y0, x1, y1 = page:getUsedBBox() + if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then + x0 = 0 + y0 = 0 + x1 = pwidth + y1 = pheight end - -- clamp to page BBox if x0 < 0 then x0 = 0 end if x1 > pwidth then x1 = pwidth end From 86ff74acd6beb83fad05d8e9f47aade622cf816c Mon Sep 17 00:00:00 2001 From: HW Date: Mon, 12 Mar 2012 20:48:46 +0100 Subject: [PATCH 21/28] prepare for more elaborate caching policy we allow for bigger render buffers, so the cache now returns the ID (hash) of the relevant cashed tile PLUS offsets into that tile, pointing to the coordinates where the requested frame has its origin. --- unireader.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/unireader.lua b/unireader.lua index 435f0d1aa..d3ea6bc07 100644 --- a/unireader.lua +++ b/unireader.lua @@ -189,7 +189,7 @@ function UniReader:draworcache(no, zoom, offset_x, offset_y, width, height, gamm -- so give it more ttl. self.cache[hash].ttl = self.cache_max_ttl end - return hash + return hash, 0, 0 end -- calculate a hash for our current state @@ -358,12 +358,14 @@ end -- render and blit a page function UniReader:show(no) local slot + local offset_x -- resulting display offset + local offset_y if self.globalzoommode ~= self.ZOOM_BY_VALUE then - slot = self:draworcache(no,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + slot, offset_x, offset_y = self:draworcache(no,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) else - slot = self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + slot, offset_x, offset_y = self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) end - fb.bb:blitFullFrom(self.cache[slot].bb) + fb.bb:blitFrom(self.cache[slot].bb, 0, 0, offset_x, offset_y, width, height) if self.rcount == self.rcountmax then print("full refresh") self.rcount = 1 From aab05c3002a84d4a567e3993f3f4b71ddfcba4c2 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 13 Mar 2012 00:02:49 +0100 Subject: [PATCH 22/28] Fix page caching Fixed page caching. Cache strategy is the following: prio 1: cache/render requested area prio 2: cache/render as much of the current page as possible prio 3: cache/render full page prio 4: render next page This is still a bit buggy when in fit-to-content mode. --- unireader.lua | 157 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 43 deletions(-) diff --git a/unireader.lua b/unireader.lua index d3ea6bc07..10f238beb 100644 --- a/unireader.lua +++ b/unireader.lua @@ -67,6 +67,9 @@ UniReader = { -- tile cache state: cache_current_memsize = 0, cache = {}, + + pagehash = nil, + jump_stack = {}, toc = nil, @@ -168,34 +171,97 @@ function UniReader:cacheclaim(size) return true end -function UniReader:draworcache(no, zoom, offset_x, offset_y, width, height, gamma, rotate) - -- hash draw state - local hash = self:cachehash(no, zoom, offset_x, offset_y, width, height, gamma, rotate) - if self.cache[hash] == nil then - -- not in cache, so prepare cache slot... - self:cacheclaim(width * height / 2); - self.cache[hash] = { - ttl = self.cache_max_ttl, - size = width * height / 2, - bb = Blitbuffer.new(width, height) - } - -- and draw the page - local page = self.doc:openPage(no) - local dc = self:setzoom(page, hash) - page:draw(dc, self.cache[hash].bb, 0, 0) - page:close() - else - -- we have the page in our cache, - -- so give it more ttl. - self.cache[hash].ttl = self.cache_max_ttl - end - return hash, 0, 0 -end +function UniReader:draworcache(no, preCache) + -- our general caching strategy is as follows: + -- #1 goal: we must render the needed area. + -- #2 goal: we render as much of the requested page as we can + -- #3 goal: we render the full page + -- #4 goal: we render next page, too. (TODO) --- calculate a hash for our current state -function UniReader:cachehash(no, zoom, offset_x, offset_y, width, height, gamma, rotate) - -- TODO (?): make this a "real" hash... - return no..'_'..zoom..'_'..offset_x..','..offset_y..'-'..width..'x'..height..'_'..gamma..'_'..rotate + -- ideally, this should be factored out and only be called when needed (TODO) + local page = self.doc:openPage(no) + local dc = self:setzoom(page) + + -- check if we have relevant cache contents + local pagehash = no..'_'..self.globalzoom..'_'..self.globalrotate..'_'..self.globalgamma + if self.cache[pagehash] ~= nil then + -- we have something in cache, check if it contains the requested part + if self.cache[pagehash].x <= (-self.offset_x) + and self.cache[pagehash].y <= (-self.offset_y) + and self.cache[pagehash].x + self.cache[pagehash].w >= (-self.offset_x) + width + and self.cache[pagehash].y + self.cache[pagehash].h >= (-self.offset_y) + height + then + -- requested part is within cached tile + -- ...so properly clean page + page:close() + -- ...and give it more time to live (ttl), except if we're precaching + if not preCache then + self.cache[pagehash].ttl = self.cache_max_ttl + end + -- ...and return blitbuffer plus offset into it + return pagehash, + (-self.offset_x) - self.cache[pagehash].x, + (-self.offset_y) - self.cache[pagehash].y + end + end + -- okay, we do not have it in cache yet. + -- so render now. + -- start off with the requested area + local tile = { x = (-self.offset_x), y = (-self.offset_y), w = width, h = heigth } + -- can we cache the full page? + local max_cache = self.cache_max_memsize + if preCache then + max_cache = max_cache - self.cache[self.pagehash].size + end + if (self.fullwidth * self.fullheight / 2) <= max_cache then + -- yes we can, so do this with offset 0, 0 + tile.x = 0 + tile.y = 0 + tile.w = self.fullwidth + tile.h = self.fullheight + elseif (tile.w*tile.h / 2) > max_cache then + -- no, we can't. so generate a tile as big as we can go + -- grow area in steps of 10px + while ((tile.w+10) * (tile.h+10) / 2) < max_cache do + if tile.x > 0 then + tile.x = tile.x - 5 + tile.w = tile.w + 5 + end + if tile.x + tile.w < self.fullwidth then + tile.w = tile.w + 5 + end + if tile.y > 0 then + tile.y = tile.y - 5 + tile.h = tile.h + 5 + end + if tile.y + tile.h < self.fullheigth then + tile.h = tile.h + 5 + end + end + else + if not preCache then + print("E: not enough memory in cache left, probably a bug.") + end + return nil + end + self:cacheclaim(tile.w * tile.h / 2); + self.cache[pagehash] = { + x = tile.x, + y = tile.y, + w = tile.w, + h = tile.h, + ttl = self.cache_max_ttl, + size = tile.w * tile.h / 2, + bb = Blitbuffer.new(tile.w, tile.h) + } + dc:setOffset(-tile.x, -tile.y) + print("# rendering: page="..no) + page:draw(dc, self.cache[pagehash].bb, 0, 0) + page:close() + + return pagehash, + (-self.offset_x) - tile.x, + (-self.offset_y) - tile.y end -- blank the cache @@ -334,7 +400,6 @@ function UniReader:setzoom(page) self.globalzoom_orig = self.globalzoom dc:setRotate(self.globalrotate); - dc:setOffset(self.offset_x, self.offset_y) self.fullwidth, self.fullheight = page:getSize(dc) self.min_offset_x = fb.bb:getWidth() - self.fullwidth self.min_offset_y = fb.bb:getHeight() - self.fullheight @@ -357,15 +422,23 @@ end -- render and blit a page function UniReader:show(no) - local slot - local offset_x -- resulting display offset - local offset_y - if self.globalzoommode ~= self.ZOOM_BY_VALUE then - slot, offset_x, offset_y = self:draworcache(no,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) - else - slot, offset_x, offset_y = self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + local pagehash, offset_x, offset_y = self:draworcache(no) + self.pagehash = pagehash + local bb = self.cache[pagehash].bb + local dest_x = 0 + local dest_y = 0 + if bb:getWidth() - offset_x < width then + -- we can't fill the whole output width + dest_x = (width - (bb:getWidth() - offset_x)) / 2 end - fb.bb:blitFrom(self.cache[slot].bb, 0, 0, offset_x, offset_y, width, height) + if bb:getHeight() - offset_y < height then + -- we can't fill the whole output heigth + dest_y = (height - (bb:getHeight() - offset_y)) / 2 + end + if dest_x or dest_y then + fb.bb:paintRect(0, 0, width, height, 8) + end + fb.bb:blitFrom(bb, dest_x, dest_y, offset_x, offset_y, width, height) if self.rcount == self.rcountmax then print("full refresh") self.rcount = 1 @@ -446,14 +519,12 @@ function UniReader:goto(no) self.pageno = no self:show(no) + -- TODO: move the following to a more appropriate place + -- into the caching section if no < self.doc:getPages() then - if self.globalzoommode ~= self.ZOOM_BY_VALUE then - if #self.bbox == 0 or not self.bbox.enabled then - -- pre-cache next page, but if we will modify bbox don't! - self:draworcache(no+1,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) - end - else - self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + if #self.bbox == 0 or not self.bbox.enabled then + -- pre-cache next page, but if we will modify bbox don't! + self:draworcache(no+1, true) end end end From 8410ac5cb78be7e3675ad7405403ff00de34f85f Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 13 Mar 2012 00:11:31 +0100 Subject: [PATCH 23/28] fix forgotten corner case when caching --- unireader.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/unireader.lua b/unireader.lua index 10f238beb..9def0d545 100644 --- a/unireader.lua +++ b/unireader.lua @@ -188,8 +188,10 @@ function UniReader:draworcache(no, preCache) -- we have something in cache, check if it contains the requested part if self.cache[pagehash].x <= (-self.offset_x) and self.cache[pagehash].y <= (-self.offset_y) - and self.cache[pagehash].x + self.cache[pagehash].w >= (-self.offset_x) + width - and self.cache[pagehash].y + self.cache[pagehash].h >= (-self.offset_y) + height + and ( self.cache[pagehash].x + self.cache[pagehash].w >= (-self.offset_x) + width + or self.cache[pagehash].w >= self.fullwidth - 1) + and ( self.cache[pagehash].y + self.cache[pagehash].h >= (-self.offset_y) + height + or self.cache[pagehash].h >= self.fullheight - 1) then -- requested part is within cached tile -- ...so properly clean page From 734f94da898b15a6fbd0459b26a015bb4a8667a0 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 13 Mar 2012 15:37:45 +0800 Subject: [PATCH 24/28] fix: handle positive self.offset in draworcache method --- unireader.lua | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/unireader.lua b/unireader.lua index 9def0d545..85e2df6d2 100644 --- a/unireader.lua +++ b/unireader.lua @@ -182,15 +182,24 @@ function UniReader:draworcache(no, preCache) local page = self.doc:openPage(no) local dc = self:setzoom(page) + -- offset_x_in_page & offset_y_in_page is the offset within zoomed page + -- they are always positive. + -- you can see self.offset_x_& self.offset_y as the offset within + -- draw space, which includes the page. So it can be negative and positive. + local offset_x_in_page = -self.offset_x + local offset_y_in_page = -self.offset_y + if offset_x_in_page < 0 then offset_x_in_page = 0 end + if offset_x_in_page < 0 then offset_y_in_page = 0 end + -- check if we have relevant cache contents local pagehash = no..'_'..self.globalzoom..'_'..self.globalrotate..'_'..self.globalgamma if self.cache[pagehash] ~= nil then -- we have something in cache, check if it contains the requested part - if self.cache[pagehash].x <= (-self.offset_x) - and self.cache[pagehash].y <= (-self.offset_y) - and ( self.cache[pagehash].x + self.cache[pagehash].w >= (-self.offset_x) + width + if self.cache[pagehash].x <= offset_x_in_page + and self.cache[pagehash].y <= offset_y_in_page + and ( self.cache[pagehash].x + self.cache[pagehash].w >= offset_x_in_page + width or self.cache[pagehash].w >= self.fullwidth - 1) - and ( self.cache[pagehash].y + self.cache[pagehash].h >= (-self.offset_y) + height + and ( self.cache[pagehash].y + self.cache[pagehash].h >= offset_y_in_page + height or self.cache[pagehash].h >= self.fullheight - 1) then -- requested part is within cached tile @@ -202,14 +211,15 @@ function UniReader:draworcache(no, preCache) end -- ...and return blitbuffer plus offset into it return pagehash, - (-self.offset_x) - self.cache[pagehash].x, - (-self.offset_y) - self.cache[pagehash].y + offset_x_in_page - self.cache[pagehash].x, + offset_y_in_page - self.cache[pagehash].y end end -- okay, we do not have it in cache yet. -- so render now. -- start off with the requested area - local tile = { x = (-self.offset_x), y = (-self.offset_y), w = width, h = heigth } + local tile = { x = offset_x_in_page, y = offset_y_in_page, + w = width, h = heigth } -- can we cache the full page? local max_cache = self.cache_max_memsize if preCache then @@ -256,14 +266,15 @@ function UniReader:draworcache(no, preCache) size = tile.w * tile.h / 2, bb = Blitbuffer.new(tile.w, tile.h) } + --print ("# new biltbuffer:"..dump(self.cache[pagehash])) dc:setOffset(-tile.x, -tile.y) print("# rendering: page="..no) page:draw(dc, self.cache[pagehash].bb, 0, 0) page:close() return pagehash, - (-self.offset_x) - tile.x, - (-self.offset_y) - tile.y + offset_x_in_page - tile.x, + offset_y_in_page - tile.y end -- blank the cache From 8c31dd3c5fce39251b3d5e705f8d45040de57ceb Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 13 Mar 2012 16:21:16 +0800 Subject: [PATCH 25/28] fix: hanlde offset in ZOOM_FIT_TO_WIDTH_PAN mode ZOOM_FIT_TO_WIDTH_PAN mode must be handled differently. Because not like other zoom mode, its offset is not set to middle of the screen or page. --- unireader.lua | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/unireader.lua b/unireader.lua index 85e2df6d2..1cb4ea516 100644 --- a/unireader.lua +++ b/unireader.lua @@ -189,7 +189,7 @@ function UniReader:draworcache(no, preCache) local offset_x_in_page = -self.offset_x local offset_y_in_page = -self.offset_y if offset_x_in_page < 0 then offset_x_in_page = 0 end - if offset_x_in_page < 0 then offset_y_in_page = 0 end + if offset_y_in_page < 0 then offset_y_in_page = 0 end -- check if we have relevant cache contents local pagehash = no..'_'..self.globalzoom..'_'..self.globalrotate..'_'..self.globalgamma @@ -272,6 +272,9 @@ function UniReader:draworcache(no, preCache) page:draw(dc, self.cache[pagehash].bb, 0, 0) page:close() + print("offset_x_in_page", offset_x_in_page) + print("offset_y_in_page", offset_y_in_page) + -- return hash and offset within blitbuffer return pagehash, offset_x_in_page - tile.x, offset_y_in_page - tile.y @@ -441,16 +444,27 @@ function UniReader:show(no) local dest_x = 0 local dest_y = 0 if bb:getWidth() - offset_x < width then - -- we can't fill the whole output width + -- we can't fill the whole output width, center the content dest_x = (width - (bb:getWidth() - offset_x)) / 2 end - if bb:getHeight() - offset_y < height then - -- we can't fill the whole output heigth + if bb:getHeight() - offset_y < height and + self.globalzoommode ~= self.ZOOM_FIT_TO_CONTENT_WIDTH_PAN then + -- we can't fill the whole output height and not in + -- ZOOM_FIT_TO_CONTENT_WIDTH_PAN mode, center the content dest_y = (height - (bb:getHeight() - offset_y)) / 2 + elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_WIDTH_PAN and + self.offset_y > 0 then + -- if we are in ZOOM_FIT_TO_CONTENT_WIDTH_PAN mode and turning to + -- the top of the page, we might leave an empty space between the + -- page top and screen top. + dest_y = self.offset_y end if dest_x or dest_y then fb.bb:paintRect(0, 0, width, height, 8) end + print("# blitFrom dest_off:("..dest_x..", "..dest_y.. + "), src_off:("..offset_x..", "..offset_y.."), ".. + "width:"..width..", height:"..height) fb.bb:blitFrom(bb, dest_x, dest_y, offset_x, offset_y, width, height) if self.rcount == self.rcountmax then print("full refresh") From 46cfd950c79abf1a602017911730c640d6f6e7c0 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 13 Mar 2012 17:07:55 +0800 Subject: [PATCH 26/28] fix: typo --- unireader.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unireader.lua b/unireader.lua index 1cb4ea516..192d81727 100644 --- a/unireader.lua +++ b/unireader.lua @@ -219,7 +219,7 @@ function UniReader:draworcache(no, preCache) -- so render now. -- start off with the requested area local tile = { x = offset_x_in_page, y = offset_y_in_page, - w = width, h = heigth } + w = width, h = height } -- can we cache the full page? local max_cache = self.cache_max_memsize if preCache then From 56a00d79a0888adf1db41c7ce847c9cb74037026 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 13 Mar 2012 17:16:05 +0800 Subject: [PATCH 27/28] mod: delete debug print --- unireader.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/unireader.lua b/unireader.lua index 192d81727..61fd3e26a 100644 --- a/unireader.lua +++ b/unireader.lua @@ -272,8 +272,6 @@ function UniReader:draworcache(no, preCache) page:draw(dc, self.cache[pagehash].bb, 0, 0) page:close() - print("offset_x_in_page", offset_x_in_page) - print("offset_y_in_page", offset_y_in_page) -- return hash and offset within blitbuffer return pagehash, offset_x_in_page - tile.x, From ad6198efb867f0eb5ff05f87bcf5182f0be15d1b Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 13 Mar 2012 18:34:04 +0100 Subject: [PATCH 28/28] A take at better boundary checks in blitbuffer this will hopefully prevent segfaults resulting from bad coordinate/size input when blitting --- blitbuffer.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/blitbuffer.c b/blitbuffer.c index 1a8253967..c8a51de7f 100644 --- a/blitbuffer.c +++ b/blitbuffer.c @@ -93,26 +93,53 @@ static int blitToBuffer(lua_State *L) { int x, y; // check bounds + if(ydest < 0) { + // negative ydest, try to compensate + if(ydest + h > 0) { + // shrink h by negative dest offset + h += ydest; + // extend source offset + yoffs += -ydest; + ydest = 0; + } else { + // effectively no height + return 0; + } + } else if(ydest >= dst->h) { + // we're told to paint to off-bound target coords + return 0; + } + if(ydest + h > dst->h) { + // clamp height if too large for target size + h = dst->h - ydest; + } if(yoffs >= src->h) { + // recalculated source offset is out of bounds return 0; } else if(yoffs + h > src->h) { + // clamp height if too large for source size h = src->h - yoffs; } - if(ydest >= dst->h) { + // same stuff for x coords: + if(xdest < 0) { + if(xdest + w > 0) { + w += xdest; + xoffs += -xdest; + xdest = 0; + } else { + return 0; + } + } else if(xdest >= dst->w) { return 0; - } else if(ydest + h > dst->h) { - h = dst->h - ydest; + } + if(xdest + w > dst->w) { + w = dst->w - xdest; } if(xoffs >= src->w) { return 0; } else if(xoffs + w > src->w) { w = src->w - xoffs; } - if(xdest >= dst->w) { - return 0; - } else if(xdest + w > dst->w) { - w = dst->w - xdest; - } uint8_t *dstptr; uint8_t *srcptr;