From 2b13e2b8deb24128ffc9baffe3500c63ded6d0c8 Mon Sep 17 00:00:00 2001 From: Elliot Wolk Date: Wed, 31 Aug 2022 02:05:37 -0400 Subject: [PATCH 1/4] android: skip PAGEUP animation in ViewMode=SCROLL (was always broken) --- .../src/org/coolreader/crengine/ReaderView.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/android/src/org/coolreader/crengine/ReaderView.java b/android/src/org/coolreader/crengine/ReaderView.java index 52ec2a0ae..9a0e3c67a 100644 --- a/android/src/org/coolreader/crengine/ReaderView.java +++ b/android/src/org/coolreader/crengine/ReaderView.java @@ -2487,10 +2487,19 @@ public void onCommand(final ReaderCommand cmd, final int param, final Runnable o break; case DCMD_PAGEUP: if (isBookLoaded()) { - if (param == 1 && !DeviceInfo.EINK_SCREEN) - animatePageFlip(-1, onFinishHandler); - else + if (param == 1 && !DeviceInfo.EINK_SCREEN) { + if (mIsPageMode) { + animatePageFlip(-1, onFinishHandler); + } else{ + //PAGEUP animation is broken in ScrollView, so skip it + PositionProperties currPos = doc.getPositionProps(null, false); + int offset = currPos.pageHeight * 7/8; + int destPos = currPos.y - offset; + doEngineCommand(ReaderCommand.DCMD_GO_POS, destPos, onFinishHandler); + } + } else { doEngineCommand(cmd, param, onFinishHandler); + } } break; case DCMD_BEGIN: From 7da0ef5a0dd6a5a1c4e5c27ceffe29a2d5933cf2 Mon Sep 17 00:00:00 2001 From: Elliot Wolk Date: Wed, 31 Aug 2022 02:20:34 -0400 Subject: [PATCH 2/4] android: explicitly skip all animation code when animation is disabled --- .../org/coolreader/crengine/ReaderView.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/android/src/org/coolreader/crengine/ReaderView.java b/android/src/org/coolreader/crengine/ReaderView.java index 9a0e3c67a..97884d6fb 100644 --- a/android/src/org/coolreader/crengine/ReaderView.java +++ b/android/src/org/coolreader/crengine/ReaderView.java @@ -2479,26 +2479,39 @@ public void onCommand(final ReaderCommand cmd, final int param, final Runnable o break; case DCMD_PAGEDOWN: if (isBookLoaded()) { - if (param == 1 && !DeviceInfo.EINK_SCREEN) + boolean animationEnabled = pageFlipAnimationMode != PAGE_ANIMATION_NONE; + if (animationEnabled && param == 1 && !DeviceInfo.EINK_SCREEN) { animatePageFlip(1, onFinishHandler); - else - doEngineCommand(cmd, param, onFinishHandler); + } else { + if (mIsPageMode) { + doEngineCommand(ReaderCommand.DCMD_PAGEDOWN, param, onFinishHandler); + } else { + PositionProperties currPos = doc.getPositionProps(null, false); + int offset = currPos.pageHeight * 7/8; + int destPos = currPos.y + offset; + doEngineCommand(ReaderCommand.DCMD_GO_POS, destPos, onFinishHandler); + } + } } break; case DCMD_PAGEUP: if (isBookLoaded()) { - if (param == 1 && !DeviceInfo.EINK_SCREEN) { + boolean animationEnabled = pageFlipAnimationMode != PAGE_ANIMATION_NONE; + if (!mIsPageMode) { + //PAGEUP animation is broken in ViewMode=SCROLL, so skip it + animationEnabled = false; + } + if (animationEnabled && param == 1 && !DeviceInfo.EINK_SCREEN) { + animatePageFlip(-1, onFinishHandler); + } else { if (mIsPageMode) { - animatePageFlip(-1, onFinishHandler); - } else{ - //PAGEUP animation is broken in ScrollView, so skip it + doEngineCommand(ReaderCommand.DCMD_PAGEUP, param, onFinishHandler); + } else { PositionProperties currPos = doc.getPositionProps(null, false); int offset = currPos.pageHeight * 7/8; int destPos = currPos.y - offset; doEngineCommand(ReaderCommand.DCMD_GO_POS, destPos, onFinishHandler); } - } else { - doEngineCommand(cmd, param, onFinishHandler); } } break; From 4ecda031245b48790d87b0c67f28474a7c470ff5 Mon Sep 17 00:00:00 2001 From: Elliot Wolk Date: Wed, 31 Aug 2022 02:22:34 -0400 Subject: [PATCH 3/4] crengine: add pageHeader and top/bottom margins in SCROLL mode (and TTS) --- crengine/src/lvdocview.cpp | 42 ++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/crengine/src/lvdocview.cpp b/crengine/src/lvdocview.cpp index 849fe079d..eaf5fb135 100644 --- a/crengine/src/lvdocview.cpp +++ b/crengine/src/lvdocview.cpp @@ -2476,7 +2476,7 @@ void LVDocView::Draw(LVDrawBuf & drawbuf, int position, int page, bool rotate, b return; if (isScrollMode()) { drawbuf.SetClipRect(NULL); - drawbuf.setHidePartialGlyphs(false); + drawbuf.setHidePartialGlyphs(true); drawPageBackground(drawbuf, 0, position); int cover_height = 0; if (m_pages.length() > 0 && (m_pages[0]->flags & RN_PAGE_TYPE_COVER)) @@ -2492,9 +2492,37 @@ void LVDocView::Draw(LVDrawBuf & drawbuf, int position, int page, bool rotate, b rc.right -= m_pageMargins.right; drawCoverTo(&drawbuf, rc); } - DrawDocument(drawbuf, m_doc->getRootNode(), m_pageMargins.left, 0, drawbuf.GetWidth() - - m_pageMargins.left - m_pageMargins.right, drawbuf.GetHeight(), 0, -position, - drawbuf.GetHeight(), &m_markRanges, &m_bmkRanges); + + int curPage = m_pages.FindNearestPage(position, 0); + int totalPages = m_pages.length(); + + lvRect info; + getPageHeaderRectangle(curPage, info); + drawPageHeader(&drawbuf, info, curPage, m_pageHeaderInfo, totalPages); + + int top = m_pageMargins.top + + (PAGE_HEADER_POS_TOP == m_pageHeaderPos ? info.height() : 0); + int left = m_pageMargins.left; + + int contentWidth = drawbuf.GetWidth() + - left + - m_pageMargins.right; + int contentHeight = drawbuf.GetHeight() + - top + - m_pageMargins.bottom; + + lvRect clip; + clip.top = top; + clip.bottom = top + contentHeight; + //do not clip left/right + // (ignore left/right margins, allow partial glyphs to dangle) + clip.left = 0; + clip.right = drawbuf.GetWidth(); + + drawbuf.SetClipRect(&clip); + + DrawDocument(drawbuf, m_doc->getRootNode(), left, top, contentWidth, + contentHeight, 0, -position, m_dy, &m_markRanges, &m_bmkRanges); } else { int pc = getVisiblePageCount(); //CRLog::trace("searching for page with offset=%d", position); @@ -2534,7 +2562,8 @@ bool LVDocView::windowToDocPoint(lvPoint & pt) { #endif if (getViewMode() == DVM_SCROLL) { // SCROLL mode - pt.y += _pos; + int headerHeight = (PAGE_HEADER_POS_TOP == m_pageHeaderPos) ? getPageHeaderHeight() : 0; + pt.y += _pos + m_pageMargins.top + headerHeight; pt.x -= m_pageMargins.left; return true; } else { @@ -2582,7 +2611,8 @@ bool LVDocView::docToWindowPoint(lvPoint & pt, bool isRectBottom, bool fitToPage // TODO: implement coordinate conversion here if (getViewMode() == DVM_SCROLL) { // SCROLL mode - pt.y -= _pos; + int headerHeight = (PAGE_HEADER_POS_TOP == m_pageHeaderPos) ? getPageHeaderHeight() : 0; + pt.y -= _pos + m_pageMargins.top + headerHeight; pt.x += m_pageMargins.left; return true; } else { From 98dea2733578a472f664ba3a50bdf4500b400642 Mon Sep 17 00:00:00 2001 From: Elliot Wolk Date: Fri, 2 Sep 2022 12:04:34 -0400 Subject: [PATCH 4/4] android: implement sane Scroll mode animation that works with page up --- .../org/coolreader/crengine/ReaderView.java | 185 +++++++----------- 1 file changed, 69 insertions(+), 116 deletions(-) diff --git a/android/src/org/coolreader/crengine/ReaderView.java b/android/src/org/coolreader/crengine/ReaderView.java index 97884d6fb..aa7bd4ebf 100644 --- a/android/src/org/coolreader/crengine/ReaderView.java +++ b/android/src/org/coolreader/crengine/ReaderView.java @@ -2497,10 +2497,6 @@ public void onCommand(final ReaderCommand cmd, final int param, final Runnable o case DCMD_PAGEUP: if (isBookLoaded()) { boolean animationEnabled = pageFlipAnimationMode != PAGE_ANIMATION_NONE; - if (!mIsPageMode) { - //PAGEUP animation is broken in ViewMode=SCROLL, so skip it - animationEnabled = false; - } if (animationEnabled && param == 1 && !DeviceInfo.EINK_SCREEN) { animatePageFlip(-1, onFinishHandler); } else { @@ -3835,14 +3831,10 @@ private void animatePageFlip(final int dir, final Runnable onFinishHandler) { BackgroundThread.instance().executeGUI(onFinishHandler); } } else { - //new ScrollViewAnimation(startY, maxY); - int fromY = dir > 0 ? h * 7 / 8 : 0; - int toY = dir > 0 ? 0 : h * 7 / 8; - new ScrollViewAnimation(fromY, h); + new ScrollViewAnimation(dir > 0 ? h*7/8 : 0-(h*7/8)); if (currentAnimation != null) { nextHiliteId++; hiliteRect = null; - currentAnimation.update(w / 2, toY); currentAnimation.move(speed, true); currentAnimation.stop(-1, -1); if (onFinishHandler != null) @@ -4137,7 +4129,8 @@ private void startAnimation(final int startX, final int startY, final int maxX, // sx = 0; new PageViewAnimation(sx, maxX, dir); } else { - new ScrollViewAnimation(startY, maxY); + int dir = newX < startX || newY < startY ? -1 : 1; + new ScrollViewAnimation(dir * currPos.pageHeight * 7 / 8); } if (currentAnimation != null) { nextHiliteId++; @@ -4354,46 +4347,34 @@ public void draw(boolean isPartially) { //private static final int PAGE_ANIMATION_DURATION = 3000; class ScrollViewAnimation extends ViewAnimationBase { - int startY; - int maxY; + int offset; + int dir; + int posStart; + int posEnd; + double progress; int pageHeight; - int fullHeight; - int pointerStartPos; - int pointerDestPos; - int pointerCurrPos; - BitmapInfo image1; - BitmapInfo image2; + int pageWidth; + Bitmap imgStart; + Bitmap imgEnd; - ScrollViewAnimation(int startY, int maxY) { + ScrollViewAnimation(int offset) { super(); - this.startY = startY; - this.maxY = maxY; - long start = android.os.SystemClock.uptimeMillis(); log.v("ScrollViewAnimation -- creating: drawing two pages to buffer"); + this.offset = offset; + this.dir = offset < 0 ? -1 : 1; + PositionProperties currPos = doc.getPositionProps(null, false); - int pos = currPos.y; - int pos0 = pos - (maxY - startY); - if (pos0 < 0) - pos0 = 0; - pointerStartPos = pos; - pointerCurrPos = pos; - pointerDestPos = startY; - pageHeight = currPos.pageHeight; - fullHeight = currPos.fullHeight; - doc.doCommand(ReaderCommand.DCMD_GO_POS.nativeId, pos0); - image1 = preparePageImage(0); - if (image1 == null) { + this.posStart = currPos.y; + this.posEnd = posStart + offset; + this.pageHeight = currPos.pageHeight; + this.pageWidth = currPos.pageWidth; + this.progress = 0.0; + this.imgStart = preparePageImage(0).bitmap; + this.imgEnd = preparePageImage(offset).bitmap; + if (this.imgStart == null || this.imgEnd == null) { log.v("ScrollViewAnimation -- not started: image is null"); return; } - image2 = preparePageImage(image1.position.pageHeight); - doc.doCommand(ReaderCommand.DCMD_GO_POS.nativeId, pos); - if (image2 == null) { - log.v("ScrollViewAnimation -- not started: image is null"); - return; - } - long duration = android.os.SystemClock.uptimeMillis() - start; - log.v("ScrollViewAnimation -- created in " + duration + " millis"); currentAnimation = this; } @@ -4401,19 +4382,9 @@ class ScrollViewAnimation extends ViewAnimationBase { public void stop(int x, int y) { if (currentAnimation == null) return; - //if ( started ) { - if (y != -1) { - int delta = startY - y; - pointerCurrPos = pointerStartPos + delta; - } - if (pointerCurrPos < 0) - pointerCurrPos = 0; - if (pointerCurrPos > fullHeight - pageHeight) - pointerCurrPos = fullHeight - pageHeight; - pointerDestPos = pointerCurrPos; + this.progress = 1.0; draw(); - doc.doCommand(ReaderCommand.DCMD_GO_POS.nativeId, pointerDestPos); - //} + doc.doCommand(ReaderCommand.DCMD_GO_POS.nativeId, this.posEnd); scheduleSaveCurrentPositionBookmark(DEF_SAVE_POSITION_INTERVAL); close(); } @@ -4422,84 +4393,66 @@ public void stop(int x, int y) { public void move(int duration, boolean accelerated) { if (duration > 0 && pageFlipAnimationSpeedMs != 0) { int steps = (int) (duration / getAvgAnimationDrawDuration()) + 2; - int x0 = pointerCurrPos; - int x1 = pointerDestPos; - if ((x0 - x1) < 10 && (x0 - x1) > -10) - steps = 2; for (int i = 1; i < steps; i++) { - int x = x0 + (x1 - x0) * i / steps; - pointerCurrPos = accelerated ? accelerate(x0, x1, x) : x; - if (pointerCurrPos < 0) - pointerCurrPos = 0; - if (pointerCurrPos > fullHeight - pageHeight) - pointerCurrPos = fullHeight - pageHeight; + this.progress = i/steps; + if(accelerated){ + double accelFactor = Math.pow(i, 2)/Math.pow(steps, 2); + this.progress += (1-progress) * accelFactor; + } draw(); } + }else{ + draw(); } - pointerCurrPos = pointerDestPos; - draw(); } @Override public void update(int x, int y) { - int delta = startY - y; - pointerDestPos = pointerStartPos + delta; - if (pointerDestPos < 0) - pointerDestPos = 0; - if (pointerDestPos > fullHeight - pageHeight) - pointerDestPos = fullHeight - pageHeight; } public void animate() { - //log.d("animate() is called"); - if (pointerDestPos != pointerCurrPos) { - if (!started) - started = true; - if (pageFlipAnimationSpeedMs == 0) - pointerCurrPos = pointerDestPos; - else { - int delta = pointerCurrPos - pointerDestPos; - if (delta < 0) - delta = -delta; - long avgDraw = getAvgAnimationDrawDuration(); - //int maxStep = (int)(maxY * PAGE_ANIMATION_DURATION / avgDraw); - int maxStep = pageFlipAnimationSpeedMs > 0 ? (int) (maxY * 1000 / avgDraw / pageFlipAnimationSpeedMs) : maxY; - int step; - if (delta > maxStep * 2) - step = maxStep; - else - step = (delta + 3) / 4; - //int step = delta<3 ? 1 : (delta<5 ? 2 : (delta<10 ? 3 : (delta<15 ? 6 : (delta<25 ? 10 : (delta<50 ? 15 : 30))))); - if (pointerCurrPos < pointerDestPos) - pointerCurrPos += step; - else - pointerCurrPos -= step; - log.d("animate(" + pointerCurrPos + " => " + pointerDestPos + " step=" + step + ")"); - } - //pointerCurrPos = pointerDestPos; - draw(); - if (pointerDestPos != pointerCurrPos) - scheduleAnimation(); + if (!started) { + started = true; + } + if (pageFlipAnimationSpeedMs == 0) { + progress = 1.0; + }else { + //int duration = pageFlipAnimationSpeedMs; + //long frameDur = getAvgAnimationDrawDuration(); + /* just move 12px per frame */ + int absOffset = offset < 0 ? 0-offset : offset; + long remainingPx = Math.round(absOffset * (1 - progress)); //delta + long targetStepCount = Math.round(remainingPx / 12); + targetStepCount = targetStepCount < 1 ? 1 : targetStepCount; + progress += (1-progress)/targetStepCount; + } + draw(); + if (progress < 1.0) { + scheduleAnimation(); } } public void draw(Canvas canvas) { -// BitmapInfo image1 = mCurrentPageInfo; -// BitmapInfo image2 = mNextPageInfo; - if (image1 == null || image1.isReleased() || image2 == null || image2.isReleased()) + if (imgStart == null || imgEnd == null){ return; - int h = image1.position.pageHeight; - int rowsFromImg1 = image1.position.y + h - pointerCurrPos; - int rowsFromImg2 = h - rowsFromImg1; - Rect src1 = new Rect(0, h - rowsFromImg1, mCurrentPageInfo.bitmap.getWidth(), h); - Rect dst1 = new Rect(0, 0, mCurrentPageInfo.bitmap.getWidth(), rowsFromImg1); - drawDimmedBitmap(canvas, image1.bitmap, src1, dst1); - if (image2 != null) { - Rect src2 = new Rect(0, 0, mCurrentPageInfo.bitmap.getWidth(), rowsFromImg2); - Rect dst2 = new Rect(0, rowsFromImg1, mCurrentPageInfo.bitmap.getWidth(), h); - drawDimmedBitmap(canvas, image2.bitmap, src2, dst2); - } - //log.v("anim.drawScroll( pos=" + pointerCurrPos + ", " + src1 + "=>" + dst1 + ", " + src2 + "=>" + dst2 + " )"); + } + int h = this.pageHeight; + int w = this.pageWidth; + int yBoundary = (int) (this.pageHeight * progress); + Rect rectImgStartBitmapSrc, rectImgStartCanvasDest, rectImgEndBitmapSrc, rectImgEndCanvasDest; + if(dir > 0){ + rectImgStartBitmapSrc = new Rect(0, yBoundary, w, h); + rectImgStartCanvasDest = new Rect(0, 0, w, h - yBoundary); + rectImgEndBitmapSrc = new Rect(0, 0, w, yBoundary); + rectImgEndCanvasDest = new Rect(0, h - yBoundary, w, h); + } else { + rectImgStartBitmapSrc = new Rect(0, 0, w, h - yBoundary); + rectImgStartCanvasDest = new Rect(0, yBoundary, w, h); + rectImgEndBitmapSrc = new Rect(0, h - yBoundary, w, h); + rectImgEndCanvasDest = new Rect(0, 0, w, yBoundary); + } + drawDimmedBitmap(canvas, imgStart, rectImgStartBitmapSrc, rectImgStartCanvasDest); + drawDimmedBitmap(canvas, imgEnd, rectImgEndBitmapSrc, rectImgEndCanvasDest); } }