ref: d9657f82748a397eed451a4cfd0bbc6f19551488
parent: d02a0b77666d94bc97bbf0412b3cbefeff12c462
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Thu Sep 15 16:59:31 EDT 2011
replaceing page with npage
--- a/sys/man/1/page
+++ b/sys/man/1/page
@@ -80,27 +80,6 @@
.B -r
option reverses the order in which pages are displayed.
.PP
-When viewing a document,
-.I page
-will try to guess the true bounding box, usually rounding up from
-the file's bounding box to
-8½×11 or A4 size.
-The
-.B -b
-option causes it to respect the bounding box given in the file.
-As a more general problem,
-some PostScript files claim to conform to Adobe's
-Document Structuring Conventions but do not.
-The
-.B -P
-option enables a slightly slower and slightly more
-skeptical version of the PostScript processing code.
-Unfortunately, there are PostScript documents
-that can only be viewed with the
-.B -P
-option, and there are PostScript documents that
-can only be viewed without it.
-.PP
When viewing images with
.IR page ,
it listens to the
@@ -117,21 +96,6 @@
from standard input but rather to listen
for ones to load from the plumbing channel.
.PP
-The
-.B -v
-option turns on extra debugging output, and
-the
-.B -V
-option turns on even more debugging output.
-The
-.B -a
-option causes
-.I page
-to call
-.IR abort (2)
-rather than exit cleanly on errors,
-to facilitate debugging.
-.PP
Pressing and holding button 1 permits panning about the page.
.PP
Button 2 raises a menu of operations on the current image or the
@@ -145,10 +109,9 @@
Restores the image to the original. All modifications are lost.
.TP
.B Zoom
-Prompts the user to sweep a rectangle on the image which is
-expanded proportionally to the rectangle.
+controls magnification.
.TP
-.B Fit window
+.B Fit
Resizes the image so that it fits in the current window.
.TP
.B Rotate 90
@@ -166,12 +129,6 @@
.B Zerox
Displays the current image in a new page window.
Useful for selecting important pages from large documents.
-.TP
-.B Reverse
-Reverses the order in which pages are displayed.
-.TP
-.B Write
-Writes the image to file.
.PD
.PP
Button 3 raises a menu of the
@@ -182,23 +139,6 @@
.B q
or
control-D exits the program.
-Typing a
-.B u
-toggles whether images are displayed upside-down.
-(This is useful in the common case of mistransmitted upside-down faxes).
-Typing a
-.B r
-reverses the order in which pages are displayed.
-Typing a
-.B w
-will write the currently viewed page to a new file as a compressed
-.IR image (6)
-file.
-When possible, the filename is of the form
-.IR basename . pagenum . bit .
-Typing a
-.B d
-removes an image from the working set.
.PP
To go to a specific page, one can type its number followed by enter.
Typing left arrow, backspace, or minus displays the previous page.
@@ -238,34 +178,7 @@
.IR troff (1)
.SH SOURCE
.B /sys/src/cmd/page
-.SH DIAGNOSTICS
-The mouse cursor changes to an arrow and ellipsis
-when
-.I page
-is reading or writing a file.
.SH BUGS
-.I Page
-supports reading of only one document
-file at a time, and
-the user interface is clumsy when viewing very large documents.
-.PP
-When viewing multipage PostScript files that do not contain
-.RB `` %%Page ''
-comments, the button 3 menu only contains
-``this page'' and ``next page'':
-correctly determining
-page boundaries in Postscript code is not computable
-in the general case.
-.PP
-If
-.I page
-has trouble viewing a Postscript file,
-it might not be exactly conforming: try viewing it with the
-.B -P
-option.
-.PP
The interface to the plumber is unsatisfactory. In particular,
document references cannot be sent
via plumbing messages.
-.PP
-There are too many keyboard commands.
--- a/sys/src/cmd/npage.c
+++ /dev/null
@@ -1,1246 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <cursor.h>
-#include <keyboard.h>
-#include <plumb.h>
-
-typedef struct Page Page;
-struct Page {
- char *label;
-
- QLock;
- void *data;
- int (*open)(Page *);
-
- char *text;
- Image *image;
- int fd;
- int gen;
-
- Page *up;
- Page *next;
- Page *down;
- Page *tail;
-};
-
-int zoom = 1;
-int ppi = 100;
-int imode;
-int newwin;
-int rotate;
-int viewgen;
-int pagegen;
-Point resize, pos;
-Page *root, *current;
-QLock pagelock;
-int nullfd;
-
-char pagespool[] = "/tmp/pagespool.";
-
-enum {
- NPROC = 4,
- NAHEAD = 2,
- NBUF = 8*1024,
- NPATH = 1024,
-};
-
-char *pagemenugen(int i);
-
-char *menuitems[] = {
- "orig size",
- "rotate 90",
- "upside down",
- "",
- "fit width",
- "fit height",
- "",
- "zoom in",
- "zoom out",
- "",
- "next",
- "prev",
- "zerox",
- "",
- "quit",
- nil
-};
-
-Menu pagemenu = {
- nil,
- pagemenugen,
- -1,
-};
-
-Menu menu = {
- menuitems,
- nil,
- -1,
-};
-
-Cursor reading = {
- {-1, -1},
- {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00,
- 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0,
- 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0,
- 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },
- {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00,
- 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0,
- 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40,
- 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }
-};
-
-void showpage(Page *);
-void drawpage(Page *);
-Point pagesize(Page *);
-
-Page*
-addpage(Page *up, char *label, int (*popen)(Page *), void *pdata, int fd)
-{
- Page *p;
-
- p = mallocz(sizeof(*p), 1);
- p->label = strdup(label);
- p->gen = pagegen;
- p->text = nil;
- p->image = nil;
- p->data = pdata;
- p->open = popen;
- p->fd = fd;
-
- p->down = nil;
- p->tail = nil;
- p->next = nil;
-
- qlock(&pagelock);
- if(p->up = up){
- if(up->tail == nil)
- up->down = up->tail = p;
- else {
- up->tail->next = p;
- up->tail = p;
- }
- }
- qunlock(&pagelock);
-
- if(up && current == up)
- showpage(p);
- return p;
-}
-
-void
-resizewin(Point size)
-{
- int wctl;
-
- if((wctl = open("/dev/wctl", OWRITE)) < 0)
- return;
- /* add rio border */
- size = addpt(size, Pt(Borderwidth*2, Borderwidth*2));
- fprint(wctl, "resize -dx %d -dy %d\n", size.x, size.y);
- close(wctl);
-}
-
-int
-createtmp(ulong id, char *pfx)
-{
- char nam[64];
-
- snprint(nam, sizeof nam, "%s%s%.12d%.8lux", pagespool, pfx, getpid(), id ^ 0xcafebabe);
- return create(nam, OEXCL|ORCLOSE|ORDWR, 0600);
-}
-
-int
-catchnote(void *, char *msg)
-{
- if(strstr(msg, "sys: write on closed pipe"))
- return 1;
- if(strstr(msg, "hangup"))
- return 1;
- if(strstr(msg, "alarm"))
- return 1;
- return 0;
-}
-
-void
-pipeline(int fd, char *fmt, ...)
-{
- char buf[128], *argv[4];
- va_list arg;
- int pfd[2];
-
- if(pipe(pfd) < 0){
- Err:
- dup(nullfd, fd);
- return;
- }
- switch(rfork(RFPROC|RFFDG|RFREND|RFNOWAIT)){
- case -1:
- close(pfd[0]);
- close(pfd[1]);
- goto Err;
- case 0:
- if(dup(fd, 0)<0)
- exits("dup");
- if(dup(pfd[1], 1)<0)
- exits("dup");
- close(fd);
- close(pfd[1]);
- close(pfd[0]);
- va_start(arg, fmt);
- vsnprint(buf, sizeof buf, fmt, arg);
- va_end(arg);
-
- argv[0] = "rc";
- argv[1] = "-c";
- argv[2] = buf;
- argv[3] = nil;
- exec("/bin/rc", argv);
- sysfatal("exec: %r");
- }
- close(pfd[1]);
- dup(pfd[0], fd);
- close(pfd[0]);
-}
-
-int
-popenfile(Page*);
-
-int
-popenconv(Page *p)
-{
- char nam[NPATH];
- int fd;
-
- if((fd = dup(p->fd, -1)) < 0){
- close(p->fd);
- p->fd = -1;
- return -1;
- }
-
- seek(fd, 0, 0);
- if(p->data)
- pipeline(fd, "%s", (char*)p->data);
-
- /*
- * dont keep the file descriptor arround if it can simply
- * be reopened.
- */
- fd2path(p->fd, nam, sizeof(nam));
- if(strncmp(nam, pagespool, strlen(pagespool))){
- close(p->fd);
- p->fd = -1;
- p->data = strdup(nam);
- p->open = popenfile;
- }
-
- return fd;
-}
-
-typedef struct Ghost Ghost;
-struct Ghost
-{
- QLock;
-
- int pin;
- int pout;
- int pdat;
-};
-
-int
-popenpdf(Page *p)
-{
- char buf[NBUF];
- int n, pfd[2];
- Ghost *gs;
-
- if(pipe(pfd) < 0)
- return -1;
- switch(rfork(RFFDG|RFPROC|RFMEM|RFNOWAIT)){
- case -1:
- close(pfd[0]);
- close(pfd[1]);
- return -1;
- case 0:
- close(pfd[0]);
- gs = p->data;
- qlock(gs);
- fprint(gs->pin, "%s DoPDFPage\n"
- "(/fd/3) (w) file "
- "dup flushfile "
- "dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring "
- "flushfile\n", p->label);
- while((n = read(gs->pdat, buf, sizeof buf)) > 0){
- if(memcmp(buf, "THIS IS NOT AN INFERNO BITMAP\n", 30) == 0)
- break;
- if(pfd[1] < 0)
- continue;
- if(write(pfd[1], buf, n) != n){
- close(pfd[1]);
- pfd[1]=-1;
- }
- }
- qunlock(gs);
- exits(nil);
- }
- close(pfd[1]);
- return pfd[0];
-}
-
-int
-infernobithdr(char *buf, int n)
-{
- if(n >= 11){
- if(memcmp(buf, "compressed\n", 11) == 0)
- return 1;
- if(strtochan((char*)buf))
- return 1;
- if(memcmp(buf, " ", 10) == 0 &&
- '0' <= buf[10] && buf[10] <= '9' &&
- buf[11] == ' ')
- return 1;
- }
- return 0;
-}
-
-int
-popengs(Page *p)
-{
- int n, i, pdf, ifd, ofd, pin[2], pout[2], pdat[2];
- char buf[NBUF], nam[32], *argv[16];
-
- pdf = 0;
- ifd = p->fd;
- p->fd = -1;
- seek(ifd, 0, 0);
- if(read(ifd, buf, 5) != 5)
- goto Err0;
- seek(ifd, 0, 0);
- if(memcmp(buf, "%PDF-", 5) == 0)
- pdf = 1;
- p->text = strdup(p->label);
- if(pipe(pin) < 0){
- Err0:
- close(ifd);
- return -1;
- }
- if(pipe(pout) < 0){
- Err1:
- close(pin[0]);
- close(pin[1]);
- goto Err0;
- }
- if(pipe(pdat) < 0){
- Err2:
- close(pdat[0]);
- close(pdat[1]);
- goto Err1;
- }
-
- switch(rfork(RFREND|RFPROC|RFFDG|RFNOWAIT)){
- case -1:
- goto Err2;
- case 0:
- if(pdf){
- if(dup(pin[1], 0)<0)
- exits("dup");
- if(dup(pout[1], 1)<0)
- exits("dup");
- } else {
- if(dup(nullfd, 0)<0)
- exits("dup");
- if(dup(nullfd, 1)<0)
- exits("dup");
- }
- if(dup(nullfd, 2)<0)
- exits("dup");
- if(dup(pdat[1], 3)<0)
- exits("dup");
- if(dup(ifd, 4)<0)
- exits("dup");
-
- close(pin[0]);
- close(pin[1]);
- close(pout[0]);
- close(pout[1]);
- close(pdat[0]);
- close(pdat[1]);
- close(ifd);
-
- if(p->data)
- pipeline(4, "%s", (char*)p->data);
-
- argv[0] = "gs";
- argv[1] = "-q";
- argv[2] = "-sDEVICE=plan9";
- argv[3] = "-sOutputFile=/fd/3";
- argv[4] = "-dBATCH";
- argv[5] = pdf ? "-dDELAYSAFER" : "-dSAFER";
- argv[6] = "-dQUIET";
- argv[7] = "-dTextAlphaBits=4";
- argv[8] = "-dGraphicsAlphaBits=4";
- snprint(buf, sizeof buf, "-r%d", ppi);
- argv[9] = buf;
- argv[10] = "-dDOINTERPOLATE";
- argv[11] = pdf ? "-" : "/fd/4";
- argv[12] = nil;
- exec("/bin/gs", argv);
- sysfatal("exec: %r");
- }
-
- close(pin[1]);
- close(pout[1]);
- close(pdat[1]);
- close(ifd);
-
- if(pdf){
- Ghost *gs;
- char *prolog =
- "/PAGEOUT (/fd/1) (w) file def\n"
- "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n"
- "\n"
- "/Page null def\n"
- "/Page# 0 def\n"
- "/PDFSave null def\n"
- "/DSCPageCount 0 def\n"
- "/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def\n"
- "\n"
- "GS_PDF_ProcSet begin\n"
- "pdfdict begin\n"
- "(/fd/4) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n"
- "\n"
- "pdfpagecount PAGE==\n";
-
- n = strlen(prolog);
- if(write(pin[0], prolog, n) != n)
- goto Out;
- if((n = read(pout[0], buf, sizeof(buf)-1)) < 0)
- goto Out;
- buf[n] = 0;
- n = atoi(buf);
- if(n <= 0){
- werrstr("no pages");
- goto Out;
- }
- gs = mallocz(sizeof(*gs), 1);
- gs->pin = pin[0];
- gs->pout = pout[0];
- gs->pdat = pdat[0];
- for(i=1; i<=n; i++){
- snprint(nam, sizeof nam, "%d", i);
- addpage(p, nam, popenpdf, gs, -1);
- }
-
- /* keep ghostscript arround */
- return -1;
- } else {
- i = 0;
- ofd = -1;
- while((n = read(pdat[0], buf, sizeof(buf))) >= 0){
- if(ofd >= 0 && (n <= 0 || infernobithdr(buf, n))){
- snprint(nam, sizeof nam, "%d", i);
- addpage(p, nam, popenconv, nil, ofd);
- ofd = -1;
- }
- if(n <= 0)
- break;
- if(ofd < 0){
- snprint(nam, sizeof nam, "%.4d", ++i);
- if((ofd = createtmp((ulong)p, nam)) < 0)
- ofd = dup(nullfd, -1);
- }
- if(write(ofd, buf, n) != n)
- break;
- }
- if(ofd >= 0)
- close(ofd);
- }
-Out:
- close(pin[0]);
- close(pout[0]);
- close(pdat[0]);
- return -1;
-}
-
-int
-popenfile(Page *p)
-{
- char buf[NBUF], *file;
- int i, n, fd, tfd;
- Dir *d;
-
- fd = p->fd;
- p->fd = -1;
- file = p->data;
- if(fd < 0){
- if((fd = open(file, OREAD)) < 0){
- Err0:
- p->data = nil;
- free(file);
- return -1;
- }
- }
- seek(fd, 0, 0);
- if((d = dirfstat(fd)) == nil){
- Err1:
- close(fd);
- goto Err0;
- }
- if(d->mode & DMDIR){
- free(d);
- d = nil;
- if((n = dirreadall(fd, &d)) < 0)
- goto Err1;
- for(i = 0; i<n; i++)
- addpage(p, d[i].name, popenfile, smprint("%s/%s", file, d[i].name), -1);
- free(d);
- p->text = strdup(p->label);
- goto Err1;
- }
- free(d);
-
- memset(buf, 0, 32+1);
- if((n = read(fd, buf, 32)) <= 0)
- goto Err1;
-
- p->fd = fd;
- p->data = nil;
- p->open = popenconv;
- if(memcmp(buf, "%PDF-", 5) == 0 || strstr(buf, "%!"))
- p->open = popengs;
- else if(memcmp(buf, "x T ", 4) == 0){
- p->data = "lp -dstdout";
- p->open = popengs;
- }
- else if(memcmp(buf, "\xF7\x02\x01\x83\x92\xC0\x1C;", 8) == 0){
- p->data = "dvips -Pps -r0 -q1 -f1";
- p->open = popengs;
- }
- else if(memcmp(buf, "\x1F\x8B", 2) == 0){
- p->data = "gunzip";
- p->open = popengs;
- }
- else if(memcmp(buf, "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", 8) == 0){
- p->data = "doc2ps";
- p->open = popengs;
- }
- else if(memcmp(buf, "GIF", 3) == 0)
- p->data = "gif -t9";
- else if(memcmp(buf, "\111\111\052\000", 4) == 0)
- p->data = "fb/tiff2pic | fb/3to1 rgbv | fb/pcp -tplan9";
- else if(memcmp(buf, "\115\115\000\052", 4) == 0)
- p->data = "fb/tiff2pic | fb/3to1 rgbv | fb/pcp -tplan9";
- else if(memcmp(buf, "\377\330\377", 3) == 0)
- p->data = "jpg -t9";
- else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0)
- p->data = "png -t9";
- else if(memcmp(buf, "\0PC Research, Inc", 17) == 0)
- p->data = "aux/g3p9bit -g";
- else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0)
- p->data = "aux/g3p9bit -g";
- else if(memcmp(buf, "II*", 3) == 0)
- p->data = "aux/g3p9bit -g";
- else if(memcmp(buf, "TYPE=", 5) == 0)
- p->data = "fb/3to1 rgbv |fb/pcp -tplan9";
- else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9')
- p->data = "ppm -t9";
- else if(memcmp(buf, "BM", 2) == 0)
- p->data = "bmp -t9";
- else if(infernobithdr(buf, n))
- p->data = nil;
- else {
- werrstr("unknown image format");
- goto Err1;
- }
-
- if(seek(fd, 0, 0) < 0)
- goto Noseek;
- if((i = read(fd, buf+n, n)) < 0)
- goto Err1;
- if(i != n || memcmp(buf, buf+n, i)){
- n += i;
- Noseek:
- if((tfd = createtmp((ulong)p, "file")) < 0)
- goto Err1;
- while(n > 0){
- if(write(tfd, buf, n) != n)
- goto Err2;
- if((n = read(fd, buf, sizeof(buf))) < 0)
- goto Err2;
- }
- if(dup(tfd, fd) < 0){
- Err2:
- close(tfd);
- goto Err1;
- }
- close(tfd);
- }
- free(file);
- return p->open(p);
-}
-
-Page*
-nextpage(Page *p)
-{
- if(p){
- if(p->down)
- return p->down;
- if(p->next)
- return p->next;
- if(p->up)
- return p->up->next;
- }
- return nil;
-}
-
-Page*
-prevpage(Page *x)
-{
- Page *p, *t;
-
- if(x){
- for(p = root->down; p; p = t)
- if((t = nextpage(p)) == x)
- return p;
- }
- return nil;
-}
-
-int
-openpage(Page *p)
-{
- int fd;
-
- fd = -1;
- if(p->open == nil || (fd = p->open(p)) < 0)
- p->open = nil;
- else {
- if(rotate)
- pipeline(fd, "rotate -r %d", rotate);
- if(resize.x)
- pipeline(fd, "resize -x %d", resize.x);
- else if(resize.y)
- pipeline(fd, "resize -y %d", resize.y);
- }
- return fd;
-}
-
-void
-loadpage(Page *p)
-{
- int fd;
-
- if(p->open && p->image == nil && p->text == nil){
- if((fd = openpage(p)) >= 0){
- pagegen++;
- p->image = readimage(display, fd, 1);
- close(fd);
- }
- if(p->image == nil && p->text == nil)
- p->text = smprint("%s: %r", p->label);
- }
- p->gen = pagegen;
-}
-
-void
-unloadpage(Page *p)
-{
- if(p->open){
- if(p->text)
- free(p->text);
- p->text = nil;
- if(p->image){
- lockdisplay(display);
- freeimage(p->image);
- unlockdisplay(display);
- }
- p->image = nil;
- }
-}
-
-void
-unloadpages(int age)
-{
- Page *p;
-
- for(p = root->down; p; p = nextpage(p)){
- if(age == 0) /* synchronous flush */
- qlock(p);
- else if(!canqlock(p))
- continue;
- if((pagegen - p->gen) >= age)
- unloadpage(p);
- qunlock(p);
- }
-}
-
-void
-loadpages(Page *p, int ahead, int oviewgen)
-{
- int i;
-
- ahead++; /* load at least one */
- unloadpages(ahead*2);
- for(i = 0; i < ahead && p; p = nextpage(p), i++){
- if(viewgen != oviewgen)
- break;
- if(canqlock(p)){
- loadpage(p);
- if(viewgen != oviewgen){
- unloadpage(p);
- qunlock(p);
- break;
- }
- if(p == current){
- Point size;
-
- esetcursor(nil);
- size = pagesize(p);
- if(size.x && size.y && newwin){
- newwin = 0;
- resizewin(size);
- }
- lockdisplay(display);
- drawpage(p);
- unlockdisplay(display);
- }
- qunlock(p);
- }
- }
-}
-
-/*
- * A draw operation that touches only the area contained in bot but not in top.
- * mp and sp get aligned with bot.min.
- */
-static void
-gendrawdiff(Image *dst, Rectangle bot, Rectangle top,
- Image *src, Point sp, Image *mask, Point mp, int op)
-{
- Rectangle r;
- Point origin;
- Point delta;
-
- USED(op);
-
- if(Dx(bot)*Dy(bot) == 0)
- return;
-
- /* no points in bot - top */
- if(rectinrect(bot, top))
- return;
-
- /* bot - top ≡ bot */
- if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){
- gendrawop(dst, bot, src, sp, mask, mp, op);
- return;
- }
-
- origin = bot.min;
- /* split bot into rectangles that don't intersect top */
- /* left side */
- if(bot.min.x < top.min.x){
- r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.min.x = top.min.x;
- }
-
- /* right side */
- if(bot.max.x > top.max.x){
- r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.max.x = top.max.x;
- }
-
- /* top */
- if(bot.min.y < top.min.y){
- r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.min.y = top.min.y;
- }
-
- /* bottom */
- if(bot.max.y > top.max.y){
- r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.max.y = top.max.y;
- }
-}
-
-void
-zoomdraw(Image *d, Rectangle r, Rectangle top, Image *s, Point sp, int f)
-{
- int w, x, y;
- Image *t;
- Point a;
-
- if(f <= 1){
- gendrawdiff(d, r, top, s, sp, nil, ZP, S);
- return;
- }
- a = ZP;
- if(r.min.x < d->r.min.x){
- sp.x += (d->r.min.x - r.min.x)/f;
- a.x = (d->r.min.x - r.min.x)%f;
- r.min.x = d->r.min.x;
- }
- if(r.min.y < d->r.min.y){
- sp.y += (d->r.min.y - r.min.y)/f;
- a.y = (d->r.min.y - r.min.y)%f;
- r.min.y = d->r.min.y;
- }
- rectclip(&r, d->r);
- w = s->r.max.x - sp.x;
- if(w > Dx(r))
- w = Dx(r);
- t = allocimage(display, Rect(r.min.x, r.min.y, r.min.x+w, r.max.y), s->chan, 0, DNofill);
- if(t == nil)
- return;
- for(y=r.min.y; y<r.max.y; y++){
- draw(t, Rect(r.min.x, y, r.min.x+w, y+1), s, nil, sp);
- if(++a.y == zoom){
- a.y = 0;
- sp.y++;
- }
- }
- sp = r.min;
- for(x=r.min.x; x<r.max.x; x++){
- gendrawdiff(d, Rect(x, r.min.y, x+1, r.max.y), top, t, sp, nil, ZP, S);
- if(++a.x == f){
- a.x = 0;
- sp.x++;
- }
- }
- freeimage(t);
-}
-
-Point
-pagesize(Page *p)
-{
- return p->image ? mulpt(subpt(p->image->r.max, p->image->r.min), zoom) : ZP;
-}
-
-void
-drawpage(Page *p)
-{
- Rectangle r;
- Image *i;
-
- if((i = p->image) == nil){
- char *s;
-
- if((s = p->text) == nil)
- s = "...";
- r.min = ZP;
- r.max = stringsize(font, p->text);
- r = rectaddpt(r, addpt(subpt(divpt(subpt(screen->r.max, screen->r.min), 2), divpt(r.max, 2)),
- screen->r.min));
- draw(screen, r, display->white, nil, ZP);
- string(screen, r.min, display->black, ZP, font, s);
- } else {
- r = rectaddpt(Rpt(ZP, pagesize(p)), addpt(pos, screen->r.min));
- zoomdraw(screen, r, ZR, i, i->r.min, zoom);
- }
- gendrawdiff(screen, screen->r, r, display->white, ZP, nil, ZP, S);
- border(screen, r, -Borderwidth, display->black, ZP);
- flushimage(display, 1);
-}
-
-void
-translate(Page *p, Point d)
-{
- Rectangle r, or, nr;
- Image *i;
-
- i = p->image;
- if((i==0) || (d.x==0 && d.y==0))
- return;
- r = rectaddpt(Rpt(ZP, pagesize(p)), addpt(pos, screen->r.min));
- pos = addpt(pos, d);
- nr = rectaddpt(r, d);
- or = r;
- rectclip(&or, screen->r);
- draw(screen, rectaddpt(or, d), screen, nil, or.min);
- zoomdraw(screen, nr, rectaddpt(or, d), i, i->r.min, zoom);
- gendrawdiff(screen, screen->r, nr, display->white, ZP, nil, ZP, S);
- border(screen, nr, -Borderwidth, display->black, ZP);
- flushimage(display, 1);
-}
-
-Page*
-pageat(int i)
-{
- Page *p;
-
- for(p = root->down; i > 0 && p; p = nextpage(p))
- i--;
- return i ? nil : p;
-}
-
-int
-pageindex(Page *x)
-{
- Page *p;
- int i;
-
- for(i = 0, p = root->down; p && p != x; p = nextpage(p))
- i++;
- return (p == x) ? i : -1;
-}
-
-char*
-pagemenugen(int i)
-{
- Page *p;
- if(p = pageat(i))
- return p->label;
- return nil;
-}
-
-void
-showpage(Page *p)
-{
- static int nproc;
- int oviewgen;
-
- if(p == nil)
- return;
- esetcursor(&reading);
- current = p;
- oviewgen = viewgen;
- if(++nproc > NPROC)
- if(waitpid() > 0)
- nproc--;
- switch(rfork(RFPROC|RFMEM)){
- case -1:
- sysfatal("rfork: %r");
- case 0:
- loadpages(p, NAHEAD, oviewgen);
- exits(nil);
- }
-}
-
-void
-zerox(Page *p)
-{
- char nam[64], *argv[4];
- int fd;
-
- if(p == nil)
- return;
- esetcursor(&reading);
- qlock(p);
- if((fd = openpage(p)) < 0)
- goto Out;
- if(rfork(RFREND|RFFDG|RFPROC|RFENVG|RFNOTEG|RFNOWAIT) == 0){
- dup(fd, 0);
- close(fd);
-
- snprint(nam, sizeof nam, "/bin/%s", argv0);
- argv[0] = argv0;
- argv[1] = "-w";
- argv[2] = nil;
- exec(nam, argv);
- sysfatal("exec: %r");
- }
- close(fd);
-Out:
- qunlock(p);
- esetcursor(nil);
-}
-
-void
-eresized(int new)
-{
- Page *p;
-
- lockdisplay(display);
- if(new && getwindow(display, Refnone) == -1)
- sysfatal("getwindow: %r");
- if(p = current){
- if(canqlock(p)){
- drawpage(p);
- qunlock(p);
- }
- }
- unlockdisplay(display);
-}
-
-void killcohort(void)
-{
- int i;
- for(i=0;i!=3;i++){ /* It's a long way to the kitchen */
- postnote(PNGROUP, getpid(), "kill");
- sleep(1);
- }
-}
-
-void drawerr(Display *, char *msg)
-{
- sysfatal("draw: %s", msg);
-}
-
-char*
-shortname(char *s)
-{
- char *x;
- if(x = strrchr(s, '/'))
- if(x[1] != 0)
- return x+1;
- return s;
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: %s [ -iRw ] [ -p ppi ] [ file ... ]\n", argv0);
- exits("usage");
-}
-
-void
-main(int argc, char *argv[])
-{
- enum { Eplumb = 4 };
- Plumbmsg *pm;
- Point o;
- Mouse m;
- Event e;
- char *s;
- int i;
-
- ARGBEGIN {
- case 'a':
- case 'v':
- case 'V':
- case 'P':
- break;
- case 'R':
- newwin = -1;
- break;
- case 'w':
- newwin = 1;
- break;
- case 'i':
- imode = 1;
- break;
- case 'p':
- ppi = atoi(EARGF(usage()));
- break;
- default:
- usage();
- } ARGEND;
-
- /*
- * so that we can stop all subprocesses with a note,
- * and to isolate rendezvous from other processes
- */
- rfork(RFNOTEG|RFNAMEG|RFREND);
- atexit(killcohort);
- atnotify(catchnote, 1);
- if(newwin > 0){
- s = smprint("-pid %d", getpid());
- if(newwindow(s) < 0)
- sysfatal("newwindow: %r");
- free(s);
- }
- initdraw(drawerr, nil, argv0);
- display->locking = 1;
- unlockdisplay(display);
- einit(Ekeyboard|Emouse);
- eplumb(Eplumb, "image");
- nullfd = open("/dev/null", ORDWR);
- current = root = addpage(nil, "root", nil, nil, -1);
-
- if(*argv == nil && !imode)
- addpage(root, "stdin", popenfile, strdup("/fd/0"), -1);
- for(; *argv; argv++)
- addpage(root, shortname(*argv), popenfile, strdup(*argv), -1);
-
- for(;;){
- i=event(&e);
- switch(i){
- case Emouse:
- lockdisplay(display);
- m = e.mouse;
- if(m.buttons & 1){
- if(current == nil || !canqlock(current))
- goto Unlock;
- for(;;) {
- o = m.xy;
- m = emouse();
- if((m.buttons & 1) == 0)
- break;
- translate(current, subpt(m.xy, o));
- }
- qunlock(current);
- goto Unlock;
- }
- if(m.buttons & 2){
- i = emenuhit(2, &m, &menu);
- if(i < 0 || i >= nelem(menuitems) || menuitems[i]==nil)
- goto Unlock;
- s = menuitems[i];
- if(strcmp(s, "orig size")==0){
- pos = ZP;
- zoom = 1;
- resize = ZP;
- rotate = 0;
- Unload:
- viewgen++;
- unlockdisplay(display);
- esetcursor(&reading);
- unloadpages(0);
- showpage(current);
- continue;
- }
- if(strncmp(s, "rotate ", 7)==0){
- rotate += atoi(s+7);
- rotate %= 360;
- goto Unload;
- }
- if(strcmp(s, "upside down")==0){
- rotate += 180;
- goto Unload;
- }
- if(strcmp(s, "fit width")==0){
- pos = ZP;
- zoom = 1;
- resize = subpt(screen->r.max, screen->r.min);
- resize.y = 0;
- goto Unload;
- }
- if(strcmp(s, "fit height")==0){
- pos = ZP;
- zoom = 1;
- resize = subpt(screen->r.max, screen->r.min);
- resize.x = 0;
- goto Unload;
- }
- if(strncmp(s, "zoom", 4)==0){
- if(current && canqlock(current)){
- o = subpt(m.xy, screen->r.min);
- if(strstr(s, "in")){
- if(zoom < 0x40000000){
- zoom *= 2;
- pos = addpt(mulpt(subpt(pos, o), 2), o);
- }
- }else{
- if(zoom > 1){
- zoom /= 2;
- pos = addpt(divpt(subpt(pos, o), 2), o);
- }
- }
- drawpage(current);
- qunlock(current);
- }
- }
- unlockdisplay(display);
- if(strcmp(s, "next")==0)
- showpage(nextpage(current));
- if(strcmp(s, "prev")==0)
- showpage(prevpage(current));
- if(strcmp(s, "zerox")==0)
- zerox(current);
- if(strcmp(s, "quit")==0)
- exits(0);
- continue;
- }
- if(m.buttons & 4){
- if(root->down == nil)
- goto Unlock;
- pagemenu.lasthit = pageindex(current);
- i = emenuhit(3, &m, &pagemenu);
- unlockdisplay(display);
- if(i != -1)
- showpage(pageat(i));
- continue;
- }
- Unlock:
- unlockdisplay(display);
- break;
- case Ekeyboard:
- switch(e.kbdc){
- case 'q':
- case Kdel:
- case Keof:
- exits(0);
- case Kup:
- if(current == nil || !canqlock(current))
- break;
- lockdisplay(display);
- if(pos.y < 0){
- translate(current, Pt(0, Dy(screen->r)/2));
- unlockdisplay(display);
- qunlock(current);
- continue;
- }
- unlockdisplay(display);
- qunlock(current);
- if(prevpage(current))
- pos.y = 0;
- case Kleft:
- showpage(prevpage(current));
- break;
- case Kdown:
- if(current == nil || !canqlock(current))
- break;
- o = addpt(pos, pagesize(current));
- lockdisplay(display);
- if(o.y > Dy(screen->r)){
- translate(current, Pt(0, -Dy(screen->r)/2));
- unlockdisplay(display);
- qunlock(current);
- continue;
- }
- unlockdisplay(display);
- qunlock(current);
- if(nextpage(current))
- pos.y = 0;
- case ' ':
- case Kright:
- showpage(nextpage(current));
- break;
- }
- break;
- case Eplumb:
- pm = e.v;
- if(pm && pm->ndata > 0){
- int fd;
-
- fd = -1;
- s = plumblookup(pm->attr, "action");
- if(s && strcmp(s, "quit")==0)
- exits(0);
- if(s && strcmp(s, "showdata")==0){
- static ulong plumbid;
-
- if((fd = createtmp(plumbid++, "plumb")) < 0){
- fprint(2, "plumb: createtmp: %r\n");
- goto Plumbfree;
- }
- s = malloc(NPATH);
- if(fd2path(fd, s, NPATH) < 0){
- close(fd);
- goto Plumbfree;
- }
- write(fd, pm->data, pm->ndata);
- }else if(pm->data[0] == '/'){
- s = strdup(pm->data);
- }else{
- s = malloc(strlen(pm->wdir)+1+pm->ndata+1);
- sprint(s, "%s/%s", pm->wdir, pm->data);
- cleanname(s);
- }
- showpage(addpage(root, shortname(s), popenfile, s, fd));
- }
- Plumbfree:
- plumbfree(pm);
- break;
- }
- }
-}
--- /dev/null
+++ b/sys/src/cmd/page.c
@@ -1,0 +1,1282 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <plumb.h>
+
+typedef struct Page Page;
+struct Page {
+ char *label;
+
+ QLock;
+ void *data;
+ int (*open)(Page *);
+
+ char *text;
+ Image *image;
+ int fd;
+ int gen;
+
+ Page *up;
+ Page *next;
+ Page *down;
+ Page *tail;
+};
+
+int zoom = 1;
+int ppi = 100;
+int imode;
+int newwin;
+int rotate;
+int viewgen;
+int pagegen;
+Point resize, pos;
+Page *root, *current;
+QLock pagelock;
+int nullfd;
+
+char pagespool[] = "/tmp/pagespool.";
+
+enum {
+ NPROC = 4,
+ NAHEAD = 2,
+ NBUF = 8*1024,
+ NPATH = 1024,
+};
+
+char *pagemenugen(int i);
+
+char *menuitems[] = {
+ "orig size",
+ "rotate 90",
+ "upside down",
+ "",
+ "fit width",
+ "fit height",
+ "",
+ "zoom in",
+ "zoom out",
+ "",
+ "next",
+ "prev",
+ "zerox",
+ "",
+ "quit",
+ nil
+};
+
+Menu pagemenu = {
+ nil,
+ pagemenugen,
+ -1,
+};
+
+Menu menu = {
+ menuitems,
+ nil,
+ -1,
+};
+
+Cursor reading = {
+ {-1, -1},
+ {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00,
+ 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0,
+ 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0,
+ 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },
+ {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00,
+ 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0,
+ 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40,
+ 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }
+};
+
+void showpage(Page *);
+void drawpage(Page *);
+Point pagesize(Page *);
+
+Page*
+addpage(Page *up, char *label, int (*popen)(Page *), void *pdata, int fd)
+{
+ Page *p;
+
+ p = mallocz(sizeof(*p), 1);
+ p->label = strdup(label);
+ p->gen = pagegen;
+ p->text = nil;
+ p->image = nil;
+ p->data = pdata;
+ p->open = popen;
+ p->fd = fd;
+
+ p->down = nil;
+ p->tail = nil;
+ p->next = nil;
+
+ qlock(&pagelock);
+ if(p->up = up){
+ if(up->tail == nil)
+ up->down = up->tail = p;
+ else {
+ up->tail->next = p;
+ up->tail = p;
+ }
+ }
+ qunlock(&pagelock);
+
+ if(up && current == up)
+ showpage(p);
+ return p;
+}
+
+void
+resizewin(Point size)
+{
+ int wctl;
+
+ if((wctl = open("/dev/wctl", OWRITE)) < 0)
+ return;
+ /* add rio border */
+ size = addpt(size, Pt(Borderwidth*2, Borderwidth*2));
+ fprint(wctl, "resize -dx %d -dy %d\n", size.x, size.y);
+ close(wctl);
+}
+
+int
+createtmp(ulong id, char *pfx)
+{
+ char nam[64];
+
+ snprint(nam, sizeof nam, "%s%s%.12d%.8lux", pagespool, pfx, getpid(), id ^ 0xcafebabe);
+ return create(nam, OEXCL|ORCLOSE|ORDWR, 0600);
+}
+
+int
+catchnote(void *, char *msg)
+{
+ if(strstr(msg, "sys: write on closed pipe"))
+ return 1;
+ if(strstr(msg, "hangup"))
+ return 1;
+ if(strstr(msg, "alarm"))
+ return 1;
+ return 0;
+}
+
+void
+pipeline(int fd, char *fmt, ...)
+{
+ char buf[128], *argv[4];
+ va_list arg;
+ int pfd[2];
+
+ if(pipe(pfd) < 0){
+ Err:
+ dup(nullfd, fd);
+ return;
+ }
+ switch(rfork(RFPROC|RFFDG|RFREND|RFNOWAIT)){
+ case -1:
+ close(pfd[0]);
+ close(pfd[1]);
+ goto Err;
+ case 0:
+ if(dup(fd, 0)<0)
+ exits("dup");
+ if(dup(pfd[1], 1)<0)
+ exits("dup");
+ close(fd);
+ close(pfd[1]);
+ close(pfd[0]);
+ va_start(arg, fmt);
+ vsnprint(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+
+ argv[0] = "rc";
+ argv[1] = "-c";
+ argv[2] = buf;
+ argv[3] = nil;
+ exec("/bin/rc", argv);
+ sysfatal("exec: %r");
+ }
+ close(pfd[1]);
+ dup(pfd[0], fd);
+ close(pfd[0]);
+}
+
+int
+popenfile(Page*);
+
+int
+popenconv(Page *p)
+{
+ char nam[NPATH];
+ int fd;
+
+ if((fd = dup(p->fd, -1)) < 0){
+ close(p->fd);
+ p->fd = -1;
+ return -1;
+ }
+
+ seek(fd, 0, 0);
+ if(p->data)
+ pipeline(fd, "%s", (char*)p->data);
+
+ /*
+ * dont keep the file descriptor arround if it can simply
+ * be reopened.
+ */
+ fd2path(p->fd, nam, sizeof(nam));
+ if(strncmp(nam, pagespool, strlen(pagespool))){
+ close(p->fd);
+ p->fd = -1;
+ p->data = strdup(nam);
+ p->open = popenfile;
+ }
+
+ return fd;
+}
+
+typedef struct Ghost Ghost;
+struct Ghost
+{
+ QLock;
+
+ int pin;
+ int pout;
+ int pdat;
+};
+
+int
+popenpdf(Page *p)
+{
+ char buf[NBUF];
+ int n, pfd[2];
+ Ghost *gs;
+
+ if(pipe(pfd) < 0)
+ return -1;
+ switch(rfork(RFFDG|RFPROC|RFMEM|RFNOWAIT)){
+ case -1:
+ close(pfd[0]);
+ close(pfd[1]);
+ return -1;
+ case 0:
+ close(pfd[0]);
+ gs = p->data;
+ qlock(gs);
+ fprint(gs->pin, "%s DoPDFPage\n"
+ "(/fd/3) (w) file "
+ "dup flushfile "
+ "dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring "
+ "flushfile\n", p->label);
+ while((n = read(gs->pdat, buf, sizeof buf)) > 0){
+ if(memcmp(buf, "THIS IS NOT AN INFERNO BITMAP\n", 30) == 0)
+ break;
+ if(pfd[1] < 0)
+ continue;
+ if(write(pfd[1], buf, n) != n){
+ close(pfd[1]);
+ pfd[1]=-1;
+ }
+ }
+ qunlock(gs);
+ exits(nil);
+ }
+ close(pfd[1]);
+ return pfd[0];
+}
+
+int
+infernobithdr(char *buf, int n)
+{
+ if(n >= 11){
+ if(memcmp(buf, "compressed\n", 11) == 0)
+ return 1;
+ if(strtochan((char*)buf))
+ return 1;
+ if(memcmp(buf, " ", 10) == 0 &&
+ '0' <= buf[10] && buf[10] <= '9' &&
+ buf[11] == ' ')
+ return 1;
+ }
+ return 0;
+}
+
+int
+popengs(Page *p)
+{
+ int n, i, pdf, ifd, ofd, pin[2], pout[2], pdat[2];
+ char buf[NBUF], nam[32], *argv[16];
+
+ pdf = 0;
+ ifd = p->fd;
+ p->fd = -1;
+ seek(ifd, 0, 0);
+ if(read(ifd, buf, 5) != 5)
+ goto Err0;
+ seek(ifd, 0, 0);
+ if(memcmp(buf, "%PDF-", 5) == 0)
+ pdf = 1;
+ p->text = strdup(p->label);
+ if(pipe(pin) < 0){
+ Err0:
+ close(ifd);
+ return -1;
+ }
+ if(pipe(pout) < 0){
+ Err1:
+ close(pin[0]);
+ close(pin[1]);
+ goto Err0;
+ }
+ if(pipe(pdat) < 0){
+ Err2:
+ close(pdat[0]);
+ close(pdat[1]);
+ goto Err1;
+ }
+
+ switch(rfork(RFREND|RFPROC|RFFDG|RFNOWAIT)){
+ case -1:
+ goto Err2;
+ case 0:
+ if(pdf){
+ if(dup(pin[1], 0)<0)
+ exits("dup");
+ if(dup(pout[1], 1)<0)
+ exits("dup");
+ } else {
+ if(dup(nullfd, 0)<0)
+ exits("dup");
+ if(dup(nullfd, 1)<0)
+ exits("dup");
+ }
+ if(dup(nullfd, 2)<0)
+ exits("dup");
+ if(dup(pdat[1], 3)<0)
+ exits("dup");
+ if(dup(ifd, 4)<0)
+ exits("dup");
+
+ close(pin[0]);
+ close(pin[1]);
+ close(pout[0]);
+ close(pout[1]);
+ close(pdat[0]);
+ close(pdat[1]);
+ close(ifd);
+
+ if(p->data)
+ pipeline(4, "%s", (char*)p->data);
+
+ argv[0] = "gs";
+ argv[1] = "-q";
+ argv[2] = "-sDEVICE=plan9";
+ argv[3] = "-sOutputFile=/fd/3";
+ argv[4] = "-dBATCH";
+ argv[5] = pdf ? "-dDELAYSAFER" : "-dSAFER";
+ argv[6] = "-dQUIET";
+ argv[7] = "-dTextAlphaBits=4";
+ argv[8] = "-dGraphicsAlphaBits=4";
+ snprint(buf, sizeof buf, "-r%d", ppi);
+ argv[9] = buf;
+ argv[10] = "-dDOINTERPOLATE";
+ argv[11] = pdf ? "-" : "/fd/4";
+ argv[12] = nil;
+ exec("/bin/gs", argv);
+ sysfatal("exec: %r");
+ }
+
+ close(pin[1]);
+ close(pout[1]);
+ close(pdat[1]);
+ close(ifd);
+
+ if(pdf){
+ Ghost *gs;
+ char *prolog =
+ "/PAGEOUT (/fd/1) (w) file def\n"
+ "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n"
+ "\n"
+ "/Page null def\n"
+ "/Page# 0 def\n"
+ "/PDFSave null def\n"
+ "/DSCPageCount 0 def\n"
+ "/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def\n"
+ "\n"
+ "GS_PDF_ProcSet begin\n"
+ "pdfdict begin\n"
+ "(/fd/4) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n"
+ "\n"
+ "pdfpagecount PAGE==\n";
+
+ n = strlen(prolog);
+ if(write(pin[0], prolog, n) != n)
+ goto Out;
+ if((n = read(pout[0], buf, sizeof(buf)-1)) < 0)
+ goto Out;
+ buf[n] = 0;
+ n = atoi(buf);
+ if(n <= 0){
+ werrstr("no pages");
+ goto Out;
+ }
+ gs = mallocz(sizeof(*gs), 1);
+ gs->pin = pin[0];
+ gs->pout = pout[0];
+ gs->pdat = pdat[0];
+ for(i=1; i<=n; i++){
+ snprint(nam, sizeof nam, "%d", i);
+ addpage(p, nam, popenpdf, gs, -1);
+ }
+
+ /* keep ghostscript arround */
+ return -1;
+ } else {
+ i = 0;
+ ofd = -1;
+ while((n = read(pdat[0], buf, sizeof(buf))) >= 0){
+ if(ofd >= 0 && (n <= 0 || infernobithdr(buf, n))){
+ snprint(nam, sizeof nam, "%d", i);
+ addpage(p, nam, popenconv, nil, ofd);
+ ofd = -1;
+ }
+ if(n <= 0)
+ break;
+ if(ofd < 0){
+ snprint(nam, sizeof nam, "%.4d", ++i);
+ if((ofd = createtmp((ulong)p, nam)) < 0)
+ ofd = dup(nullfd, -1);
+ }
+ if(write(ofd, buf, n) != n)
+ break;
+ }
+ if(ofd >= 0)
+ close(ofd);
+ }
+Out:
+ close(pin[0]);
+ close(pout[0]);
+ close(pdat[0]);
+ return -1;
+}
+
+int
+popenfile(Page *p)
+{
+ char buf[NBUF], *file;
+ int i, n, fd, tfd;
+ Dir *d;
+
+ fd = p->fd;
+ p->fd = -1;
+ file = p->data;
+ if(fd < 0){
+ if((fd = open(file, OREAD)) < 0){
+ Err0:
+ p->data = nil;
+ free(file);
+ return -1;
+ }
+ }
+ seek(fd, 0, 0);
+ if((d = dirfstat(fd)) == nil){
+ Err1:
+ close(fd);
+ goto Err0;
+ }
+ if(d->mode & DMDIR){
+ free(d);
+ d = nil;
+ if((n = dirreadall(fd, &d)) < 0)
+ goto Err1;
+ for(i = 0; i<n; i++)
+ addpage(p, d[i].name, popenfile, smprint("%s/%s", file, d[i].name), -1);
+ free(d);
+ p->text = strdup(p->label);
+ goto Err1;
+ }
+ free(d);
+
+ memset(buf, 0, 32+1);
+ if((n = read(fd, buf, 32)) <= 0)
+ goto Err1;
+
+ p->fd = fd;
+ p->data = nil;
+ p->open = popenconv;
+ if(memcmp(buf, "%PDF-", 5) == 0 || strstr(buf, "%!"))
+ p->open = popengs;
+ else if(memcmp(buf, "x T ", 4) == 0){
+ p->data = "lp -dstdout";
+ p->open = popengs;
+ }
+ else if(memcmp(buf, "\xF7\x02\x01\x83\x92\xC0\x1C;", 8) == 0){
+ p->data = "dvips -Pps -r0 -q1 -f1";
+ p->open = popengs;
+ }
+ else if(memcmp(buf, "\x1F\x8B", 2) == 0){
+ p->data = "gunzip";
+ p->open = popengs;
+ }
+ else if(memcmp(buf, "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", 8) == 0){
+ p->data = "doc2ps";
+ p->open = popengs;
+ }
+ else if(memcmp(buf, "GIF", 3) == 0)
+ p->data = "gif -t9";
+ else if(memcmp(buf, "\111\111\052\000", 4) == 0)
+ p->data = "fb/tiff2pic | fb/3to1 rgbv | fb/pcp -tplan9";
+ else if(memcmp(buf, "\115\115\000\052", 4) == 0)
+ p->data = "fb/tiff2pic | fb/3to1 rgbv | fb/pcp -tplan9";
+ else if(memcmp(buf, "\377\330\377", 3) == 0)
+ p->data = "jpg -t9";
+ else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0)
+ p->data = "png -t9";
+ else if(memcmp(buf, "\0PC Research, Inc", 17) == 0)
+ p->data = "aux/g3p9bit -g";
+ else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0)
+ p->data = "aux/g3p9bit -g";
+ else if(memcmp(buf, "II*", 3) == 0)
+ p->data = "aux/g3p9bit -g";
+ else if(memcmp(buf, "TYPE=", 5) == 0)
+ p->data = "fb/3to1 rgbv |fb/pcp -tplan9";
+ else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9')
+ p->data = "ppm -t9";
+ else if(memcmp(buf, "BM", 2) == 0)
+ p->data = "bmp -t9";
+ else if(infernobithdr(buf, n))
+ p->data = nil;
+ else {
+ werrstr("unknown image format");
+ goto Err1;
+ }
+
+ if(seek(fd, 0, 0) < 0)
+ goto Noseek;
+ if((i = read(fd, buf+n, n)) < 0)
+ goto Err1;
+ if(i != n || memcmp(buf, buf+n, i)){
+ n += i;
+ Noseek:
+ if((tfd = createtmp((ulong)p, "file")) < 0)
+ goto Err1;
+ while(n > 0){
+ if(write(tfd, buf, n) != n)
+ goto Err2;
+ if((n = read(fd, buf, sizeof(buf))) < 0)
+ goto Err2;
+ }
+ if(dup(tfd, fd) < 0){
+ Err2:
+ close(tfd);
+ goto Err1;
+ }
+ close(tfd);
+ }
+ free(file);
+ return p->open(p);
+}
+
+Page*
+nextpage(Page *p)
+{
+ if(p){
+ if(p->down)
+ return p->down;
+ if(p->next)
+ return p->next;
+ if(p->up)
+ return p->up->next;
+ }
+ return nil;
+}
+
+Page*
+prevpage(Page *x)
+{
+ Page *p, *t;
+
+ if(x){
+ for(p = root->down; p; p = t)
+ if((t = nextpage(p)) == x)
+ return p;
+ }
+ return nil;
+}
+
+int
+openpage(Page *p)
+{
+ int fd;
+
+ fd = -1;
+ if(p->open == nil || (fd = p->open(p)) < 0)
+ p->open = nil;
+ else {
+ if(rotate)
+ pipeline(fd, "rotate -r %d", rotate);
+ if(resize.x)
+ pipeline(fd, "resize -x %d", resize.x);
+ else if(resize.y)
+ pipeline(fd, "resize -y %d", resize.y);
+ }
+ return fd;
+}
+
+void
+loadpage(Page *p)
+{
+ int fd;
+
+ if(p->open && p->image == nil && p->text == nil){
+ if((fd = openpage(p)) >= 0){
+ pagegen++;
+ p->image = readimage(display, fd, 1);
+ close(fd);
+ }
+ if(p->image == nil && p->text == nil)
+ p->text = smprint("%s: %r", p->label);
+ }
+ p->gen = pagegen;
+}
+
+void
+unloadpage(Page *p)
+{
+ if(p->open){
+ if(p->text)
+ free(p->text);
+ p->text = nil;
+ if(p->image){
+ lockdisplay(display);
+ freeimage(p->image);
+ unlockdisplay(display);
+ }
+ p->image = nil;
+ }
+}
+
+void
+unloadpages(int age)
+{
+ Page *p;
+
+ for(p = root->down; p; p = nextpage(p)){
+ if(age == 0) /* synchronous flush */
+ qlock(p);
+ else if(!canqlock(p))
+ continue;
+ if((pagegen - p->gen) >= age)
+ unloadpage(p);
+ qunlock(p);
+ }
+}
+
+void
+loadpages(Page *p, int ahead, int oviewgen)
+{
+ int i;
+
+ ahead++; /* load at least one */
+ unloadpages(ahead*2);
+ for(i = 0; i < ahead && p; p = nextpage(p), i++){
+ if(viewgen != oviewgen)
+ break;
+ if(canqlock(p)){
+ loadpage(p);
+ if(viewgen != oviewgen){
+ unloadpage(p);
+ qunlock(p);
+ break;
+ }
+ if(p == current){
+ Point size;
+
+ esetcursor(nil);
+ size = pagesize(p);
+ if(size.x && size.y && newwin){
+ newwin = 0;
+ resizewin(size);
+ }
+ lockdisplay(display);
+ drawpage(p);
+ unlockdisplay(display);
+ }
+ qunlock(p);
+ }
+ }
+}
+
+/*
+ * A draw operation that touches only the area contained in bot but not in top.
+ * mp and sp get aligned with bot.min.
+ */
+static void
+gendrawdiff(Image *dst, Rectangle bot, Rectangle top,
+ Image *src, Point sp, Image *mask, Point mp, int op)
+{
+ Rectangle r;
+ Point origin;
+ Point delta;
+
+ USED(op);
+
+ if(Dx(bot)*Dy(bot) == 0)
+ return;
+
+ /* no points in bot - top */
+ if(rectinrect(bot, top))
+ return;
+
+ /* bot - top ≡ bot */
+ if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){
+ gendrawop(dst, bot, src, sp, mask, mp, op);
+ return;
+ }
+
+ origin = bot.min;
+ /* split bot into rectangles that don't intersect top */
+ /* left side */
+ if(bot.min.x < top.min.x){
+ r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y);
+ delta = subpt(r.min, origin);
+ gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
+ bot.min.x = top.min.x;
+ }
+
+ /* right side */
+ if(bot.max.x > top.max.x){
+ r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y);
+ delta = subpt(r.min, origin);
+ gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
+ bot.max.x = top.max.x;
+ }
+
+ /* top */
+ if(bot.min.y < top.min.y){
+ r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y);
+ delta = subpt(r.min, origin);
+ gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
+ bot.min.y = top.min.y;
+ }
+
+ /* bottom */
+ if(bot.max.y > top.max.y){
+ r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y);
+ delta = subpt(r.min, origin);
+ gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
+ bot.max.y = top.max.y;
+ }
+}
+
+void
+zoomdraw(Image *d, Rectangle r, Rectangle top, Image *s, Point sp, int f)
+{
+ int w, x, y;
+ Image *t;
+ Point a;
+
+ if(f <= 1){
+ gendrawdiff(d, r, top, s, sp, nil, ZP, S);
+ return;
+ }
+ a = ZP;
+ if(r.min.x < d->r.min.x){
+ sp.x += (d->r.min.x - r.min.x)/f;
+ a.x = (d->r.min.x - r.min.x)%f;
+ r.min.x = d->r.min.x;
+ }
+ if(r.min.y < d->r.min.y){
+ sp.y += (d->r.min.y - r.min.y)/f;
+ a.y = (d->r.min.y - r.min.y)%f;
+ r.min.y = d->r.min.y;
+ }
+ rectclip(&r, d->r);
+ w = s->r.max.x - sp.x;
+ if(w > Dx(r))
+ w = Dx(r);
+ t = allocimage(display, Rect(r.min.x, r.min.y, r.min.x+w, r.max.y), s->chan, 0, DNofill);
+ if(t == nil)
+ return;
+ for(y=r.min.y; y<r.max.y; y++){
+ draw(t, Rect(r.min.x, y, r.min.x+w, y+1), s, nil, sp);
+ if(++a.y == zoom){
+ a.y = 0;
+ sp.y++;
+ }
+ }
+ sp = r.min;
+ for(x=r.min.x; x<r.max.x; x++){
+ gendrawdiff(d, Rect(x, r.min.y, x+1, r.max.y), top, t, sp, nil, ZP, S);
+ if(++a.x == f){
+ a.x = 0;
+ sp.x++;
+ }
+ }
+ freeimage(t);
+}
+
+Point
+pagesize(Page *p)
+{
+ return p->image ? mulpt(subpt(p->image->r.max, p->image->r.min), zoom) : ZP;
+}
+
+void
+drawpage(Page *p)
+{
+ Rectangle r;
+ Image *i;
+
+ if((i = p->image) == nil){
+ char *s;
+
+ if((s = p->text) == nil)
+ s = "...";
+ r.min = ZP;
+ r.max = stringsize(font, p->text);
+ r = rectaddpt(r, addpt(subpt(divpt(subpt(screen->r.max, screen->r.min), 2), divpt(r.max, 2)),
+ screen->r.min));
+ draw(screen, r, display->white, nil, ZP);
+ string(screen, r.min, display->black, ZP, font, s);
+ } else {
+ r = rectaddpt(Rpt(ZP, pagesize(p)), addpt(pos, screen->r.min));
+ zoomdraw(screen, r, ZR, i, i->r.min, zoom);
+ }
+ gendrawdiff(screen, screen->r, r, display->white, ZP, nil, ZP, S);
+ border(screen, r, -Borderwidth, display->black, ZP);
+ flushimage(display, 1);
+}
+
+void
+translate(Page *p, Point d)
+{
+ Rectangle r, or, nr;
+ Image *i;
+
+ i = p->image;
+ if((i==0) || (d.x==0 && d.y==0))
+ return;
+ r = rectaddpt(Rpt(ZP, pagesize(p)), addpt(pos, screen->r.min));
+ pos = addpt(pos, d);
+ nr = rectaddpt(r, d);
+ or = r;
+ rectclip(&or, screen->r);
+ draw(screen, rectaddpt(or, d), screen, nil, or.min);
+ zoomdraw(screen, nr, rectaddpt(or, d), i, i->r.min, zoom);
+ gendrawdiff(screen, screen->r, nr, display->white, ZP, nil, ZP, S);
+ border(screen, nr, -Borderwidth, display->black, ZP);
+ flushimage(display, 1);
+}
+
+Page*
+findpage(char *name)
+{
+ Page *p;
+ int n;
+
+ n = strlen(name);
+ /* look in current document first */
+ if(current && current->up){
+ for(p = current->up->down; p; p = p->next)
+ if(cistrncmp(p->label, name, n) == 0)
+ return p;
+ }
+ /* look everywhere */
+ for(p = root->down; p; p = nextpage(p))
+ if(cistrncmp(p->label, name, n) == 0)
+ return p;
+ return nil;
+}
+
+Page*
+pageat(int i)
+{
+ Page *p;
+
+ for(p = root->down; i > 0 && p; p = nextpage(p))
+ i--;
+ return i ? nil : p;
+}
+
+int
+pageindex(Page *x)
+{
+ Page *p;
+ int i;
+
+ for(i = 0, p = root->down; p && p != x; p = nextpage(p))
+ i++;
+ return (p == x) ? i : -1;
+}
+
+char*
+pagemenugen(int i)
+{
+ Page *p;
+ if(p = pageat(i))
+ return p->label;
+ return nil;
+}
+
+void
+showpage(Page *p)
+{
+ static int nproc;
+ int oviewgen;
+
+ if(p == nil)
+ return;
+ esetcursor(&reading);
+ current = p;
+ oviewgen = viewgen;
+ if(++nproc > NPROC)
+ if(waitpid() > 0)
+ nproc--;
+ switch(rfork(RFPROC|RFMEM)){
+ case -1:
+ sysfatal("rfork: %r");
+ case 0:
+ loadpages(p, NAHEAD, oviewgen);
+ exits(nil);
+ }
+}
+
+void
+zerox(Page *p)
+{
+ char nam[64], *argv[4];
+ int fd;
+
+ if(p == nil)
+ return;
+ esetcursor(&reading);
+ qlock(p);
+ if((fd = openpage(p)) < 0)
+ goto Out;
+ if(rfork(RFREND|RFFDG|RFPROC|RFENVG|RFNOTEG|RFNOWAIT) == 0){
+ dup(fd, 0);
+ close(fd);
+
+ snprint(nam, sizeof nam, "/bin/%s", argv0);
+ argv[0] = argv0;
+ argv[1] = "-w";
+ argv[2] = nil;
+ exec(nam, argv);
+ sysfatal("exec: %r");
+ }
+ close(fd);
+Out:
+ qunlock(p);
+ esetcursor(nil);
+}
+
+void
+eresized(int new)
+{
+ Page *p;
+
+ lockdisplay(display);
+ if(new && getwindow(display, Refnone) == -1)
+ sysfatal("getwindow: %r");
+ if(p = current){
+ if(canqlock(p)){
+ drawpage(p);
+ qunlock(p);
+ }
+ }
+ unlockdisplay(display);
+}
+
+void killcohort(void)
+{
+ int i;
+ for(i=0;i!=3;i++){ /* It's a long way to the kitchen */
+ postnote(PNGROUP, getpid(), "kill");
+ sleep(1);
+ }
+}
+
+void drawerr(Display *, char *msg)
+{
+ sysfatal("draw: %s", msg);
+}
+
+char*
+shortname(char *s)
+{
+ char *x;
+ if(x = strrchr(s, '/'))
+ if(x[1] != 0)
+ return x+1;
+ return s;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [ -iRw ] [ -p ppi ] [ file ... ]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ enum { Eplumb = 4 };
+ char jump[32];
+ Plumbmsg *pm;
+ Point o;
+ Mouse m;
+ Event e;
+ char *s;
+ int i;
+
+ ARGBEGIN {
+ case 'a':
+ case 'v':
+ case 'V':
+ case 'P':
+ break;
+ case 'R':
+ newwin = -1;
+ break;
+ case 'w':
+ newwin = 1;
+ break;
+ case 'i':
+ imode = 1;
+ break;
+ case 'p':
+ ppi = atoi(EARGF(usage()));
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ /*
+ * so that we can stop all subprocesses with a note,
+ * and to isolate rendezvous from other processes
+ */
+ rfork(RFNOTEG|RFNAMEG|RFREND);
+ atexit(killcohort);
+ atnotify(catchnote, 1);
+ if(newwin > 0){
+ s = smprint("-pid %d", getpid());
+ if(newwindow(s) < 0)
+ sysfatal("newwindow: %r");
+ free(s);
+ }
+ initdraw(drawerr, nil, argv0);
+ display->locking = 1;
+ unlockdisplay(display);
+ einit(Ekeyboard|Emouse);
+ eplumb(Eplumb, "image");
+ nullfd = open("/dev/null", ORDWR);
+ current = root = addpage(nil, "root", nil, nil, -1);
+
+ if(*argv == nil && !imode)
+ addpage(root, "stdin", popenfile, strdup("/fd/0"), -1);
+ for(; *argv; argv++)
+ addpage(root, shortname(*argv), popenfile, strdup(*argv), -1);
+
+ jump[0] = 0;
+ for(;;){
+ i=event(&e);
+ switch(i){
+ case Emouse:
+ lockdisplay(display);
+ m = e.mouse;
+ if(m.buttons & 1){
+ if(current == nil || !canqlock(current))
+ goto Unlock;
+ for(;;) {
+ o = m.xy;
+ m = emouse();
+ if((m.buttons & 1) == 0)
+ break;
+ translate(current, subpt(m.xy, o));
+ }
+ qunlock(current);
+ goto Unlock;
+ }
+ if(m.buttons & 2){
+ i = emenuhit(2, &m, &menu);
+ if(i < 0 || i >= nelem(menuitems) || menuitems[i]==nil)
+ goto Unlock;
+ s = menuitems[i];
+ if(strcmp(s, "orig size")==0){
+ pos = ZP;
+ zoom = 1;
+ resize = ZP;
+ rotate = 0;
+ Unload:
+ viewgen++;
+ unlockdisplay(display);
+ esetcursor(&reading);
+ unloadpages(0);
+ showpage(current);
+ continue;
+ }
+ if(strncmp(s, "rotate ", 7)==0){
+ rotate += atoi(s+7);
+ rotate %= 360;
+ goto Unload;
+ }
+ if(strcmp(s, "upside down")==0){
+ rotate += 180;
+ goto Unload;
+ }
+ if(strcmp(s, "fit width")==0){
+ pos = ZP;
+ zoom = 1;
+ resize = subpt(screen->r.max, screen->r.min);
+ resize.y = 0;
+ goto Unload;
+ }
+ if(strcmp(s, "fit height")==0){
+ pos = ZP;
+ zoom = 1;
+ resize = subpt(screen->r.max, screen->r.min);
+ resize.x = 0;
+ goto Unload;
+ }
+ if(strncmp(s, "zoom", 4)==0){
+ if(current && canqlock(current)){
+ o = subpt(m.xy, screen->r.min);
+ if(strstr(s, "in")){
+ if(zoom < 0x40000000){
+ zoom *= 2;
+ pos = addpt(mulpt(subpt(pos, o), 2), o);
+ }
+ }else{
+ if(zoom > 1){
+ zoom /= 2;
+ pos = addpt(divpt(subpt(pos, o), 2), o);
+ }
+ }
+ drawpage(current);
+ qunlock(current);
+ }
+ }
+ unlockdisplay(display);
+ if(strcmp(s, "next")==0)
+ showpage(nextpage(current));
+ if(strcmp(s, "prev")==0)
+ showpage(prevpage(current));
+ if(strcmp(s, "zerox")==0)
+ zerox(current);
+ if(strcmp(s, "quit")==0)
+ exits(0);
+ continue;
+ }
+ if(m.buttons & 4){
+ if(root->down == nil)
+ goto Unlock;
+ pagemenu.lasthit = pageindex(current);
+ i = emenuhit(3, &m, &pagemenu);
+ unlockdisplay(display);
+ if(i != -1)
+ showpage(pageat(i));
+ continue;
+ }
+ Unlock:
+ unlockdisplay(display);
+ break;
+ case Ekeyboard:
+ switch(e.kbdc){
+ case 'q':
+ case Kdel:
+ case Keof:
+ exits(0);
+ case Kup:
+ if(current == nil || !canqlock(current))
+ break;
+ lockdisplay(display);
+ if(pos.y < 0){
+ translate(current, Pt(0, Dy(screen->r)/2));
+ unlockdisplay(display);
+ qunlock(current);
+ continue;
+ }
+ unlockdisplay(display);
+ qunlock(current);
+ if(prevpage(current))
+ pos.y = 0;
+ case '-':
+ case Kbs:
+ case Kleft:
+ showpage(prevpage(current));
+ break;
+ case Kdown:
+ if(current == nil || !canqlock(current))
+ break;
+ o = addpt(pos, pagesize(current));
+ lockdisplay(display);
+ if(o.y > Dy(screen->r)){
+ translate(current, Pt(0, -Dy(screen->r)/2));
+ unlockdisplay(display);
+ qunlock(current);
+ continue;
+ }
+ unlockdisplay(display);
+ qunlock(current);
+ if(nextpage(current))
+ pos.y = 0;
+ case '\n':
+ if(jump[0]){
+ showpage(findpage(jump));
+ jump[0] = 0;
+ break;
+ }
+ case ' ':
+ case Kright:
+ showpage(nextpage(current));
+ break;
+ default:
+ i = strlen(jump);
+ if(i+1 < sizeof(jump)){
+ jump[i] = e.kbdc;
+ jump[i+1] = 0;
+ }
+ }
+ break;
+ case Eplumb:
+ pm = e.v;
+ if(pm && pm->ndata > 0){
+ int fd;
+
+ fd = -1;
+ s = plumblookup(pm->attr, "action");
+ if(s && strcmp(s, "quit")==0)
+ exits(0);
+ if(s && strcmp(s, "showdata")==0){
+ static ulong plumbid;
+
+ if((fd = createtmp(plumbid++, "plumb")) < 0){
+ fprint(2, "plumb: createtmp: %r\n");
+ goto Plumbfree;
+ }
+ s = malloc(NPATH);
+ if(fd2path(fd, s, NPATH) < 0){
+ close(fd);
+ goto Plumbfree;
+ }
+ write(fd, pm->data, pm->ndata);
+ }else if(pm->data[0] == '/'){
+ s = strdup(pm->data);
+ }else{
+ s = malloc(strlen(pm->wdir)+1+pm->ndata+1);
+ sprint(s, "%s/%s", pm->wdir, pm->data);
+ cleanname(s);
+ }
+ showpage(addpage(root, shortname(s), popenfile, s, fd));
+ }
+ Plumbfree:
+ plumbfree(pm);
+ break;
+ }
+ }
+}
--- a/sys/src/cmd/page/cache.c
+++ /dev/null
@@ -1,187 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <cursor.h>
-#include <event.h>
-#include <bio.h>
-#include <plumb.h>
-#include <ctype.h>
-#include <keyboard.h>
-#include "page.h"
-
-typedef struct Cached Cached;
-struct Cached
-{
- Document *doc;
- int page;
- int angle;
- Image *im;
-};
-
-static Cached cache[5];
-
-static Image*
-questionmark(void)
-{
- static Image *im;
-
- if(im)
- return im;
- im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);
- if(im == nil)
- return nil;
- string(im, ZP, display->white, ZP, display->defaultfont, "?");
- return im;
-}
-
-void
-cacheflush(void)
-{
- int i;
- Cached *c;
-
- for(i=0; i<nelem(cache); i++){
- c = &cache[i];
- if(c->im)
- freeimage(c->im);
- c->im = nil;
- c->doc = nil;
- }
-}
-
-static Image*
-_cachedpage(Document *doc, int angle, int page, char *ra)
-{
- int i;
- Cached *c, old;
- Image *im, *tmp;
- static int lastpage = -1;
-
- if((page < 0 || page >= doc->npage) && !doc->fwdonly)
- return nil;
-
-Again:
- for(i=0; i<nelem(cache); i++){
- c = &cache[i];
- if(c->doc == doc && c->angle == angle && c->page == page){
- if(chatty) fprint(2, "cache%s hit %d\n", ra, page);
- goto Found;
- }
- if(c->doc == nil)
- break;
- }
-
- if(i >= nelem(cache))
- i = nelem(cache)-1;
- c = &cache[i];
- if(c->im)
- freeimage(c->im);
- c->im = nil;
- c->doc = nil;
- c->page = -1;
-
- if(chatty) fprint(2, "cache%s load %d\n", ra, page);
- im = doc->drawpage(doc, page);
- if(im == nil){
- if(doc->fwdonly) /* end of file */
- wexits(0);
- im = questionmark();
- if(im == nil){
- Flush:
- if(i > 0){
- cacheflush();
- goto Again;
- }
- fprint(2, "out of memory: %r\n");
- wexits("memory");
- }
- return im;
- }
-
- if(im->r.min.x != 0 || im->r.min.y != 0){
- /* translate to 0,0 */
- tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill);
- if(tmp == nil){
- freeimage(im);
- goto Flush;
- }
- drawop(tmp, tmp->r, im, nil, im->r.min, S);
- freeimage(im);
- im = tmp;
- }
-
- switch(angle){
- case 90:
- im = rot90(im);
- break;
- case 180:
- rot180(im);
- break;
- case 270:
- im = rot270(im);
- break;
- }
- if(im == nil)
- goto Flush;
-
- c->doc = doc;
- c->page = page;
- c->angle = angle;
- c->im = im;
-
-Found:
- if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i);
- old = *c;
- memmove(cache+1, cache, (c-cache)*sizeof cache[0]);
- cache[0] = old;
- if(chatty){
- for(i=0; i<nelem(cache); i++)
- fprint(2, " %d", cache[i].page);
- fprint(2, "\n");
- }
- if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im);
- return old.im;
-}
-
-Image*
-cachedpage(Document *doc, int angle, int page)
-{
- static int lastpage = -1;
- static int rabusy;
- Image *im;
- int ra;
-
- if(doc->npage < 1)
- return display->white;
-
- im = _cachedpage(doc, angle, page, "");
- if(im == nil)
- return nil;
-
- /* readahead */
- ra = -1;
- if(!rabusy){
- if(page == lastpage+1)
- ra = page+1;
- else if(page == lastpage-1)
- ra = page-1;
- }
- lastpage = page;
- if(ra >= 0){
- rabusy = 1;
- switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
- case -1:
- rabusy = 0;
- break;
- case 0:
- lockdisplay(display);
- _cachedpage(doc, angle, ra, "-ra");
- rabusy = 0;
- unlockdisplay(display);
- _exits(nil);
- default:
- break;
- }
- }
- return im;
-}
--- a/sys/src/cmd/page/filter.c
+++ /dev/null
@@ -1,107 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <bio.h>
-#include "page.h"
-
-Document*
-initfilt(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf, char *type, char *cmd, int docopy)
-{
- int ofd;
- int p[2];
- char xbuf[8192];
- int n;
-
- if(argc > 1) {
- fprint(2, "can only view one %s file at a time\n", type);
- return nil;
- }
-
- fprint(2, "converting from %s to postscript...\n", type);
-
- if(docopy){
- if(pipe(p) < 0){
- fprint(2, "pipe fails: %r\n");
- exits("Epipe");
- }
- }else{
- p[0] = open("/dev/null", ORDWR);
- p[1] = open("/dev/null", ORDWR);
- }
-
- ofd = opentemp("/tmp/pagecvtXXXXXXXXX");
- switch(fork()){
- case -1:
- fprint(2, "fork fails: %r\n");
- exits("Efork");
- default:
- close(p[1]);
- if(docopy){
- write(p[0], buf, nbuf);
- if(b)
- while((n = Bread(b, xbuf, sizeof xbuf)) > 0)
- write(p[0], xbuf, n);
- else
- while((n = read(stdinfd, xbuf, sizeof xbuf)) > 0)
- write(p[0], xbuf, n);
- }
- close(p[0]);
- waitpid();
- break;
- case 0:
- close(p[0]);
- dup(p[1], 0);
- dup(ofd, 1);
- /* stderr shines through */
- execl("/bin/rc", "rc", "-c", cmd, nil);
- break;
- }
-
- if(b)
- Bterm(b);
- seek(ofd, 0, 0);
- b = emalloc(sizeof(Biobuf));
- Binit(b, ofd, OREAD);
-
- return initps(b, argc, argv, nil, 0);
-}
-
-Document*
-initdvi(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
-{
- int fd;
- char *name;
- char cmd[256];
- char fdbuf[20];
-
- /*
- * Stupid DVIPS won't take standard input.
- */
- if(b == nil){ /* standard input; spool to disk (ouch) */
- fd = spooltodisk(buf, nbuf, &name);
- sprint(fdbuf, "/fd/%d", fd);
- b = Bopen(fdbuf, OREAD);
- if(b == nil){
- fprint(2, "cannot open disk spool file\n");
- wexits("Bopen temp");
- }
- argv = &name;
- argc = 1;
- }
-
- snprint(cmd, sizeof cmd, "dvips -Pps -r0 -q1 -f1 '%s'", argv[0]);
- return initfilt(b, argc, argv, buf, nbuf, "dvi", cmd, 0);
-}
-
-Document*
-inittroff(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
-{
- return initfilt(b, argc, argv, buf, nbuf, "troff", "lp -dstdout", 1);
-}
-
-Document*
-initmsdoc(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
-{
- return initfilt(b, argc, argv, buf, nbuf, "microsoft office", "doc2ps", 1);
-}
--- a/sys/src/cmd/page/gfx.c
+++ /dev/null
@@ -1,332 +1,0 @@
-/*
- * graphics file reading for page
- */
-
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <bio.h>
-#include "page.h"
-
-typedef struct Convert Convert;
-typedef struct GfxInfo GfxInfo;
-typedef struct Graphic Graphic;
-
-struct Convert {
- char *name;
- char *cmd;
- char *truecmd; /* cmd for true color */
-};
-
-struct GfxInfo {
- Graphic *g;
-};
-
-struct Graphic {
- int type;
- char *name;
- uchar *buf; /* if stdin */
- int nbuf;
-};
-
-enum {
- Ipic,
- Itiff,
- Ijpeg,
- Igif,
- Iinferno,
- Ifax,
- Icvt2pic,
- Iplan9bm,
- Iccittg4,
- Ippm,
- Ipng,
- Iyuv,
- Ibmp,
-};
-
-/*
- * N.B. These commands need to read stdin if %a is replaced
- * with an empty string.
- */
-Convert cvt[] = {
-[Ipic] { "plan9", "fb/3to1 rgbv %a |fb/pcp -tplan9" },
-[Itiff] { "tiff", "fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" },
-[Iplan9bm] { "plan9bm", nil },
-[Ijpeg] { "jpeg", "jpg -9 %a", "jpg -t9 %a" },
-[Igif] { "gif", "gif -9 %a", "gif -t9 %a" },
-[Iinferno] { "inferno", nil },
-[Ifax] { "fax", "aux/g3p9bit -g %a" },
-[Icvt2pic] { "unknown", "fb/cvt2pic %a |fb/3to1 rgbv" },
-[Ippm] { "ppm", "ppm -9 %a", "ppm -t9 %a" },
-/* ``temporary'' hack for hobby */
-[Iccittg4] { "ccitt-g4", "cat %a|rx nslocum /usr/lib/ocr/bin/bcp -M|fb/pcp -tcompressed -l0" },
-[Ipng] { "png", "png -9 %a", "png -t9 %a" },
-[Iyuv] { "yuv", "yuv -9 %a", "yuv -t9 %a" },
-[Ibmp] { "bmp", "bmp -9 %a", "bmp -t9 %a" },
-};
-
-static Image* convert(Graphic*);
-static Image* gfxdrawpage(Document *d, int page);
-static char* gfxpagename(Document*, int);
-static int spawnrc(char*, uchar*, int);
-static void waitrc(void);
-static int spawnpost(int);
-static int addpage(Document*, char*);
-static int rmpage(Document*, int);
-static int genaddpage(Document*, char*, uchar*, int);
-
-static char*
-gfxpagename(Document *doc, int page)
-{
- GfxInfo *gfx = doc->extra;
- return gfx->g[page].name;
-}
-
-static Image*
-gfxdrawpage(Document *doc, int page)
-{
- GfxInfo *gfx = doc->extra;
- return convert(gfx->g+page);
-}
-
-Document*
-initgfx(Biobuf*, int argc, char **argv, uchar *buf, int nbuf)
-{
- GfxInfo *gfx;
- Document *doc;
- int i;
-
- doc = emalloc(sizeof(*doc));
- gfx = emalloc(sizeof(*gfx));
- gfx->g = nil;
-
- doc->npage = 0;
- doc->drawpage = gfxdrawpage;
- doc->pagename = gfxpagename;
- doc->addpage = addpage;
- doc->rmpage = rmpage;
- doc->extra = gfx;
- doc->fwdonly = 0;
-
- fprint(2, "reading through graphics...\n");
- if(argc==0 && buf)
- genaddpage(doc, nil, buf, nbuf);
- else{
- for(i=0; i<argc; i++)
- if(addpage(doc, argv[i]) < 0)
- fprint(2, "warning: not including %s: %r\n", argv[i]);
- }
-
- return doc;
-}
-
-static int
-genaddpage(Document *doc, char *name, uchar *buf, int nbuf)
-{
- Graphic *g;
- GfxInfo *gfx;
- Biobuf *b;
- uchar xbuf[32];
- int i, l;
-
- l = 0;
- gfx = doc->extra;
-
- assert((name == nil) ^ (buf == nil));
- assert(name != nil || doc->npage == 0);
-
- for(i=0; i<doc->npage; i++)
- if(strcmp(gfx->g[i].name, name) == 0)
- return i;
-
- if(name){
- l = strlen(name);
- if((b = Bopen(name, OREAD)) == nil) {
- werrstr("Bopen: %r");
- return -1;
- }
-
- if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) {
- werrstr("short read: %r");
- return -1;
- }
- Bterm(b);
- buf = xbuf;
- nbuf = sizeof xbuf;
- }
-
-
- gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g)));
- g = &gfx->g[doc->npage];
-
- memset(g, 0, sizeof *g);
- if(memcmp(buf, "GIF", 3) == 0)
- g->type = Igif;
- else if(memcmp(buf, "\111\111\052\000", 4) == 0)
- g->type = Itiff;
- else if(memcmp(buf, "\115\115\000\052", 4) == 0)
- g->type = Itiff;
- else if(memcmp(buf, "\377\330\377", 3) == 0)
- g->type = Ijpeg;
- else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0)
- g->type = Ipng;
- else if(memcmp(buf, "compressed\n", 11) == 0)
- g->type = Iinferno;
- else if(memcmp(buf, "\0PC Research, Inc", 17) == 0)
- g->type = Ifax;
- else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0)
- g->type = Ifax;
- else if(memcmp(buf, "II*", 3) == 0)
- g->type = Ifax;
- else if(memcmp(buf, "TYPE=ccitt-g4", 13) == 0)
- g->type = Iccittg4;
- else if(memcmp(buf, "TYPE=", 5) == 0)
- g->type = Ipic;
- else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9')
- g->type = Ippm;
- else if(memcmp(buf, "BM", 2) == 0)
- g->type = Ibmp;
- else if(memcmp(buf, " ", 10) == 0 &&
- '0' <= buf[10] && buf[10] <= '9' &&
- buf[11] == ' ')
- g->type = Iplan9bm;
- else if(strtochan((char*)buf) != 0)
- g->type = Iplan9bm;
- else if (l > 4 && strcmp(name + l -4, ".yuv") == 0)
- g->type = Iyuv;
- else
- g->type = Icvt2pic;
-
- if(name)
- g->name = estrdup(name);
- else{
- g->name = estrdup("stdin"); /* so it can be freed */
- g->buf = buf;
- g->nbuf = nbuf;
- }
-
- if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name);
- return doc->npage++;
-}
-
-static int
-addpage(Document *doc, char *name)
-{
- return genaddpage(doc, name, nil, 0);
-}
-
-static int
-rmpage(Document *doc, int n)
-{
- int i;
- GfxInfo *gfx;
-
- if(n < 0 || n >= doc->npage)
- return -1;
-
- gfx = doc->extra;
- doc->npage--;
- free(gfx->g[n].name);
-
- for(i=n; i<doc->npage; i++)
- gfx->g[i] = gfx->g[i+1];
-
- if(n < doc->npage)
- return n;
- if(n == 0)
- return 0;
- return n-1;
-}
-
-
-static Image*
-convert(Graphic *g)
-{
- int fd;
- Convert c;
- char *cmd;
- char *name, buf[1000];
- Image *im;
- int rcspawned = 0;
- Waitmsg *w;
-
- c = cvt[g->type];
- if(c.cmd == nil) {
- if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name);
- if(g->buf == nil){ /* not stdin */
- fd = open(g->name, OREAD);
- if(fd < 0) {
- fprint(2, "cannot open file: %r\n");
- wexits("open");
- }
- }else
- fd = stdinpipe(g->buf, g->nbuf);
- } else {
- cmd = c.cmd;
- if(truecolor && c.truecmd)
- cmd = c.truecmd;
-
- if(g->buf != nil) /* is stdin */
- name = "";
- else
- name = g->name;
- if(strlen(cmd)+strlen(name) > sizeof buf) {
- fprint(2, "command too long\n");
- wexits("convert");
- }
- snprint(buf, sizeof buf, cmd, name);
- if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name);
- fd = spawnrc(buf, g->buf, g->nbuf);
- rcspawned++;
- if(fd < 0) {
- fprint(2, "cannot spawn converter: %r\n");
- wexits("convert");
- }
- }
-
- im = readimage(display, fd, 0);
- if(im == nil) {
- fprint(2, "warning: couldn't read image: %r\n");
- }
- close(fd);
-
- /* for some reason rx doesn't work well with wait */
- /* for some reason 3to1 exits on success with a non-null status of |3to1 */
- if(rcspawned && g->type != Iccittg4) {
- if((w=wait())!=nil && w->msg[0] && !strstr(w->msg, "3to1"))
- fprint(2, "slave wait error: %s\n", w->msg);
- free(w);
- }
- return im;
-}
-
-static int
-spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf)
-{
- int pfd[2];
- int pid;
-
- if(chatty) fprint(2, "spawning(%s)...", cmd);
-
- if(pipe(pfd) < 0)
- return -1;
- if((pid = fork()) < 0)
- return -1;
-
- if(pid == 0) {
- close(pfd[1]);
- if(stdinbuf)
- dup(stdinpipe(stdinbuf, nstdinbuf), 0);
- else
- dup(open("/dev/null", OREAD), 0);
- dup(pfd[0], 1);
- //dup(pfd[0], 2);
- execl("/bin/rc", "rc", "-c", cmd, nil);
- wexits("exec");
- }
- close(pfd[0]);
- return pfd[1];
-}
-
--- a/sys/src/cmd/page/gs.c
+++ /dev/null
@@ -1,342 +1,0 @@
-/*
- * gs interface for page.
- * ps.c and pdf.c both use these routines.
- * a caveat: if you run more than one gs, only the last
- * one gets killed by killgs
- */
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <bio.h>
-#include "page.h"
-
-static int gspid; /* globals for atexit */
-static int gsfd;
-static void killgs(void);
-
-static void
-killgs(void)
-{
- char tmpfile[100];
-
- close(gsfd);
- postnote(PNGROUP, getpid(), "die");
-
- /*
- * from ghostscript's use.txt:
- * ``Ghostscript currently doesn't do a very good job of deleting temporary
- * files when it exits; you may have to delete them manually from time to
- * time.''
- */
- sprint(tmpfile, "/tmp/gs_%.5da", (gspid+300000)%100000);
- if(chatty) fprint(2, "remove %s...\n", tmpfile);
- remove(tmpfile);
- sleep(100);
- postnote(PNPROC, gspid, "die yankee pig dog");
-}
-
-int
-spawnwriter(GSInfo *g, Biobuf *b)
-{
- char buf[4096];
- int n;
- int fd;
-
- switch(fork()){
- case -1: return -1;
- case 0: break;
- default: return 0;
- }
-
- Bseek(b, 0, 0);
- fd = g->gsfd;
- while((n = Bread(b, buf, sizeof buf)) > 0)
- write(fd, buf, n);
- fprint(fd, "(/fd/3) (w) file dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring flushfile\n");
- _exits(0);
- return -1;
-}
-
-int
-spawnreader(int fd)
-{
- int n, pfd[2];
- char buf[1024];
-
- if(pipe(pfd)<0)
- return -1;
- switch(fork()){
- case -1:
- return -1;
- case 0:
- break;
- default:
- close(pfd[0]);
- return pfd[1];
- }
-
- close(pfd[1]);
- switch(fork()){
- case -1:
- wexits("fork failed");
- case 0:
- while((n=read(fd, buf, sizeof buf)) > 0) {
- write(1, buf, n);
- write(pfd[0], buf, n);
- }
- break;
- default:
- while((n=read(pfd[0], buf, sizeof buf)) > 0) {
- write(1, buf, n);
- write(fd, buf, n);
- }
- break;
- }
- postnote(PNGROUP, getpid(), "i'm die-ing");
- _exits(0);
- return -1;
-}
-
-void
-spawnmonitor(int fd)
-{
- char buf[4096];
- char *xbuf;
- int n;
- int out;
- int first;
-
- switch(rfork(RFFDG|RFNOTEG|RFPROC)){
- case -1:
- default:
- return;
-
- case 0:
- break;
- }
-
- out = open("/dev/cons", OWRITE);
- if(out < 0)
- out = 2;
-
- xbuf = buf; /* for ease of acid */
- first = 1;
- while((n = read(fd, xbuf, sizeof buf)) > 0){
- if(first){
- first = 0;
- fprint(2, "Ghostscript Error:\n");
- }
- write(out, xbuf, n);
- alarm(500);
- }
- _exits(0);
-}
-
-int
-spawngs(GSInfo *g, char *safer)
-{
- char *args[16];
- char tb[32], gb[32];
- int i, nargs;
- int devnull;
- int stdinout[2];
- int dataout[2];
- int errout[2];
-
- /*
- * spawn gs
- *
- * gs's standard input is fed from stdinout.
- * gs output written to fd-2 (i.e. output we generate intentionally) is fed to stdinout.
- * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout.
- * gs data output is written to fd 3, which is dataout.
- */
- if(pipe(stdinout) < 0 || pipe(dataout)<0 || pipe(errout)<0)
- return -1;
-
- nargs = 0;
- args[nargs++] = "gs";
- args[nargs++] = "-dNOPAUSE";
- args[nargs++] = safer;
- args[nargs++] = "-sDEVICE=plan9";
- args[nargs++] = "-sOutputFile=/fd/3";
- args[nargs++] = "-dQUIET";
- args[nargs++] = "-r100";
- sprint(tb, "-dTextAlphaBits=%d", textbits);
- sprint(gb, "-dGraphicsAlphaBits=%d", gfxbits);
- if(textbits)
- args[nargs++] = tb;
- if(gfxbits)
- args[nargs++] = gb;
- args[nargs++] = "-";
- args[nargs] = nil;
-
- gspid = fork();
- if(gspid == 0) {
- close(stdinout[1]);
- close(dataout[1]);
- close(errout[1]);
-
- /*
- * Horrible problem: we want to dup fd's 0-4 below,
- * but some of the source fd's might have those small numbers.
- * So we need to reallocate those. In order to not step on
- * anything else, we'll dup the fd's to higher ones using
- * dup(x, -1), but we need to use up the lower ones first.
- */
- while((devnull = open("/dev/null", ORDWR)) < 5)
- ;
-
- stdinout[0] = dup(stdinout[0], -1);
- errout[0] = dup(errout[0], -1);
- dataout[0] = dup(dataout[0], -1);
-
- dup(stdinout[0], 0);
- dup(errout[0], 1);
- dup(devnull, 2); /* never anything useful */
- dup(dataout[0], 3);
- dup(stdinout[0], 4);
- for(i=5; i<20; i++)
- close(i);
- exec("/bin/gs", args);
- wexits("exec");
- }
- close(stdinout[0]);
- close(errout[0]);
- close(dataout[0]);
- atexit(killgs);
-
- if(teegs)
- stdinout[1] = spawnreader(stdinout[1]);
-
- gsfd = g->gsfd = stdinout[1];
- g->gsdfd = dataout[1];
- g->gspid = gspid;
-
- spawnmonitor(errout[1]);
- Binit(&g->gsrd, g->gsfd, OREAD);
-
- gscmd(g, "/PAGEOUT (/fd/4) (w) file def\n");
- gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n");
- waitgs(g);
-
- return 0;
-}
-
-int
-gscmd(GSInfo *gs, char *fmt, ...)
-{
- char buf[1024];
- int n;
-
- va_list v;
- va_start(v, fmt);
- n = vseprint(buf, buf+sizeof buf, fmt, v) - buf;
- if(n <= 0)
- return n;
-
- if(chatty) {
- fprint(2, "cmd: ");
- write(2, buf, n);
- }
-
- if(write(gs->gsfd, buf, n) != 0)
- return -1;
-
- return n;
-}
-
-/*
- * set the dimensions of the bitmap we expect to get back from GS.
- */
-void
-setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape)
-{
- Rectangle pbox;
-
- if(chatty)
- fprint(2, "setdim: bbox=%R\n", bbox);
-
- if(ppi)
- gs->ppi = ppi;
-
- gscmd(gs, "mark\n");
- if(ppi)
- gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi);
-
- if(!Dx(bbox))
- bbox = Rect(0, 0, 612, 792); /* 8½×11 */
-
- switch(landscape){
- case 0:
- pbox = bbox;
- break;
- case 1:
- pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x);
- break;
- }
- gscmd(gs, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox));
- gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y);
- gscmd(gs, "currentdevice putdeviceprops pop\n");
- gscmd(gs, "/#copies 1 store\n");
-
- if(!eqpt(bbox.min, ZP))
- gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y);
-
- switch(landscape){
- case 0:
- break;
- case 1:
- gscmd(gs, "%d 0 translate\n", Dy(bbox));
- gscmd(gs, "90 rotate\n");
- break;
- }
-
- waitgs(gs);
-}
-
-void
-waitgs(GSInfo *gs)
-{
- /* we figure out that gs is done by telling it to
- * print something and waiting until it does.
- */
- char *p;
- Biobuf *b = &gs->gsrd;
- uchar buf[1024];
- int n;
-
-// gscmd(gs, "(\\n**bstack\\n) print flush\n");
-// gscmd(gs, "stack flush\n");
-// gscmd(gs, "(**estack\\n) print flush\n");
- gscmd(gs, "(\\n//GO.SYSIN DD\\n) PAGE==\n");
-
- alarm(300*1000);
- for(;;) {
- p = Brdline(b, '\n');
- if(p == nil) {
- n = Bbuffered(b);
- if(n <= 0)
- break;
- if(n > sizeof buf)
- n = sizeof buf;
- Bread(b, buf, n);
- continue;
- }
- p[Blinelen(b)-1] = 0;
- if(chatty) fprint(2, "p: ");
- if(chatty) write(2, p, Blinelen(b)-1);
- if(chatty) fprint(2, "\n");
- if(strstr(p, "Error:")) {
- alarm(0);
- fprint(2, "ghostscript error: %s\n", p);
- wexits("gs error");
- }
-
- if(strstr(p, "//GO.SYSIN DD")) {
- break;
- }
- }
- alarm(0);
-}
--- a/sys/src/cmd/page/mkfile
+++ /dev/null
@@ -1,36 +1,0 @@
-</$objtype/mkfile
-
-TARG=page
-
-HFILES=page.h
-OFILES=\
- cache.$O\
- filter.$O\
- gfx.$O\
- gs.$O\
- page.$O\
- pdf.$O\
- ps.$O\
- rotate.$O\
- util.$O\
- view.$O\
-
-LIB=/$objtype/lib/libdraw.a
-
-UPDATE=\
- mkfile\
- ${OFILES:%.$O=%.c}\
- pdfprolog.ps\
- $HFILES\
- /sys/man/1/page\
- /386/bin/page\
-
-</sys/src/cmd/mkone
-
-BIN=/$objtype/bin
-
-pdfprolog.c: pdfprolog.ps
- cat pdfprolog.ps | sed 's/.*/"&\\n"/g' >pdfprolog.c
-
-pdf.$O: pdfprolog.c
-
--- a/sys/src/cmd/page/nrotate.c
+++ /dev/null
@@ -1,277 +1,0 @@
-/*
- * Rotate an image 180° in O(log Dx + log Dy)
- * draw calls, using an extra buffer the same size
- * as the image.
- *
- * The basic concept is that you can invert an array by
- * inverting the top half, inverting the bottom half, and
- * then swapping them.
- *
- * This is usually overkill, but it speeds up slow remote
- * connections quite a bit.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <draw.h>
-#include <event.h>
-#include "page.h"
-
-int ndraw = 0;
-
-enum {
- Xaxis,
- Yaxis,
-};
-
-static void reverse(Image*, Image*, int);
-static void shuffle(Image*, Image*, int, int, Image*, int, int);
-static void writefile(char *name, Image *im, int gran);
-static void halvemaskdim(Image*);
-static void swapranges(Image*, Image*, int, int, int, int);
-
-/*
- * Rotate the image 180° by reflecting first
- * along the X axis, and then along the Y axis.
- */
-void
-rot180(Image *img)
-{
- Image *tmp;
-
- tmp = xallocimage(display, img->r, img->chan, 0, DNofill);
- if(tmp == nil)
- return;
-
- reverse(img, tmp, Xaxis);
- reverse(img, tmp, Yaxis);
-
- freeimage(tmp);
-}
-
-Image *mtmp;
-
-static void
-reverse(Image *img, Image *tmp, int axis)
-{
- Image *mask;
- Rectangle r;
- int i, d;
-
- /*
- * We start by swapping large chunks at a time.
- * The chunk size should be the largest power of
- * two that fits in the dimension.
- */
- d = axis==Xaxis ? Dx(img) : Dy(img);
- for(i = 1; i*2 <= d; i *= 2)
- ;
-
- r = axis==Xaxis ? Rect(0,0, i,100) : Rect(0,0, 100,i);
- mask = xallocimage(display, r, GREY1, 1, DTransparent);
- mtmp = xallocimage(display, r, GREY1, 1, DTransparent);
-
- /*
- * Now color the bottom (or left) half of the mask opaque.
- */
- if(axis==Xaxis)
- r.max.x /= 2;
- else
- r.max.y /= 2;
-
- draw(mask, r, display->opaque, nil, ZP);
- writefile("mask", mask, i);
-
- /*
- * Shuffle will recur, shuffling the pieces as necessary
- * and making the mask a finer and finer grating.
- */
- shuffle(img, tmp, axis, d, mask, i, 0);
-
- freeimage(mask);
-}
-
-/*
- * Shuffle the image by swapping pieces of size maskdim.
- */
-static void
-shuffle(Image *img, Image *tmp, int axis, int imgdim, Image *mask, int maskdim)
-{
- int slop;
-
- if(maskdim == 0)
- return;
-
- /*
- * Figure out how much will be left over that needs to be
- * shifted specially to the bottom.
- */
- slop = imgdim % maskdim;
-
- /*
- * Swap adjacent grating lines as per mask.
- */
- swapadjacent(img, tmp, axis, imgdim - slop, mask, maskdim);
-
- /*
- * Calculate the mask with gratings half as wide and recur.
- */
- halvemaskdim(mask, maskdim, axis);
- writefile("mask", mask, maskdim/2);
-
- shuffle(img, tmp, axis, imgdim, mask, maskdim/2);
-
- /*
- * Move the slop down to the bottom of the image.
- */
- swapranges(img, tmp, 0, imgdim-slop, imgdim, axis);
- moveup(im, tmp, lastnn, nn, n, axis);
-}
-
-/*
- * Halve the grating period in the mask.
- * The grating currently looks like
- * ####____####____####____####____
- * where #### is opacity.
- *
- * We want
- * ##__##__##__##__##__##__##__##__
- * which is achieved by shifting the mask
- * and drawing on itself through itself.
- * Draw doesn't actually allow this, so
- * we have to copy it first.
- *
- * ####____####____####____####____ (dst)
- * + ____####____####____####____#### (src)
- * in __####____####____####____####__ (mask)
- * ===========================================
- * ##__##__##__##__##__##__##__##__
- */
-static void
-halvemaskdim(Image *m, int maskdim, int axis)
-{
- Point δ;
-
- δ = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim);
- draw(mtmp, mtmp->r, mask, nil, mask->r.min);
- gendraw(mask, mask->r, mtmp, δ, mtmp, divpt(δ,2));
- writefile("mask", mask, maskdim/2);
-}
-
-/*
- * Swap the regions [a,b] and [b,c]
- */
-static void
-swapranges(Image *img, Image *tmp, int a, int b, int c, int axis)
-{
- Rectangle r;
- Point δ;
-
- if(a == b || b == c)
- return;
-
- writefile("swap", img, 0);
- draw(tmp, tmp->r, im, nil, im->r.min);
-
- /* [a,a+(c-b)] gets [b,c] */
- r = img->r;
- if(axis==Xaxis){
- δ = Pt(1,0);
- r.min.x = img->r.min.x + a;
- r.max.x = img->r.min.x + a + (c-b);
- }else{
- δ = Pt(0,1);
- r.min.y = img->r.min.y + a;
- r.max.y = img->r.min.y + a + (c-b);
- }
- draw(img, r, tmp, nil, addpt(tmp->r.min, mulpt(δ, b)));
-
- /* [a+(c-b), c] gets [a,b] */
- r = img->r;
- if(axis==Xaxis){
- r.min.x = img->r.min.x + a + (c-b);
- r.max.x = img->r.min.x + c;
- }else{
- r.min.y = img->r.min.y + a + (c-b);
- r.max.y = img->r.min.y + c;
- }
- draw(img, r, tmp, nil, addpt(tmp->r.min, mulpt(δ, a)));
- writefile("swap", img, 1);
-}
-
-/*
- * Swap adjacent regions as specified by the grating.
- * We do this by copying the image through the mask twice,
- * once aligned with the grading and once 180° out of phase.
- */
-static void
-swapadjacent(Image *img, Image *tmp, int axis, int imgdim, Image *mask, int maskdim)
-{
- Point δ;
- Rectangle r0, r1;
-
- δ = axis==Xaxis ? Pt(1,0) : Pt(0,1);
-
- r0 = img->r;
- r1 = img->r;
- switch(axis){
- case Xaxis:
- r0.max.x = imgdim;
- r1.min.x = imgdim;
- break;
- case Yaxis:
- r0.max.y = imgdim;
- r1.min.y = imgdim;
- }
-
- /*
- * r0 is the lower rectangle, while r1 is the upper one.
- */
- draw(tmp, tmp->r, img, nil,
-}
-
-void
-interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
-{
- Point p0, p1;
- Rectangle r0, r1;
-
- r0 = im->r;
- r1 = im->r;
- switch(axis) {
- case Xaxis:
- r0.max.x = n;
- r1.min.x = n;
- p0 = (Point){gran, 0};
- p1 = (Point){-gran, 0};
- break;
- case Yaxis:
- r0.max.y = n;
- r1.min.y = n;
- p0 = (Point){0, gran};
- p1 = (Point){0, -gran};
- break;
- }
-
- draw(tmp, im->r, im, display->black, im->r.min);
- gendraw(im, r0, tmp, p0, mask, mask->r.min);
- gendraw(im, r0, tmp, p1, mask, p1);
-}
-
-
-static void
-writefile(char *name, Image *im, int gran)
-{
- static int c = 100;
- int fd;
- char buf[200];
-
- snprint(buf, sizeof buf, "%d%s%d", c++, name, gran);
- fd = create(buf, OWRITE, 0666);
- if(fd < 0)
- return;
- writeimage(fd, im, 0);
- close(fd);
-}
-
--- a/sys/src/cmd/page/page.c
+++ /dev/null
@@ -1,238 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <bio.h>
-#include "page.h"
-
-int resizing;
-int mknewwindow;
-int doabort;
-int chatty;
-int reverse = -1;
-int goodps = 1;
-int ppi = 100;
-int teegs = 0;
-int truetoboundingbox;
-int textbits=4, gfxbits=4;
-int wctlfd = -1;
-int stdinfd;
-int truecolor;
-int imagemode;
-int notewatcher;
-int notegp;
-
-int
-watcher(void*, char *x)
-{
- if(strcmp(x, "die") != 0)
- postnote(PNGROUP, notegp, x);
- _exits(0);
- return 0;
-}
-
-int
-bell(void *u, char *x)
-{
- if(x && strcmp(x, "hangup") == 0)
- _exits(0);
-
- if(x && strstr(x, "die") == nil)
- fprint(2, "postnote %d: %s\n", getpid(), x);
-
- /* alarms come from the gs monitor */
- if(x && strstr(x, "alarm")){
- postnote(PNGROUP, getpid(), "die (gs error)");
- postnote(PNPROC, notewatcher, "die (gs error)");
- }
-
- /* function mentions u so that it's in the stack trace */
- if((u == nil || u != x) && doabort)
- abort();
-
-/* fprint(2, "exiting %d\n", getpid()); */
- wexits("note");
- return 0;
-}
-
-static int
-afmt(Fmt *fmt)
-{
- char *s;
-
- s = va_arg(fmt->args, char*);
- if(s == nil || s[0] == '\0')
- return fmtstrcpy(fmt, "");
- else
- return fmtprint(fmt, "%#q", s);
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: page [-biRrw] [-p ppi] file...\n");
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- Document *doc;
- Biobuf *b;
- enum { Ninput = 16 };
- uchar buf[Ninput+1];
- int readstdin;
-
- ARGBEGIN{
- /* "temporary" debugging options */
- case 'P':
- goodps = 0;
- break;
- case 'v':
- chatty++;
- break;
- case 'V':
- teegs++;
- break;
- case 'a':
- doabort++;
- break;
- case 'T':
- textbits = atoi(EARGF(usage()));
- gfxbits = atoi(EARGF(usage()));
- break;
-
- /* real options */
- case 'R':
- resizing = 1;
- break;
- case 'r':
- reverse = 1;
- break;
- case 'p':
- ppi = atoi(EARGF(usage()));
- break;
- case 'b':
- truetoboundingbox = 1;
- break;
- case 'w':
- mknewwindow = 1;
- resizing = 1;
- break;
- case 'i':
- imagemode = 1;
- break;
- default:
- usage();
- }ARGEND;
-
- notegp = getpid();
-
- switch(notewatcher = fork()){
- case -1:
- sysfatal("fork");
- exits(0);
- default:
- break;
- case 0:
- atnotify(watcher, 1);
- for(;;)
- sleep(1000);
- /* not reached */
- }
-
- rfork(RFNOTEG);
- atnotify(bell, 1);
-
- readstdin = 0;
- if(imagemode == 0 && argc == 0){
- readstdin = 1;
- stdinfd = dup(0, -1);
- close(0);
- open("/dev/cons", OREAD);
- }
-
- quotefmtinstall();
- fmtinstall('a', afmt);
-
- fmtinstall('R', Rfmt);
- fmtinstall('P', Pfmt);
- if(mknewwindow)
- newwin();
-
- if(readstdin){
- b = nil;
- if(readn(stdinfd, buf, Ninput) != Ninput){
- fprint(2, "page: short read reading %s\n", argv[0]);
- wexits("read");
- }
- }else if(argc != 0){
- if(!(b = Bopen(argv[0], OREAD))) {
- fprint(2, "page: cannot open \"%s\"\n", argv[0]);
- wexits("open");
- }
-
- if(Bread(b, buf, Ninput) != Ninput) {
- fprint(2, "page: short read reading %s\n", argv[0]);
- wexits("read");
- }
- }else
- b = nil;
-
- buf[Ninput] = '\0';
- if(imagemode)
- doc = initgfx(nil, 0, nil, nil, 0);
- else if(strncmp((char*)buf, "%PDF-", 5) == 0)
- doc = initpdf(b, argc, argv, buf, Ninput);
- else if(strncmp((char*)buf, "\x04%!", 2) == 0)
- doc = initps(b, argc, argv, buf, Ninput);
- else if(buf[0] == '\x1B' && strstr((char*)buf, "@PJL"))
- doc = initps(b, argc, argv, buf, Ninput);
- else if(strncmp((char*)buf, "%!", 2) == 0)
- doc = initps(b, argc, argv, buf, Ninput);
- else if(strcmp((char*)buf, "\xF7\x02\x01\x83\x92\xC0\x1C;") == 0)
- doc = initdvi(b, argc, argv, buf, Ninput);
- else if(strncmp((char*)buf, "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", 8) == 0)
- doc = initmsdoc(b, argc, argv, buf, Ninput);
- else if(strncmp((char*)buf, "x T ", 4) == 0)
- doc = inittroff(b, argc, argv, buf, Ninput);
- else {
- if(ppi != 100) {
- fprint(2, "page: you can't specify -p with graphic files\n");
- wexits("-p and graphics");
- }
- doc = initgfx(b, argc, argv, buf, Ninput);
- }
-
- if(doc == nil) {
- fprint(2, "page: error reading file: %r\n");
- wexits("document init");
- }
-
- if(doc->npage < 1 && !imagemode) {
- fprint(2, "page: no pages found?\n");
- wexits("pagecount");
- }
-
- if(reverse == -1) /* neither cmdline nor ps reader set it */
- reverse = 0;
-
- if(initdraw(0, 0, "page") < 0){
- fprint(2, "page: initdraw failed: %r\n");
- wexits("initdraw");
- }
- display->locking = 1;
-
- truecolor = screen->depth > 8;
- viewer(doc);
- wexits(0);
-}
-
-void
-wexits(char *s)
-{
- if(s && *s && strcmp(s, "note") != 0 && mknewwindow)
- sleep(10*1000);
- postnote(PNPROC, notewatcher, "die");
- exits(s);
-}
--- a/sys/src/cmd/page/page.h
+++ /dev/null
@@ -1,85 +1,0 @@
-typedef struct Document Document;
-
-struct Document {
- char *docname;
- int npage;
- int fwdonly;
- char* (*pagename)(Document*, int);
- Image* (*drawpage)(Document*, int);
- int (*addpage)(Document*, char*);
- int (*rmpage)(Document*, int);
- Biobuf *b;
- void *extra;
-};
-
-void *emalloc(int);
-void *erealloc(void*, int);
-char *estrdup(char*);
-int spawncmd(char*, char **, int, int, int);
-
-int spooltodisk(uchar*, int, char**);
-int stdinpipe(uchar*, int);
-Document *initps(Biobuf*, int, char**, uchar*, int);
-Document *initpdf(Biobuf*, int, char**, uchar*, int);
-Document *initgfx(Biobuf*, int, char**, uchar*, int);
-Document *inittroff(Biobuf*, int, char**, uchar*, int);
-Document *initdvi(Biobuf*, int, char**, uchar*, int);
-Document *initmsdoc(Biobuf*, int, char**, uchar*, int);
-
-void viewer(Document*);
-extern Cursor reading;
-extern int chatty;
-extern int goodps;
-extern int textbits, gfxbits;
-extern int reverse;
-extern int clean;
-extern int ppi;
-extern int teegs;
-extern int truetoboundingbox;
-extern int wctlfd;
-extern int resizing;
-extern int mknewwindow;
-
-void rot180(Image*);
-Image *rot90(Image*);
-Image *rot270(Image*);
-Image *resample(Image*, Image*);
-
-/* ghostscript interface shared by ps, pdf */
-typedef struct GSInfo GSInfo;
-struct GSInfo {
- int gsfd;
- Biobuf gsrd;
- int gspid;
- int gsdfd;
- int ppi;
-};
-void waitgs(GSInfo*);
-int gscmd(GSInfo*, char*, ...);
-int spawngs(GSInfo*, char*);
-void setdim(GSInfo*, Rectangle, int, int);
-int spawnwriter(GSInfo*, Biobuf*);
-Rectangle screenrect(void);
-void newwin(void);
-void zerox(void);
-Rectangle winrect(void);
-void resize(int, int);
-int max(int, int);
-int min(int, int);
-void wexits(char*);
-Image* xallocimage(Display*, Rectangle, ulong, int, ulong);
-int bell(void*, char*);
-int opentemp(char *template);
-Image* cachedpage(Document*, int, int);
-void cacheflush(void);
-
-extern int stdinfd;
-extern int truecolor;
-
-/* BUG BUG BUG BUG BUG: cannot use new draw operations in drawterm,
- * or in vncs, and there is a bug in the kernel for copying images
- * from cpu memory -> video memory (memmove is not being used).
- * until all that is settled, ignore the draw operators.
- */
-#define drawop(a,b,c,d,e,f) draw(a,b,c,d,e)
-#define gendrawop(a,b,c,d,e,f,g) gendraw(a,b,c,d,e,f)
--- a/sys/src/cmd/page/pdf.c
+++ /dev/null
@@ -1,153 +1,0 @@
-/*
- * pdf.c
- *
- * pdf file support for page
- */
-
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <bio.h>
-#include "page.h"
-
-typedef struct PDFInfo PDFInfo;
-struct PDFInfo {
- GSInfo;
- Rectangle *pagebbox;
-};
-
-static Image* pdfdrawpage(Document *d, int page);
-static char* pdfpagename(Document*, int);
-
-char *pdfprolog =
-#include "pdfprolog.c"
- ;
-
-Rectangle
-pdfbbox(GSInfo *gs)
-{
- char *p;
- char *f[4];
- Rectangle r;
-
- r = Rect(0,0,0,0);
- waitgs(gs);
- gscmd(gs, "/CropBox knownoget {} {[0 0 0 0]} ifelse PAGE==\n");
- p = Brdline(&gs->gsrd, '\n');
- p[Blinelen(&gs->gsrd)-1] ='\0';
- if(p[0] != '[')
- return r;
- if(tokenize(p+1, f, 4) != 4)
- return r;
- r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3]));
- waitgs(gs);
- return r;
-}
-
-Document*
-initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
-{
- Document *d;
- PDFInfo *pdf;
- char *p;
- char *fn;
- char fdbuf[20];
- int fd;
- int i, npage;
- Rectangle bbox;
-
- if(argc > 1) {
- fprint(2, "can only view one pdf file at a time\n");
- return nil;
- }
-
- fprint(2, "reading through pdf...\n");
- if(b == nil){ /* standard input; spool to disk (ouch) */
- fd = spooltodisk(buf, nbuf, &fn);
- sprint(fdbuf, "/fd/%d", fd);
- b = Bopen(fdbuf, OREAD);
- if(b == nil){
- fprint(2, "cannot open disk spool file\n");
- wexits("Bopen temp");
- }
- }else
- fn = argv[0];
-
- /* sanity check */
- Bseek(b, 0, 0);
- if(!(p = Brdline(b, '\n')) && !(p = Brdline(b, '\r'))) {
- fprint(2, "cannot find end of first line\n");
- wexits("initps");
- }
- if(strncmp(p, "%PDF-", 5) != 0) {
- werrstr("not pdf");
- return nil;
- }
-
- /* setup structures so one free suffices */
- p = emalloc(sizeof(*d) + sizeof(*pdf));
- d = (Document*) p;
- p += sizeof(*d);
- pdf = (PDFInfo*) p;
-
- d->extra = pdf;
- d->b = b;
- d->drawpage = pdfdrawpage;
- d->pagename = pdfpagename;
- d->fwdonly = 0;
-
- if(spawngs(pdf, "-dDELAYSAFER") < 0)
- return nil;
-
- gscmd(pdf, "%s", pdfprolog);
- waitgs(pdf);
-
- setdim(pdf, Rect(0,0,0,0), ppi, 0);
- gscmd(pdf, "(%s) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n", fn);
- gscmd(pdf, "pdfpagecount PAGE==\n");
- p = Brdline(&pdf->gsrd, '\n');
- npage = atoi(p);
- if(npage < 1) {
- fprint(2, "no pages?\n");
- return nil;
- }
- d->npage = npage;
- d->docname = argv[0];
-
- gscmd(pdf, "Trailer\n");
- bbox = pdfbbox(pdf);
-
- pdf->pagebbox = emalloc(sizeof(Rectangle)*npage);
- for(i=0; i<npage; i++) {
- gscmd(pdf, "%d pdfgetpage\n", i+1);
- pdf->pagebbox[i] = pdfbbox(pdf);
- if(Dx(pdf->pagebbox[i]) <= 0)
- pdf->pagebbox[i] = bbox;
- }
- return d;
-}
-
-static Image*
-pdfdrawpage(Document *doc, int page)
-{
- PDFInfo *pdf = doc->extra;
- Image *im;
-
- gscmd(pdf, "%d DoPDFPage\n", page+1);
- im = readimage(display, pdf->gsdfd, 0);
- if(im == nil) {
- fprint(2, "fatal: readimage error %r\n");
- wexits("readimage");
- }
- waitgs(pdf);
- return im;
-}
-
-static char*
-pdfpagename(Document*, int page)
-{
- static char str[15];
- sprint(str, "p %d", page+1);
- return str;
-}
--- a/sys/src/cmd/page/pdfprolog.ps
+++ /dev/null
@@ -1,20 +1,0 @@
-/Page null def
-/Page# 0 def
-/PDFSave null def
-/DSCPageCount 0 def
-/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def
-
-/pdfshowpage_mysetpage { % <pagedict> pdfshowpage_mysetpage <pagedict>
- dup /CropBox pget {
- boxrect
- 2 array astore /PageSize exch 4 2 roll
- 4 index /Rotate pget {
- dup 0 lt {360 add} if 90 idiv {exch neg} repeat
- } if
- exch neg exch 2 array astore /PageOffset exch
- << 5 1 roll >> setpagedevice
- } if
-} bind def
-
-GS_PDF_ProcSet begin
-pdfdict begin
--- a/sys/src/cmd/page/ps.c
+++ /dev/null
@@ -1,450 +1,0 @@
-/*
- * ps.c
- *
- * provide postscript file reading support for page
- */
-
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <bio.h>
-#include <ctype.h>
-#include "page.h"
-
-typedef struct PSInfo PSInfo;
-typedef struct Page Page;
-
-struct Page {
- char *name;
- int offset; /* offset of page beginning within file */
-};
-
-struct PSInfo {
- GSInfo;
- Rectangle bbox; /* default bounding box */
- Page *page;
- int npage;
- int clueless; /* don't know where page boundaries are */
- long psoff; /* location of %! in file */
- char ctm[256];
-};
-
-static int pswritepage(Document *d, int fd, int page);
-static Image* psdrawpage(Document *d, int page);
-static char* pspagename(Document*, int);
-
-#define R(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y
-Rectangle
-rdbbox(char *p)
-{
- Rectangle r;
- int a;
- char *f[4];
- while(*p == ':' || *p == ' ' || *p == '\t')
- p++;
- if(tokenize(p, f, 4) != 4)
- return Rect(0,0,0,0);
- r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3]));
- r = canonrect(r);
- if(Dx(r) <= 0 || Dy(r) <= 0)
- return Rect(0,0,0,0);
-
- if(truetoboundingbox)
- return r;
-
- /* initdraw not called yet, can't use %R */
- if(chatty) fprint(2, "[%d %d %d %d] -> ", R(r));
- /*
- * attempt to sniff out A4, 8½×11, others
- * A4 is 596×842
- * 8½×11 is 612×792
- */
-
- a = Dx(r)*Dy(r);
- if(a < 300*300){ /* really small, probably supposed to be */
- /* empty */
- } else if(Dx(r) <= 596 && r.max.x <= 596 && Dy(r) > 792 && Dy(r) <= 842 && r.max.y <= 842) /* A4 */
- r = Rect(0, 0, 596, 842);
- else { /* cast up to 8½×11 */
- if(Dx(r) <= 612 && r.max.x <= 612){
- r.min.x = 0;
- r.max.x = 612;
- }
- if(Dy(r) <= 792 && r.max.y <= 792){
- r.min.y = 0;
- r.max.y = 792;
- }
- }
- if(chatty) fprint(2, "[%d %d %d %d]\n", R(r));
- return r;
-}
-
-#define RECT(X) X.min.x, X.min.y, X.max.x, X.max.y
-
-int
-prefix(char *x, char *y)
-{
- return strncmp(x, y, strlen(y)) == 0;
-}
-
-/*
- * document ps is really being printed as n-up pages.
- * we need to treat every n pages as 1.
- */
-void
-repaginate(PSInfo *ps, int n)
-{
- int i, np, onp;
- Page *page;
-
- page = ps->page;
- onp = ps->npage;
- np = (ps->npage+n-1)/n;
-
- if(chatty) {
- for(i=0; i<=onp+1; i++)
- print("page %d: %d\n", i, page[i].offset);
- }
-
- for(i=0; i<np; i++)
- page[i] = page[n*i];
-
- /* trailer */
- page[np] = page[onp];
-
- /* EOF */
- page[np+1] = page[onp+1];
-
- ps->npage = np;
-
- if(chatty) {
- for(i=0; i<=np+1; i++)
- print("page %d: %d\n", i, page[i].offset);
- }
-
-}
-
-Document*
-initps(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
-{
- Document *d;
- PSInfo *ps;
- char *p;
- char *q, *r;
- char eol;
- char *nargv[1];
- char fdbuf[20];
- char tmp[32];
- int fd;
- int i;
- int incomments;
- int cantranslate;
- int trailer=0;
- int nesting=0;
- int dumb=0;
- int landscape=0;
- long psoff;
- long npage, mpage;
- Page *page;
- Rectangle bbox = Rect(0,0,0,0);
-
- if(argc > 1) {
- fprint(2, "can only view one ps file at a time\n");
- return nil;
- }
-
- fprint(2, "reading through postscript...\n");
- if(b == nil){ /* standard input; spool to disk (ouch) */
- fd = spooltodisk(buf, nbuf, nil);
- sprint(fdbuf, "/fd/%d", fd);
- b = Bopen(fdbuf, OREAD);
- if(b == nil){
- fprint(2, "cannot open disk spool file\n");
- wexits("Bopen temp");
- }
- nargv[0] = fdbuf;
- argv = nargv;
- }
-
- /* find %!, perhaps after PCL nonsense */
- Bseek(b, 0, 0);
- psoff = 0;
- eol = 0;
- for(i=0; i<16; i++){
- psoff = Boffset(b);
- if(!(p = Brdline(b, eol='\n')) && !(p = Brdline(b, eol='\r'))) {
- fprint(2, "cannot find end of first line\n");
- wexits("initps");
- }
- if(p[0]=='\x1B')
- p++, psoff++;
- if(p[0] == '%' && p[1] == '!')
- break;
- }
- if(i == 16){
- werrstr("not ps");
- return nil;
- }
-
- /* page counting */
- npage = 0;
- mpage = 16;
- page = emalloc(mpage*sizeof(*page));
- memset(page, 0, mpage*sizeof(*page));
-
- cantranslate = goodps;
- incomments = 1;
-Keepreading:
- while(p = Brdline(b, eol)) {
- if(p[0] == '%')
- if(chatty > 1) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p);
- if(npage == mpage) {
- mpage *= 2;
- page = erealloc(page, mpage*sizeof(*page));
- memset(&page[npage], 0, npage*sizeof(*page));
- }
-
- if(p[0] != '%' || p[1] != '%')
- continue;
-
- if(prefix(p, "%%BeginDocument")) {
- nesting++;
- continue;
- }
- if(nesting > 0 && prefix(p, "%%EndDocument")) {
- nesting--;
- continue;
- }
- if(nesting)
- continue;
-
- if(prefix(p, "%%EndComment")) {
- incomments = 0;
- continue;
- }
- if(reverse == -1 && prefix(p, "%%PageOrder")) {
- /* glean whether we should reverse the viewing order */
- p[Blinelen(b)-1] = 0;
- if(strstr(p, "Ascend"))
- reverse = 0;
- else if(strstr(p, "Descend"))
- reverse = 1;
- else if(strstr(p, "Special"))
- dumb = 1;
- p[Blinelen(b)-1] = '\n';
- continue;
- } else if(prefix(p, "%%Trailer")) {
- incomments = 1;
- page[npage].offset = Boffset(b)-Blinelen(b);
- trailer = 1;
- continue;
- } else if(incomments && prefix(p, "%%Orientation")) {
- if(strstr(p, "Landscape"))
- landscape = 1;
- } else if(incomments && Dx(bbox)==0 && prefix(p, q="%%BoundingBox")) {
- bbox = rdbbox(p+strlen(q)+1);
- if(chatty)
- /* can't use %R because haven't initdraw() */
- fprint(2, "document bbox [%d %d %d %d]\n",
- RECT(bbox));
- continue;
- }
-
- /*
- * If they use the initgraphics command, we can't play our translation tricks.
- */
- p[Blinelen(b)-1] = 0;
- if((q=strstr(p, "initgraphics")) && ((r=strchr(p, '%'))==nil || r > q))
- cantranslate = 0;
- p[Blinelen(b)-1] = eol;
-
- if(!prefix(p, "%%Page:"))
- continue;
-
- /*
- * figure out of the %%Page: line contains a page number
- * or some other page description to use in the menu bar.
- *
- * lines look like %%Page: x y or %%Page: x
- * we prefer just x, and will generate our
- * own if necessary.
- */
- p[Blinelen(b)-1] = 0;
- if(chatty) fprint(2, "page %s\n", p);
- r = p+7;
- while(*r == ' ' || *r == '\t')
- r++;
- q = r;
- while(*q && *q != ' ' && *q != '\t')
- q++;
- free(page[npage].name);
- if(*r) {
- if(*r == '"' && *q == '"')
- r++, q--;
- if(*q)
- *q = 0;
- page[npage].name = estrdup(r);
- *q = 'x';
- } else {
- snprint(tmp, sizeof tmp, "p %ld", npage+1);
- page[npage].name = estrdup(tmp);
- }
-
- /*
- * store the offset info for later viewing
- */
- trailer = 0;
- p[Blinelen(b)-1] = eol;
- page[npage++].offset = Boffset(b)-Blinelen(b);
- }
- if(Blinelen(b) > 0){
- fprint(2, "page: linelen %d\n", Blinelen(b));
- Bseek(b, Blinelen(b), 1);
- goto Keepreading;
- }
-
- if(Dx(bbox) == 0 || Dy(bbox) == 0)
- bbox = Rect(0,0,612,792); /* 8½×11 */
- /*
- * if we didn't find any pages, assume the document
- * is one big page
- */
- if(npage == 0) {
- dumb = 1;
- if(chatty) fprint(2, "don't know where pages are\n");
- reverse = 0;
- goodps = 0;
- trailer = 0;
- page[npage].name = "p 1";
- page[npage++].offset = 0;
- }
-
- if(npage+2 > mpage) {
- mpage += 2;
- page = erealloc(page, mpage*sizeof(*page));
- memset(&page[mpage-2], 0, 2*sizeof(*page));
- }
-
- if(!trailer)
- page[npage].offset = Boffset(b);
-
- Bseek(b, 0, 2); /* EOF */
- page[npage+1].offset = Boffset(b);
-
- d = emalloc(sizeof(*d));
- ps = emalloc(sizeof(*ps));
- ps->page = page;
- ps->npage = npage;
- ps->bbox = bbox;
- ps->psoff = psoff;
-
- d->extra = ps;
- d->npage = ps->npage;
- d->b = b;
- d->drawpage = psdrawpage;
- d->pagename = pspagename;
-
- d->fwdonly = ps->clueless = dumb;
- d->docname = argv[0];
-
- if(spawngs(ps, "-dSAFER") < 0)
- return nil;
-
- if(!cantranslate)
- bbox.min = ZP;
- setdim(ps, bbox, ppi, landscape);
-
- if(goodps){
- /*
- * We want to only send the page (i.e. not header and trailer) information
- * for each page, so initialize the device by sending the header now.
- */
- pswritepage(d, ps->gsfd, -1);
- waitgs(ps);
- }
-
- if(dumb) {
- fprint(ps->gsfd, "(%s) run\n", argv[0]);
- fprint(ps->gsfd, "(/fd/3) (w) file dup (THIS IS NOT A PLAN9 BITMAP 01234567890123456789012345678901234567890123456789\\n) writestring flushfile\n");
- }
-
- ps->bbox = bbox;
-
- return d;
-}
-
-static int
-pswritepage(Document *d, int fd, int page)
-{
- Biobuf *b = d->b;
- PSInfo *ps = d->extra;
- int t, n, i;
- long begin, end;
- char buf[8192];
-
- if(page == -1)
- begin = ps->psoff;
- else
- begin = ps->page[page].offset;
-
- end = ps->page[page+1].offset;
-
- if(chatty) {
- fprint(2, "writepage(%d)... from #%ld to #%ld...\n",
- page, begin, end);
- }
- Bseek(b, begin, 0);
-
- t = end-begin;
- n = sizeof(buf);
- if(n > t) n = t;
- while(t > 0 && (i=Bread(b, buf, n)) > 0) {
- if(write(fd, buf, i) != i)
- return -1;
- t -= i;
- if(n > t)
- n = t;
- }
- return end-begin;
-}
-
-static Image*
-psdrawpage(Document *d, int page)
-{
- PSInfo *ps = d->extra;
- Image *im;
-
- if(ps->clueless)
- return readimage(display, ps->gsdfd, 0);
-
- waitgs(ps);
-
- if(goodps)
- pswritepage(d, ps->gsfd, page);
- else {
- pswritepage(d, ps->gsfd, -1);
- pswritepage(d, ps->gsfd, page);
- pswritepage(d, ps->gsfd, d->npage);
- }
- /*
- * If last line terminator is \r, gs will read ahead to check for \n
- * so send one to avoid deadlock.
- */
- write(ps->gsfd, "\n", 1);
- im = readimage(display, ps->gsdfd, 0);
- if(im == nil) {
- fprint(2, "fatal: readimage error %r\n");
- wexits("readimage");
- }
- waitgs(ps);
-
- return im;
-}
-
-static char*
-pspagename(Document *d, int page)
-{
- PSInfo *ps = (PSInfo *) d->extra;
- return ps->page[page].name;
-}
--- a/sys/src/cmd/page/rotate.c
+++ /dev/null
@@ -1,500 +1,0 @@
-/*
- * rotate an image 180° in O(log Dx + log Dy) /dev/draw writes,
- * using an extra buffer same size as the image.
- *
- * the basic concept is that you can invert an array by inverting
- * the top half, inverting the bottom half, and then swapping them.
- * the code does this slightly backwards to ensure O(log n) runtime.
- * (If you do it wrong, you can get O(log² n) runtime.)
- *
- * This is usually overkill, but it speeds up slow remote
- * connections quite a bit.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <draw.h>
-#include <event.h>
-#include "page.h"
-
-int ndraw = 0;
-enum {
- Xaxis = 0,
- Yaxis = 1,
-};
-
-Image *mtmp;
-
-void
-writefile(char *name, Image *im, int gran)
-{
- static int c = 100;
- int fd;
- char buf[200];
-
- snprint(buf, sizeof buf, "%d%s%d", c++, name, gran);
- fd = create(buf, OWRITE, 0666);
- if(fd < 0)
- return;
- writeimage(fd, im, 0);
- close(fd);
-}
-
-void
-moveup(Image *im, Image *tmp, int a, int b, int c, int axis)
-{
- Rectangle range;
- Rectangle dr0, dr1;
- Point p0, p1;
-
- if(a == b || b == c)
- return;
-
- drawop(tmp, tmp->r, im, nil, im->r.min, S);
-
- switch(axis){
- case Xaxis:
- range = Rect(a, im->r.min.y, c, im->r.max.y);
- dr0 = range;
- dr0.max.x = dr0.min.x+(c-b);
- p0 = Pt(b, im->r.min.y);
-
- dr1 = range;
- dr1.min.x = dr1.max.x-(b-a);
- p1 = Pt(a, im->r.min.y);
- break;
- case Yaxis:
- range = Rect(im->r.min.x, a, im->r.max.x, c);
- dr0 = range;
- dr0.max.y = dr0.min.y+(c-b);
- p0 = Pt(im->r.min.x, b);
-
- dr1 = range;
- dr1.min.y = dr1.max.y-(b-a);
- p1 = Pt(im->r.min.x, a);
- break;
- }
- drawop(im, dr0, tmp, nil, p0, S);
- drawop(im, dr1, tmp, nil, p1, S);
-}
-
-void
-interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
-{
- Point p0, p1;
- Rectangle r0, r1;
-
- r0 = im->r;
- r1 = im->r;
- switch(axis) {
- case Xaxis:
- r0.max.x = n;
- r1.min.x = n;
- p0 = (Point){gran, 0};
- p1 = (Point){-gran, 0};
- break;
- case Yaxis:
- r0.max.y = n;
- r1.min.y = n;
- p0 = (Point){0, gran};
- p1 = (Point){0, -gran};
- break;
- }
-
- drawop(tmp, im->r, im, display->opaque, im->r.min, S);
- gendrawop(im, r0, tmp, p0, mask, mask->r.min, S);
- gendrawop(im, r0, tmp, p1, mask, p1, S);
-}
-
-/*
- * Halve the grating period in the mask.
- * The grating currently looks like
- * ####____####____####____####____
- * where #### is opacity.
- *
- * We want
- * ##__##__##__##__##__##__##__##__
- * which is achieved by shifting the mask
- * and drawing on itself through itself.
- * Draw doesn't actually allow this, so
- * we have to copy it first.
- *
- * ####____####____####____####____ (dst)
- * + ____####____####____####____#### (src)
- * in __####____####____####____####__ (mask)
- * ===========================================
- * ##__##__##__##__##__##__##__##__
- */
-int
-nextmask(Image *mask, int axis, int maskdim)
-{
- Point δ;
-
- δ = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim);
- drawop(mtmp, mtmp->r, mask, nil, mask->r.min, S);
- gendrawop(mask, mask->r, mtmp, δ, mtmp, divpt(δ,-2), S);
-// writefile("mask", mask, maskdim/2);
- return maskdim/2;
-}
-
-void
-shuffle(Image *im, Image *tmp, int axis, int n, Image *mask, int gran,
- int lastnn)
-{
- int nn, left;
-
- if(gran == 0)
- return;
- left = n%(2*gran);
- nn = n - left;
-
- interlace(im, tmp, axis, nn, mask, gran);
-// writefile("interlace", im, gran);
-
- gran = nextmask(mask, axis, gran);
- shuffle(im, tmp, axis, n, mask, gran, nn);
-// writefile("shuffle", im, gran);
- moveup(im, tmp, lastnn, nn, n, axis);
-// writefile("move", im, gran);
-}
-
-void
-rot180(Image *im)
-{
- Image *tmp, *tmp0;
- Image *mask;
- Rectangle rmask;
- int gran;
-
- if(chantodepth(im->chan) < 8){
- /* this speeds things up dramatically; draw is too slow on sub-byte pixel sizes */
- tmp0 = xallocimage(display, im->r, CMAP8, 0, DNofill);
- drawop(tmp0, tmp0->r, im, nil, im->r.min, S);
- }else
- tmp0 = im;
-
- tmp = xallocimage(display, tmp0->r, tmp0->chan, 0, DNofill);
- if(tmp == nil){
- if(tmp0 != im)
- freeimage(tmp0);
- return;
- }
- for(gran=1; gran<Dx(im->r); gran *= 2)
- ;
- gran /= 4;
-
- rmask.min = ZP;
- rmask.max = (Point){2*gran, 100};
-
- mask = xallocimage(display, rmask, GREY1, 1, DTransparent);
- mtmp = xallocimage(display, rmask, GREY1, 1, DTransparent);
- if(mask == nil || mtmp == nil) {
- fprint(2, "out of memory during rot180: %r\n");
- wexits("memory");
- }
- rmask.max.x = gran;
- drawop(mask, rmask, display->opaque, nil, ZP, S);
-// writefile("mask", mask, gran);
- shuffle(im, tmp, Xaxis, Dx(im->r), mask, gran, 0);
- freeimage(mask);
- freeimage(mtmp);
-
- for(gran=1; gran<Dy(im->r); gran *= 2)
- ;
- gran /= 4;
- rmask.max = (Point){100, 2*gran};
- mask = xallocimage(display, rmask, GREY1, 1, DTransparent);
- mtmp = xallocimage(display, rmask, GREY1, 1, DTransparent);
- if(mask == nil || mtmp == nil) {
- fprint(2, "out of memory during rot180: %r\n");
- wexits("memory");
- }
- rmask.max.y = gran;
- drawop(mask, rmask, display->opaque, nil, ZP, S);
- shuffle(im, tmp, Yaxis, Dy(im->r), mask, gran, 0);
- freeimage(mask);
- freeimage(mtmp);
- freeimage(tmp);
- if(tmp0 != im)
- freeimage(tmp0);
-}
-
-/* rotates an image 90 degrees clockwise */
-Image *
-rot90(Image *im)
-{
- Image *tmp;
- int i, j, dx, dy;
-
- dx = Dx(im->r);
- dy = Dy(im->r);
- tmp = xallocimage(display, Rect(0, 0, dy, dx), im->chan, 0, DCyan);
- if(tmp == nil) {
- fprint(2, "out of memory during rot90: %r\n");
- wexits("memory");
- }
-
- for(j = 0; j < dx; j++) {
- for(i = 0; i < dy; i++) {
- drawop(tmp, Rect(i, j, i+1, j+1), im, nil, Pt(j, dy-(i+1)), S);
- }
- }
- freeimage(im);
-
- return(tmp);
-}
-
-/* rotates an image 270 degrees clockwise */
-Image *
-rot270(Image *im)
-{
- Image *tmp;
- int i, j, dx, dy;
-
- dx = Dx(im->r);
- dy = Dy(im->r);
- tmp = xallocimage(display, Rect(0, 0, dy, dx), im->chan, 0, DCyan);
- if(tmp == nil) {
- fprint(2, "out of memory during rot270: %r\n");
- wexits("memory");
- }
-
- for(i = 0; i < dy; i++) {
- for(j = 0; j < dx; j++) {
- drawop(tmp, Rect(i, j, i+1, j+1), im, nil, Pt(dx-(j+1), i), S);
- }
- }
- freeimage(im);
-
- return(tmp);
-}
-
-/* from resample.c -- resize from → to using interpolation */
-
-
-#define K2 7 /* from -.7 to +.7 inclusive, meaning .2 into each adjacent pixel */
-#define NK (2*K2+1)
-double K[NK];
-
-double
-fac(int L)
-{
- int i, f;
-
- f = 1;
- for(i=L; i>1; --i)
- f *= i;
- return f;
-}
-
-/*
- * i0(x) is the modified Bessel function, Σ (x/2)^2L / (L!)²
- * There are faster ways to calculate this, but we precompute
- * into a table so let's keep it simple.
- */
-double
-i0(double x)
-{
- double v;
- int L;
-
- v = 1.0;
- for(L=1; L<10; L++)
- v += pow(x/2., 2*L)/pow(fac(L), 2);
- return v;
-}
-
-double
-kaiser(double x, double τ, double α)
-{
- if(fabs(x) > τ)
- return 0.;
- return i0(α*sqrt(1-(x*x/(τ*τ))))/i0(α);
-}
-
-
-void
-resamplex(uchar *in, int off, int d, int inx, uchar *out, int outx)
-{
- int i, x, k;
- double X, xx, v, rat;
-
-
- rat = (double)inx/(double)outx;
- for(x=0; x<outx; x++){
- if(inx == outx){
- /* don't resample if size unchanged */
- out[off+x*d] = in[off+x*d];
- continue;
- }
- v = 0.0;
- X = x*rat;
- for(k=-K2; k<=K2; k++){
- xx = X + rat*k/10.;
- i = xx;
- if(i < 0)
- i = 0;
- if(i >= inx)
- i = inx-1;
- v += in[off+i*d] * K[K2+k];
- }
- out[off+x*d] = v;
- }
-}
-
-void
-resampley(uchar **in, int off, int iny, uchar **out, int outy)
-{
- int y, i, k;
- double Y, yy, v, rat;
-
- rat = (double)iny/(double)outy;
- for(y=0; y<outy; y++){
- if(iny == outy){
- /* don't resample if size unchanged */
- out[y][off] = in[y][off];
- continue;
- }
- v = 0.0;
- Y = y*rat;
- for(k=-K2; k<=K2; k++){
- yy = Y + rat*k/10.;
- i = yy;
- if(i < 0)
- i = 0;
- if(i >= iny)
- i = iny-1;
- v += in[i][off] * K[K2+k];
- }
- out[y][off] = v;
- }
-
-}
-
-Image*
-resample(Image *from, Image *to)
-{
- int i, j, bpl, nchan;
- uchar **oscan, **nscan;
- char tmp[20];
- int xsize, ysize;
- double v;
- Image *t1, *t2;
- ulong tchan;
-
- for(i=-K2; i<=K2; i++){
- K[K2+i] = kaiser(i/10., K2/10., 4.);
- }
-
- /* normalize */
- v = 0.0;
- for(i=0; i<NK; i++)
- v += K[i];
- for(i=0; i<NK; i++)
- K[i] /= v;
-
- switch(from->chan){
- case GREY8:
- case RGB24:
- case RGBA32:
- case ARGB32:
- case XRGB32:
- break;
-
- case CMAP8:
- case RGB15:
- case RGB16:
- tchan = RGB24;
- goto Convert;
-
- case GREY1:
- case GREY2:
- case GREY4:
- tchan = GREY8;
- Convert:
- /* use library to convert to byte-per-chan form, then convert back */
- t1 = xallocimage(display, Rect(0, 0, Dx(from->r), Dy(from->r)), tchan, 0, DNofill);
- if(t1 == nil) {
- fprint(2, "out of memory for temp image 1 in resample: %r\n");
- wexits("memory");
- }
- drawop(t1, t1->r, from, nil, ZP, S);
- t2 = xallocimage(display, to->r, tchan, 0, DNofill);
- if(t2 == nil) {
- fprint(2, "out of memory temp image 2 in resample: %r\n");
- wexits("memory");
- }
- resample(t1, t2);
- drawop(to, to->r, t2, nil, ZP, S);
- freeimage(t1);
- freeimage(t2);
- return to;
-
- default:
- sysfatal("can't handle channel type %s", chantostr(tmp, from->chan));
- }
-
- xsize = Dx(to->r);
- ysize = Dy(to->r);
- oscan = malloc(Dy(from->r)*sizeof(uchar*));
- nscan = malloc(max(ysize, Dy(from->r))*sizeof(uchar*));
- if(oscan == nil || nscan == nil)
- sysfatal("can't allocate: %r");
-
- /* unload original image into scan lines */
- bpl = bytesperline(from->r, from->depth);
- for(i=0; i<Dy(from->r); i++){
- oscan[i] = malloc(bpl);
- if(oscan[i] == nil)
- sysfatal("can't allocate: %r");
- j = unloadimage(from, Rect(from->r.min.x, from->r.min.y+i, from->r.max.x, from->r.min.y+i+1), oscan[i], bpl);
- if(j != bpl)
- sysfatal("unloadimage");
- }
-
- /* allocate scan lines for destination. we do y first, so need at least Dy(from->r) lines */
- bpl = bytesperline(Rect(0, 0, xsize, Dy(from->r)), from->depth);
- for(i=0; i<max(ysize, Dy(from->r)); i++){
- nscan[i] = malloc(bpl);
- if(nscan[i] == nil)
- sysfatal("can't allocate: %r");
- }
-
- /* resample in X */
- nchan = from->depth/8;
- for(i=0; i<Dy(from->r); i++){
- for(j=0; j<nchan; j++){
- if(j==0 && from->chan==XRGB32)
- continue;
- resamplex(oscan[i], j, nchan, Dx(from->r), nscan[i], xsize);
- }
- free(oscan[i]);
- oscan[i] = nscan[i];
- nscan[i] = malloc(bpl);
- if(nscan[i] == nil)
- sysfatal("can't allocate: %r");
- }
-
- /* resample in Y */
- for(i=0; i<xsize; i++)
- for(j=0; j<nchan; j++)
- resampley(oscan, nchan*i+j, Dy(from->r), nscan, ysize);
-
- /* pack data into destination */
- bpl = bytesperline(to->r, from->depth);
- for(i=0; i<ysize; i++){
- j = loadimage(to, Rect(0, i, xsize, i+1), nscan[i], bpl);
- if(j != bpl)
- sysfatal("loadimage: %r");
- }
-
- for(i=0; i<Dy(from->r); i++){
- free(oscan[i]);
- free(nscan[i]);
- }
- free(oscan);
- free(nscan);
-
- return to;
-}
--- a/sys/src/cmd/page/util.c
+++ /dev/null
@@ -1,131 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <bio.h>
-#include "page.h"
-
-void*
-emalloc(int sz)
-{
- void *v;
- v = malloc(sz);
- if(v == nil) {
- fprint(2, "out of memory allocating %d\n", sz);
- wexits("mem");
- }
- memset(v, 0, sz);
- return v;
-}
-
-void*
-erealloc(void *v, int sz)
-{
- v = realloc(v, sz);
- if(v == nil) {
- fprint(2, "out of memory allocating %d\n", sz);
- wexits("mem");
- }
- return v;
-}
-
-char*
-estrdup(char *s)
-{
- char *t;
- if((t = strdup(s)) == nil) {
- fprint(2, "out of memory in strdup(%.10s)\n", s);
- wexits("mem");
- }
- return t;
-}
-
-int
-opentemp(char *template)
-{
- int fd, i;
- char *p;
-
- p = estrdup(template);
- fd = -1;
- for(i=0; i<10; i++){
- mktemp(p);
- if(access(p, 0) < 0 && (fd=create(p, ORDWR|ORCLOSE, 0400)) >= 0)
- break;
- strcpy(p, template);
- }
- if(fd < 0){
- fprint(2, "couldn't make temporary file\n");
- wexits("Ecreat");
- }
- strcpy(template, p);
- free(p);
-
- return fd;
-}
-
-/*
- * spool standard input to /tmp.
- * we've already read the initial in bytes into ibuf.
- */
-int
-spooltodisk(uchar *ibuf, int in, char **name)
-{
- uchar buf[8192];
- int fd, n;
- char temp[40];
-
- strcpy(temp, "/tmp/pagespoolXXXXXXXXX");
- fd = opentemp(temp);
- if(name)
- *name = estrdup(temp);
-
- if(write(fd, ibuf, in) != in){
- fprint(2, "error writing temporary file\n");
- wexits("write temp");
- }
-
- while((n = read(stdinfd, buf, sizeof buf)) > 0){
- if(write(fd, buf, n) != n){
- fprint(2, "error writing temporary file\n");
- wexits("write temp0");
- }
- }
- seek(fd, 0, 0);
- return fd;
-}
-
-/*
- * spool standard input into a pipe.
- * we've already ready the first in bytes into ibuf
- */
-int
-stdinpipe(uchar *ibuf, int in)
-{
- uchar buf[8192];
- int n;
- int p[2];
- if(pipe(p) < 0){
- fprint(2, "pipe fails: %r\n");
- wexits("pipe");
- }
-
- switch(rfork(RFMEM|RFPROC|RFFDG)){
- case -1:
- fprint(2, "fork fails: %r\n");
- wexits("fork");
- default:
- close(p[1]);
- return p[0];
- case 0:
- break;
- }
-
- close(p[0]);
- write(p[1], ibuf, in);
- while((n = read(stdinfd, buf, sizeof buf)) > 0)
- write(p[1], buf, n);
-
- _exits(0);
- return -1; /* not reached */
-}
--- a/sys/src/cmd/page/view.c
+++ /dev/null
@@ -1,1073 +1,0 @@
-/*
- * the actual viewer that handles screen stuff
- */
-
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <cursor.h>
-#include <event.h>
-#include <bio.h>
-#include <plumb.h>
-#include <ctype.h>
-#include <keyboard.h>
-#include "page.h"
-
-Document *doc;
-Image *im;
-Image *tofree;
-int page;
-int angle = 0;
-int showbottom = 0; /* on the next showpage, move the image so the bottom is visible. */
-
-Rectangle ulrange; /* the upper left corner of the image must be in this rectangle */
-Point ul; /* the upper left corner of the image is at this point on the screen */
-
-Point pclip(Point, Rectangle);
-Rectangle mkrange(Rectangle screenr, Rectangle imr);
-void redraw(Image*);
-
-Cursor reading={
- {-1, -1},
- {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00,
- 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0,
- 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0,
- 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },
- {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00,
- 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0,
- 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40,
- 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }
-};
-
-Cursor query = {
- {-7,-7},
- {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe,
- 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8,
- 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0,
- 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, },
- {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c,
- 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0,
- 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80,
- 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }
-};
-
-enum {
- Left = 1,
- Middle = 2,
- Right = 4,
-
- RMenu = 3,
-};
-
-static void
-delayfreeimage(Image *m)
-{
- if(m == tofree)
- return;
- if(tofree)
- freeimage(tofree);
- tofree = m;
-}
-
-void
-unhide(void)
-{
- static int wctl = -1;
-
- if(wctl < 0)
- wctl = open("/dev/wctl", OWRITE);
- if(wctl < 0)
- return;
-
- write(wctl, "unhide", 6);
-}
-
-int
-max(int a, int b)
-{
- return a > b ? a : b;
-}
-
-int
-min(int a, int b)
-{
- return a < b ? a : b;
-}
-
-
-char*
-menugen(int n)
-{
- static char menustr[32];
- char *p;
- int len;
-
- if(n == doc->npage)
- return "exit";
- if(n > doc->npage)
- return nil;
-
- if(reverse)
- n = doc->npage-1-n;
-
- p = doc->pagename(doc, n);
- len = (sizeof menustr)-2;
-
- if(strlen(p) > len && strrchr(p, '/'))
- p = strrchr(p, '/')+1;
- if(strlen(p) > len)
- p = p+strlen(p)-len;
-
- strcpy(menustr+1, p);
- if(page == n)
- menustr[0] = '>';
- else
- menustr[0] = ' ';
- return menustr;
-}
-
-void
-showpage(int page, Menu *m)
-{
- if(doc->fwdonly)
- m->lasthit = 0; /* this page */
- else
- m->lasthit = reverse ? doc->npage-1-page : page;
-
- esetcursor(&reading);
- delayfreeimage(nil);
- im = cachedpage(doc, angle, page);
- if(im == nil)
- wexits(0);
- if(resizing)
- resize(Dx(im->r), Dy(im->r));
-
- esetcursor(nil);
- if(showbottom){
- ul.y = screen->r.max.y - Dy(im->r);
- showbottom = 0;
- }
-
- redraw(screen);
- flushimage(display, 1);
-}
-
-char*
-writebitmap(void)
-{
- char basename[64];
- char name[64+30];
- static char result[200];
- char *p, *q;
- int fd;
-
- if(im == nil)
- return "no image";
-
- memset(basename, 0, sizeof basename);
- if(doc->docname)
- strncpy(basename, doc->docname, sizeof(basename)-1);
- else if((p = menugen(page)) && p[0] != '\0')
- strncpy(basename, p+1, sizeof(basename)-1);
-
- if(basename[0]) {
- if(q = strrchr(basename, '/'))
- q++;
- else
- q = basename;
- if(p = strchr(q, '.'))
- *p = 0;
-
- memset(name, 0, sizeof name);
- snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1);
- if(access(name, 0) >= 0) {
- strcat(name, "XXXX");
- mktemp(name);
- }
- if(access(name, 0) >= 0)
- return "couldn't think of a name for bitmap";
- } else {
- strcpy(name, "bitXXXX");
- mktemp(name);
- if(access(name, 0) >= 0)
- return "couldn't think of a name for bitmap";
- }
-
- if((fd = create(name, OWRITE, 0666)) < 0) {
- snprint(result, sizeof result, "cannot create %s: %r", name);
- return result;
- }
-
- if(writeimage(fd, im, 0) < 0) {
- snprint(result, sizeof result, "cannot writeimage: %r");
- close(fd);
- return result;
- }
- close(fd);
-
- snprint(result, sizeof result, "wrote %s", name);
- return result;
-}
-
-static void translate(Point);
-
-static int
-showdata(Plumbmsg *msg)
-{
- char *s;
-
- s = plumblookup(msg->attr, "action");
- return s && strcmp(s, "showdata")==0;
-}
-
-static int
-plumbquit(Plumbmsg *msg)
-{
- char *s;
-
- s = plumblookup(msg->attr, "action");
- return s && strcmp(s, "quit")==0;
-}
-
-/* correspond to entries in miditems[] below,
- * changing one means you need to change
- */
-enum{
- Restore = 0,
- Zin,
- Fit,
- Rot,
- Upside,
- Empty1,
- Next,
- Prev,
- Zerox,
- Empty2,
- Reverse,
- Del,
- Write,
- Empty3,
- Exit,
-};
-
-void
-viewer(Document *dd)
-{
- int i, fd, n, oldpage;
- int nxt;
- Menu menu, midmenu;
- Mouse m;
- Event e;
- Point dxy, oxy, xy0;
- Rectangle r;
- Image *tmp;
- static char *fwditems[] = { "this page", "next page", "exit", 0 };
- static char *miditems[] = {
- "orig size",
- "zoom in",
- "fit window",
- "rotate 90",
- "upside down",
- "",
- "next",
- "prev",
- "zerox",
- "",
- "reverse",
- "discard",
- "write",
- "",
- "quit",
- 0
- };
- char *s;
- enum { Eplumb = 4 };
- Plumbmsg *pm;
-
- doc = dd; /* save global for menuhit */
- ul = screen->r.min;
- einit(Emouse|Ekeyboard);
- if(doc->addpage != nil)
- eplumb(Eplumb, "image");
-
- esetcursor(&reading);
- r.min = ZP;
-
- /*
- * im is a global pointer to the current image.
- * eventually, i think we will have a layer between
- * the display routines and the ps/pdf/whatever routines
- * to perhaps cache and handle images of different
- * sizes, etc.
- */
- im = 0;
- page = reverse ? doc->npage-1 : 0;
-
- if(doc->fwdonly) {
- menu.item = fwditems;
- menu.gen = 0;
- menu.lasthit = 0;
- } else {
- menu.item = 0;
- menu.gen = menugen;
- menu.lasthit = 0;
- }
-
- midmenu.item = miditems;
- midmenu.gen = 0;
- midmenu.lasthit = Next;
-
- showpage(page, &menu);
- esetcursor(nil);
-
- nxt = 0;
- for(;;) {
- /*
- * throughout, if doc->fwdonly is set, we restrict the functionality
- * a fair amount. we don't care about doc->npage anymore, and
- * all that can be done is select the next page.
- */
- unlockdisplay(display);
- i = eread(Emouse|Ekeyboard|Eplumb, &e);
- lockdisplay(display);
- switch(i){
- case Ekeyboard:
- if(e.kbdc <= 0xFF && isdigit(e.kbdc)) {
- nxt = nxt*10+e.kbdc-'0';
- break;
- } else if(e.kbdc != '\n')
- nxt = 0;
- switch(e.kbdc) {
- case 'r': /* reverse page order */
- if(doc->fwdonly)
- break;
- reverse = !reverse;
- menu.lasthit = doc->npage-1-menu.lasthit;
-
- /*
- * the theory is that if we are reversing the
- * document order and are on the first or last
- * page then we're just starting and really want
- * to view the other end. maybe the if
- * should be dropped and this should happen always.
- */
- if(page == 0 || page == doc->npage-1) {
- page = doc->npage-1-page;
- showpage(page, &menu);
- }
- break;
- case 'w': /* write bitmap of current screen */
- esetcursor(&reading);
- s = writebitmap();
- if(s)
- string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
- display->defaultfont, s);
- esetcursor(nil);
- flushimage(display, 1);
- break;
- case 'd': /* remove image from working set */
- if(doc->rmpage && page < doc->npage) {
- if(doc->rmpage(doc, page) >= 0) {
- if(doc->npage < 0)
- wexits(0);
- if(page >= doc->npage)
- page = doc->npage-1;
- showpage(page, &menu);
- }
- }
- break;
- case 'q':
- case 0x04: /* ctrl-d */
- wexits(0);
- case 'u':
- if(im==nil)
- break;
- angle = (angle+180) % 360;
- showpage(page, &menu);
- break;
- case '-':
- case '\b':
- case Kleft:
- if(page > 0 && !doc->fwdonly) {
- --page;
- showpage(page, &menu);
- }
- break;
- case '\n':
- if(nxt) {
- nxt--;
- if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly)
- showpage(page=nxt, &menu);
- nxt = 0;
- break;
- }
- goto Gotonext;
- case Kright:
- case ' ':
- Gotonext:
- if(doc->npage && ++page >= doc->npage && !doc->fwdonly)
- wexits(0);
- showpage(page, &menu);
- break;
-
- /*
- * The upper y coordinate of the image is at ul.y in screen->r.
- * Panning up means moving the upper left corner down. If the
- * upper left corner is currently visible, we need to go back a page.
- */
- case Kup:
- if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){
- if(page > 0 && !doc->fwdonly){
- --page;
- showbottom = 1;
- showpage(page, &menu);
- }
- } else {
- i = Dy(screen->r)/2;
- if(i > 10)
- i -= 10;
- if(i+ul.y > screen->r.min.y)
- i = screen->r.min.y - ul.y;
- translate(Pt(0, i));
- }
- break;
-
- /*
- * If the lower y coordinate is on the screen, we go to the next page.
- * The lower y coordinate is at ul.y + Dy(im->r).
- */
- case Kdown:
- i = ul.y + Dy(im->r);
- if(screen->r.min.y <= i && i <= screen->r.max.y){
- ul.y = screen->r.min.y;
- goto Gotonext;
- } else {
- i = -Dy(screen->r)/2;
- if(i < -10)
- i += 10;
- if(i+ul.y+Dy(im->r) <= screen->r.max.y)
- i = screen->r.max.y - Dy(im->r) - ul.y - 1;
- translate(Pt(0, i));
- }
- break;
- default:
- esetcursor(&query);
- sleep(1000);
- esetcursor(nil);
- break;
- }
- break;
-
- case Emouse:
- m = e.mouse;
- switch(m.buttons){
- case Left:
- oxy = m.xy;
- xy0 = oxy;
- do {
- dxy = subpt(m.xy, oxy);
- oxy = m.xy;
- translate(dxy);
- unlockdisplay(display);
- m = emouse();
- lockdisplay(display);
- } while(m.buttons == Left);
- if(m.buttons) {
- dxy = subpt(xy0, oxy);
- translate(dxy);
- }
- break;
-
- case Middle:
- if(doc->npage == 0)
- break;
-
- unlockdisplay(display);
- n = emenuhit(Middle, &m, &midmenu);
- lockdisplay(display);
- if(n == -1)
- break;
- switch(n){
- case Next: /* next */
- if(reverse)
- page--;
- else
- page++;
- if(page < 0) {
- if(reverse) return;
- else page = 0;
- }
-
- if((page >= doc->npage) && !doc->fwdonly)
- return;
-
- showpage(page, &menu);
- nxt = 0;
- break;
- case Prev: /* prev */
- if(reverse)
- page++;
- else
- page--;
- if(page < 0) {
- if(reverse) return;
- else page = 0;
- }
-
- if((page >= doc->npage) && !doc->fwdonly && !reverse)
- return;
-
- showpage(page, &menu);
- nxt = 0;
- break;
- case Zerox: /* prev */
- zerox();
- break;
- case Zin: /* zoom in */
- {
- double delta;
- Rectangle r;
-
- r = egetrect(Middle, &m);
- if((rectclip(&r, rectaddpt(im->r, ul)) == 0) ||
- Dx(r) == 0 || Dy(r) == 0)
- break;
- /* use the smaller side to expand */
- if(Dx(r) < Dy(r))
- delta = (double)Dx(im->r)/(double)Dx(r);
- else
- delta = (double)Dy(im->r)/(double)Dy(r);
-
- esetcursor(&reading);
- tmp = xallocimage(display,
- Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)),
- im->chan, 0, DBlack);
- if(tmp == nil) {
- fprint(2, "out of memory during zoom: %r\n");
- wexits("memory");
- }
- resample(im, tmp);
- im = tmp;
- delayfreeimage(tmp);
- esetcursor(nil);
- ul = screen->r.min;
- redraw(screen);
- flushimage(display, 1);
- break;
- }
- case Fit: /* fit */
- {
- double delta;
- Rectangle r;
-
- delta = (double)Dx(screen->r)/(double)Dx(im->r);
- if((double)Dy(im->r)*delta > Dy(screen->r))
- delta = (double)Dy(screen->r)/(double)Dy(im->r);
-
- r = Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta));
- esetcursor(&reading);
- tmp = xallocimage(display, r, im->chan, 0, DBlack);
- if(tmp == nil) {
- fprint(2, "out of memory during fit: %r\n");
- wexits("memory");
- }
- resample(im, tmp);
- im = tmp;
- delayfreeimage(tmp);
- esetcursor(nil);
- ul = screen->r.min;
- redraw(screen);
- flushimage(display, 1);
- break;
- }
- case Rot: /* rotate 90 */
- angle = (angle+90) % 360;
- showpage(page, &menu);
- break;
- case Upside: /* upside-down */
- angle = (angle+180) % 360;
- showpage(page, &menu);
- break;
- case Restore: /* restore */
- showpage(page, &menu);
- break;
- case Reverse: /* reverse */
- if(doc->fwdonly)
- break;
- reverse = !reverse;
- menu.lasthit = doc->npage-1-menu.lasthit;
-
- if(page == 0 || page == doc->npage-1) {
- page = doc->npage-1-page;
- showpage(page, &menu);
- }
- break;
- case Write: /* write */
- esetcursor(&reading);
- s = writebitmap();
- if(s)
- string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
- display->defaultfont, s);
- esetcursor(nil);
- flushimage(display, 1);
- break;
- case Del: /* delete */
- if(doc->rmpage && page < doc->npage) {
- if(doc->rmpage(doc, page) >= 0) {
- if(doc->npage < 0)
- wexits(0);
- if(page >= doc->npage)
- page = doc->npage-1;
- showpage(page, &menu);
- }
- }
- break;
- case Exit: /* exit */
- return;
- case Empty1:
- case Empty2:
- case Empty3:
- break;
-
- };
-
-
-
- case Right:
- if(doc->npage == 0)
- break;
-
- oldpage = page;
- unlockdisplay(display);
- n = emenuhit(RMenu, &m, &menu);
- lockdisplay(display);
- if(n == -1)
- break;
-
- if(doc->fwdonly) {
- switch(n){
- case 0: /* this page */
- break;
- case 1: /* next page */
- showpage(++page, &menu);
- break;
- case 2: /* exit */
- return;
- }
- break;
- }
-
- if(n == doc->npage)
- return;
- else
- page = reverse ? doc->npage-1-n : n;
-
- if(oldpage != page)
- showpage(page, &menu);
- nxt = 0;
- break;
- }
- break;
-
- case Eplumb:
- pm = e.v;
- if(pm->ndata <= 0){
- plumbfree(pm);
- break;
- }
- if(plumbquit(pm))
- exits(nil);
- if(showdata(pm)) {
- s = estrdup("/tmp/pageplumbXXXXXXX");
- fd = opentemp(s);
- write(fd, pm->data, pm->ndata);
- /* lose fd reference on purpose; the file is open ORCLOSE */
- } else if(pm->data[0] == '/') {
- s = estrdup(pm->data);
- } else {
- s = emalloc(strlen(pm->wdir)+1+pm->ndata+1);
- sprint(s, "%s/%s", pm->wdir, pm->data);
- cleanname(s);
- }
- if((i = doc->addpage(doc, s)) >= 0) {
- page = i;
- unhide();
- showpage(page, &menu);
- }
- free(s);
- plumbfree(pm);
- break;
- }
- }
-}
-
-Image *gray;
-
-/*
- * A draw operation that touches only the area contained in bot but not in top.
- * mp and sp get aligned with bot.min.
- */
-static void
-gendrawdiff(Image *dst, Rectangle bot, Rectangle top,
- Image *src, Point sp, Image *mask, Point mp, int op)
-{
- Rectangle r;
- Point origin;
- Point delta;
-
- USED(op);
-
- if(Dx(bot)*Dy(bot) == 0)
- return;
-
- /* no points in bot - top */
- if(rectinrect(bot, top))
- return;
-
- /* bot - top ≡ bot */
- if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){
- gendrawop(dst, bot, src, sp, mask, mp, op);
- return;
- }
-
- origin = bot.min;
- /* split bot into rectangles that don't intersect top */
- /* left side */
- if(bot.min.x < top.min.x){
- r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.min.x = top.min.x;
- }
-
- /* right side */
- if(bot.max.x > top.max.x){
- r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.max.x = top.max.x;
- }
-
- /* top */
- if(bot.min.y < top.min.y){
- r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.min.y = top.min.y;
- }
-
- /* bottom */
- if(bot.max.y > top.max.y){
- r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y);
- delta = subpt(r.min, origin);
- gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
- bot.max.y = top.max.y;
- }
-}
-
-static void
-drawdiff(Image *dst, Rectangle bot, Rectangle top, Image *src, Image *mask, Point p, int op)
-{
- gendrawdiff(dst, bot, top, src, p, mask, p, op);
-}
-
-/*
- * Translate the image in the window by delta.
- */
-static void
-translate(Point delta)
-{
- Point u;
- Rectangle r, or;
-
- if(im == nil)
- return;
-
- u = pclip(addpt(ul, delta), ulrange);
- delta = subpt(u, ul);
- if(delta.x == 0 && delta.y == 0)
- return;
-
- /*
- * The upper left corner of the image is currently at ul.
- * We want to move it to u.
- */
- or = rectaddpt(Rpt(ZP, Pt(Dx(im->r), Dy(im->r))), ul);
- r = rectaddpt(or, delta);
-
- drawop(screen, r, screen, nil, ul, S);
- ul = u;
-
- /* fill in gray where image used to be but isn't. */
- drawdiff(screen, insetrect(or, -2), insetrect(r, -2), gray, nil, ZP, S);
-
- /* fill in black border */
- drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP, S);
-
- /* fill in image where it used to be off the screen. */
- if(rectclip(&or, screen->r))
- drawdiff(screen, r, rectaddpt(or, delta), im, nil, im->r.min, S);
- else
- drawop(screen, r, im, nil, im->r.min, S);
- flushimage(display, 1);
-}
-
-void
-redraw(Image *screen)
-{
- Rectangle r;
-
- if(im == nil)
- return;
-
- ulrange.max = screen->r.max;
- ulrange.min = subpt(screen->r.min, Pt(Dx(im->r), Dy(im->r)));
-
- ul = pclip(ul, ulrange);
- drawop(screen, screen->r, im, nil, subpt(im->r.min, subpt(ul, screen->r.min)), S);
-
- if(im->repl)
- return;
-
- /* fill in any outer edges */
- /* black border */
- r = rectaddpt(im->r, subpt(ul, im->r.min));
- border(screen, r, -2, display->black, ZP);
- r.min = subpt(r.min, Pt(2,2));
- r.max = addpt(r.max, Pt(2,2));
-
- /* gray for the rest */
- if(gray == nil) {
- gray = xallocimage(display, Rect(0,0,1,1), RGB24, 1, 0x888888FF);
- if(gray == nil) {
- fprint(2, "g out of memory: %r\n");
- wexits("mem");
- }
- }
- border(screen, r, -4000, gray, ZP);
-// flushimage(display, 0);
-}
-
-void
-eresized(int new)
-{
- Rectangle r;
- r = screen->r;
- if(new && getwindow(display, Refnone) < 0)
- fprint(2,"can't reattach to window");
- ul = addpt(ul, subpt(screen->r.min, r.min));
- redraw(screen);
-}
-
-/* clip p to be in r */
-Point
-pclip(Point p, Rectangle r)
-{
- if(p.x < r.min.x)
- p.x = r.min.x;
- else if(p.x >= r.max.x)
- p.x = r.max.x-1;
-
- if(p.y < r.min.y)
- p.y = r.min.y;
- else if(p.y >= r.max.y)
- p.y = r.max.y-1;
-
- return p;
-}
-
-/*
- * resize is perhaps a misnomer.
- * this really just grows the window to be at least dx across
- * and dy high. if the window hits the bottom or right edge,
- * it is backed up until it hits the top or left edge.
- */
-void
-resize(int dx, int dy)
-{
- static Rectangle sr;
- Rectangle r, or;
-
- dx += 2*Borderwidth;
- dy += 2*Borderwidth;
- if(wctlfd < 0){
- wctlfd = open("/dev/wctl", OWRITE);
- if(wctlfd < 0)
- return;
- }
-
- r = insetrect(screen->r, -Borderwidth);
- if(Dx(r) >= dx && Dy(r) >= dy)
- return;
-
- if(Dx(sr)*Dy(sr) == 0)
- sr = screenrect();
-
- or = r;
-
- r.max.x = max(r.min.x+dx, r.max.x);
- r.max.y = max(r.min.y+dy, r.max.y);
- if(r.max.x > sr.max.x){
- if(Dx(r) > Dx(sr)){
- r.min.x = 0;
- r.max.x = sr.max.x;
- }else
- r = rectaddpt(r, Pt(sr.max.x-r.max.x, 0));
- }
- if(r.max.y > sr.max.y){
- if(Dy(r) > Dy(sr)){
- r.min.y = 0;
- r.max.y = sr.max.y;
- }else
- r = rectaddpt(r, Pt(0, sr.max.y-r.max.y));
- }
-
- /*
- * Sometimes we can't actually grow the window big enough,
- * and resizing it to the same shape makes it flash.
- */
- if(Dx(r) == Dx(or) && Dy(r) == Dy(or))
- return;
-
- fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n",
- r.min.x, r.min.y, r.max.x, r.max.y);
-}
-
-/*
- * If we allocimage after a resize but before flushing the draw buffer,
- * we won't have seen the reshape event, and we won't have called
- * getwindow, and allocimage will fail. So we flushimage before every alloc.
- */
-Image*
-xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val)
-{
- flushimage(display, 0);
- return allocimage(d, r, chan, repl, val);
-}
-
-/* all code below this line should be in the library, but is stolen from colors instead */
-static char*
-rdenv(char *name)
-{
- char *v;
- int fd, size;
-
- fd = open(name, OREAD);
- if(fd < 0)
- return 0;
- size = seek(fd, 0, 2);
- v = malloc(size+1);
- if(v == 0){
- fprint(2, "page: can't malloc: %r\n");
- wexits("no mem");
- }
- seek(fd, 0, 0);
- read(fd, v, size);
- v[size] = 0;
- close(fd);
- return v;
-}
-
-void
-newwin(void)
-{
- char *srv, *mntsrv;
- char spec[100];
- int srvfd, cons, pid;
-
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){
- case -1:
- fprint(2, "page: can't fork: %r\n");
- wexits("no fork");
- case 0:
- break;
- default:
- wexits(0);
- }
-
- srv = rdenv("/env/wsys");
- if(srv == 0){
- mntsrv = rdenv("/mnt/term/env/wsys");
- if(mntsrv == 0){
- fprint(2, "page: can't find $wsys\n");
- wexits("srv");
- }
- srv = malloc(strlen(mntsrv)+10);
- sprint(srv, "/mnt/term%s", mntsrv);
- free(mntsrv);
- pid = 0; /* can't send notes to remote processes! */
- }else
- pid = getpid();
- srvfd = open(srv, ORDWR);
- if(srvfd == -1){
- fprint(2, "page: can't open %s: %r\n", srv);
- wexits("no srv");
- }
- free(srv);
- sprint(spec, "new -pid %d", pid);
- if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){
- fprint(2, "page: can't mount /mnt/wsys: %r (spec=%s)\n", spec);
- wexits("no mount");
- }
- close(srvfd);
- unmount("/mnt/acme", "/dev");
- bind("/mnt/wsys", "/dev", MBEFORE);
- cons = open("/dev/cons", OREAD);
- if(cons==-1){
- NoCons:
- fprint(2, "page: can't open /dev/cons: %r");
- wexits("no cons");
- }
- dup(cons, 0);
- close(cons);
- cons = open("/dev/cons", OWRITE);
- if(cons==-1)
- goto NoCons;
- dup(cons, 1);
- dup(cons, 2);
- close(cons);
-// wctlfd = open("/dev/wctl", OWRITE);
-}
-
-Rectangle
-screenrect(void)
-{
- int fd;
- char buf[12*5];
-
- fd = open("/dev/screen", OREAD);
- if(fd == -1)
- fd=open("/mnt/term/dev/screen", OREAD);
- if(fd == -1){
- fprint(2, "page: can't open /dev/screen: %r\n");
- wexits("window read");
- }
- if(read(fd, buf, sizeof buf) != sizeof buf){
- fprint(2, "page: can't read /dev/screen: %r\n");
- wexits("screen read");
- }
- close(fd);
- return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
-}
-
-void
-zerox(void)
-{
- int pfd[2];
-
- pipe(pfd);
- switch(rfork(RFFDG|RFREND|RFPROC)) {
- case -1:
- wexits("cannot fork in zerox: %r");
- case 0:
- dup(pfd[1], 0);
- close(pfd[0]);
- execl("/bin/page", "page", "-w", nil);
- wexits("cannot exec in zerox: %r\n");
- default:
- close(pfd[1]);
- writeimage(pfd[0], im, 0);
- close(pfd[0]);
- break;
- }
-}