Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5,064 changes: 2,508 additions & 2,556 deletions prettysumatra/webui/toolbar.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion scripts/installer/PrettySumatraPDF.iss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
; Requires Inno Setup (ISCC.exe) to compile

#define AppName "PrettySumatraPDF"
#define AppVersion "1.0.0"
#define AppVersion "1.0.1"
#define AppPublisher "PrettySumatraPDF"
#define AppURL "https://github.com/JaviLendi/PrettySumatraPDF"
#define AppExeName "SumatraPDF-dll.exe"
Expand Down
2 changes: 1 addition & 1 deletion scripts/installer/README_INSTALLER.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ cmd /c "scripts\\build-vs2022.cmd Release x64 SumatraPDF-dll"
3. Compile the installer with Inno Setup:

```powershell
& 'C:\Users\javil\AppData\Local\Programs\Inno Setup 6\ISCC.exe' scripts\\installer\\PrettySumatraPDF.iss
& 'C:\Users\user\AppData\Local\Programs\Inno Setup 6\ISCC.exe' scripts\\installer\\PrettySumatraPDF.iss
```

4. The installer will be produced under `scripts\installer\dist\` with filename `PrettySumatraPDF-Setup-1.0.0.exe`.
Expand Down
Binary file not shown.
89 changes: 63 additions & 26 deletions src/DisplayModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,33 @@
// if true, we pre-render the pages right before and after the visible pages
bool gPredictiveRender = true;

constexpr int kLargeDocPrecacheThresholdPages = 100;
constexpr int kLargeDocPrecacheRadiusPages = 30;

static bool IsDisplayModelValid(DisplayModel* dm) {
for (MainWindow* win : gWindows) {
for (WindowTab* tab : win->Tabs()) {
if (tab->AsFixed() == dm) {
return true;
}
}
}
return false;
}

static void RenderVisiblePartsOnUIThread(DisplayModel* dm) {
if (!IsDisplayModelValid(dm)) {
return;
}
dm->renderVisiblePartsScheduled = false;
dm->RenderVisibleParts();
}

static void ScheduleRenderVisiblePartsOnUIThread(DisplayModel* dm) {
auto fn = MkFunc0<DisplayModel>(RenderVisiblePartsOnUIThread, dm);
uitask::Post(fn, "RenderVisibleParts");
}

static int ColumnsFromDisplayMode(DisplayMode displayMode) {
if (!IsSingle(displayMode)) {
return 2;
Expand Down Expand Up @@ -219,17 +246,6 @@ void DisplayModel::RepaintDisplay() {
cb->Repaint();
}

static bool IsDisplayModelValid(DisplayModel* dm) {
for (MainWindow* win : gWindows) {
for (WindowTab* tab : win->Tabs()) {
if (tab->AsFixed() == dm) {
return true;
}
}
}
return false;
}

static void RenderFinishedOnUIThread(PageRenderRequest* req) {
if (!IsDisplayModelValid(req->dm)) {
delete req;
Expand Down Expand Up @@ -1202,13 +1218,6 @@ void DisplayModel::RenderVisibleParts() {
return;
}

// rendering happens LIFO except if the queue is currently
// empty, so request the visible pages first and last to
// make sure they're rendered before the predicted pages
for (int pageNo = firstVisiblePage; pageNo <= lastVisiblePage; pageNo++) {
cb->RequestRendering(pageNo);
}

if (gPredictiveRender) {
// prerender two more pages in facing and book view modes
// if the rendering queue still has place for them
Expand All @@ -1228,15 +1237,43 @@ void DisplayModel::RenderVisibleParts() {
}
}

// re-request the visible pages again so:
// * they get picked first by rendering thread
// * if queue fills up, the invisible pages from predictive rendering
// wont be rendered
// rendering happens LIFO, so request the visible pages last in reverse
// order to make sure the most relevant page gets rendered first.
for (int pageNo = lastVisiblePage; pageNo >= firstVisiblePage; pageNo--) {
cb->RequestRendering(pageNo);
}
}

void DisplayModel::PrecacheLargeDocumentPages() {
if (!cb || PageCount() <= kLargeDocPrecacheThresholdPages) {
return;
}

int currentPageNo = CurrentPageNo();
if (!ValidPageNo(currentPageNo)) {
return;
}

for (int delta = kLargeDocPrecacheRadiusPages; delta >= 1; --delta) {
int prevPageNo = currentPageNo - delta;
if (prevPageNo >= 1) {
cb->RequestRendering(prevPageNo);
}
int nextPageNo = currentPageNo + delta;
if (nextPageNo <= PageCount()) {
cb->RequestRendering(nextPageNo);
}
}
}

void DisplayModel::ScheduleRenderVisibleParts() {
if (pauseRendering || renderVisiblePartsScheduled) {
return;
}
renderVisiblePartsScheduled = true;
ScheduleRenderVisiblePartsOnUIThread(this);
}

void DisplayModel::SetViewPortSize(Size newViewPortSize) {
ScrollState ss;

Expand All @@ -1257,7 +1294,7 @@ void DisplayModel::SetViewPortSize(Size newViewPortSize) {
}
} else {
RecalcVisibleParts();
RenderVisibleParts();
ScheduleRenderVisibleParts();
cb->UpdateScrollbars(canvasSize);
}
}
Expand Down Expand Up @@ -1370,7 +1407,7 @@ void DisplayModel::GoToPage(int pageNo, int scrollY, bool addNavPt, int scrollX)
viewPort.y = limitValue(viewPort.y, 0, canvasSize.dy - viewPort.dy);

RecalcVisibleParts();
RenderVisibleParts();
ScheduleRenderVisibleParts();
cb->UpdateScrollbars(canvasSize);
cb->PageNoChanged(this, pageNo);
RepaintDisplay();
Expand Down Expand Up @@ -1559,7 +1596,7 @@ void DisplayModel::ScrollYTo(int yOff) {
int currPageNo = CurrentPageNo();
viewPort.y = yOff;
RecalcVisibleParts();
RenderVisibleParts();
ScheduleRenderVisibleParts();

int newPageNo = CurrentPageNo();
if (newPageNo != currPageNo) {
Expand Down Expand Up @@ -1617,7 +1654,7 @@ void DisplayModel::ScrollYBy(int dy, bool changePage) {
currPageNo = CurrentPageNo();
viewPort.y = newYOff;
RecalcVisibleParts();
RenderVisibleParts();
ScheduleRenderVisibleParts();
cb->UpdateScrollbars(canvasSize);
newPageNo = CurrentPageNo();
if (newPageNo != currPageNo) {
Expand Down
3 changes: 3 additions & 0 deletions src/DisplayModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ struct DisplayModel : DocController {
Point GetContentStart(int pageNo) const;
void RecalcVisibleParts() const;
void RenderVisibleParts();
void PrecacheLargeDocumentPages();
void ScheduleRenderVisibleParts();
void AddNavPoint();
RectF GetContentBox(int pageNo) const;
void CalcZoomReal(float zoomVirtual);
Expand Down Expand Up @@ -263,6 +265,7 @@ struct DisplayModel : DocController {

/* allow resizing a window without triggering a new rendering (needed for window destruction) */
bool pauseRendering = false;
bool renderVisiblePartsScheduled = false;

void RenderFinished(PageRenderRequest* req);
void RenderFinishedAsync(PageRenderRequest* req);
Expand Down
6 changes: 6 additions & 0 deletions src/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ struct MainWindow {
LayoutState lastLayoutState;

int currPageNo = 0; // cached value, needed to determine when to auto-update the ToC selection
DocController* hybridToolbarSyncCtrl = nullptr;
int hybridToolbarSyncPageNo = 0;
int hybridToolbarSyncPageCount = 0;
float hybridToolbarSyncZoom = 0.0f;
bool hybridToolbarSyncCanAnnotate = false;
bool hybridToolbarSyncHasState = false;

// overlay scrollbars (used when scrollbars mode is "smart" or "overlay")
struct OverlayScrollbar* overlayScrollV = nullptr;
Expand Down
90 changes: 75 additions & 15 deletions src/RenderCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ static DWORD WINAPI RenderCacheThread(LPVOID data);
bool gShowTileLayout = false;
int gMaxRenderThreads = 8;

static int GetRequestPriority(DisplayModel* dm, int pageNo) {
if (!dm || !dm->ValidPageNo(pageNo)) {
return 0;
}
int currentPageNo = dm->CurrentPageNo();
if (!dm->ValidPageNo(currentPageNo)) {
return 0;
}
return pageNo >= currentPageNo ? pageNo - currentPageNo : currentPageNo - pageNo;
}

struct RenderThreadData {
RenderCache* cache;
int threadIdx;
Expand Down Expand Up @@ -114,16 +125,39 @@ RenderCache::~RenderCache() {
<rotation> and <zoom> in the cache - call DropCacheEntry when you
no longer need a found entry. */
BitmapCacheEntry* RenderCache::Find(DisplayModel* dm, int pageNo, int rotation, float zoom, TilePosition* tile) {
ScopedCritSec scope(&cacheAccess);
rotation = NormalizeRotation(rotation);
float targetZoom = zoom == kInvalidZoom ? dm->GetZoomReal(pageNo) : zoom;

ScopedCritSec scope(&cacheAccess);
BitmapCacheEntry* bestMatch = nullptr;
float bestZoomDiff = 0;
for (int i = 0; i < cacheCount; i++) {
BitmapCacheEntry* e = cache[i];
if ((dm == e->dm) && (pageNo == e->pageNo) && (rotation == e->rotation) &&
(kInvalidZoom == zoom || zoom == e->zoom) && (!tile || e->tile == *tile)) {
if ((dm != e->dm) || (pageNo != e->pageNo) || (rotation != e->rotation) || (tile && e->tile != *tile)) {
continue;
}
if (kInvalidZoom != zoom && zoom == e->zoom) {
e->refs++;
ReportIf(i != e->cacheIdx);
return e;
}
if (kInvalidZoom == zoom) {
if (e->zoom == kInvalidZoom) {
continue;
}
float zoomDiff = e->zoom - targetZoom;
if (zoomDiff < 0) {
zoomDiff = -zoomDiff;
}
if (!bestMatch || zoomDiff < bestZoomDiff) {
bestMatch = e;
bestZoomDiff = zoomDiff;
}
}
}
if (bestMatch) {
bestMatch->refs++;
return bestMatch;
}
return nullptr;
}
Expand Down Expand Up @@ -497,6 +531,7 @@ void RenderCache::RequestRendering(DisplayModel* dm, int pageNo, TilePosition ti

int rotation = NormalizeRotation(dm->GetRotation());
float zoom = dm->GetZoomReal(pageNo);
int priority = GetRequestPriority(dm, pageNo);

for (int i = 0; i < nRenderThreads; i++) {
auto* cr = curReqs[i];
Expand Down Expand Up @@ -533,6 +568,7 @@ void RenderCache::RequestRendering(DisplayModel* dm, int pageNo, TilePosition ti
req->zoom = zoom;
req->rotation = rotation;
}
req->priority = std::min(req->priority, priority);
return;
}
}
Expand Down Expand Up @@ -577,18 +613,29 @@ bool RenderCache::Render(DisplayModel* dm, int pageNo, int rotation, float zoom,

ScopedCritSec scope(&requestAccess);
PageRenderRequest* newRequest;
int priority = GetRequestPriority(dm, pageNo);

/* add request to the queue */
if (requestCount == MAX_PAGE_REQUESTS) {
/* queue is full -> remove the oldest items on the queue */
if (requests[0].renderFinishedCb.IsValid()) {
requests[0].abort = true;
requests[0].bmp = nullptr;
requests[0].errorCode = 0;
requests[0].renderFinishedCb.Call(&requests[0]);
/* queue is full -> replace the lowest-priority queued item if the new
request is more important. Otherwise drop the new request. */
int worstIdx = 0;
for (int i = 1; i < MAX_PAGE_REQUESTS; i++) {
if (requests[i].priority > requests[worstIdx].priority ||
(requests[i].priority == requests[worstIdx].priority && requests[i].timestamp < requests[worstIdx].timestamp)) {
worstIdx = i;
}
}
if (priority >= requests[worstIdx].priority) {
return true;
}
if (requests[worstIdx].renderFinishedCb.IsValid()) {
requests[worstIdx].abort = true;
requests[worstIdx].bmp = nullptr;
requests[worstIdx].errorCode = 0;
requests[worstIdx].renderFinishedCb.Call(&requests[worstIdx]);
}
memmove(&(requests[0]), &(requests[1]), sizeof(PageRenderRequest) * (MAX_PAGE_REQUESTS - 1));
newRequest = &(requests[MAX_PAGE_REQUESTS - 1]);
newRequest = &(requests[worstIdx]);
} else {
newRequest = &(requests[requestCount]);
requestCount++;
Expand All @@ -599,6 +646,7 @@ bool RenderCache::Render(DisplayModel* dm, int pageNo, int rotation, float zoom,
newRequest->pageNo = pageNo;
newRequest->rotation = rotation;
newRequest->zoom = zoom;
newRequest->priority = priority;
if (tile) {
newRequest->pageRect = GetTileRectUser(dm->GetEngine(), pageNo, rotation, zoom, *tile);
newRequest->tile = *tile;
Expand Down Expand Up @@ -661,8 +709,18 @@ bool RenderCache::GetNextRequest(PageRenderRequest* req, int threadIdx) {

ReportIf(requestCount < 0);
ReportIf(requestCount > MAX_PAGE_REQUESTS);
int bestIdx = 0;
for (int i = 1; i < requestCount; i++) {
if (requests[i].priority < requests[bestIdx].priority ||
(requests[i].priority == requests[bestIdx].priority && i > bestIdx)) {
bestIdx = i;
}
}
*req = requests[bestIdx];
requestCount--;
*req = requests[requestCount];
if (bestIdx != requestCount) {
requests[bestIdx] = requests[requestCount];
}
curReqs[threadIdx] = req;
ReportIf(requestCount < 0);
ReportIf(req->abort);
Expand All @@ -677,6 +735,8 @@ bool RenderCache::ClearCurrentRequest(int threadIdx) {
}
curReqs[threadIdx] = nullptr;



bool isQueueEmpty = requestCount == 0;
return isQueueEmpty;
}
Expand All @@ -686,7 +746,6 @@ bool RenderCache::ClearCurrentRequest(int threadIdx) {
user know he has to wait until we finish */
void RenderCache::CancelRendering(DisplayModel* dm) {
ClearQueueForDisplayModel(dm);

for (;;) {
EnterCriticalSection(&requestAccess);
bool found = false;
Expand All @@ -704,8 +763,9 @@ void RenderCache::CancelRendering(DisplayModel* dm) {
}
LeaveCriticalSection(&requestAccess);

/* TODO: busy loop is not good, but I don't have a better idea */
Sleep(50);
// Small sleep to avoid busy-looping while waiting for render threads
// to process the abort signals
Sleep(10);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/RenderCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct PageRenderRequest {
int pageNo = 0;
int rotation = 0;
float zoom = 0.f;
int priority = 0;
TilePosition tile;

RectF pageRect; // calculated from TilePosition
Expand Down
14 changes: 5 additions & 9 deletions src/SumatraPDF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5732,15 +5732,11 @@ void SetSidebarVisibility(MainWindow* win, bool tocVisible, bool showFavorites,

// Notify hybrid toolbar WebView (if present) about panel state changes
if (win->hybridToolbar) {
TempStr jsFav =
str::FormatTemp("try{if(window.notifyPanelState)window.notifyPanelState('favorites',%s);}catch(e){};",
showFavorites ? "true" : "false");
win->hybridToolbar->Eval(jsFav);

TempStr jsToc =
str::FormatTemp("try{if(window.notifyPanelState)window.notifyPanelState('bookmarks',%s);}catch(e){};",
tocVisible ? "true" : "false");
win->hybridToolbar->Eval(jsToc);
TempStr js = str::FormatTemp(
"try{if(window.notifyPanelState){window.notifyPanelState('favorites',%s);"
"window.notifyPanelState('bookmarks',%s);}}catch(e){};",
showFavorites ? "true" : "false", tocVisible ? "true" : "false");
win->hybridToolbar->Eval(js);
}
}

Expand Down
Loading
Loading