Skip to content
This repository was archived by the owner on Nov 10, 2025. It is now read-only.

Commit 28382bb

Browse files
committed
Add support for pages with different sizes
Add support for links Add support for page fitting policies
1 parent 46e2dde commit 28382bb

File tree

18 files changed

+1188
-678
lines changed

18 files changed

+1188
-678
lines changed

android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/AnimationManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void computeFling() {
8484
if (scroller.computeScrollOffset()) {
8585
pdfView.moveTo(scroller.getCurrX(), scroller.getCurrY());
8686
pdfView.loadPageByOffset();
87-
} else if(flinging) { // fling finished
87+
} else if (flinging) { // fling finished
8888
flinging = false;
8989
pdfView.loadPages();
9090
hideHandle();

android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/CacheManager.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.github.barteksc.pdfviewer.model.PagePart;
2222

2323
import java.util.ArrayList;
24+
import java.util.Collection;
2425
import java.util.Comparator;
2526
import java.util.List;
2627
import java.util.PriorityQueue;
@@ -38,11 +39,11 @@ class CacheManager {
3839

3940
private final Object passiveActiveLock = new Object();
4041

41-
private final PagePartComparator comparator = new PagePartComparator();
42+
private final PagePartComparator orderComparator = new PagePartComparator();
4243

4344
public CacheManager() {
44-
activeCache = new PriorityQueue<>(CACHE_SIZE, comparator);
45-
passiveCache = new PriorityQueue<>(CACHE_SIZE, comparator);
45+
activeCache = new PriorityQueue<>(CACHE_SIZE, orderComparator);
46+
passiveCache = new PriorityQueue<>(CACHE_SIZE, orderComparator);
4647
thumbnails = new ArrayList<>();
4748
}
4849

@@ -81,18 +82,18 @@ private void makeAFreeSpace() {
8182
public void cacheThumbnail(PagePart part) {
8283
synchronized (thumbnails) {
8384
// If cache too big, remove and recycle
84-
if (thumbnails.size() >= THUMBNAILS_CACHE_SIZE) {
85+
while (thumbnails.size() >= THUMBNAILS_CACHE_SIZE) {
8586
thumbnails.remove(0).getRenderedBitmap().recycle();
8687
}
8788

8889
// Then add thumbnail
89-
thumbnails.add(part);
90+
addWithoutDuplicates(thumbnails, part);
9091
}
9192

9293
}
9394

94-
public boolean upPartIfContained(int userPage, int page, float width, float height, RectF pageRelativeBounds, int toOrder) {
95-
PagePart fakePart = new PagePart(userPage, page, null, width, height, pageRelativeBounds, false, 0);
95+
public boolean upPartIfContained(int page, RectF pageRelativeBounds, int toOrder) {
96+
PagePart fakePart = new PagePart(page, null, pageRelativeBounds, false, 0);
9697

9798
PagePart found;
9899
synchronized (passiveActiveLock) {
@@ -110,8 +111,8 @@ public boolean upPartIfContained(int userPage, int page, float width, float heig
110111
/**
111112
* Return true if already contains the described PagePart
112113
*/
113-
public boolean containsThumbnail(int userPage, int page, float width, float height, RectF pageRelativeBounds) {
114-
PagePart fakePart = new PagePart(userPage, page, null, width, height, pageRelativeBounds, true, 0);
114+
public boolean containsThumbnail(int page, RectF pageRelativeBounds) {
115+
PagePart fakePart = new PagePart(page, null, pageRelativeBounds, true, 0);
115116
synchronized (thumbnails) {
116117
for (PagePart part : thumbnails) {
117118
if (part.equals(fakePart)) {
@@ -122,6 +123,19 @@ public boolean containsThumbnail(int userPage, int page, float width, float heig
122123
}
123124
}
124125

126+
/**
127+
* Add part if it doesn't exist, recycle bitmap otherwise
128+
*/
129+
private void addWithoutDuplicates(Collection<PagePart> collection, PagePart newPart) {
130+
for (PagePart part : collection) {
131+
if (part.equals(newPart)) {
132+
newPart.getRenderedBitmap().recycle();
133+
return;
134+
}
135+
}
136+
collection.add(newPart);
137+
}
138+
125139
@Nullable
126140
private static PagePart find(PriorityQueue<PagePart> vector, PagePart fakePart) {
127141
for (PagePart part : vector) {

android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DecodingAsyncTask.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,60 +15,58 @@
1515
*/
1616
package com.github.barteksc.pdfviewer;
1717

18-
import android.content.Context;
1918
import android.os.AsyncTask;
2019

2120
import com.github.barteksc.pdfviewer.source.DocumentSource;
2221
import com.shockwave.pdfium.PdfDocument;
2322
import com.shockwave.pdfium.PdfiumCore;
23+
import com.shockwave.pdfium.util.Size;
2424

2525
class DecodingAsyncTask extends AsyncTask<Void, Void, Throwable> {
2626

2727
private boolean cancelled;
2828

2929
private PDFView pdfView;
3030

31-
private Context context;
3231
private PdfiumCore pdfiumCore;
33-
private PdfDocument pdfDocument;
3432
private String password;
3533
private DocumentSource docSource;
36-
private int firstPageIdx;
37-
private int pageWidth;
38-
private int pageHeight;
34+
private int[] userPages;
35+
private PdfFile pdfFile;
3936

40-
DecodingAsyncTask(DocumentSource docSource, String password, PDFView pdfView, PdfiumCore pdfiumCore, int firstPageIdx) {
37+
DecodingAsyncTask(DocumentSource docSource, String password, int[] userPages, PDFView pdfView, PdfiumCore pdfiumCore) {
4138
this.docSource = docSource;
42-
this.firstPageIdx = firstPageIdx;
39+
this.userPages = userPages;
4340
this.cancelled = false;
4441
this.pdfView = pdfView;
4542
this.password = password;
4643
this.pdfiumCore = pdfiumCore;
47-
context = pdfView.getContext();
4844
}
4945

5046
@Override
5147
protected Throwable doInBackground(Void... params) {
5248
try {
53-
pdfDocument = docSource.createDocument(context, pdfiumCore, password);
54-
// We assume all the pages are the same size
55-
pdfiumCore.openPage(pdfDocument, firstPageIdx);
56-
pageWidth = pdfiumCore.getPageWidth(pdfDocument, firstPageIdx);
57-
pageHeight = pdfiumCore.getPageHeight(pdfDocument, firstPageIdx);
49+
PdfDocument pdfDocument = docSource.createDocument(pdfView.getContext(), pdfiumCore, password);
50+
pdfFile = new PdfFile(pdfiumCore, pdfDocument, pdfView.getPageFitPolicy(), getViewSize(),
51+
userPages, pdfView.isSwipeVertical(), pdfView.getSpacingPx());
5852
return null;
5953
} catch (Throwable t) {
6054
return t;
6155
}
6256
}
6357

58+
private Size getViewSize() {
59+
return new Size(pdfView.getWidth(), pdfView.getHeight());
60+
}
61+
6462
@Override
6563
protected void onPostExecute(Throwable t) {
6664
if (t != null) {
6765
pdfView.loadError(t);
6866
return;
6967
}
7068
if (!cancelled) {
71-
pdfView.loadComplete(pdfDocument, pageWidth, pageHeight);
69+
pdfView.loadComplete(pdfFile);
7270
}
7371
}
7472

android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/DragPinchManager.java

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
package com.github.barteksc.pdfviewer;
1717

1818
import android.graphics.PointF;
19+
import android.graphics.RectF;
1920
import android.view.GestureDetector;
2021
import android.view.MotionEvent;
2122
import android.view.ScaleGestureDetector;
2223
import android.view.View;
2324

25+
import com.github.barteksc.pdfviewer.model.LinkTapEvent;
2426
import com.github.barteksc.pdfviewer.scroll.ScrollHandle;
25-
import com.github.barteksc.pdfviewer.listener.OnTapListener;
27+
import com.shockwave.pdfium.PdfDocument;
28+
import com.shockwave.pdfium.util.SizeF;
2629

2730
import static com.github.barteksc.pdfviewer.util.Constants.Pinch.MAXIMUM_ZOOM;
2831
import static com.github.barteksc.pdfviewer.util.Constants.Pinch.MINIMUM_ZOOM;
@@ -39,51 +42,31 @@ class DragPinchManager implements GestureDetector.OnGestureListener, GestureDete
3942
private GestureDetector gestureDetector;
4043
private ScaleGestureDetector scaleGestureDetector;
4144

42-
private boolean isSwipeEnabled;
43-
44-
private boolean swipeVertical;
45-
4645
private boolean scrolling = false;
4746
private boolean scaling = false;
47+
private boolean enabled = false;
4848

49-
public DragPinchManager(PDFView pdfView, AnimationManager animationManager) {
49+
DragPinchManager(PDFView pdfView, AnimationManager animationManager) {
5050
this.pdfView = pdfView;
5151
this.animationManager = animationManager;
52-
this.isSwipeEnabled = false;
53-
this.swipeVertical = pdfView.isSwipeVertical();
5452
gestureDetector = new GestureDetector(pdfView.getContext(), this);
5553
scaleGestureDetector = new ScaleGestureDetector(pdfView.getContext(), this);
5654
pdfView.setOnTouchListener(this);
5755
}
5856

59-
public void enableDoubletap(boolean enableDoubletap) {
60-
if (enableDoubletap) {
61-
gestureDetector.setOnDoubleTapListener(this);
62-
} else {
63-
gestureDetector.setOnDoubleTapListener(null);
64-
}
65-
}
66-
67-
public boolean isZooming() {
68-
return pdfView.isZooming();
69-
}
70-
71-
private boolean isPageChange(float distance) {
72-
return Math.abs(distance) > Math.abs(pdfView.toCurrentScale(swipeVertical ? pdfView.getOptimalPageHeight() : pdfView.getOptimalPageWidth()) / 2);
73-
}
74-
75-
public void setSwipeEnabled(boolean isSwipeEnabled) {
76-
this.isSwipeEnabled = isSwipeEnabled;
57+
void enable() {
58+
enabled = true;
7759
}
7860

79-
public void setSwipeVertical(boolean swipeVertical) {
80-
this.swipeVertical = swipeVertical;
61+
void disable() {
62+
enabled = false;
8163
}
8264

8365
@Override
8466
public boolean onSingleTapConfirmed(MotionEvent e) {
85-
OnTapListener onTapListener = pdfView.getOnTapListener();
86-
if (onTapListener == null || !onTapListener.onTap(e)) {
67+
boolean onTapHandled = pdfView.callbacks.callOnTap(e);
68+
boolean linkTapped = checkLinkTapped(e.getX(), e.getY());
69+
if (!onTapHandled && !linkTapped) {
8770
ScrollHandle ps = pdfView.getScrollHandle();
8871
if (ps != null && !pdfView.documentFitsView()) {
8972
if (!ps.shown()) {
@@ -97,8 +80,47 @@ public boolean onSingleTapConfirmed(MotionEvent e) {
9780
return true;
9881
}
9982

83+
private boolean checkLinkTapped(float x, float y) {
84+
PdfFile pdfFile = pdfView.pdfFile;
85+
float mappedX = -pdfView.getCurrentXOffset() + x;
86+
float mappedY = -pdfView.getCurrentYOffset() + y;
87+
int page = pdfFile.getPageAtOffset(pdfView.isSwipeVertical() ? mappedY : mappedX, pdfView.getZoom());
88+
SizeF pageSize = pdfFile.getScaledPageSize(page, pdfView.getZoom());
89+
int pageX, pageY;
90+
if (pdfView.isSwipeVertical()) {
91+
pageX = (int) getSecondaryOffset(pageSize);
92+
pageY = (int) pdfFile.getPageOffset(page, pdfView.getZoom());
93+
} else {
94+
pageY = (int) getSecondaryOffset(pageSize);
95+
pageX = (int) pdfFile.getPageOffset(page, pdfView.getZoom());
96+
}
97+
for (PdfDocument.Link link : pdfFile.getPageLinks(page)) {
98+
RectF mapped = pdfFile.mapRectToDevice(page, pageX, pageY, (int) pageSize.getWidth(),
99+
(int) pageSize.getHeight(), link.getBounds());
100+
if (mapped.contains(mappedX, mappedY)) {
101+
pdfView.callbacks.callLinkHandler(new LinkTapEvent(x, y, mappedX, mappedY, mapped, link));
102+
return true;
103+
}
104+
}
105+
return false;
106+
}
107+
108+
private float getSecondaryOffset(SizeF pageSize) {
109+
if (pdfView.isSwipeVertical()) {
110+
float maxWidth = pdfView.pdfFile.getMaxPageWidth();
111+
return (pdfView.toCurrentScale(maxWidth) - pageSize.getWidth()) / 2; //x
112+
} else {
113+
float maxHeight = pdfView.pdfFile.getMaxPageHeight();
114+
return (pdfView.toCurrentScale(maxHeight) - pageSize.getHeight()) / 2; //y
115+
}
116+
}
117+
100118
@Override
101119
public boolean onDoubleTap(MotionEvent e) {
120+
if (!pdfView.isDoubletapEnabled()) {
121+
return false;
122+
}
123+
102124
if (pdfView.getZoom() < pdfView.getMidZoom()) {
103125
pdfView.zoomWithAnimation(e.getX(), e.getY(), pdfView.getMidZoom());
104126
} else if (pdfView.getZoom() < pdfView.getMaxZoom()) {
@@ -133,7 +155,7 @@ public boolean onSingleTapUp(MotionEvent e) {
133155
@Override
134156
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
135157
scrolling = true;
136-
if (isZooming() || isSwipeEnabled) {
158+
if (pdfView.isZooming() || pdfView.isSwipeEnabled()) {
137159
pdfView.moveRelativeTo(-distanceX, -distanceY);
138160
}
139161
if (!scaling || pdfView.doRenderDuringScale()) {
@@ -142,7 +164,7 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float d
142164
return true;
143165
}
144166

145-
public void onScrollEnd(MotionEvent event) {
167+
private void onScrollEnd(MotionEvent event) {
146168
pdfView.loadPages();
147169
hideHandle();
148170
}
@@ -154,16 +176,20 @@ public void onLongPress(MotionEvent e) {
154176

155177
@Override
156178
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
179+
if (!pdfView.isSwipeEnabled()) {
180+
return false;
181+
}
157182
int xOffset = (int) pdfView.getCurrentXOffset();
158183
int yOffset = (int) pdfView.getCurrentYOffset();
159184

160185
float minX, minY;
186+
PdfFile pdfFile = pdfView.pdfFile;
161187
if (pdfView.isSwipeVertical()) {
162-
minX = -(pdfView.toCurrentScale(pdfView.getOptimalPageWidth()) - pdfView.getWidth());
163-
minY = -(pdfView.calculateDocLength() - pdfView.getHeight());
188+
minX = -(pdfView.toCurrentScale(pdfFile.getMaxPageWidth()) - pdfView.getWidth());
189+
minY = -(pdfFile.getDocLen(pdfView.getZoom()) - pdfView.getHeight());
164190
} else {
165-
minX = -(pdfView.calculateDocLength() - pdfView.getWidth());
166-
minY = -(pdfView.toCurrentScale(pdfView.getOptimalPageHeight()) - pdfView.getHeight());
191+
minX = -(pdfFile.getDocLen(pdfView.getZoom()) - pdfView.getWidth());
192+
minY = -(pdfView.toCurrentScale(pdfFile.getMaxPageHeight()) - pdfView.getHeight());
167193
}
168194

169195
animationManager.startFlingAnimation(xOffset, yOffset, (int) (velocityX), (int) (velocityY),
@@ -200,6 +226,10 @@ public void onScaleEnd(ScaleGestureDetector detector) {
200226

201227
@Override
202228
public boolean onTouch(View v, MotionEvent event) {
229+
if (!enabled) {
230+
return false;
231+
}
232+
203233
boolean retVal = scaleGestureDetector.onTouchEvent(event);
204234
retVal = gestureDetector.onTouchEvent(event) || retVal;
205235

@@ -213,8 +243,9 @@ public boolean onTouch(View v, MotionEvent event) {
213243
}
214244

215245
private void hideHandle() {
216-
if (pdfView.getScrollHandle() != null && pdfView.getScrollHandle().shown()) {
217-
pdfView.getScrollHandle().hideDelayed();
246+
ScrollHandle scrollHandle = pdfView.getScrollHandle();
247+
if (scrollHandle != null && scrollHandle.shown()) {
248+
scrollHandle.hideDelayed();
218249
}
219250
}
220251
}

0 commit comments

Comments
 (0)