Back to index

tetex-bin  3.0
dvi-draw.c
Go to the documentation of this file.
00001 /* The rest of the code has the following copyright:
00002 
00003 Copyright (c) 1990-2004  Paul Vojta and others
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to
00007 deal in the Software without restriction, including without limitation the
00008 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00009 sell copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00018 PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
00019 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00020 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00021 OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 NOTE:
00024        xdvi is based on prior work, as noted in the modification history
00025        in xdvi.c.
00026 
00027 \*========================================================================*/
00028 
00029 #include "xdvi-config.h"
00030 #include "xdvi.h"
00031 
00032 #include <stdarg.h>
00033 
00034 #include <stdlib.h>
00035 #include <ctype.h>
00036 
00037 #include <setjmp.h>
00038 
00039 #define USE_HASH
00040 
00041 #include <ctype.h>
00042 #include "kpathsea/c-fopen.h"
00043 #include "kpathsea/c-stat.h"
00044 #include "kpathsea/magstep.h"
00045 #include "kpathsea/tex-file.h"
00046 #include "kpathsea/c-vararg.h"
00047 
00048 #include <string.h>
00049 
00050 #include "dvi.h"
00051 #include "string-utils.h"
00052 #include "util.h"
00053 #include "x_util.h"
00054 #include "events.h"
00055 #include "dvi-init.h"
00056 #include "statusline.h"
00057 #include "hypertex.h"
00058 #include "special.h"
00059 #include "tfmload.h"
00060 #include "read-mapfile.h"
00061 #include "my-snprintf.h"
00062 #include "kpathsea/tex-file.h"
00063 #include "mag.h"
00064 #include "message-window.h"
00065 
00066 #include "dvi-draw.h"
00067 #include "search-internal.h"
00068 #include "encodings.h"
00069 #include "pagesel.h"
00070 #include "pagehist.h"
00071 
00072 #ifdef RGB_ANTI_ALIASING
00073 #define TRACE_AA 0
00074 #define TRACE_AA1 1
00075 #define TRACE_AA3 0
00076 #else
00077 #define TRACE_AA 0
00078 #define TRACE_AA1 0
00079 #define TRACE_AA3 0
00080 #endif
00081 
00082 #define MY_DEBUG 1
00083 
00084 #if MY_DEBUG
00085 # define TRACE_FIND_VERBOSE(x) TRACE_FIND(x)
00086 #else
00087 # define TRACE_FIND_VERBOSE(x) /* as nothing */
00088 #endif
00089 
00090 #if PS && PS_GS
00091 #include "psgs.h"
00092 #endif /* PS && PS_GS */
00093 
00094 #ifdef DOPRNT /* define this if vfprintf gives you trouble */
00095 # define vfprintf(stream, message, args)  _doprnt(message, args, stream)
00096 #endif
00097 
00098 #define BUF_SIZE 1024
00099 
00100 /*
00101  *     All calculations are done with shrink factor = 1, so we re-do some
00102  *     macros accordingly.  Many of these are also defined in special.c.
00103  */
00104 
00105 #define       xpixel_conv(x)       ((int) ((x) >> 16))
00106 #define       xpixel_round(x)      ((int) ROUNDUP(x, 1 << 16))
00107 
00108 #define       G_PXL_H              xpixel_conv(currinf.data.dvi_h)
00109 #define       G_OFFSET_X    (resource.xoffset_int << 16) + (3 << 15)
00110 #define       G_OFFSET_Y    (resource.yoffset_int << 16) + (3 << 15)
00111 
00112 #ifdef T1LIB
00113 /* hashing stuff to speed up checking whether a font or tfminfo file
00114    has already been loaded.
00115 */
00116 #define T1FONTS_INITIAL_HASHTABLE_SIZE 1031
00117 static hashTableT t1fonts_hash;
00118 static hashTableT tfminfo_hash;
00119 static hashTableT fontmaps_hash;
00120 static hashTableT font_warn_hash;
00121 
00122 typedef enum { FAILURE_BLANK = -2, FAILURE_PK = -1, SUCCESS = 0 } t1FontLoadStatusT;
00123 #endif
00124 
00125 #if PS
00126 int scanned_page_ps;
00127 int scanned_page_ps_bak;
00128 #endif
00129 
00130 #if COLOR
00131 int scanned_page_color;
00132 #endif
00133 
00134 int scanned_page_reset, scanned_page;
00135 
00136 struct drawinf currinf;
00137 Boolean htex_inside_href = False; /* whether we're inside a href */
00138 
00139 Boolean       drawing_mag = False;
00140 
00141 #ifdef T1LIB
00142 
00143 # include "t1lib.h"
00144 
00145 /* Datastructures:
00146 
00147    encodings[n]: Loaded from map file
00148    [0] = 8r,  <vector>
00149    [1] = 8c,  <vector>
00150 
00151    The vectors are demand-loaded in 'load_encoded_font'
00152 */
00153 
00154 struct encoding {
00155     char *enc;       /* This may be NULL.  From dvips maps we get
00156                  encodings loaded by filename, and no name given */
00157     char *file;
00158     char **vector;
00159 };
00160 
00161 static struct encoding *encodings = NULL; /* Dynamic array = realloc when it gets full */
00162 static size_t enclidx = 0;                /* global, for communication with find_T1_font */
00163 
00164 /*
00165 
00166    t1fonts[n]: Built as xdvi loads t1 fonts
00167    idx  file                short  t1id   loaded
00168    [0] = /path/cmr10.pfb,   cmr10  0      1
00169    [1] = /path/prmr.pfa,    prmr   1      0
00170    [2] = /path/pcrr8a.pfa,  pcrr8a 2      0
00171 
00172    This array enumerates the loaded t1 fonts by full path name.
00173    The integer `t1id' is the t1lib font id.  The font will not be
00174    extended/slanted/encoded.  The `loaded' field indicates if
00175    T1_LoadFont has been called for the font yet.  Texfonts that need a
00176    modified version of the t1 font must use T1_CopyFont to copy the
00177    raw font and obtain the id of a new t1 font which can then be
00178    modified.  As described in the t1 docs a font must be loaded before
00179    it can be copied.
00180 
00181    Fonts that are copies of other fonts have NULL filenames.  If any
00182    font files are to be reused based on the file name, the raw font
00183    must be reused, not a copy.
00184 
00185    The `short' field contains the font as it was identified in the
00186    fontmap.  This is used to save searching; if two fonts are
00187    identified the same way in the fontmap, they are the same font.
00188 
00189 */
00190 
00191 struct t1font_info {
00192     char *file;
00193     char *shortname;
00194     int t1id;
00195     int loaded;
00196 };
00197 
00198 static struct t1font_info *t1fonts = NULL;       /* Dynamic array */
00199 
00200 /*
00201    fontmaps[n]: Loaded from map file, and extended with 'implied'
00202        fonts as needed.
00203    idx  texname enc  exten. slant  filena.       t1libid       pathn. tfmidx
00204    [0] = pcrr8rn 0   750    0      pcrr8a 2      ...    2
00205    [1] = putro8r 0   0      0      putro8r 3     ...    3
00206 
00207    The first 5 fields of this table are loaded from the font map
00208    files, or filled out with default values when implied fonts are
00209    set-up.  The t1libid is -1 until the font is loaded or copied as
00210    described under t1fonts.  Once the dvi file reveals that the font
00211    is needed, it is located on disk to ensure it exists, and the
00212    pathname field is filled out.  The t1 font is not loaded or
00213    copied before it's needed because set_t1_char has been called to
00214    draw a glyph from the font.  The late loading is necessiated by the
00215    high cost of loading fonts.  If the font loading is concentrated at
00216    startup of the program the startup-time becomes ecessively high due
00217    to the high number of fonts used by the average LaTeX document.
00218 
00219    A value of 0 for `extension'/`slant' means no extension/slant.  If
00220    the input values are decimal (less than 10) they're multiplied by
00221    1000 and 10000 respectively to obtain fixed-point integer values.
00222    (This means that xdvi will translate entries like `0.81' to 810.)
00223    Integer values have the advantage that they can be tested for
00224    exact equality on all architectures.
00225 */
00226 
00227 struct fontmap {
00228     char *texname;
00229     int enc;  /* Index in encoding array */
00230     int extension;   /* Fixed point, *1000 */
00231     int slant;       /* Fixed point, *10000, some font slantings have 4
00232                  significant digits, all after the decimalpoint */
00233     char *filename;  /* Name of the t1 font file as given in map/dvi */
00234 
00235     int t1libid;     /* The t1lib id of this font, or -1 if not set up */
00236     char *pathname;  /* Full path of the font, once needed and located */
00237     int tfmidx;      /* Index in tfminfo array, or -1 */
00238     Boolean warned_about;   /* whether a warning message about this font has been displayed yet */
00239     /*
00240       if the font file was not readable for some reason (e.g. corrupt,
00241       or encrypted for proprietry distribution), load_font_now() will
00242       try to load a PK version via load_font() instead. If this is
00243       successful, it will set force_pk to true, which will tell
00244       get_t1_glyph() to return immediately, and just use the standard
00245       set_char() routine to set the PK glyph. If even that fails,
00246       get_t1_glyph() returns an error status in a special flag that's
00247       evaluated by set_t1_char().
00248     */
00249     Boolean force_pk;              
00250 };
00251 
00252 static struct fontmap *fontmaps = NULL;
00253 static size_t g_maplidx = 0; /* global, for communication with find_texfont */
00254 
00255 /*
00256    widthinfo[n]: TFM width info, loaded on demand as the fonts are used.
00257    idx  texname      widths
00258    [0] = cmr10              ...
00259    [1] = ptmr8r             ...
00260    [2] = pcrr8rn     ...
00261    [3] = putro8r     ...
00262 
00263    The widthinfo is loaded from the font tfm file because the type1
00264    width information isn't precise enough to avoid accumulating
00265    rounding errors that make things visibly misaligned.  This is
00266    esp. noticeable in tables (for the lines separating the columns).
00267 
00268    For other than "design" sizes the widths are scaled up or down.
00269 
00270 */
00271 
00272 struct tfminfos {
00273     const char *texname;
00274     long designsize;
00275     long widths[256];
00276     long fontdimen2; /* width of word spacing in this font */
00277 };
00278 
00279 static struct tfminfos *tfminfo = NULL;
00280 
00281 /* For file reading */
00282 # define BUFFER_SIZE 1024
00283 
00284 /* This is the conversion factor from TeXs pt to TeXs bp (big point).
00285    Maximum machine precision is needed to keep it accurate. */
00286 /* UNUSED */
00287 /* static double bp_fac=72.0/72.27; */
00288 
00289 /* Try to convert from PS charspace units to DVI units with minimal
00290    loss of significant digits */
00291 # define t1_dvi_conv(x)     ((((int) (x)) << 16)/1000)
00292 /* Convert from DVI units to TeX pt */
00293 # define dvi_pt_conv(x) (((long) ((x)*dimconv)) >> 19)
00294 
00295 /* Convert from TFM units to DVI units */
00296 # define tfm_dvi_conv(x) (((int) (x)) >> 1)
00297 
00298 static Boolean padMismatch = False; /* Does t1lib padding match xdvi required padding? */
00299 static int archpad;
00300 # define T1PAD(bits, pad)  (((bits) + (pad) - 1) & -(pad))
00301 
00302 static struct glyph *get_t1_glyph(
00303 # ifdef TEXXET
00304                               wide_ubyte cmd,
00305 # endif
00306                               wide_ubyte ch, t1FontLoadStatusT *flag,
00307                               Boolean is_geom_scan);
00308 
00309 # ifdef WORDS_BIGENDIAN
00310 unsigned char rbits[] = {
00311     0x00,   /* 00000000 -> 00000000 */
00312     0x80,   /* 00000001 -> 10000000 */
00313     0x40,   /* 00000010 -> 01000000 */
00314     0xC0,   /* 00000011 -> 11000000 */
00315     0x20,   /* 00000100 -> 00100000 */
00316     0xA0,   /* 00000101 -> 10100000 */
00317     0x60,   /* 00000110 -> 01100000 */
00318     0xE0,   /* 00000111 -> 11100000 */
00319     0x10,   /* 00001000 -> 00010000 */
00320     0x90,   /* 00001001 -> 10010000 */
00321     0x50,   /* 00001010 -> 01010000 */
00322     0xD0,   /* 00001011 -> 11010000 */
00323     0x30,   /* 00001100 -> 00110000 */
00324     0xB0,   /* 00001101 -> 10110000 */
00325     0x70,   /* 00001110 -> 01110000 */
00326     0xF0,   /* 00001111 -> 11110000 */
00327     0x08,   /* 00010000 -> 00001000 */
00328     0x88,   /* 00010001 -> 10001000 */
00329     0x48,   /* 00010010 -> 01001000 */
00330     0xC8,   /* 00010011 -> 11001000 */
00331     0x28,   /* 00010100 -> 00101000 */
00332     0xA8,   /* 00010101 -> 10101000 */
00333     0x68,   /* 00010110 -> 01101000 */
00334     0xE8,   /* 00010111 -> 11101000 */
00335     0x18,   /* 00011000 -> 00011000 */
00336     0x98,   /* 00011001 -> 10011000 */
00337     0x58,   /* 00011010 -> 01011000 */
00338     0xD8,   /* 00011011 -> 11011000 */
00339     0x38,   /* 00011100 -> 00111000 */
00340     0xB8,   /* 00011101 -> 10111000 */
00341     0x78,   /* 00011110 -> 01111000 */
00342     0xF8,   /* 00011111 -> 11111000 */
00343     0x04,   /* 00100000 -> 00000100 */
00344     0x84,   /* 00100001 -> 10000100 */
00345     0x44,   /* 00100010 -> 01000100 */
00346     0xC4,   /* 00100011 -> 11000100 */
00347     0x24,   /* 00100100 -> 00100100 */
00348     0xA4,   /* 00100101 -> 10100100 */
00349     0x64,   /* 00100110 -> 01100100 */
00350     0xE4,   /* 00100111 -> 11100100 */
00351     0x14,   /* 00101000 -> 00010100 */
00352     0x94,   /* 00101001 -> 10010100 */
00353     0x54,   /* 00101010 -> 01010100 */
00354     0xD4,   /* 00101011 -> 11010100 */
00355     0x34,   /* 00101100 -> 00110100 */
00356     0xB4,   /* 00101101 -> 10110100 */
00357     0x74,   /* 00101110 -> 01110100 */
00358     0xF4,   /* 00101111 -> 11110100 */
00359     0x0C,   /* 00110000 -> 00001100 */
00360     0x8C,   /* 00110001 -> 10001100 */
00361     0x4C,   /* 00110010 -> 01001100 */
00362     0xCC,   /* 00110011 -> 11001100 */
00363     0x2C,   /* 00110100 -> 00101100 */
00364     0xAC,   /* 00110101 -> 10101100 */
00365     0x6C,   /* 00110110 -> 01101100 */
00366     0xEC,   /* 00110111 -> 11101100 */
00367     0x1C,   /* 00111000 -> 00011100 */
00368     0x9C,   /* 00111001 -> 10011100 */
00369     0x5C,   /* 00111010 -> 01011100 */
00370     0xDC,   /* 00111011 -> 11011100 */
00371     0x3C,   /* 00111100 -> 00111100 */
00372     0xBC,   /* 00111101 -> 10111100 */
00373     0x7C,   /* 00111110 -> 01111100 */
00374     0xFC,   /* 00111111 -> 11111100 */
00375     0x02,   /* 01000000 -> 00000010 */
00376     0x82,   /* 01000001 -> 10000010 */
00377     0x42,   /* 01000010 -> 01000010 */
00378     0xC2,   /* 01000011 -> 11000010 */
00379     0x22,   /* 01000100 -> 00100010 */
00380     0xA2,   /* 01000101 -> 10100010 */
00381     0x62,   /* 01000110 -> 01100010 */
00382     0xE2,   /* 01000111 -> 11100010 */
00383     0x12,   /* 01001000 -> 00010010 */
00384     0x92,   /* 01001001 -> 10010010 */
00385     0x52,   /* 01001010 -> 01010010 */
00386     0xD2,   /* 01001011 -> 11010010 */
00387     0x32,   /* 01001100 -> 00110010 */
00388     0xB2,   /* 01001101 -> 10110010 */
00389     0x72,   /* 01001110 -> 01110010 */
00390     0xF2,   /* 01001111 -> 11110010 */
00391     0x0A,   /* 01010000 -> 00001010 */
00392     0x8A,   /* 01010001 -> 10001010 */
00393     0x4A,   /* 01010010 -> 01001010 */
00394     0xCA,   /* 01010011 -> 11001010 */
00395     0x2A,   /* 01010100 -> 00101010 */
00396     0xAA,   /* 01010101 -> 10101010 */
00397     0x6A,   /* 01010110 -> 01101010 */
00398     0xEA,   /* 01010111 -> 11101010 */
00399     0x1A,   /* 01011000 -> 00011010 */
00400     0x9A,   /* 01011001 -> 10011010 */
00401     0x5A,   /* 01011010 -> 01011010 */
00402     0xDA,   /* 01011011 -> 11011010 */
00403     0x3A,   /* 01011100 -> 00111010 */
00404     0xBA,   /* 01011101 -> 10111010 */
00405     0x7A,   /* 01011110 -> 01111010 */
00406     0xFA,   /* 01011111 -> 11111010 */
00407     0x06,   /* 01100000 -> 00000110 */
00408     0x86,   /* 01100001 -> 10000110 */
00409     0x46,   /* 01100010 -> 01000110 */
00410     0xC6,   /* 01100011 -> 11000110 */
00411     0x26,   /* 01100100 -> 00100110 */
00412     0xA6,   /* 01100101 -> 10100110 */
00413     0x66,   /* 01100110 -> 01100110 */
00414     0xE6,   /* 01100111 -> 11100110 */
00415     0x16,   /* 01101000 -> 00010110 */
00416     0x96,   /* 01101001 -> 10010110 */
00417     0x56,   /* 01101010 -> 01010110 */
00418     0xD6,   /* 01101011 -> 11010110 */
00419     0x36,   /* 01101100 -> 00110110 */
00420     0xB6,   /* 01101101 -> 10110110 */
00421     0x76,   /* 01101110 -> 01110110 */
00422     0xF6,   /* 01101111 -> 11110110 */
00423     0x0E,   /* 01110000 -> 00001110 */
00424     0x8E,   /* 01110001 -> 10001110 */
00425     0x4E,   /* 01110010 -> 01001110 */
00426     0xCE,   /* 01110011 -> 11001110 */
00427     0x2E,   /* 01110100 -> 00101110 */
00428     0xAE,   /* 01110101 -> 10101110 */
00429     0x6E,   /* 01110110 -> 01101110 */
00430     0xEE,   /* 01110111 -> 11101110 */
00431     0x1E,   /* 01111000 -> 00011110 */
00432     0x9E,   /* 01111001 -> 10011110 */
00433     0x5E,   /* 01111010 -> 01011110 */
00434     0xDE,   /* 01111011 -> 11011110 */
00435     0x3E,   /* 01111100 -> 00111110 */
00436     0xBE,   /* 01111101 -> 10111110 */
00437     0x7E,   /* 01111110 -> 01111110 */
00438     0xFE,   /* 01111111 -> 11111110 */
00439     0x01,   /* 10000000 -> 00000001 */
00440     0x81,   /* 10000001 -> 10000001 */
00441     0x41,   /* 10000010 -> 01000001 */
00442     0xC1,   /* 10000011 -> 11000001 */
00443     0x21,   /* 10000100 -> 00100001 */
00444     0xA1,   /* 10000101 -> 10100001 */
00445     0x61,   /* 10000110 -> 01100001 */
00446     0xE1,   /* 10000111 -> 11100001 */
00447     0x11,   /* 10001000 -> 00010001 */
00448     0x91,   /* 10001001 -> 10010001 */
00449     0x51,   /* 10001010 -> 01010001 */
00450     0xD1,   /* 10001011 -> 11010001 */
00451     0x31,   /* 10001100 -> 00110001 */
00452     0xB1,   /* 10001101 -> 10110001 */
00453     0x71,   /* 10001110 -> 01110001 */
00454     0xF1,   /* 10001111 -> 11110001 */
00455     0x09,   /* 10010000 -> 00001001 */
00456     0x89,   /* 10010001 -> 10001001 */
00457     0x49,   /* 10010010 -> 01001001 */
00458     0xC9,   /* 10010011 -> 11001001 */
00459     0x29,   /* 10010100 -> 00101001 */
00460     0xA9,   /* 10010101 -> 10101001 */
00461     0x69,   /* 10010110 -> 01101001 */
00462     0xE9,   /* 10010111 -> 11101001 */
00463     0x19,   /* 10011000 -> 00011001 */
00464     0x99,   /* 10011001 -> 10011001 */
00465     0x59,   /* 10011010 -> 01011001 */
00466     0xD9,   /* 10011011 -> 11011001 */
00467     0x39,   /* 10011100 -> 00111001 */
00468     0xB9,   /* 10011101 -> 10111001 */
00469     0x79,   /* 10011110 -> 01111001 */
00470     0xF9,   /* 10011111 -> 11111001 */
00471     0x05,   /* 10100000 -> 00000101 */
00472     0x85,   /* 10100001 -> 10000101 */
00473     0x45,   /* 10100010 -> 01000101 */
00474     0xC5,   /* 10100011 -> 11000101 */
00475     0x25,   /* 10100100 -> 00100101 */
00476     0xA5,   /* 10100101 -> 10100101 */
00477     0x65,   /* 10100110 -> 01100101 */
00478     0xE5,   /* 10100111 -> 11100101 */
00479     0x15,   /* 10101000 -> 00010101 */
00480     0x95,   /* 10101001 -> 10010101 */
00481     0x55,   /* 10101010 -> 01010101 */
00482     0xD5,   /* 10101011 -> 11010101 */
00483     0x35,   /* 10101100 -> 00110101 */
00484     0xB5,   /* 10101101 -> 10110101 */
00485     0x75,   /* 10101110 -> 01110101 */
00486     0xF5,   /* 10101111 -> 11110101 */
00487     0x0D,   /* 10110000 -> 00001101 */
00488     0x8D,   /* 10110001 -> 10001101 */
00489     0x4D,   /* 10110010 -> 01001101 */
00490     0xCD,   /* 10110011 -> 11001101 */
00491     0x2D,   /* 10110100 -> 00101101 */
00492     0xAD,   /* 10110101 -> 10101101 */
00493     0x6D,   /* 10110110 -> 01101101 */
00494     0xED,   /* 10110111 -> 11101101 */
00495     0x1D,   /* 10111000 -> 00011101 */
00496     0x9D,   /* 10111001 -> 10011101 */
00497     0x5D,   /* 10111010 -> 01011101 */
00498     0xDD,   /* 10111011 -> 11011101 */
00499     0x3D,   /* 10111100 -> 00111101 */
00500     0xBD,   /* 10111101 -> 10111101 */
00501     0x7D,   /* 10111110 -> 01111101 */
00502     0xFD,   /* 10111111 -> 11111101 */
00503     0x03,   /* 11000000 -> 00000011 */
00504     0x83,   /* 11000001 -> 10000011 */
00505     0x43,   /* 11000010 -> 01000011 */
00506     0xC3,   /* 11000011 -> 11000011 */
00507     0x23,   /* 11000100 -> 00100011 */
00508     0xA3,   /* 11000101 -> 10100011 */
00509     0x63,   /* 11000110 -> 01100011 */
00510     0xE3,   /* 11000111 -> 11100011 */
00511     0x13,   /* 11001000 -> 00010011 */
00512     0x93,   /* 11001001 -> 10010011 */
00513     0x53,   /* 11001010 -> 01010011 */
00514     0xD3,   /* 11001011 -> 11010011 */
00515     0x33,   /* 11001100 -> 00110011 */
00516     0xB3,   /* 11001101 -> 10110011 */
00517     0x73,   /* 11001110 -> 01110011 */
00518     0xF3,   /* 11001111 -> 11110011 */
00519     0x0B,   /* 11010000 -> 00001011 */
00520     0x8B,   /* 11010001 -> 10001011 */
00521     0x4B,   /* 11010010 -> 01001011 */
00522     0xCB,   /* 11010011 -> 11001011 */
00523     0x2B,   /* 11010100 -> 00101011 */
00524     0xAB,   /* 11010101 -> 10101011 */
00525     0x6B,   /* 11010110 -> 01101011 */
00526     0xEB,   /* 11010111 -> 11101011 */
00527     0x1B,   /* 11011000 -> 00011011 */
00528     0x9B,   /* 11011001 -> 10011011 */
00529     0x5B,   /* 11011010 -> 01011011 */
00530     0xDB,   /* 11011011 -> 11011011 */
00531     0x3B,   /* 11011100 -> 00111011 */
00532     0xBB,   /* 11011101 -> 10111011 */
00533     0x7B,   /* 11011110 -> 01111011 */
00534     0xFB,   /* 11011111 -> 11111011 */
00535     0x07,   /* 11100000 -> 00000111 */
00536     0x87,   /* 11100001 -> 10000111 */
00537     0x47,   /* 11100010 -> 01000111 */
00538     0xC7,   /* 11100011 -> 11000111 */
00539     0x27,   /* 11100100 -> 00100111 */
00540     0xA7,   /* 11100101 -> 10100111 */
00541     0x67,   /* 11100110 -> 01100111 */
00542     0xE7,   /* 11100111 -> 11100111 */
00543     0x17,   /* 11101000 -> 00010111 */
00544     0x97,   /* 11101001 -> 10010111 */
00545     0x57,   /* 11101010 -> 01010111 */
00546     0xD7,   /* 11101011 -> 11010111 */
00547     0x37,   /* 11101100 -> 00110111 */
00548     0xB7,   /* 11101101 -> 10110111 */
00549     0x77,   /* 11101110 -> 01110111 */
00550     0xF7,   /* 11101111 -> 11110111 */
00551     0x0F,   /* 11110000 -> 00001111 */
00552     0x8F,   /* 11110001 -> 10001111 */
00553     0x4F,   /* 11110010 -> 01001111 */
00554     0xCF,   /* 11110011 -> 11001111 */
00555     0x2F,   /* 11110100 -> 00101111 */
00556     0xAF,   /* 11110101 -> 10101111 */
00557     0x6F,   /* 11110110 -> 01101111 */
00558     0xEF,   /* 11110111 -> 11101111 */
00559     0x1F,   /* 11111000 -> 00011111 */
00560     0x9F,   /* 11111001 -> 10011111 */
00561     0x5F,   /* 11111010 -> 01011111 */
00562     0xDF,   /* 11111011 -> 11011111 */
00563     0x3F,   /* 11111100 -> 00111111 */
00564     0xBF,   /* 11111101 -> 10111111 */
00565     0x7F,   /* 11111110 -> 01111111 */
00566     0xFF    /* 11111111 -> 11111111 */
00567 };
00568 # endif /* WORDS_BIGENDIAN */
00569 #endif /* T1LIB */
00570 
00571 static struct frame frame0; /* dummy head of list */
00572 #ifdef TEXXET
00573 static struct frame *scan_frame;   /* head frame for scanning */
00574 #endif
00575 
00576 static const char *const reverse_search_helptext =
00577 "Forward/reverse search allows you to jump from a point "
00578 "in the DVI file to the corresponding location in the .tex source file, and vice versa. "
00579 "To make this possible, the .tex file needs to be compiled with source special support. "
00580 "This can be done by using either a package like \"srcltx.sty\" or \"srctex.sty\", "
00581 "or a command-line switch like \"-src\" for the TeX executable. "
00582 "See the xdvi man page (section SOURCE SPECIALS) "
00583 "for more information about this.";
00584 
00585 static ubyte dvi_buffer[DVI_BUFFER_LEN];
00586 ubyte *G_dvi_buf_ptr = dvi_buffer;
00587 static struct frame *current_frame;
00588 
00589 /* Points to drawinf record containing current dvi file location (for update by
00590    geom_scan).  */
00591 static struct drawinf       *dvi_pointer_frame = NULL;
00592 
00593 #ifdef TEXXET
00594 #define       DIR    currinf.dir
00595 #else
00596 #define       DIR    1
00597 #endif
00598 
00599 /*
00600  *     Explanation of the following constant:
00601  *     offset_[xy]   << 16: margin (defaults to one inch)
00602  *     currwin.shrinkfactor << 16: one pixel page border
00603  *     currwin.shrinkfactor << 15: rounding for pixel_conv
00604  */
00605 #define OFFSET_X     (resource.xoffset_int << 16) + (currwin.shrinkfactor * 3 << 15)
00606 #define OFFSET_Y     (resource.yoffset_int << 16) + (currwin.shrinkfactor * 3 << 15)
00607 
00608 #if (BMBYTES == 1)
00609 bmUnitT bit_masks[] = {
00610     0x0, 0x1, 0x3, 0x7,
00611     0xf, 0x1f, 0x3f, 0x7f,
00612     0xff
00613 };
00614 #else
00615 #if (BMBYTES == 2)
00616 bmUnitT bit_masks[] = {
00617     0x0, 0x1, 0x3, 0x7,
00618     0xf, 0x1f, 0x3f, 0x7f,
00619     0xff, 0x1ff, 0x3ff, 0x7ff,
00620     0xfff, 0x1fff, 0x3fff, 0x7fff,
00621     0xffff
00622 };
00623 #else /* BMBYTES == 4 */
00624 bmUnitT bit_masks[] = {
00625     0x0, 0x1, 0x3, 0x7,
00626     0xf, 0x1f, 0x3f, 0x7f,
00627     0xff, 0x1ff, 0x3ff, 0x7ff,
00628     0xfff, 0x1fff, 0x3fff, 0x7fff,
00629     0xffff, 0x1ffff, 0x3ffff, 0x7ffff,
00630     0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
00631     0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
00632     0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
00633     0xffffffff
00634 };
00635 #endif
00636 #endif
00637 
00638 #ifdef VMS
00639 #define       off_t  int
00640 #endif
00641 extern off_t lseek();
00642 
00643 #ifndef       SEEK_SET      /* if <unistd.h> is not provided (or for <X11R5) */
00644 #define       SEEK_SET      0
00645 #define       SEEK_CUR      1
00646 #define       SEEK_END      2
00647 #endif
00648 
00649 static void draw_part(FILE *fp, struct frame *minframe, double current_dimconv);
00650 
00651 static void source_fwd_draw_box(void);
00652 
00653 
00654 
00655 /*
00656  *     X routines.
00657  */
00658 
00659 /*
00660  *     Put a rectangle on the screen.
00661  */
00662 static void
00663 put_rule(int x, int y, unsigned int w, unsigned int h)
00664 {
00665     if (htex_inside_href)
00666        htex_record_position(x, y, w, h);
00667     if (x < globals.win_expose.max_x && x + (int)w >= globals.win_expose.min_x && y < globals.win_expose.max_y && y + (int)h >= globals.win_expose.min_y) {
00668        if (--globals.ev.ctr == 0) {
00669            if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
00670 /*            fprintf(stderr, "longjmp1!\n"); */
00671               longjmp(globals.ev.canit, 1);
00672            }
00673        }
00674 #if COLOR
00675        if (fg_active != fg_current)
00676            do_color_change();
00677 #endif
00678        XFillRectangle(DISP, currwin.win,
00679                      globals.gc.rule,
00680                      x - currwin.base_x,
00681                      y - currwin.base_y,
00682                      w ? w : 1,
00683                      h ? h : 1);
00684     }
00685 }
00686 
00687 static void
00688 put_bitmap(struct bitmap *bitmap, int x, int y)
00689 {
00690     if (globals.debug & DBG_BITMAP)
00691        printf("X(%d,%d)\n", x - currwin.base_x, y - currwin.base_y);
00692     if (htex_inside_href)
00693        htex_record_position(x, y, bitmap->w, bitmap->h);
00694     if (x < globals.win_expose.max_x && x + (int)bitmap->w >= globals.win_expose.min_x &&
00695        y < globals.win_expose.max_y && y + (int)bitmap->h >= globals.win_expose.min_y) {
00696        if (--globals.ev.ctr == 0)
00697            if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
00698 /*            fprintf(stderr, "longjmp2!\n"); */
00699               longjmp(globals.ev.canit, 1);
00700            }
00701 #if COLOR
00702        if (fg_active != fg_current)
00703            do_color_change();
00704 #endif
00705        G_image->width = bitmap->w;
00706        G_image->height = bitmap->h;
00707        G_image->data = bitmap->bits;
00708        G_image->bytes_per_line = bitmap->bytes_wide;
00709        XPutImage(DISP, currwin.win, globals.gc.fore, G_image,
00710                 0, 0,
00711                 x - currwin.base_x, y - currwin.base_y, bitmap->w, bitmap->h);
00712        if (globals.gc.fore2) {
00713            XPutImage(DISP, currwin.win, globals.gc.fore2, G_image,
00714                     0, 0,
00715                     x - currwin.base_x, y - currwin.base_y,
00716                     bitmap->w, bitmap->h);
00717        }
00718     }
00719 }
00720 
00721 #if GREY
00722 
00723 /* Anti-aliasing stuff.
00724    The method used here is supersampling of the unshrunk glyph (this
00725    also means that no anti-aliasing happens at shrink 1). A sample
00726    of the number of bits that are `on' in the unsrunk glyph determines
00727    the grey level of the shrunk image.
00728 */
00729 
00730 /* Pixel lookup tables for anti-aliasing: These store all possible
00731    supersampling values (i.e. number of bits set in the unshrunk
00732    image) for the given shrink factor. E.g. at shrink level 2, the
00733    size of the pixel table is 4; in other words, 1 pixel in the shrunk
00734    image corresponds to 4 pixels in the unshrunk image. Thus, the possible
00735    values for shink level 2 are: black, 1/4 (0x404040), 1/2 (0x808080),
00736    3/4 (0xc0c0c0) and white (0xffffff).
00737 */
00738 static Pixel *pixeltbl;
00739 static Pixel *pixeltbl_gc2; /* drawing to globals.gc.fore2 (compare pixmap2_gc2) */
00740 
00741 static void shrink_glyph_grey(struct glyph *);
00742 
00743 static void
00744 put_image(struct glyph *g, int x, int y)
00745 {
00746     XImage *img = g->image2;
00747 
00748     if (htex_inside_href)
00749        htex_record_position(x, y, img->width, img->height);
00750     if (x < globals.win_expose.max_x && x + img->width >= globals.win_expose.min_x &&
00751        y < globals.win_expose.max_y && y + img->height >= globals.win_expose.min_y) {
00752        if (--globals.ev.ctr == 0)
00753            if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
00754 /*            fprintf(stderr, "longjmp3!\n"); */
00755               longjmp(globals.ev.canit, 1);
00756            }
00757 
00758 #if COLOR
00759        if (g->fg != fg_current)    /* if color change since last use */
00760            shrink_glyph_grey(g);
00761        else if (fg_active != fg_current)  /* if GCs need updating */
00762            do_color_change();
00763 #endif
00764        /* TODO: Can we increase gamma locally to make the inverted text more readable?
00765           
00766           and to draw the background, so something like this:
00767           XFillRectangle(DISP, currwin.win, globals.gc.fore, x - currwin.base_x, y - currwin.base_y,
00768           (unsigned int)img->width * 2, (unsigned int)img->height * 2);
00769           
00770           test this with color changes!!
00771        */
00772        /*TEST_DELAY("check point 1 ...")*/
00773        XPutImage(DISP, currwin.win, globals.gc.fore, img,
00774                 0, 0,
00775                 x - currwin.base_x, y - currwin.base_y,
00776                 (unsigned int)img->width, (unsigned int)img->height);
00777        /*TEST_DELAY("check point 2 ...")*/
00778 
00779        if (globals.gc.fore2 != NULL) {
00780            img->data = g->pixmap2_gc2;
00781            XPutImage(DISP, currwin.win, globals.gc.fore2, img,
00782                     0, 0,
00783                     x - currwin.base_x, y - currwin.base_y,
00784                     (unsigned int)img->width, (unsigned int)img->height);
00785            img->data = g->pixmap2;
00786        }
00787        /*TEST_DELAY("check point 3 ...")*/
00788     }
00789 }
00790 #endif /* GREY */
00791 
00792 /*
00793  *     Draw the border of a rectangle on the screen.
00794  *     This should be replaced by a grey background both in Xaw and Motif
00795  *     as soon as #470325 is fixed (see also FIXED_FLUSHING_PAGING).
00796  */
00797 static void
00798 draw_border(int x, int y, unsigned int width, unsigned int height, GC ourGC)
00799 {
00800     --width;
00801     --height;
00802     XDrawRectangle(DISP, currwin.win, ourGC, x, y, width, height);
00803 }
00804 
00805 
00806 /*
00807  *     Byte reading routines for dvi file.
00808  */
00809 
00810 #define       xtell(fp, pos)       (lseek(fileno(fp), 0L, SEEK_CUR) - \
00811                          (currinf.end - (pos)))
00812 
00813 static ubyte
00814 xxone(FILE *fp)
00815 {
00816     if (currinf.virtual) {
00817        ++currinf.pos;
00818        return EOP;
00819     }
00820 
00821     currinf.end = G_dvi_buf_ptr
00822        + read(fileno(fp), (char *)(currinf.pos = G_dvi_buf_ptr), DVI_BUFFER_LEN);
00823     return currinf.end > G_dvi_buf_ptr ? *(currinf.pos)++ : EOF;
00824 }
00825 
00826 #define       xone(fp)  (currinf.pos < currinf.end ? *(currinf.pos)++ : xxone(fp))
00827 
00828 static unsigned long
00829 xnum(FILE *fp, ubyte size)
00830 {
00831     long x = 0;
00832 
00833     while (size--)
00834        x = (x << 8) | xone(fp);
00835     return x;
00836 }
00837 
00838 static long
00839 xsnum(FILE *fp, ubyte size)
00840 {
00841     long x;
00842 
00843 #if    __STDC__
00844     x = (signed char)xone(fp);
00845 #else
00846     x = xone(fp);
00847     if (x & 0x80)
00848        x -= 0x100;
00849 #endif
00850     while (--size)
00851        x = (x << 8) | xone(fp);
00852     return x;
00853 }
00854 
00855 #define       xsfour(fp)    xsnum(fp, 4)
00856 
00857 static void
00858 xskip(FILE *fp, long offset)
00859 {
00860     currinf.pos += offset;
00861     if (!currinf.virtual && currinf.pos > currinf.end)
00862        (void)lseek(fileno(fp), (long)(currinf.pos - currinf.end), SEEK_CUR);
00863 }
00864 
00865 void
00866 dvi_fmt_error(const char *message, ...)
00867 {
00868     
00869     va_list args;
00870     va_start(args, message);
00871     fprintf(stderr, "%s: ", globals.program_name);
00872     (void)vfprintf(stderr, message, args);
00873     va_end(args);
00874     if (currinf.virtual)
00875        fprintf(stderr, " in virtual font %s\n", currinf.virtual->fontname);
00876     else
00877        fprintf(stderr, ", offset %ld\n", (long)xtell(globals.dvi_file.bak_fp, currinf.pos - 1));
00878     /* #ifndef NDEBUG */
00879     /*     xdvi_exit(EXIT_FAILURE); */
00880     /* #else */
00881     XDVI_ABORT((stderr, "I'll abort now, to help you debugging this."));
00882     /* #endif */
00883 }
00884 
00885 
00886 /*
00887  *     Code for debugging options.
00888  */
00889 
00890 static void
00891 print_bitmap(struct bitmap *bitmap)
00892 {
00893     bmUnitT *ptr = (bmUnitT *)bitmap->bits;
00894     int x, y, i;
00895 
00896     ASSERT(ptr != NULL, "Invalid bitmap bits");
00897 
00898     printf("w = %d, h = %d, bytes wide = %d\n",
00899           bitmap->w, bitmap->h, bitmap->bytes_wide);
00900     for (y = 0; y < (int)bitmap->h; ++y) {
00901        for (x = bitmap->bytes_wide; x > 0; x -= BMBYTES) {
00902 #ifdef WORDS_BIGENDIAN
00903            for (i = BMBITS - 1; i >= 0; --i)
00904               putchar((*ptr & (1 << i)) ? '@' : '.');
00905 #else
00906            for (i = 0; i < BMBITS; ++i)
00907               putchar((*ptr & (1 << i)) ? '@' : '.');
00908 #endif
00909            ++ptr;
00910        }
00911        putchar('\n');
00912     }
00913 }
00914 
00915 static void
00916 print_char(ubyte ch, struct glyph *g)
00917 {
00918     printf("char %d", ch);
00919     if (isprint(ch))
00920        printf(" (%c)", ch);
00921     putchar('\n');
00922     printf("x = %d, y = %d, dvi = %ld\n", g->x, g->y, g->dvi_adv);
00923     print_bitmap(&g->bitmap);
00924 }
00925 
00926 static const char *dvi_table1[] = {
00927     "SET1", "SET2", NULL, NULL, "SETRULE", "PUT1", "PUT2", NULL,
00928     NULL, "PUTRULE", "NOP", "BOP", "EOP", "PUSH", "POP", "RIGHT1",
00929     "RIGHT2", "RIGHT3", "RIGHT4", "W0", "W1", "W2", "W3", "W4",
00930     "X0", "X1", "X2", "X3", "X4", "DOWN1", "DOWN2", "DOWN3",
00931     "DOWN4", "Y0", "Y1", "Y2", "Y3", "Y4", "Z0", "Z1",
00932     "Z2", "Z3", "Z4"
00933 };
00934 
00935 static const char *dvi_table2[] = {
00936     "FNT1", "FNT2", "FNT3", "FNT4", "XXX1", "XXX2", "XXX3", "XXX4",
00937     "FNTDEF1", "FNTDEF2", "FNTDEF3", "FNTDEF4", "PRE", "POST", "POSTPOST",
00938     "SREFL", "EREFL", NULL, NULL, NULL, NULL
00939 };
00940 
00941 static void
00942 print_dvi(ubyte ch)
00943 {
00944     const char *s;
00945 
00946     fprintf(stderr, "%4d %4d ", PXL_H, PXL_V);
00947     if (ch <= (ubyte) (SETCHAR0 + 127)) {
00948        fprintf(stderr, "SETCHAR%-3d", ch - SETCHAR0);
00949        if (isprint(ch))
00950            fprintf(stderr, " (%c)", ch);
00951        fputc('\n', stderr);
00952        return;
00953     }
00954     else if (ch < FNTNUM0)
00955        s = dvi_table1[ch - 128];
00956     else if (ch <= (ubyte) (FNTNUM0 + 63)) {
00957        fprintf(stderr, "FNTNUM%d\n", ch - FNTNUM0);
00958        return;
00959     }
00960     else
00961        s = dvi_table2[ch - (FNTNUM0 + 64)];
00962     if (s) {
00963        fputs(s, stderr);
00964        fputc('\n', stderr);
00965     }
00966     else
00967        XDVI_FATAL((stderr, "print_dvi: unknown op-code %d", ch));
00968 }
00969 
00970 
00971 /*
00972  *     Count the number of set bits in a 4x4-region of the bitmap
00973  */
00974 
00975 static char sample_count[] = {
00976     0, 1, 1, 2,
00977     1, 2, 2, 3,
00978     1, 2, 2, 3,
00979     2, 3, 3, 4
00980 };
00981 
00982 /*
00983  * For greyscaling, return the number of bits that are set in a given region
00984  * of width w and height h of the bitmap `bits', starting horizontally after
00985  * `bit_skip' bits, where `bytes_wide' is the same as the `bytes_wide' field
00986  * in the bitmap struct (scan line width in bytes).
00987  * Note that `bits' is really a one-dimensional array, i.e. all the rows
00988  * are put in sequence into one single row.
00989  */
00990 static int
00991 sample(bmUnitT *bits, int bytes_wide, int bit_skip, int w, int h)
00992 {
00993     bmUnitT *beg_ptr, *end_ptr, *curr_ptr;
00994     int bits_left;
00995     int n, bit_shift, wid;
00996 
00997 #if TRACE_AA
00998     fprintf(stderr, "sample: %d bytes wide, %d skip, %d w, %d h\n", bytes_wide, bit_skip, w, h);
00999 #endif
01000 
01001     beg_ptr = bits + bit_skip / BMBITS;
01002     end_ptr = ADD(bits, h * bytes_wide);
01003     
01004 #if TRACE_AA
01005     fprintf(stderr, "beg_ptr: %p, end: %p\n", (void *)beg_ptr, (void *)end_ptr);
01006 #endif
01007     
01008     bits_left = w;
01009 #ifdef WORDS_BIGENDIAN
01010     bit_shift = BMBITS - bit_skip % BMBITS;
01011 #else
01012     bit_shift = bit_skip % BMBITS;
01013 #endif
01014 #if TRACE_AA
01015     fprintf(stderr, "shift: %d\n", bit_shift);
01016 #endif
01017     n = 0;
01018        
01019     while (bits_left) {
01020 #ifdef WORDS_BIGENDIAN
01021        wid = bit_shift;
01022 #else
01023        wid = BMBITS - bit_shift;
01024 #endif
01025        if (wid > bits_left)
01026            wid = bits_left;
01027        if (wid > 4) /* why? */
01028            wid = 4;
01029 #ifdef WORDS_BIGENDIAN
01030        bit_shift -= wid;
01031 #endif
01032        for (curr_ptr = beg_ptr;
01033             curr_ptr < end_ptr;
01034             curr_ptr = ADD(curr_ptr, bytes_wide)) {
01035 #if TRACE_AA
01036            int i;
01037            for (i = 0; i < bytes_wide; i++) {
01038               fprintf(stderr, "%d ", *(curr_ptr + i));
01039            }
01040            fprintf(stderr, "\nMask: %d; count: %d\n", wid,
01041                   sample_count[ (*curr_ptr >> bit_shift) & bit_masks[wid] ]);
01042 #endif
01043            n += sample_count[ (*curr_ptr >> bit_shift) & bit_masks[wid] ];
01044        }
01045 #ifdef WORDS_BIGENDIAN
01046        if (bit_shift == 0) {
01047            bit_shift = BMBITS;
01048            ++beg_ptr;
01049        }
01050 #else
01051        bit_shift += wid;
01052        if (bit_shift == BMBITS) {
01053            bit_shift = 0;
01054            ++beg_ptr;
01055        }
01056 #endif
01057        bits_left -= wid;
01058        /*         fprintf(stderr, "bits_left: %d\n", bits_left); */
01059     }
01060     return n;
01061 }
01062 
01063 static void
01064 shrink_glyph(struct glyph *g)
01065 {
01066     int shrunk_bytes_wide, shrunk_height;
01067     int rows_left, rows, init_cols;
01068     int cols_left;
01069     int cols;
01070     bmUnitT *unshrunk_ptr, *shrunk_ptr;
01071     bmUnitT m, *cp;
01072     /* threshold for which a bit will be set to `on' in the shrunken bitmap */
01073     int min_sample = currwin.shrinkfactor * currwin.shrinkfactor * resource.density / 100;
01074     int row_num;
01075 
01076     /* These machinations ensure that the character is shrunk according to
01077        its hot point, rather than its upper left-hand corner. */
01078     g->x2 = g->x / currwin.shrinkfactor;
01079     init_cols = g->x - g->x2 * currwin.shrinkfactor;
01080     if (init_cols <= 0)
01081        init_cols += currwin.shrinkfactor;
01082     else
01083        ++g->x2;
01084     g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
01085     /* include row zero with the positively numbered rows */
01086     row_num = g->y + 1;
01087     g->y2 = row_num / currwin.shrinkfactor;
01088     rows = row_num - g->y2 * currwin.shrinkfactor;
01089     if (rows <= 0) {
01090        rows += currwin.shrinkfactor;
01091        --g->y2;
01092     }
01093     g->bitmap2.h = shrunk_height
01094        = g->y2 + ROUNDUP((int)g->bitmap.h - row_num, currwin.shrinkfactor) + 1;
01095     alloc_bitmap(&g->bitmap2);
01096 
01097     unshrunk_ptr = (bmUnitT *) g->bitmap.bits;
01098     shrunk_ptr = (bmUnitT *) g->bitmap2.bits;
01099     shrunk_bytes_wide = g->bitmap2.bytes_wide;
01100     rows_left = g->bitmap.h;
01101     memset((char *)shrunk_ptr, '\0', shrunk_bytes_wide * shrunk_height);
01102     
01103     while (rows_left) {
01104        if (rows > rows_left)
01105            rows = rows_left;
01106        cols_left = g->bitmap.w;
01107 #ifndef       WORDS_BIGENDIAN
01108        m = 1; /* XXX was (1 << 0) */
01109 #else
01110        m = ((bmUnitT)1 << (BMBITS - 1));
01111 #endif
01112        cp = shrunk_ptr;
01113        cols = init_cols;
01114        while (cols_left) {
01115            /* ??? */
01116            if (cols > cols_left)
01117               cols = cols_left;
01118            /* set a bit to `on' if it's over the threshold */
01119            if (sample(unshrunk_ptr, g->bitmap.bytes_wide,
01120                      (int)g->bitmap.w - cols_left, cols, rows)
01121               >= min_sample)
01122               *cp |= m;
01123 #ifndef       WORDS_BIGENDIAN
01124            if (m == ((bmUnitT)1 << (BMBITS - 1))) {
01125               m = 1; /* XXX was (1 << 0) */
01126               ++cp;
01127            }
01128            else
01129               m <<= 1;
01130 #else
01131            if (m == 1) { /* XXX was (1 << 0) */
01132               m = ((bmUnitT)1 << (BMBITS - 1));
01133               ++cp;
01134            }
01135            else
01136               m >>= 1;
01137 #endif
01138            cols_left -= cols;
01139            cols = currwin.shrinkfactor;
01140        }
01141        shrunk_ptr += shrunk_bytes_wide / sizeof(bmUnitT);
01142        unshrunk_ptr += rows * g->bitmap.bytes_wide / sizeof(bmUnitT);
01143 /*     *((char **)&shrunk_ptr) += shrunk_bytes_wide; */
01144 /*     *((char **)&unshrunk_ptr) += rows * g->bitmap.bytes_wide; */
01145        rows_left -= rows;
01146        rows = currwin.shrinkfactor;
01147     }
01148     g->y2 = g->y / currwin.shrinkfactor;
01149     if (globals.debug & DBG_BITMAP)
01150        print_bitmap(&g->bitmap2);
01151 }
01152 
01153 #ifdef GREY
01154 
01155 #ifdef RGB_ANTI_ALIASING
01156 /* void */
01157 /* filter_colors(Pixel *p1, Pixel *p2) */
01158 /* { */
01159 /*     Pixel res1, res2; */
01160 
01161 /*     int res1_r = *p1 & G_visual->red_mask; */
01162 /*     int res1_g = *p1 & G_visual->green_mask; */
01163 /*     int res1_b = *p1 & G_visual->blue_mask; */
01164 
01165 /*     int res2_r = *p2 & G_visual->red_mask; */
01166 /*     int res2_g = *p2 & G_visual->green_mask; */
01167 /*     int res2_b = *p2 & G_visual->blue_mask; */
01168 /* } */
01169 
01170 static void
01171 color_filter_image(struct glyph *g)
01172 {
01173     int rows = g->bitmap2.h;
01174     int cols = g->bitmap2.w;
01175     int i, j, k;
01176     int arr_size = rows * cols * 3;
01177     unsigned char *arr = xmalloc(arr_size * sizeof *arr);
01178     unsigned char *arr2 = xmalloc(arr_size * sizeof *arr2);
01179 
01180     fprintf(stderr, "total: %d\n", arr_size);
01181     
01182     for (i = 0, j = 0; j < rows; j++) {
01183        for (k = 0; k < cols; k++) {
01184            Pixel p = XGetPixel(g->image2, k, j);
01185 #if TRACE_AA3
01186            fprintf(stderr, "k: %d, j: %d, idx: %d\n", k, j, i);
01187 #endif
01188            arr[i] = (p & G_visual->red_mask) >> 16;
01189            arr[i + 1] = (p & G_visual->green_mask) >> 8;
01190            arr[i + 2] = (p & G_visual->blue_mask);
01191 #if TRACE_AA3
01192            fprintf(stderr, "0x%.6lX -> %d, %d, %d\n", p, arr[i], arr[i + 1], arr[i + 2]);
01193 #endif
01194            i += 3;
01195        }
01196     }
01197 
01198     for (i = 0; i < arr_size; i++) {
01199        if (i == 0) { /* merge two elems */
01200            if (i == arr_size - 1) /* only one elem, do nothing */
01201               break;
01202            arr2[i] = (int)(resource.subpixel_energy[0] * arr[i] +
01203                          resource.subpixel_energy[1] * arr[i + 1] + 0.5);
01204        }
01205        else if (i == arr_size - 1) { /* merge two elems */
01206            if (i == 0) /* only one elem, do nothing */
01207               break;
01208            arr2[i] = (int)(resource.subpixel_energy[1] * arr[i - 1] +
01209                          resource.subpixel_energy[0] * arr[i] + 0.5);
01210        }
01211        else { /* merge three elems */
01212            arr2[i] = (int)(resource.subpixel_energy[1] * arr[i - 1] +
01213                          resource.subpixel_energy[0] * arr[i] +
01214                          resource.subpixel_energy[1] * arr[i + 1] + 0.5);
01215 #if TRACE_AA3
01216            fprintf(stderr, "%d, %d, %d -> %d\n", arr[i - 1], arr[i], arr[i + 1], arr2[i]);
01217 #endif
01218        }
01219     }
01220 
01221     for (i = 0, j = 0; j < rows; j++) {
01222        for (k = 0; k < cols; k++) {
01223            Pixel p = arr2[i] << 16 | (arr2[i + 1] << 8) | arr2[i + 2];
01224 #if TRACE_AA3
01225            fprintf(stderr, "%d, %d, %d -> 0x%.6lX\n", arr2[i], arr2[i + 1], arr2[i + 2], p);
01226 #endif
01227            XPutPixel(g->image2, k, j, p);
01228            i += 3;
01229        }
01230     }
01231     
01232     free(arr);
01233     free(arr2);
01234 }
01235 
01236 #endif
01237 
01238 static void
01239 shrink_glyph_grey(struct glyph *g)
01240 {
01241     int rows_left, rows, init_cols;
01242     int cols_left;
01243     int cols;
01244     int x, y;
01245     long thesample;
01246 /*     int min_sample = currwin.shrinkfactor * currwin.shrinkfactor * resource.density / 100; */
01247     Pixel onoff, onoff2;
01248     bmUnitT *unshrunk_ptr;
01249     unsigned int size;
01250     int row_num;
01251     int actual_w;
01252 
01253 #if COLOR
01254     if (fg_active != fg_current) {
01255        do_color_change();
01256     }
01257 #endif
01258 
01259     /* TODO: rounding errors causing color fringing (see HACK comment below):
01260        
01261        \documentclass{article}
01262        \pagestyle{empty}
01263 
01264        \begin{document}
01265        l
01266        \end{document}
01267 
01268        With ./xdvi-xaw.bin -name xdvi -subpixel rgb -s 4 ./test.dvi:
01269 
01270        subpixel order: rgb = 1
01271        g->x2: 0, init_cols: -2
01272        AFTER: g->x2: 0, init_cols: 2
01273 
01274        but with ./xdvi-xaw.bin -name xdvi -s 4 ./test.dvi:
01275 
01276        g->x2: 0, init_cols: -3
01277        AFTER: g->x2: 0, init_cols: 1
01278     */
01279     
01280     /* These machinations ensure that the character is shrunk according to
01281        its hot point, rather than its upper left-hand corner. */
01282 #ifdef RGB_ANTI_ALIASING
01283     if (resource.subpixel_order == SUBPIXEL_NONE)
01284        g->x2 = g->x / currwin.shrinkfactor;
01285     else {
01286        if (g->x < 0)
01287            g->x2 = (int)(g->x / 3.0 - 0.5) / currwin.shrinkfactor;
01288        else
01289            g->x2 = (int)(g->x / 3.0 + 0.5) / currwin.shrinkfactor;
01290     }
01291     
01292     if (resource.subpixel_order == SUBPIXEL_NONE)
01293        init_cols = g->x - g->x2 * currwin.shrinkfactor;
01294     else {
01295        if (g->x < 0)
01296            init_cols = (int)(g->x / 3.0 - 0.5) - g->x2 * currwin.shrinkfactor;
01297        else
01298            init_cols = (int)(g->x / 3.0 + 0.5) - g->x2 * currwin.shrinkfactor;
01299        fprintf(stderr, "g->x: %d, g->x2: %d, init_cols: %d\n", g->x, g->x2, init_cols);
01300     }
01301 #else
01302     g->x2 = g->x / currwin.shrinkfactor;
01303     init_cols = g->x - g->x2 * currwin.shrinkfactor;
01304 #endif
01305     
01306     if (init_cols <= 0)
01307        init_cols += currwin.shrinkfactor;
01308     else
01309        ++(g->x2);
01310 
01311 #ifdef RGB_ANTI_ALIASING
01312     
01313     if (resource.subpixel_order == SUBPIXEL_NONE)
01314        g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
01315     else {
01316        fprintf(stderr, "AFTER: g->x2: %d, init_cols: %d\n", g->x2, init_cols);
01317 /*     fprintf(stderr, "g->bitmap.w / 3.0 + 0.5: %d; g->x / 3.0: %d; all: %d, %d\n", */
01318 /*            (int)(g->bitmap.w / 3.0 + 0.5), */
01319 /*            (int)(g->x / 3.0), */
01320 /*            (int)((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0), */
01321 /*            g->x2 + (int)((((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0) + currwin.shrinkfactor - 1) / currwin.shrinkfactor)); */
01322        g->bitmap2.w = g->x2 + ROUNDUP((int)((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0), currwin.shrinkfactor);
01323 /*     fprintf(stderr, "g->bitmap.w: %d\n", g->bitmap2.w); */
01324     }
01325 #else
01326     g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
01327 #endif
01328 
01329     /* include row zero with the positively numbered rows */
01330     row_num = g->y + 1;
01331 #ifdef DBG_AA
01332     fprintf(stderr, "row_num: %d\n", row_num);
01333 #endif /* DBG_AA */
01334     /* g->y2 is the new height of the image: */
01335     g->y2 = row_num / currwin.shrinkfactor;
01336 #ifdef DBG_AA
01337     fprintf(stderr, "g->y2: %d\n", g->y2);
01338 #endif /* DBG_AA */
01339     /* in C89 and before, result of division can `truncate towards negative infinity'
01340        (i.e., round to the larger digit) for negative quotients, hence we need
01341        to test for rows < 0. OTOH, if rows = 0, use currwin.shrinkfactor instead
01342        (why?)
01343     */
01344     if ((rows = row_num - g->y2 * currwin.shrinkfactor) <= 0) {
01345        rows += currwin.shrinkfactor;
01346        --(g->y2);
01347     }
01348     g->bitmap2.h = g->y2 + ROUNDUP((int)g->bitmap.h - row_num, currwin.shrinkfactor) + 1;
01349 
01350 #if TRACE_AA1
01351     if (resource.subpixel_order != SUBPIXEL_NONE) {
01352        fprintf(stderr, "\nbitmap.h: %d, bitmap.w: %d\n", g->bitmap2.h, g->bitmap2.w);
01353     }
01354 #endif /* DBG_AA */
01355 
01356     /* allocate pixmap for antialiasing ... */
01357     if (g->pixmap2 == NULL) {
01358        g->image2 = XCreateImage(DISP, G_visual, G_depth, ZPixmap,
01359                              0, (char *)NULL, g->bitmap2.w, g->bitmap2.h,
01360                              BMBITS, 0);
01361        size = g->image2->bytes_per_line * g->bitmap2.h;
01362        g->pixmap2 = g->image2->data = xmalloc(size != 0 ? size : 1);
01363     }
01364     /* ... and the pixmap used for globals.gc.fore2: */
01365     if (globals.gc.fore2 != NULL && g->pixmap2_gc2 == NULL) {
01366        size = g->image2->bytes_per_line * g->bitmap2.h;
01367        g->pixmap2_gc2 = xmalloc(size != 0 ? size : 1);
01368     }
01369 
01370 #if 0
01371     if (resource.subpixel_order != SUBPIXEL_NONE) {
01372        fprintf(stderr, "\n============= BITMAP ==============\n");
01373        print_bitmap(&g->bitmap);
01374     }
01375 #endif
01376     
01377     unshrunk_ptr = (bmUnitT *)g->bitmap.bits;
01378     actual_w = g->bitmap.w;
01379     rows_left = g->bitmap.h;
01380     y = 0;
01381     /* the basic algorithm is the same as in the nogrey code, with the main
01382        exception that the return value of sample() is used. */
01383     while (rows_left) {
01384 #ifdef RGB_ANTI_ALIASING
01385        Pixel pixel = 0;
01386        Pixel pixel2 = 0;
01387 #endif
01388        x = 0;
01389        if (rows > rows_left) /* why - extra safety? */
01390            rows = rows_left;
01391        cols_left = g->bitmap.w;
01392 /*     fprintf(stderr, "init_cols: %d\n", init_cols); */
01393        cols = init_cols;
01394        while (cols_left) {
01395            if (cols > cols_left) /* why - extra safety? */
01396               cols = cols_left;
01397            
01398            thesample = sample(unshrunk_ptr, g->bitmap.bytes_wide,
01399                             (int)g->bitmap.w - cols_left, cols, rows);
01400            
01401 /*         if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[2] != 0) */
01402 /*            onoff = thesample >= min_sample ? 0xffffff : 0; */
01403 /*         else */
01404            onoff = pixeltbl[thesample];
01405 
01406 #ifdef XSERVER_INFO
01407            if (globals.debug & DBG_PK) {
01408               int c;
01409 /*            fprintf(stderr, "onoff: %d\n", onoff); */
01410               if (onoff > 65536)
01411                   c = onoff / 65536;
01412               else if (onoff > 256)
01413                   c = onoff / 256;
01414               else
01415                   c = onoff;
01416               if (c == 0)
01417                   fprintf(stdout, ",..");
01418               else
01419                   fprintf(stdout, ",%.2x", c);
01420            }
01421 #endif
01422 
01423 #ifdef RGB_ANTI_ALIASING
01424            if (resource.subpixel_order != SUBPIXEL_NONE) {
01425               int div = x / 3;
01426               int rest = x % 3;
01427 
01428               if (resource.subpixel_order == SUBPIXEL_RGB) {
01429                   if (rest == 0)
01430                      pixel = onoff & G_visual->red_mask;
01431                   else if (rest == 1)
01432                      pixel |= onoff & G_visual->green_mask;
01433                   else
01434                      pixel |= onoff & G_visual->blue_mask;
01435               }
01436               else { /* SUBPIXEL_BGR */
01437                   if (rest == 0)
01438                      pixel = onoff & G_visual->blue_mask;
01439                   else if (rest == 1)
01440                      pixel |= onoff & G_visual->green_mask;
01441                   else
01442                      pixel |= onoff & G_visual->red_mask;
01443               }
01444               
01445 #if 0 && TRACE_AA1
01446               fprintf(stderr, "sample: %ld; row %d, col %d, left %d: 0x%.6lx; pixel: 0x%.6lx at pos %d,%d (x:%d)\n",
01447                      thesample, rows, cols, cols_left, onoff, pixel, div, y, x);
01448 #endif /* TRACE_AA */
01449               fprintf(stderr, "pixel at %d\n", div);
01450               XPutPixel(g->image2, div, y, pixel);
01451 
01452               /* HACK to fix color fringing problem */
01453               if (div + 1 < g->bitmap2.w) {
01454                   fprintf(stderr, "rest pixel at %d\n", div);
01455                   XPutPixel(g->image2, div + 1, y, 0);
01456               }
01457            }
01458            else {
01459 #if 0 && TRACE_AA1
01460               fprintf(stderr, "sample: %ld; row %d, col %d, left %d: 0x%.6lx at pos %d, %d\n",
01461                      thesample, rows, cols, cols_left, onoff, x, y);
01462 #endif /* TRACE_AA */
01463               XPutPixel(g->image2, x, y, onoff);
01464            }
01465 #else
01466            XPutPixel(g->image2, x, y, onoff);
01467 #endif /* RGB_ANTI_ALIASING */
01468            if (globals.gc.fore2 != NULL) {
01469               onoff2 = pixeltbl_gc2[thesample];
01470 #ifdef RGB_ANTI_ALIASING
01471               if (resource.subpixel_order != SUBPIXEL_NONE) {
01472                   int div = x / 3;
01473                   int rest = x % 3;
01474                   
01475                   if (resource.subpixel_order == SUBPIXEL_RGB) {
01476                      if (rest == 0)
01477                          pixel2 = onoff2 & G_visual->red_mask;
01478                      else if (rest == 1)
01479                          pixel2 |= onoff2 & G_visual->green_mask;
01480                      else
01481                      pixel2 |= onoff2 & G_visual->blue_mask;
01482                   }
01483                   else { /* SUBPIXEL_BGR */
01484                      if (rest == 0)
01485                          pixel2 = onoff2 & G_visual->blue_mask;
01486                      else if (rest == 1)
01487                          pixel2 |= onoff2 & G_visual->green_mask;
01488                      else
01489                          pixel2 |= onoff2 & G_visual->red_mask;
01490                   }
01491                   
01492                   g->image2->data = g->pixmap2_gc2;
01493 #if TRACE_AA1
01494                   fprintf(stderr, "fore2 at %d, %d\n", div, y);
01495 #endif
01496                   XPutPixel(g->image2, div, y, pixel2);
01497                   g->image2->data = g->pixmap2;
01498               }
01499               else {
01500 #else /* RGB_ANTI_ALIASING */
01501                   g->image2->data = g->pixmap2_gc2;
01502                   XPutPixel(g->image2, x, y, onoff2);
01503                   g->image2->data = g->pixmap2;
01504 #endif
01505 #ifdef RGB_ANTI_ALIASING
01506               }
01507 #endif
01508            }
01509            
01510 #if 0 && TRACE_AA1
01511            fprintf(stderr, "subtracting %d from %d: %d\n", cols, cols_left, cols_left - cols);
01512 #endif
01513            cols_left -= cols;
01514            cols = currwin.shrinkfactor;
01515            x++;
01516        }
01517        /* advance pointer by the number of rows covered */
01518 /*     fprintf(stderr, "++: %d; %d, %d\n", rows * g->bitmap.bytes_wide, g->bitmap.bytes_wide, sizeof(bmUnitT)); */
01519        unshrunk_ptr += rows * g->bitmap.bytes_wide / sizeof(bmUnitT);
01520 /*     *((char **)&unshrunk_ptr) += rows * g->bitmap.bytes_wide; */
01521        rows_left -= rows;
01522        rows = currwin.shrinkfactor;
01523        y++;
01524 #ifdef XSERVER_INFO
01525        if (globals.debug & DBG_PK)
01526            fprintf(stdout, "\n");
01527 #endif
01528     }
01529 #ifdef XSERVER_INFO
01530     if (globals.debug & DBG_PK)
01531        fprintf(stdout, "\n");
01532 #endif
01533 
01534 #if 0
01535     fprintf(stderr, "y: %d, bitmap.h: %d\n", y, (int)g->bitmap2.h);
01536 #endif /* DBG_AA */
01537 
01538     /* fill remaining rows not covered before (how?) */
01539     while (y < (int)g->bitmap2.h) {
01540        for (x = 0; x < (int)g->bitmap2.w; x++) {
01541 /*         int c = *pixeltbl; */
01542 #if TRACE_AA1
01543            fprintf(stderr, "Remaining at %d, %d: 0x%.6lx\n", x, y, *pixeltbl);
01544 #endif
01545            XPutPixel(g->image2, x, y, *pixeltbl);
01546 /*         if (c == 0) */
01547 /*            fprintf(stdout, ",.."); */
01548 /*         else */
01549 /*            fprintf(stdout, ",%.2x", c); */
01550            if (globals.gc.fore2 != NULL) {
01551               g->image2->data = g->pixmap2_gc2;
01552 #if TRACE_AA1
01553               fprintf(stderr, "image2 at %d, %d: 0x%.6lx\n", x, y, *pixeltbl_gc2);
01554 #endif
01555               XPutPixel(g->image2, x, y, *pixeltbl_gc2);
01556               g->image2->data = g->pixmap2;
01557            }
01558        }
01559        y++;
01560     }
01561 
01562 #ifdef RGB_ANTI_ALIASING
01563     if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[1] != 0)
01564        color_filter_image(g);
01565     if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[2] != 0)
01566        color_filter_image(g);
01567 #endif
01568     
01569     g->y2 = g->y / currwin.shrinkfactor;
01570 #if COLOR
01571     g->fg = fg_current;
01572 #endif
01573 }
01574 #endif /* GREY */
01575 
01576 /*
01577  *     Find font #n.
01578  */
01579 
01580 static void
01581 change_font(unsigned long n)
01582 {
01583     struct tn *tnp;
01584 
01585     if (n < currinf.tn_table_len)
01586        currinf.fontp = currinf.tn_table[n];
01587     else {
01588        currinf.fontp = NULL;
01589        for (tnp = currinf.tn_head; tnp != NULL; tnp = tnp->next)
01590            if (tnp->TeXnumber == n) {
01591               currinf.fontp = tnp->fontp;
01592               break;
01593            }
01594     }
01595     if (currinf.fontp == NULL)
01596        XDVI_FATAL((stderr, "Non-existent font number %ld", n));
01597     if (currinf.fontp->set_char_p == NULL)
01598        XDVI_FATAL((stderr, "No procedure to set font %ld, %s", n, currinf.fontp->fontname));
01599     maxchar = currinf.fontp->maxchar;
01600     currinf.set_char_p = currinf.fontp->set_char_p;
01601 }
01602 
01603 
01604 /*
01605  *     Open a font file.
01606  */
01607 
01608 static void
01609 open_font_file(struct font *fontp)
01610 {
01611     if (fontp->file == NULL) {
01612        fontp->file = XFOPEN(fontp->filename, OPEN_MODE);
01613        if (fontp->file == NULL)
01614            XDVI_FATAL((stderr, "Couldn't re-locate font file `%s'", fontp->filename));
01615     }
01616 }
01617 
01618 /*
01619  * Read and return a 0-terminated special string allocated in static memory
01620  * (i.e. contents will be overwritten by next call of this function).
01621  */
01622 
01623 static char *
01624 read_special(FILE *fp, long nbytes)
01625 {
01626     static char *spcl = NULL;
01627     static long spcl_len = -1;
01628     char *p;
01629 
01630     if (nbytes > spcl_len) {
01631        spcl = xrealloc(spcl, (unsigned)nbytes + 1);
01632        spcl_len = nbytes;
01633     }
01634     p = spcl;
01635     for (;;) {
01636        int i = currinf.end - currinf.pos;
01637 
01638        if (i > nbytes)
01639            i = nbytes;
01640        memcpy(p, (char *)currinf.pos, i);
01641        currinf.pos += i;
01642        p += i;
01643        nbytes -= i;
01644        if (nbytes == 0)
01645            break;
01646        (void)xxone(fp);
01647        --currinf.pos;
01648     }
01649     *p = '\0';
01650     return spcl;
01651 }
01652 
01653 /*
01654  *     Table used for scanning.  If >= 0, then skip that many bytes.
01655  *     M1 means end of page, M2 means special, M3 means FNTDEF,
01656  *     M4 means unrecognizable, and M5 means doesn't belong here.
01657  */
01658 
01659 #define       M1     255
01660 #define       M2     254
01661 #define       M3     253
01662 #define       M4     252
01663 #define       M5     251
01664 #define       MM     251
01665 
01666 static ubyte scantable[256] = {
01667     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     /* chars 0 - 127 */
01668     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01669     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01670     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01671     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01672     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01673     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01674     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01675     1, 2,     /* SET1,SET2 (128,129) */
01676     /* -,-,SETRULE,PUT1,PUT2,-,-,PUTRULE,NOP,BOP (130-139) */
01677     M4, M4, 8, 1, 2, M4, M4, 8, 0, 44,
01678     M1, 0, 0, 1, 2, 3, 4, 0, 1, 2, /* EOP,PUSH,POP,RIGHT1-4,W0M2 (140-149) */
01679     3, 4, 0, 1, 2, 3, 4, 1, 2, 3,  /* W3-4,X0-4,DOWN1-3 (150-159) */
01680     4, 0, 1, 2, 3, 4, 0, 1, 2, 3,  /* DOWN4,Y0-4,Z0-3 (160-169) */
01681     4, /* Z4 (170) */
01682     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     /* change font 171 - 234 */
01683     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01684     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01685     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01686     1, 2, 3, 4, M2,  /* FNT1-4,XXX1 (235-239) */
01687     /* XXX2-4,FNTDEF1-4,PRE,POST,POSTPOST (240-249) */
01688     M2, M2, M2, M3, M3, M3, M3, M5, M5, M5,
01689     0, 0, M4, M4, M4, M4
01690 };     /* SREFL,EREFL,-,-,-,- (250-255) */
01691 
01692 /*
01693  *     This is the generic scanning routine.  It assumes that currinf, etc.
01694  *     are ready to go at the start of the page to be scanned.
01695  */
01696 
01697 
01698 
01699 Boolean
01700 spcl_scan(Boolean (*spcl_proc)(char *str, int str_len, void *data), void *data, Boolean return_if_found, FILE *fp)
01701 {
01702     ubyte ch;
01703     ubyte n;
01704     long a;
01705 
01706     for (;;) {
01707        ch = xone(fp);
01708 /*     print_dvi(ch); */
01709        n = scantable[ch];
01710        if (n < MM)
01711            while (n-- != 0)
01712               (void)xone(fp);
01713        else if (n == M1)
01714            break;    /* end of page */
01715        else
01716            switch (n) {
01717            case M2:  /* special */
01718               a = xnum(fp, ch - XXX1 + 1);
01719               if (a > 0) {
01720                   if (spcl_proc(read_special(fp, a), a, data) && return_if_found) {
01721                      return True;
01722                   }
01723               }
01724               break;
01725            case M3:  /* FNTDEF */
01726               xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
01727               ch = xone(fp);
01728               xskip(fp, (long)ch + (long)xone(fp));
01729               break;
01730            case M4:  /* unrecognizable */
01731               XDVI_FATAL((stderr, "unknown op-code %d", ch));
01732               break;
01733            case M5:  /* doesn't belong */
01734               dvi_fmt_error("spcl_scan: shouldn't happen: %s encountered",
01735                            dvi_table2[ch - (FNTNUM0 + 64)]);
01736               break;
01737            }
01738     }
01739     return False;
01740 }
01741 
01742 #define       xspell_conv(n)       spell_conv0(n, current_dimconv)
01743 
01744 /*
01745  *     Prescanning routine for dvi file.  This looks for specials like
01746  *     `header=' and `!'.
01747  */
01748 
01749 void
01750 prescan(FILE *fp)
01751 {
01752     if (fp == NULL) {
01753        return;
01754     }
01755 
01756     TRACE_FILES((stderr, "prescan on %p", (void *)fp));
01757     
01758     (void)lseek(fileno(fp), pageinfo_get_offset(scanned_page + 1), SEEK_SET);
01759     G_dvi_buf_ptr = dvi_buffer;
01760     currinf.pos = currinf.end = G_dvi_buf_ptr;
01761     for (;;) {
01762        if (scanned_page == -1) { /* on first page */
01763            TRACE_FILES((stderr, "prescan on page 1"));
01764            pageinfo_set_page_width(scanned_page + 1, pageinfo_get_page_width(total_pages));
01765            pageinfo_set_page_height(scanned_page + 1, pageinfo_get_page_height(total_pages));
01766            pageinfo_set_window_width(scanned_page + 1, pageinfo_get_window_width(total_pages));
01767            pageinfo_set_window_height(scanned_page + 1, pageinfo_get_window_height(total_pages));
01768        }
01769        else {
01770            TRACE_FILES((stderr, "prescan on page %d", scanned_page));
01771            pageinfo_set_page_width(scanned_page + 1, pageinfo_get_page_width(scanned_page));
01772            pageinfo_set_page_height(scanned_page + 1, pageinfo_get_page_height(scanned_page));
01773            pageinfo_set_window_width(scanned_page + 1, pageinfo_get_window_width(scanned_page));
01774            pageinfo_set_window_height(scanned_page + 1, pageinfo_get_window_height(scanned_page));
01775        }
01776        if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE) {
01777            break;
01778        }
01779        /* NOTE:  longjmp(globals.ev.canit) should not be done within
01780           read_events(). */
01781        htex_prescan_save();
01782        htex_prescan_initpage();
01783 
01784        if (!setjmp(globals.ev.canit)) {
01785            struct htex_prescan_data data;
01786            int pre_depth, depth;
01787            data.pageno = scanned_page + 1;
01788            data.scan_type = HTEX_ANCHOR_NUM; /* just for the anchor numbers */
01789            pre_depth = htex_prescan_get_depth();
01790            (void)spcl_scan(scan_special, &data, False, fp);
01791            
01792            depth = htex_prescan_get_depth();
01793 
01794            if (depth > pre_depth) {
01795               /* we have a mismatched anchor. We currently don't deal with
01796                  _nested_ mismatched anchors (ugh), so there's only one
01797                  anchor string that can be used as info on the next page. */
01798               int anchor_num = htex_prescan_get_mismatched_anchor_num(depth);
01799               /* scan again to find the anchor string at anchor number `anchor_num' */
01800               (void)lseek(fileno(fp), pageinfo_get_offset(scanned_page + 1), SEEK_SET);
01801               currinf.pos = currinf.end = G_dvi_buf_ptr;
01802               data.anchor_num = anchor_num;
01803               data.scan_type = HTEX_ANCHOR_STRING;
01804               htex_prescan_reset_firstpass();
01805               (void)spcl_scan(scan_special, &data, False, fp);
01806               depth = htex_prescan_get_depth();
01807            }
01808            else if (depth > 0 && scanned_page >= 0) { /* mismatch was on a previous page */
01809               htex_prescan_carry_over(scanned_page, scanned_page + 1);
01810            }
01811        }
01812        else { /* if interrupted */
01813            htex_prescan_restore(scanned_page + 1);
01814 #if PS
01815            psp.interrupt();
01816 #endif
01817            break;
01818        }
01819        if (globals.ev.flags & EV_GE_NEWPAGE)
01820            break;
01821        ++scanned_page;
01822 #if COLOR
01823        if (scanned_page_color < scanned_page) {
01824            scan_color_eop();
01825            scanned_page_color = scanned_page;
01826        }
01827 #endif
01828 #if PS
01829        if (scanned_page_ps < scanned_page)
01830            scanned_page_ps = scanned_page;
01831 #endif
01832        if (scanned_page >= current_page)
01833            break;
01834     }
01835     
01836 #if PS
01837     if (!(globals.ev.flags & EV_GE_NEWPAGE))
01838        psp.endheader();
01839 #endif
01840 }
01841 
01842 /*
01843  *     Routines to print characters.
01844  */
01845 
01846 setcharRetvalT
01847 set_char(
01848 #ifdef TEXXET
01849         wide_ubyte cmd,
01850 #endif
01851         wide_ubyte ch)
01852 {
01853     struct glyph *g;
01854 #ifdef TEXXET
01855     long dvi_h_sav;
01856 #endif
01857 
01858     if (ch > maxchar)
01859        realloc_font(currinf.fontp, (wide_ubyte)ch);
01860     if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
01861        if (g->addr == 0) {
01862            if (!resource.hush_chars)
01863               XDVI_WARNING((stderr, "Character %d not defined in font %s", ch, currinf.fontp->fontname));
01864            g->addr = -1;
01865 #ifdef TEXXET
01866            return;
01867 #else
01868            return 0L;
01869 #endif
01870        }
01871        if (g->addr == -1) {
01872 #ifdef TEXXET
01873            return;
01874 #else
01875            return 0L; /* previously flagged missing char */
01876 #endif
01877        }
01878        open_font_file(currinf.fontp);
01879        fseek(currinf.fontp->file, g->addr, SEEK_SET);
01880        (*currinf.fontp->read_char) (currinf.fontp, ch);
01881        if (globals.debug & DBG_BITMAP)
01882            print_char((ubyte) ch, g);
01883        currinf.fontp->timestamp = ++current_timestamp;
01884     }
01885 
01886 #ifdef TEXXET
01887     dvi_h_sav = DVI_H;
01888     if (currinf.dir < 0)
01889        DVI_H -= g->dvi_adv;
01890 
01891     if (scan_frame == NULL) {
01892 #endif
01893        
01894 #ifdef RGB_ANTI_ALIASING
01895        if (currwin.shrinkfactor == -1) {
01896            put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
01897        }
01898 #ifdef __GNUC__
01899 #warning TODO: implement horizontal AA at shrink 1
01900 #endif
01901 #else
01902        if (currwin.shrinkfactor == 1) {
01903            put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
01904        }
01905 #endif
01906        else {
01907 #ifdef GREY
01908            if (resource.use_grey) {
01909               if (g->pixmap2 == NULL) {
01910 #ifdef DBG_AA
01911                   fprintf(stderr, "shinking the bitmap!\n");
01912 #endif /* DBG_AA */
01913 /*                print_bitmap(&g->bitmap); */
01914                   shrink_glyph_grey(g);
01915               }
01916               put_image(g, PXL_H - g->x2, PXL_V - g->y2);
01917            }
01918            else {
01919               if (g->bitmap2.bits == NULL) {
01920                   shrink_glyph(g);
01921               }
01922               put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
01923            }
01924 #else
01925            if (g->bitmap2.bits == NULL) {
01926               shrink_glyph(g);
01927            }
01928            put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
01929 #endif
01930        }
01931 #ifdef TEXXET
01932     }
01933     if (cmd == PUT1 || (resource.omega && cmd == PUT2))
01934        DVI_H = dvi_h_sav;
01935     else if (currinf.dir > 0)
01936        DVI_H += g->dvi_adv;
01937     return;
01938 #else
01939     return g->dvi_adv;
01940 #endif
01941 }
01942 
01943 /*
01944  *     Routines to print characters.
01945  */
01946 
01947 static setcharRetvalT
01948 set_empty_char(
01949 #ifdef TEXXET
01950               wide_ubyte cmd,
01951 #endif
01952               wide_ubyte ch)
01953 {
01954 #ifdef TEXXET
01955     UNUSED(cmd);
01956 #endif
01957     UNUSED(ch);
01958 #ifdef TEXXET
01959     return;
01960 #else
01961     return 0L;
01962 #endif
01963 }
01964 
01965 setcharRetvalT
01966 load_n_set_char(
01967 #ifdef TEXXET
01968               wide_ubyte cmd,
01969 #endif
01970               wide_ubyte ch)
01971 {
01972     if (!load_font(currinf.fontp, resource.t1lib)) {    /* if not found */
01973        if (globals.ev.flags & EV_GE_NEWDOC) {    /* if abort */
01974            longjmp(globals.ev.canit, 1);
01975        }
01976 
01977        /* FIXME: does this need to be replaced by GUI warning, or has this case already been covered? */
01978        XDVI_WARNING((stderr, "load_n_set_char: Character(s) will be left blank."));
01979        currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
01980 
01981 #ifdef TEXXET
01982        return;
01983 #else
01984        return 0L;
01985 #endif
01986     }
01987     maxchar = currinf.fontp->maxchar;
01988     currinf.set_char_p = currinf.fontp->set_char_p;
01989 #ifdef TEXXET
01990     (*currinf.set_char_p) (cmd, ch);
01991     return;
01992 #else
01993     return (*currinf.set_char_p) (ch);
01994 #endif
01995 }
01996 
01997 setcharRetvalT
01998 set_vf_char(
01999 #ifdef TEXXET
02000            wide_ubyte cmd,
02001 #endif
02002            wide_ubyte ch)
02003 {
02004     struct macro *m;
02005     struct drawinf oldinfo;
02006     wide_ubyte oldmaxchar;
02007     static ubyte c;
02008 #ifdef TEXXET
02009     long dvi_h_sav;
02010 #endif
02011 
02012     if (ch > maxchar)
02013        realloc_virtual_font(currinf.fontp, ch);
02014     if ((m = &currinf.fontp->macro[ch])->pos == NULL) {
02015        if (!resource.hush_chars)
02016            XDVI_WARNING((stderr, "Character %d not defined in font %s", ch, currinf.fontp->fontname));
02017        m->pos = m->end = &c;
02018 #ifdef TEXXET
02019        return;
02020 #else
02021        return 0L;
02022 #endif
02023     }
02024 #ifdef TEXXET
02025     dvi_h_sav = DVI_H;
02026     if (currinf.dir < 0)
02027        DVI_H -= m->dvi_adv;
02028     if (scan_frame == NULL) {
02029 #endif
02030        oldinfo = currinf;
02031        if (!currinf.virtual)
02032            dvi_pointer_frame = &oldinfo;
02033        oldmaxchar = maxchar;
02034        WW = XX = YY = ZZ = 0;
02035        currinf.tn_table_len = VFTABLELEN;
02036        currinf.tn_table = currinf.fontp->vf_table;
02037        currinf.tn_head = currinf.fontp->vf_chain;
02038        currinf.pos = m->pos;
02039        currinf.end = m->end;
02040        currinf.virtual = currinf.fontp;
02041 
02042        draw_part(globals.dvi_file.bak_fp, current_frame, currinf.fontp->dimconv);
02043        if (currinf.pos != currinf.end + 1)
02044            dvi_fmt_error("virtual character macro does not end correctly");
02045        currinf = oldinfo;
02046        if (!currinf.virtual)
02047            dvi_pointer_frame = &currinf;
02048        maxchar = oldmaxchar;
02049 #ifdef TEXXET
02050     }
02051     if (cmd == PUT1 || (resource.omega && cmd == PUT2))
02052        DVI_H = dvi_h_sav;
02053     else if (currinf.dir > 0)
02054        DVI_H += m->dvi_adv;
02055     return;
02056 #else
02057     return m->dvi_adv;
02058 #endif
02059 }
02060 
02061 static setcharRetvalT
02062 set_no_char(
02063 #ifdef TEXXET
02064            wide_ubyte cmd,
02065 #endif
02066            wide_ubyte ch)
02067 {
02068     if (currinf.virtual) {
02069        currinf.fontp = currinf.virtual->first_font;
02070        if (currinf.fontp != NULL) {
02071            maxchar = currinf.fontp->maxchar;
02072            currinf.set_char_p = currinf.fontp->set_char_p;
02073 #ifdef TEXXET
02074            (*currinf.set_char_p) (cmd, ch);
02075            return;
02076 #else
02077            return (*currinf.set_char_p) (ch);
02078 #endif
02079        }
02080     }
02081     dvi_fmt_error("set_no_char: attempt to set character of unknown font");
02082     exit(0);
02083     /* NOTREACHED */
02084 }
02085 
02086 
02087 /*
02088  *     Set rule.  Arguments are coordinates of lower left corner.
02089  */
02090 
02091 static void
02092 set_rule(int h, int w)
02093 {
02094 #ifdef TEXXET
02095     put_rule(PXL_H - (currinf.dir < 0 ? w - 1 : 0), PXL_V - h + 1,
02096             (unsigned int)w, (unsigned int)h);
02097 #else
02098     put_rule(PXL_H, PXL_V - h + 1, (unsigned int)w, (unsigned int)h);
02099 #endif
02100 }
02101 
02102 
02103 /*
02104  *     Interpret a sequence of dvi bytes (either the page from the dvi file,
02105  *     or a character from a virtual font).
02106  */
02107 
02108 static void
02109 draw_part(FILE *fp, struct frame *minframe, double current_dimconv)
02110 {
02111     ubyte ch = 0;
02112 #ifdef TEXXET
02113     struct drawinf oldinfo;
02114     ubyte oldmaxchar = 0;
02115     off_t file_pos = 0;
02116     int refl_count = 0;
02117 #endif
02118     int pause_cnt = 0;
02119 
02120     globals.pausing.flag = False;
02121 
02122     currinf.fontp = NULL;
02123     currinf.set_char_p = set_no_char;
02124 #ifdef TEXXET
02125     currinf.dir = 1;
02126     scan_frame = NULL;      /* indicates we're not scanning */
02127 #endif
02128 
02129     for (;;) {
02130        ch = xone(fp);
02131        if (globals.debug & DBG_DVI) {
02132            print_dvi(ch);
02133        }
02134        if (ch <= (ubyte)(SETCHAR0 + 127)) {
02135 #ifdef TEXXET
02136            (*currinf.set_char_p) (ch, ch);
02137 #else
02138            DVI_H += (*currinf.set_char_p) (ch);
02139 #endif
02140        }
02141        else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63)) {
02142            change_font((unsigned long)(ch - FNTNUM0));
02143        }
02144        else {
02145            long a, b;
02146 
02147            switch (ch) {
02148            case SET1:
02149            case PUT1:
02150 #ifdef TEXXET
02151               (*currinf.set_char_p) (ch, xone(fp));
02152 #else
02153               a = (*currinf.set_char_p) (xone(fp));
02154               if (ch != PUT1)
02155                   DVI_H += a;
02156 #endif
02157               break;
02158 
02159            case SET2:
02160            case PUT2:
02161               if (!resource.omega)
02162                   dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
02163                               __FILE__, __LINE__, ch);
02164               else {
02165 #ifdef TEXXET
02166                   (*currinf.set_char_p) (ch, xnum(fp, 2));
02167 #else
02168                   a = (*currinf.set_char_p) (xnum(fp, 2));
02169                   if (ch != PUT2)
02170                      DVI_H += a;
02171 #endif
02172               }
02173               break;
02174 
02175            case SETRULE:
02176               /* Be careful, dvicopy outputs rules with
02177                  height = 0x80000000.  We don't want any
02178                  SIGFPE here. */
02179               a = xsfour(fp);
02180               b = xspell_conv(xsfour(fp));
02181               if (a > 0 && b > 0
02182 #ifdef TEXXET
02183                   && scan_frame == NULL
02184 #endif
02185                   ) {
02186                   set_rule(pixel_round(xspell_conv(a)), pixel_round(b));
02187               }
02188               DVI_H += DIR * b;
02189               break;
02190 
02191            case PUTRULE:
02192               a = xspell_conv(xsfour(fp));
02193               b = xspell_conv(xsfour(fp));
02194               if (a > 0 && b > 0
02195 #ifdef TEXXET
02196                   && scan_frame == NULL
02197 #endif
02198                   ) {
02199                   set_rule(pixel_round(a), pixel_round(b));
02200               }
02201               break;
02202 
02203            case NOP:
02204               break;
02205 
02206            case BOP:
02207               xskip(fp, (long)11 * 4);
02208               DVI_H = OFFSET_X;
02209               DVI_V = OFFSET_Y;
02210               PXL_V = pixel_conv(DVI_V);
02211               WW = XX = YY = ZZ = 0;
02212               break;
02213 
02214            case EOP:
02215               if (current_frame != minframe)
02216                   dvi_fmt_error("%s:%d: draw_part: stack not empty at EOP", __FILE__, __LINE__);
02217               return;
02218 
02219            case PUSH:
02220               if (current_frame->next == NULL) {
02221                   struct frame *newp = xmalloc(sizeof *newp);
02222 
02223                   current_frame->next = newp;
02224                   newp->prev = current_frame;
02225                   newp->next = NULL;
02226               }
02227               current_frame = current_frame->next;
02228               current_frame->data = currinf.data;
02229               break;
02230 
02231            case POP:
02232               if (current_frame == minframe)
02233                   dvi_fmt_error("%s:%d: draw_part: more POPs than PUSHes", __FILE__, __LINE__);
02234               currinf.data = current_frame->data;
02235               current_frame = current_frame->prev;
02236               break;
02237 
02238 #ifdef TEXXET
02239            case SREFL:
02240               if (scan_frame == NULL) {
02241                   /* we're not scanning:  save some info. */
02242                   oldinfo = currinf;
02243                   oldmaxchar = maxchar;
02244                   if (!currinf.virtual)
02245                      file_pos = xtell(fp, currinf.pos);
02246                   scan_frame = current_frame;    /* now we're scanning */
02247                   refl_count = 0;
02248                   break;
02249               }
02250               /* we are scanning */
02251               if (current_frame == scan_frame)
02252                   ++refl_count;
02253               break;
02254 
02255            case EREFL:
02256               if (scan_frame != NULL) {   /* if we're scanning */
02257                   if (current_frame == scan_frame && --refl_count < 0) {
02258                      /* we've hit the end of our scan */
02259                      scan_frame = NULL;
02260                      /* first:  push */
02261                      if (current_frame->next == NULL) {
02262                          struct frame *newp = xmalloc(sizeof *newp);
02263 
02264                          current_frame->next = newp;
02265                          newp->prev = current_frame;
02266                          newp->next = NULL;
02267                      }
02268                      current_frame = current_frame->next;
02269                      current_frame->data = currinf.data;
02270                      /* next:  restore old file position, XX, etc. */
02271                      if (!currinf.virtual) {
02272                          off_t bgn_pos = xtell(fp, G_dvi_buf_ptr);
02273 
02274                          if (file_pos >= bgn_pos) {
02275                             oldinfo.pos = dvi_buffer + (file_pos - bgn_pos);
02276                             oldinfo.end = currinf.end;
02277                          }
02278                          else {
02279                             (void)lseek(fileno(fp), file_pos, SEEK_SET);
02280                             oldinfo.pos = oldinfo.end;
02281                          }
02282                      }
02283                      currinf = oldinfo;
02284                      maxchar = oldmaxchar;
02285                      /* and then:  recover position info. */
02286                      DVI_H = current_frame->data.dvi_h;
02287                      DVI_V = current_frame->data.dvi_v;
02288                      PXL_V = current_frame->data.pxl_v;
02289                      /* and finally, reverse direction */
02290                      currinf.dir = -currinf.dir;
02291                   }
02292                   break;
02293               }
02294               /* we're not scanning, */
02295               /* so just reverse direction and then pop */
02296               currinf.dir = -currinf.dir;
02297               currinf.data = current_frame->data;
02298               current_frame = current_frame->prev;
02299               break;
02300 #endif /* TEXXET */
02301 
02302            case RIGHT1:
02303            case RIGHT2:
02304            case RIGHT3:
02305            case RIGHT4:
02306               DVI_H += DIR * xspell_conv(xsnum(fp, ch - RIGHT1 + 1));
02307               break;
02308 
02309            case W1:
02310            case W2:
02311            case W3:
02312            case W4:
02313               WW = xspell_conv(xsnum(fp, ch - W0));
02314            case W0:
02315               DVI_H += DIR * WW;
02316               break;
02317 
02318            case X1:
02319            case X2:
02320            case X3:
02321            case X4:
02322               XX = xspell_conv(xsnum(fp, ch - X0));
02323            case X0:
02324               DVI_H += DIR * XX;
02325               break;
02326 
02327            case DOWN1:
02328            case DOWN2:
02329            case DOWN3:
02330            case DOWN4:
02331               DVI_V += xspell_conv(xsnum(fp, ch - DOWN1 + 1));
02332               PXL_V = pixel_conv(DVI_V);
02333               break;
02334 
02335            case Y1:
02336            case Y2:
02337            case Y3:
02338            case Y4:
02339               YY = xspell_conv(xsnum(fp, ch - Y0));
02340            case Y0:
02341               DVI_V += YY;
02342               PXL_V = pixel_conv(DVI_V);
02343               break;
02344 
02345            case Z1:
02346            case Z2:
02347            case Z3:
02348            case Z4:
02349               ZZ = xspell_conv(xsnum(fp, ch - Z0));
02350            case Z0:
02351               DVI_V += ZZ;
02352               PXL_V = pixel_conv(DVI_V);
02353               break;
02354 
02355            case FNT1:
02356            case FNT2:
02357            case FNT3:
02358            case FNT4:
02359               change_font(xnum(fp, ch - FNT1 + 1));
02360               break;
02361 
02362            case XXX1:
02363            case XXX2:
02364            case XXX3:
02365            case XXX4:
02366               a = xnum(fp, ch - XXX1 + 1);
02367               if (a > 0) {
02368                   char *p = read_special(fp, a);
02369                   if (resource.pause && strcmp(p, resource.pause_special) == 0) {
02370                      if (++pause_cnt > globals.pausing.num) {
02371                          globals.pausing.flag = True;
02372                          /* can't use longjmp(globals.ev.canit, 1); */
02373                          return;
02374                      }
02375                   }
02376                   applicationDoSpecial(p, a);
02377               }
02378               break;
02379 
02380            case FNTDEF1:
02381            case FNTDEF2:
02382            case FNTDEF3:
02383            case FNTDEF4:
02384               xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
02385               a = (long)xone(fp);
02386               xskip(fp, a + (long)xone(fp));
02387               break;
02388 
02389 #ifndef TEXXET
02390            case SREFL:
02391            case EREFL:
02392 #endif
02393            case PRE:
02394            case POST:
02395            case POSTPOST:
02396               dvi_fmt_error("%s:%d: draw_part: shouldn't happen: %s encountered",
02397                            __FILE__, __LINE__, dvi_table2[ch - (FNTNUM0 + 64)]);
02398               break;
02399 
02400            default:
02401               dvi_fmt_error("%s:%d: draw_part: unknown op-code %d", __FILE__, __LINE__, ch);
02402            }  /* end switch */
02403        }      /* end else (ch not a SETCHAR or FNTNUM) */
02404     }  /* end for */
02405 }
02406 
02407 extern int waiting_for_anchor;
02408 
02409 static void
02410 warn_raw_postscript(void)
02411 {
02412     static int *pagelist = NULL;
02413     static int pagelist_size = 0;
02414 #ifdef PS
02415     if (!resource.hush_stdout) {
02416        if (total_pages >= pagelist_size) {
02417            pagelist_size = total_pages + 1;
02418            pagelist = xrealloc(pagelist, pagelist_size * sizeof *pagelist);
02419            memset(pagelist, 0, pagelist_size * sizeof *pagelist);
02420        }
02421        
02422        ASSERT(pagelist_size > current_page, "pagelist_size too small");
02423        if (pagelist[current_page] == 0) {
02424            XDVI_WARNING((stderr, "Raw Postscript commands on page %d may be rendered incorrectly.",
02425                        current_page + 1));
02426            pagelist[current_page] = 1;
02427        }
02428        
02429        /* too likely to overdraw important information */
02430        /*     statusline_print(STATUS_MEDIUM, */
02431        /*                    "Warning: Postscript commands on this page may not display correctly."); */
02432     }
02433 #endif /* PS */
02434 }
02435 
02436 void
02437 draw_page(void)
02438 {
02439 #if 0
02440     volatile double save_gamma = 0.0;
02441 #endif /* 0 */
02442     /* Check for changes in dvi file. */
02443     if (dvi_file_changed()) {
02444        return;
02445     }
02446 
02447     if (globals.dvi_file.bak_fp == NULL) {
02448        return;
02449     }
02450 
02451 #ifdef PS
02452     have_raw_postscript = False;
02453 #endif
02454     
02455 #if COLOR
02456     color_bottom = &fg_initial;
02457     color_bot_size = 1;
02458 
02459     if (page_colors.stack != NULL && current_page > 0) {
02460        color_bottom = page_colors.stack[current_page - 1].colorstack;
02461        color_bot_size = page_colors.stack[current_page - 1].stacksize;
02462     }
02463     rcs_top = NULL;
02464     ASSERT(color_bot_size > 0, "color_bot_size mustn't become negative!");
02465     ASSERT(color_bottom != NULL, "color_bottom mustn't become negative!");
02466     set_fg_color(&color_bottom[color_bot_size - 1]);
02467 #endif /* COLOR */
02468 
02469 #if !FIXED_FLUSHING_PAGING    
02470     draw_border(-currwin.base_x, -currwin.base_y,
02471               ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2,
02472               ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2, globals.gc.high);
02473 #endif /* MOTIF */
02474 
02475     (void) lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(current_page), SEEK_SET);
02476 
02477     memset((char *)&currinf.data, '\0', sizeof currinf.data);
02478     currinf.tn_table_len = TNTABLELEN;
02479     currinf.tn_table = tn_table;
02480     currinf.tn_head = tn_head;
02481     currinf.pos = currinf.end = dvi_buffer;
02482     currinf.virtual = NULL;
02483     dvi_pointer_frame = &currinf;
02484     drawing_mag = (currwin.win == magnifier.win);
02485     psfig_begun = False;
02486 
02487     htex_initpage(False, False, current_page);
02488 
02489     if (currwin.win == mane.win) {
02490        XRectangle rect;
02491        rect.x = globals.win_expose.min_x;
02492        rect.y = globals.win_expose.min_y;
02493        rect.width = globals.win_expose.max_x - globals.win_expose.min_x;
02494        rect.height = globals.win_expose.max_y - globals.win_expose.min_y;
02495 /*     fprintf(stderr, "clip: %d, %d, %d, %d\n", */
02496 /*            globals.win_expose.min_x, */
02497 /*            globals.win_expose.min_y, */
02498 /*            globals.win_expose.max_x - globals.win_expose.min_x, */
02499 /*            globals.win_expose.max_y - globals.win_expose.min_y); */
02500 #define SET_CLIP(gc) if (gc != NULL) XSetClipRectangles(DISP, gc, 0, 0, &rect, 1, Unsorted)
02501 #define CLEAR_CLIP(gc)  if (gc != NULL) XSetClipMask(DISP, gc, None)
02502        /* Set clip masks for all GC's */
02503        SET_CLIP(globals.gc.fore);
02504        SET_CLIP(globals.gc.fore2);
02505        SET_CLIP(globals.gc.fore2_bak);
02506        SET_CLIP(globals.gc.fore2_bak1);
02507        SET_CLIP(globals.gc.rule);
02508        SET_CLIP(globals.gc.high);
02509        SET_CLIP(globals.gc.linkcolor);
02510        SET_CLIP(globals.gc.copy);
02511     }
02512     
02513     if (!setjmp(globals.ev.canit)) {
02514        /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
02515 
02516           ALL GLYPH DRAWING/RULE SETTING COMMANDS THAT MIGHT INVOKE
02517           longjmp(globals.ev.canit)
02518           MUST GO INSIDE THIS IF CASE, AND MUST NOT BE INVOKED FROM
02519           SOMEWHERE ELSE!
02520           
02521           Failure to check whether a command could (indirectly) invoke
02522           such a drawing routine (like e.g. put_rule()) will result
02523           in *really* strange bugs (see e.g. #616920, and probably also #471021).
02524           
02525           !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
02526        */
02527        /* generate an expose event */
02528        if (search_have_match(current_page)) {
02529            search_erase_highlighting(False);
02530        }
02531        if (resource.mouse_mode == MOUSE_TEXT_MODE) {
02532            text_change_region(TEXT_SEL_ERASE, NULL);
02533        }
02534        draw_part(globals.dvi_file.bak_fp, current_frame = &frame0, dimconv);
02535 
02536        if (have_raw_postscript) {
02537            warn_raw_postscript();
02538        }
02539     }
02540     else {
02541        /* If we were interrupted, put the expose event back, so that the
02542         * region gets redrawn.  The if statement is necessary because the
02543         * magnifier may have been destroyed as part of the interrupt.  */
02544        if (currwin.win == mane.win || currwin.win == magnifier.win) {
02545            expose(currwin.win == mane.win ? &mane : &magnifier,
02546                  globals.win_expose.min_x - currwin.base_x, globals.win_expose.min_y - currwin.base_y,
02547                  globals.win_expose.max_x - globals.win_expose.min_x, globals.win_expose.max_y - globals.win_expose.min_y);
02548        }
02549 
02550 #ifdef PS
02551        psp.interrupt();
02552        /* reset this flag too, just to make sure ... */
02553 #if GS_PIXMAP_CLEARING_HACK
02554        had_ps_specials = False;
02555 #endif
02556 #endif
02557        globals.ev.flags &= ~EV_MAG_GONE;
02558 #if 0
02559        if (search_have_match() && save_gamma != 0.0) {
02560            resource.gamma = save_gamma;
02561            do_color_change();
02562            reset_fonts();
02563        }
02564 #endif /* 0 */
02565     }
02566 
02567     drawing_mag = False;
02568     dvi_pointer_frame = NULL;
02569     if (currwin.win == mane.win) {
02570        if (globals.src.fwd_box_page >= 0) {
02571            source_fwd_draw_box(); /* draw box showing found source line */
02572        }
02573        htex_draw_anchormarkers();
02574     }
02575 #ifdef PS
02576     psp.endpage();
02577 #endif
02578     if (currwin.win == mane.win && resource.postscript != 1) {
02579        display_bboxes();
02580     }
02581     if (search_have_match(current_page)) {
02582        /* highlight search match */
02583        search_draw_inverted_regions();
02584     }
02585     if (currwin.win == mane.win && resource.mouse_mode == MOUSE_TEXT_MODE) {
02586        /* highlight selection */
02587        text_change_region(TEXT_SEL_REDRAW, NULL);
02588     }
02589     if (resource.mouse_mode == MOUSE_RULER_MODE) {
02590        redraw_ruler();
02591     }
02592 
02593     clear_bboxes();
02594 
02595     if (currwin.win == mane.win) {
02596        CLEAR_CLIP(globals.gc.fore);
02597        CLEAR_CLIP(globals.gc.fore2);
02598        CLEAR_CLIP(globals.gc.fore2_bak);
02599        CLEAR_CLIP(globals.gc.fore2_bak1);
02600        CLEAR_CLIP(globals.gc.rule);
02601        CLEAR_CLIP(globals.gc.high);
02602        CLEAR_CLIP(globals.gc.linkcolor);
02603        CLEAR_CLIP(globals.gc.copy);
02604     }
02605 #undef SET_CLIP
02606 #undef CLEAR_CLIP
02607 
02608     currwin.win = (Window) 0;
02609 }
02610 
02611 /* this sets the file-scope htex_anchor_type to the type of the anchor just scanned,
02612    which is used by the drawing routines to determine whether current position is inside
02613    an anchor. Called from special.c.
02614  */
02615 void
02616 htex_do_special(const char *str, size_t len)
02617 {
02618     if (INSIDE_MANE_WIN) {
02619        htex_inside_href = htex_scan_anchor(str, len);
02620     }
02621 }
02622 
02623 /*
02624  *     General dvi scanning routines.  These are used for:
02625  *         o  source special lookups and
02626  *         o  finding the dimensions of links (if compiling with support for
02627  *            hypertext specials).
02628  *     This routine can be a bit slower than draw_page()/draw_part(), since
02629  *     it is not run that often; that is why it is a separate routine in
02630  *     spite of much duplication.
02631  *
02632  *     Note that it does not use a separate copy of define_font().
02633  */
02634 
02635 /*
02636  *     This set of routines can be called while draw_part() is active,
02637  *     so the global variables must be separate.
02638  */
02639 
02640 static struct frame geom_frame0;   /* dummy head of list */
02641 
02642 #ifdef TEXXET
02643 static struct frame *geom_scan_frame;     /* head frame for scanning */
02644 #endif
02645 
02646 static struct frame *geom_current_frame;
02647 
02648 static uint32_t
02649 get_unicode_char(wide_ubyte ch, struct drawinf currinf, char *retbuf)
02650 {
02651     /* attempt 1: if it's a Type1 font, get the Adobe character name
02652        from T1lib's T1_GetCharName */
02653     if (currinf.set_char_p == set_t1_char) {
02654        int id = currinf.fontp->t1id;
02655        int t1libid = fontmaps[id].t1libid;
02656        char *char_name;
02657        ASSERT(t1libid != -1, "Font must have been loaded at this point!");
02658        char_name = T1_GetCharName(t1libid, ch);
02659        TRACE_FIND_VERBOSE((stderr, "T1 char: %d = `%s' (id: %d; font: %s; enc: %d)",
02660                          ch, char_name,
02661                          currinf.fontp->t1id, fontmaps[currinf.fontp->t1id].texname,
02662                          fontmaps[currinf.fontp->t1id].enc));
02663        return adobe2unicode_name(char_name);
02664     }
02665     else {
02666        /* attempt 2: try to derive the encoding from the font name, by
02667           looking it up in a list of known font names.
02668        */
02669        return guess_encoding(ch, currinf.fontp->fontname, retbuf);
02670     }
02671 }
02672 
02673 #define MAX_CHARS 16 /* maximum number of unicode characters that one do_char can produce (rounded up ...) */
02674 static const size_t ALLOC_STEP = 1024;
02675 
02676 /* create a page break at BOP, unless we're at the start of the file */
02677 static void
02678 do_newpage(struct scan_info *info)
02679 {
02680     struct word_info *w_info = (struct word_info *)info->data;
02681     if (w_info->curr_buf_idx > 0) { /* not at start of file */
02682        /* resize buffer if needed */
02683        while (w_info->curr_buf_idx + MAX_CHARS >= w_info->txt_buf_size) {
02684            w_info->txt_buf_size += ALLOC_STEP;
02685            w_info->txt_buf = xrealloc(w_info->txt_buf, w_info->txt_buf_size);
02686        }
02687        w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
02688     }
02689 }
02690 
02691 static void
02692 reset_bboxes(struct word_info *info)
02693 {
02694     size_t i;
02695     for (i = 0; i < info->bboxes_size; i++) {
02696        info->bboxes[i].ulx = INT_MAX;
02697        info->bboxes[i].uly = INT_MAX;
02698        info->bboxes[i].lrx = 0;
02699        info->bboxes[i].lry = 0;
02700     }
02701 }
02702 
02703 static void
02704 delete_last_bbox(struct word_info *info)
02705 {
02706     info->bboxes[info->bboxes_idx].ulx = INT_MAX;
02707     info->bboxes[info->bboxes_idx].uly = INT_MAX;
02708     info->bboxes[info->bboxes_idx].lrx = 0;
02709     info->bboxes[info->bboxes_idx].lry = 0;
02710 }
02711 
02712 static void
02713 finish_bbox(struct word_info *info)
02714 {
02715 /*     if (info->bboxes_idx == 0) /\* nothing to do *\/ */
02716 /*     return; */
02717     
02718     info->bboxes_idx++;
02719     while (info->bboxes_idx + 1 > info->bboxes_size) {
02720        /* re-allocate info */
02721        info->bboxes_size += 32;
02722        info->bboxes = xrealloc(info->bboxes, info->bboxes_size * sizeof *(info->bboxes));
02723     }
02724     info->bboxes[info->bboxes_idx].ulx = INT_MAX;
02725     info->bboxes[info->bboxes_idx].uly = INT_MAX;
02726     info->bboxes[info->bboxes_idx].lrx = 0;
02727     info->bboxes[info->bboxes_idx].lry = 0;
02728 
02729 #if 0
02730     fprintf(stderr, "========= finish_bbox: index=%d, boxes:\n", info->bboxes_idx);
02731     {
02732        int i;
02733        for (i = 0; i < info->bboxes_idx; i++) {
02734            fprintf(stderr, "%d: x %d, y %d, w %d, h %d\n",
02735                   i, info->bboxes[i].ulx, info->bboxes[i].uly, info->bboxes[i].lrx, info->bboxes[i].lry);
02736        }
02737     }
02738 #endif /* 0 */
02739 }
02740 
02741 static void
02742 create_bbox(struct word_info *info, int x, int y, int w, int h)
02743 {
02744 #if 0
02745     fprintf(stderr, "++++++++++++++ inside match: %d,%d,%d,%d!\n", x,y,w,h);
02746     XDrawRectangle(DISP, mane.win, globals.gc.high,
02747                  x / (double)currwin.shrinkfactor + 0.5,
02748                  y / (double)currwin.shrinkfactor + 0.5,
02749                  w / (double)currwin.shrinkfactor + 0.5,
02750                  h / (double)currwin.shrinkfactor + 0.5);
02751 #endif
02752     while (info->bboxes_idx + 1 > info->bboxes_size) {
02753        /* re-allocate info */
02754        size_t old_size = info->bboxes_size;
02755        size_t i;
02756        info->bboxes_size += 32;
02757        info->bboxes = xrealloc(info->bboxes, info->bboxes_size * sizeof *(info->bboxes));
02758        for (i = old_size; i < info->bboxes_size; i++) {
02759            info->bboxes[i].ulx = INT_MAX;
02760            info->bboxes[i].uly = INT_MAX;
02761            info->bboxes[i].lrx = 0;
02762            info->bboxes[i].lry = 0;
02763        }
02764        
02765     }
02766     /* adjust size of box */
02767     if (x < info->bboxes[info->bboxes_idx].ulx)
02768        info->bboxes[info->bboxes_idx].ulx = x;
02769     if (y < info->bboxes[info->bboxes_idx].uly)
02770        info->bboxes[info->bboxes_idx].uly = y;
02771     if (x + w > info->bboxes[info->bboxes_idx].lrx)
02772        info->bboxes[info->bboxes_idx].lrx = x + w;
02773     if (y + h > info->bboxes[info->bboxes_idx].lry)
02774        info->bboxes[info->bboxes_idx].lry = y + h;
02775 #if 0
02776     fprintf(stderr, "dimens: %d, %d, %d, %d\n",
02777            info->bboxes[info->bboxes_idx].ulx,
02778            info->bboxes[info->bboxes_idx].uly,
02779            info->bboxes[info->bboxes_idx].lrx,
02780            info->bboxes[info->bboxes_idx].lry);
02781     fprintf(stderr, "============ create_bbox: index=%d, boxes:\n", info->bboxes_idx);
02782     {
02783        int i;
02784        for (i = 0; i <= info->bboxes_idx; i++) {
02785            fprintf(stderr, "%d: x %d, y %d, w %d, h %d\n",
02786                   i, info->bboxes[i].ulx, info->bboxes[i].uly, info->bboxes[i].lrx, info->bboxes[i].lry);
02787        }
02788     }
02789 #endif /* 0 */
02790 }
02791 
02792 static void
02793 map_index_positions(const struct search_info *searchinfo,
02794                   const struct page_mapping *page_mapping,
02795                   int *from, int *to)
02796 {
02797     *from = searchinfo->from_pos;
02798     *to = searchinfo->to_pos;
02799 
02800     if (*from >= page_mapping[0].offset) { /* on second page of scan */
02801 #if 0
02802        fprintf(stderr, "current_page: %d, from: %d, to: %d; subtracting %d for pageinfo at index 0\n",
02803               current_page, *from, *to, page_mapping[0].offset);
02804 #endif /* 0 */
02805        if (page_mapping[0].offset != -1) {
02806            ASSERT(page_mapping[0].offset != -1, "page_mapping not properly initialized?");
02807            (*from) -= page_mapping[0].offset;
02808            (*to) -= page_mapping[0].offset;
02809        }
02810        ASSERT(*from >= 0, "index must be > 0");
02811        ASSERT(*to >= 0, "index must be > 0");
02812        
02813     }
02814 }
02815 
02816 /* decrement curr_buf_idx so that the previous character in info
02817  * (which might be a multi-byte character) is erased.
02818  */
02819 static void
02820 erase_prev_char(struct word_info *info)
02821 {
02822     /* erase the hyphen, which might be a multibyte character */
02823     if ((unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) < 0x80) { /* single-byte */
02824        TRACE_FIND_VERBOSE((stderr, "1 XXX: %d",
02825                          (unsigned char)(info->txt_buf[info->curr_buf_idx - 1])));
02826        info->txt_buf[--(info->curr_buf_idx)] = '\0';
02827     }
02828     else { /* skip back over multi-byte sequence */
02829        while ((unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) >= 0x80
02830               && (unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) < 0xC0) { /* 10xxxxxx bytes */
02831            TRACE_FIND_VERBOSE((stderr, "2 XXX: %d",
02832                             (unsigned char)(info->txt_buf[info->curr_buf_idx - 1])));
02833            info->txt_buf[--(info->curr_buf_idx)] = '\0';
02834        }
02835        /* first byte (TODO: sanity check?) */
02836        info->txt_buf[--(info->curr_buf_idx)] = '\0';
02837     }
02838 }
02839 
02840 
02841 static Boolean
02842 inside_text_match(int curr_pos, int from, int to)
02843 {
02844     return from < curr_pos && curr_pos <= to;
02845 }
02846 
02847 static Boolean reinit_scan = False;
02848 
02849 void
02850 reinit_text_scan(void) {
02851     reinit_scan = True;
02852 }
02853 
02854 static Boolean
02855 inside_bbox(int x, int y, int w, int h,
02856            struct bbox *bboxes)
02857 {
02858     int mid_x, mid_y;
02859 #if 0
02860     XDrawRectangle(DISP, mane.win, globals.gc.high,
02861                  x / (double)currwin.shrinkfactor + 0.5,
02862                  y / (double)currwin.shrinkfactor + 0.5,
02863                  w / (double)currwin.shrinkfactor + 0.5,
02864                  h / (double)currwin.shrinkfactor + 0.5);
02865 #endif
02866     /* already treat it as inside if there's an overlap of more than 50% */
02867     mid_x = x + w / 2.0;
02868     mid_y = y + h / 2.0;
02869 #if 0
02870     fprintf(stderr, "------- check:\n%d, %d\n%d, %d, %d, %d\n",
02871            mid_x, mid_y, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
02872 #endif
02873     if (bboxes->ulx <= mid_x &&
02874        bboxes->uly <= mid_y &&
02875        bboxes->lrx >= mid_x &&
02876        bboxes->lry >= mid_y) {
02877 #if 0
02878        fprintf(stderr, "====== MATCH:\n%d, %d\n%d, %d, %d, %d\n",
02879               mid_x, mid_y, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
02880 #endif
02881        return True;
02882     }
02883     return False;
02884 }
02885 
02886 static Boolean
02887 inside_bbox_line(int y, int h,
02888                struct bbox *bboxes)
02889 {
02890     int mid_y = y + h / 2.0;
02891     if (bboxes->uly <= mid_y &&
02892        bboxes->lry >= mid_y) {
02893 #if 0
02894        fprintf(stderr, "MATCH:\n%d, %d, %d, %d\n%d, %d, %d, %d\n",
02895               x, y, w, h, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
02896 #endif
02897        return True;
02898     }
02899     return False;
02900 }
02901 
02902 static void
02903 do_char(wide_ubyte ch,
02904        struct drawinf currinf,
02905        struct scan_info *info,
02906        long pxl_v1, long pxl_v2,
02907        long x1, long x2,
02908        struct glyph *g)
02909 {
02910     struct word_info *w_info = (struct word_info *)info->data;
02911     struct search_settings *settings = NULL;
02912     const struct page_mapping *page_mapping = NULL;
02913     uint32_t u_glyph = 0, new_glyph = 0;
02914     float fsize = dvi_pt_conv(currinf.fontp->scale); /* font size in pt */
02915     Boolean convert_to_lowercase = False;
02916     /* if set to true, ignore whitespace before/after character (for CJK characters) */
02917     Boolean ignore_whitespace = False;
02918     
02919     /* default min space between words, in DVI units */
02920     /* TODO: for T1 fonts, should we look at fontdimen2 / fontdimen4?
02921        (e.g. tfminfo[fontmaps[currinf.fontp->t1id].tfmidx].fontdimen2)
02922      */
02923     long min_delta = (int)(1.5 * fsize + 0.5) << 16;
02924 
02925     size_t buf_offset = w_info->buffer_offset;
02926 
02927     size_t i;
02928     /* for delayed insertion of newlines in text selection mode */
02929     static Boolean had_newline = False;
02930     /* for whitespace insertion in text selection mode */
02931     static Boolean had_chars_in_line = False;
02932     static long last_dvi_h1 = 0, last_pxl_v = 0;
02933     static long last_dvi_h2 = 0;
02934     static long last_x = 0;
02935     static uint32_t last_u_glyph = 0;
02936     static int last_page = -1;
02937     static int page_bak = -1;
02938     const char *expanded_lig = NULL;
02939     const uint32_t UNKNOWN_GLYPH_CODE = 0x003F; /* question mark */
02940     char retbuf[MAX_CHARS];
02941     retbuf[0] = '\0';
02942     
02943     if (w_info != NULL && w_info->settings != NULL) {
02944        settings = w_info->settings;
02945        if (!settings->case_sensitive)
02946            convert_to_lowercase = True;
02947     }
02948     
02949     if (w_info->bbox_pass) {
02950        ASSERT(w_info != NULL, "");
02951        ASSERT(w_info->page_mapping != NULL, "");
02952        page_mapping = w_info->page_mapping;
02953     }
02954     
02955     if (reinit_scan || last_page != current_page) { /* reinit */
02956        last_dvi_h1 = last_pxl_v = last_dvi_h2 = last_x = 0;
02957        last_page = current_page;
02958        last_u_glyph = 0;
02959        w_info->bboxes_idx = 0;
02960        reset_bboxes(w_info);
02961 /*     w_info->curr_buf_idx  = 0; */
02962        reinit_scan = False;
02963        had_newline = False;
02964        had_chars_in_line = False;
02965     }
02966     
02967 /*      TRACE_FIND((stderr, "\n--------- POSITIONS: %ld, %ld, %ld, %ld", x1, pxl_v2, x2, y2)); */
02968 
02969     if ((u_glyph = get_unicode_char(ch, currinf, retbuf)) == 0) {
02970        if (retbuf[0] == '\0') {
02971            TRACE_FIND((stderr, "unknown glyph `%lu'\n", (unsigned long)ch));
02972            u_glyph = UNKNOWN_GLYPH_CODE;
02973        }
02974        else /* several characters in retbuf, will be evaluated later */
02975            u_glyph = 0;
02976     }
02977 
02978     TRACE_FIND_VERBOSE((stderr, "UNICODE: 0x%.4X; idx: %ld",
02979                      (unsigned int)u_glyph,
02980                      (unsigned long)w_info->curr_buf_idx));
02981     
02982     /* resize buffer if needed */
02983     while (w_info->curr_buf_idx + MAX_CHARS >= w_info->txt_buf_size) {
02984        w_info->txt_buf_size += ALLOC_STEP;
02985        w_info->txt_buf = xrealloc(w_info->txt_buf, w_info->txt_buf_size);
02986     }
02987 
02988     /* Copy text into buffer, applying heuristics for special glyphs.
02989        A `\0' is always appended, so that we have a valid C string;
02990        if we have more text, this '\0' will be overwritten in the next call. */
02991 
02992     /* apply accent/linebreak heuristics */
02993 /*     fprintf(stderr, "Checking: %ld > 0, %ld > 0\n", last_dvi_h1, last_pxl_v); */
02994     if (last_dvi_h1 > 0 && last_pxl_v > 0) { /* had at least 1 character */
02995        TRACE_FIND_VERBOSE((stderr, "++++ dvi_h: %ld, last_dvi_h1: %ld, w_info->curr_buf_idx: %ld",
02996                          DVI_H, last_dvi_h1, (unsigned long)w_info->curr_buf_idx));
02997        
02998        /* spaces after/before ideographic characters are ignored */
02999        if (is_ideograph(last_u_glyph) || is_ideograph(u_glyph))
03000            ignore_whitespace = true;
03001        
03002        /* first, check for linebreaks since accents are also triggered by negative hspace.
03003         * Usually, a linebreak is signalled by vertical movement down. However, in multicolumn
03004         * mode, it can also be a movement up, which we try to catch with the second condition. */
03005        if (pxl_v2 > last_pxl_v + (int)(1.2 * fsize + 0.5)
03006            || (page_bak == current_page && pxl_v2 + (int)(6 * fsize + 0.5) < last_pxl_v)) {
03007            TRACE_FIND_VERBOSE((stderr, "linebreak (%ld > %ld + %d || %ld < %ld)!\n",
03008                             pxl_v2, last_pxl_v, (int)(1.2 * fsize + 0.5),
03009                             pxl_v2 + (int)(6 * fsize + 0.5), last_pxl_v));
03010            
03011            /* remove hyphen followed by newline if ignore_hyphens option is set,
03012               and we're scanning for string search: */
03013            if ((w_info->search_scan_pass || w_info->bbox_pass)
03014               && settings->ignore_hyphens && w_info->curr_buf_idx > 0
03015               && is_hyphenchar(last_u_glyph)) {
03016               
03017               erase_prev_char(w_info);
03018               TRACE_FIND_VERBOSE((stderr, "%d > %d + %d? offset: %lu",
03019                                 settings->searchinfo->from_pos,
03020                                 (int)w_info->curr_buf_idx,
03021                                 settings->hyphen_delta, (unsigned long)buf_offset));
03022               if (!w_info->bbox_pass
03023                   && settings->searchinfo->from_pos
03024                   > (int)(w_info->curr_buf_idx + buf_offset + settings->hyphen_delta)) {
03025                   settings->hyphen_delta += 2;
03026               }
03027               TRACE_FIND((stderr, "erasing hyphen %lu at pos %lu with char %c; hyphen_delta is: %d",
03028                          (unsigned long)last_u_glyph, (unsigned long)w_info->curr_buf_idx, ch, settings->hyphen_delta));
03029               /* If the position of this hyphen had been at the start of the bounding
03030                  box, this bounding box info is now invalid - delete it */
03031               if (w_info->bbox_pass) {
03032                   int from, to;
03033                   map_index_positions(settings->searchinfo, page_mapping, &from, &to);
03034                   if ((int)w_info->curr_buf_idx == from) {
03035                      delete_last_bbox(w_info);
03036                   }
03037               }
03038            }
03039            else { /* ignore_hyphens not set, insert newline */
03040               /* Also save hyphen_delta, in case we need to update from_pos and to_pos
03041                  if user switched from ignore hyphens to don't ignore hyphens */
03042               if (w_info->search_scan_pass && !w_info->bbox_pass
03043                   && is_hyphenchar(last_u_glyph)
03044                   && settings->searchinfo->from_pos + settings->hyphen_delta
03045                   >= (int)(w_info->curr_buf_idx + buf_offset)) {
03046                   settings->hyphen_delta += 2;
03047                   TRACE_FIND((stderr, "updating delta: %d at pos %d, curr_idx %d, offset: %lu",
03048                             settings->hyphen_delta, settings->searchinfo->from_pos,
03049                             (int)w_info->curr_buf_idx, (unsigned long)buf_offset));
03050               }
03051               if (w_info->text_selection_pass) {
03052                   if (inside_bbox(last_x, last_pxl_v, 5, 5, w_info->bboxes)
03053                      || (inside_bbox_line(last_pxl_v, 5, w_info->bboxes))) {
03054                      had_newline = True;
03055                      had_chars_in_line = False;
03056                   }
03057               }
03058               else if (w_info->search_scan_pass && settings->ignore_linebreaks && !ignore_whitespace)
03059                   w_info->txt_buf[w_info->curr_buf_idx++] = ' ';
03060               else if (!ignore_whitespace)
03061                   w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
03062            }
03063            if (w_info->bbox_pass) {
03064               int from, to;
03065               map_index_positions(settings->searchinfo, page_mapping, &from, &to);
03066               if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
03067                   finish_bbox(w_info);
03068               }
03069            }
03070        }
03071        else if (w_info->curr_buf_idx > 0 && last_u_glyph != 0 && last_x > 0
03072                && (!w_info->text_selection_pass
03073                    || (w_info->text_selection_pass
03074                       && inside_bbox(last_x, pxl_v2, x1 - last_x, pxl_v1 - pxl_v2, w_info->bboxes)))
03075                && x1 < last_x /* overlapping glyphs: check for diacritics */
03076                && ((new_glyph = get_accented_glyph(last_u_glyph, u_glyph)) != 0)) {
03077            erase_prev_char(w_info);
03078            /* use new glyph for next writing operation: */
03079            u_glyph = new_glyph;
03080        }
03081        else if (!ignore_whitespace && last_dvi_h2 > 0 && DVI_H > last_dvi_h2 + min_delta) {
03082            TRACE_FIND_VERBOSE((stderr, "space (%ld > %ld + %ld)!", DVI_H, last_dvi_h2, min_delta));
03083            if (!w_info->text_selection_pass
03084               || (w_info->text_selection_pass
03085                   && had_chars_in_line
03086                   && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h, w_info->bboxes))) {
03087               w_info->txt_buf[w_info->curr_buf_idx++] = ' ';
03088               w_info->txt_buf[w_info->curr_buf_idx] = '\0';
03089               if (w_info->bbox_pass) {
03090                   int from, to;
03091                   map_index_positions(settings->searchinfo, page_mapping, &from, &to);
03092                   if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
03093                      TRACE_FIND_VERBOSE((stderr, "bounding box for space: %ld, %ld, %ld, %ld",
03094                                        last_x, last_pxl_v, x1 - last_x, pxl_v1 - pxl_v2));
03095                      create_bbox(w_info, last_x, pxl_v2, x1 - last_x, pxl_v1 - pxl_v2);
03096                   }
03097               }
03098            }
03099        }
03100     }
03101 
03102     last_page = current_page;
03103     if (retbuf[0] != '\0'
03104        || (expanded_lig = expand_ligature(u_glyph)) != NULL
03105        /* when in search pass, normalize more characters */
03106        || ((w_info->bbox_pass || w_info->search_scan_pass)
03107            && (expanded_lig = search_normalize_chars(u_glyph)) != NULL)) {
03108        /* expanded ligature, which is always in 7-bit ASCII -> copy into buffer */
03109        size_t len;
03110        if (retbuf[0] != '\0')
03111            expanded_lig = retbuf;
03112        len = strlen(expanded_lig);
03113        TRACE_FIND_VERBOSE((stderr, "I: %lu to %lu",
03114                          (unsigned long)w_info->curr_buf_idx,
03115                          (unsigned long)(w_info->curr_buf_idx + len)));
03116 
03117        if (!w_info->text_selection_pass
03118            || (w_info->text_selection_pass && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h,
03119                                                     w_info->bboxes))) {
03120 
03121 /*         fprintf(stderr, "inserting1 %s\n", expanded_lig); */
03122            if (had_newline) {
03123               w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
03124               had_newline = False;
03125            }
03126            memcpy(w_info->txt_buf + w_info->curr_buf_idx, expanded_lig, len);
03127            had_chars_in_line = True;
03128            for (i = 0; i < len; i++) {
03129               w_info->curr_buf_idx++;
03130 /*            fprintf(stderr, "setting index to: %d\n", w_info->curr_buf_idx); */
03131               if (w_info->bbox_pass) {
03132                   int from, to;
03133                   map_index_positions(settings->searchinfo, page_mapping, &from, &to);
03134                   if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
03135                      create_bbox(w_info, x1, pxl_v2, x2 - x1, g->bitmap.h);
03136                   }
03137               }
03138            }
03139            w_info->txt_buf[w_info->curr_buf_idx] = '\0';
03140        }
03141     }
03142     else if (!w_info->text_selection_pass
03143          || (w_info->text_selection_pass && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h, w_info->bboxes))) {
03144        /* convert to utf8 */
03145        char utf8_buf[MAX_CHARS]; /* ample ... */
03146        size_t len;
03147        /* convert to utf8, eventually lowercasing */
03148        ucs4_to_utf8(u_glyph, utf8_buf, &len, convert_to_lowercase);
03149 /*     fprintf(stderr, "inserting2 %lu\n", u_glyph); */
03150        if (had_newline) {
03151            w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
03152            had_newline = False;
03153        }
03154        memcpy(w_info->txt_buf + w_info->curr_buf_idx, utf8_buf, len);
03155        had_chars_in_line = True;
03156        for (i = 0; i < len; i++) {
03157            w_info->curr_buf_idx++;
03158 /*         fprintf(stderr, "setting index2 to: %d\n", w_info->curr_buf_idx); */
03159            if (w_info->bbox_pass) {
03160               int from, to;
03161 #if 0
03162               int j;
03163               fprintf(stderr, "current page_mapping:\n");
03164               for (j = 0; j <= total_pages; j++) {
03165                   fprintf(stderr, "%d: %d\n", j, page_mapping[j]);
03166               }
03167 #endif /* 0 */
03168 /*            fprintf(stderr, "mapping!\n"); */
03169               map_index_positions(settings->searchinfo, page_mapping, &from, &to);
03170               if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
03171                   create_bbox(w_info, x1, pxl_v2, x2 - x1, g->bitmap.h);
03172               }
03173            }
03174        }
03175        w_info->txt_buf[w_info->curr_buf_idx] = '\0'; /* ensure termination */
03176     }
03177 
03178     last_dvi_h1 = DVI_H;
03179     last_u_glyph = u_glyph;
03180     last_pxl_v = pxl_v1;
03181     last_dvi_h2 = DVI_H + currinf.fontp->glyph[ch].dvi_adv;
03182     last_x = x2;
03183 }
03184 
03185 /* handle a character in the text scanning routine */
03186 long
03187 text_do_char(FILE *fp, struct scan_info *info, wide_ubyte ch)
03188 {
03189     if (currinf.set_char_p == set_no_char) {
03190        if (currinf.virtual == NULL
03191            || (currinf.fontp = currinf.virtual->first_font) == NULL)
03192            return 0; /* error; we'll catch it later */
03193        maxchar = currinf.fontp->maxchar;
03194        currinf.set_char_p = currinf.fontp->set_char_p;
03195     }
03196 
03197     if (currinf.set_char_p == set_empty_char)
03198        return 0;     /* error; we'll catch it later */
03199 
03200     if (currinf.set_char_p == load_n_set_char) {
03201        if (globals.ev.flags & EV_GE_NEWDOC)      /* if abort */
03202            return 0;
03203        if (!load_font(currinf.fontp, resource.t1lib)) { /* if not found */
03204            if (globals.ev.flags & EV_GE_NEWDOC)  /* if abort */
03205               return 0;
03206 
03207            /* FIXME: replace by GUI warning! */
03208            fputs("geom_do_char: Character(s) will be left blank.\n", stderr);
03209            currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
03210            return 0;
03211        }
03212        maxchar = currinf.fontp->maxchar;
03213        currinf.set_char_p = currinf.fontp->set_char_p;
03214     }
03215 
03216     if (currinf.set_char_p == set_char) {
03217        struct glyph *g;
03218        long x, y;
03219 
03220        if (ch > maxchar)
03221            return 0; /* catch the error later */
03222        if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
03223            if (g->addr == 0)
03224               return 0;     /* catch the error later */
03225            if (g->addr == -1)
03226               return 0;     /* previously flagged missing char */
03227            open_font_file(currinf.fontp);
03228            fseek(currinf.fontp->file, g->addr, SEEK_SET);
03229            (*currinf.fontp->read_char) (currinf.fontp, ch);
03230            if (globals.debug & DBG_BITMAP)
03231               print_char((ubyte) ch, g);
03232            currinf.fontp->timestamp = ++current_timestamp;
03233        }
03234 #ifdef TEXXET
03235        if (geom_scan_frame == NULL) {
03236            long dvi_h_sav = DVI_H;
03237            if (currinf.dir < 0)
03238               DVI_H -= g->dvi_adv;
03239 #endif
03240            x = G_PXL_H - g->x;
03241            y = PXL_V - g->y;
03242            do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
03243 #ifdef TEXXET
03244            DVI_H = dvi_h_sav;
03245        }
03246 #endif
03247        return DIR * g->dvi_adv;
03248     }
03249     else if (currinf.set_char_p == set_vf_char) {
03250        struct macro *m;
03251        struct drawinf oldinfo;
03252        ubyte oldmaxchar;
03253 #ifdef TEXXET
03254        long dvi_h_sav;
03255 #endif
03256 
03257        if (ch > maxchar)
03258            return 0; /* catch the error later */
03259        if ((m = &currinf.fontp->macro[ch])->pos == NULL)
03260            return 0; /* catch the error later */
03261 #ifdef TEXXET
03262        dvi_h_sav = DVI_H;
03263        if (currinf.dir < 0)
03264            DVI_H -= m->dvi_adv;
03265        if (geom_scan_frame == NULL) {
03266 #endif
03267            oldinfo = currinf;
03268            oldmaxchar = maxchar;
03269            WW = XX = YY = ZZ = 0;
03270            currinf.tn_table_len = VFTABLELEN;
03271            currinf.tn_table = currinf.fontp->vf_table;
03272            currinf.tn_head = currinf.fontp->vf_chain;
03273            currinf.pos = m->pos;
03274            currinf.end = m->end;
03275            currinf.virtual = currinf.fontp;
03276            geom_scan_part(text_do_char, fp, info, geom_current_frame, currinf.fontp->dimconv);
03277            currinf = oldinfo;
03278            maxchar = oldmaxchar;
03279 #ifdef TEXXET
03280            DVI_H = dvi_h_sav;
03281        }
03282 #endif
03283        return DIR * m->dvi_adv;
03284     }
03285 #ifdef T1LIB
03286     else if (currinf.set_char_p == set_t1_char) {
03287        struct glyph *g ;
03288        long x, y;
03289        t1FontLoadStatusT status;
03290 
03291 #ifdef TEXXET
03292        g = get_t1_glyph(0, ch, &status, True);
03293        if (status == FAILURE_BLANK)
03294            return 0;
03295        if (geom_scan_frame == NULL) {
03296            long dvi_h_sav = DVI_H;
03297            if (currinf.dir < 0)
03298               DVI_H -= g->dvi_adv;
03299            x = G_PXL_H - g->x;
03300            y = PXL_V - g->y;
03301            do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
03302            DVI_H = dvi_h_sav;
03303        }
03304 #else
03305        g = get_t1_glyph(ch, &status, True);
03306        if (status == FAILURE_BLANK)
03307            return 0;
03308        x = G_PXL_H - g->x;
03309        y = PXL_V - g->y;
03310        do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
03311 #endif
03312        return DIR * g->dvi_adv;
03313     }
03314 #endif /* T1LIB */
03315     else {
03316        XDVI_FATAL((stderr, "currinf.set_char_p not a registered routine!"));
03317     }
03318     /* NOTREACHED */
03319     return 0;
03320 }
03321 
03322 /*
03323  *     Handle a character in geometric scanning routine.
03324  */
03325 
03326 static long
03327 geom_do_char(FILE *fp, struct scan_info *info, wide_ubyte ch)
03328 {
03329     struct geom_info *g_info = info->data;
03330     
03331     if (currinf.set_char_p == set_no_char) {
03332        if (currinf.virtual == NULL
03333            || (currinf.fontp = currinf.virtual->first_font) == NULL)
03334            return 0; /* error; we'll catch it later */
03335        maxchar = currinf.fontp->maxchar;
03336        currinf.set_char_p = currinf.fontp->set_char_p;
03337     }
03338 
03339     if (currinf.set_char_p == set_empty_char)
03340        return 0;     /* error; we'll catch it later */
03341 
03342     if (currinf.set_char_p == load_n_set_char) {
03343        if (globals.ev.flags & EV_GE_NEWDOC)      /* if abort */
03344            return 0;
03345        if (!load_font(currinf.fontp, resource.t1lib)) { /* if not found */
03346            if (globals.ev.flags & EV_GE_NEWDOC)  /* if abort */
03347               return 0;
03348 
03349            /* FIXME: replace by GUI warning! */
03350            fputs("geom_do_char: Character(s) will be left blank.\n", stderr);
03351            currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
03352            return 0;
03353        }
03354        maxchar = currinf.fontp->maxchar;
03355        currinf.set_char_p = currinf.fontp->set_char_p;
03356     }
03357 
03358     if (currinf.set_char_p == set_char) {
03359        struct glyph *g;
03360        long x, y;
03361 
03362        if (ch > maxchar)
03363            return 0; /* catch the error later */
03364        if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
03365            if (g->addr == 0)
03366               return 0;     /* catch the error later */
03367            if (g->addr == -1)
03368               return 0;     /* previously flagged missing char */
03369            open_font_file(currinf.fontp);
03370            fseek(currinf.fontp->file, g->addr, SEEK_SET);
03371            (*currinf.fontp->read_char) (currinf.fontp, ch);
03372            if (globals.debug & DBG_BITMAP)
03373               print_char((ubyte) ch, g);
03374            currinf.fontp->timestamp = ++current_timestamp;
03375        }
03376 #ifdef TEXXET
03377        if (geom_scan_frame == NULL) {
03378            long dvi_h_sav = DVI_H;
03379            if (currinf.dir < 0)
03380               DVI_H -= g->dvi_adv;
03381 #endif
03382            x = G_PXL_H - g->x;
03383            y = PXL_V - g->y;
03384            g_info->geom_box(info, x, y,
03385                           x + g->bitmap.w - 1, y + g->bitmap.h - 1);
03386 
03387 #ifdef TEXXET
03388            DVI_H = dvi_h_sav;
03389        }
03390 #endif
03391        return DIR * g->dvi_adv;
03392     }
03393     else if (currinf.set_char_p == set_vf_char) {
03394        struct macro *m;
03395        struct drawinf oldinfo;
03396        ubyte oldmaxchar;
03397 #ifdef TEXXET
03398        long dvi_h_sav;
03399 #endif
03400 
03401        if (ch > maxchar)
03402            return 0; /* catch the error later */
03403        if ((m = &currinf.fontp->macro[ch])->pos == NULL)
03404            return 0; /* catch the error later */
03405 #ifdef TEXXET
03406        dvi_h_sav = DVI_H;
03407        if (currinf.dir < 0)
03408            DVI_H -= m->dvi_adv;
03409        if (geom_scan_frame == NULL) {
03410 #endif
03411            oldinfo = currinf;
03412            oldmaxchar = maxchar;
03413            WW = XX = YY = ZZ = 0;
03414            currinf.tn_table_len = VFTABLELEN;
03415            currinf.tn_table = currinf.fontp->vf_table;
03416            currinf.tn_head = currinf.fontp->vf_chain;
03417            currinf.pos = m->pos;
03418            currinf.end = m->end;
03419            currinf.virtual = currinf.fontp;
03420            geom_scan_part(geom_do_char, fp, info, geom_current_frame, currinf.fontp->dimconv);
03421            currinf = oldinfo;
03422            maxchar = oldmaxchar;
03423 #ifdef TEXXET
03424            DVI_H = dvi_h_sav;
03425        }
03426 #endif
03427        return DIR * m->dvi_adv;
03428     }
03429 #ifdef T1LIB
03430     else if (currinf.set_char_p == set_t1_char) {
03431        struct glyph *g ;
03432        long x, y;
03433        t1FontLoadStatusT status;
03434 
03435 #ifdef TEXXET
03436        g = get_t1_glyph(0, ch, &status, False);
03437        if (status == FAILURE_BLANK)
03438            return 0;
03439        if (geom_scan_frame == NULL) {
03440            long dvi_h_sav = DVI_H;
03441            if (currinf.dir < 0)
03442               DVI_H -= g->dvi_adv;
03443            x = G_PXL_H - g->x;
03444            y = PXL_V - g->y;
03445            g_info->geom_box(info, x, y,
03446                           x + g->bitmap.w - 1, y + g->bitmap.h - 1);
03447            DVI_H = dvi_h_sav;
03448        }
03449 #else
03450        g = get_t1_glyph(ch, &status, False);
03451        if (status == FAILURE_BLANK)
03452            return 0;
03453        x = G_PXL_H - g->x;
03454        y = PXL_V - g->y;
03455        g_info->geom_box(info, x, y,
03456                       x + g->bitmap.w - 1, y + g->bitmap.h - 1);
03457 #endif
03458        return DIR * g->dvi_adv;
03459     }
03460 #endif /* T1LIB */
03461     else {
03462        XDVI_FATAL((stderr, "currinf.set_char_p not a registered routine!"));
03463     }
03464     /* NOTREACHED */
03465     return 0;
03466 }
03467 
03468 /*
03469  *     Do a rule in the geometry-scanning routine.
03470  */
03471 
03472 static void
03473 geom_do_rule(struct scan_info *info, long h, long w)
03474 {
03475     long x, y;
03476 #ifdef TEXXET
03477     long dvi_h_save = DVI_H;
03478 #endif
03479     struct geom_info *g_info = info->data;
03480     
03481 #ifdef TEXXET
03482     if (currinf.dir < 0)
03483        DVI_H -= w - 1;
03484 #endif
03485     x = G_PXL_H;
03486     y = PXL_V;
03487     g_info->geom_box(info, x, y - xpixel_round(h) + 1,
03488                    x + xpixel_round(w) - 1, y);
03489 #ifdef TEXXET
03490     DVI_H = dvi_h_save;
03491 #endif
03492 }
03493 
03494 /*
03495  *     Geometric dvi scanner work routine.  This does most of the work
03496  *     (a) reading from a page, and (b) executing vf macros.
03497  */
03498 
03499 void
03500 geom_scan_part(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
03501               FILE *fp, struct scan_info *info, struct frame *minframe, double current_dimconv)
03502 {
03503     ubyte ch;
03504 #ifdef TEXXET
03505     struct drawinf oldinfo;
03506     ubyte oldmaxchar = 0;
03507     off_t file_pos = 0;
03508     int refl_count = 0;
03509 #endif
03510 
03511     currinf.fontp = NULL;
03512     currinf.set_char_p = set_no_char;
03513 #ifdef TEXXET
03514     currinf.dir = 1;
03515     geom_scan_frame = NULL; /* indicates we're not scanning */
03516 #endif
03517     for (;;) {
03518        ch = xone(fp);
03519        if (ch <= (ubyte)(SETCHAR0 + 127))
03520            DVI_H += char_proc(fp, info, ch);
03521        else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63)) {
03522            change_font((unsigned long)(ch - FNTNUM0));
03523        }
03524        else {
03525            long a, b;
03526 
03527            switch (ch) {
03528            case SET1:
03529            case PUT1:
03530               a = char_proc(fp, info, xone(fp));
03531               if (ch != PUT1)
03532                   DVI_H += a;
03533               break;
03534 
03535            case SET2:
03536            case PUT2:
03537               if (!resource.omega)
03538                   dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
03539                               __FILE__, __LINE__, ch);
03540               else {
03541 #ifdef TEXXET
03542                   char_proc(fp, info, xnum(fp, 2));
03543 #else
03544                   a = char_proc(fp, info, xnum(fp, 2));
03545                   if (ch != PUT2)
03546                      DVI_H += a;
03547 #endif
03548               }
03549               break;
03550 
03551            case SETRULE:
03552               /* Be careful, dvicopy outputs rules with
03553                  height = 0x80000000.  We don't want any
03554                  SIGFPE here. */
03555               a = xsfour(fp);
03556               b = xspell_conv(xsfour(fp));
03557               if (a >= 0 && b >= 0
03558 #ifdef TEXXET
03559                   && geom_scan_frame == NULL
03560 #endif
03561                   ) {
03562                   /* is this a geom scan? */
03563                   if (info->geom_special != NULL)
03564                      geom_do_rule(info, xspell_conv(a), b);
03565               }
03566               DVI_H += DIR * b;
03567               break;
03568 
03569            case PUTRULE:
03570               a = xspell_conv(xsfour(fp));
03571               b = xspell_conv(xsfour(fp));
03572               if (a >= 0 && b >= 0
03573 #ifdef TEXXET
03574                   && geom_scan_frame == NULL
03575 #endif
03576                   ) {
03577                   /* is this a geom scan? */
03578                   if (info->geom_special != NULL)
03579                      geom_do_rule(info, a, b);
03580               }
03581               break;
03582 
03583            case NOP:
03584               break;
03585 
03586            case BOP:
03587               xskip(fp, (long)11 * 4);
03588               DVI_H = G_OFFSET_X;
03589               DVI_V = G_OFFSET_Y;
03590               PXL_V = xpixel_conv(DVI_V);
03591               WW = XX = YY = ZZ = 0;
03592               /* create pagebreak in character scan */
03593               if (info->geom_special == NULL) {
03594                   do_newpage(info);
03595               }
03596               break;
03597 
03598            case PUSH:
03599               if (geom_current_frame->next == NULL) {
03600                   struct frame *newp = xmalloc(sizeof *newp);
03601 
03602                   geom_current_frame->next = newp;
03603                   newp->prev = geom_current_frame;
03604                   newp->next = NULL;
03605               }
03606               geom_current_frame = geom_current_frame->next;
03607               geom_current_frame->data = currinf.data;
03608               break;
03609 
03610            case POP:
03611               if (geom_current_frame == minframe)
03612                   dvi_fmt_error("more POPs than PUSHes");
03613               currinf.data = geom_current_frame->data;
03614               geom_current_frame = geom_current_frame->prev;
03615               break;
03616 
03617 #ifdef TEXXET
03618            case SREFL:
03619               if (geom_scan_frame == NULL) {
03620                   /* we're not scanning:  save some info. */
03621                   oldinfo = currinf;
03622                   oldmaxchar = maxchar;
03623                   if (!currinf.virtual)
03624                      file_pos = xtell(fp, currinf.pos);
03625                   geom_scan_frame = geom_current_frame; /* start scanning */
03626                   refl_count = 0;
03627                   break;
03628               }
03629               /* we are scanning */
03630               if (geom_current_frame == geom_scan_frame)
03631                   ++refl_count;
03632               break;
03633 
03634            case EREFL:
03635               if (geom_scan_frame != NULL) {     /* if we're scanning */
03636                   if (geom_current_frame == geom_scan_frame
03637                      && --refl_count < 0) {
03638                      /* we've hit the end of our scan */
03639                      geom_scan_frame = NULL;
03640                      /* first:  push */
03641                      if (geom_current_frame->next == NULL) {
03642                          struct frame *newp = xmalloc(sizeof *newp);
03643 
03644                          geom_current_frame->next = newp;
03645                          newp->prev = geom_current_frame;
03646                          newp->next = NULL;
03647                      }
03648                      geom_current_frame = geom_current_frame->next;
03649                      geom_current_frame->data = currinf.data;
03650                      /* next:  restore old file position, XX, etc. */
03651                      if (!currinf.virtual) {
03652                          off_t bgn_pos = xtell(fp, G_dvi_buf_ptr);
03653 
03654                          if (file_pos >= bgn_pos) {
03655                             oldinfo.pos = dvi_buffer + (file_pos - bgn_pos);
03656                             oldinfo.end = currinf.end;
03657                          }
03658                          else {
03659                             (void)lseek(fileno(fp), file_pos,
03660                                        SEEK_SET);
03661                             oldinfo.pos = oldinfo.end;
03662                          }
03663                      }
03664                      currinf = oldinfo;
03665                      maxchar = oldmaxchar;
03666                      /* and then:  recover position info. */
03667                      DVI_H = geom_current_frame->data.dvi_h;
03668                      DVI_V = geom_current_frame->data.dvi_v;
03669                      PXL_V = geom_current_frame->data.pxl_v;
03670                      /* and finally, reverse direction */
03671                      currinf.dir = -currinf.dir;
03672                   }
03673                   break;
03674               }
03675               /* we're not scanning, */
03676               /* so just reverse direction and then pop */
03677               currinf.dir = -currinf.dir;
03678               currinf.data = geom_current_frame->data;
03679               geom_current_frame = geom_current_frame->prev;
03680               break;
03681 #endif /* TEXXET */
03682 
03683            case RIGHT1:
03684            case RIGHT2:
03685            case RIGHT3:
03686            case RIGHT4:
03687               DVI_H += DIR * xspell_conv(xsnum(fp, ch - RIGHT1 + 1));
03688               break;
03689 
03690            case W1:
03691            case W2:
03692            case W3:
03693            case W4:
03694               WW = xspell_conv(xsnum(fp, ch - W0));
03695            case W0:
03696               DVI_H += DIR * WW;
03697               break;
03698 
03699            case X1:
03700            case X2:
03701            case X3:
03702            case X4:
03703               XX = xspell_conv(xsnum(fp, ch - X0));
03704            case X0:
03705               DVI_H += DIR * XX;
03706               break;
03707 
03708            case DOWN1:
03709            case DOWN2:
03710            case DOWN3:
03711            case DOWN4:
03712               DVI_V += xspell_conv(xsnum(fp, ch - DOWN1 + 1));
03713               PXL_V = xpixel_conv(DVI_V);
03714               break;
03715 
03716            case Y1:
03717            case Y2:
03718            case Y3:
03719            case Y4:
03720               YY = xspell_conv(xsnum(fp, ch - Y0));
03721            case Y0:
03722               DVI_V += YY;
03723               PXL_V = xpixel_conv(DVI_V);
03724               break;
03725 
03726            case Z1:
03727            case Z2:
03728            case Z3:
03729            case Z4:
03730               ZZ = xspell_conv(xsnum(fp, ch - Z0));
03731            case Z0:
03732               DVI_V += ZZ;
03733               PXL_V = xpixel_conv(DVI_V);
03734               break;
03735 
03736            case FNT1:
03737            case FNT2:
03738            case FNT3:
03739            case FNT4:
03740               change_font(xnum(fp, ch - FNT1 + 1));
03741               break;
03742 
03743            case XXX1:
03744            case XXX2:
03745            case XXX3:
03746            case XXX4:
03747               a = xnum(fp, ch - XXX1 + 1);
03748               if (a > 0) {
03749                   char *str = read_special(fp, a);
03750 
03751                   /* is this a geom scan? */
03752                   if (info->geom_special != NULL) {
03753                      /* process the bounding box */
03754                      geom_do_special(info, str, current_dimconv);
03755                      /* process the specials we're looking for */
03756                      info->geom_special(info, str, a);
03757                   }
03758               }
03759               break;
03760 
03761            case FNTDEF1:
03762            case FNTDEF2:
03763            case FNTDEF3:
03764            case FNTDEF4:
03765               xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
03766               a = (long)xone(fp);
03767               xskip(fp, a + (long)xone(fp));
03768               break;
03769 
03770 #ifndef TEXXET
03771            case SREFL:
03772            case EREFL:
03773 #endif
03774            case PRE:
03775            case POST:
03776            case POSTPOST:
03777            case EOP:
03778            default:
03779               return;
03780 
03781            }  /* end switch */
03782        }      /* end else (ch not a SETCHAR or FNTNUM) */
03783     }  /* end for */
03784 }
03785 
03786 
03787 /*
03788  *     Main scanning routine.
03789  */
03790 
03791 void
03792 geom_scan(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
03793          FILE *fp, struct scan_info *info, int pageno)
03794 {
03795     volatile off_t pos_save = 0;
03796     struct drawinf currinf_save;
03797     ubyte maxchar_save;
03798 
03799 #if PS
03800     if (info->geom_special != NULL && scanned_page < current_page) {
03801        fprintf(stderr, "shouldn't happen: %d >= %d!\n", scanned_page, current_page);
03802        return;       /* should not happen */
03803     }
03804 #endif
03805 
03806     if (dvi_pointer_frame != NULL)
03807        pos_save = lseek(fileno(fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
03808 
03809     (void) lseek(fileno(fp), pageinfo_get_offset(pageno), SEEK_SET);
03810     
03811     currinf_save = currinf;
03812     maxchar_save = maxchar;
03813 
03814     memset((char *)&currinf.data, '\0', sizeof currinf.data);
03815     currinf.tn_table_len = TNTABLELEN;
03816     currinf.tn_table = tn_table;
03817     currinf.tn_head = tn_head;
03818     currinf.pos = currinf.end = dvi_buffer;
03819     currinf.virtual = NULL;
03820 
03821     if (!setjmp(info->done_env)) {
03822        geom_scan_part(char_proc, fp, info, geom_current_frame = &geom_frame0, dimconv);
03823     }
03824 
03825     maxchar = maxchar_save;
03826     currinf = currinf_save;
03827 
03828     if (dvi_pointer_frame != NULL) {
03829        (void)lseek(fileno(fp), pos_save, SEEK_SET);
03830        dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
03831     }
03832 }
03833 
03834 
03835 /*
03836  *     Routines for source special lookup
03837  */
03838 
03839 struct src_spec_data {
03840     long x, y;                            /* coordinates we're looking for */
03841     unsigned long distance;        /* best distance so far */
03842     Boolean recent_in_best;        /* most recent string == XXX->best */
03843     struct src_parsed_special best;       /* best special so far */
03844     struct src_parsed_special recent;     /* most recent special */
03845 };
03846 
03847 void
03848 src_parse(const char *str, int str_len, struct src_parsed_special *parsed)
03849 {
03850     const char *p = str;
03851 
03852     if (*p >= '0' && *p <= '9') {
03853        parsed->line = atoi(p);
03854        do {
03855            ++p;
03856            str_len--;
03857        }
03858        while (*p >= '0' && *p <= '9');
03859     }
03860 
03861     parsed->col = 0;
03862     if (*p == ':') {
03863        ++p;
03864        str_len--;
03865        parsed->col = atoi(p);
03866        while (*p >= '0' && *p <= '9') {
03867            ++p;
03868            str_len--;
03869        }
03870     }
03871 
03872     if (*p == ' ') {
03873        ++p;
03874        str_len--;
03875     }
03876 
03877     if (*p != '\0') {
03878        size_t len = str_len + 1;
03879 
03880        if (len > parsed->filename_len) {
03881            if (parsed->filename_len != 0)
03882               free(parsed->filename);
03883            parsed->filename_len = (len & -8) + 64; /* rounding? */
03884            parsed->filename = xmalloc(parsed->filename_len);
03885        }
03886        memcpy(parsed->filename, p, len);
03887     }
03888 }
03889 
03890 static void
03891 src_spec_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
03892 {
03893     struct geom_info *g_info = (struct geom_info *)info->data;
03894     struct src_spec_data *data = g_info->geom_data;
03895     unsigned long distance;
03896 
03897     distance = 0;
03898 
03899     if (data->x < ulx)
03900        distance += (ulx - data->x) * (ulx - data->x);
03901     else if (data->x > lrx)
03902        distance += (data->x - lrx) * (data->x - lrx);
03903 
03904     if (data->y < uly)
03905        distance += (uly - data->y) * (uly - data->y);
03906     else if (data->y > lry)
03907        distance += (data->y - lry) * (data->y - lry);
03908 
03909     if (distance < data->distance) {
03910        data->distance = distance;
03911 
03912        /* Copy it over */
03913        if (!data->recent_in_best) {
03914            data->best.line = data->recent.line;
03915            data->best.col = data->recent.col;
03916            if (data->recent.filename_len != 0) {
03917               if (data->best.filename_len < data->recent.filename_len) {
03918                   if (data->best.filename_len != 0)
03919                      free(data->best.filename);
03920                   data->best.filename_len = data->recent.filename_len;
03921                   data->best.filename = xmalloc(data->best.filename_len);
03922               }
03923               memcpy(data->best.filename, data->recent.filename,
03924                      data->recent.filename_len);
03925            }
03926 
03927            data->recent_in_best = True;
03928        }
03929 
03930        /* Quit early if we've found our glyph.  */
03931        if (distance == 0 && data->best.filename_len != 0) {
03932            longjmp(info->done_env, 1);
03933        }
03934     }
03935 }
03936 
03937 static void
03938 src_spec_special(struct scan_info *info, const char *str, int str_len)
03939 {
03940     struct geom_info *g_info = (struct geom_info *)info->data;
03941     struct src_spec_data *data = g_info->geom_data;
03942 
03943     if (memcmp(str, "src:", 4) != 0)
03944        return;
03945 
03946     src_parse(str + 4, str_len - 4, &data->recent);
03947 
03948     /*
03949      * If this is the first special on the page, we may already have
03950      * spotted the nearest box.
03951      */
03952 
03953     if (data->best.filename_len == 0) {
03954        data->best.line = data->recent.line;
03955        data->best.col = data->recent.col;
03956        if (data->recent.filename_len != 0) {
03957            if (data->best.filename_len < data->recent.filename_len) {
03958               if (data->best.filename_len != 0)
03959                   free(data->best.filename);
03960               data->best.filename_len = data->recent.filename_len;
03961               data->best.filename = xmalloc(data->best.filename_len);
03962            }
03963            memcpy(data->best.filename, data->recent.filename,
03964                  data->recent.filename_len);
03965 
03966            data->recent_in_best = True;
03967        }
03968 
03969        if (data->distance == 0) {
03970            longjmp(info->done_env, 1);
03971        }
03972     }
03973     else
03974        data->recent_in_best = False;
03975 }
03976 
03977 /*
03978  *     Routines for reverse searches on other pages.
03979  */
03980 
03981 static struct src_parsed_special found;
03982 /* static jmp_buf scan_env; */
03983 
03984 static Boolean
03985 scan_first_src_spcl(char *str, int str_len, void *data)
03986 {
03987     UNUSED(data);
03988     if (memcmp(str, "src:", 4) != 0)
03989        return False;
03990 
03991     src_parse(str + 4, str_len - 4, &found);
03992 
03993     return True;
03994 }
03995 
03996 static Boolean
03997 scan_last_src_spcl(char *str, int str_len, void *data)
03998 {
03999     UNUSED(data);
04000     if (memcmp(str, "src:", 4) != 0)
04001        return False;
04002 
04003     src_parse(str + 4, str_len - 4, &found);
04004 
04005     return True;
04006 }
04007 
04008 
04009 /* Replace (pseudo-)format arguments in NULL-terminated argv list as follows:
04010  * %f -> filename, %l -> linenumber, %c -> column number.
04011  * If %f or %l are not specified, they are appended as %f and +%l.
04012  * If colno == 0, no %c argument is provided.
04013  */
04014 static char **
04015 src_format_arguments(char **argv, const char *filename, int lineno, int colno)
04016 {
04017     size_t i;
04018     Boolean found_filename = False;
04019     Boolean found_lineno = False;
04020     /* index of argv elem that contained a deleted column number specifier */
04021     int colno_deleted = -1;
04022     
04023     for (i = 0; argv[i] != NULL; i++) {
04024        char *ptr, *curr = argv[i];
04025        while ((ptr = strchr(curr, '%')) != NULL) {
04026            char *p1;
04027            if ((p1 = strchr("flc", ptr[1])) != NULL) { /* we have a formatting char */
04028               char digit_arg[LENGTH_OF_INT];
04029               const char *new_elem = NULL;
04030               /* remember offsets and lengths */
04031               size_t l_init = ptr - argv[i];
04032               size_t l_rest = strlen(ptr + 2) + 1;
04033               size_t l_mid;
04034               
04035               if (*p1 == 'f') {
04036                   found_filename = True;
04037                   new_elem = filename;
04038               }
04039               else if (*p1 == 'l') {
04040                   found_lineno = True;
04041                   sprintf(digit_arg, "%d", lineno);
04042                   new_elem = digit_arg;
04043               }
04044               else if (*p1 == 'c') {
04045                   if (colno == 0) { /* if we have no column information, don't provide this argument */
04046                      memmove(ptr, ptr + 2, l_rest);
04047                      curr = ptr;
04048                      colno_deleted = i;
04049                      continue;
04050                   }
04051                   sprintf(digit_arg, "%d", colno);
04052                   new_elem = digit_arg;
04053               }
04054               
04055               l_mid = strlen(new_elem);
04056               
04057               argv[i] = xrealloc(argv[i], strlen(argv[i]) + l_mid + 1);
04058               curr = argv[i] + l_init; /* need to reinitialize it because of realloc */
04059               memmove(curr + l_mid, curr + 2, l_rest);
04060               memcpy(curr, new_elem, l_mid);
04061               curr += l_mid;
04062            }
04063            else if (ptr[1] == '%') { /* escaped %, skip both */
04064               curr = ptr + 2;
04065            }
04066            else {
04067               curr = ptr + 1;
04068            }
04069        }
04070     }
04071 
04072     /* append line number and file name arguments if they were not specified */
04073     if (!found_lineno) {
04074        i++;
04075        argv = xrealloc(argv, (i + 1) * sizeof *argv);
04076        argv[i - 1] = xmalloc(LENGTH_OF_INT + 2);
04077        sprintf(argv[i - 1], "+%d", lineno);
04078        argv[i] = NULL;
04079     }
04080     
04081     if (!found_filename) {
04082        i++;
04083        argv = xrealloc(argv, (i + 1) * sizeof *argv);
04084        argv[i - 1] = xstrdup(filename);
04085        argv[i] = NULL;
04086     }
04087 
04088     /* if we deleted %c, remove from argv if it's empty now */
04089     if (colno_deleted > -1 && strlen(argv[colno_deleted]) == 0) {
04090        for (i = colno_deleted; argv[i] != NULL; i++) {
04091            argv[i] = argv[i + 1];
04092            
04093        }
04094     }
04095     return argv;
04096 }
04097 
04098 
04099 static void
04100 src_spawn_editor(const struct src_parsed_special *parsed)
04101 {
04102     char *expanded_filename;
04103     char **argv;
04104     const char *p;
04105     char *q;
04106     int i;
04107 
04108     struct stat buf;
04109 
04110     /* first, determine the editor if necessary */
04111     if (resource.editor == NULL || *resource.editor == '\0') {
04112        p = getenv("XEDITOR");
04113        if (p != NULL)
04114            resource.editor = xstrdup(p);
04115        else {
04116 
04117            p = getenv("VISUAL");
04118            if (p == NULL) {
04119               p = getenv("EDITOR");
04120               if (p == NULL) {
04121                   popup_message(globals.widgets.top_level,
04122                               MSG_WARN,
04123                               /* help text */
04124                               "Use the \"-editor\" command-line opion, the X resource "
04125                               "\"xdvi.editor\" or one of the following environment variables "
04126                               "to select the editor for source specials: "
04127                               "\"XEDITOR\", \"VISUAL\" or \"EDITOR\".\n"
04128                               "See the xdvi man page for more information on source specials "
04129                               "and the editor options.",
04130                               /* message */
04131                               "No custom editor set - using vi as default.");
04132                   p = "vi";
04133               }
04134            }
04135            q = xmalloc(strlen(p) + 10);
04136            memcpy(q, "xterm -e ", 9);
04137            strcpy(q + 9, p);
04138            resource.editor = q;
04139        }
04140     }
04141 
04142     /* now try to open the file; find_file allocates space for expanded_filename */
04143     if ((expanded_filename = find_file(parsed->filename, &buf, kpse_tex_format)) == NULL) {
04144        popup_message(globals.widgets.top_level,
04145                     MSG_ERR, NULL,
04146                     "File \"%s\" not found, couldn't jump to special\n\"%s:%d\"\n",
04147                     parsed->filename, parsed->filename, parsed->line);
04148     }
04149     else {
04150        TRACE_SRC((stderr, "source file \"%s\" expanded to \"%s\"\n", parsed->filename, expanded_filename));
04151        if (buf.st_mtime > globals.dvi_file.time) {
04152            statusline_print(STATUS_FOREVER,
04153                           "Warning: TeX file is newer than dvi file - "
04154                           "source special information might be wrong.");
04155        }
04156 
04157        /* this allocates argv */
04158        argv = src_format_arguments(get_separated_list(resource.editor, " \t", True),
04159                                 expanded_filename, parsed->line, parsed->col);
04160        
04161        fork_process(argv[0], False, NULL, NULL, NULL, argv);
04162 
04163        free(expanded_filename);
04164        for (i = 0; argv[i] != NULL; i++)
04165            free(argv[i]);   
04166        free(argv);
04167     }
04168 }
04169 
04170 off_t
04171 save_file_status(FILE *fp, struct drawinf *currinf_save, ubyte *maxchar_save)
04172 {
04173     off_t pos_save = 0;
04174     if (dvi_pointer_frame != NULL)
04175        pos_save = lseek(fileno(fp), 0L, SEEK_CUR)
04176            - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
04177     
04178     *currinf_save = currinf;
04179     *maxchar_save = maxchar;
04180     return pos_save;
04181 }
04182 
04183 void
04184 restore_file_status(FILE *fp, struct drawinf currinf_save, ubyte maxchar_save, off_t pos_save)
04185 {
04186     maxchar = maxchar_save;
04187     currinf = currinf_save;
04188     
04189     if (dvi_pointer_frame != NULL) {
04190        (void)lseek(fileno(fp), pos_save, SEEK_SET);
04191        dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
04192     }
04193 }
04194 
04195 
04196 
04197 /*
04198  *     The main routine for source specials (reverse search).
04199  */
04200 void
04201 source_reverse_search(int x, int y, wide_bool call_editor)
04202 {
04203     struct scan_info info;
04204     struct geom_info g_info;
04205     struct src_spec_data data;
04206     struct src_parsed_special *foundp;
04207     
04208     info.geom_special = src_spec_special;
04209 
04210     g_info.geom_box = src_spec_box;
04211     g_info.geom_data = &data;
04212 
04213     info.data = &g_info;
04214     
04215     data.x = x;
04216     data.y = y;
04217     data.distance = 0xffffffff;
04218     data.recent_in_best = True;
04219     data.best.filename_len = data.recent.filename_len = 0;
04220     foundp = &data.best;
04221 
04222     geom_scan(geom_do_char, globals.dvi_file.bak_fp, &info, current_page);
04223 
04224     if (data.best.filename_len == 0) {
04225        /*
04226         * nothing found on current page;
04227         * scan next and previous pages with increasing offset
04228         */
04229        volatile int upper, lower;
04230        volatile off_t pos_save;
04231        struct drawinf currinf_save;
04232        ubyte maxchar_save;
04233 
04234        /* Save file position */
04235        pos_save = save_file_status(globals.dvi_file.bak_fp, &currinf_save, &maxchar_save);
04236        
04237        upper = lower = current_page;
04238        found.filename_len = 0;     /* mark it as empty */
04239        for (;;) {
04240            if (++upper < total_pages) {
04241               (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(upper), SEEK_SET);
04242               memset((char *)&currinf.data, '\0', sizeof currinf.data);
04243               currinf.tn_table_len = TNTABLELEN;
04244               currinf.tn_table = tn_table;
04245               currinf.tn_head = tn_head;
04246               currinf.pos = currinf.end = dvi_buffer;
04247               currinf.virtual = NULL;
04248 
04249               if (spcl_scan(scan_first_src_spcl, NULL, True, globals.dvi_file.bak_fp)) {
04250                   lower = upper;
04251                   break;
04252               }
04253            }
04254            else if (lower < 0)
04255               break;
04256 
04257            if (--lower >= 0) {
04258               (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(lower), SEEK_SET);
04259 
04260               memset((char *)&currinf.data, '\0', sizeof currinf.data);
04261               currinf.tn_table_len = TNTABLELEN;
04262               currinf.tn_table = tn_table;
04263               currinf.tn_head = tn_head;
04264               currinf.pos = currinf.end = dvi_buffer;
04265               currinf.virtual = NULL;
04266 
04267               (void)spcl_scan(scan_last_src_spcl, NULL, False, globals.dvi_file.bak_fp);
04268               if (found.filename_len != 0)
04269                   break;
04270            }
04271        }
04272 
04273        if (found.filename_len != 0)
04274            statusline_print(STATUS_MEDIUM,
04275                           "No source specials on this page - nearest on page %d",
04276                           lower + globals.pageno_correct);
04277        else {
04278            /* nothing found at all; complain */
04279            XBell(DISP, 0);
04280            popup_message(globals.widgets.top_level,
04281                        MSG_ERR,
04282                        /* helptext */
04283                        reverse_search_helptext,
04284                        /* popup */
04285                        "No source specials in this DVI file - couldn't do reverse search.");
04286        }
04287 
04288        /* Restore file status.  */
04289        restore_file_status(globals.dvi_file.bak_fp, currinf_save, maxchar_save, pos_save);
04290 
04291        foundp = &found;
04292     }
04293 
04294     if (data.recent.filename_len != 0)
04295        free(data.recent.filename);
04296 
04297     if (foundp->filename_len != 0) {
04298        if (call_editor) {
04299            src_spawn_editor(foundp);
04300        }
04301        else {
04302            statusline_print(STATUS_MEDIUM, "nearest special at (%d,%d): \"%s:%d\"",
04303                           x / currwin.shrinkfactor, y / currwin.shrinkfactor, foundp->filename, foundp->line);
04304        }
04305        free(foundp->filename);
04306     }
04307 }
04308 
04309 
04310 /*
04311  *     Debug routines for source special display (highlight the first box
04312  *     after each source special, or highlight each box).
04313  */
04314 
04315 struct src_spec_show_data {
04316     Boolean do_this_one;    /* flag set after source special */
04317     Boolean do_them_all;    /* flag to reset the above to */
04318 };
04319 
04320 static void
04321 src_spec_show_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
04322 {
04323     struct geom_info *g_info = (struct geom_info *)info->data;
04324     struct src_spec_show_data *data = g_info->geom_data;
04325 
04326     if (data->do_this_one) {
04327        long x = ulx / mane.shrinkfactor;
04328        long y = uly / mane.shrinkfactor;
04329 
04330        XDrawRectangle(DISP, mane.win, globals.gc.high,
04331                      x - mane_base_x, y - mane_base_y,
04332                      lrx / mane.shrinkfactor - x,
04333                      lry / mane.shrinkfactor - y);
04334        data->do_this_one = data->do_them_all;
04335     }
04336 }
04337 
04338 static void
04339 src_spec_show_special(struct scan_info *info, const char *str, int str_len)
04340 {
04341     /*     if (memcmp(str, "src:", 4) != 0) */
04342     /*        return; */
04343     struct geom_info *g_info = (struct geom_info *)info->data;
04344     UNUSED(str_len);
04345     XDVI_INFO((stdout, "special: %s", str));
04346     ((struct src_spec_show_data *)g_info->geom_data)->do_this_one = True;
04347 }
04348 
04349 void
04350 source_special_show(wide_bool do_them_all)
04351 {
04352     struct scan_info info;
04353     struct geom_info g_info;
04354     struct src_spec_show_data src_data;
04355 
04356     info.geom_special = src_spec_show_special;
04357 
04358     g_info.geom_box = src_spec_show_box;
04359     g_info.geom_data = &src_data;
04360 
04361     info.data = &g_info;
04362     
04363     src_data.do_this_one = src_data.do_them_all = do_them_all;
04364 
04365     geom_scan(geom_do_char, globals.dvi_file.bak_fp, &info, current_page);
04366 }
04367 
04368 
04369 /*
04370  *     Routines for forward search (look up a source line).
04371  *
04372  *     The general procedure is:
04373  *        (1) Use spcl_scan() to find the page containing the line (or at
04374  *            least the closest line).  This could be optimized further.
04375  *        (2) Use geom_scan_part() to find the exact location of the source
04376  *            special, and the box to highlight.
04377  */
04378 
04379 /* These variables are referenced by src_scan_special().  */
04380 
04381 static int src_this_line;
04382 static Boolean src_this_file_equal;
04383 static int src_line;
04384 static int src_col;
04385 static const char *src_file;
04386 static int src_page;
04387 /* static jmp_buf src_env; */
04388 static Boolean found_src;
04389 static unsigned long best_distance;
04390 static unsigned long best_col_dist;
04391 static int best_line;
04392 static int best_page;
04393 static off_t best_offset;
04394 static off_t max_offset;
04395 
04396 /* Some of the above, plus these below, are used by geom_scan_part().  */
04397 
04398 static Boolean src_fwd_active;
04399 
04400 #define BBOX_INFO_MAXIDX 8 /* maximum number of bounding boxes */
04401 
04402 /* list of bounding boxes */
04403 struct bbox_info {
04404     long min_x, max_x, min_y, max_y;
04405     long spcl_min_x, spcl_max_x, spcl_min_y, spcl_max_y;
04406 } g_bbox_info[BBOX_INFO_MAXIDX];
04407 
04408 /* current index in g_bbox_info[] */
04409 static size_t bbox_info_idx = 0;
04410 
04411 static Boolean
04412 src_scan_special(char *str, int str_len, void *data)
04413 {
04414     char *p;
04415     int col = 0;
04416     unsigned long distance;
04417     unsigned long col_dist;
04418     
04419     UNUSED(data);
04420     if (memcmp(str, "src:", 4) != 0)
04421        return False;
04422 
04423     found_src = True;
04424 
04425     p = str + 4;
04426     str_len -= 4;
04427     
04428     if (*p >= '0' && *p <= '9') {
04429        src_this_line = atoi(p);
04430        do {
04431            ++p;
04432            str_len--;
04433        }
04434        while (*p >= '0' && *p <= '9');
04435     }
04436 
04437     if (*p == ':') {
04438        ++p;
04439        str_len--;
04440        col = atoi(p);
04441        while (*p >= '0' && *p <= '9') {
04442            ++p;
04443            str_len--;
04444        }
04445     }
04446 
04447     if (*p == ' ') {
04448        ++p;
04449        str_len--;
04450     }
04451 
04452     /* src specials might omit the file name when it had already
04453        been specified on the page; so skip the test when the
04454        special ends right here:
04455     */
04456     if (*p != '\0') {
04457        ASSERT(globals.dvi_file.dirname != NULL, "DVI name should be set here");
04458        src_this_file_equal = src_compare(p, str_len, src_file, globals.dvi_file.dirname, globals.dvi_file.dirlen);
04459     }
04460     
04461     if (!src_this_file_equal)
04462        return False;
04463     
04464     distance = (src_line > src_this_line
04465               ? src_line - src_this_line
04466               : 2 * (src_this_line - src_line)); /* favor earlier lines */
04467 
04468     if (distance < best_distance) {       /* found a better line */
04469        best_distance = distance;
04470        best_line = src_this_line;
04471        best_page = src_page;
04472        max_offset = best_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
04473     }
04474     else if (distance == best_distance) { /* still on a good line, remember diff */
04475        max_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
04476     }
04477 
04478     if (distance == 0 && best_distance == 0) {   /* found a better col */
04479        col_dist = (src_col > col ? src_col - col : 2 * (col - src_col));
04480 
04481        if (col_dist < best_col_dist) {
04482            best_col_dist = col_dist;
04483            best_page = src_page;
04484            max_offset = best_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
04485        }
04486        else if (col_dist == best_col_dist) {
04487            max_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
04488        }
04489     }
04490     return True;
04491 }
04492 
04493 static Boolean
04494 htex_scan_special(char *str, int str_len, void *data)
04495 {
04496     UNUSED(data);
04497 
04498     if (g_anchor_pos == NULL)
04499        return False;
04500     
04501     /* first, hypertex specials */
04502     if (memicmp(str, "html:", strlen("html:")) == 0) {
04503        size_t offset = strlen("html:");
04504        str += offset;
04505        str_len -= offset;
04506        
04507        while (*str == ' ' || *str == '\t') {
04508            str++;
04509            str_len--;
04510        }
04511 
04512        if (memicmp(str, "<a name", strlen("<a name")) != 0)
04513            return False;
04514 
04515        offset = strlen("<a name");
04516        str += offset;
04517        str_len -= offset;
04518        str_len--; /* for the closing > */
04519        
04520        /* skip over spaces, = and open quotes */
04521        while (*str == ' ' || *str == '=') {
04522            str++;
04523            str_len--;
04524        }
04525        if (*str == '"') {
04526            str++;
04527            str_len -= 2; /* don't compare closing quote */
04528        }
04529 
04530        /* fprintf(stderr, "comparing: |%s|%s|%d\n", str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)); */
04531        if (memcmp(str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)) == 0)
04532            return True;
04533        else
04534            return False;
04535     }
04536     /* then, hdvips specials */
04537     else if (memicmp(str, "ps:", 3) == 0 && g_anchor_pos != NULL) {
04538        str += 3;
04539        if (memicmp(str, "sdict begin ", strlen("sdict begin ")) == 0) {
04540            char *ptr = NULL, *pptr = NULL;
04541            str += strlen("sdict begin ");
04542            if ((ptr = strstr(str, "/View")) != NULL
04543               && (ptr = strchr(ptr, '(')) != NULL
04544               && (pptr = strchr(ptr + 1, ')')) != NULL) {
04545               if (memcmp(ptr + 1, g_anchor_pos, pptr - ptr - 1) == 0
04546                   && g_anchor_pos[pptr - ptr - 1] == '\0') {
04547                   return True;
04548               }
04549            }
04550        }
04551        return False;
04552     }
04553     else {
04554        return False;
04555     }
04556 }
04557 
04558 static void
04559 htex_scan_special_noreturn(struct scan_info *info, const char *str, int str_len)
04560 {
04561     struct geom_info *g_info = (struct geom_info *)info->data;
04562 
04563     /* first, hypertex specials */
04564     if (memcmp(str, "html:", strlen("html:")) == 0) {
04565        size_t offset = strlen("html:");
04566        str += offset;
04567        str_len -= offset;
04568 
04569        while (*str == ' ' || *str == '\t') {
04570            str++;
04571            str_len--;
04572        }
04573        
04574        if (memicmp(str, "<a name", strlen("<a name")) != 0)
04575            return;
04576        
04577        offset = strlen("<a name");
04578        str += offset;
04579        str_len -= offset;
04580        str_len--; /* for the closing > */
04581        
04582        /* skip over spaces, = and open quotes */
04583        while (*str == ' ' || *str == '=') {
04584            str++;
04585            str_len--;
04586        }
04587        if (*str == '"') {
04588            str++;
04589            str_len -= 2; /* don't compare closing quote */
04590        }
04591 
04592        if (g_anchor_pos != NULL
04593            && memcmp(str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)) == 0) {
04594            *((int *)g_info->geom_data) = pixel_conv(DVI_V);
04595            longjmp(info->done_env, 1);
04596        }
04597     }
04598     /* then, hdvips specials */
04599     else if (memicmp(str, "ps:", 3) == 0 && g_anchor_pos != NULL) {
04600        str += 3;
04601        if (memicmp(str, "sdict begin ", strlen("sdict begin ")) == 0) {
04602            char *ptr = NULL, *pptr = NULL;
04603            str += strlen("sdict begin ");
04604            if ((ptr = strstr(str, "/View")) != NULL
04605               && (ptr = strchr(ptr, '(')) != NULL
04606               && (pptr = strchr(ptr + 1, ')')) != NULL) {
04607               if (memcmp(ptr + 1, g_anchor_pos, pptr - ptr - 1) == 0
04608                   && g_anchor_pos[pptr - ptr - 1] == '\0') {
04609                   *((int *)g_info->geom_data) = pixel_conv(DVI_V);
04610                   longjmp(info->done_env, 1);
04611               }
04612            }
04613        }
04614     }
04615 }
04616 
04617 static void
04618 src_spec_fwd_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
04619 {
04620     /* Heuristic value to detect column breaks: A negative vertical
04621        offset to the next glyph larger than BBOX_OFF will create a new
04622        bounding box. The amount is in unshrunken pixels, i.e. 120
04623        \approx 1 Line of 12pt Text. */
04624     static const int BBOX_OFF = 360;
04625     
04626     UNUSED(info);
04627     if (src_fwd_active) {
04628        /* probably a column break, create new box */
04629        if (lry < g_bbox_info[bbox_info_idx].max_y - BBOX_OFF
04630            && lrx > g_bbox_info[bbox_info_idx].max_x + 50) {
04631            if (bbox_info_idx < BBOX_INFO_MAXIDX - 1) {
04632               bbox_info_idx++;
04633 
04634               g_bbox_info[bbox_info_idx].min_y = g_bbox_info[bbox_info_idx].min_x = LONG_MAX;
04635               g_bbox_info[bbox_info_idx].max_x = g_bbox_info[bbox_info_idx].max_y = 0;
04636            }
04637        }
04638        if (ulx < g_bbox_info[bbox_info_idx].min_x) {
04639            g_bbox_info[bbox_info_idx].min_x = ulx;
04640        }
04641        if (uly < g_bbox_info[bbox_info_idx].min_y) {
04642            g_bbox_info[bbox_info_idx].min_y = uly;
04643        }
04644        if (lrx > g_bbox_info[bbox_info_idx].max_x)
04645            g_bbox_info[bbox_info_idx].max_x = lrx;
04646        if (lry > g_bbox_info[bbox_info_idx].max_y) {
04647            g_bbox_info[bbox_info_idx].max_y = lry;
04648        }
04649     }
04650 }
04651 
04652 /* dummy procedure for hyperlinks; we don't need geometry info for these. */
04653 static void
04654 htex_dummy_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
04655 {
04656     UNUSED(info);
04657     UNUSED(ulx);
04658     UNUSED(uly);
04659     UNUSED(lrx);
04660     UNUSED(lry);
04661     return;
04662 }
04663 
04664 static void
04665 src_spec_fwd_special(struct scan_info *info, const char *str, int str_len)
04666 {
04667     long pos;
04668     UNUSED(str_len);
04669     
04670     if (memcmp(str, "src:", 4) != 0)      /* if no source special */
04671        return;
04672 
04673     pos = xtell(globals.dvi_file.bak_fp, currinf.pos);
04674     if (pos >= best_offset)
04675        src_fwd_active = True;
04676 
04677     if (src_fwd_active) {
04678        if (pos > max_offset)
04679            longjmp(info->done_env, 1);
04680        
04681        if (G_PXL_H < g_bbox_info[bbox_info_idx].spcl_min_x)
04682            g_bbox_info[bbox_info_idx].spcl_min_x = G_PXL_H;
04683        if (G_PXL_H > g_bbox_info[bbox_info_idx].spcl_max_x)
04684            g_bbox_info[bbox_info_idx].spcl_max_x = G_PXL_H;
04685        if (PXL_V < g_bbox_info[bbox_info_idx].spcl_min_y)
04686            g_bbox_info[bbox_info_idx].spcl_min_y = PXL_V;
04687        if (PXL_V > g_bbox_info[bbox_info_idx].spcl_max_y)
04688            g_bbox_info[bbox_info_idx].spcl_max_y = PXL_V;
04689 
04690     }
04691 }
04692 
04693 /*
04694  *     Routine to actually draw the box.
04695  */
04696 
04697 static void
04698 source_fwd_draw_box(void)
04699 {
04700     if (globals.src.fwd_box_page != current_page) {
04701        globals.src.fwd_box_page = -1;     /* different page---clear it */
04702     }
04703     else {
04704        size_t i;
04705        static const int padding = 15;
04706 
04707        /* fix oversplitting by heuristics, by merging box n with box n+1 if they overlap */
04708        for (i = 0; i < bbox_info_idx; i++) {
04709            if (g_bbox_info[i].min_x == LONG_MAX)
04710               continue;
04711            if ((g_bbox_info[i+1].min_x < g_bbox_info[i].max_x
04712                && g_bbox_info[i+1].min_y < g_bbox_info[i].max_y) ||
04713               (g_bbox_info[i].min_x < g_bbox_info[i+1].max_x
04714                && g_bbox_info[i].min_y < g_bbox_info[i+1].max_y)) { /* overlap */          
04715               g_bbox_info[i].min_x = MIN(g_bbox_info[i].min_x, g_bbox_info[i+1].min_x);
04716               g_bbox_info[i].min_y = MIN(g_bbox_info[i].min_y, g_bbox_info[i+1].min_y);
04717               g_bbox_info[i].max_x = MAX(g_bbox_info[i].max_x, g_bbox_info[i+1].max_x);
04718               g_bbox_info[i].max_y = MAX(g_bbox_info[i].max_y, g_bbox_info[i+1].max_y);
04719               bbox_info_idx--;
04720            }
04721        }
04722        
04723        for (i = 0; i <= bbox_info_idx; i++) {
04724            int min_x, min_y, max_x, max_y;
04725            
04726            XPoint ul, ur, ll, lr;
04727            
04728            if (g_bbox_info[i].min_x == LONG_MAX) {
04729               /* If no glyphs or rules, use hot point of special instead.  */
04730               g_bbox_info[i].min_x = g_bbox_info[i].spcl_min_x;
04731               g_bbox_info[i].min_y = g_bbox_info[i].spcl_min_y;
04732               g_bbox_info[i].max_x = g_bbox_info[i].spcl_max_x;
04733               g_bbox_info[i].max_y = g_bbox_info[i].spcl_max_y;
04734            }
04735 
04736            min_x = (g_bbox_info[i].min_x - padding) / mane.shrinkfactor - mane_base_x;
04737            min_y = (g_bbox_info[i].min_y - padding) / mane.shrinkfactor - mane_base_y;
04738            max_x = (g_bbox_info[i].max_x + padding) / mane.shrinkfactor - mane_base_x;
04739            max_y = (g_bbox_info[i].max_y + padding) / mane.shrinkfactor - mane_base_y;
04740 
04741            ul.x = min_x;
04742            ul.y = min_y;
04743 
04744            ur.x = max_x;
04745            ur.y = min_y;
04746 
04747            ll.x = min_x;
04748            ll.y = max_y;
04749 
04750            lr.x = max_x;
04751            lr.y = max_y;
04752            
04753            if (i == 0 && bbox_info_idx == 0) { /* only 1 bounding box */
04754               XDrawRectangle(DISP, mane.win, globals.gc.high,
04755                             min_x, min_y, max_x - min_x, max_y - min_y);
04756            }
04757            else if (i == 0) { /* draw first bbox with open bottom */
04758               XPoint points[4];
04759               points[0] = ll;
04760               points[1] = ul;
04761               points[2] = ur;
04762               points[3] = lr;
04763               XDrawLines(DISP, mane.win, globals.gc.high, points, 4, CoordModeOrigin);
04764            }
04765            else if (i > 0 && i < bbox_info_idx) { /* draw middle box with open top and open bottom */
04766               XPoint points[2];
04767               points[0] = ul;
04768               points[1] = ll;
04769               XDrawLines(DISP, mane.win, globals.gc.high, points, 2, CoordModeOrigin);
04770               points[0] = ur;
04771               points[1] = lr;
04772               XDrawLines(DISP, mane.win, globals.gc.high, points, 2, CoordModeOrigin);
04773            }
04774            else { /* draw last box with open top */
04775               XPoint points[4];
04776               points[0] = ul;
04777               points[1] = ll;
04778               points[2] = lr;
04779               points[3] = ur;
04780               XDrawLines(DISP, mane.win, globals.gc.high, points, 4, CoordModeOrigin);
04781            }
04782        }
04783     }
04784 }
04785 
04786 #if 0
04787 #include<asm/msr.h>
04788 unsigned long time_start=0, time_end=0;
04789 #endif
04790 
04791 void
04792 source_forward_search(const char *str)
04793 {
04794     volatile off_t pos_save = 0;
04795     struct drawinf currinf_save;
04796     ubyte maxchar_save;
04797     struct scan_info info;
04798     struct geom_info g_info;
04799     
04800     TRACE_CLIENT((stderr, "Entering source_forward_search(%s)", str));
04801 
04802     max_offset = 0;
04803     src_file = str;
04804     while (*src_file == '0')
04805        ++src_file;
04806     if (*src_file < '1' || *src_file > '9') {
04807        XDVI_WARNING((stderr, "Ignoring malformed source special \"%s\"", str));
04808        return;
04809     }
04810     src_line = atoi(src_file);
04811     while (*src_file >= '0' && *src_file <= '9')
04812        ++src_file;
04813 
04814     src_col = 0;
04815     if (*src_file == ':') {
04816        ++src_file;
04817        src_col = atoi(src_file);
04818        while (*src_file >= '0' && *src_file <= '9')
04819            ++src_file;
04820     }
04821 
04822     if (*src_file == ' ')
04823        ++src_file;
04824 
04825     TRACE_CLIENT((stderr, "File = \"%s\", line = %d, col = %d", src_file, src_line, src_col));
04826 
04827     /* Save status of dvi_file reading (in case we hit an error and resume
04828        drawing).  */
04829 
04830     if (dvi_pointer_frame != NULL)
04831        pos_save = lseek(fileno(globals.dvi_file.bak_fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
04832     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(0), SEEK_SET);
04833 
04834     currinf_save = currinf;
04835     maxchar_save = maxchar;
04836 
04837     memset((char *)&currinf.data, '\0', sizeof currinf.data);
04838     currinf.tn_table_len = TNTABLELEN;
04839     currinf.tn_table = tn_table;
04840     currinf.tn_head = tn_head;
04841     currinf.pos = currinf.end = dvi_buffer;
04842     currinf.virtual = NULL;
04843 
04844     /* Start search over pages */
04845 #if 0
04846     rdtscl(time_start);
04847 #endif
04848 
04849     found_src = False;
04850     best_distance = best_col_dist = ULONG_MAX;
04851     src_this_line = 0;      /* initialize things that are kept as defaults */
04852     src_this_file_equal = False;
04853 
04854     /* These two lines do the actual scanning (first pass).  */
04855     for (src_page = 0; src_page < total_pages; ++src_page)
04856        (void)spcl_scan(src_scan_special, NULL, False, globals.dvi_file.bak_fp);
04857 
04858     if (best_distance == ULONG_MAX) {
04859        if (!found_src) {
04860            popup_message(globals.widgets.top_level,
04861                        MSG_WARN,
04862                        /* helptext */
04863                        reverse_search_helptext,
04864                        /* popup */
04865                        "No source specials in this DVI file - couldn't do reverse search.");
04866        }
04867        else {
04868            popup_message(globals.widgets.top_level,
04869                        MSG_WARN,
04870                        /* helptext */
04871                        "To enable reverse search, the TeX file has to be compiled with source specials. "
04872                        "See the xdvi man page (section SOURCE SPECIALS) for details.",
04873                        /* popup */
04874                        "No references to source file \"%s\" in DVI file.",
04875                        src_file);
04876        }
04877 
04878        /* Restore file position.  */
04879        maxchar = maxchar_save;
04880        currinf = currinf_save;
04881 
04882        if (dvi_pointer_frame != NULL) {
04883            (void)lseek(fileno(globals.dvi_file.bak_fp), pos_save, SEEK_SET);
04884            dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
04885        }
04886 
04887        return;
04888     }
04889     TRACE_CLIENT((stderr, "Match:  line %d on page %d, offset %lu",
04890                 best_line, best_page + globals.pageno_correct, (unsigned long)best_offset));
04891 
04892     /*
04893      * In this case we don't need to restore maxchar and currinf, since
04894      * we won't resume drawing -- we'll jump to a new page instead.
04895      */
04896 
04897     /* Move to that page.  */
04898     goto_page(best_page, resource.keep_flag ? NULL : home, False);
04899     page_history_insert(best_page);
04900     globals.ev.flags |= EV_NEWPAGE; /* so that existing mark gets erased */
04901     /* Now search that particular page.  */
04902 
04903     info.geom_special = src_spec_fwd_special;
04904 
04905     g_info.geom_box = src_spec_fwd_box;
04906     g_info.geom_data = NULL;
04907 
04908     src_fwd_active = False;
04909     bbox_info_idx = 0;
04910 
04911     g_bbox_info[bbox_info_idx].min_x =
04912        g_bbox_info[bbox_info_idx].min_y =
04913        g_bbox_info[bbox_info_idx].spcl_min_x =
04914        g_bbox_info[bbox_info_idx].spcl_min_y = LONG_MAX;
04915     g_bbox_info[bbox_info_idx].max_x =
04916        g_bbox_info[bbox_info_idx].max_y =
04917        g_bbox_info[bbox_info_idx].spcl_max_x =
04918        g_bbox_info[bbox_info_idx].spcl_max_y = 0;
04919     globals.src.fwd_box_page = -1; /* in case of error, suppress box */
04920 
04921     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(best_page), SEEK_SET);
04922     currinf.tn_table_len = TNTABLELEN;
04923     currinf.tn_table = tn_table;
04924     currinf.tn_head = tn_head;
04925     currinf.pos = currinf.end = dvi_buffer;
04926     currinf.virtual = NULL;
04927 
04928     info.data = &g_info;
04929     
04930     if (!setjmp(info.done_env))
04931        geom_scan_part(geom_do_char, globals.dvi_file.bak_fp, &info, geom_current_frame = &geom_frame0, dimconv);
04932 
04933     if (!src_fwd_active) {
04934        XDVI_ERROR((stderr, "%s:%d: shouldn't happen: geom_scan_part() failed to re-find the special.", __FILE__, __LINE__));
04935     }
04936     else {
04937        long x_min = g_bbox_info[bbox_info_idx].min_x;
04938        long y_min = g_bbox_info[bbox_info_idx].min_y;
04939        long x_max = g_bbox_info[bbox_info_idx].max_x;
04940        long y_max = g_bbox_info[bbox_info_idx].max_y;
04941        do_autoscroll = True;
04942        globals.src.fwd_box_page = current_page;
04943        if (x_min == LONG_MAX || x_max == LONG_MAX) {
04944            /* If no glyphs or rules, use hot point of special instead.  */
04945            x_min = g_bbox_info[bbox_info_idx].spcl_min_x;
04946            y_min = g_bbox_info[bbox_info_idx].spcl_min_y;
04947            x_max = g_bbox_info[bbox_info_idx].spcl_max_x;
04948            y_max = g_bbox_info[bbox_info_idx].spcl_max_y;
04949        }
04950        scroll_page_if_needed((int)(x_min / currwin.shrinkfactor) + 2, (int)(x_max / currwin.shrinkfactor) - 2,
04951                            (int)(y_min / currwin.shrinkfactor) + 10, (int)(y_max / currwin.shrinkfactor) - 10);
04952     }
04953 #if 0
04954     rdtscl(time_end);
04955     printf("time search: %lu\n", time_end - time_start);
04956 #endif
04957 }
04958 
04959 
04960 void
04961 anchor_search(const char *str)
04962 {
04963     off_t pos_save = 0;
04964     struct drawinf currinf_save;
04965     ubyte maxchar_save;
04966     volatile int test_page = 0;
04967     Boolean found_anchor = False;
04968     int y_pos = -1;
04969     struct scan_info info;
04970     struct geom_info g_info;
04971 
04972     ASSERT(str != NULL, "Argument to anchor_search() musn't be NULL");
04973     TRACE_HTEX((stderr, "Entering anchor_search(%s)", str));
04974 
04975     /* Save status of dvi_file reading (in case we hit an error and resume drawing).  */
04976     if (dvi_pointer_frame != NULL)
04977        pos_save = lseek(fileno(globals.dvi_file.bak_fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
04978     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(0), SEEK_SET);
04979 
04980     currinf_save = currinf;
04981     maxchar_save = maxchar;
04982 
04983     memset((char *)&currinf.data, '\0', sizeof currinf.data);
04984     currinf.tn_table_len = TNTABLELEN;
04985     currinf.tn_table = tn_table;
04986     currinf.tn_head = tn_head;
04987     currinf.pos = currinf.end = dvi_buffer;
04988     currinf.virtual = NULL;
04989 
04990     /* Start search over pages */
04991     for (test_page = 0; test_page < total_pages; test_page++) {
04992        if (spcl_scan(htex_scan_special, NULL, True, globals.dvi_file.bak_fp)) {
04993            found_anchor = True;
04994            break;
04995        }
04996     }
04997 
04998     if (!found_anchor) {
04999        /* Restore file position.  */
05000        maxchar = maxchar_save;
05001        currinf = currinf_save;
05002        
05003        if (dvi_pointer_frame != NULL) {
05004            (void)lseek(fileno(globals.dvi_file.bak_fp), pos_save, SEEK_SET);
05005            dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
05006        }
05007        XBell(DISP, 0);
05008        statusline_print(STATUS_MEDIUM, "Error: Anchor \"%s\" not found.", str);
05009        return;
05010     }
05011 
05012     /*
05013      * In this case we don't need to restore maxchar and currinf, since
05014      * we won't resume drawing -- we'll jump to a new page instead.
05015      */
05016 
05017     /* Move to that page.  */
05018     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(test_page), SEEK_SET);
05019     currinf.tn_table_len = TNTABLELEN;
05020     currinf.tn_table = tn_table;
05021     currinf.tn_head = tn_head;
05022     currinf.pos = currinf.end = dvi_buffer;
05023     currinf.virtual = NULL;
05024 
05025     info.geom_special = htex_scan_special_noreturn;
05026 
05027     g_info.geom_box = htex_dummy_box;
05028     g_info.geom_data = &y_pos;
05029 
05030     info.data = &g_info;
05031     
05032     if (!setjmp(info.done_env))
05033        geom_scan_part(geom_do_char, globals.dvi_file.bak_fp, &info, geom_current_frame = &geom_frame0, dimconv);
05034 
05035     if (y_pos == -1) { /* not found */
05036        XDVI_ERROR((stderr, "%s:%d: shouldn't happen: geom_scan_part() failed to re-find the link.", __FILE__, __LINE__));
05037     }
05038     else {
05039        goto_page(test_page, resource.keep_flag ? NULL : home, False);
05040        page_history_insert(test_page);
05041        do_autoscroll = True;
05042        htex_set_anchormarker(y_pos);
05043     }
05044     /* reset info */
05045     free(g_anchor_pos);
05046     g_anchor_pos = NULL;
05047     g_anchor_len = 0;
05048 }
05049 
05050 
05051 
05052 #ifdef T1LIB
05053 
05054 /* ********************** FONT AND ENCODING LOADING ******************** */
05055 
05056 static char **
05057 load_vector(const char *enc)
05058 {
05059     char *filename;
05060 
05061     TRACE_T1((stderr, "loading vector: |%s|", enc));
05062     /*
05063      * With TDS 1.0/kpathsea 3.5.2(?), encoding files are in texmf/fonts/enc and accessed
05064      * via kpse_enc_format; see e.g.:
05065      * http://tug.org/mailman/htdig/tex-live/2004-January/004734.html
05066      *
05067      * The lookups under kpse_program_text_format and kpse_tex_ps_header_format
05068      * are kept for backwards compatibility.
05069      */
05070     do {
05071        filename = kpse_find_file(enc, kpse_enc_format, 0);
05072        if (filename != NULL)
05073            break;
05074        filename = kpse_find_file(enc, kpse_program_text_format, 0);
05075        if (filename != NULL)
05076            break;
05077        /* If that fails we try the standard place: postscript headers */
05078        filename = kpse_find_file(enc, kpse_tex_ps_header_format, 1);
05079     } while (0);
05080     
05081     if (filename != NULL) {
05082        return T1_LoadEncoding(filename);
05083     }
05084     return NULL;
05085 }
05086 
05087 
05088 
05089 static int
05090 add_tfm(const char *texname)
05091 {
05092     /* Load font metrics if not already loaded.  Return index into
05093        fontmetrics array. If it fails, fallback metrics must be
05094        loaded instead; if that fails as well, exit. */
05095 
05096     size_t i;
05097     int idx;
05098     static size_t wlidx = 0;
05099     static size_t wlidx_max = 0;
05100     static const size_t wlidx_step = 1024;
05101 
05102 #ifdef USE_HASH
05103     if (tfminfo_hash.size == 0)
05104        tfminfo_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
05105 
05106     if (find_str_int_hash(&tfminfo_hash, texname, &i)) {
05107        return i;
05108     }
05109 #else
05110     for (i = 0; i <= wlidx; i++)
05111        if (strcmp(tfminfo[i].texname, texname) == 0)
05112            return i;
05113 #endif /* USE_HASH */
05114     
05115     while (wlidx >= wlidx_max) {
05116        wlidx_max += wlidx_step;
05117        tfminfo = xrealloc(tfminfo, wlidx_max * sizeof *tfminfo);
05118     }
05119 
05120     tfminfo[wlidx].texname = texname;
05121 #ifdef USE_HASH
05122     put_str_int_hash(&tfminfo_hash, tfminfo[wlidx].texname, wlidx);
05123 #endif /* USE_HASH */
05124     
05125     if (!tfmload(texname, &tfminfo[wlidx].designsize, tfminfo[wlidx].widths,
05126                &(tfminfo[wlidx].fontdimen2))) {
05127        XDVI_FATAL((stderr, "Cannot find font metrics file %s.tfm, "
05128                   "and fallback metrics cmr10.tfm is missing as well - exiting.\n",
05129                   texname));
05130     }
05131 
05132     idx = wlidx++;
05133 
05134     if (fallbacktfm == 1) {
05135        fallbacktfm = 2;
05136        popup_message(globals.widgets.top_level,
05137                     MSG_ERR,
05138                     /* helptext */
05139                     "A font metrics file is missing and cmr10.tfm is used instead.  Either "
05140                     "you don't have the file, or your TeX system cannot find it.  Try to "
05141                     "invoke \"kpsewhich\" with the filename mentioned in the error "
05142                     "message and the \"-debug 2\" option to find out where Xdvik is "
05143                     "searching for your files.\n"
05144                     "To enable automatic creation of .tfm files for "
05145                     "Metafont fonts, "
05146                     /* FIXME: how about Type1 fonts?? */
05147                     "set the environment variable MKTEXTFM "
05148                     "to 1 and re-start xdvi. See the file texmf.cnf for the default settings "
05149                     "of MKTEXTFM and related variables.",
05150                     /* message */
05151                     "Could not find font metrics file %s.tfm; using cmr10.tfm instead. "
05152                     "Expect ugly output.",
05153                     texname);
05154     }
05155 
05156     return idx;
05157 }
05158 
05159 static int
05160 add_t1font(const char *fontname, const char *filename)
05161 {
05162     /* Add t1 font to list if it's not already there; return the
05163        (newly created, or already existing) t1lib font id.  The
05164        filename argument is optional, but is assumed to be a full path
05165        if it is given.
05166     */
05167 
05168     int id, idx;
05169     size_t i;
05170     char *path = NULL;
05171     
05172     static size_t t1lidx = 0;
05173     static size_t t1lidx_max = 0;
05174     static const size_t t1lidx_step = 1024;
05175 
05176     
05177 #ifdef USE_HASH
05178     /* Already set up by that name? */
05179     if (t1fonts_hash.size == 0)
05180        t1fonts_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
05181     
05182     if (find_str_int_hash(&t1fonts_hash, fontname, &i)) {
05183        return i;
05184     }
05185 #else
05186     for (i = 0; i <= t1lidx; i++) {
05187        if (strcmp(t1fonts[i].shortname, fontname) == 0 ||
05188            strcmp(t1fonts[i].file, fontname) == 0) {
05189            TRACE_T1((stderr, "Type1 font %s already loaded from %s", fontname, filename));
05190            return i;
05191        }
05192     }
05193 #endif /* USE_HASH */
05194 
05195     /* Insert and set up new t1 font */
05196     while (t1lidx >= t1lidx_max) {
05197        t1lidx_max += t1lidx_step;
05198        t1fonts = xrealloc(t1fonts, t1lidx_max * sizeof *t1fonts);
05199 
05200        TRACE_T1((stderr, "Enlarged t1 table from %lu to %lu entries",
05201                 (unsigned long)t1lidx, (unsigned long)t1lidx_max));
05202     }
05203 
05204     if (filename == NULL) {
05205        /* We don't know the full path name yet, find it */
05206        path = kpse_find_file(fontname, kpse_type1_format, 0);
05207        if (path == NULL)
05208            return -1;       /* xdvi will use substitution font */
05209     }
05210     else {
05211        path = xstrdup(filename);
05212     }
05213 
05214     t1fonts[t1lidx].file = xstrdup(path);
05215     t1fonts[t1lidx].t1id = id = T1_AddFont(path);
05216     t1fonts[t1lidx].shortname = xstrdup(fontname);
05217     t1fonts[t1lidx].loaded = 0;
05218 
05219     TRACE_T1((stderr, "Loaded font %lu/%s (%d) from %s", (unsigned long)t1lidx, fontname, id, path));
05220 
05221 #ifdef USE_HASH
05222     /* also save the info in the hashtable (note: no duplication of the string here!) */
05223     put_str_int_hash(&t1fonts_hash, t1fonts[t1lidx].shortname, t1lidx);
05224 #endif /* USE_HASH */
05225 
05226     idx = t1lidx++;
05227     
05228     free(path);
05229 
05230 #if USE_AFM
05231     /* BZZT! AFM files are useless to us, their metric information is
05232        too inacurate for TeX use.  Never define USE_AFM */
05233     /* Set the afm filename.  Always before loading.  If no afm file
05234        found t1lib will use fallback code.  In fact the fallback code
05235        has been deactivated entierly, it's dog slow. */
05236     path = kpse_find_file(fontname, kpse_afm_format, 0);
05237     if (path != NULL) {
05238        TRACE_T1((stderr, "found afm file: %s", path));
05239        T1_SetAfmFileName(id, path);
05240        free(path);
05241     }
05242 #endif
05243 
05244     return idx;
05245 }
05246 
05247 static int
05248 find_texfont(const char *texname)
05249 {
05250     /* Find fontmap index of texfont */
05251     size_t i;
05252 
05253 #ifdef USE_HASH
05254     if (fontmaps_hash.size == 0)
05255        fontmaps_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
05256     
05257     if (find_str_int_hash(&fontmaps_hash, texname, &i)) {
05258        return i;
05259     }
05260 #else
05261     for (i = 0; i < g_maplidx; i++) {
05262        if (strcmp(fontmaps[i].texname, texname) == 0) {
05263            TRACE_T1((stderr, "Type1 font already loaded at index %d: %s\n", i, texname));
05264            return i;
05265        }
05266     }
05267 #endif /* USE_HASH */
05268     return -1;
05269 }
05270 
05271 
05272 static int
05273 setup_encoded_T1_font(const char *mapfile,
05274                     int lineno,
05275                     const char *texname,
05276                     const char *alias,
05277                     const char *filename,
05278                     int enc,
05279                     int ext,
05280                     int sl)
05281 {
05282     /* xdvi T1 Font loading is done in two steps:
05283 
05284        1. At xdvi startup two things happen:
05285 
05286        a. The fontmaps are read.
05287 
05288        b. the dvi file is (partialy) scanned, and fonts are set up.
05289        In the case of t1 fonts we only set up the data structures,
05290        they are not actually loaded until they are used.
05291 
05292        2. At the time a T1 font is used it is loaded, encoded, extended
05293        and slanted as prescribed.
05294 
05295        This procedure takes care of step 1a.  It locates the font and
05296        sets up the data-structures so it may be assumed, by xdvi, to be
05297        loaded.  Return the fontmaps array index.
05298 
05299        The 'texname' param should be the texname of the font, such as
05300        ptmr8r or cmr10.
05301 
05302        The 'alias' param should be the file name of the font if it is
05303        different from the texname.  This is often the case with fonts
05304        defined in fontmaps.
05305 
05306        If, for some reason, the full filename of the font has already
05307        been looked up before we get here it is passed in the filename
05308        param so we don't have to look it up again.
05309 
05310        Implied encodings are not handled here.
05311 
05312        REMEMBER: THIS PROC IS CALLED FOR EACH FONT IN THE FONTMAPS, WE
05313        CANNOT DO ANY EXPENSIVE OPERATIONS HERE!!!
05314 
05315      */
05316 
05317     int test_idx;
05318     size_t curr_idx;
05319     static size_t maplidx_max = 0;
05320     static const size_t maplidx_step = 1024;
05321 
05322     /* fprintf(stderr, "setup font: |%s|, %s\n", texname, mapfile); */
05323     
05324     /* Already setup by that name? */
05325     test_idx = find_texfont(texname);
05326     ASSERT(test_idx == -1 || (test_idx > -1 && test_idx < (int)g_maplidx), "Result of find_texfont() out of range");
05327     
05328     if (mapfile != NULL && test_idx != -1) {
05329        /* font is already set up, and we're scanning the map file: replace existing font with new one */
05330        curr_idx = test_idx;
05331        XDVI_INFO((stdout, "%s: Entry for font \"%s\" on line %d overrides previous entry.",
05332                  mapfile, texname, lineno));
05333        
05334        free(fontmaps[curr_idx].filename);
05335        free(fontmaps[curr_idx].pathname);
05336     }
05337     else if (test_idx != -1) {
05338        /* font is already set up, but we're not scanning the map file - return font index */
05339        TRACE_T1_VERBOSE((stderr, "font |%s| already set up at index %d", texname, test_idx));
05340        return test_idx;
05341     }
05342     else { /* Not set up yet, do it. */
05343        curr_idx = g_maplidx++;            /* increment global index count */
05344        while (curr_idx >= maplidx_max) {
05345            maplidx_max += maplidx_step;
05346            fontmaps = xrealloc(fontmaps, maplidx_max * sizeof *fontmaps);
05347            
05348            TRACE_T1((stderr, "Enlarged the fontmap from %lu to %lu entries",
05349                     (unsigned long)curr_idx, (unsigned long)maplidx_max));
05350        }
05351        fontmaps[curr_idx].texname = xstrdup(texname);
05352     }
05353 
05354     if (alias == NULL)
05355        alias = texname;
05356 
05357 #ifdef USE_HASH
05358     if (test_idx == -1) {
05359        if (fontmaps_hash.size == 0)
05360            fontmaps_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
05361        put_str_int_hash(&fontmaps_hash, fontmaps[curr_idx].texname, curr_idx);
05362     }
05363 #endif /* USE_HASH */
05364     
05365     fontmaps[curr_idx].enc = enc;
05366     fontmaps[curr_idx].extension = ext;
05367     fontmaps[curr_idx].slant = sl;
05368 
05369     fontmaps[curr_idx].filename = xstrdup(alias);
05370     fontmaps[curr_idx].t1libid = -1;
05371     TRACE_T1((stderr,
05372              "fontmaps[%lu]: \"%s\", enc=%d, ext=%d, sl=%d, alias \"%s\"",
05373              (unsigned long)curr_idx, texname, enc, ext, sl, alias));
05374 
05375     if (filename != NULL) {
05376        fontmaps[curr_idx].pathname = xstrdup(filename);
05377     }
05378     else {
05379        fontmaps[curr_idx].pathname = NULL;
05380     }
05381     fontmaps[curr_idx].tfmidx = -1;
05382     fontmaps[curr_idx].warned_about = False;
05383     fontmaps[curr_idx].force_pk = False;
05384 
05385     return curr_idx;
05386 }
05387 
05388 
05389 static t1FontLoadStatusT
05390 try_pk_fallback(int idx, struct font *fontp)
05391 {
05392     Boolean success;
05393 
05394     success = load_font(fontp, False); /* loading non-t1 version of font */
05395     fontmaps[idx].force_pk = True;
05396     TRACE_T1((stderr,
05397              "setting force_pk for %d to true; success for PK fallback: %d\n",
05398              idx, success));
05399     
05400     if (!success) {
05401        /* this is probably serious enough for a GUI warning */
05402        popup_message(globals.widgets.top_level,
05403                     MSG_ERR,
05404                     /* helptext */
05405                     "Xdvi tries all of the following possibilities in turn, and all of them have failed:\n\n"
05406                     "  (1) If the resource t1lib is set, try a Postscript Type1 version of a font.\n\n"
05407                     "  (2) Otherwise, or if the Type1 version hasn't been found, try to "
05408                     "locate, or generate via mktexpk, a TeX Pixel (PK) version of the font.\n\n"
05409                     "  (3) Use the fallback font defined via the \"altfont\" resource (cmr10 by default), "
05410                     "both as Type1 and as PK version, at various resolutions.\n\n"
05411                     "It seems that your font setup is defective.\n",
05412                     /* errmsg */
05413                     "Error loading font %s: Neither a Type1 version nor "
05414                     "a pixel version could be found. The character(s) "
05415                     "will be left blank.",
05416                     fontmaps[idx].texname);
05417        currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
05418        return FAILURE_BLANK;
05419     }
05420     /* free unneeded resources. We mustn't free
05421        fontmaps[idx].texname,
05422        else find_T1_font will try to load the font all over again.
05423     */
05424     free(fontmaps[idx].filename);
05425     free(fontmaps[idx].pathname);
05426     currinf.set_char_p = currinf.fontp->set_char_p = set_char;
05427     return FAILURE_PK;
05428 }
05429 
05430 static t1FontLoadStatusT
05431 load_font_now(int idx, struct font *fontp)
05432 {
05433     /* At this point xdvi needs to draw a glyph from this font.  But
05434        first it must be loaded/copied and modified if needed. */
05435 
05436     int t1idx;       /* The fontmap entry number */
05437     int t1id; /* The id of the unmodified font */
05438     int cid;  /* The id of the copied font */
05439     int enc, sl, ext;
05440 
05441 /*      statusline_print(STATUS_SHORT, "Loading T1 font %s", fontmaps[idx].filename); */
05442     TRACE_T1((stderr, "adding %s %s",
05443              fontmaps[idx].filename, fontmaps[idx].pathname));
05444 
05445     t1idx = add_t1font(fontmaps[idx].filename, fontmaps[idx].pathname);
05446 
05447     t1id = fontmaps[idx].t1libid = t1fonts[t1idx].t1id;
05448 
05449     errno = 0;
05450     if (!t1fonts[t1idx].loaded && T1_LoadFont(t1id) == -1) {
05451        /* this error is somehow better kept at stderr instead of
05452           a popup (too annoying) or the statusline (might disappear
05453           too fast) ... */
05454        XDVI_ERROR((stderr, "Could not load Type1 font %s from %s: %s %s (T1_errno = %d); "
05455                   "will try pixel version instead.\nPlease see the T1lib documentation for details about this.\n",
05456                   fontmaps[idx].texname, fontmaps[idx].pathname,
05457                   T1_StrError(T1_errno),
05458                   errno != 0 ? strerror(errno) : "",
05459                   T1_errno));
05460        return try_pk_fallback(idx, fontp);
05461     }
05462 
05463     fontmaps[idx].tfmidx = add_tfm(fontmaps[idx].texname);
05464 
05465     t1fonts[t1idx].loaded = 1;
05466 
05467     /* If there is nothing further to do, just return */
05468     enc = fontmaps[idx].enc;
05469     ext = fontmaps[idx].extension;
05470     sl = fontmaps[idx].slant;
05471     TRACE_T1((stderr, "lookup at idx[%d] yields: %d, %d, %d", idx, enc, ext, sl));
05472 
05473     if (enc == -1 && ext == 0 && sl == 0)
05474        return SUCCESS;
05475 
05476     /* The fontmap entry speaks of a modified font.  Copy it first. */
05477     cid = T1_CopyFont(t1id);
05478 
05479     fontmaps[idx].t1libid = cid;
05480 
05481     if (enc != -1) {
05482        TRACE_T1_VERBOSE((stderr, "trying to load vector from encodings index %d", enc));
05483        /* Demand load vector */
05484        if (encodings[enc].vector == NULL)
05485            encodings[enc].vector = load_vector(encodings[enc].file);
05486 
05487        if (encodings[enc].vector == NULL) {
05488            /* this error is somehow better kept at stderr instead of
05489               a popup (too annoying) or the statusline (might disappear
05490               too fast) ... */
05491            XDVI_ERROR((stderr, "Could not load load encoding file %s for vector %s (font %s): %s (T1_errno = %d); "
05492                      "will try pixel version instead.\n"
05493                      "Please see the T1lib documentation for details about this.\n",
05494                      encodings[enc].file, encodings[enc].enc, fontmaps[idx].texname,
05495                      T1_StrError(T1_errno), T1_errno));
05496            return try_pk_fallback(idx, fontp);
05497        }
05498        else {
05499            if (T1_ReencodeFont(cid, encodings[enc].vector) != 0) {
05500               XDVI_ERROR((stderr, "Re-encoding of %s failed: %s (T1_errno = %d); "
05501                          "will try pixel version instead.\n"
05502                          "Please see the T1lib documentation for details about this.\n",
05503                          fontmaps[idx].texname,
05504                          T1_StrError(T1_errno), T1_errno));
05505               return try_pk_fallback(idx, fontp);
05506            }
05507        }
05508     }
05509 
05510     if (ext)
05511        T1_ExtendFont(cid, ext / 1000.0);
05512 
05513     if (sl)
05514        T1_SlantFont(cid, sl / 10000.0);
05515 
05516     return SUCCESS;
05517 }
05518 
05519 
05520 int
05521 find_T1_font(const char *texname)
05522 {
05523     /* Step 1b in the scenario above.  xdvi knows that this font is
05524        needed.  Check if it is available, but do not load it yet.
05525        Return the fontmap index at which the font was found */
05526 
05527     int idx;  /* Iterator, t1 font id */
05528     char *filename;
05529     int fl, el;      /* Fontname length, encoding name length */
05530     int encoded = -1;
05531     char *mname;     /* Modified font name */
05532     size_t i;
05533     
05534     encoded = 0;
05535 
05536     /* First: Check the maps */
05537     idx = find_texfont(texname);
05538 
05539     if (idx != -1) {
05540        if (fontmaps[idx].force_pk) {
05541            return idx;
05542        }
05543        if (fontmaps[idx].pathname == NULL) {
05544            filename = kpse_find_file(fontmaps[idx].filename, kpse_type1_format, 0);
05545            /* It should have been on disk according to the map, but never
05546               fear, xdvi will try to find it other ways. */
05547            if (filename == NULL) {
05548               if (!fontmaps[idx].warned_about) {
05549                   fontmaps[idx].warned_about = True;
05550                   XDVI_WARNING((stderr, "Font map calls for %s, but it was not found (will try PK version instead).",
05551                               fontmaps[idx].filename));
05552               }
05553               return -1;
05554            }
05555            fontmaps[idx].pathname = filename;
05556        }
05557        TRACE_T1((stderr, "find_T1_font map: %s, entered as #%d",texname,idx));
05558        return idx;
05559     }
05560 
05561     /* Second: the bare name */
05562     filename = kpse_find_file(texname, kpse_type1_format, 0);
05563 
05564     if (filename != NULL) {
05565        idx = setup_encoded_T1_font(NULL, 0, texname, NULL, filename, -1, 0, 0);
05566        TRACE_T1((stderr, "find_T1_font bare enc: %s, entered as #%d", texname, idx));
05567        return idx;
05568     }
05569 
05570     /* Third: Implied encoding? */
05571     fl = strlen(texname);
05572 
05573     for (i = 0; i < enclidx; i++) {
05574        if (encodings[i].enc == NULL)
05575            continue;
05576 
05577        el = strlen(encodings[i].enc);
05578        
05579        /* Note: the encodings map is short, so the strcmp doesn't hurt here */
05580        if (strcmp(texname + (fl - el), encodings[i].enc) == 0) {
05581            /* Found a matching encoding */
05582            TRACE_T1((stderr, "Encoding match: %s - %s", texname,
05583                     encodings[i].enc));
05584 
05585            mname = malloc(fl + 2);
05586            strcpy(mname, texname);
05587            mname[fl - el] = '\0';
05588            /* If we had 'ptmr8r' the we now look for 'ptmr' */
05589            filename = kpse_find_file(mname, kpse_type1_format, 0);
05590            if (filename == NULL) {
05591               /* No? Look for ptmr8a. 8a postfix is oft used on raw fonts */
05592               strcat(mname, "8a");
05593               filename = kpse_find_file(mname, kpse_type1_format, 0);
05594            }
05595            if (filename != NULL) {
05596               idx = setup_encoded_T1_font(NULL, 0, texname, mname, filename, i, 0, 0);
05597               TRACE_T1((stderr, "find_T1_font implied enc: %s, is #%d", texname, idx));
05598               return idx;
05599            }
05600 
05601            free(mname);
05602            /* Now we have tried everything.  Time to give up. */
05603            return -1;
05604 
05605        }      /* If (strcmp...) */
05606     }  /* for */
05607     return -1;
05608 }
05609 
05610 /* ************************* CONFIG FILE READING ************************ */
05611 
05612 
05613 static int
05614 new_encoding(const char *enc, const char *file)
05615 {
05616     /* (Possibly) new encoding entered from .cfg file, or from dvips
05617        map.  When entered from dvips map the enc is null/anonymous */
05618 
05619     size_t i;
05620     static size_t enclidx_max = 0;
05621     static const size_t enclidx_step = 16;
05622 
05623     /* Shirley!  You're jesting! */
05624     if (file == NULL)
05625        return -1;
05626 
05627     if (enc == NULL) {
05628        /* Enter by file name.  First check if the file has been entered
05629           already. */
05630        for (i = 0; i < enclidx; i++) { 
05631            if (strcmp(encodings[i].file, file) == 0) {
05632               return i;
05633            }
05634        }
05635     }
05636     else {
05637        /* Enter by encoding name.  Check if already loaded first. */
05638        for (i = 0; i < enclidx; i++) {
05639            if (encodings[i].enc != NULL && strcmp(encodings[i].enc, enc) == 0)
05640               return i;
05641        }
05642     }
05643 
05644     /* Bonafide new encoding */
05645 
05646     while (enclidx >= enclidx_max) {
05647        enclidx_max += enclidx_step;
05648        encodings = xrealloc(encodings, enclidx_max * sizeof *encodings);
05649 
05650        TRACE_T1((stderr, "Enlarged encoding map from %lu to %lu entries",
05651                 (unsigned long)enclidx, (unsigned long)enclidx_max));
05652     }
05653 
05654     TRACE_T1((stderr, "New encoding #%lu: '%s' -> '%s'", (unsigned long)enclidx, enc ? enc : "<NULL>", file));
05655 
05656     /* The encoding name is optional */
05657     encodings[enclidx].enc = NULL;
05658     if (enc != NULL)
05659        encodings[enclidx].enc = xstrdup(enc);
05660 
05661     /* The file name is required */
05662     encodings[enclidx].file = xstrdup(file);
05663     encodings[enclidx].vector = NULL;     /* Demand load later */
05664 
05665     return enclidx++;
05666 }
05667 
05668 
05669 void
05670 add_T1_mapentry(int lineno,
05671               const char *mapfile,
05672               const char *name,
05673               const char *file,
05674               const char *vec,
05675               char *spec)
05676 {
05677     /* This is called from read_map_file, once for each fontmap line `lineno'.  We
05678        will dutifully enter the information into our fontmap table */
05679 
05680     static char delim[] = "\t ";
05681     char *last, *current;
05682     float number;
05683     int extend = 0;
05684     int slant = 0;
05685 
05686     TRACE_T1_VERBOSE((stderr, "%s:%d: %s -> %s Enc: %s Spec: %s",
05687                     mapfile, lineno,
05688                     name, file,
05689                     vec == NULL ? "<none>" : vec,
05690                     spec == NULL ? "<none>" : spec));
05691 
05692     if (spec != NULL) {
05693        /* Try to analyze the postscript string.  We recognize two things:
05694           "n ExtendFont" and "m SlantFont".  n can be a decimal number in
05695           which case it's an extension factor, or a integer, in which
05696           case it's a charspace unit? In any case 850 = .85 */
05697 
05698        last = strtok(spec, delim);
05699        current = strtok(NULL, delim);
05700        while (current != NULL) {
05701            if (strcmp(current, "ExtendFont") == 0) {
05702               sscanf(last, "%f", &number);
05703               if (number < 10.0)
05704                   extend = number * 1000.0;
05705               else
05706                   extend = number;
05707            }
05708            else if (strcmp(current, "SlantFont") == 0) {
05709               sscanf(last, "%f", &number);
05710               slant = number * 10000.0;
05711            }
05712            last = current;
05713            current = strtok(NULL, delim);
05714        }
05715     }
05716 
05717     setup_encoded_T1_font(mapfile, lineno,
05718                        name, file, NULL, new_encoding(NULL, vec), extend,
05719                        slant);
05720 }
05721 
05722 static void
05723 read_cfg_file(const char *file)
05724 {
05725     char *filename;
05726     FILE *fp;
05727     int len;
05728     char *keyword;
05729     char *ptr;
05730     char *buffer;
05731     char *enc;
05732     char *name;
05733     int i;
05734     static const char delim[] = "\t \n\r";
05735     Boolean found_no_map_files = True;
05736     
05737     if (file == NULL)
05738        file = "xdvi.cfg";
05739     
05740     filename = kpse_find_file(file, kpse_program_text_format, 1);
05741     if (filename == NULL) {
05742        statusline_print(STATUS_MEDIUM, "Warning: Unable to find \"%s\"!", file);
05743        return;
05744     }
05745 
05746     if ((fp = XFOPEN(filename, "r")) == NULL) {
05747        XDVI_ERROR((stderr, "Cannot open config file `%s' for reading: %s", filename, strerror(errno)));
05748        return;
05749     }
05750 
05751     TRACE_T1((stderr, "Reading cfg file %s", filename));
05752 
05753     buffer = xmalloc(BUFFER_SIZE);
05754 
05755     while (fgets(buffer, BUFFER_SIZE, fp) != NULL) {
05756        len = strlen(buffer);
05757        if (buffer[len - 1] != '\n') {
05758            int c;
05759            /* this really shouldn't happen ... */
05760            XDVI_WARNING((stderr, "Skipping overlong line (> %d characters) in config file `%s':\n%s ...",
05761                        BUFFER_SIZE, filename, buffer));
05762            /* read until end of this line */
05763            while((c = fgetc(fp)) != '\n' && c != EOF) { ; }
05764            continue;
05765        }
05766 
05767        keyword = buffer;
05768 
05769        /* Skip leading whitespace */
05770        while (keyword[0] != '\0' && (keyword[0] == ' ' || keyword[0] == '\t'))
05771            keyword++;
05772 
05773        /* % in first column is a correct comment */
05774        if (keyword[0] == '%' || keyword[0] == '\0' || keyword[0] == '\n')
05775            continue;
05776 
05777        keyword = strtok(keyword, delim);
05778 
05779        if (strcmp(keyword, "dvipsmap") == 0) {
05780            if ((ptr = strtok(NULL, delim)) == NULL) {
05781               XDVI_WARNING((stderr, "Syntax error in entry \"%s\"", buffer));
05782               continue;
05783            }
05784            TRACE_T1((stderr, "DVIPSMAP: '%s'", ptr));
05785 
05786            if (read_map_file(ptr)) {
05787               found_no_map_files = False;
05788            }
05789            else {
05790               TRACE_T1((stderr, "Read map file: '%s'", ptr));
05791            }
05792        }
05793        else if (strcmp(keyword, "encmap") == 0) {
05794            popup_message(globals.widgets.top_level,
05795                        MSG_ERR,
05796                        "Your xdvi.cfg file is for a previous version of xdvik. Please replace "
05797                        "it by the xdvi.cfg file in the current xdvik distribution.",
05798                        "Keyword \"encmap\" in xdvi.cfg is no longer supported, "
05799                        "please update the config file %s.",
05800                        filename);
05801        }
05802        else if (strcmp(keyword, "enc") == 0) {
05803            enc = strtok(NULL, delim);
05804            name = strtok(NULL, delim);
05805            if ((ptr = strtok(NULL, delim)) == NULL) {
05806               XDVI_WARNING((stderr, "Syntax error in entry \"%s\" (skipping line)", buffer));
05807               continue;
05808            }
05809            i = new_encoding(enc, ptr);
05810            TRACE_T1((stderr, "Encoding[%d]: '%s' = '%s' -> '%s'", i, enc, name, ptr));
05811        } else {
05812            /* again, nag them with a popup so that they'll do something about this ... */
05813            popup_message(globals.widgets.top_level,
05814                        MSG_ERR,
05815                        "Please check the syntax of your config file. "
05816                        "Valid keywords are: \"enc\" and \"dvipsmap\".",
05817                        "Skipping unknown keyword \"%s\" in config file %s.",
05818                        keyword, filename);
05819        }
05820     }
05821 
05822     if (found_no_map_files) {
05823        /* nag 'em with a popup so that they'll do something about this ... */
05824        popup_message(globals.widgets.top_level,
05825                     MSG_ERR,
05826                     "Direct Type 1 font rendering via T1lib gives you many benefits, such as:\n"
05827                     " - quicker startup time, since no bitmap fonts need to be generated;\n"
05828                     " - saving disk space for storing the bitmap fonts.\n"
05829                     "To fix this error, check that the file `ps2pk.map' is located somewhere "
05830                     "in your XDVIINPUTS path. Have a look at the xdvi wrapper shell script "
05831                     "(type \"which xdvi\" to locate that shell script) for the current setting "
05832                     "of XDVIINPUTS.",
05833                     "Could not load any of the map files listed in xdvi.cfg - disabling T1lib.");
05834        resource.t1lib = False;
05835     }
05836     fclose(fp);
05837 
05838     free(buffer);
05839     free(filename);
05840 }
05841 
05842 
05843 /* **************************** GLYPH DRAWING *************************** */
05844 
05845 
05846 /* Set character# ch */
05847 
05848 static struct glyph *
05849 get_t1_glyph(
05850 #ifdef TEXXET
05851             wide_ubyte cmd,
05852 #endif
05853             wide_ubyte ch, t1FontLoadStatusT *flag,
05854             Boolean is_geom_scan)
05855 {
05856 
05857     /*
05858       A problem is that there are some gaps in math modes tall braces '{',
05859       (see for example the amstex users guide).  These gaps are seen less if a
05860       small size factor is applied, 1.03 seems nice.  This does not seem like
05861       the Right Thing though.  Also gaps do not show up in the fullsize
05862       window.
05863 
05864       All in all the factor has been dropped.  Despite the beauty flaw.
05865     */
05866 
05867     float size = dvi_pt_conv(currinf.fontp->scale);
05868 
05869     int id = currinf.fontp->t1id;
05870     int t1libid = fontmaps[id].t1libid;
05871 
05872     GLYPH *G;        /* t1lib glyph */
05873     struct glyph *g; /* xdvi glyph */
05874 
05875 #ifdef TEXXET
05876     UNUSED(cmd);
05877 #endif
05878     *flag = SUCCESS;
05879 
05880 #if COLOR
05881     if (!is_geom_scan && fg_active != fg_current)
05882        do_color_change();
05883 #endif
05884 
05885     /* return immediately if we need to use the fallback PK */
05886     if (fontmaps[id].force_pk)
05887        return NULL;
05888 
05889     TRACE_T1((stderr, "scale: %ld, ppi %d, sf: %d, size: %f",
05890              currinf.fontp->scale, resource.pixels_per_inch,
05891              currwin.shrinkfactor, size));
05892 
05893     if (t1libid == -1) {
05894        TRACE_T1((stderr, "trying to load font %d", id));
05895        *flag = load_font_now(id, currinf.fontp);
05896        if (*flag < 0) {
05897            TRACE_T1((stderr, "load_font_now failed for T1 font %d", id));
05898            return NULL;
05899        }
05900        t1libid = fontmaps[id].t1libid;
05901     }
05902     
05903     TRACE_T1((stderr, "Setting 0x%x `%c' of %d, at %ld(%.2fpt), shrinkage is %d",
05904              ch,
05905              isprint(ch) ? ch : '?',
05906              t1libid, currinf.fontp->scale,
05907              size, currwin.shrinkfactor));
05908 
05909     /* Check if the glyph already has been rendered */
05910     if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
05911        int bitmapbytes;
05912        int h;
05913        unsigned char *f;
05914        unsigned char *t;
05915        /* Not rendered: Generate xdvi glyph from t1font */
05916 
05917        g->addr = 1; /* Dummy, should not provoke errors other places in xdvi */
05918 
05919        /* Use the width from the tfm file */
05920        g->dvi_adv = tfminfo[fontmaps[id].tfmidx].widths[ch] * currinf.fontp->dimconv;
05921        TRACE_T1((stderr, "0x%x, dvi_adv = %ld; dimconv: %f",
05922                 ch,
05923                 tfminfo[fontmaps[id].tfmidx].widths[ch],
05924                 currinf.fontp->dimconv));
05925 
05926        /* Render the glyph.  Size here should be postscript bigpoints */
05927        G = T1_SetChar(t1libid, ch, size, NULL);
05928        ASSERT(G != NULL, "T1_SetChar() returned NULL");
05929 
05930        if (G->bits == NULL) {
05931            if (ch != ' ') {
05932               /* -- janl:
05933                  Blank glyph != .notdef (e.g., it could be a space char).
05934                  Drop message until I find out how .notdef can be detected.
05935                  -- SU 2003/02/24:
05936                  I changed this, since dropped characters is an important
05937                  thing to warn users about. We try to catch the space char
05938                  case by checking for space above (rather lame, since it won't
05939                  catch all fonts, but ...)
05940                  The only case in which TeX actually uses a space character seems
05941                  to be the output of `tex testfont', or in some CJK fonts
05942                  (e.g. gbksong25).
05943               */
05944               char index[128];
05945               char *fontname = xstrdup(currinf.fontp->fontname);
05946               size_t dummy = 0;
05947               
05948               SNPRINTF(index, sizeof index, "%d", ch);
05949               fontname = xstrcat(fontname, index);
05950               if (font_warn_hash.size == 0) {
05951                   /* TODO: print to statusline */
05952                   /*                   popup_message(MSG_WARN, */
05953                   /*                                  NULL, */
05954                   /*                                  "Unexpected blank character (.notdef) in font %s, " */
05955                   /*                                  "replacing with whitespace (see output to stderr for details). " */
05956                   /*                                  "This might indicate that the font %s is missing " */
05957                   /*                                  "from the font map, or that it has been specified " */
05958                   /*                                  "with a wrong encoding.", */
05959                   /*                                  currinf.fontp->fontname, currinf.fontp->fontname); */
05960                   font_warn_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
05961               }
05962               
05963               if (!find_str_int_hash(&font_warn_hash, fontname, &dummy)) {
05964                   if (!resource.hush_chars)
05965                      XDVI_WARNING((stderr, "Character %d is mapped to .notdef in font %s (page %d), "
05966                                   "replacing by whitespace.",
05967                                   ch, currinf.fontp->fontname, current_page + 1));
05968                   put_str_int_hash(&font_warn_hash, fontname, dummy);
05969               }
05970               else {
05971                   free(fontname);
05972               }
05973            }
05974            /* *flag = FAILURE_BLANK; */
05975            /* g->addr = -1; */
05976            /* return NULL; */
05977            
05978            /* FIXME: g->dvi_adv is only used when invoking set_char(), not with
05979               set_empty_char(), and the former apparently needs a valid bitmap.
05980               Check how this is done without t1lib.
05981            */
05982            TRACE_T1((stderr, "replacing .notdef char 0x%02x by space.\n", ch));
05983            g->bitmap.w = 1;
05984            g->bitmap.h = 1;
05985            g->bitmap.bytes_wide = T1PAD(g->bitmap.w, archpad) / 8;
05986            alloc_bitmap(&g->bitmap);
05987            memset(g->bitmap.bits, 0, g->bitmap.h * g->bitmap.bytes_wide);
05988            g->x = 0;
05989            g->y = 0;
05990 #if COLOR
05991            g->fg = fg_current;
05992 #endif
05993            return g;
05994        }
05995 
05996        g->bitmap.w = abs(G->metrics.rightSideBearing - G->metrics.leftSideBearing);
05997        g->bitmap.h = abs(G->metrics.descent - G->metrics.ascent);
05998        g->bitmap.bytes_wide = T1PAD(g->bitmap.w, archpad) / 8;
05999        alloc_bitmap(&g->bitmap);
06000 
06001        bitmapbytes = g->bitmap.bytes_wide * g->bitmap.h;
06002 
06003        if (padMismatch) {
06004            /* Fix alignment mismatch */
06005            int from_bytes = T1PAD(g->bitmap.w, 8) / 8;
06006 
06007            f = (unsigned char *)G->bits;
06008            t = (unsigned char *)g->bitmap.bits;
06009 
06010            memset(t, 0, bitmapbytes); /* OR ELSE! you get garbage */
06011 
06012            for (h = 0 ; h < g->bitmap.h; h++) {
06013               memcpy(t, f, from_bytes);
06014               f += from_bytes;
06015               t += g->bitmap.bytes_wide;
06016            }
06017 
06018 
06019        } else {
06020            /* t1lib and arch alignment matches */
06021            memcpy(g->bitmap.bits, G->bits, bitmapbytes);
06022        }
06023 
06024 #ifdef WORDS_BIGENDIAN
06025        /* xdvi expects the bits to be reversed according to
06026           endianness.  t1lib expects no such thing.  This loop reverses
06027           the bit order in all the bytes. -janl 18/5/2001 */
06028        t = (unsigned char *)g->bitmap.bits;
06029 
06030        for (h = 0; h < bitmapbytes; h++) {
06031            *t = rbits[*t];
06032            t++;
06033        }
06034 #endif
06035 
06036        g->x = -G->metrics.leftSideBearing;  /* Opposed x-axis */
06037        g->y = G->metrics.ascent;
06038 #if COLOR
06039        g->fg = fg_current;
06040 #endif
06041     }
06042     return g;
06043 }
06044 
06045 setcharRetvalT
06046 set_t1_char(
06047 #ifdef TEXXET
06048            wide_ubyte cmd,
06049 #endif
06050            wide_ubyte ch)
06051 {
06052     t1FontLoadStatusT flag;
06053     
06054     /*
06055       get_t1_glyph() will itself set currinf.fontp->set_char_p
06056       to set_empty_char() or set_char() if it failed to load the
06057       T1 version, but for the *current* call of set_t1_char,
06058       we still need to know whether (1) or (2) holds:
06059       (1) Type1 font hasn't been found but PK is working,
06060       use set_char() to set the PK version
06061       (2) neither Type1 nor PK have been found (this is the
06062       FAILURE_BLANK case), use set_empty_char().
06063       So we need the flag to pass this additional information.
06064     */
06065 #ifdef TEXXET      
06066     (void)get_t1_glyph(cmd, ch, &flag, False);
06067     if (flag == FAILURE_BLANK)
06068        set_empty_char(cmd, ch);
06069     else
06070        set_char(cmd, ch);
06071     return;
06072 #else
06073     (void)get_t1_glyph(ch, &flag, False);
06074     if (flag == FAILURE_BLANK)
06075        return set_empty_char(ch);
06076     else
06077        return set_char(ch);
06078 #endif
06079 }
06080 
06081 void read_T1_char(struct font *fontp, wide_ubyte ch)
06082 {
06083     UNUSED(fontp);
06084     UNUSED(ch);
06085     /* Should never be called */
06086     XDVI_ABORT((stderr, "%s:%d: asked to load %c", __FILE__, __LINE__, ch));
06087 }
06088 
06089 void init_t1(void)
06090 {
06091     int i;
06092     void *success;
06093     /* Attempt to set needed padding.
06094 
06095        FIXME: This is not really the required alignment/padding.  On
06096        ix86 the requirement for int * is 8 bits, on sparc on the other
06097        hand it's 32 bits.  Even so, some operations will be faster if
06098        the bitmaps lines are alligned "better".  But on the other hand
06099        this requires a more complex glyph copying operation...
06100 
06101        - janl 16/5/2001
06102     */
06103     archpad = BMBYTES * 8;
06104     i = T1_SetBitmapPad(archpad);
06105     if (i == -1) {
06106        /* Failed, revert to 8 bits and compilicated bitmap copying */
06107        padMismatch = True;
06108        T1_SetBitmapPad(8);
06109     } else {
06110        padMismatch = False;
06111     }
06112 
06113     /* Initialize t1lib, use LOGFILE to get logging, NO_LOGFILE otherwise */
06114     /* Under NO circumstances remove T1_NO_AFM, it slows us down a LOT */
06115 
06116     if (globals.debug & DBG_T1) {
06117        XDVI_INFO((stdout, "Additional t1lib messages may be found in \"t1lib.log\"."));
06118        success = T1_InitLib(LOGFILE | T1_NO_AFM | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE);
06119     }
06120     else
06121        success = T1_InitLib(NO_LOGFILE | T1_NO_AFM | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE);
06122     if (success == NULL) {
06123        XDVI_FATAL((stderr, "Initialization of t1lib failed!"));
06124     }
06125     T1_SetLogLevel(T1LOG_DEBUG);
06126 
06127     if (resource.subpixel_order == SUBPIXEL_NONE)
06128        T1_SetDeviceResolutions(BDPI, BDPI);
06129     else
06130        T1_SetDeviceResolutions(3 * BDPI, BDPI);
06131 
06132     read_cfg_file(NULL);
06133 }
06134 
06135 #endif /* T1LIB */
06136 
06137 
06138 #if GREY
06139 
06140 extern double pow();
06141 
06142 static void
06143 mask_shifts(Pixel mask, int *pshift1, int *pshift2)
06144 {
06145     int k, l;
06146 
06147     for (k = 0; (mask & 1) == 0; ++k)
06148        mask >>= 1;
06149     for (l = 0; (mask & 1) == 1; ++l)
06150        mask >>= 1;
06151     *pshift1 = sizeof(short) * 8 - l;
06152     *pshift2 = k;
06153 }
06154 
06155 /*
06156  *     Try to allocate 4 color planes for 16 colors (for GXor drawing).
06157  *     Not called if the visual type is TrueColor.
06158  *     When color specials are active, this is called exactly once.
06159  *     It is used for the first foreground/background pair displayed in
06160  *     the document.  For other documents, we act as if this call had failed.
06161  */
06162 
06163 
06164 void
06165 init_plane_masks(void)
06166 {
06167     Pixel pixel;
06168 
06169     if (globals.gc.do_copy || plane_masks[0] != 0)
06170        return;
06171 
06172     if (XAllocColorCells(DISP, G_colormap, False, plane_masks, 4, &pixel, 1)) {
06173        /* Make sure fore_Pixel and back_Pixel are a part of the palette */
06174        resource.back_Pixel = pixel;
06175        resource.fore_Pixel = pixel | plane_masks[0] | plane_masks[1]
06176            | plane_masks[2] | plane_masks[3];
06177        if (mane.win != (Window) 0)
06178            XSetWindowBackground(DISP, mane.win, resource.back_Pixel);
06179     }
06180     else {
06181        globals.gc.do_copy = True;
06182        warn_overstrike();
06183     }
06184 }
06185 
06186 #endif /* GREY */
06187 
06188 #if COLOR
06189 
06190 /*
06191  *     Insert into list of colors to be freed upon opening new document.
06192  */
06193 
06194 static void
06195 color_list_insert(Pixel pixel)
06196 {
06197     if (color_list_len >= color_list_max) {
06198        if (color_list_max == 0)
06199            color_list = xmalloc((color_list_max += 16) * sizeof *color_list);
06200        else
06201            color_list = xrealloc(color_list,
06202                               (color_list_max += 16) * sizeof *color_list);
06203     }
06204     color_list[color_list_len++] = pixel;
06205 }
06206 
06207 
06208 /*
06209  *     Warn about colors not being correct.
06210  */
06211 
06212 static void
06213 color_warn(void)
06214 {
06215     if (!color_warned) {
06216        color_warned = True;
06217        popup_message(globals.widgets.top_level,
06218                     MSG_WARN,
06219                     /* helptext */
06220                     "Either this document is using too many "
06221                     "colors, or some other application is. "
06222                     "In the latter case, try to close that "
06223                     "application and re-read the DVI file.",
06224                     /* msg */
06225                     "Cannot allocate colormap entry, "
06226                     "displayed colors will not be exact.");
06227     }
06228 }
06229 
06230 
06231 /*
06232  *     Allocate a color and add it to our list of pixels to be returned
06233  *     upon opening a new document.
06234  */
06235 
06236 #define       SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
06237 
06238 static int    shift1_r, shift1_g, shift1_b;
06239 static int    shift2_r, shift2_g, shift2_b;
06240 static Boolean       shifts_good   = False;
06241 
06242 Pixel
06243 alloc_color(const struct rgb *colorp, Pixel fallback_pixel)
06244 {
06245     XColor xcol;
06246 
06247     if (G_visual->class == TrueColor) {
06248        if (!shifts_good) {
06249            mask_shifts(G_visual->red_mask,   &shift1_r, &shift2_r);
06250            mask_shifts(G_visual->green_mask, &shift1_g, &shift2_g);
06251            mask_shifts(G_visual->blue_mask,  &shift1_b, &shift2_b);
06252            shifts_good = True;
06253        }
06254        return SHIFTIFY(colorp->r, shift1_r, shift2_r)
06255            | SHIFTIFY(colorp->g, shift1_g, shift2_g)
06256            | SHIFTIFY(colorp->b, shift1_b, shift2_b);
06257     }
06258     else {
06259        xcol.red = colorp->r;
06260        xcol.green = colorp->g;
06261        xcol.blue = colorp->b;
06262        xcol.flags = DoRed | DoGreen | DoBlue;
06263        if (XAllocColor(DISP, G_colormap, &xcol)) {
06264            color_list_insert(xcol.pixel);
06265            if (globals.debug & DBG_DVI)
06266               printf("alloc_color%6d%6d%6d --> %ld\n",
06267                      xcol.red, xcol.green, xcol.blue, xcol.pixel);
06268            return xcol.pixel;
06269        }
06270        else {
06271            if (globals.debug & DBG_DVI)
06272               printf("alloc_color%6d%6d%6d --> failed\n",
06273                      xcol.red, xcol.green, xcol.blue);
06274            color_warn();
06275            return fallback_pixel;
06276        }
06277     }
06278 }
06279 
06280 #undef SHIFTIFY
06281 
06282 
06283 /*
06284  *     Switch colors of GCs, etc.  Called when we're about to use a GC.
06285  */
06286 
06287 void
06288 do_color_change(void)
06289 {
06290     static int shrink_allocated_for = 0;
06291     Pixel set_bits;
06292     Pixel clr_bits;
06293     
06294     ASSERT(fg_current != NULL, "Current foreground mustn't be NULL");
06295     ASSERT(bg_current != NULL, "Current background mustn't be NULL");
06296 #if GREY
06297     if (resource.use_grey) {
06298        if (G_visual->class == TrueColor) {
06299            if (!fg_current->pixel_good) {
06300               fg_current->pixel = alloc_color(&fg_current->color,
06301                                           color_data[0].pixel);
06302               fg_current->pixel_good = True;
06303            }
06304 
06305            set_bits = fg_current->pixel & ~bg_current->pixel;
06306            clr_bits = bg_current->pixel & ~fg_current->pixel;
06307 
06308            if (set_bits & G_visual->red_mask)
06309               set_bits |= G_visual->red_mask;
06310            if (clr_bits & G_visual->red_mask)
06311               clr_bits |= G_visual->red_mask;
06312            if (set_bits & G_visual->green_mask)
06313               set_bits |= G_visual->green_mask;
06314            if (clr_bits & G_visual->green_mask)
06315               clr_bits |= G_visual->green_mask;
06316            if (set_bits & G_visual->blue_mask)
06317               set_bits |= G_visual->blue_mask;
06318            if (clr_bits & G_visual->blue_mask)
06319               clr_bits |= G_visual->blue_mask;
06320 
06321            /*
06322             * Make the GCs
06323             */
06324 
06325            globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->pixel, bg_current->pixel);
06326            globals.gc.fore2 = NULL;
06327 
06328            if (resource.copy
06329               || (set_bits && clr_bits && !resource.thorough)) {
06330               if (!resource.copy) {
06331                   warn_overstrike();
06332               }
06333               globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->pixel, bg_current->pixel);
06334            }
06335            else {
06336               if (set_bits) {
06337                   globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, fg_current->pixel & set_bits, 0);
06338                   if (clr_bits) {
06339                      globals.gc.fore2 = globals.gc.fore2_bak = set_or_make_gc(globals.gc.fore2_bak, GXandInverted,
06340                                                         ~fg_current->pixel & clr_bits, 0);
06341                   }
06342               }
06343               else {
06344                   globals.gc.fore = set_or_make_gc(globals.gc.fore, GXandInverted,
06345                                        ~fg_current->pixel & clr_bits, 0);
06346               }
06347            }
06348 
06349            if (globals.debug & DBG_DVI)
06350               printf("do_color_change: fg = %lx, bg = %lx, with%s globals.gc.fore2\n",
06351                      fg_current->pixel, bg_current->pixel,
06352                      globals.gc.fore2 == NULL ? "out" : "");
06353 
06354            if (mane.shrinkfactor > 1) {
06355               unsigned int i;
06356               unsigned int sf_squared;
06357 
06358               sf_squared = mane.shrinkfactor * mane.shrinkfactor;
06359 
06360               if (shrink_allocated_for < mane.shrinkfactor) {
06361                   if (pixeltbl != NULL) {
06362                      free((char *) pixeltbl);
06363                      if (pixeltbl_gc2 != NULL) {
06364                          free((char *) pixeltbl_gc2);
06365                          pixeltbl_gc2 = NULL;
06366                      }
06367                   }
06368                   pixeltbl = xmalloc((sf_squared + 1) * sizeof *pixeltbl);
06369                   shrink_allocated_for = mane.shrinkfactor;
06370               }
06371               if (globals.gc.fore2 != NULL && pixeltbl_gc2 == NULL) {
06372                   /* Can't use sf_squared (or mane.shrinkfactor) here */
06373                   pixeltbl_gc2 = xmalloc((shrink_allocated_for * shrink_allocated_for + 1) * sizeof *pixeltbl_gc2);
06374               }
06375 
06376               /*
06377                * Initialize the pixel lookup table according to the gamma values.
06378                */
06379 #define       SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
06380 
06381               for (i = 0; i <= sf_squared; ++i) {
06382                   double frac = resource.gamma > 0
06383                      ? pow((double)i / sf_squared, 1 / resource.gamma)
06384                      : 1 - pow((double) (sf_squared - i) / sf_squared, -resource.gamma);
06385                   unsigned int red, green, blue;
06386                   Pixel pixel;
06387                   /*                   fprintf(stderr, "frac: %f\n", frac); */
06388 /*                fprintf(stderr, "fg_current: %d, bg_current: %d\n", fg_current->color.r, bg_current->color.r); */
06389                   red = frac
06390                      * ((double) fg_current->color.r - bg_current->color.r)
06391                      + bg_current->color.r;
06392                   green = frac
06393                      * ((double) fg_current->color.g - bg_current->color.g)
06394                      + bg_current->color.g;
06395                   blue = frac
06396                      * ((double) fg_current->color.b - bg_current->color.b)
06397                      + bg_current->color.b;
06398 
06399                   pixel = SHIFTIFY(red,   shift1_r, shift2_r)
06400                      | SHIFTIFY(green, shift1_g, shift2_g)
06401                      | SHIFTIFY(blue,  shift1_b, shift2_b);
06402 
06403                   if (globals.gc.fore2 != NULL) {       /* if thorough */
06404                      /*     fprintf(stderr, "++++++ pixeltable at %d: %ld\n", i, pixel & ~bg_current->pixel); */
06405                      pixeltbl[i] = pixel & ~bg_current->pixel;
06406                      pixeltbl_gc2[i] = ~pixel & bg_current->pixel;
06407                   }
06408                   else if (resource.copy || (set_bits && clr_bits)) {
06409                      /*     fprintf(stderr, "++++++ pixeltable2 at %d: %ld\n", i, pixel); */
06410                      pixeltbl[i] = pixel;
06411                   }
06412                   else {
06413                      /*     fprintf(stderr, "++++++ pixeltable3 at %d: 0x%lx\n", i, ~pixel & clr_bits); */
06414                      /*     fprintf(stderr, "++++++ pixeltable3 at %d: %ld\n", i, pixel & set_bits); */
06415                      pixeltbl[i] = set_bits ? pixel & set_bits : ~pixel & clr_bits;
06416                   }
06417               }
06418 #undef SHIFTIFY
06419            }
06420 
06421        }
06422        else { /* not TrueColor */
06423            int       i;
06424            Boolean   using_planes;
06425 
06426            using_planes = (fg_current == bg_head->fg_head && !globals.gc.do_copy);
06427            if (!fg_current->palette_good) {
06428               XColor color;
06429 
06430               /*
06431                * Initialize the pixel lookup table according to the gamma values.
06432                */
06433               for (i = 0; i < 16; ++i) {
06434                   double frac;
06435 
06436                   frac = resource.gamma > 0
06437                      ? pow((double) i / 15, 1 / resource.gamma)
06438                      : 1 - pow((double) (15 - i) / 15, -resource.gamma);
06439                   color.red = frac
06440                      * ((double) fg_current->color.r - bg_current->color.r)
06441                      + bg_current->color.r;
06442                   color.green = frac
06443                      * ((double) fg_current->color.g - bg_current->color.g)
06444                      + bg_current->color.g;
06445                   color.blue = frac
06446                      * ((double) fg_current->color.b - bg_current->color.b)
06447                      + bg_current->color.b;
06448 
06449                   color.flags = DoRed | DoGreen | DoBlue;
06450 
06451                   if (using_planes) {
06452                      color.pixel = resource.back_Pixel; /* start of block */
06453                      if (i & 1) color.pixel |= plane_masks[0];
06454                      if (i & 2) color.pixel |= plane_masks[1];
06455                      if (i & 4) color.pixel |= plane_masks[2];
06456                      if (i & 8) color.pixel |= plane_masks[3];
06457                      XStoreColor(DISP, G_colormap, &color);
06458                      fg_current->palette[i] = color.pixel;
06459                   }
06460                   else {
06461                      if (XAllocColor(DISP, G_colormap, &color)) {
06462                          fg_current->palette[i] = color.pixel;
06463                          color_list_insert(color.pixel);
06464                      }
06465                      else {
06466                          color_warn();
06467                          fg_current->palette[i] =
06468                             (i * 100 >= resource.density * 15)
06469                             ? resource.fore_Pixel : bg_current->pixel;
06470                      }
06471                   }
06472               }
06473 
06474               if (using_planes && bg_current->pixel != resource.back_Pixel) {
06475                   bg_current->pixel = resource.back_Pixel;
06476 /*                XSetWindowBackground(DISP, mane.win, bg_current->pixel); */
06477 #if MOTIF
06478                   fprintf(stderr, "setting window background!\n");
06479                   XSetWindowBackground(DISP, XtWindow(globals.widgets.main_window), bg_current->pixel);
06480                   XtVaSetValues(globals.widgets.main_window, XmNbackground, bg_current->pixel, NULL);
06481 #else
06482                   XSetWindowBackground(DISP, mane.win, bg_current->pixel);
06483 #endif
06484                   XClearWindow(DISP, mane.win);
06485               }
06486 
06487               fg_current->palette_good = True;
06488            }
06489 
06490            if (globals.debug & DBG_DVI)
06491               printf("do_color_change: fg = %ld, bg = %ld, using_planes = %d\n",
06492                      fg_current->palette[15], bg_current->pixel, using_planes);
06493 
06494            if (using_planes) {
06495               globals.gc.rule = set_or_make_gc(globals.gc.rule, GXor, fg_current->palette[15],
06496                                    bg_current->pixel);
06497               globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, fg_current->palette[15],
06498                                    bg_current->pixel);
06499            }
06500            else {
06501               globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->palette[15],
06502                                    bg_current->pixel);
06503               globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->palette[15],
06504                                    bg_current->pixel);
06505            }
06506 
06507            globals.gc.fore2 = NULL;
06508 
06509            if (mane.shrinkfactor > 1) {
06510               if (shrink_allocated_for < mane.shrinkfactor) {
06511                   if (pixeltbl != NULL)
06512                      free((char *) pixeltbl);
06513                   pixeltbl = xmalloc((unsigned)(mane.shrinkfactor * mane.shrinkfactor + 1)
06514                                    * sizeof *pixeltbl);
06515                   shrink_allocated_for = mane.shrinkfactor;
06516               }
06517 
06518               for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i) {
06519                   pixeltbl[i] = fg_current->palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
06520                                                / (2 * mane.shrinkfactor * mane.shrinkfactor)];
06521               }
06522            }
06523        }
06524     }  /* end if resource.use_grey */
06525     else
06526 #endif /* GREY */
06527        {
06528            if (!fg_current->pixel_good) {
06529               fg_current->pixel = alloc_color(&fg_current->color,
06530                                           color_data[0].pixel);
06531               fg_current->pixel_good = True;
06532            }
06533 
06534            if (globals.debug & DBG_DVI)
06535               printf("do_color_change: fg = %lx, bg = %lx\n",
06536                      fg_current->pixel, bg_current->pixel);
06537 
06538            globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->pixel, bg_current->pixel);
06539 
06540            set_bits = (Pixel) (fg_current->pixel & ~bg_current->pixel);
06541            clr_bits = (Pixel) (bg_current->pixel & ~fg_current->pixel);
06542            globals.gc.fore2 = NULL;
06543 
06544            if (resource.copy
06545               || (set_bits && clr_bits && !resource.thorough)) {
06546               if (!resource.copy) {
06547                   /* I used to get a warning here which I didn't get for
06548                      xdvi-22.64/events.c, l.1330, but I can't reproduce
06549                      it any more ...
06550                   */
06551                   warn_overstrike();
06552               }
06553               globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->pixel, bg_current->pixel);
06554            }
06555            else {
06556               if (set_bits) {
06557                   globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, set_bits, 0);
06558                   if (clr_bits) {
06559                      globals.gc.fore2 = globals.gc.fore2_bak1 = set_or_make_gc(globals.gc.fore2_bak1, GXandInverted, clr_bits, 0);
06560                   }
06561               }
06562               else
06563                   globals.gc.fore = set_or_make_gc(globals.gc.fore, GXandInverted, clr_bits, 0);
06564            }
06565        }
06566 
06567     fg_active = fg_current;
06568 }
06569 
06570 #elif GREY /* if COLOR */
06571 
06572 void
06573 init_pix(void)
06574 {
06575     static int shrink_allocated_for = 0;
06576     static float oldgamma = 0.0;
06577     static Pixel palette[17];
06578     int i;
06579 
06580     if (G_visual->class == TrueColor) {
06581        /* This mirrors the non-grey code in xdvi.c */
06582        static int shift1_r, shift1_g, shift1_b;
06583        static int shift2_r, shift2_g, shift2_b;
06584        static Pixel set_bits;
06585        static Pixel clr_bits;
06586        unsigned int sf_squared;
06587 
06588        if (oldgamma == 0.0) {
06589            mask_shifts(G_visual->red_mask, &shift1_r, &shift2_r);
06590            mask_shifts(G_visual->green_mask, &shift1_g, &shift2_g);
06591            mask_shifts(G_visual->blue_mask, &shift1_b, &shift2_b);
06592 
06593            set_bits = color_data[0].pixel & ~(color_data[1].pixel);
06594            clr_bits = color_data[1].pixel & ~(color_data[0].pixel);
06595 
06596            if (set_bits & G_visual->red_mask)
06597               set_bits |= G_visual->red_mask;
06598            if (clr_bits & G_visual->red_mask)
06599               clr_bits |= G_visual->red_mask;
06600            if (set_bits & G_visual->green_mask)
06601               set_bits |= G_visual->green_mask;
06602            if (clr_bits & G_visual->green_mask)
06603               clr_bits |= G_visual->green_mask;
06604            if (set_bits & G_visual->blue_mask)
06605               set_bits |= G_visual->blue_mask;
06606            if (clr_bits & G_visual->blue_mask)
06607               clr_bits |= G_visual->blue_mask;
06608 
06609            /*
06610             * Make the GCs
06611             */
06612 
06613            globals.gc.fore = globals.gc.fore2 = globals.gc.rule = 0;
06614            globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel);
06615            if (globals.gc.do_copy || (set_bits && clr_bits)) {
06616               globals.gc.rule = globals.gc.copy;
06617               if (!resource.thorough)
06618                   globals.gc.do_copy = True;
06619            }
06620            if (globals.gc.do_copy) {
06621               globals.gc.fore = globals.gc.rule;
06622               if (!resource.copy) {
06623                   warn_overstrike();
06624               }
06625            }
06626            else {
06627               if (set_bits) {
06628                   globals.gc.fore = set_or_make_gc(NULL, GXor, set_bits & color_data[0].pixel, 0);
06629               }
06630               if (clr_bits || !set_bits) {
06631 /*                fprintf(stderr, "using GXandInverted!\n"); */
06632                   *(globals.gc.fore ? &globals.gc.fore2 : &globals.gc.fore) =
06633                      set_or_make_gc(NULL, GXandInverted, clr_bits & ~(color_data[0].pixel), 0);
06634               }
06635               if (!globals.gc.rule)
06636                   globals.gc.rule = globals.gc.fore;
06637            }
06638 
06639            oldgamma = resource.gamma;
06640        }
06641 
06642        if (mane.shrinkfactor == 1)
06643            return;
06644        sf_squared = mane.shrinkfactor * mane.shrinkfactor;
06645 
06646        if (shrink_allocated_for < mane.shrinkfactor) {
06647            if (pixeltbl != NULL) {
06648               free((char *)pixeltbl);
06649               if (pixeltbl_gc2 != NULL)
06650                   free((char *)pixeltbl_gc2);
06651            }
06652            pixeltbl = xmalloc((sf_squared + 1) * sizeof *pixeltbl);
06653            shrink_allocated_for = mane.shrinkfactor;
06654            if (globals.gc.fore2 != NULL) {
06655               pixeltbl_gc2 = xmalloc((sf_squared + 1) * sizeof *pixeltbl_gc2);
06656            }
06657        }
06658 
06659        /*
06660         * Initialize the pixel lookup table according to the gamma values.
06661         */
06662 #define       SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
06663 
06664        for (i = 0; i <= sf_squared; ++i) {
06665            double frac = resource.gamma > 0
06666               ? pow((double)i / sf_squared, 1 / resource.gamma)
06667               : 1 - pow((double)(sf_squared - i) / sf_squared, -resource.gamma);
06668            unsigned int red, green, blue;
06669            Pixel pixel;
06670 
06671            red = frac * ((double)color_data[0].red - color_data[1].red)
06672               + color_data[1].red;
06673            green = frac
06674               * ((double)color_data[0].green - color_data[1].green)
06675               + color_data[1].green;
06676            blue = frac * ((double)color_data[0].blue - color_data[1].blue)
06677               + color_data[1].blue;
06678 
06679            pixel = SHIFTIFY(red, shift1_r, shift2_r) |
06680               SHIFTIFY(green, shift1_g, shift2_g) |
06681               SHIFTIFY(blue, shift1_b, shift2_b);
06682 
06683            if (globals.gc.do_copy) {
06684               pixeltbl[i] = pixel;
06685            }
06686            else if (globals.gc.fore2 != NULL) {  /* if thorough */
06687               pixeltbl[i] = pixel & ~(color_data[1].pixel);
06688               pixeltbl_gc2[i] = ~pixel & color_data[1].pixel;
06689            }
06690            else {
06691               pixeltbl[i] = set_bits ? pixel & set_bits : ~pixel & clr_bits;
06692            }
06693        }
06694 
06695 #undef SHIFTIFY
06696 
06697        return;
06698     }
06699 
06700     /* if not TrueColor ... */
06701 
06702     if (resource.gamma != oldgamma) {
06703        XColor color;
06704 
06705        for (i = 0; i < 16; ++i) {
06706            double frac = resource.gamma > 0
06707               ? pow((double)i / 15, 1 / resource.gamma)
06708               : 1 - pow((double)(15 - i) / 15, -resource.gamma);
06709 
06710            color.red = frac
06711               * ((double)color_data[0].red - color_data[1].red)
06712               + color_data[1].red;
06713            color.green = frac
06714               * ((double)color_data[0].green - color_data[1].green)
06715               + color_data[1].green;
06716            color.blue = frac
06717               * ((double)color_data[0].blue - color_data[1].blue)
06718               + color_data[1].blue;
06719 
06720            color.pixel = resource.back_Pixel;
06721            color.flags = DoRed | DoGreen | DoBlue;
06722 
06723            if (!globals.gc.do_copy) {
06724               if (i & 1)
06725                   color.pixel |= plane_masks[0];
06726               if (i & 2)
06727                   color.pixel |= plane_masks[1];
06728               if (i & 4)
06729                   color.pixel |= plane_masks[2];
06730               if (i & 8)
06731                   color.pixel |= plane_masks[3];
06732               XStoreColor(DISP, G_colormap, &color);
06733               palette[i] = color.pixel;
06734            }
06735            else {
06736               if (XAllocColor(DISP, G_colormap, &color))
06737                   palette[i] = color.pixel;
06738               else
06739                   palette[i] = (i * 100 >= resource.density * 15)
06740                      ? resource.fore_Pixel : resource.back_Pixel;
06741            }
06742        }
06743 
06744        globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel);
06745        globals.gc.rule = globals.gc.do_copy
06746            ? globals.gc.copy
06747            : set_or_make_gc(NULL, GXor, resource.fore_Pixel, resource.back_Pixel);
06748        globals.gc.fore = globals.gc.rule;
06749        globals.gc.fore2 = NULL;
06750        oldgamma = resource.gamma;
06751     }
06752 
06753     if (mane.shrinkfactor == 1)
06754        return;
06755 
06756     if (shrink_allocated_for < mane.shrinkfactor) {
06757        if (pixeltbl != NULL)
06758            free((char *)pixeltbl);
06759        pixeltbl = xmalloc((unsigned)
06760                         (mane.shrinkfactor * mane.shrinkfactor + 1) * sizeof *pixeltbl);
06761        shrink_allocated_for = mane.shrinkfactor;
06762     }
06763 
06764     for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i) {
06765        pixeltbl[i] = palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
06766                           / (2 * mane.shrinkfactor * mane.shrinkfactor)];
06767     }
06768 }
06769 
06770 #endif /* COLOR */