]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/XSplashOutputDev.cc
guard against unloaded docs when the title is accessed.
[evince.git] / pdf / xpdf / XSplashOutputDev.cc
1 //========================================================================
2 //
3 // XSplashOutputDev.cc
4 //
5 // Copyright 2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <X11/Xlib.h>
16 #include <X11/Xutil.h>
17 #include "gmem.h"
18 #include "SplashTypes.h"
19 #include "SplashBitmap.h"
20 #include "Object.h"
21 #include "GfxState.h"
22 #include "TextOutputDev.h"
23 #include "XSplashOutputDev.h"
24
25 //------------------------------------------------------------------------
26 // Constants and macros
27 //------------------------------------------------------------------------
28
29 #define xoutRound(x) ((int)(x + 0.5))
30
31 //------------------------------------------------------------------------
32 // XSplashOutputDev
33 //------------------------------------------------------------------------
34
35 XSplashOutputDev::XSplashOutputDev(Display *displayA, int screenNumA,
36                                    Visual *visualA, Colormap colormapA,
37                                    GBool reverseVideoA,
38                                    SplashColor paperColorA,
39                                    GBool installCmapA, int rgbCubeSizeA,
40                                    GBool incrementalUpdateA,
41                                    void (*redrawCbkA)(void *data),
42                                    void *redrawCbkDataA):
43   SplashOutputDev(splashModeRGB8, reverseVideoA, paperColorA)
44 {
45   XVisualInfo visualTempl;
46   XVisualInfo *visualList;
47   Gulong mask;
48   int nVisuals;
49   XColor xcolor;
50   XColor *xcolors;
51   int r, g, b, n, m;
52   GBool ok;
53
54   incrementalUpdate = incrementalUpdateA;
55   redrawCbk = redrawCbkA;
56   redrawCbkData = redrawCbkDataA;
57
58   // create text object
59   text = new TextPage(gFalse);
60
61   //----- set up the X color stuff
62
63   display = displayA;
64   visual = visualA;
65
66   // check for TrueColor visual
67   //~ this should scan the list, not just look at the first one
68   visualTempl.visualid = XVisualIDFromVisual(visual);
69   visualList = XGetVisualInfo(display, VisualIDMask,
70                               &visualTempl, &nVisuals);
71   if (nVisuals < 1) {
72     // this shouldn't happen
73     XFree((XPointer)visualList);
74     visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl,
75                                 &nVisuals);
76   }
77   depth = visualList->depth;
78   if (visualList->c_class == TrueColor) {
79     trueColor = gTrue;
80     for (mask = visualList->red_mask, rShift = 0;
81          mask && !(mask & 1);
82          mask >>= 1, ++rShift) ;
83     for (rDiv = 8; mask; mask >>= 1, --rDiv) ;
84     for (mask = visualList->green_mask, gShift = 0;
85          mask && !(mask & 1);
86          mask >>= 1, ++gShift) ;
87     for (gDiv = 8; mask; mask >>= 1, --gDiv) ;
88     for (mask = visualList->blue_mask, bShift = 0;
89          mask && !(mask & 1);
90          mask >>= 1, ++bShift) ;
91     for (bDiv = 8; mask; mask >>= 1, --bDiv) ;
92   } else {
93     trueColor = gFalse;
94   }
95   XFree((XPointer)visualList);
96
97   // allocate a color cube
98   if (!trueColor) {
99
100     // set colors in private colormap
101     if (installCmapA) {
102       for (rgbCubeSize = xOutMaxRGBCube; rgbCubeSize >= 2; --rgbCubeSize) {
103         m = rgbCubeSize * rgbCubeSize * rgbCubeSize;
104         if (XAllocColorCells(display, colormapA, False, NULL, 0, colors, m)) {
105           break;
106         }
107       }
108       if (rgbCubeSize >= 2) {
109         m = rgbCubeSize * rgbCubeSize * rgbCubeSize;
110         xcolors = (XColor *)gmalloc(m * sizeof(XColor));
111         n = 0;
112         for (r = 0; r < rgbCubeSize; ++r) {
113           for (g = 0; g < rgbCubeSize; ++g) {
114             for (b = 0; b < rgbCubeSize; ++b) {
115               xcolors[n].pixel = colors[n];
116               xcolors[n].red = (r * 65535) / (rgbCubeSize - 1);
117               xcolors[n].green = (g * 65535) / (rgbCubeSize - 1);
118               xcolors[n].blue = (b * 65535) / (rgbCubeSize - 1);
119               xcolors[n].flags = DoRed | DoGreen | DoBlue;
120               ++n;
121             }
122           }
123         }
124         XStoreColors(display, colormapA, xcolors, m);
125         gfree(xcolors);
126       } else {
127         rgbCubeSize = 1;
128         colors[0] = BlackPixel(display, screenNumA);
129         colors[1] = WhitePixel(display, screenNumA);
130       }
131
132     // allocate colors in shared colormap
133     } else {
134       if (rgbCubeSize > xOutMaxRGBCube) {
135         rgbCubeSize = xOutMaxRGBCube;
136       }
137       ok = gFalse;
138       for (rgbCubeSize = rgbCubeSizeA; rgbCubeSize >= 2; --rgbCubeSize) {
139         ok = gTrue;
140         n = 0;
141         for (r = 0; r < rgbCubeSize && ok; ++r) {
142           for (g = 0; g < rgbCubeSize && ok; ++g) {
143             for (b = 0; b < rgbCubeSize && ok; ++b) {
144               if (n == 0) {
145                 colors[n] = BlackPixel(display, screenNumA);
146                 ++n;
147               } else {
148                 xcolor.red = (r * 65535) / (rgbCubeSize - 1);
149                 xcolor.green = (g * 65535) / (rgbCubeSize - 1);
150                 xcolor.blue = (b * 65535) / (rgbCubeSize - 1);
151                 if (XAllocColor(display, colormapA, &xcolor)) {
152                   colors[n++] = xcolor.pixel;
153                 } else {
154                   ok = gFalse;
155                 }
156               }
157             }
158           }
159         }
160         if (ok) {
161           break;
162         }
163         XFreeColors(display, colormapA, &colors[1], n-1, 0);
164       }
165       if (!ok) {
166         rgbCubeSize = 1;
167         colors[0] = BlackPixel(display, screenNumA);
168         colors[1] = WhitePixel(display, screenNumA);
169       }
170     }
171   }
172 }
173
174 XSplashOutputDev::~XSplashOutputDev() {
175   delete text;
176 }
177
178 void XSplashOutputDev::drawChar(GfxState *state, double x, double y,
179                                 double dx, double dy,
180                                 double originX, double originY,
181                                 CharCode code, Unicode *u, int uLen) {
182   text->addChar(state, x, y, dx, dy, code, u, uLen);
183   SplashOutputDev::drawChar(state, x, y, dx, dy, originX, originY,
184                             code, u, uLen);
185 }
186
187 GBool XSplashOutputDev::beginType3Char(GfxState *state, double x, double y,
188                                        double dx, double dy,
189                                        CharCode code, Unicode *u, int uLen) {
190   text->addChar(state, x, y, dx, dy, code, u, uLen);
191   return SplashOutputDev::beginType3Char(state, x, y, dx, dy, code, u, uLen);
192 }
193
194 void XSplashOutputDev::clear() {
195   startDoc(NULL);
196   startPage(0, NULL);
197 }
198
199 void XSplashOutputDev::startPage(int pageNum, GfxState *state) {
200   SplashOutputDev::startPage(pageNum, state);
201   text->startPage(state);
202 }
203
204 void XSplashOutputDev::endPage() {
205   SplashOutputDev::endPage();
206   if (!incrementalUpdate) {
207     (*redrawCbk)(redrawCbkData);
208   }
209   text->coalesce(gTrue);
210 }
211
212 void XSplashOutputDev::dump() {
213   if (incrementalUpdate) {
214     (*redrawCbk)(redrawCbkData);
215   }
216 }
217
218 void XSplashOutputDev::updateFont(GfxState *state) {
219   SplashOutputDev::updateFont(state);
220   text->updateFont(state);
221 }
222
223 void XSplashOutputDev::redraw(int srcX, int srcY,
224                               Drawable destDrawable, GC destGC,
225                               int destX, int destY,
226                               int width, int height) {
227   XImage *image;
228   SplashColorPtr dataPtr;
229   SplashRGB8 *p;
230   SplashRGB8 rgb;
231   Gulong pixel;
232   int bw, x, y, r, g, b, gray;
233
234   //~ allocate this image once (whenever the window changes size)
235   //~ use XShm
236   image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL,
237                        width, height, 8, 0);
238   image->data = (char *)gmalloc(height * image->bytes_per_line);
239
240   //~ optimize for known XImage formats
241   bw = getBitmap()->getWidth();
242   dataPtr = getBitmap()->getDataPtr();
243
244   if (trueColor) {
245     for (y = 0; y < height; ++y) {
246       p = dataPtr.rgb8 + (y + srcY) * bw + srcX;
247       for (x = 0; x < width; ++x) {
248         rgb = *p++;
249         r = splashRGB8R(rgb) >> rDiv;
250         g = splashRGB8G(rgb) >> gDiv;
251         b = splashRGB8B(rgb) >> bDiv;
252         pixel = ((Gulong)r << rShift) +
253                 ((Gulong)g << gShift) +
254                 ((Gulong)b << bShift);
255         XPutPixel(image, x, y, pixel);
256       }
257     }
258   } else if (rgbCubeSize == 1) {
259     //~ this should really use splashModeMono, with non-clustered dithering
260     for (y = 0; y < height; ++y) {
261       p = dataPtr.rgb8 + (y + srcY) * bw + srcX;
262       for (x = 0; x < width; ++x) {
263         rgb = *p++;
264         gray = xoutRound(0.299 * splashRGB8R(rgb) +
265                          0.587 * splashRGB8G(rgb) +
266                          0.114 * splashRGB8B(rgb));
267         if (gray < 128) {
268           pixel = colors[0];
269         } else {
270           pixel = colors[1];
271         }
272         XPutPixel(image, x, y, pixel);
273       }
274     }
275   } else {
276     for (y = 0; y < height; ++y) {
277       p = dataPtr.rgb8 + (y + srcY) * bw + srcX;
278       for (x = 0; x < width; ++x) {
279         rgb = *p++;
280         r = (splashRGB8R(rgb) * (rgbCubeSize - 1)) / 255;
281         g = (splashRGB8G(rgb) * (rgbCubeSize - 1)) / 255;
282         b = (splashRGB8B(rgb) * (rgbCubeSize - 1)) / 255;
283         pixel = colors[(r * rgbCubeSize + g) * rgbCubeSize + b];
284         XPutPixel(image, x, y, pixel);
285       }
286     }
287   }
288
289   XPutImage(display, destDrawable, destGC, image,
290             0, 0, destX, destY, width, height);
291
292   gfree(image->data);
293   image->data = NULL;
294   XDestroyImage(image);
295 }
296
297 GBool XSplashOutputDev::findText(Unicode *s, int len,
298                                  GBool startAtTop, GBool stopAtBottom,
299                                  GBool startAtLast, GBool stopAtLast,
300                                  int *xMin, int *yMin,
301                                  int *xMax, int *yMax) {
302   double xMin1, yMin1, xMax1, yMax1;
303   
304   xMin1 = (double)*xMin;
305   yMin1 = (double)*yMin;
306   xMax1 = (double)*xMax;
307   yMax1 = (double)*yMax;
308   if (text->findText(s, len, startAtTop, stopAtBottom,
309                      startAtLast, stopAtLast,
310                      &xMin1, &yMin1, &xMax1, &yMax1)) {
311     *xMin = xoutRound(xMin1);
312     *xMax = xoutRound(xMax1);
313     *yMin = xoutRound(yMin1);
314     *yMax = xoutRound(yMax1);
315     return gTrue;
316   }
317   return gFalse;
318 }
319
320 GString *XSplashOutputDev::getText(int xMin, int yMin, int xMax, int yMax) {
321   return text->getText((double)xMin, (double)yMin,
322                        (double)xMax, (double)yMax);
323 }