1 //========================================================================
5 // Copyright 2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
16 #include <X11/Xutil.h>
18 #include "SplashTypes.h"
19 #include "SplashBitmap.h"
22 #include "TextOutputDev.h"
23 #include "XSplashOutputDev.h"
25 //------------------------------------------------------------------------
26 // Constants and macros
27 //------------------------------------------------------------------------
29 #define xoutRound(x) ((int)(x + 0.5))
31 //------------------------------------------------------------------------
33 //------------------------------------------------------------------------
35 XSplashOutputDev::XSplashOutputDev(Display *displayA, int screenNumA,
36 Visual *visualA, Colormap colormapA,
38 SplashColor paperColorA,
39 GBool installCmapA, int rgbCubeSizeA,
40 GBool incrementalUpdateA,
41 void (*redrawCbkA)(void *data),
42 void *redrawCbkDataA):
43 SplashOutputDev(splashModeRGB8, reverseVideoA, paperColorA)
45 XVisualInfo visualTempl;
46 XVisualInfo *visualList;
54 incrementalUpdate = incrementalUpdateA;
55 redrawCbk = redrawCbkA;
56 redrawCbkData = redrawCbkDataA;
59 text = new TextPage(gFalse);
61 //----- set up the X color stuff
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);
72 // this shouldn't happen
73 XFree((XPointer)visualList);
74 visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl,
77 depth = visualList->depth;
78 if (visualList->c_class == TrueColor) {
80 for (mask = visualList->red_mask, rShift = 0;
82 mask >>= 1, ++rShift) ;
83 for (rDiv = 8; mask; mask >>= 1, --rDiv) ;
84 for (mask = visualList->green_mask, gShift = 0;
86 mask >>= 1, ++gShift) ;
87 for (gDiv = 8; mask; mask >>= 1, --gDiv) ;
88 for (mask = visualList->blue_mask, bShift = 0;
90 mask >>= 1, ++bShift) ;
91 for (bDiv = 8; mask; mask >>= 1, --bDiv) ;
95 XFree((XPointer)visualList);
97 // allocate a color cube
100 // set colors in private colormap
102 for (rgbCubeSize = xOutMaxRGBCube; rgbCubeSize >= 2; --rgbCubeSize) {
103 m = rgbCubeSize * rgbCubeSize * rgbCubeSize;
104 if (XAllocColorCells(display, colormapA, False, NULL, 0, colors, m)) {
108 if (rgbCubeSize >= 2) {
109 m = rgbCubeSize * rgbCubeSize * rgbCubeSize;
110 xcolors = (XColor *)gmalloc(m * sizeof(XColor));
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;
124 XStoreColors(display, colormapA, xcolors, m);
128 colors[0] = BlackPixel(display, screenNumA);
129 colors[1] = WhitePixel(display, screenNumA);
132 // allocate colors in shared colormap
134 if (rgbCubeSize > xOutMaxRGBCube) {
135 rgbCubeSize = xOutMaxRGBCube;
138 for (rgbCubeSize = rgbCubeSizeA; rgbCubeSize >= 2; --rgbCubeSize) {
141 for (r = 0; r < rgbCubeSize && ok; ++r) {
142 for (g = 0; g < rgbCubeSize && ok; ++g) {
143 for (b = 0; b < rgbCubeSize && ok; ++b) {
145 colors[n] = BlackPixel(display, screenNumA);
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;
163 XFreeColors(display, colormapA, &colors[1], n-1, 0);
167 colors[0] = BlackPixel(display, screenNumA);
168 colors[1] = WhitePixel(display, screenNumA);
174 XSplashOutputDev::~XSplashOutputDev() {
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,
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);
194 void XSplashOutputDev::clear() {
199 void XSplashOutputDev::startPage(int pageNum, GfxState *state) {
200 SplashOutputDev::startPage(pageNum, state);
201 text->startPage(state);
204 void XSplashOutputDev::endPage() {
205 SplashOutputDev::endPage();
206 if (!incrementalUpdate) {
207 (*redrawCbk)(redrawCbkData);
209 text->coalesce(gTrue);
212 void XSplashOutputDev::dump() {
213 if (incrementalUpdate) {
214 (*redrawCbk)(redrawCbkData);
218 void XSplashOutputDev::updateFont(GfxState *state) {
219 SplashOutputDev::updateFont(state);
220 text->updateFont(state);
223 void XSplashOutputDev::redraw(int srcX, int srcY,
224 Drawable destDrawable, GC destGC,
225 int destX, int destY,
226 int width, int height) {
228 SplashColorPtr dataPtr;
232 int bw, x, y, r, g, b, gray;
234 //~ allocate this image once (whenever the window changes size)
236 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL,
237 width, height, 8, 0);
238 image->data = (char *)gmalloc(height * image->bytes_per_line);
240 //~ optimize for known XImage formats
241 bw = getBitmap()->getWidth();
242 dataPtr = getBitmap()->getDataPtr();
245 for (y = 0; y < height; ++y) {
246 p = dataPtr.rgb8 + (y + srcY) * bw + srcX;
247 for (x = 0; x < width; ++x) {
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);
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) {
264 gray = xoutRound(0.299 * splashRGB8R(rgb) +
265 0.587 * splashRGB8G(rgb) +
266 0.114 * splashRGB8B(rgb));
272 XPutPixel(image, x, y, pixel);
276 for (y = 0; y < height; ++y) {
277 p = dataPtr.rgb8 + (y + srcY) * bw + srcX;
278 for (x = 0; x < width; ++x) {
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);
289 XPutImage(display, destDrawable, destGC, image,
290 0, 0, destX, destY, width, height);
294 XDestroyImage(image);
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;
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);
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);