From 35776f1f870423424cd38e47d55ca13f03bced93 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Sun, 6 Feb 2022 18:01:45 +0100 Subject: [PATCH] "Simplify" HW/SW dithering checks Make it a real Document property, updated at init & toggle time. Also, simplify a bunch of redundant nested lookups in ReaderView (self.ui.view is self, self.ui.document is self.document). --- .../reader/modules/readerkoptlistener.lua | 1 + frontend/apps/reader/modules/readerview.lua | 110 +++++++++++------- frontend/document/document.lua | 13 ++- frontend/document/picdocument.lua | 9 ++ frontend/ui/data/koptoptions.lua | 4 + 5 files changed, 90 insertions(+), 47 deletions(-) diff --git a/frontend/apps/reader/modules/readerkoptlistener.lua b/frontend/apps/reader/modules/readerkoptlistener.lua index da5703d36..3a8d76c92 100644 --- a/frontend/apps/reader/modules/readerkoptlistener.lua +++ b/frontend/apps/reader/modules/readerkoptlistener.lua @@ -33,6 +33,7 @@ function ReaderKoptListener:onReadSettings(config) if self.document.configurable.word_spacing == -1 then self.document.configurable.word_spacing = -0.2 end + self.ui:handleEvent(Event:new("DitheringUpdate")) end function ReaderKoptListener:onSaveSettings() diff --git a/frontend/apps/reader/modules/readerview.lua b/frontend/apps/reader/modules/readerview.lua index 1b88adeec..509a1bd22 100644 --- a/frontend/apps/reader/modules/readerview.lua +++ b/frontend/apps/reader/modules/readerview.lua @@ -164,7 +164,7 @@ function ReaderView:paintTo(bb, x, y) end -- draw page content - if self.ui.document.info.has_pages then + if self.ui.paging then if self.page_scroll then self:drawScrollPages(bb, x, y) else @@ -220,15 +220,14 @@ function ReaderView:paintTo(bb, x, y) -- Most pages should not require dithering self.dialog.dithered = nil -- For KOpt, let the user choose. - if self.ui.document.info.has_pages then - -- Also enforce HW dithering in PicDocument - if self.ui.document.is_pic or self.document.configurable.hw_dithering == 1 then + if self.ui.paging then + if self.document.hw_dithering then self.dialog.dithered = true end else -- Whereas for CRe, -- If we're attempting to show a large enough amount of image data, request dithering (without triggering another repaint ;)). - local img_count, img_coverage = self.ui.document:getDrawnImagesStatistics() + local img_count, img_coverage = self.document:getDrawnImagesStatistics() -- With some nil guards because this may not be implemented in every engine ;). if img_count and img_count > 0 and img_coverage and img_coverage >= 0.075 then self.dialog.dithered = true @@ -245,15 +244,15 @@ end Given coordinates on the screen return position in original page ]]-- function ReaderView:screenToPageTransform(pos) - if self.ui.document.info.has_pages then + if self.ui.paging then if self.page_scroll then return self:getScrollPagePosition(pos) else return self:getSinglePagePosition(pos) end else - pos.page = self.ui.document:getCurrentPage() - -- local last_y = self.ui.document:getCurrentPos() + pos.page = self.document:getCurrentPage() + -- local last_y = self.document:getCurrentPos() logger.dbg("document has no pages at", pos) return pos end @@ -263,7 +262,7 @@ end Given rectangle in original page return rectangle on the screen ]]-- function ReaderView:pageToScreenTransform(page, rect) - if self.ui.document.info.has_pages then + if self.ui.paging then if self.page_scroll then return self:getScrollPageRect(page, rect) else @@ -278,7 +277,7 @@ end Get page area on screen for a given page number --]] function ReaderView:getScreenPageArea(page) - if self.ui.document.info.has_pages then + if self.ui.paging then local area = Geom:new{x = 0, y = 0} if self.page_scroll then for _, state in ipairs(self.page_states) do @@ -313,7 +312,7 @@ function ReaderView:drawPageSurround(bb, x, y) bb:paintRect(x, y, self.dimen.w, self.state.offset.y, self.outer_page_color) local bottom_margin = y + self.visible_area.h + self.state.offset.y bb:paintRect(x, bottom_margin, self.dimen.w, self.state.offset.y + - self.ui.view.footer:getHeight(), self.outer_page_color) + self.footer:getHeight(), self.outer_page_color) end if self.dimen.w > self.visible_area.w then bb:paintRect(x, y, self.state.offset.x, self.dimen.h, self.outer_page_color) @@ -325,7 +324,7 @@ end function ReaderView:drawScrollPages(bb, x, y) local pos = Geom:new{x = x , y = y} for page, state in ipairs(self.page_states) do - self.ui.document:drawPage( + self.document:drawPage( bb, pos.x + state.offset.x, pos.y + state.offset.y, @@ -347,7 +346,7 @@ end function ReaderView:getCurrentPageList() local pages = {} - if self.ui.document.info.has_pages then + if self.ui.paging then if self.page_scroll then for _, state in ipairs(self.page_states) do table.insert(pages, state.page) @@ -400,7 +399,7 @@ function ReaderView:drawPageGap(bb, x, y) end function ReaderView:drawSinglePage(bb, x, y) - self.ui.document:drawPage( + self.document:drawPage( bb, x + self.state.offset.x, y + self.state.offset.y, @@ -438,7 +437,7 @@ function ReaderView:getSinglePageRect(rect_p) end function ReaderView:drawPageView(bb, x, y) - self.ui.document:drawCurrentViewByPage( + self.document:drawCurrentViewByPage( bb, x + self.state.offset.x, y + self.state.offset.y, @@ -447,7 +446,7 @@ function ReaderView:drawPageView(bb, x, y) end function ReaderView:drawScrollView(bb, x, y) - self.ui.document:drawCurrentViewByPos( + self.document:drawCurrentViewByPos( bb, x + self.state.offset.x, y + self.state.offset.y, @@ -467,7 +466,7 @@ function ReaderView:drawTempHighlight(bb, x, y) end function ReaderView:drawSavedHighlight(bb, x, y) - if self.ui.document.info.has_pages then + if self.ui.paging then self:drawPageSavedHighlight(bb, x, y) else self:drawXPointerSavedHighlight(bb, x, y) @@ -482,7 +481,7 @@ function ReaderView:drawPageSavedHighlight(bb, x, y) for i = 1, #items do local item = items[i] local pos0, pos1 = item.pos0, item.pos1 - local boxes = self.ui.document:getPageBoxesFromPositions(page, pos0, pos1) + local boxes = self.document:getPageBoxesFromPositions(page, pos0, pos1) if boxes then for _, box in pairs(boxes) do local rect = self:pageToScreenTransform(page, box) @@ -513,19 +512,19 @@ function ReaderView:drawXPointerSavedHighlight(bb, x, y) -- Even in page mode, it's safer to use pos and ui.dimen.h -- than pages' xpointers pos, even if ui.dimen.h is a bit -- larger than pages' heights - cur_view_top = self.ui.document:getCurrentPos() - if self.view_mode == "page" and self.ui.document:getVisiblePageCount() > 1 then + cur_view_top = self.document:getCurrentPos() + if self.view_mode == "page" and self.document:getVisiblePageCount() > 1 then cur_view_bottom = cur_view_top + 2 * self.ui.dimen.h else cur_view_bottom = cur_view_top + self.ui.dimen.h end end - local spos0 = self.ui.document:getPosFromXPointer(pos0) - local spos1 = self.ui.document:getPosFromXPointer(pos1) + local spos0 = self.document:getPosFromXPointer(pos0) + local spos1 = self.document:getPosFromXPointer(pos1) local start_pos = math.min(spos0, spos1) local end_pos = math.max(spos0, spos1) if start_pos <= cur_view_bottom and end_pos >= cur_view_top then - local boxes = self.ui.document:getScreenBoxesFromPositions(pos0, pos1, true) -- get_segments=true + local boxes = self.document:getScreenBoxesFromPositions(pos0, pos1, true) -- get_segments=true if boxes then for _, box in pairs(boxes) do local rect = self:pageToScreenTransform(page, box) @@ -559,9 +558,9 @@ end function ReaderView:getPageArea(page, zoom, rotation) if self.use_bbox then - return self.ui.document:getUsedBBoxDimensions(page, zoom, rotation) + return self.document:getUsedBBoxDimensions(page, zoom, rotation) else - return self.ui.document:getPageDimensions(page, zoom, rotation) + return self.document:getPageDimensions(page, zoom, rotation) end end @@ -572,17 +571,17 @@ function ReaderView:recalculate() -- Start by resetting the dithering flag early, so it doesn't carry over from the previous page. self.dialog.dithered = nil - if self.ui.document.info.has_pages and self.state.page then + if self.ui.paging and self.state.page then self.page_area = self:getPageArea( self.state.page, self.state.zoom, self.state.rotation) -- reset our size self.visible_area:setSizeTo(self.dimen) - if self.ui.view.footer_visible and not self.ui.view.footer.settings.reclaim_height then - self.visible_area.h = self.visible_area.h - self.ui.view.footer:getHeight() + if self.footer_visible and not self.footer.settings.reclaim_height then + self.visible_area.h = self.visible_area.h - self.footer:getHeight() end - if self.ui.document.configurable.writing_direction == 0 then + if self.document.configurable.writing_direction == 0 then -- starts from left of page_area self.visible_area.x = self.page_area.x else @@ -609,8 +608,8 @@ function ReaderView:recalculate() end self.state.offset = Geom:new{x = 0, y = 0} if self.dimen.h > self.visible_area.h then - if self.ui.view.footer_visible and not self.ui.view.footer.settings.reclaim_height then - self.state.offset.y = (self.dimen.h - (self.visible_area.h + self.ui.view.footer:getHeight())) / 2 + if self.footer_visible and not self.footer.settings.reclaim_height then + self.state.offset.y = (self.dimen.h - (self.visible_area.h + self.footer:getHeight())) / 2 else self.state.offset.y = (self.dimen.h - self.visible_area.h) / 2 end @@ -740,9 +739,9 @@ function ReaderView:onSetFullScreen(full_screen) end function ReaderView:onSetScrollMode(page_scroll) - if self.ui.document.info.has_pages and page_scroll + if self.ui.paging and page_scroll and self.ui.zooming.paged_modes[self.zoom_mode] - and self.ui.document.configurable.text_wrap == 0 then + and self.document.configurable.text_wrap == 0 then UIManager:show(InfoMessage:new{ text = _([[ Continuous view (scroll mode) works best with zoom to page width, zoom to content width or zoom to rows. @@ -754,7 +753,7 @@ In combination with zoom to fit page, page height, content height, content or co self.page_scroll = page_scroll if not page_scroll then - self.ui.document.configurable.page_scroll = 0 + self.document.configurable.page_scroll = 0 end self:recalculate() self.ui:handleEvent(Event:new("InitScrollPageStates")) @@ -772,7 +771,7 @@ function ReaderView:onReadSettings(config) rotation_mode = config:readSetting("rotation_mode") -- Doc's else -- No doc specific rotation, pickup global defaults for the doc type - if self.ui.document.info.has_pages then + if self.ui.paging then rotation_mode = G_reader_settings:readSetting("kopt_rotation_mode") or Screen.ORIENTATION_PORTRAIT else rotation_mode = G_reader_settings:readSetting("copt_rotation_mode") or Screen.ORIENTATION_PORTRAIT @@ -864,17 +863,17 @@ end function ReaderView:onReaderFooterVisibilityChange() -- Don't bother ReaderRolling with this nonsense, the footer's height is NOT handled via visible_area there ;) - if self.ui.document.info.has_pages and self.state.page then + if self.ui.paging and self.state.page then -- NOTE: Simply relying on recalculate would be a wee bit too much: it'd reset the in-page offsets, -- which would be wrong, and is also not necessary, since the footer is at the bottom of the screen ;). -- So, simply mangle visible_area's height ourselves... - if not self.ui.view.footer.settings.reclaim_height then + if not self.footer.settings.reclaim_height then -- NOTE: Yes, this means that toggling reclaim_height requires a page switch (for a proper recalculate). -- Thankfully, most of the time, the quirks are barely noticeable ;). - if self.ui.view.footer_visible then - self.visible_area.h = self.visible_area.h - self.ui.view.footer:getHeight() + if self.footer_visible then + self.visible_area.h = self.visible_area.h - self.footer:getHeight() else - self.visible_area.h = self.visible_area.h + self.ui.view.footer:getHeight() + self.visible_area.h = self.visible_area.h + self.footer:getHeight() end end self.ui:handleEvent(Event:new("ViewRecalculate", self.visible_area, self.page_area)) @@ -889,6 +888,33 @@ function ReaderView:onGammaUpdate(gamma) Notification:notify(T(_("Font gamma set to: %1."), gamma)) end +-- For ReaderKOptListener +function ReaderView:onDitheringUpdate() + -- Do the device cap checks again, to avoid snafus when sharing configs between devices + if Device:hasEinkScreen() then + if Device:canHWDither() then + if self.document.configurable.hw_dithering then + self.document.hw_dithering = self.document.configurable.hw_dithering == 1 + end + elseif Screen.fb_bpp == 8 then + if self.document.configurable.sw_dithering then + self.document.sw_dithering = self.document.configurable.sw_dithering == 1 + end + end + end +end + +-- For KOptOptions +function ReaderView:onHWDitheringUpdate(toggle) + self.document.hw_dithering = toggle + Notification:notify(T(_("Hardware dithering set to: %1."), tostring(toggle))) +end + +function ReaderView:onSWDitheringUpdate(toggle) + self.document.sw_dithering = toggle + Notification:notify(T(_("Software dithering set to: %1."), tostring(toggle))) +end + function ReaderView:onFontSizeUpdate(font_size) self.ui:handleEvent(Event:new("ReZoom", font_size)) Notification:notify(T(_("Font zoom set to: %1."), font_size)) @@ -909,7 +935,7 @@ end function ReaderView:onSetViewMode(new_mode) if new_mode ~= self.view_mode then self.view_mode = new_mode - self.ui.document:setViewMode(new_mode) + self.document:setViewMode(new_mode) self.ui:handleEvent(Event:new("ChangeViewMode")) Notification:notify(T( _("View mode set to: %1"), optionsutil:getOptionText("SetViewMode", new_mode))) end @@ -1006,7 +1032,7 @@ function ReaderView:checkAutoSaveSettings() end function ReaderView:isOverlapAllowed() - if self.ui.document.info.has_pages then + if self.ui.paging then return not self.page_scroll and (self.ui.paging.zoom_mode ~= "page" or (self.ui.paging.zoom_mode == "page" and self.ui.paging.is_reflowed)) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index 90f4de793..668f3eb73 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -75,9 +75,14 @@ function Document:_init() date = "" } - -- Should be updated by a call to Document.updateColorRendering(self) - -- in subclasses + -- Should be updated by a call to Document.updateColorRendering(self) in subclasses self.render_color = false + + -- Those may be updated via KOptOptions, or the DitheringUpdate event. + -- Whether HW dithering is enabled + self.hw_dithering = false + -- Whether SW dithering is enabled + self.sw_dithering = false end -- override this method to open a document @@ -496,9 +501,7 @@ Draw page content to blitbuffer. function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, render_mode) local tile = self:renderPage(pageno, rect, zoom, rotation, gamma, render_mode) -- Enable SW dithering if requested (only available in koptoptions) - -- Much Like ReaderView, also enforce SW dithering in PicDocument if the device can't do HW dithering... - if (self.is_pic and CanvasContext:hasEinkScreen() and not CanvasContext:canHWDither() and CanvasContext.fb_bpp == 8) - or (self.configurable.sw_dithering and self.configurable.sw_dithering == 1) then + if self.sw_dithering then target:ditherblitFrom(tile.bb, x, y, rect.x - tile.excerpt.x, diff --git a/frontend/document/picdocument.lua b/frontend/document/picdocument.lua index 1422a7481..c2cde6872 100644 --- a/frontend/document/picdocument.lua +++ b/frontend/document/picdocument.lua @@ -26,6 +26,15 @@ function PicDocument:init() self.info.has_pages = true self.info.configurable = false + -- Enforce dithering in PicDocument + if CanvasContext:hasEinkScreen() then + if CanvasContext:canHWDither() then + self.hw_dithering = true + elseif CanvasContext.fb_bpp == 8 then + self.sw_dithering = true + end + end + self:_readMetadata() end diff --git a/frontend/ui/data/koptoptions.lua b/frontend/ui/data/koptoptions.lua index b0eacdc0d..a6dd67389 100644 --- a/frontend/ui/data/koptoptions.lua +++ b/frontend/ui/data/koptoptions.lua @@ -502,6 +502,8 @@ This can also be used to remove some gray background or to convert a grayscale o values = {0, 1}, default_value = 0, advanced = true, + event = "HWDitheringUpdate", + args = {false, true}, show = Device:hasEinkScreen() and Device:canHWDither(), name_text_hold_callback = optionsutil.showValues, help_text = _([[Enable hardware dithering.]]), @@ -513,6 +515,8 @@ This can also be used to remove some gray background or to convert a grayscale o values = {0, 1}, default_value = 0, advanced = true, + event = "SWDitheringUpdate", + args = {false, true}, show = Device:hasEinkScreen() and not Device:canHWDither() and Device.screen.fb_bpp == 8, name_text_hold_callback = optionsutil.showValues, help_text = _([[Enable software dithering.]]),