updf v1.5:
- continuous scrolling through pages - add scroll-bar - drag page by holding right mouse button - select and copy text in UTF-8 - colored icons
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -512,3 +512,12 @@ int kos_get_key()
|
||||
asm volatile("int $0x40":"=a"(__ret):"0"(2));
|
||||
if(!(__ret & 0xFF)) return (__ret>>8)&0xFF; else return 0;
|
||||
}
|
||||
|
||||
// Raw result of fn 2: bits 0-7 = status (0 = key present),
|
||||
// bits 8-15 = ASCII code, bits 16-23 = layout-independent scancode.
|
||||
unsigned kos_get_key_full()
|
||||
{
|
||||
unsigned __ret;
|
||||
asm volatile("int $0x40":"=a"(__ret):"0"(2));
|
||||
return __ret;
|
||||
}
|
||||
|
||||
@@ -182,4 +182,5 @@ int kos_random(int num);
|
||||
int kos_get_mouse_wheels(void);
|
||||
void kos_screen_max(int* x, int* y);
|
||||
int kos_get_key();
|
||||
unsigned kos_get_key_full();
|
||||
void kos_text(int x, int y, int color, const char* text, int len);
|
||||
|
||||
+644
-120
@@ -20,7 +20,50 @@ struct proc_info Form;
|
||||
#define DOCUMENT_BORDER 0x979797
|
||||
#define DOCUMENT_BG 0xABABAB
|
||||
|
||||
#define SCROLL_H 25
|
||||
#define SCROLL_STEP 50 // pixels moved per scroll gesture (arrow key / wheel notch)
|
||||
#define PAGE_GAP 14 // gray gap between pages, like in a word processor
|
||||
|
||||
// keyboard scancodes (layout-independent, from fn 2 bits 16-23)
|
||||
#define SC_ESC 0x01
|
||||
#define SC_MINUS 0x0C // main row -
|
||||
#define SC_EQUAL 0x0D // main row =/+
|
||||
#define SC_R 0x13
|
||||
#define SC_LBRACKET 0x1A // [
|
||||
#define SC_RBRACKET 0x1B // ]
|
||||
#define SC_G 0x22
|
||||
#define SC_L 0x26
|
||||
#define SC_NUM_MINUS 0x4A // keypad -
|
||||
#define SC_NUM_PLUS 0x4E // keypad +
|
||||
#define SC_HOME 0x47
|
||||
#define SC_UP 0x48
|
||||
#define SC_PGUP 0x49
|
||||
#define SC_END 0x4F
|
||||
#define SC_DOWN 0x50
|
||||
#define SC_PGDN 0x51
|
||||
|
||||
// vertical scrollbar in the WebView style: flat box_lib type 2, no arrows
|
||||
#define SCROLL_W 15
|
||||
#define SB_BG_COL 0xEEEEEE // track
|
||||
#define SB_FRONT_COL 0xBBBBBB // runner
|
||||
#define SB_MIN_RUN 10 // minimal runner height, as in box_lib
|
||||
|
||||
static int sb_run_y, sb_run_h; // runner rect (client coords), for hit testing
|
||||
static char sb_active; // the document is longer than the viewport
|
||||
static char sb_drag, sb_lmb_prev;
|
||||
static int sb_drag_off; // pointer offset inside the runner while dragging
|
||||
|
||||
// mouse interaction on the page: left = select text, right = drag (pan)
|
||||
static char sel_dragging; // left button held, building a selection
|
||||
static char sel_has; // a highlighted selection is on screen
|
||||
static int sel_x0, sel_y0; // selection anchor, device coordinates
|
||||
static char pan_dragging; // right button held, panning the page
|
||||
static int pan_last_my; // last pointer y while panning
|
||||
|
||||
// look-ahead cache of rendered neighbour pages for continuous scrolling
|
||||
#define PAGE_CACHE_N 3
|
||||
static fz_pixmap *cache_pix[PAGE_CACHE_N];
|
||||
static int cache_no[PAGE_CACHE_N];
|
||||
static int cache_res = -1, cache_rot = -1, cache_gray = -1;
|
||||
|
||||
short show_area_w = 65;
|
||||
short show_area_x;
|
||||
@@ -28,21 +71,19 @@ short show_area_x;
|
||||
char key_mode_enter_page_number;
|
||||
int new_page_number;
|
||||
|
||||
static short window_center, draw_h, draw_w;
|
||||
|
||||
const char *help[] = {
|
||||
"Keys:",
|
||||
" ",
|
||||
"PageUp - go to previous page",
|
||||
"PageDown - go to next page",
|
||||
"Home - go to first page",
|
||||
"End - go to last page",
|
||||
"Down arrow - scroll current page down",
|
||||
"Up arrow - scroll current page up",
|
||||
"+/- - zoom in/out",
|
||||
"[ or l - rotate page 90 deg to the left",
|
||||
"] or r - rotate page 90 deg to the right",
|
||||
"g - grayscale on/off",
|
||||
" ",
|
||||
"PageUp - go to previous page",
|
||||
"PageDown - go to next page",
|
||||
"Home - go to first page",
|
||||
"End - go to last page",
|
||||
"Down arrow - scroll down",
|
||||
"Up arrow - scroll up",
|
||||
"+/- - zoom in/out",
|
||||
"[ or l - rotate page 90 deg to the left",
|
||||
"] or r - rotate page 90 deg to the right",
|
||||
"g - grayscale on/off",
|
||||
" ",
|
||||
"Press Escape to hide help",
|
||||
0
|
||||
@@ -56,6 +97,23 @@ void DrawPagination(void);
|
||||
void HandleNewPageNumber(unsigned char key);
|
||||
void ApplyNewPageNumber(void);
|
||||
void DrawMainWindow(void);
|
||||
void FlushPageCache(void);
|
||||
void SyncCacheParams(void);
|
||||
void StashPixmap(int pageno, fz_pixmap *pix);
|
||||
fz_pixmap *GetPageImage(int pageno);
|
||||
int PageCenterX(fz_pixmap *pix);
|
||||
void BlitPageSlice(fz_pixmap *pix, int vy, int srcy, int h);
|
||||
void GoToPage(int n, int new_pany);
|
||||
void NormalizeScrollPos(void);
|
||||
int ViewW(void);
|
||||
void GetDocMetrics(int *total, int *pos);
|
||||
void DrawScrollbar(void);
|
||||
void ScrollToDocPos(int pos);
|
||||
void ScrollbarMouse(void);
|
||||
void ClearSelection(void);
|
||||
int ClientToPageDev(int mx, int my, int *dx, int *dy);
|
||||
void CopySelectionToClipboard(void);
|
||||
void ProcessPageMouse(void);
|
||||
|
||||
|
||||
// not implemented yet
|
||||
@@ -120,59 +178,505 @@ void winrepaint(pdfapp_t *app)
|
||||
}
|
||||
|
||||
|
||||
/* == continuous scroll: page cache =============================== */
|
||||
|
||||
void FlushPageCache(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PAGE_CACHE_N; i++)
|
||||
{
|
||||
if (cache_pix[i]) fz_drop_pixmap(cache_pix[i]);
|
||||
cache_pix[i] = NULL;
|
||||
cache_no[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// drop all cached pages if the view parameters have changed
|
||||
void SyncCacheParams(void)
|
||||
{
|
||||
if (cache_res != gapp.resolution || cache_rot != gapp.rotate || cache_gray != gapp.grayscale)
|
||||
{
|
||||
FlushPageCache();
|
||||
cache_res = gapp.resolution;
|
||||
cache_rot = gapp.rotate;
|
||||
cache_gray = gapp.grayscale;
|
||||
}
|
||||
}
|
||||
|
||||
// keep a reference to an already rendered page (e.g. the outgoing current
|
||||
// page on a flip) so scrolling back to it is instant
|
||||
void StashPixmap(int pageno, fz_pixmap *pix)
|
||||
{
|
||||
int i, slot = -1;
|
||||
|
||||
if (!pix) return;
|
||||
SyncCacheParams(); // the pixmap is rendered with the current params
|
||||
|
||||
for (i = 0; i < PAGE_CACHE_N; i++)
|
||||
if (cache_pix[i] && cache_no[i] == pageno) return; // already cached
|
||||
|
||||
for (i = 0; i < PAGE_CACHE_N; i++)
|
||||
if (!cache_pix[i]) { slot = i; break; }
|
||||
|
||||
if (slot < 0) // evict the entry farthest from this page
|
||||
{
|
||||
slot = 0;
|
||||
for (i = 1; i < PAGE_CACHE_N; i++)
|
||||
if (ABS(cache_no[i] - pageno) > ABS(cache_no[slot] - pageno)) slot = i;
|
||||
fz_drop_pixmap(cache_pix[slot]);
|
||||
}
|
||||
cache_pix[slot] = fz_keep_pixmap(pix);
|
||||
cache_no[slot] = pageno;
|
||||
}
|
||||
|
||||
// pixmap of any page: the current one comes from pdfapp, neighbours
|
||||
// are rendered on demand and cached
|
||||
fz_pixmap *GetPageImage(int pageno)
|
||||
{
|
||||
int i, slot;
|
||||
|
||||
if (pageno == gapp.pageno) return gapp.image;
|
||||
if (pageno < 1 || pageno > gapp.pagecount) return NULL;
|
||||
|
||||
SyncCacheParams();
|
||||
for (i = 0; i < PAGE_CACHE_N; i++)
|
||||
if (cache_pix[i] && cache_no[i] == pageno) return cache_pix[i];
|
||||
|
||||
slot = -1;
|
||||
for (i = 0; i < PAGE_CACHE_N; i++)
|
||||
if (!cache_pix[i]) { slot = i; break; }
|
||||
if (slot < 0) // evict the entry farthest from the current page
|
||||
{
|
||||
slot = 0;
|
||||
for (i = 1; i < PAGE_CACHE_N; i++)
|
||||
if (ABS(cache_no[i] - gapp.pageno) > ABS(cache_no[slot] - gapp.pageno)) slot = i;
|
||||
fz_drop_pixmap(cache_pix[slot]);
|
||||
cache_pix[slot] = NULL;
|
||||
}
|
||||
cache_pix[slot] = pdfapp_renderpage(&gapp, pageno);
|
||||
cache_no[slot] = cache_pix[slot] ? pageno : 0;
|
||||
return cache_pix[slot];
|
||||
}
|
||||
|
||||
/* == continuous scroll: view composition ========================= */
|
||||
|
||||
// width of the page area: the client width minus the scrollbar strip
|
||||
int ViewW(void)
|
||||
{
|
||||
return Form.cwidth - SCROLL_W;
|
||||
}
|
||||
|
||||
int PageCenterX(fz_pixmap *pix)
|
||||
{
|
||||
if (ViewW() > pix->w) return (ViewW() - pix->w) / 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// draw a horizontal slice of a page at viewport line vy:
|
||||
// side backgrounds, 1px borders and the page image itself
|
||||
void BlitPageSlice(fz_pixmap *pix, int vy, int srcy, int h)
|
||||
{
|
||||
int wc = PageCenterX(pix);
|
||||
|
||||
if (wc > 0)
|
||||
{
|
||||
kol_paint_bar(0, TOOLBAR_HEIGHT + vy, wc - 1, h, DOCUMENT_BG);
|
||||
kol_paint_bar(wc - 1, TOOLBAR_HEIGHT + vy, 1, h, DOCUMENT_BORDER);
|
||||
kol_paint_bar(wc + pix->w, TOOLBAR_HEIGHT + vy, 1, h, DOCUMENT_BORDER);
|
||||
if (ViewW() > wc + pix->w + 1)
|
||||
kol_paint_bar(wc + pix->w + 1, TOOLBAR_HEIGHT + vy,
|
||||
ViewW() - wc - pix->w - 1, h, DOCUMENT_BG);
|
||||
}
|
||||
|
||||
kos_blit(wc + Form.cleft,
|
||||
Form.ctop + TOOLBAR_HEIGHT + vy,
|
||||
ViewW() - wc,
|
||||
h,
|
||||
0,
|
||||
srcy,
|
||||
pix->w,
|
||||
pix->h,
|
||||
pix->w * pix->n, // stride
|
||||
pix->samples // image
|
||||
);
|
||||
}
|
||||
|
||||
// compose the viewport: tail of the current page, the gap, the head of
|
||||
// the next page(s) - like the continuous page view in a word processor
|
||||
void winblit(pdfapp_t *app)
|
||||
{
|
||||
int vh, vy, page_top, k, wc;
|
||||
fz_pixmap *pix;
|
||||
|
||||
if (do_not_blit) return;
|
||||
if (Form.cwidth == 0) return; // window is not drawn yet
|
||||
|
||||
if (key_mode_enter_page_number==1) HandleNewPageNumber(0); else DrawPagination();
|
||||
|
||||
if (Form.cwidth > gapp.image->w) window_center = (Form.cwidth - gapp.image->w) / 2; else window_center = 0;
|
||||
|
||||
gapp.panx = 0;
|
||||
|
||||
kos_blit(window_center + Form.cleft,
|
||||
Form.ctop + TOOLBAR_HEIGHT,
|
||||
Form.cwidth,
|
||||
Form.cheight - TOOLBAR_HEIGHT,
|
||||
gapp.panx,
|
||||
gapp.pany,
|
||||
gapp.image->w,
|
||||
gapp.image->h,
|
||||
gapp.image->w * gapp.image->n, // stride
|
||||
gapp.image->samples // image
|
||||
);
|
||||
|
||||
/*
|
||||
void kos_blit(int dstx, int dsty, int w, int h, int srcx, int srcy, int srcw, int srch, int stride, char *d)
|
||||
*/
|
||||
|
||||
vh = Form.cheight - TOOLBAR_HEIGHT;
|
||||
if (vh <= 0) return;
|
||||
|
||||
vy = 0; // how much of the viewport is painted already
|
||||
page_top = -gapp.pany; // viewport y of the current page top
|
||||
k = gapp.pageno;
|
||||
|
||||
while (vy < vh && (pix = GetPageImage(k)) != NULL)
|
||||
{
|
||||
int page_bot = page_top + pix->h;
|
||||
wc = PageCenterX(pix);
|
||||
|
||||
// border above the page, on the last row of the gap
|
||||
if (page_top > 0 && page_top - 1 < vh)
|
||||
kol_paint_bar(wc ? wc - 1 : 0, TOOLBAR_HEIGHT + page_top - 1,
|
||||
MIN(pix->w + 2, ViewW()), 1, DOCUMENT_BORDER);
|
||||
|
||||
if (page_bot > vy)
|
||||
{
|
||||
int h = MIN(page_bot, vh) - vy;
|
||||
BlitPageSlice(pix, vy, vy - page_top, h);
|
||||
vy += h;
|
||||
}
|
||||
if (vy >= vh) break;
|
||||
|
||||
page_top = page_bot;
|
||||
|
||||
if (k < gapp.pagecount) // inter-page gap
|
||||
{
|
||||
int gap_bot = page_bot + PAGE_GAP;
|
||||
if (gap_bot > vy)
|
||||
{
|
||||
kol_paint_bar(0, TOOLBAR_HEIGHT + vy, ViewW(),
|
||||
MIN(gap_bot, vh) - vy, DOCUMENT_BG);
|
||||
// border under the page
|
||||
if (page_bot >= 0 && page_bot < vh)
|
||||
kol_paint_bar(wc ? wc - 1 : 0, TOOLBAR_HEIGHT + page_bot,
|
||||
MIN(pix->w + 2, ViewW()), 1, DOCUMENT_BORDER);
|
||||
vy = MIN(gap_bot, vh);
|
||||
}
|
||||
page_top = gap_bot;
|
||||
}
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
if (vy < vh) // area below the last page
|
||||
kol_paint_bar(0, TOOLBAR_HEIGHT + vy, ViewW(), vh - vy, DOCUMENT_BG);
|
||||
|
||||
DrawScrollbar();
|
||||
}
|
||||
|
||||
/* == vertical scrollbar (WebView / box_lib type 2 style) ========= */
|
||||
|
||||
void DrawPageSides(void)
|
||||
{
|
||||
if (gapp.image->h < Form.cheight - TOOLBAR_HEIGHT) {
|
||||
draw_h = gapp.image->h - gapp.pany;
|
||||
} else {
|
||||
draw_h = Form.cheight - TOOLBAR_HEIGHT;
|
||||
// document height and current position in pixels; pages are assumed
|
||||
// to be as tall as the current one (true for typical PDFs)
|
||||
void GetDocMetrics(int *total, int *pos)
|
||||
{
|
||||
int unit = gapp.image->h + PAGE_GAP;
|
||||
*total = gapp.pagecount * unit - PAGE_GAP;
|
||||
*pos = (gapp.pageno - 1) * unit + gapp.pany;
|
||||
}
|
||||
|
||||
void DrawScrollbar(void)
|
||||
{
|
||||
int VH = Form.cheight - TOOLBAR_HEIGHT;
|
||||
int x0 = ViewW();
|
||||
int total, pos, run, pos2;
|
||||
|
||||
GetDocMetrics(&total, &pos);
|
||||
|
||||
kol_paint_bar(x0, TOOLBAR_HEIGHT, SCROLL_W, VH, SB_BG_COL); // track
|
||||
if (total <= VH)
|
||||
{
|
||||
sb_active = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (gapp.image->w < Form.cwidth) {
|
||||
window_center = (Form.cwidth - gapp.image->w) / 2;
|
||||
draw_w = gapp.image->w + 2;
|
||||
kol_paint_bar(0, TOOLBAR_HEIGHT, window_center-1, Form.cheight - TOOLBAR_HEIGHT, DOCUMENT_BG);
|
||||
kol_paint_bar(window_center-1, TOOLBAR_HEIGHT, 1, draw_h, DOCUMENT_BORDER);
|
||||
kol_paint_bar(window_center + gapp.image->w, TOOLBAR_HEIGHT, 1, draw_h, DOCUMENT_BORDER);
|
||||
kol_paint_bar(window_center + gapp.image->w+1, TOOLBAR_HEIGHT, Form.cwidth - window_center - gapp.image->w - 1, Form.cheight - TOOLBAR_HEIGHT, DOCUMENT_BG);
|
||||
} else {
|
||||
window_center = 1;
|
||||
draw_w = Form.cwidth;
|
||||
|
||||
// box_lib formulas: runner size and offset inside the track
|
||||
run = (int)((long long)VH * VH / total);
|
||||
if (run < SB_MIN_RUN) run = SB_MIN_RUN;
|
||||
if (run > VH) run = VH;
|
||||
pos2 = (int)((long long)(VH - run) * pos / (total - VH));
|
||||
if (pos2 > VH - run) pos2 = VH - run;
|
||||
if (pos2 < 0) pos2 = 0;
|
||||
|
||||
// flat runner: 1px inset on the left, 1px track-colored lines
|
||||
// on top and bottom (line_col == bckg_col in the WebView scheme)
|
||||
kol_paint_bar(x0 + 1, TOOLBAR_HEIGHT + pos2 + 1, SCROLL_W - 1, run - 2, SB_FRONT_COL);
|
||||
|
||||
sb_active = 1;
|
||||
sb_run_y = TOOLBAR_HEIGHT + pos2;
|
||||
sb_run_h = run;
|
||||
}
|
||||
|
||||
// jump so that the viewport top lands at the given document position
|
||||
void ScrollToDocPos(int pos)
|
||||
{
|
||||
int unit = gapp.image->h + PAGE_GAP;
|
||||
int page;
|
||||
|
||||
ClearSelection();
|
||||
if (pos < 0) pos = 0;
|
||||
page = pos / unit + 1;
|
||||
if (page > gapp.pagecount) page = gapp.pagecount;
|
||||
if (page != gapp.pageno)
|
||||
GoToPage(page, pos - (page - 1) * unit);
|
||||
else
|
||||
gapp.pany = pos - (page - 1) * unit;
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
void ScrollbarMouse(void)
|
||||
{
|
||||
int mp, mx, my, lmb, VH, total, pos;
|
||||
|
||||
// fn 37/1 returns coordinates relative to the client area,
|
||||
// signed 16-bit (negative when the cursor is above/left of it)
|
||||
mp = kol_mouse_posw();
|
||||
mx = (short)(mp >> 16);
|
||||
my = (short)(mp & 0xFFFF);
|
||||
lmb = kol_mouse_btn() & 1;
|
||||
VH = Form.cheight - TOOLBAR_HEIGHT;
|
||||
|
||||
if (!sb_active || !lmb)
|
||||
{
|
||||
sb_drag = 0;
|
||||
sb_lmb_prev = lmb;
|
||||
return;
|
||||
}
|
||||
|
||||
kol_paint_bar(window_center - 1, gapp.image->h - gapp.pany + TOOLBAR_HEIGHT, draw_w, 1, DOCUMENT_BORDER);
|
||||
kol_paint_bar(window_center - 1, gapp.image->h - gapp.pany + TOOLBAR_HEIGHT + 1,
|
||||
draw_w, Form.cheight - gapp.image->h - TOOLBAR_HEIGHT + gapp.pany - 1, DOCUMENT_BG);
|
||||
|
||||
GetDocMetrics(&total, &pos);
|
||||
|
||||
if (sb_drag)
|
||||
{
|
||||
// runner follows the pointer
|
||||
int pos2 = my - sb_drag_off - TOOLBAR_HEIGHT;
|
||||
int space = VH - sb_run_h;
|
||||
if (space > 0)
|
||||
{
|
||||
int newpos = (int)((long long)pos2 * (total - VH) / space);
|
||||
if (newpos > total - VH) newpos = total - VH;
|
||||
ScrollToDocPos(newpos);
|
||||
}
|
||||
}
|
||||
else if (!sb_lmb_prev
|
||||
&& mx >= ViewW() && mx < Form.cwidth
|
||||
&& my >= TOOLBAR_HEIGHT && my < Form.cheight)
|
||||
{
|
||||
if (my >= sb_run_y && my < sb_run_y + sb_run_h)
|
||||
{
|
||||
sb_drag = 1;
|
||||
sb_drag_off = my - sb_run_y;
|
||||
}
|
||||
else if (my < sb_run_y) ScrollToDocPos(pos - VH); // page up
|
||||
else ScrollToDocPos(pos + VH); // page down
|
||||
}
|
||||
sb_lmb_prev = lmb;
|
||||
}
|
||||
|
||||
/* == text selection & drag-to-pan =============================== */
|
||||
|
||||
// restore the pixels under the current highlight (if any); the caller
|
||||
// must repaint. Called before any scroll/zoom/rotate/page flip so the
|
||||
// pixmap is never stashed or re-rendered with inverted pixels in it.
|
||||
void ClearSelection(void)
|
||||
{
|
||||
if (sel_has)
|
||||
{
|
||||
pdfapp_invertselection(&gapp);
|
||||
sel_has = 0;
|
||||
}
|
||||
sel_dragging = 0;
|
||||
}
|
||||
|
||||
// map a client point to device coordinates inside the current page.
|
||||
// Coordinates are clamped to the page; the return value tells whether
|
||||
// the original point was actually within the page rectangle.
|
||||
int ClientToPageDev(int mx, int my, int *dx, int *dy)
|
||||
{
|
||||
int wc = PageCenterX(gapp.image);
|
||||
int px = mx - wc; // pixel x within the page
|
||||
int py = my - TOOLBAR_HEIGHT + gapp.pany; // pixel y within the page
|
||||
int inside = (px >= 0 && px < gapp.image->w && py >= 0 && py < gapp.image->h);
|
||||
|
||||
if (px < 0) px = 0; else if (px > gapp.image->w) px = gapp.image->w;
|
||||
if (py < 0) py = 0; else if (py > gapp.image->h) py = gapp.image->h;
|
||||
*dx = px + gapp.image->x;
|
||||
*dy = py + gapp.image->y;
|
||||
return inside;
|
||||
}
|
||||
|
||||
// UTF-8 encode a single code point (<= 0xFFFF); returns bytes written
|
||||
static int utf8_put(unsigned c, char *out)
|
||||
{
|
||||
if (c < 0x80) { out[0] = c; return 1; }
|
||||
if (c < 0x800) { out[0] = 0xC0 | (c >> 6); out[1] = 0x80 | (c & 0x3F); return 2; }
|
||||
out[0] = 0xE0 | (c >> 12);
|
||||
out[1] = 0x80 | ((c >> 6) & 0x3F);
|
||||
out[2] = 0x80 | (c & 0x3F);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// extract the selected text and push it to the KolibriOS clipboard
|
||||
// (fn 54: 12-byte header {size, type=text, encoding=UTF-8} + data)
|
||||
void CopySelectionToClipboard(void)
|
||||
{
|
||||
static unsigned short ucs[4096];
|
||||
static char clip[12 + 4096 * 3 + 1];
|
||||
int i, n = 0;
|
||||
|
||||
int total;
|
||||
|
||||
pdfapp_oncopy(&gapp, ucs, 4096);
|
||||
for (i = 0; ucs[i]; i++)
|
||||
n += utf8_put(ucs[i], clip + 12 + n);
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
total = 12 + n;
|
||||
// 12-byte header, little-endian, written byte-wise to avoid aliasing
|
||||
clip[0] = total; clip[1] = total >> 8; clip[2] = total >> 16; clip[3] = total >> 24;
|
||||
clip[4] = clip[5] = clip[6] = clip[7] = 0; // type: text
|
||||
clip[8] = clip[9] = clip[10] = clip[11] = 0; // encoding: 0 = UTF-8
|
||||
kol_clip_set(total, clip);
|
||||
}
|
||||
|
||||
// left button = select text, right button = grab & drag the page.
|
||||
// Called on every mouse event unless the scrollbar owns the drag.
|
||||
void ProcessPageMouse(void)
|
||||
{
|
||||
int mp = kol_mouse_posw();
|
||||
int mx = (short)(mp >> 16);
|
||||
int my = (short)(mp & 0xFFFF);
|
||||
int btn = kol_mouse_btn();
|
||||
int left = btn & 1, right = btn & 2;
|
||||
int dx, dy;
|
||||
|
||||
/* --- right button: grab & drag (hand tool) --- */
|
||||
if (right)
|
||||
{
|
||||
if (!pan_dragging)
|
||||
{
|
||||
if (my >= TOOLBAR_HEIGHT && mx >= 0 && mx < ViewW())
|
||||
{
|
||||
ClearSelection();
|
||||
winblit(&gapp);
|
||||
pan_dragging = 1;
|
||||
pan_last_my = my;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int d = my - pan_last_my;
|
||||
pan_last_my = my;
|
||||
if (d)
|
||||
{
|
||||
gapp.pany -= d; // content follows the cursor
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
pan_dragging = 0;
|
||||
|
||||
/* --- left button: text selection --- */
|
||||
if (left && mx >= 0 && mx < ViewW() && my >= TOOLBAR_HEIGHT)
|
||||
{
|
||||
int inside = ClientToPageDev(mx, my, &dx, &dy);
|
||||
if (!sel_dragging)
|
||||
{
|
||||
if (!inside) return; // start only on the page itself
|
||||
ClearSelection();
|
||||
winblit(&gapp);
|
||||
sel_x0 = dx;
|
||||
sel_y0 = dy;
|
||||
sel_dragging = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sel_has) pdfapp_invertselection(&gapp); // lift old highlight
|
||||
gapp.selr.x0 = MIN(sel_x0, dx);
|
||||
gapp.selr.x1 = MAX(sel_x0, dx);
|
||||
gapp.selr.y0 = MIN(sel_y0, dy);
|
||||
gapp.selr.y1 = MAX(sel_y0, dy);
|
||||
pdfapp_invertselection(&gapp);
|
||||
sel_has = 1;
|
||||
winblit(&gapp);
|
||||
}
|
||||
}
|
||||
else if (sel_dragging) // left released
|
||||
{
|
||||
sel_dragging = 0;
|
||||
if (sel_has) CopySelectionToClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
/* == continuous scroll: position management ====================== */
|
||||
|
||||
// switch the current page keeping the given scroll offset;
|
||||
// reuses a cached pixmap when possible to avoid re-rendering
|
||||
void GoToPage(int n, int new_pany)
|
||||
{
|
||||
fz_pixmap *cached = NULL;
|
||||
int i;
|
||||
|
||||
// keep the outgoing page: scrolling back to it will be instant
|
||||
StashPixmap(gapp.pageno, gapp.image);
|
||||
|
||||
for (i = 0; i < PAGE_CACHE_N; i++)
|
||||
if (cache_pix[i] && cache_no[i] == n)
|
||||
{
|
||||
cached = cache_pix[i];
|
||||
cache_pix[i] = NULL;
|
||||
cache_no[i] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
gapp.pageno = n;
|
||||
gapp.pany = new_pany;
|
||||
|
||||
if (cached)
|
||||
{
|
||||
if (gapp.image) fz_drop_pixmap(gapp.image);
|
||||
gapp.image = cached;
|
||||
pdfapp_showpage(&gapp, 1, 0, 0); // reload page_list/text/links only
|
||||
}
|
||||
else
|
||||
{
|
||||
pdfapp_showpage(&gapp, 1, 1, 0); // full render, pany is kept
|
||||
}
|
||||
}
|
||||
|
||||
// bring (pageno, pany) back into range, flipping pages when the
|
||||
// viewport top has crossed a page boundary
|
||||
void NormalizeScrollPos(void)
|
||||
{
|
||||
int maxs, rem;
|
||||
|
||||
// crossed the gap downwards: the next page becomes current
|
||||
while (gapp.pageno < gapp.pagecount && gapp.pany >= gapp.image->h + PAGE_GAP)
|
||||
GoToPage(gapp.pageno + 1, gapp.pany - gapp.image->h - PAGE_GAP);
|
||||
|
||||
// scrolled above the page top: the previous page becomes current
|
||||
while (gapp.pany < 0)
|
||||
{
|
||||
if (gapp.pageno <= 1) { gapp.pany = 0; break; }
|
||||
rem = gapp.pany;
|
||||
GoToPage(gapp.pageno - 1, 0);
|
||||
gapp.pany = rem + gapp.image->h + PAGE_GAP;
|
||||
}
|
||||
|
||||
// do not scroll past the bottom of the last page
|
||||
if (gapp.pageno == gapp.pagecount)
|
||||
{
|
||||
maxs = gapp.image->h - (Form.cheight - TOOLBAR_HEIGHT);
|
||||
if (maxs < 0) maxs = 0;
|
||||
if (gapp.pany > maxs) gapp.pany = maxs;
|
||||
}
|
||||
if (gapp.pany < 0) gapp.pany = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,8 +756,9 @@ void DrawMainWindow(void)
|
||||
kol_btn_define(show_area_x-1, 5, show_area_w+1, 23, 20 + BT_HIDE, 0xA4A4A4);
|
||||
kol_paint_bar(show_area_x, 5, show_area_w, 1, 0xA4A4A4);
|
||||
kol_paint_bar(show_area_x, 28, show_area_w, 1, 0xA4A4A4);
|
||||
ClearSelection();
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
DrawPageSides();
|
||||
}
|
||||
|
||||
|
||||
@@ -261,39 +766,28 @@ void DrawMainWindow(void)
|
||||
|
||||
void PageScrollDown(void)
|
||||
{
|
||||
//pdfapp_onkey(&gapp, 'k'); //move down
|
||||
if (gapp.image->h - gapp.pany - SCROLL_H < Form.cheight - TOOLBAR_HEIGHT)
|
||||
{
|
||||
pdfapp_onkey(&gapp, '.');
|
||||
}
|
||||
else {
|
||||
gapp.pany += SCROLL_H;
|
||||
winblit(&gapp);
|
||||
}
|
||||
gapp.pany += SCROLL_STEP;
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
|
||||
void PageScrollUp(void)
|
||||
{
|
||||
//pdfapp_onkey(&gapp, 'j'); //move up
|
||||
if (gapp.pany >= SCROLL_H) {
|
||||
gapp.pany -= SCROLL_H;
|
||||
winblit(&gapp);
|
||||
}
|
||||
else {
|
||||
//not very nice way of using do_not_blit, but it simple
|
||||
if (gapp.pageno == 1) return;
|
||||
do_not_blit = 1;
|
||||
pdfapp_onkey(&gapp, ',');
|
||||
do_not_blit = 0;
|
||||
gapp.pany = gapp.image->h - SCROLL_H - Form.cheight + TOOLBAR_HEIGHT;
|
||||
if (gapp.pany < 0) gapp.pany = 0;
|
||||
//sprintf (debugstr, "gapp.pany: %d \n", gapp.pany);
|
||||
//kol_board_puts(debugstr);
|
||||
winblit(&gapp);
|
||||
}
|
||||
gapp.pany -= SCROLL_STEP;
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
void PageScroll(signed int delta)
|
||||
{
|
||||
ClearSelection();
|
||||
gapp.pany += delta;
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
|
||||
void RunApp(char app[], char param[])
|
||||
{
|
||||
kol_struct70 r;
|
||||
@@ -309,27 +803,50 @@ void RunApp(char app[], char param[])
|
||||
|
||||
void PageZoomIn(void)
|
||||
{
|
||||
int oldh = gapp.image->h;
|
||||
ClearSelection();
|
||||
do_not_blit = 1;
|
||||
pdfapp_onkey(&gapp, '+');
|
||||
DrawPageSides();
|
||||
do_not_blit = 0;
|
||||
// keep the same relative position on the page
|
||||
gapp.pany = (int)((long long)gapp.pany * gapp.image->h / oldh);
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
|
||||
void PageZoomOut(void)
|
||||
{
|
||||
pdfapp_onkey(&gapp, '-');
|
||||
DrawPageSides();
|
||||
int oldh = gapp.image->h;
|
||||
ClearSelection();
|
||||
do_not_blit = 1;
|
||||
pdfapp_onkey(&gapp, '-');
|
||||
do_not_blit = 0;
|
||||
gapp.pany = (int)((long long)gapp.pany * gapp.image->h / oldh);
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
void PageRotateLeft(void)
|
||||
{
|
||||
ClearSelection();
|
||||
do_not_blit = 1;
|
||||
pdfapp_onkey(&gapp, 'L');
|
||||
DrawPageSides();
|
||||
do_not_blit = 0;
|
||||
gapp.pany = 0;
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
void PageRotateRight(void)
|
||||
{
|
||||
ClearSelection();
|
||||
do_not_blit = 1;
|
||||
pdfapp_onkey(&gapp, 'R');
|
||||
DrawPageSides();
|
||||
do_not_blit = 0;
|
||||
gapp.pany = 0;
|
||||
NormalizeScrollPos();
|
||||
winblit(&gapp);
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[])
|
||||
@@ -344,34 +861,26 @@ int main (int argc, char* argv[])
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
kol_board_puts("uPDF: no param set, showing OpenDialog...\n");
|
||||
RunOpenApp(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
kol_board_puts(full_argv);
|
||||
kol_board_puts("\n");
|
||||
|
||||
char buf[128];
|
||||
int resolution = 72;
|
||||
int pageno = 1;
|
||||
fz_accelerate();
|
||||
kol_board_puts("PDF init...\n");
|
||||
pdfapp_init(&gapp);
|
||||
gapp.scrw = 600;
|
||||
gapp.scrh = 400;
|
||||
gapp.resolution = resolution;
|
||||
gapp.pageno = pageno;
|
||||
kol_board_puts("PDF Open...\n");
|
||||
pdfapp_open(&gapp, full_argv, 0, 0);
|
||||
kol_board_puts("PDF Opened!\n");
|
||||
wintitle(&gapp, 0, full_argv);
|
||||
|
||||
kol_board_puts("Inital paint\n");
|
||||
|
||||
int butt, key, screen_max_x, screen_max_y;
|
||||
int butt, key, scan, ascii, screen_max_x, screen_max_y;
|
||||
kos_screen_max(&screen_max_x, &screen_max_y);
|
||||
kol_event_mask(EVENT_REDRAW+EVENT_KEY+EVENT_BUTTON+EVENT_MOUSE_CHANGE);
|
||||
// mouse events only for the active window, as WebView does (EVM_MOUSE_FILTER)
|
||||
kol_event_mask(EVENT_REDRAW+EVENT_KEY+EVENT_BUTTON+EVENT_MOUSE_CHANGE+EVENT_MOUSE_WINDOW_MASK);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@@ -388,45 +897,61 @@ int main (int argc, char* argv[])
|
||||
|
||||
if (Form.window_state & 4) continue; // if Rolled-up
|
||||
|
||||
// Minimal size (700x600)
|
||||
if (Form.width < 700) kol_wnd_change(-1, -1, 700, -1);
|
||||
if (Form.height < 600) kol_wnd_change(-1, -1, -1, 600);
|
||||
// Minimal size (640x480)
|
||||
if (Form.width < 640) kol_wnd_change(-1, -1, 640, -1);
|
||||
if (Form.height < 480) kol_wnd_change(-1, -1, -1, 480);
|
||||
|
||||
DrawMainWindow();
|
||||
break;
|
||||
|
||||
case evKey:
|
||||
key = kos_get_key();
|
||||
key = kos_get_key_full();
|
||||
if (key & 0xFF) break; // no key in buffer
|
||||
scan = (key >> 16) & 0xFF; // layout-independent scancode
|
||||
ascii = (key >> 8) & 0xFF; // ASCII, for digit entry only
|
||||
|
||||
// page-number entry still needs literal digits/enter/bs/esc
|
||||
if (key_mode_enter_page_number)
|
||||
{
|
||||
HandleNewPageNumber(key);
|
||||
HandleNewPageNumber(ascii);
|
||||
break;
|
||||
}
|
||||
if (key==ASCII_KEY_ESC) DrawMainWindow(); //close help
|
||||
if (key==ASCII_KEY_PGDN) pdfapp_onkey(&gapp, ']');
|
||||
if (key==ASCII_KEY_PGUP) pdfapp_onkey(&gapp, '[');
|
||||
if (key==ASCII_KEY_HOME) pdfapp_onkey(&gapp, 'g');
|
||||
if (key==ASCII_KEY_END ) pdfapp_onkey(&gapp, 'G');
|
||||
if (key=='g' ) pdfapp_onkey(&gapp, 'c');
|
||||
if ((key=='[' ) || (key=='l')) PageRotateLeft();
|
||||
if ((key==']' ) || (key=='r')) PageRotateRight();
|
||||
if (key==ASCII_KEY_DOWN ) PageScrollDown();
|
||||
if (key==ASCII_KEY_UP ) PageScrollUp();
|
||||
if (key=='-') PageZoomOut();
|
||||
if ((key=='=') || (key=='+')) PageZoomIn();
|
||||
|
||||
ClearSelection(); // any hotkey drops the current selection
|
||||
|
||||
switch (scan)
|
||||
{
|
||||
case SC_ESC: DrawMainWindow(); break; // close help
|
||||
case SC_PGDN: PageScroll(Form.cheight - TOOLBAR_HEIGHT - SCROLL_STEP); break;
|
||||
case SC_PGUP: PageScroll(-Form.cheight + TOOLBAR_HEIGHT + SCROLL_STEP); break;
|
||||
case SC_HOME: pdfapp_onkey(&gapp, 'g'); break; // first page
|
||||
case SC_END: pdfapp_onkey(&gapp, 'G'); break; // last page
|
||||
case SC_G: pdfapp_onkey(&gapp, 'c'); break; // grayscale on/off
|
||||
case SC_L:
|
||||
case SC_LBRACKET: PageRotateLeft(); break;
|
||||
case SC_R:
|
||||
case SC_RBRACKET: PageRotateRight(); break;
|
||||
case SC_DOWN: PageScroll(SCROLL_STEP); break;
|
||||
case SC_UP: PageScroll(-SCROLL_STEP); break;
|
||||
case SC_MINUS:
|
||||
case SC_NUM_MINUS: PageZoomOut(); break;
|
||||
case SC_EQUAL:
|
||||
case SC_NUM_PLUS: PageZoomIn(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case evButton:
|
||||
butt = kol_btn_get();
|
||||
if(butt==1) exit(0);
|
||||
if (butt!=13) ClearSelection(); // any toolbar action but help drops selection
|
||||
if(butt==10) RunOpenApp(argv[0]);
|
||||
if(butt==11) PageZoomOut(); //magnify -
|
||||
if(butt==12) PageZoomIn(); //magnify +
|
||||
if(butt==13) //show help
|
||||
{
|
||||
kol_paint_bar(0, TOOLBAR_HEIGHT, Form.cwidth, Form.cheight - TOOLBAR_HEIGHT, 0xF2F2F2);
|
||||
kos_text(20, TOOLBAR_HEIGHT + 20 , 0x90000000, "uPDF for KolibriOS v1.2", 0);
|
||||
kos_text(21, TOOLBAR_HEIGHT + 20 , 0x90000000, "uPDF for KolibriOS v1.2", 0);
|
||||
kos_text(20, TOOLBAR_HEIGHT + 20, 0x90000000, "uPDF for KolibriOS v1.5", 0);
|
||||
kos_text(21, TOOLBAR_HEIGHT + 20, 0x90000000, "uPDF for KolibriOS v1.5", 0);
|
||||
for (ii=0; help[ii]!=0; ii++) {
|
||||
kos_text(20, TOOLBAR_HEIGHT + 60 + ii * 15, 0x80000000, help[ii], 0);
|
||||
}
|
||||
@@ -441,12 +966,11 @@ int main (int argc, char* argv[])
|
||||
case evMouse:
|
||||
if (mouse_wheels_state = kos_get_mouse_wheels())
|
||||
{
|
||||
if (mouse_wheels_state==1) { PageScrollDown(); PageScrollDown(); }
|
||||
if (mouse_wheels_state==-1) { PageScrollUp(); PageScrollUp(); }
|
||||
if (mouse_wheels_state>0) PageScroll(SCROLL_STEP);
|
||||
if (mouse_wheels_state<0) PageScroll(-SCROLL_STEP);
|
||||
}
|
||||
//sprintf (debugstr, "mouse_wheels_state: %d \n", mouse_wheels_state);
|
||||
//kol_board_puts(debugstr);
|
||||
//pdfapp_onmouse(&gapp, int x, int y, int btn, int modifiers, int state)
|
||||
ScrollbarMouse();
|
||||
if (!sb_drag) ProcessPageMouse(); // page area: select / drag
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ enum panning
|
||||
PAN_TO_BOTTOM
|
||||
};
|
||||
|
||||
void DrawPageSides(void);
|
||||
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint);
|
||||
/* pdfapp_showpage and pdfapp_renderpage are declared in pdfapp.h */
|
||||
|
||||
static void pdfapp_warn(pdfapp_t *app, const char *fmt, ...)
|
||||
{
|
||||
@@ -111,12 +110,9 @@ static void pdfapp_open_pdf(pdfapp_t *app, char *filename, int fd)
|
||||
/*
|
||||
* Open PDF and load xref table
|
||||
*/
|
||||
kol_board_puts("FZ OPEN\n");
|
||||
//file = fz_open_fd(fd);
|
||||
kol_board_puts("FZ ready\n");
|
||||
error = pdf_open_xref(&app->xref, filename, NULL);
|
||||
if (error){
|
||||
kol_board_puts("FZ can't open\n");
|
||||
pdfapp_error(app, fz_rethrow(error, "cannot open document '%s'", filename));}
|
||||
fz_close(file);
|
||||
|
||||
@@ -162,16 +158,12 @@ kol_board_puts("FZ OPEN\n");
|
||||
/*
|
||||
* Start at first page
|
||||
*/
|
||||
kol_board_puts("Start at first page\n");
|
||||
|
||||
error = pdf_load_page_tree(app->xref);
|
||||
if (error) {
|
||||
kol_board_puts("Can't load tree\n");
|
||||
pdfapp_error(app, fz_rethrow(error, "cannot load page tree"));}
|
||||
|
||||
kol_board_puts("Page counter\n");
|
||||
app->pagecount = pdf_count_pages(app->xref);
|
||||
kol_board_puts("All is set!\n");
|
||||
}
|
||||
|
||||
void pdfapp_open(pdfapp_t *app, char *filename, int fd, int reload)
|
||||
@@ -242,39 +234,13 @@ static fz_matrix pdfapp_viewctm(pdfapp_t *app)
|
||||
|
||||
static void pdfapp_panview(pdfapp_t *app, int newx, int newy)
|
||||
{
|
||||
/* vertical position is managed by the continuous scroll code in kos_main.c,
|
||||
here we only forbid negative offsets */
|
||||
if (newx < 0)
|
||||
newx = 0;
|
||||
if (newy < 0)
|
||||
newy = 0;
|
||||
|
||||
if (newx + app->image->w < app->winw)
|
||||
newx = app->winw - app->image->w;
|
||||
if (newy + app->image->h < app->winh)
|
||||
newy = app->winh - app->image->h;
|
||||
|
||||
if (app->winw >= app->image->w)
|
||||
newx = (app->winw - app->image->w) / 2;
|
||||
if (app->winh >= app->image->h)
|
||||
newy = (app->winh - app->image->h) / 2;
|
||||
|
||||
if (newx != app->panx || newy != app->pany)
|
||||
winrepaint(app);
|
||||
|
||||
if (newy > app->image->h) {
|
||||
|
||||
app->pageno++;
|
||||
|
||||
|
||||
if (app->pageno > app->pagecount)
|
||||
app->pageno = app->pagecount;
|
||||
|
||||
|
||||
newy = 0;
|
||||
app->pany = newy;
|
||||
|
||||
pdfapp_showpage(app, 1, 1, 1);
|
||||
}
|
||||
|
||||
app->panx = newx;
|
||||
app->pany = newy;
|
||||
}
|
||||
@@ -310,7 +276,92 @@ static void pdfapp_loadpage_pdf(pdfapp_t *app)
|
||||
pdf_age_store(app->xref->store, 3);
|
||||
}
|
||||
|
||||
static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint)
|
||||
/*
|
||||
* The KolibriOS blitter (syscall 73) always treats the image as 32-bit
|
||||
* BGRA, so we render in colour (n=4) and, when grayscale is requested,
|
||||
* convert each pixel to its luminance in place. Rendering into an
|
||||
* fz_device_gray pixmap instead gives a 2-channel (gray+alpha) buffer
|
||||
* that the blitter misreads - green tint and a horizontally doubled page.
|
||||
*/
|
||||
static void pdfapp_desaturate(fz_pixmap *pix)
|
||||
{
|
||||
unsigned char *p = pix->samples;
|
||||
int i, n, y;
|
||||
|
||||
if (pix->n != 4)
|
||||
return;
|
||||
|
||||
n = pix->w * pix->h;
|
||||
for (i = 0; i < n; i++, p += 4)
|
||||
{
|
||||
/* bgr order: p[0]=B, p[1]=G, p[2]=R, p[3]=A */
|
||||
y = (p[2] * 77 + p[1] * 150 + p[0] * 29) >> 8;
|
||||
p[0] = p[1] = p[2] = y;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Render any page into a fresh pixmap using the current view parameters
|
||||
* (resolution, rotation, grayscale) without touching the state of the
|
||||
* currently displayed page. Used by the continuous-scroll composer to
|
||||
* draw neighbour pages. Returns NULL on failure.
|
||||
*/
|
||||
fz_pixmap *pdfapp_renderpage(pdfapp_t *app, int pageno)
|
||||
{
|
||||
pdf_page *page;
|
||||
fz_error error;
|
||||
fz_device *dev;
|
||||
fz_display_list *list;
|
||||
fz_matrix ctm;
|
||||
fz_bbox bbox;
|
||||
fz_colorspace *colorspace;
|
||||
fz_pixmap *pix;
|
||||
|
||||
if (pageno < 1 || pageno > app->pagecount)
|
||||
return NULL;
|
||||
|
||||
error = pdf_load_page(&page, app->xref, pageno - 1);
|
||||
if (error)
|
||||
return NULL;
|
||||
|
||||
list = fz_new_display_list();
|
||||
dev = fz_new_list_device(list);
|
||||
error = pdf_run_page(app->xref, page, dev, fz_identity);
|
||||
fz_free_device(dev);
|
||||
if (error)
|
||||
{
|
||||
fz_free_display_list(list);
|
||||
pdf_free_page(page);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* same transform as pdfapp_viewctm, but for this page's box and rotation */
|
||||
ctm = fz_identity;
|
||||
ctm = fz_concat(ctm, fz_translate(0, -page->mediabox.y1));
|
||||
ctm = fz_concat(ctm, fz_scale(app->resolution/72.0f, -app->resolution/72.0f));
|
||||
ctm = fz_concat(ctm, fz_rotate(app->rotate + page->rotate));
|
||||
bbox = fz_round_rect(fz_transform_rect(ctm, page->mediabox));
|
||||
|
||||
/* always render 32-bit BGRA for the blitter, then desaturate if needed */
|
||||
colorspace = fz_device_bgr;
|
||||
|
||||
pix = fz_new_pixmap_with_rect(colorspace, bbox);
|
||||
fz_clear_pixmap_with_color(pix, 255);
|
||||
dev = fz_new_draw_device(app->cache, pix);
|
||||
fz_execute_display_list(list, dev, ctm, bbox);
|
||||
fz_free_device(dev);
|
||||
|
||||
if (app->grayscale)
|
||||
pdfapp_desaturate(pix);
|
||||
|
||||
fz_free_display_list(list);
|
||||
pdf_free_page(page);
|
||||
pdf_age_store(app->xref->store, 3);
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint)
|
||||
{
|
||||
char buf[256];
|
||||
fz_device *idev;
|
||||
@@ -356,23 +407,17 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
|
||||
/* Draw */
|
||||
if (app->image)
|
||||
fz_drop_pixmap(app->image);
|
||||
if (app->grayscale)
|
||||
colorspace = fz_device_gray;
|
||||
else
|
||||
/*
|
||||
#ifdef _WIN32
|
||||
colorspace = fz_device_bgr;
|
||||
#else
|
||||
colorspace = fz_device_rgb;
|
||||
#endif
|
||||
*/
|
||||
colorspace = fz_device_bgr;
|
||||
|
||||
/* always render 32-bit BGRA for the blitter, then desaturate if needed */
|
||||
colorspace = fz_device_bgr;
|
||||
|
||||
app->image = fz_new_pixmap_with_rect(colorspace, bbox);
|
||||
fz_clear_pixmap_with_color(app->image, 255);
|
||||
idev = fz_new_draw_device(app->cache, app->image);
|
||||
fz_execute_display_list(app->page_list, idev, ctm, bbox);
|
||||
fz_free_device(idev);
|
||||
|
||||
if (app->grayscale)
|
||||
pdfapp_desaturate(app->image);
|
||||
}
|
||||
|
||||
if (repaint)
|
||||
@@ -381,7 +426,6 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
|
||||
|
||||
if (app->shrinkwrap)
|
||||
{
|
||||
kol_board_puts ("SHRINK\n");
|
||||
int w = app->image->w;
|
||||
int h = app->image->h;
|
||||
if (app->winw == w)
|
||||
@@ -402,8 +446,6 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
|
||||
}
|
||||
|
||||
fz_flush_warnings();
|
||||
|
||||
DrawPageSides();
|
||||
}
|
||||
|
||||
static void pdfapp_gotouri(pdfapp_t *app, fz_obj *uri)
|
||||
@@ -484,6 +526,35 @@ void pdfapp_inverthit(pdfapp_t *app)
|
||||
pdfapp_invert(app, fz_transform_bbox(ctm, hitbox));
|
||||
}
|
||||
|
||||
/*
|
||||
* Invert on screen every character whose box lies inside app->selr
|
||||
* (device coordinates). Inversion is its own inverse, so calling this
|
||||
* twice with the same selr restores the original pixels - the caller
|
||||
* uses that to move/clear the highlight without re-rendering the page.
|
||||
*/
|
||||
void pdfapp_invertselection(pdfapp_t *app)
|
||||
{
|
||||
fz_bbox hitbox;
|
||||
fz_matrix ctm;
|
||||
fz_text_span *span;
|
||||
int i;
|
||||
int x0 = app->selr.x0, x1 = app->selr.x1;
|
||||
int y0 = app->selr.y0, y1 = app->selr.y1;
|
||||
|
||||
if (!app->image || !app->page_text)
|
||||
return;
|
||||
|
||||
ctm = pdfapp_viewctm(app);
|
||||
for (span = app->page_text; span; span = span->next)
|
||||
for (i = 0; i < span->len; i++)
|
||||
{
|
||||
hitbox = fz_transform_bbox(ctm, span->text[i].bbox);
|
||||
if (hitbox.x1 >= x0 && hitbox.x0 <= x1 &&
|
||||
hitbox.y1 >= y0 && hitbox.y0 <= y1)
|
||||
pdfapp_invert(app, hitbox);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int charat(fz_text_span *span, int idx)
|
||||
{
|
||||
int ofs = 0;
|
||||
|
||||
@@ -95,6 +95,9 @@ void pdfapp_close(pdfapp_t *app);
|
||||
char *pdfapp_version(pdfapp_t *app);
|
||||
char *pdfapp_usage(pdfapp_t *app);
|
||||
|
||||
void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repaint);
|
||||
fz_pixmap *pdfapp_renderpage(pdfapp_t *app, int pageno);
|
||||
|
||||
void pdfapp_onkey(pdfapp_t *app, int c);
|
||||
void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state);
|
||||
void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen);
|
||||
@@ -102,3 +105,4 @@ void pdfapp_onresize(pdfapp_t *app, int w, int h);
|
||||
|
||||
void pdfapp_invert(pdfapp_t *app, fz_bbox rect);
|
||||
void pdfapp_inverthit(pdfapp_t *app);
|
||||
void pdfapp_invertselection(pdfapp_t *app);
|
||||
|
||||
@@ -1,29 +1,81 @@
|
||||
# BUILD ONLY LIBRARIES
|
||||
#!/bin/bash
|
||||
# Build uPDF for KolibriOS: third-party libs from the SDK, the MuPDF
|
||||
# libraries (fitz, pdf, draw) and the application itself.
|
||||
# Needs only the kos32-gcc toolchain, no make.
|
||||
#
|
||||
# Usage: ./build_libs.sh - build missing libraries, then the app
|
||||
# ./build_libs.sh all - force-rebuild everything
|
||||
|
||||
mkdir lib
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
SDK=$(cd ../../sdk && pwd)
|
||||
|
||||
cd SYSCALL/src
|
||||
make
|
||||
cd ../..
|
||||
# locate the kos32 toolchain
|
||||
if ! command -v kos32-gcc >/dev/null 2>&1; then
|
||||
for p in /home/autobuild/tools/win32/bin \
|
||||
/c/MinGW/msys/1.0/home/autobuild/tools/win32/bin; do
|
||||
if [ -x "$p/kos32-gcc" ] || [ -x "$p/kos32-gcc.exe" ]; then
|
||||
export PATH="$p:$PATH"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
command -v kos32-gcc >/dev/null 2>&1 || { echo "error: kos32-gcc not found"; exit 1; }
|
||||
TOOLLIB="$(dirname "$(command -v kos32-gcc)")/../lib"
|
||||
|
||||
cd fitz
|
||||
make
|
||||
cd ..
|
||||
CFLAGS="-c -fno-ident -O2 -fomit-frame-pointer -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32"
|
||||
NEWLIB_INC="-I $SDK/sources/newlib/libc/include"
|
||||
|
||||
cd pdf
|
||||
make
|
||||
cd ..
|
||||
FORCE=0
|
||||
[ "$1" = "all" ] && FORCE=1
|
||||
|
||||
cd libopenjpeg
|
||||
make
|
||||
cd ..
|
||||
build_lib() { # <src dir> <lib name> <dest dir> <cflags...>
|
||||
local dir="$1" lib="$2" dest="$3"
|
||||
shift 3
|
||||
if [ $FORCE = 0 ] && [ -f "$dest/$lib" ]; then
|
||||
echo "skip $lib (already in $dest)"
|
||||
return
|
||||
fi
|
||||
echo "building $lib..."
|
||||
( cd "$dir"
|
||||
rm -f *.o
|
||||
for f in *.c; do
|
||||
kos32-gcc $CFLAGS "$@" -o "${f%.c}.o" "$f"
|
||||
done
|
||||
kos32-ar rcs "$lib" *.o
|
||||
rm -f *.o
|
||||
mkdir -p "$dest"
|
||||
mv -f "$lib" "$dest/" )
|
||||
}
|
||||
|
||||
cd libjbig2dec
|
||||
make
|
||||
cd ..
|
||||
build_lib "$SDK/sources/libjbig2dec" libjbig2dec.a "$SDK/lib" \
|
||||
-DHAVE_CONFIG_H $NEWLIB_INC -I "$SDK/sources/freetype/include" \
|
||||
-I "$SDK/sources/libpng" -I "$SDK/sources/zlib" -I .
|
||||
|
||||
cd draw
|
||||
make
|
||||
cd ..
|
||||
build_lib "$SDK/sources/libopenjpeg" libopenjpeg.a "$SDK/lib" \
|
||||
$NEWLIB_INC -I "$SDK/sources/freetype/include" -I "$SDK/sources/zlib" -I .
|
||||
|
||||
sleep 100
|
||||
build_lib fitz libfitz.a "$PWD/lib" \
|
||||
$NEWLIB_INC -I "$SDK/sources/freetype/include" -I "$SDK/sources/libjpeg" \
|
||||
-I "$SDK/sources/zlib" -I "$SDK/sources/libopenjpeg" -I "$SDK/sources/libjbig2dec"
|
||||
|
||||
build_lib pdf libmupdf.a "$PWD/lib" \
|
||||
$NEWLIB_INC -I "$PWD/fitz" -I "$SDK/sources/freetype/include"
|
||||
|
||||
build_lib draw libdraw.a "$PWD/lib" \
|
||||
$NEWLIB_INC -I "$PWD/fitz"
|
||||
|
||||
echo "building updf..."
|
||||
cd apps
|
||||
rm -f *.o updf
|
||||
for f in kolibri.c kos_main.c pdfapp.c; do
|
||||
kos32-gcc $CFLAGS $NEWLIB_INC -I "$SDK/sources/freetype/include" \
|
||||
-I "$SDK/sources/zlib" -I ../fitz -I ../pdf -o "${f%.c}.o" "$f"
|
||||
done
|
||||
kos32-ld -static -nostdlib -T "$SDK/sources/newlib/app.lds" --image-base 0 \
|
||||
-L "$SDK/lib" -L "$TOOLLIB" -L ../lib --subsystem native \
|
||||
-o updf kolibri.o pdfapp.o kos_main.o \
|
||||
-lmupdf -lfitz -lgcc -lfitz -ldraw -ljpeg -ljbig2dec -lfreetype -lopenjpeg -lz.dll -lc.dll
|
||||
kos32-objcopy updf -O binary
|
||||
rm -f *.o
|
||||
echo "done: apps/updf"
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user