Back to index

texmacs  1.0.7.15
x_font.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : x_font.cpp
00004 * DESCRIPTION: server_ps_fonts and server_tex_fonts under X11
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "X11/x_window.hpp"
00013 #include "X11/x_font.hpp"
00014 #include "analyze.hpp"
00015 #include "dictionary.hpp"
00016 
00017 /******************************************************************************
00018 * Displaying characters
00019 ******************************************************************************/
00020 
00021 bool char_clip= true;
00022 
00023 #define conv(x) ((SI) (((double) (x))*(fn->unit)))
00024 
00025 void
00026 x_drawable_rep::draw_clipped (Pixmap pm, Pixmap bm, int w, int h, SI x, SI y) {
00027   int x1=cx1-ox, y1=cy2-oy, x2= cx2-ox, y2= cy1-oy;
00028   decode (x , y );
00029   decode (x1, y1);
00030   decode (x2, y2);
00031   y--; // top-left origin to bottom-left origin conversion
00032   int X1= max (x1- x, 0); if (X1>=w) return;
00033   int Y1= max (y1- y, 0); if (Y1>=h) return;
00034   int X2= min (x2- x, w); if (X2<0) return;
00035   int Y2= min (y2- y, h); if (Y2<0) return;
00036 
00037   if (char_clip) {
00038 #ifdef OS_WIN32_LATER
00039     /*
00040     int X, Y, N;
00041     for (Y=Y1; Y<Y2; Y++) {
00042       for (X=X1, N=0; X<X2; X++) {
00043        if (XGetBitmapPixel (bm, X, Y)) N++;
00044        else {
00045          if (N > 0)
00046            XCopyArea (dpy, (Drawable)pm, win, gc, X-N, Y, N, 1, x+X1-N, y+Y1);
00047          N= 0;
00048        }
00049       }
00050       if (N > 0)
00051        XCopyArea (dpy, (Drawable)pm, win, gc, X, Y-N, N, 1, x+X1-N, y+Y1);
00052     }
00053     */
00054     XCopyClipped (dpy, (Drawable) pm, (Drawable) bm, win, gc,
00055                 X, Y-N, N, 1, x+X1-N, y+Y1);
00056     // FIXME: Dan should write a routine for this.
00057 #else
00058     XSetClipMask (dpy, gc, bm);
00059     XSetClipOrigin (dpy, gc, x, y);
00060     XCopyArea (dpy, (Drawable) pm, win, gc, X1, Y1, X2-X1, Y2-Y1, x+X1, y+Y1);
00061     set_clipping (cx1- ox, cy1- oy, cx2- ox, cy2- oy);
00062 #endif
00063   }
00064   else
00065     XCopyArea (dpy, (Drawable) pm, win, gc, X1, Y1, X2-X1, Y2-Y1, x+X1, y+Y1);
00066 }
00067 
00068 void
00069 x_drawable_rep::draw (int c, font_glyphs fng, SI x, SI y) {
00070   // get the pixmap
00071   x_character xc (c, fng, sfactor, cur_fg, cur_bg);
00072   Pixmap pm= (Pixmap) gui->character_pixmap [xc];
00073   if (pm == 0) {
00074     gui->prepare_color (sfactor, cur_fg, cur_bg);
00075     x_character col_entry (0, font_glyphs (), sfactor, cur_fg, cur_bg);
00076     color* cols= (color*) gui->color_scale [col_entry];
00077     SI xo, yo;
00078     glyph pre_gl= fng->get (c); if (is_nil (pre_gl)) return;
00079     glyph gl= shrink (pre_gl, sfactor, sfactor, xo, yo);
00080     int i, j, w= gl->width, h= gl->height;
00081     pm= XCreatePixmap (gui->dpy, gui->root, w, h, gui->depth);
00082     for (j=0; j<h; j++)
00083       for (i=0; i<w; i++) {
00084        color col= cols [gl->get_x(i,j)];
00085        XSetForeground (gui->dpy, gui->pixmap_gc, CONVERT (col));
00086        XDrawPoint (gui->dpy, (Drawable) pm, gui->pixmap_gc, i, j);
00087       }
00088     gui->character_pixmap (xc)= (pointer) pm;
00089   }
00090 
00091   // get the bitmap
00092   xc= x_character (c, fng, sfactor, 0, 0);
00093   Bitmap bm= (Bitmap) gui->character_bitmap [xc];
00094   if (bm == NULL) {
00095     SI xo, yo;
00096     glyph pre_gl= fng->get (c); if (is_nil (pre_gl)) return;
00097     glyph gl= shrink (pre_gl, sfactor, sfactor, xo, yo);
00098     int i, j, b, on, w= gl->width, h= gl->height;
00099     int byte_width= ((w-1)>>3)+1;
00100     char* data= tm_new_array<char> (byte_width * h);
00101     for (i=0; i<(byte_width * h); i++) data[i]=0;
00102 
00103     for (j=0; j<h; j++)
00104       for (i=0; i<w; i++) {
00105        b = j*byte_width + (i>>3);
00106        on= (gl->get_x(i,j)!=0 ? 1:0);
00107        if (on) data[b]= data[b] | (1<<(i&7));
00108       }
00109     bm= tm_new<Bitmap_rep> ();
00110     bm->bm    = XCreateBitmapFromData (gui->dpy, gui->root, data, w, h);
00111     bm->width = gl->width;
00112     bm->height= gl->height;
00113     bm->xoff  = xo;
00114     bm->yoff  = yo;
00115     gui->character_bitmap (xc)= (pointer) bm;
00116     tm_delete_array (data);
00117   }
00118 
00119   // draw the character
00120   draw_clipped (pm, bm->bm, bm->width, bm->height,
00121               x- bm->xoff*sfactor, y+ bm->yoff*sfactor);
00122 }
00123 
00124 #undef conv
00125 
00126 /******************************************************************************
00127 * Server fonts
00128 ******************************************************************************/
00129 
00130 static string the_default_font ("");
00131 font the_default_wait_font;
00132 
00133 void
00134 x_gui_rep::set_default_font (string name) {
00135   the_default_font= name;
00136 }
00137 
00138 font
00139 x_gui_rep::default_font_sub (bool tt, bool mini, bool bold) {
00140   string s= the_default_font;
00141   string series= (bold? string ("bold"): string ("medium"));
00142   if (s == "") s= "ecrm11@300";
00143   int i, j, n= N(s);
00144   for (j=0; j<n; j++) if ((s[j] >= '0') && (s[j] <= '9')) break;
00145   string fam= s (0, j);
00146   if (mini && fam == "ecrm") fam= "ecss";
00147   if (bold && fam == "ecrm") fam= "ecbx";
00148   if (bold && fam == "ecss") fam= "ecsx";
00149   for (i=j; j<n; j++) if (s[j] == '@') break;
00150   int sz= (j<n? as_int (s (i, j)): 10);
00151   if (j<n) j++;
00152   int dpi= (j<n? as_int (s (j, n)): 300);
00153   if (mini) { sz= (int) (0.6 * sz); dpi= (int) (1.3333333 * dpi); }
00154   if (use_macos_fonts ()) {
00155     tree lucida_fn= tuple ("apple-lucida", "ss", series, "right");
00156     lucida_fn << as_string (sz) << as_string ((int) (0.95 * dpi));
00157     return find_font (lucida_fn);
00158   }
00159   if (N(fam) >= 2) {
00160     string ff= fam (0, 2);
00161     string out_lan= get_output_language ();
00162     if (((out_lan == "bulgarian") || (out_lan == "russian") ||
00163         (out_lan == "ukrainian")) &&
00164        ((ff == "cm") || (ff == "ec"))) {
00165       fam= "la" * fam (2, N(fam)); ff= "la"; if (sz<100) sz *= 100; }
00166     if (out_lan == "japanese" || out_lan == "korean") {
00167       tree modern_fn= tuple ("modern", "ss", series, "right");
00168       modern_fn << as_string (sz) << as_string (dpi);
00169       return find_font (modern_fn);
00170     }
00171     if (out_lan == "chinese" || out_lan == "taiwanese")
00172       return unicode_font ("fireflysung", sz, dpi);
00173     //if (out_lan == "japanese")
00174     //return unicode_font ("ipagui", sz, dpi);
00175     //if (out_lan == "korean")
00176     //return unicode_font ("UnDotum", sz, dpi);
00177     if (ff == "ec")
00178       return tex_ec_font (tt? ff * "tt": fam, sz, dpi);
00179     if (ff == "la")
00180       return tex_la_font (tt? ff * "tt": fam, sz, dpi, 1000);
00181     if (ff == "pu") tt= false;
00182     if ((ff == "cm") || (ff == "pn") || (ff == "pu"))
00183       return tex_cm_font (tt? ff * "tt": fam, sz, dpi);
00184   }
00185   return tex_font (fam, sz, dpi);
00186   // if (out_lan == "german") return tex_font ("ygoth", 14, 300, 0);
00187   // return tex_font ("rpagk", 10, 300, 0);
00188   // return tex_font ("rphvr", 10, 300, 0);
00189   // return ps_font ("b&h-lucidabright-medium-r-normal", 11, 300);
00190 }
00191 
00192 font
00193 x_gui_rep::default_font (bool tt, bool mini, bool bold) {
00194   font fn= default_font_sub (tt, mini, bold);
00195   if (!tt && !mini) the_default_wait_font= fn;
00196   return fn;
00197 }
00198 
00199 void
00200 set_default_font (string name) {
00201   the_gui->set_default_font (name);
00202 }
00203 
00204 font
00205 get_default_font (bool tt, bool mini, bool bold) {
00206   return the_gui->default_font (tt, mini, bold);
00207 }
00208 
00209 /******************************************************************************
00210 * Loading postscript fonts
00211 ******************************************************************************/
00212 
00213 void
00214 x_gui_rep::get_ps_char (Font fn, int c, metric& ex, glyph& gl) {
00215   XCharStruct xcs;
00216   int i1, i2, i3;
00217   char temp[1]; temp[0]= (char) c;
00218 
00219   XQueryTextExtents (dpy, fn, temp, 1, &i1, &i2, &i3, &xcs);
00220   ex->x1= 0;
00221   ex->y1= (-1-xcs.descent) * PIXEL;
00222   ex->x2= xcs.width * PIXEL;
00223   ex->y2= (-1+xcs.ascent) * PIXEL;
00224   ex->x3= xcs.lbearing * PIXEL;
00225   ex->y3= (-1-xcs.descent) * PIXEL;
00226   ex->x4= xcs.rbearing * PIXEL;
00227   ex->y4= (-1+xcs.ascent) * PIXEL;
00228 
00229   int w   = xcs.rbearing- xcs.lbearing;
00230   int h   = xcs.ascent+ xcs.descent;
00231   int xoff=  -xcs.lbearing;
00232   int yoff= h-xcs.descent ;
00233   if ((w == 0) || (h == 0)) return;
00234 
00235   Pixmap pm= XCreatePixmap (dpy, root, w, h, depth);
00236   XSetForeground (dpy, pixmap_gc, white);
00237   XFillRectangle (dpy, pm, pixmap_gc, 0, 0, w, h);
00238   XSetForeground (dpy, pixmap_gc, black);
00239   XSetFont (dpy, pixmap_gc, fn);
00240   XDrawString (dpy, pm, pixmap_gc, xoff, yoff, temp, 1);
00241   XImage* im= XGetImage (dpy, pm, 0, 0, w, h, 0xffffffff, ZPixmap);
00242 
00243   int i, j;
00244   gl= glyph (w, h, xoff, yoff);
00245   for (j=0; j<h; j++)
00246     for (i=0; i<w; i++) {
00247       int c = im->f.get_pixel (im, i, j);
00248       int on= (((color) c) == black? 1: 0);
00249       gl->set_x (i, j, on);
00250     }
00251   gl->lwidth= xcs.width;
00252 
00253   im->f.destroy_image (im);
00254   XFreePixmap (dpy, pm);
00255 }
00256 
00257 void
00258 x_gui_rep::load_system_font (string family, int size, int dpi,
00259                           font_metric& fnm, font_glyphs& fng)
00260 {
00261   string fn_name= "ps:" * family * as_string (size) * "@" * as_string (dpi);
00262   if (font_metric::instances -> contains (fn_name)) {
00263     fnm= font_metric (fn_name);
00264     fng= font_glyphs (fn_name);
00265   }
00266 
00267   string name= "-" * family;
00268   string sz1= as_string ((size*dpi)/72);
00269   string sz2= as_string (10*((size*dpi)/72));
00270   name << "-*-" * sz1 * "-" * sz2 * "-*-*-*-*-*-*";
00271   if (size == 0) name= family;
00272 
00273   if (DEBUG_VERBOSE) cout << "TeXmacs] Loading ps font " << name << "\n";
00274   char* temp= as_charp (name);
00275   XFontStruct *xfs = XLoadQueryFont (dpy, temp);
00276   tm_delete_array (temp);
00277   if (xfs == NULL) {
00278     if (DEBUG_VERBOSE) cout << "TeXmacs] Font " << name << " not found\n";
00279     if (DEBUG_VERBOSE) cout << "TeXmacs] Using default font instead\n";
00280     xfs = XLoadQueryFont (dpy, "*");
00281     ASSERT (xfs != NULL, "could not load default X font");
00282   }
00283   Font fn = xfs->fid;
00284   int i;
00285   metric* texs= tm_new_array<metric> (256);
00286   glyph * gls = tm_new_array<glyph> (256);
00287   for (i=0; i<=255; i++)
00288     get_ps_char (fn, i, texs[i], gls[i]);
00289   fnm= std_font_metric (fn_name, texs, 0, 255);
00290   fng= std_font_glyphs (fn_name, gls , 0, 255);
00291 
00292   XFreeFont(dpy, xfs);
00293 }
00294 
00295 void
00296 load_system_font (string family, int size, int dpi,
00297                 font_metric& fnm, font_glyphs& fng)
00298 {
00299   the_gui->load_system_font (family, size, dpi, fnm, fng);
00300 }
00301 
00302 /******************************************************************************
00303 * The implementation
00304 ******************************************************************************/
00305 
00306 x_font_rep::x_font_rep (string name, string family2, int size2, int dpi2):
00307   font_rep (name)
00308 {
00309   metric ex;
00310   load_system_font (family2, size2, dpi2, fnm, fng);
00311 
00312   family       = family2;
00313   size         = size2;
00314   dpi          = dpi2;
00315 
00316   // get main font parameters
00317   get_extents ("f", ex);
00318   y1= ex->y1;
00319   y2= ex->y2;
00320   display_size = y2-y1;
00321   design_size  = size << 8;
00322 
00323   // get character dimensions
00324   get_extents ("x", ex);
00325   yx           = ex->y2;
00326   get_extents ("M", ex);
00327   wquad        = ex->x2;
00328 
00329   // compute other heights
00330   yfrac        = yx >> 1;
00331   ysub_lo_base = -yx/3;
00332   ysub_hi_lim  = (5*yx)/6;
00333   ysup_lo_lim  = yx/2;
00334   ysup_lo_base = (5*yx)/6;
00335   ysup_hi_lim  = yx;
00336   yshift       = yx/6;
00337 
00338   // compute other widths
00339   wpt          = (dpi*PIXEL)/72;
00340   wfn          = (wpt*design_size) >> 8;
00341   wline        = wfn/20;
00342 
00343   // get fraction bar parameters
00344   get_extents ("-", ex);
00345   yfrac= (ex->y3 + ex->y4) >> 1;
00346 
00347   // get space length
00348   get_extents (" ", ex);
00349   spc  = space ((3*(ex->x2-ex->x1))>>2, ex->x2-ex->x1, (ex->x2-ex->x1)<<1);
00350   extra= spc;
00351   sep  = wfn/10;
00352 
00353   // get_italic space
00354   get_extents ("f", ex);
00355   SI italic_spc= (ex->x4-ex->x3)-(ex->x2-ex->x1);
00356   slope= ((double) italic_spc) / ((double) display_size);
00357   if (slope<0.15) slope= 0.0;
00358 }
00359 
00360 void
00361 x_font_rep::get_extents (string s, metric& ex) {
00362   if (N(s)==0) {
00363     ex->x1= ex->x3= ex->x2= ex->x4=0;
00364     ex->y3= ex->y1= 0; ex->y4= ex->y2= yx;
00365   }
00366   else {
00367     QN c= s[0];
00368     metric_struct* first= fnm->get (c);
00369     ex->x1= first->x1; ex->y1= first->y1;
00370     ex->x2= first->x2; ex->y2= first->y2;
00371     ex->x3= first->x3; ex->y3= first->y3;
00372     ex->x4= first->x4; ex->y4= first->y4;
00373     SI x= first->x2;
00374 
00375     int i;
00376     for (i=1; i<N(s); i++) {
00377       QN c= s[i];
00378       metric_struct* next= fnm->get (c);
00379       ex->x1= min (ex->x1, x+ next->x1); ex->y1= min (ex->y1, next->y1);
00380       ex->x2= max (ex->x2, x+ next->x2); ex->y2= max (ex->y2, next->y2);
00381       ex->x3= min (ex->x3, x+ next->x3); ex->y3= min (ex->y3, next->y3);
00382       ex->x4= max (ex->x4, x+ next->x4); ex->y4= max (ex->y4, next->y4);
00383       x += next->x2;
00384     }
00385   }
00386 }
00387 
00388 void
00389 x_font_rep::get_xpositions (string s, SI* xpos) {
00390   register int i, n= N(s);
00391   if (n == 0) return;
00392   
00393   register SI x= 0;
00394   for (i=0; i<N(s); i++) {
00395     metric_struct* next= fnm->get ((QN) s[i]);
00396     x += next->x2;
00397     xpos[i+1]= x;
00398   }
00399 }
00400 
00401 void
00402 x_font_rep::draw (renderer ren, string s, SI x, SI y) {
00403   if (N(s)!=0) {
00404     int i;
00405     for (i=0; i<N(s); i++) {
00406       QN c= s[i];
00407       ren->draw (c, fng, x, y);
00408       metric_struct* ex= fnm->get (c);
00409       x += ex->x2;
00410     }
00411   }
00412 }
00413 
00414 glyph
00415 x_font_rep::get_glyph (string s) {
00416   if (N(s)!=1) return font_rep::get_glyph (s);
00417   int c= ((QN) s[0]);
00418   glyph gl= fng->get (c);
00419   if (is_nil (gl)) return font_rep::get_glyph (s);
00420   return gl;
00421 }
00422 
00423 /******************************************************************************
00424 * Interface
00425 ******************************************************************************/
00426 
00427 font
00428 x_font (string family, int size, int dpi) {
00429   string name= "ps:" * family * as_string (size) * "@" * as_string (dpi);
00430   if (font::instances -> contains (name)) return font (name);
00431   else return tm_new<x_font_rep> (name, family, size, dpi);
00432 }