From 683c7eee2c5873021510d089625ab585b4e7123e Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Fri, 7 Dec 2012 16:42:27 -0500 Subject: [PATCH 01/12] handle corrupted usedbbox in Document:getUsedBBoxDimensions() --- frontend/document/document.lua | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index cd73f22ef..fca96135b 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -124,16 +124,24 @@ function Document:getPageDimensions(pageno, zoom, rotation) return native_dimen end +--[[ +This method returns pagesize if bbox is corrupted +--]] function Document:getUsedBBoxDimensions(pageno, zoom, rotation) ubbox = self:getUsedBBox(pageno) - ubbox_dimen = Geom:new{ - x = ubbox.x0, - y = ubbox.y0, - w = ubbox.x1 - ubbox.x0, - h = ubbox.y1 - ubbox.y0, - } - if zoom ~= 1 then - ubbox_dimen:transformByScale(zoom) + if ubbox.x0 < 0 or ubbox.y0 < 0 or ubbox.x1 < 0 or ubbox.y1 < 0 then + -- if document's bbox info is corrupted, we use the page size + ubbox_dimen = self:getPageDimensions(pageno, zoom, rotation) + else + ubbox_dimen = Geom:new{ + x = ubbox.x0, + y = ubbox.y0, + w = ubbox.x1 - ubbox.x0, + h = ubbox.y1 - ubbox.y0, + } + if zoom ~= 1 then + ubbox_dimen:transformByScale(zoom) + end end return ubbox_dimen end From e98a89f8d57bf290330e23511d5d8c0cfde56294 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 8 Dec 2012 01:05:10 -0500 Subject: [PATCH 02/12] demo for dimming on page overlap --- frontend/ui/reader/readerpaging.lua | 68 +++++++++++++++++++++++++--- frontend/ui/reader/readerrolling.lua | 47 +++++++++++-------- frontend/ui/reader/readerview.lua | 19 +++++++- 3 files changed, 105 insertions(+), 29 deletions(-) diff --git a/frontend/ui/reader/readerpaging.lua b/frontend/ui/reader/readerpaging.lua index a75279bc6..f06739123 100644 --- a/frontend/ui/reader/readerpaging.lua +++ b/frontend/ui/reader/readerpaging.lua @@ -3,6 +3,8 @@ ReaderPaging = InputContainer:new{ number_of_pages = 0, visible_area = nil, page_area = nil, + show_overlap_enable = true, + overlap = 20, } function ReaderPaging:init() @@ -67,6 +69,10 @@ end function ReaderPaging:onReadSettings(config) self:gotoPage(config:readSetting("last_page") or 1) + local soe = config:readSetting("show_overlap_enable") + if not soe then + self.show_overlap_enable = soe + end end function ReaderPaging:onCloseDocument() @@ -112,7 +118,7 @@ end function ReaderPaging:onViewRecalculate(visible_area, page_area) -- we need to remember areas to handle page turn event - self.visible_area = visible_area + self.visible_area = visible_area:copy() self.page_area = page_area end @@ -144,28 +150,76 @@ function ReaderPaging:onGotoPageRel(diff) x_pan_off = self.visible_area.w * diff end end - -- adjust offset to help with page turn decision + -- we dont take overlap into account here yet, otherwise new_va will + -- always intersect with page_area x_pan_off = math.roundAwayFromZero(x_pan_off) y_pan_off = math.roundAwayFromZero(y_pan_off) new_va.x = math.roundAwayFromZero(self.visible_area.x+x_pan_off) new_va.y = math.roundAwayFromZero(self.visible_area.y+y_pan_off) - if (new_va:notIntersectWith(self.page_area)) then + if new_va:notIntersectWith(self.page_area) then + -- view area out of page area, do a page turn self:gotoPage(self.current_page + diff) -- if we are going back to previous page, reset - -- view to bottom of previous page + -- view area to bottom of previous page if x_pan_off < 0 then self.view:PanningUpdate(self.page_area.w, 0) elseif y_pan_off < 0 then self.view:PanningUpdate(0, self.page_area.h) end + -- reset dim_area + --self.view.dim_area.h = 0 + --self.view.dim_area.w = 0 + -- else + -- not end of page yet, goto next view + -- adjust panning step according to overlap + if self.show_overlap_enable then + if x_pan_off > self.overlap then + -- moving to next view, move view + x_pan_off = x_pan_off - self.overlap + elseif x_pan_off < -self.overlap then + x_pan_off = x_pan_off + self.overlap + end + if y_pan_off > self.overlap then + y_pan_off = y_pan_off - self.overlap + elseif y_pan_off < -self.overlap then + y_pan_off = y_pan_off + self.overlap + end + -- we have to calculate again to count into overlap + new_va.x = math.roundAwayFromZero(self.visible_area.x+x_pan_off) + new_va.y = math.roundAwayFromZero(self.visible_area.y+y_pan_off) + end -- fit new view area into page area new_va:offsetWithin(self.page_area, 0, 0) - self.view:PanningUpdate( - new_va.x - self.visible_area.x, - new_va.y - self.visible_area.y) + -- calculate panning offsets + local panned_x = new_va.x - self.visible_area.x + local panned_y = new_va.y - self.visible_area.y + -- adjust for crazy float point overflow... + if math.abs(panned_x) < 1 then + panned_x = 0 + end + if math.abs(panned_y) < 1 then + panned_y = 0 + end + -- singal panning update + self.view:PanningUpdate(panned_x, panned_y) + -- update dime area in ReaderView + if self.show_overlap_enable then + self.view.dim_area.h = new_va.h - math.abs(panned_y) + self.view.dim_area.w = new_va.w - math.abs(panned_x) + if panned_y < 0 then + self.view.dim_area.y = new_va.y - panned_y + else + self.view.dim_area.y = 0 + end + if panned_x < 0 then + self.view.dim_area.x = new_va.x - panned_x + else + self.view.dim_area.x = 0 + end + end -- update self.visible_area self.visible_area = new_va end diff --git a/frontend/ui/reader/readerrolling.lua b/frontend/ui/reader/readerrolling.lua index 8f6f63a2b..942921843 100644 --- a/frontend/ui/reader/readerrolling.lua +++ b/frontend/ui/reader/readerrolling.lua @@ -1,29 +1,12 @@ require "ui/reader/readerpanning" ReaderRolling = InputContainer:new{ - key_events = { - GotoNextView = { {Input.group.PgFwd}, doc = "go to next view", event = "GotoViewRel", args = 1 }, - GotoPrevView = { {Input.group.PgBack}, doc = "go to previous view", event = "GotoViewRel", args = -1 }, - - MoveUp = { {"Up"}, doc = "move view up", event = "Panning", args = {0, -1} }, - MoveDown = { {"Down"}, doc = "move view down", event = "Panning", args = {0, 1} }, - - GotoFirst = { {"1"}, doc = "go to start", event = "GotoPercent", args = 0}, - Goto11 = { {"2"}, doc = "go to 11%", event = "GotoPercent", args = 11}, - Goto22 = { {"3"}, doc = "go to 22%", event = "GotoPercent", args = 22}, - Goto33 = { {"4"}, doc = "go to 33%", event = "GotoPercent", args = 33}, - Goto44 = { {"5"}, doc = "go to 44%", event = "GotoPercent", args = 44}, - Goto55 = { {"6"}, doc = "go to 55%", event = "GotoPercent", args = 55}, - Goto66 = { {"7"}, doc = "go to 66%", event = "GotoPercent", args = 66}, - Goto77 = { {"8"}, doc = "go to 77%", event = "GotoPercent", args = 77}, - Goto88 = { {"9"}, doc = "go to 88%", event = "GotoPercent", args = 88}, - GotoLast = { {"0"}, doc = "go to end", event = "GotoPercent", args = 100}, - }, - old_doc_height = nil, current_pos = 0, doc_height = nil, panning_steps = ReaderPanning.panning_steps, + show_overlap_enable = true, + overlap = 20, } function ReaderRolling:init() @@ -103,6 +86,10 @@ end function ReaderRolling:onReadSettings(config) self:gotoPercent(config:readSetting("last_percent") or 0) + local soe = config:readSetting("show_overlap_enable") + if not soe then + self.show_overlap_enable = soe + end end function ReaderRolling:onCloseDocument() @@ -132,7 +119,15 @@ end function ReaderRolling:onGotoViewRel(diff) DEBUG("goto relative screen:", diff) - self:gotoPos(self.current_pos + diff * self.ui.dimen.h) + local pan_diff = diff * self.ui.dimen.h + if self.show_overlap_enable then + if pan_diff > self.overlap then + pan_diff = pan_diff - self.overlap + elseif pan_diff < -self.overlap then + pan_diff = pan_diff + self.overlap + end + end + self:gotoPos(self.current_pos + pan_diff) return true end @@ -167,6 +162,18 @@ function ReaderRolling:gotoPos(new_pos) if new_pos == self.current_pos then return end if new_pos < 0 then new_pos = 0 end if new_pos > self.doc_height then new_pos = self.doc_height end + -- adjust dim_area according to new_pos + if self.show_overlap_enable then + local panned_step = new_pos - self.current_pos + self.view.dim_area.x = 0 + self.view.dim_area.h = self.ui.dimen.h - math.abs(panned_step) + self.view.dim_area.w = self.ui.dimen.w + if panned_step < 0 then + self.view.dim_area.y = self.ui.dimen.h - self.view.dim_area.h + elseif panned_step > 0 then + self.view.dim_area.y = 0 + end + end self.ui:handleEvent(Event:new("PosUpdate", new_pos)) end diff --git a/frontend/ui/reader/readerview.lua b/frontend/ui/reader/readerview.lua index e0662c471..b977dc555 100644 --- a/frontend/ui/reader/readerview.lua +++ b/frontend/ui/reader/readerview.lua @@ -17,6 +17,8 @@ ReaderView = WidgetContainer:new{ visible_area = Geom:new{x = 0, y = 0}, -- dimen for current viewing page page_area = Geom:new{}, + -- dimen for area to dim + dim_area = Geom:new{w = 0, h = 0}, } function ReaderView:paintTo(bb, x, y) @@ -54,8 +56,18 @@ function ReaderView:paintTo(bb, x, y) self.visible_area, self.state.pos) end + -- dim last read area + if self.dim_area.w ~= 0 and self.dim_area.h ~= 0 then + bb:dimRect( + self.dim_area.x, self.dim_area.y, + self.dim_area.w, self.dim_area.h + ) + end end +--[[ +This method is supposed to be only used by ReaderPaging +--]] function ReaderView:recalculate() local page_size = nil if self.ui.document.info.has_pages then @@ -77,11 +89,14 @@ function ReaderView:recalculate() self.visible_area:setSizeTo(self.dimen) -- and recalculate it according to page size self.visible_area:offsetWithin(self.page_area, 0, 0) + -- clear dim area + self.dim_area.w = 0 + self.dim_area.h = 0 + self.ui:handleEvent( + Event:new("ViewRecalculate", self.visible_area, self.page_area)) else self.visible_area:setSizeTo(self.dimen) end - self.ui:handleEvent( - Event:new("ViewRecalculate", self.visible_area, self.page_area)) -- flag a repaint so self:paintTo will be called UIManager:setDirty(self.dialog) end From cc38d9e6fcd8b51d16d9d39e6bdcb5cae9eab2db Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 8 Dec 2012 01:06:47 -0500 Subject: [PATCH 03/12] add KT support --- frontend/ui/device.lua | 11 +++++++++-- frontend/ui/inputevent.lua | 6 +++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/frontend/ui/device.lua b/frontend/ui/device.lua index aaa3b1525..915b60447 100644 --- a/frontend/ui/device.lua +++ b/frontend/ui/device.lua @@ -15,9 +15,16 @@ function Device:getModel() end end if cpu_mod == "MX50" then - local f = lfs.attributes("/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity") - if f then + -- for KPW + local pw_test_fd = lfs.attributes("/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity") + -- for KT + local kt_test_fd = lfs.attributes("/sys/devices/platform/whitney-button") + -- another special file for KT is Neonode zForce touchscreen: + -- /sys/devices/platform/zforce.0/ + if pw_test_fd then return "KindlePaperWhite" + elseif kt_test_fd then + return "KindleTouch" else return "Kindle4" end diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index 89a496f29..efd2a58b8 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -239,13 +239,17 @@ function Input:init() else input.open("fake_events") local dev_mod = Device:getModel() - + -- open event0 for all models input.open("/dev/input/event0") if dev_mod ~= "KindlePaperWhite" then -- we don't have event1 in KindlePaperWhite input.open("/dev/input/event1") elseif dev_mod == "KindlePaperWhite" then print("Auto-detected Kindle PaperWhite") + elseif dev_mod == "KindleTouch" then + input.open("/dev/input/event2") + input.open("/dev/input/event3") + print("Auto-detected Kindle Touch") elseif dev_mod == "Kindle4" then print("Auto-detected Kindle 4") self:adjustKindle4EventMap() From bf86cf7a93b418efd577837ab8180c6ec605595e Mon Sep 17 00:00:00 2001 From: eureka <@mobileread.com> Date: Mon, 10 Dec 2012 18:52:22 -0500 Subject: [PATCH 04/12] KT input device patch from eureka * add KT detection * remove unnacessary input device for KT --- frontend/ui/device.lua | 2 +- frontend/ui/inputevent.lua | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/frontend/ui/device.lua b/frontend/ui/device.lua index 915b60447..454453a9a 100644 --- a/frontend/ui/device.lua +++ b/frontend/ui/device.lua @@ -67,7 +67,7 @@ end function Device:isTouchDevice() local model = self:getModel() - return (model == "Kindle4") or (model == "KindlePaperWhite") or util.isEmulated() + return (model == "Kindle4") or (model == "KindlePaperWhite") or (model == "KindleTouch") or util.isEmulated() end function Device:intoScreenSaver() diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index efd2a58b8..a7b52f590 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -239,16 +239,20 @@ function Input:init() else input.open("fake_events") local dev_mod = Device:getModel() - -- open event0 for all models - input.open("/dev/input/event0") - if dev_mod ~= "KindlePaperWhite" then - -- we don't have event1 in KindlePaperWhite + if dev_mod ~= "KindleTouch" then + -- event0 in KindleTouch is "WM8962 Beep Generator" (useless) + input.open("/dev/input/event0") + end + if dev_mod ~= "KindleTouch" and dev_mod ~= "KindlePaperWhite" then + -- event1 in KindleTouch is "imx-yoshi Headset" (useless) + -- and we don't have event1 in KindlePaperWhite input.open("/dev/input/event1") - elseif dev_mod == "KindlePaperWhite" then + end + if dev_mod == "KindlePaperWhite" then print("Auto-detected Kindle PaperWhite") elseif dev_mod == "KindleTouch" then - input.open("/dev/input/event2") - input.open("/dev/input/event3") + input.open("/dev/input/event2") -- Home button + input.open("/dev/input/event3") -- touchscreen print("Auto-detected Kindle Touch") elseif dev_mod == "Kindle4" then print("Auto-detected Kindle 4") From 1b7357fc0f7798035d6e27ff395d7ceaa5e704a9 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 10 Dec 2012 19:01:32 -0500 Subject: [PATCH 05/12] add Device:hasKeyboard to help initialize UI components So that kindle4 won't have all the gesture event registered. --- frontend/ui/device.lua | 14 ++++++++++++-- reader.lua | 5 +---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/frontend/ui/device.lua b/frontend/ui/device.lua index 454453a9a..1ff787c5f 100644 --- a/frontend/ui/device.lua +++ b/frontend/ui/device.lua @@ -1,6 +1,7 @@ Device = { screen_saver_mode = false, charging_mode = false, + model = nil, } function Device:getModel() @@ -65,9 +66,18 @@ function Device:isKindle2() end end +function Device:hasNoKeyboard() + if not self.model then + self.model = self:getModel() + end + return self:isTouchDevice() or (self.model == "Kindle4") +end + function Device:isTouchDevice() - local model = self:getModel() - return (model == "Kindle4") or (model == "KindlePaperWhite") or (model == "KindleTouch") or util.isEmulated() + if not self.model then + self.model = self:getModel() + end + return (self.model == "KindlePaperWhite") or (self.model == "KindleTouch") or util.isEmulated() end function Device:intoScreenSaver() diff --git a/reader.lua b/reader.lua index 51932222c..12afe36ea 100755 --- a/reader.lua +++ b/reader.lua @@ -62,9 +62,6 @@ end -- option parsing: longopts = { - password = "p", - goto = "g", - gamma = "G", debug = "d", help = "h", } @@ -97,7 +94,7 @@ else DEBUG = function() end end -if Device.isKindle4() or Device:isTouchDevice() then +if Device:hasNoKeyboard() then -- remove menu item shortcut for K4 Menu.is_enable_shortcut = false end From 334f680598977c4704fd60299b77ecc44cd83564 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 10 Dec 2012 19:54:44 -0500 Subject: [PATCH 06/12] use proper eink update function for KT --- einkfb.c | 269 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 137 insertions(+), 132 deletions(-) diff --git a/einkfb.c b/einkfb.c index cdbc61658..d7a594288 100644 --- a/einkfb.c +++ b/einkfb.c @@ -19,13 +19,130 @@ #include #include #include -//#include +#include #include "einkfb.h" #ifdef EMULATE_READER - int emu_w = EMULATE_READER_W; - int emu_h = EMULATE_READER_H; +int emu_w = EMULATE_READER_W; +int emu_h = EMULATE_READER_H; +#else +static void (*einkUpdateFunc)(FBInfo *fb, lua_State *L) = NULL; + +inline void fbInvert4BppTo8Bpp(FBInfo *fb) { + int i = 0, j = 0, h = 0, w = 0, pitch = 0, fb_pitch = 0; + uint8_t *shadow_buf = NULL, *fb_buf = NULL; + + shadow_buf = fb->buf->data; + fb_buf = fb->real_buf->data; + h = fb->buf->h; + w = fb->buf->w; + pitch = fb->buf->pitch; + fb_pitch = fb->real_buf->pitch; + + /* copy bitmap from 4bpp shadow blitbuffer to framebuffer */ + for (i = (h-1); i > 0; i--) { + for (j = (w-1)/2; j > 0; j--) { + fb_buf[i*fb_pitch + j*2] = shadow_buf[i*pitch + j]; + fb_buf[i*fb_pitch + j*2] &= 0xF0; + fb_buf[i*fb_pitch + j*2] |= shadow_buf[i*pitch + j]>>4 & 0x0F; + + fb_buf[i*fb_pitch + j*2 + 1] = shadow_buf[i*pitch + j]; + fb_buf[i*fb_pitch + j*2 + 1] &= 0x0F; + fb_buf[i*fb_pitch + j*2 + 1] |= shadow_buf[i*pitch + j]<<4 & 0xF0; + } + } +} + +inline void fb4BppTo8Bpp(FBInfo *fb) { + int i = 0, j = 0, h = 0, w = 0, pitch = 0, fb_pitch = 0; + uint8_t *shadow_buf = NULL, *fb_buf = NULL; + + shadow_buf = fb->buf->data; + fb_buf = fb->real_buf->data; + /* h is 1024 for PaperWhite */ + h = fb->buf->h; + /* w is 758 for PaperWhite */ + w = fb->buf->w; + /* pitch is 384 for shadow buffer */ + pitch = fb->buf->pitch; + /* pitch is 768 for PaperWhite */ + fb_pitch = fb->real_buf->pitch; + + /* copy bitmap from 4bpp shadow blitbuffer to framebuffer */ + for (i = (h-1); i > 0; i--) { + for (j = (w-1)/2; j > 0; j--) { + fb_buf[i*fb_pitch + j*2] = shadow_buf[i*pitch + j]; + fb_buf[i*fb_pitch + j*2] &= 0xF0; + fb_buf[i*fb_pitch + j*2] |= shadow_buf[i*pitch + j]>>4 & 0x0F; + fb_buf[i*fb_pitch + j*2] = ~fb_buf[i*fb_pitch + j*2]; + + fb_buf[i*fb_pitch + j*2 + 1] = shadow_buf[i*pitch + j]; + fb_buf[i*fb_pitch + j*2 + 1] &= 0x0F; + fb_buf[i*fb_pitch + j*2 + 1] |= shadow_buf[i*pitch + j]<<4 & 0xF0; + fb_buf[i*fb_pitch + j*2 + 1] = ~fb_buf[i*fb_pitch + j*2 + 1]; + } + } +} + +inline void fillUpdateAreaT(update_area_t *myarea, FBInfo *fb, lua_State *L) { + int fxtype = luaL_optint(L, 2, 0); + + myarea->x1 = luaL_optint(L, 3, 0); + myarea->y1 = luaL_optint(L, 4, 0); + myarea->x2 = myarea->x1 + luaL_optint(L, 5, fb->vinfo.xres); + myarea->y2 = myarea->y1 + luaL_optint(L, 6, fb->vinfo.yres); + myarea->buffer = NULL; + myarea->which_fx = fxtype ? fx_update_partial : fx_update_full; +} + +inline void fillMxcfbUpdateData51(mxcfb_update_data51 *myarea, FBInfo *fb, lua_State *L) { + myarea->update_region.top = luaL_optint(L, 3, 0); + myarea->update_region.left = luaL_optint(L, 4, 0); + myarea->update_region.width = luaL_optint(L, 5, fb->vinfo.xres); + myarea->update_region.height = luaL_optint(L, 6, fb->vinfo.yres); + myarea->waveform_mode = 257; + myarea->update_mode = 0; + myarea->update_marker = 1; + myarea->hist_bw_waveform_mode = 0; + myarea->hist_gray_waveform_mode = 0; + myarea->temp = 0x1001; + myarea->flags = 0; + myarea->alt_buffer_data.virt_addr = NULL; + myarea->alt_buffer_data.phys_addr = NULL; + myarea->alt_buffer_data.width = 0; + myarea->alt_buffer_data.height = 0; + myarea->alt_buffer_data.alt_update_region.top = 0; + myarea->alt_buffer_data.alt_update_region.left = 0; + myarea->alt_buffer_data.alt_update_region.width = 0; + myarea->alt_buffer_data.alt_update_region.height = 0; +} + +void kindle3einkUpdate(FBInfo *fb, lua_State *L) { + update_area_t myarea; + + fillUpdateAreaT(&myarea, fb, L); + + ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea); +} + +void kindle4einkUpdate(FBInfo *fb, lua_State *L) { + update_area_t myarea; + + fbInvert4BppTo8Bpp(fb); + fillUpdateAreaT(&myarea, fb, L); + + ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea); +} + +void kindle51einkUpdate(FBInfo *fb, lua_State *L) { + mxcfb_update_data51 myarea; + + fb4BppTo8Bpp(fb); + fillMxcfbUpdateData51(&myarea, fb, L); + + ioctl(fb->fd, 0x4048462e, &myarea); +} #endif static int openFrameBuffer(lua_State *L) { @@ -65,6 +182,22 @@ static int openFrameBuffer(lua_State *L) { fb->finfo.type); } + if (strncmp(fb->finfo.id, "mxc_epdc_fb", 11) == 0) { + /* Kindle PaperWhite and KT with 5.1 or later firmware */ + einkUpdateFunc = &kindle51einkUpdate; + } else if (strncmp(fb->finfo.id, "eink_fb", 7) == 0) { + if (fb->vinfo.bits_per_pixel == 8) { + /* kindle4 */ + einkUpdateFunc = &kindle4einkUpdate; + } else { + /* kindle2, 3, DXG */ + einkUpdateFunc = &kindle3einkUpdate; + } + } else { + return luaL_error(L, "eink model %s not supported", + fb->finfo.id); + } + if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo)) { return luaL_error(L, "cannot get variable screen info"); } @@ -167,139 +300,11 @@ static int closeFrameBuffer(lua_State *L) { return 0; } -#ifndef EMULATE_READER -inline void fbInvert4BppTo8Bpp(FBInfo *fb) { - int i = 0, j = 0, h = 0, w = 0, pitch = 0, fb_pitch = 0; - uint8_t *shadow_buf = NULL, *fb_buf = NULL; - - shadow_buf = fb->buf->data; - fb_buf = fb->real_buf->data; - h = fb->buf->h; - w = fb->buf->w; - pitch = fb->buf->pitch; - fb_pitch = fb->real_buf->pitch; - - /* copy bitmap from 4bpp shadow blitbuffer to framebuffer */ - for (i = (h-1); i > 0; i--) { - for (j = (w-1)/2; j > 0; j--) { - fb_buf[i*fb_pitch + j*2] = shadow_buf[i*pitch + j]; - fb_buf[i*fb_pitch + j*2] &= 0xF0; - fb_buf[i*fb_pitch + j*2] |= shadow_buf[i*pitch + j]>>4 & 0x0F; - - fb_buf[i*fb_pitch + j*2 + 1] = shadow_buf[i*pitch + j]; - fb_buf[i*fb_pitch + j*2 + 1] &= 0x0F; - fb_buf[i*fb_pitch + j*2 + 1] |= shadow_buf[i*pitch + j]<<4 & 0xF0; - } - } -} - -inline void fb4BppTo8Bpp(FBInfo *fb) { - int i = 0, j = 0, h = 0, w = 0, pitch = 0, fb_pitch = 0; - uint8_t *shadow_buf = NULL, *fb_buf = NULL; - - shadow_buf = fb->buf->data; - fb_buf = fb->real_buf->data; - /* h is 1024 for PaperWhite */ - h = fb->buf->h; - /* w is 758 for PaperWhite */ - w = fb->buf->w; - /* pitch is 384 for shadow buffer */ - pitch = fb->buf->pitch; - /* pitch is 768 for PaperWhite */ - fb_pitch = fb->real_buf->pitch; - - /* copy bitmap from 4bpp shadow blitbuffer to framebuffer */ - for (i = (h-1); i > 0; i--) { - for (j = (w-1)/2; j > 0; j--) { - fb_buf[i*fb_pitch + j*2] = shadow_buf[i*pitch + j]; - fb_buf[i*fb_pitch + j*2] &= 0xF0; - fb_buf[i*fb_pitch + j*2] |= shadow_buf[i*pitch + j]>>4 & 0x0F; - fb_buf[i*fb_pitch + j*2] = ~fb_buf[i*fb_pitch + j*2]; - - fb_buf[i*fb_pitch + j*2 + 1] = shadow_buf[i*pitch + j]; - fb_buf[i*fb_pitch + j*2 + 1] &= 0x0F; - fb_buf[i*fb_pitch + j*2 + 1] |= shadow_buf[i*pitch + j]<<4 & 0xF0; - fb_buf[i*fb_pitch + j*2 + 1] = ~fb_buf[i*fb_pitch + j*2 + 1]; - } - } -} - -inline void fillUpdateAreaT(update_area_t *myarea, FBInfo *fb, lua_State *L) { - int fxtype = luaL_optint(L, 2, 0); - - myarea->x1 = luaL_optint(L, 3, 0); - myarea->y1 = luaL_optint(L, 4, 0); - myarea->x2 = myarea->x1 + luaL_optint(L, 5, fb->vinfo.xres); - myarea->y2 = myarea->y1 + luaL_optint(L, 6, fb->vinfo.yres); - myarea->buffer = NULL; - myarea->which_fx = fxtype ? fx_update_partial : fx_update_full; -} - -inline void fillMxcfbUpdateData51(mxcfb_update_data51 *myarea, FBInfo *fb, lua_State *L) { - myarea->update_region.top = luaL_optint(L, 3, 0); - myarea->update_region.left = luaL_optint(L, 4, 0); - myarea->update_region.width = luaL_optint(L, 5, fb->vinfo.xres); - myarea->update_region.height = luaL_optint(L, 6, fb->vinfo.yres); - myarea->waveform_mode = 257; - myarea->update_mode = 0; - myarea->update_marker = 1; - myarea->hist_bw_waveform_mode = 0; - myarea->hist_gray_waveform_mode = 0; - myarea->temp = 0x1001; - myarea->flags = 0; - myarea->alt_buffer_data.virt_addr = NULL; - myarea->alt_buffer_data.phys_addr = NULL; - myarea->alt_buffer_data.width = 0; - myarea->alt_buffer_data.height = 0; - myarea->alt_buffer_data.alt_update_region.top = 0; - myarea->alt_buffer_data.alt_update_region.left = 0; - myarea->alt_buffer_data.alt_update_region.width = 0; - myarea->alt_buffer_data.alt_update_region.height = 0; -} - -inline void Kindle3einkUpdate(FBInfo *fb, lua_State *L) { - update_area_t myarea; - - fillUpdateAreaT(&myarea, fb, L); - - ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea); -} - -inline void kindle4einkUpdate(FBInfo *fb, lua_State *L) { - update_area_t myarea; - - fbInvert4BppTo8Bpp(fb); - fillUpdateAreaT(&myarea, fb, L); - - ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea); -} - -inline void kindlePWeinkUpdate(FBInfo *fb, lua_State *L) { - mxcfb_update_data51 myarea; - - fb4BppTo8Bpp(fb); - fillMxcfbUpdateData51(&myarea, fb, L); - - ioctl(fb->fd, 0x4048462e, &myarea); -} -#endif - static int einkUpdate(lua_State *L) { FBInfo *fb = (FBInfo*) luaL_checkudata(L, 1, "einkfb"); // for Kindle e-ink display #ifndef EMULATE_READER - if (fb->vinfo.bits_per_pixel == 8) { - if (fb->buf->h == 1024) { - /* Kindle PaperWhite */ - kindlePWeinkUpdate(fb, L); - } else { - /* kindle4 */ - kindle4einkUpdate(fb, L); - } - } else { - /* kindle2, 3, DXG */ - Kindle3einkUpdate(fb, L); - } + einkUpdateFunc(fb, L); #else int fxtype = luaL_optint(L, 2, 0); // for now, we only do fullscreen blits in emulation mode From 15e0af285727e8bc55b3bb7e800d8267ee1417f7 Mon Sep 17 00:00:00 2001 From: eureka <@mobileread.com> Date: Mon, 10 Dec 2012 20:06:27 -0500 Subject: [PATCH 07/12] update mxcfb_alt_buffer_data struct, added MXCFB_SEND_UPDATE51 * mxcfb_alt_buffer_data is modified according to amazon's source * use MXCFB_SEND_UPDATE51 instead of magic raw number for update --- einkfb.c | 4 ++-- include/mxcfb.h | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/einkfb.c b/einkfb.c index d7a594288..f4a10a8bb 100644 --- a/einkfb.c +++ b/einkfb.c @@ -108,7 +108,7 @@ inline void fillMxcfbUpdateData51(mxcfb_update_data51 *myarea, FBInfo *fb, lua_S myarea->hist_gray_waveform_mode = 0; myarea->temp = 0x1001; myarea->flags = 0; - myarea->alt_buffer_data.virt_addr = NULL; + /*myarea->alt_buffer_data.virt_addr = NULL;*/ myarea->alt_buffer_data.phys_addr = NULL; myarea->alt_buffer_data.width = 0; myarea->alt_buffer_data.height = 0; @@ -141,7 +141,7 @@ void kindle51einkUpdate(FBInfo *fb, lua_State *L) { fb4BppTo8Bpp(fb); fillMxcfbUpdateData51(&myarea, fb, L); - ioctl(fb->fd, 0x4048462e, &myarea); + ioctl(fb->fd, MXCFB_SEND_UPDATE51, &myarea); } #endif diff --git a/include/mxcfb.h b/include/mxcfb.h index e4e885bf8..4e313299b 100644 --- a/include/mxcfb.h +++ b/include/mxcfb.h @@ -1,12 +1,15 @@ /* * Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved. * - * Modified by houqp, added mxcfb_update_data51 struct from GeekMaster's video - * player, refer to: - * http://www.mobileread.com/forums/showthread.php?t=177455&page=10 - */ - -/* + * - Modified by houqp, added mxcfb_update_data51 struct from GeekMaster's + * video player, refer to: + * http://www.mobileread.com/forums/showthread.php?t=177455&page=10 + * + * - Modified mxcfb_alt_buffer_data struct according to include/linux/mxcfb.h + * from Kindle 5.3.0 firmware. Thanks to eureka@mobileread. + * http://www.mobileread.com/forums/showpost.php?p=2337118&postcount=818 + * + * * The code contained herein is licensed under the GNU Lesser General * Public License. You may obtain a copy of the GNU Lesser General * Public License Version 2.1 or later at the following locations: @@ -96,7 +99,8 @@ struct mxcfb_rect { #define FB_TEMP_AUTO_UPDATE_DISABLE -1 struct mxcfb_alt_buffer_data { - void *virt_addr; + /* virt_addr is not included in amazon's source */ + /* void *virt_addr; */ __u32 phys_addr; __u32 width; /* width of entire buffer */ __u32 height; /* height of entire buffer */ @@ -168,6 +172,9 @@ struct mxcfb_waveform_modes { #define MXCFB_SET_TEMP_AUTO_UPDATE_PERIOD _IOR('F', 0x36, int32_t) #define MXCFB_SET_MERGE_ON_WAVEFORM_MISMATCH _IOW('F', 0x37, int32_t) +/* IOCTLs for E-ink panel updates, kindle firmware version >= 5.1 */ +#define MXCFB_SEND_UPDATE51 _IOW('F', 0x2E, struct mxcfb_update_data51) + #ifdef __KERNEL__ extern struct fb_videomode mxcfb_modedb[]; From e80987c430326ce0e22f0eb61314bfb949e5f23a Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 10 Dec 2012 20:21:04 -0500 Subject: [PATCH 08/12] rename mxcfb_update_data51 to mxcfb_update_data as suggested by eureka@mobileread: http://www.mobileread.com/forums/showthread.php?p=2337061#post2337061 --- einkfb.c | 9 +++++---- include/mxcfb.h | 14 ++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/einkfb.c b/einkfb.c index f4a10a8bb..af237db63 100644 --- a/einkfb.c +++ b/einkfb.c @@ -96,7 +96,7 @@ inline void fillUpdateAreaT(update_area_t *myarea, FBInfo *fb, lua_State *L) { myarea->which_fx = fxtype ? fx_update_partial : fx_update_full; } -inline void fillMxcfbUpdateData51(mxcfb_update_data51 *myarea, FBInfo *fb, lua_State *L) { +inline void fillMxcfbUpdateData(mxcfb_update_data *myarea, FBInfo *fb, lua_State *L) { myarea->update_region.top = luaL_optint(L, 3, 0); myarea->update_region.left = luaL_optint(L, 4, 0); myarea->update_region.width = luaL_optint(L, 5, fb->vinfo.xres); @@ -135,13 +135,14 @@ void kindle4einkUpdate(FBInfo *fb, lua_State *L) { ioctl(fb->fd, FBIO_EINK_UPDATE_DISPLAY_AREA, &myarea); } +/* for kindle firmware with version >= 5.1, 5.0 is not supported for now */ void kindle51einkUpdate(FBInfo *fb, lua_State *L) { - mxcfb_update_data51 myarea; + mxcfb_update_data myarea; fb4BppTo8Bpp(fb); - fillMxcfbUpdateData51(&myarea, fb, L); + fillMxcfbUpdateData(&myarea, fb, L); - ioctl(fb->fd, MXCFB_SEND_UPDATE51, &myarea); + ioctl(fb->fd, MXCFB_SEND_UPDATE, &myarea); } #endif diff --git a/include/mxcfb.h b/include/mxcfb.h index 4e313299b..a933ef1ad 100644 --- a/include/mxcfb.h +++ b/include/mxcfb.h @@ -1,7 +1,7 @@ /* * Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved. * - * - Modified by houqp, added mxcfb_update_data51 struct from GeekMaster's + * - Modified by houqp, added mxcfb_update_data struct from GeekMaster's * video player, refer to: * http://www.mobileread.com/forums/showthread.php?t=177455&page=10 * @@ -107,7 +107,7 @@ struct mxcfb_alt_buffer_data { struct mxcfb_rect alt_update_region; /* region within buffer to update */ }; -struct mxcfb_update_data51 { +struct mxcfb_update_data { struct mxcfb_rect update_region; __u32 waveform_mode; __u32 update_mode; @@ -118,9 +118,11 @@ struct mxcfb_update_data51 { uint flags; struct mxcfb_alt_buffer_data alt_buffer_data; }; -typedef struct mxcfb_update_data51 mxcfb_update_data51; +typedef struct mxcfb_update_data mxcfb_update_data; -struct mxcfb_update_data { +/* this is only used in kindle firmware 5.0, later version (5.1) has changed + * the struct to mxcfb_update_data (see above) */ +struct mxcfb_update_data_50x { struct mxcfb_rect update_region; __u32 waveform_mode; __u32 update_mode; @@ -160,7 +162,7 @@ struct mxcfb_waveform_modes { #define MXCFB_SET_WAVEFORM_MODES _IOW('F', 0x2B, struct mxcfb_waveform_modes) #define MXCFB_SET_TEMPERATURE _IOW('F', 0x2C, int32_t) #define MXCFB_SET_AUTO_UPDATE_MODE _IOW('F', 0x2D, __u32) -#define MXCFB_SEND_UPDATE _IOW('F', 0x2E, struct mxcfb_update_data) +#define MXCFB_SEND_UPDATE_50X _IOW('F', 0x2E, struct mxcfb_update_data_50x) #define MXCFB_WAIT_FOR_UPDATE_COMPLETE _IOW('F', 0x2F, __u32) #define MXCFB_SET_PWRDOWN_DELAY _IOW('F', 0x30, int32_t) #define MXCFB_GET_PWRDOWN_DELAY _IOR('F', 0x31, int32_t) @@ -173,7 +175,7 @@ struct mxcfb_waveform_modes { #define MXCFB_SET_MERGE_ON_WAVEFORM_MISMATCH _IOW('F', 0x37, int32_t) /* IOCTLs for E-ink panel updates, kindle firmware version >= 5.1 */ -#define MXCFB_SEND_UPDATE51 _IOW('F', 0x2E, struct mxcfb_update_data51) +#define MXCFB_SEND_UPDATE _IOW('F', 0x2E, struct mxcfb_update_data) #ifdef __KERNEL__ From c8d43cd33c4408c26693058490690bc65419010c Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 10 Dec 2012 20:58:16 -0500 Subject: [PATCH 09/12] add Input:eventAdjustHook(ev) so we can adjust input event for KT on the fly. the touch input event coordinates in KT ranges from 0-4095 instead of the screen size. --- frontend/ui/geometry.lua | 4 ++++ frontend/ui/gesturedetector.lua | 14 -------------- frontend/ui/inputevent.lua | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/frontend/ui/geometry.lua b/frontend/ui/geometry.lua index b50a07d85..3eefdbd75 100644 --- a/frontend/ui/geometry.lua +++ b/frontend/ui/geometry.lua @@ -274,4 +274,8 @@ function math.roundAwayFromZero(num) end end +function math.round(num) + return math.floor(num + 0.5) +end + diff --git a/frontend/ui/gesturedetector.lua b/frontend/ui/gesturedetector.lua index 9d1fc01bb..0c7f4d902 100644 --- a/frontend/ui/gesturedetector.lua +++ b/frontend/ui/gesturedetector.lua @@ -1,18 +1,5 @@ require "ui/geometry" --- Synchronization events (SYN.code). -SYN_REPORT = 0 -SYN_CONFIG = 1 -SYN_MT_REPORT = 2 - --- For multi-touch events (ABS.code). -ABS_MT_SLOT = 47 -ABS_MT_POSITION_X = 53 -ABS_MT_POSITION_Y = 54 -ABS_MT_TRACKING_ID = 57 -ABS_MT_PRESSURE = 58 - - GestureRange = { ges = nil, range = nil, @@ -207,7 +194,6 @@ function GestureDetector:tapState(ev) sec = 0, usec = self.HOLD_INTERVAL } Input:setTimeout(function() - print("hold timer", self.state == self.tapState) if self.state == self.tapState then -- timer set in tapState, so we switch to hold return self:switchState("holdState") diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index a7b52f590..8866cd0fb 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -14,6 +14,19 @@ EVENT_VALUE_KEY_PRESS = 1 EVENT_VALUE_KEY_REPEAT = 2 EVENT_VALUE_KEY_RELEASE = 0 +-- Synchronization events (SYN.code). +SYN_REPORT = 0 +SYN_CONFIG = 1 +SYN_MT_REPORT = 2 + +-- For multi-touch events (ABS.code). +ABS_MT_SLOT = 47 +ABS_MT_POSITION_X = 53 +ABS_MT_POSITION_Y = 54 +ABS_MT_TRACKING_ID = 57 +ABS_MT_PRESSURE = 58 + + --[[ an interface for key presses @@ -253,6 +266,16 @@ function Input:init() elseif dev_mod == "KindleTouch" then input.open("/dev/input/event2") -- Home button input.open("/dev/input/event3") -- touchscreen + -- update event hook + function Input:eventAdjustHook(ev) + if ev.type == EV_ABS then + if ev.code == ABS_MT_POSITION_X then + ev.code = math.round(ev.code * (600/4095)) + elseif ev.code == ABS_MT_POSITION_Y then + ev.code = math.round(ev.code * (800/4095)) + end + end + end print("Auto-detected Kindle Touch") elseif dev_mod == "Kindle4" then print("Auto-detected Kindle 4") @@ -271,6 +294,15 @@ function Input:init() end end +--[[ +different device models shoudl overload this method if +necessary to make event compatible to KPV. +--]] +function Input:eventAdjustHook(ev) + -- do nothing by default + return ev +end + function Input:adjustKindle4EventMap() self.event_map[193] = "LPgBack" self.event_map[104] = "LPgFwd" @@ -342,6 +374,7 @@ function Input:waitEvent(timeout_us, timeout_s) end end if ok and ev then + ev = self:eventAdjustHook(ev) if ev.type == EV_KEY then local keycode = self.event_map[ev.code] if not keycode then From b253a774f649b6967665bb40f19a350f51cf05b1 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 10 Dec 2012 21:05:35 -0500 Subject: [PATCH 10/12] added TODO in Input:init in case I forget it in the future --- frontend/ui/inputevent.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index 8866cd0fb..daa21ec40 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -269,6 +269,8 @@ function Input:init() -- update event hook function Input:eventAdjustHook(ev) if ev.type == EV_ABS then + --@TODO handle coordinates properly after + --screen rotate. (houqp) if ev.code == ABS_MT_POSITION_X then ev.code = math.round(ev.code * (600/4095)) elseif ev.code == ABS_MT_POSITION_Y then From 424776b564b00522ba26e4e6c341c4dbcfb4ed85 Mon Sep 17 00:00:00 2001 From: eureka <@mobileread.com> Date: Tue, 11 Dec 2012 13:14:41 +0800 Subject: [PATCH 11/12] fix bug in eventhook for KT * no return * it is value that should be changed --- frontend/ui/inputevent.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index daa21ec40..4c5712d0a 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -272,11 +272,12 @@ function Input:init() --@TODO handle coordinates properly after --screen rotate. (houqp) if ev.code == ABS_MT_POSITION_X then - ev.code = math.round(ev.code * (600/4095)) + ev.value = math.round(ev.value * (600/4095)) elseif ev.code == ABS_MT_POSITION_Y then - ev.code = math.round(ev.code * (800/4095)) + ev.value = math.round(ev.value * (800/4095)) end end + return ev end print("Auto-detected Kindle Touch") elseif dev_mod == "Kindle4" then From 309af296db1893562c2f26f6af92c868366a3ec3 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Wed, 12 Dec 2012 09:35:49 +0800 Subject: [PATCH 12/12] read document configuration files from history dir this feature was introduced by @NuPogodi in old KPV --- frontend/settings.lua | 32 ++++++++++++++++++++++++++++++-- frontend/ui/filechooser.lua | 2 +- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/frontend/settings.lua b/frontend/settings.lua index 757b14b3a..638484488 100644 --- a/frontend/settings.lua +++ b/frontend/settings.lua @@ -1,8 +1,36 @@ DocSettings = {} +function DocSettings:getHistoryPath(fullpath) + local i = #fullpath - 1 + -- search for last slash + while i > 0 do + if fullpath:sub(i,i) == "/" then + break + end + i = i - 1 + end + -- construct path to configuration file in history dir + local filename = fullpath:sub(i+1, -1) + local basename = fullpath:sub(1, i) + return "./history/["..basename:gsub("/","#").."] "..filename..".lua" +end + function DocSettings:open(docfile) - local new = { file = docfile..".kpdfview.lua", data = {} } - local ok, stored = pcall(dofile,new.file) + local conf_path = nil + if docfile == ".reader" then + -- we handle reader setting as special case + conf_path = "settings.reader.lua" + else + conf_path = self:getHistoryPath(docfile) + end + -- construct settings obj + local new = { file = conf_path, data = {} } + local ok, stored = pcall(dofile, new.file) + if not ok then + -- try legacy conf path, for backward compatibility. this also + -- takes care of reader legacy setting + ok, stored = pcall(dofile, docfile..".kpdfview.lua") + end if ok then new.data = stored end diff --git a/frontend/ui/filechooser.lua b/frontend/ui/filechooser.lua index dbfbf044f..8be30e3cb 100644 --- a/frontend/ui/filechooser.lua +++ b/frontend/ui/filechooser.lua @@ -3,7 +3,7 @@ require "ui/menu" FileChooser = Menu:new{ height = Screen:getHeight(), width = Screen:getWidth(), - path = ".", + path = lfs.currentdir(), parent = nil, show_hidden = false, filter = function(filename) return true end,