From 72f9449de8d8dbea03c0ec6d7edf9acbfd8d5c63 Mon Sep 17 00:00:00 2001 From: chrox Date: Wed, 29 Oct 2014 16:42:00 +0800 Subject: [PATCH 1/5] ignore more markup tags in dictionary window --- base | 2 +- .../apps/reader/modules/readerdictionary.lua | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/base b/base index 959f8c216..3260f0494 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 959f8c2160abee41b846158b2b06820617427b38 +Subproject commit 3260f0494f7558f234806e68adb92606af391f8f diff --git a/frontend/apps/reader/modules/readerdictionary.lua b/frontend/apps/reader/modules/readerdictionary.lua index e1ee8d2f7..398df95e5 100644 --- a/frontend/apps/reader/modules/readerdictionary.lua +++ b/frontend/apps/reader/modules/readerdictionary.lua @@ -32,21 +32,24 @@ function ReaderDictionary:onLookupWord(word, box, highlight) return true end -local function tidyCDATA(results) +local function tidy_markup(results) local cdata_tag = "" local format_escape = "&[29Ib%+]{(.-)}" for _, result in ipairs(results) do + local def = result.definition + -- preserve the
tag for line break + def = def:gsub("<[bB][rR] ?/?>", "\n") -- parse CDATA text in XML - if result.definition:find(cdata_tag) then - local def = result.definition:gsub(cdata_tag, "%1") - -- ignore all tags - def = def:gsub("%b<>", "") + if def:find(cdata_tag) then + def = def:gsub(cdata_tag, "%1") -- ignore format strings while def:find(format_escape) do def = def:gsub(format_escape, "%1") end - result.definition = def end + -- ignore all markup tags + def = def:gsub("%b<>", "") + result.definition = def end return results end @@ -66,7 +69,7 @@ function ReaderDictionary:stardictLookup(word, box) local ok, results = pcall(JSON.decode, JSON, results_str) if ok and results then DEBUG("lookup result table:", word, results) - self:showDict(word, tidyCDATA(results), box) + self:showDict(word, tidy_markup(results), box) else -- dummy results results = { From 8c9751744ec6ff6ccea23f91f4b86e41cf472b87 Mon Sep 17 00:00:00 2001 From: chrox Date: Thu, 30 Oct 2014 11:05:22 +0800 Subject: [PATCH 2/5] fix #1064 by adding timestamp of document in cache key so that when document is modified the persistent cache will be invalidated automatically because the cache key will not be matched. There is no perfermance overhead here at all. We even don't need to check the modification time of the cache item on disk, because the name of the on disk cache is a md5sum of the cacheitem key, now the filename of the cache files contains the modification time information. If the document is modified since one rendered page is cached to disk, the cache key won't match the cache file. And the cache file will be discarded without the need to open the cache file or to check the modification time of the cache file itself. --- frontend/document/document.lua | 26 +++++++++++++++++--------- frontend/document/koptinterface.lua | 11 +++++++---- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index 535e09893..f274b6dda 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -1,11 +1,12 @@ -local DrawContext = require("ffi/drawcontext") -local Blitbuffer = require("ffi/blitbuffer") -local Cache = require("cache") -local CacheItem = require("cacheitem") local TileCacheItem = require("document/tilecacheitem") -local Geom = require("ui/geometry") +local DrawContext = require("ffi/drawcontext") local Configurable = require("configurable") +local Blitbuffer = require("ffi/blitbuffer") +local lfs = require("libs/libkoreader-lfs") +local CacheItem = require("cacheitem") +local Geom = require("ui/geometry") local Math = require("optmath") +local Cache = require("cache") local DEBUG = require("dbg") --[[ @@ -114,6 +115,7 @@ function Document:getNativePageDimensions(pageno) end function Document:_readMetadata() + self.mod_time = lfs.attributes(self.file, "modification") self.info.number_of_pages = self._document:getPages() return true end @@ -215,8 +217,13 @@ function Document:getCoverPageImage() return nil end +function Document:getFullPageHash(pageno, zoom, rotation, gamma, render_mode) + return "renderpg|"..self.file.."|"..self.mod_time.."|"..pageno.."|" + ..zoom.."|"..rotation.."|"..gamma.."|"..render_mode +end + function Document:renderPage(pageno, rect, zoom, rotation, gamma, render_mode) - local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode + local hash = self:getFullPageHash(pageno, zoom, rotation, gamma, render_mode) local page_size = self:getPageDimensions(pageno, zoom, rotation) -- this will be the size we actually render local size = page_size @@ -231,12 +238,13 @@ function Document:renderPage(pageno, rect, zoom, rotation, gamma, render_mode) return end -- only render required part - hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode.."|"..tostring(rect) + hash = self:getFullPageHash(pageno, zoom, rotation, gamma, render_mode).."|"..tostring(rect) size = rect end -- prepare cache item with contained blitbuffer local tile = TileCacheItem:new{ + persistent = true, size = size.w * size.h + 64, -- estimation excerpt = size, pageno = pageno, @@ -274,7 +282,7 @@ end -- a hint for the cache engine to paint a full page to the cache -- TODO: this should trigger a background operation function Document:hintPage(pageno, zoom, rotation, gamma, render_mode) - local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode + local hash_full_page = self:getFullPageHash(pageno, zoom, rotation, gamma, render_mode) if not Cache:check(hash_full_page, TileCacheItem) then DEBUG("hinting page", pageno) self:renderPage(pageno, nil, zoom, rotation, gamma, render_mode) @@ -290,7 +298,7 @@ Draw page content to blitbuffer. @rect: visible_area inside document page --]] function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, render_mode) - local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode + local hash_full_page = self:getFullPageHash(pageno, zoom, rotation, gamma, render_mode) local hash_excerpt = hash_full_page.."|"..tostring(rect) local tile = Cache:check(hash_full_page, TileCacheItem) if not tile then diff --git a/frontend/document/koptinterface.lua b/frontend/document/koptinterface.lua index 2193f5e29..368a78e37 100644 --- a/frontend/document/koptinterface.lua +++ b/frontend/document/koptinterface.lua @@ -107,7 +107,8 @@ function KoptInterface:getContextHash(doc, pageno, bbox) local screen_size = Screen:getSize() local screen_size_hash = screen_size.w.."|"..screen_size.h local bbox_hash = bbox.x0.."|"..bbox.y0.."|"..bbox.x1.."|"..bbox.y1 - return doc.file.."|"..pageno.."|"..doc.configurable:hash("|").."|"..bbox_hash.."|"..screen_size_hash + return doc.file.."|"..doc.mod_time.."|"..pageno.."|" + ..doc.configurable:hash("|").."|"..bbox_hash.."|"..screen_size_hash end function KoptInterface:getPageBBox(doc, pageno) @@ -215,6 +216,7 @@ function KoptInterface:getCachedContext(doc, pageno) DEBUG("reflowed page", pageno, "fullwidth:", fullwidth, "fullheight:", fullheight) self.last_context_size = fullwidth * fullheight + 128 -- estimation Cache:insert(kctx_hash, ContextCacheItem:new{ + persistent = true, size = self.last_context_size, kctx = kc }) @@ -289,7 +291,7 @@ function KoptInterface:renderReflowedPage(doc, pageno, rect, zoom, rotation, ren end -- prepare cache item with contained blitbuffer local tile = TileCacheItem:new{ - size = fullwidth * fullheight / 2 + 64, -- estimation + size = fullwidth * fullheight + 64, -- estimation excerpt = Geom:new{ w = fullwidth, h = fullheight }, pageno = pageno, } @@ -311,7 +313,7 @@ function KoptInterface:renderOptimizedPage(doc, pageno, rect, zoom, rotation, re local context_hash = self:getContextHash(doc, pageno, bbox) local renderpg_hash = "renderoptpg|"..context_hash..zoom - local cached = Cache:check(renderpg_hash) + local cached = Cache:check(renderpg_hash, TileCacheItem) if not cached then local page_size = Document.getNativePageDimensions(doc, pageno) local bbox = { @@ -329,7 +331,8 @@ function KoptInterface:renderOptimizedPage(doc, pageno, rect, zoom, rotation, re local fullwidth, fullheight = kc:getPageDim() -- prepare cache item with contained blitbuffer local tile = TileCacheItem:new{ - size = fullwidth * fullheight / 2 + 64, -- estimation + persistent = true, + size = fullwidth * fullheight + 64, -- estimation excerpt = Geom:new{ x = 0, y = 0, w = fullwidth, From f48c07335790fe175d318598a35e3bef8cd7a6da Mon Sep 17 00:00:00 2001 From: chrox Date: Thu, 30 Oct 2014 11:16:37 +0800 Subject: [PATCH 3/5] persistent cache item now need an explicit persistent flag --- frontend/cache.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/cache.lua b/frontend/cache.lua index a7306a619..a2455148e 100644 --- a/frontend/cache.lua +++ b/frontend/cache.lua @@ -136,8 +136,11 @@ function Cache:serialize() -- serialize the most recently used cache local cache_size = 0 for _, key in ipairs(self.cache_order) do - if self.cache[key].dump then - cache_size = self.cache[key]:dump(cache_path..md5(key)) or 0 + local cache_item = self.cache[key] + -- only dump cache item that requests serialization explicitly + if cache_item.persistent and cache_item.dump then + DEBUG("dump cache item", key) + cache_size = cache_item:dump(cache_path..md5(key)) or 0 if cache_size > 0 then break end end end From dfcd67c5bfa90f5855755eec20b4de02ee1e60dd Mon Sep 17 00:00:00 2001 From: chrox Date: Thu, 30 Oct 2014 15:51:31 +0800 Subject: [PATCH 4/5] move screenshot settings to submenu of Screenshot entry in readermenu And also fix a touchmenu bug that prevent some menu entries (always at the bottom of the menu) from showing submenus. The reason is that the onTapSelect method of TouchMenuItem doesn't return true, so that the tap gesture will propagate to the parent widget and be captured by touchmenu itself. But at this time the dimen of touchmenu is changed to the submenu of the tapped menuitem. If the submenu is short enough the tap will be outside of touchmenu which will cause a TapCloseAllMenus event and the submenu will never be shown. --- frontend/apps/reader/modules/readermenu.lua | 47 +++++++++++---------- frontend/ui/widget/touchmenu.lua | 8 ++-- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/frontend/apps/reader/modules/readermenu.lua b/frontend/apps/reader/modules/readermenu.lua index 8c79c3c90..da688f5bf 100644 --- a/frontend/apps/reader/modules/readermenu.lua +++ b/frontend/apps/reader/modules/readermenu.lua @@ -46,7 +46,6 @@ function ReaderMenu:init() local FileManager = require("apps/filemanager/filemanager") FileManager:restoreScreenMode() if not FileManager.is_running then - UIManager:quit() FileManager:showFiles() end end, @@ -91,8 +90,6 @@ function ReaderMenu:setUpdateItemTable() end -- setting tab - -- FIXME: it's curious that if this 'Screen' menu is placed after the Language - -- menu submenu in 'Screen' won't be shown. Probably a bug in the touchmenu module. table.insert(self.tab_item_table.setting, { text = _("Screen settings"), sub_item_table = { @@ -143,27 +140,33 @@ function ReaderMenu:setUpdateItemTable() end }) - --typeset tab if KOBO_SCREEN_SAVER_LAST_BOOK then - local exclude = self.ui.doc_settings:readSetting("exclude_screensaver") or false + local excluded = function() + return self.ui.doc_settings:readSetting("exclude_screensaver") or false + end + local proportional = function() + return self.ui.doc_settings:readSetting("proportional_screensaver") or false + end table.insert(self.tab_item_table.typeset, { - text = _("Use this book's cover as screensaver"), - checked_func = function() return not (self.ui.doc_settings:readSetting("exclude_screensaver") or false) end, - callback = function() - local exclude = self.ui.doc_settings:readSetting("exclude_screensaver") or false - self.ui.doc_settings:saveSetting("exclude_screensaver", not exclude) - self.ui:saveSettings() - end - }) - local proportional = self.ui.doc_settings:readSetting("proportional_screensaver") or false - table.insert(self.tab_item_table.typeset, { - text = _("Display proportional cover image in screensaver"), - checked_func = function() return (self.ui.doc_settings:readSetting("proportional_screensaver") or false) end, - callback = function() - local proportional = self.ui.doc_settings:readSetting("proportional_screensaver") or false - self.ui.doc_settings:saveSetting("proportional_screensaver", not proportional) - self.ui:saveSettings() - end + text = "Screensaver", + sub_item_table = { + { + text = _("Use this book's cover as screensaver"), + checked_func = function() return not excluded() end, + callback = function() + self.ui.doc_settings:saveSetting("exclude_screensaver", not excluded()) + self.ui:saveSettings() + end + }, + { + text = _("Display proportional cover image in screensaver"), + checked_func = function() return proportional() end, + callback = function() + self.ui.doc_settings:saveSetting("proportional_screensaver", not proportional()) + self.ui:saveSettings() + end + } + } }) end end diff --git a/frontend/ui/widget/touchmenu.lua b/frontend/ui/widget/touchmenu.lua index b0ea0883b..080dcec8b 100644 --- a/frontend/ui/widget/touchmenu.lua +++ b/frontend/ui/widget/touchmenu.lua @@ -103,6 +103,7 @@ function TouchMenuItem:onTapSelect(arg, ges) UIManager:setDirty(self.show_parent, "partial") end) self.menu:onMenuSelect(self.item) + return true end function TouchMenuItem:onHoldSelect(arg, ges) @@ -119,6 +120,7 @@ function TouchMenuItem:onHoldSelect(arg, ges) UIManager:setDirty(self.show_parent, "partial") end) self.menu:onMenuHold(self.item) + return true end --[[ @@ -331,11 +333,11 @@ function TouchMenu:init() self.device_info = HorizontalGroup:new{ self.time_info, self.net_info, - } - else + } + else self.device_info = HorizontalGroup:new{ self.time_info, - } + } end local footer_width = self.width - self.padding*2 - self.bordersize*2 self.footer = HorizontalGroup:new{ From 84029e9694385381a65d78d86e6ee06edc7b95bb Mon Sep 17 00:00:00 2001 From: chrox Date: Thu, 30 Oct 2014 16:01:01 +0800 Subject: [PATCH 5/5] add modal widget type that will stay on the top of window stack ConfirmBox and InfoMessage are default to be modal. Now returning to filamanager after highlighting a PDF page the confirmbox asking users to save the document will not be hidden by the filamanager window. And it's tested on Kindle that #791 is already been solved probably by out refacorting of MuPDF backend. --- frontend/ui/uimanager.lua | 16 ++++++++++++++-- frontend/ui/widget/confirmbox.lua | 1 + frontend/ui/widget/infomessage.lua | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index de9beb7d8..72a5d234a 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -132,10 +132,20 @@ function UIManager:init() end -- register & show a widget +-- modal widget should be always on the top function UIManager:show(widget, x, y) + DEBUG("show widget", widget.id) self._running = true - -- put widget on top of stack - table.insert(self._window_stack, {x = x or 0, y = y or 0, widget = widget}) + local window = {x = x or 0, y = y or 0, widget = widget} + -- put this window on top of the toppest non-modal window + for i = #self._window_stack, 0, -1 do + local top_window = self._window_stack[i] + -- skip modal window + if not top_window or not top_window.widget.modal then + table.insert(self._window_stack, i + 1, window) + break + end + end -- and schedule it to be painted self:setDirty(widget) -- tell the widget that it is shown now @@ -148,6 +158,7 @@ end -- unregister a widget function UIManager:close(widget) + DEBUG("close widget", widget.id) Input.disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP local dirty = false for i = #self._window_stack, 1, -1 do @@ -226,6 +237,7 @@ end -- signal to quit function UIManager:quit() + DEBUG("quit uimanager") self._running = false for i = #self._window_stack, 1, -1 do table.remove(self._window_stack, i) diff --git a/frontend/ui/widget/confirmbox.lua b/frontend/ui/widget/confirmbox.lua index f21240d9b..fd7a02427 100644 --- a/frontend/ui/widget/confirmbox.lua +++ b/frontend/ui/widget/confirmbox.lua @@ -24,6 +24,7 @@ local Blitbuffer = require("ffi/blitbuffer") Widget that shows a message and OK/Cancel buttons ]] local ConfirmBox = InputContainer:new{ + modal = true, text = _("no text"), face = Font:getFace("infofont", 25), ok_text = _("OK"), diff --git a/frontend/ui/widget/infomessage.lua b/frontend/ui/widget/infomessage.lua index cc006c586..adb8f4731 100644 --- a/frontend/ui/widget/infomessage.lua +++ b/frontend/ui/widget/infomessage.lua @@ -21,6 +21,7 @@ Widget that displays an informational message it vanishes on key press or after a given timeout ]] local InfoMessage = InputContainer:new{ + modal = true, face = Font:getFace("infofont", 25), text = "", timeout = nil, -- in seconds