news download themes documentation links










XFontImp.cc

00001 // XFontImp.cc for FbTk fluxbox toolkit
00002 // Copyright (c) 2002 Henrik Kinnunen (fluxgen@linuxmail.org)
00003 // 
00004 // Permission is hereby granted, free of charge, to any person obtaining a
00005 // copy of this software and associated documentation files (the "Software"),
00006 // to deal in the Software without restriction, including without limitation
00007 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 // and/or sell copies of the Software, and to permit persons to whom the
00009 // Software is furnished to do so, subject to the following conditions:
00010 //
00011 // The above copyright notice and this permission notice shall be included in
00012 // all copies or substantial portions of the Software.
00013 //
00014 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00017 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00019 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00020 // DEALINGS IN THE SOFTWARE.
00021 
00022 // $Id: XFontImp.cc,v 1.6 2003/09/11 20:00:09 fluxgen Exp $
00023 
00024 #include "XFontImp.hh"
00025 #include "App.hh"
00026 #include "GContext.hh"
00027 #include "FbPixmap.hh"
00028 
00029 #include <X11/Xutil.h>
00030 
00031 #include <iostream>
00032 #include <new>
00033 #include <cstdio>
00034 using namespace std;
00035 
00036 namespace FbTk {
00037 
00038 XFontImp::XFontImp(const char *fontname):m_rotfont(0), m_fontstruct(0),
00039                                          m_angle(0), m_rotate(true) {
00040     if (fontname != 0)
00041         load(fontname); 
00042 }
00043 
00044 XFontImp::~XFontImp() {
00045     if (m_fontstruct != 0)
00046         XFreeFont(App::instance()->display(), m_fontstruct);
00047     if (m_rotfont != 0)
00048         freeRotFont();
00049 }
00050 
00051 int XFontImp::ascent() const {
00052     if (m_fontstruct == 0)
00053         return 0;
00054     if (m_rotfont != 0)
00055         return m_rotfont->max_ascent;
00056         
00057     return m_fontstruct->ascent;
00058 }
00059 
00060 bool XFontImp::load(const std::string &fontname) {
00061     XFontStruct *font = XLoadQueryFont(App::instance()->display(), fontname.c_str());
00062     if (font == 0)
00063         return false;
00064     if (m_fontstruct != 0) // free old font struct, if any
00065         XFreeFont(App::instance()->display(), m_fontstruct);
00066 
00067     m_fontstruct = font; //set new font
00068 
00069     if (m_rotfont != 0) {
00070         freeRotFont(); // free old rotated font
00071         rotate(m_angle); // allocate new rotated font and rotate it to old angle
00072     }
00073 
00074     return true;
00075 }
00076 
00077 void XFontImp::drawText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y) const {
00078     if (m_fontstruct == 0)
00079         return;
00080     // use roated font functions?
00081     if (m_rotfont != 0 && m_rotate) {
00082         drawRotText(w, screen, gc, text, len, x, y);
00083         return;
00084     }
00085 
00086     Display *disp = App::instance()->display();
00087     XSetFont(disp, gc, m_fontstruct->fid);
00088     XDrawString(disp, w, gc, x, y, text, len);
00089 }
00090 
00091 unsigned int XFontImp::textWidth(const char * const text, unsigned int size) const {
00092     if (text == 0)
00093         return 0;
00094     if (m_fontstruct == 0)
00095         return 0;
00096     // check rotated font?
00097     if (m_rotfont != 0)
00098         return rotTextWidth(text, size);
00099 
00100     return XTextWidth(m_fontstruct, text, size);
00101 }
00102 
00103 unsigned int XFontImp::height() const {
00104     if (m_fontstruct == 0)
00105         return 0;
00106 
00107     return m_fontstruct->ascent + m_fontstruct->descent;
00108 }
00109 
00110 void XFontImp::rotate(float angle) {
00111     //we must have a font loaded before we rotate
00112     if (m_fontstruct == 0 || m_fontstruct->per_char == 0)
00113         return;
00114 
00115     if (m_rotfont != 0)
00116         freeRotFont();
00117 
00118     // no need for rotating, use regular font
00119     if (angle == 0) {
00120         m_angle = 0;
00121         return;
00122     }
00123 
00124     //get positive angle
00125     while (angle < 0)
00126         angle += 360;
00127 
00128     m_angle = angle;
00129 
00130     // X system default vars
00131     Display *dpy = App::instance()->display();
00132     Window rootwin = DefaultRootWindow(dpy);
00133     int screen = DefaultScreen(dpy);
00134 
00135     char text[3];
00136     int ichar, i, j, index, boxlen = 60;
00137     int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
00138     int min_char, max_char;
00139     unsigned char *vertdata, *bitdata;
00140     int ascent, descent, lbearing, rbearing;
00141 
00142     // get nearest vertical or horizontal direction 
00143     int dir = (int)((angle+45.0)/90.0)%4;
00144 
00145     if (dir == 0) // no rotation
00146         return;
00147 
00148     // create the depth 1 canvas bitmap
00149     FbTk::FbPixmap canvas(rootwin, boxlen, boxlen, 1);
00150  
00151     // create graphic context for our canvas
00152     FbTk::GContext font_gc(canvas);
00153     font_gc.setBackground(None);
00154     font_gc.setFont(m_fontstruct->fid);
00155 
00156     // allocate space for rotated font
00157     m_rotfont = new(nothrow) XRotFontStruct;
00158 
00159     if (m_rotfont == 0) {
00160         cerr<<"RotFont: out of memory"<<endl;
00161         return;
00162     }
00163    
00164     // determine which characters are defined in font
00165     min_char = m_fontstruct->min_char_or_byte2; 
00166     max_char = m_fontstruct->max_char_or_byte2;
00167  
00168     // we only want printable chars
00169     if (min_char<32)
00170         min_char = 32;
00171     if (max_char>126)
00172         max_char = 126;
00173      
00174     /* some overall font data ... */
00175     m_rotfont->dir = dir;
00176     m_rotfont->min_char = min_char;
00177     m_rotfont->max_char = max_char;
00178     m_rotfont->max_ascent = m_fontstruct->max_bounds.ascent;
00179     m_rotfont->max_descent = m_fontstruct->max_bounds.descent;   
00180     m_rotfont->height = m_rotfont->max_ascent + m_rotfont->max_descent;
00181 
00182     // font needs rotation
00183     // loop through each character
00184     for (ichar = min_char; ichar <= max_char; ichar++) {
00185         index = ichar - m_fontstruct->min_char_or_byte2;
00186 
00187         // per char dimensions ...
00188         ascent = m_rotfont->per_char[ichar-32].ascent = m_fontstruct->per_char[index].ascent;
00189         descent =  m_rotfont->per_char[ichar-32].descent = m_fontstruct->per_char[index].descent;
00190         lbearing = m_rotfont->per_char[ichar-32].lbearing = m_fontstruct->per_char[index].lbearing;
00191         rbearing = m_rotfont->per_char[ichar-32].rbearing = m_fontstruct->per_char[index].rbearing;
00192         m_rotfont->per_char[ichar-32].width = m_fontstruct->per_char[index].width;
00193 
00194         // some space chars have zero body, but a bitmap can't have
00195         if (!ascent && !descent)   
00196             ascent = m_rotfont->per_char[ichar-32].ascent =   1;
00197         if (!lbearing && !rbearing) 
00198             rbearing = m_rotfont->per_char[ichar-32].rbearing = 1;
00199 
00200         // glyph width and height when vertical
00201         vert_w = rbearing - lbearing;
00202         vert_h = ascent + descent;
00203 
00204         // width in bytes
00205         vert_len = (vert_w-1)/8+1;   
00206 
00207         font_gc.setForeground(None);        
00208         canvas.fillRectangle(font_gc.gc(),
00209                              0, 0,
00210                              boxlen, boxlen);
00211         // draw the character centre top right on canvas
00212         sprintf(text, "%c", ichar);
00213         font_gc.setForeground(1);
00214         XDrawImageString(dpy, canvas.drawable(), font_gc.gc(),
00215                          boxlen/2 - lbearing,
00216                          boxlen/2 - descent, text, 1);
00217 
00218         // reserve memory for first XImage
00219         vertdata = new unsigned char[vert_len * vert_h];
00220 
00221         XImage *I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 
00222                                   1, XYBitmap,
00223                                   0, (char *)vertdata, 
00224                                   vert_w, vert_h, 8, 0);
00225 
00226         if (I1 == None) {               
00227             cerr<<"RotFont: Cant create ximage."<<endl;
00228             delete m_rotfont;
00229             m_rotfont = 0;          
00230             return;
00231         }
00232 
00233         I1->byte_order = I1->bitmap_bit_order = MSBFirst;
00234 
00235         // extract character from canvas
00236         XGetSubImage(dpy, canvas.drawable(), 
00237                      boxlen/2, boxlen/2 - vert_h,
00238                      vert_w, vert_h, 1, XYPixmap, I1, 0, 0);
00239 
00240         I1->format = XYBitmap; 
00241 
00242         // width, height of rotated character
00243         if (dir == 2) { 
00244             bit_w = vert_w;
00245             bit_h = vert_h; 
00246         } else {
00247             bit_w = vert_h;
00248             bit_h = vert_w; 
00249         }
00250 
00251         // width in bytes
00252         bit_len = (bit_w-1)/8 + 1;
00253 
00254         m_rotfont->per_char[ichar-32].glyph.bit_w = bit_w;
00255         m_rotfont->per_char[ichar-32].glyph.bit_h = bit_h;
00256 
00257         // reserve memory for the rotated image
00258         bitdata = (unsigned char *)calloc((unsigned)(bit_h * bit_len), 1);
00259 
00260         // create the image
00261         XImage *I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
00262                           (char *)bitdata, bit_w, bit_h, 8, 0); 
00263 
00264         if (I2 == None) {
00265             cerr<<"XFontImp: Cant create ximage!"<<endl;
00266             delete m_rotfont;
00267             m_rotfont = 0;
00268             return;
00269         }
00270 
00271         I2->byte_order = I2->bitmap_bit_order = MSBFirst;
00272 
00273         // map vertical data to rotated character
00274         for (j = 0; j < bit_h; j++) {
00275             for (i = 0; i < bit_w; i++) {
00276                 char val = 0;
00277                 if (dir == 1) {
00278                     val = vertdata[i*vert_len + (vert_w-j-1)/8] &
00279                         (128>>((vert_w-j-1)%8));
00280                 } else if (dir == 2) {
00281                     val = vertdata[(vert_h-j-1)*vert_len +
00282                                    (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8));
00283                 } else {
00284                     val = vertdata[(vert_h-i-1)*vert_len + j/8] & 
00285                         (128>>(j%8));
00286                 } 
00287                 if (val) {
00288                     bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
00289                         (128>>(i%8));
00290                 }
00291             }
00292         }
00293 
00294         // create this character's bitmap 
00295         m_rotfont->per_char[ichar-32].glyph.bm = 
00296             XCreatePixmap(dpy, rootwin, bit_w, bit_h, 1);
00297  
00298         // put the image into the bitmap 
00299         XPutImage(dpy, m_rotfont->per_char[ichar-32].glyph.bm, 
00300                   font_gc.gc(), I2, 0, 0, 0, 0, bit_w, bit_h);
00301 
00302         // free the image and data
00303         XDestroyImage(I1);
00304         XDestroyImage(I2);
00305     }
00306 
00307 }
00308 
00309 void XFontImp::freeRotFont() {
00310     if (m_rotfont == 0)
00311         return;
00312     // loop through each character and free its pixmap
00313     for (int ichar = m_rotfont->min_char - 32; 
00314          ichar <= m_rotfont->max_char - 32; ++ichar) {
00315         XFreePixmap(App::instance()->display(), m_rotfont->per_char[ichar].glyph.bm);
00316     }
00317 
00318     delete m_rotfont;
00319     m_rotfont = 0;
00320 }
00321 
00322 void XFontImp::drawRotText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y) const {            
00323 
00324     Display *dpy = App::instance()->display();
00325     static GC my_gc = 0;
00326     int xp, yp, dir, ichar;
00327 
00328     if (text == NULL || len<1)
00329         return;
00330 
00331     dir = m_rotfont->dir;
00332     if (my_gc == 0)
00333         my_gc = XCreateGC(dpy, w, 0, 0);
00334 
00335     XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
00336 
00337     // vertical or upside down
00338 
00339     XSetFillStyle(dpy, my_gc, FillStippled);
00340 
00341     // loop through each character in texting
00342     for (size_t i = 0; i<len; i++) {
00343         ichar = text[i]-32;
00344 
00345         // make sure it's a printing character
00346         if (ichar >= 0 && ichar<95) {
00347             // suitable offset
00348             if (dir == 1) {
00349                 xp = x-m_rotfont->per_char[ichar].ascent;
00350                 yp = y-m_rotfont->per_char[ichar].rbearing; 
00351             } else if (dir == 2) {
00352                 xp = x-m_rotfont->per_char[ichar].rbearing;
00353                 yp = y-m_rotfont->per_char[ichar].descent+1; 
00354             } else {
00355                 xp = x-m_rotfont->per_char[ichar].descent+1;  
00356                 yp = y+m_rotfont->per_char[ichar].lbearing; 
00357             }
00358                    
00359             // draw the glyph
00360             XSetStipple(dpy, my_gc, m_rotfont->per_char[ichar].glyph.bm);
00361     
00362             XSetTSOrigin(dpy, my_gc, xp, yp);
00363       
00364             XFillRectangle(dpy, w, my_gc, xp, yp,
00365                            m_rotfont->per_char[ichar].glyph.bit_w,
00366                            m_rotfont->per_char[ichar].glyph.bit_h);
00367     
00368             // advance position
00369             if (dir == 1)
00370                 y -= m_rotfont->per_char[ichar].width;
00371             else if (dir == 2)
00372                 x -= m_rotfont->per_char[ichar].width;
00373             else 
00374                 y += m_rotfont->per_char[ichar].width;
00375         }
00376     }
00377 }
00378 
00379 
00380 unsigned int XFontImp::rotTextWidth(const char * const text, unsigned int size) const {
00381 
00382     if (text == 0)
00383         return 0;
00384 
00385     unsigned int width = 0; 
00386     for (size_t i = 0; i<size; i++) {
00387         int ichar = text[i] - 32;  
00388         // make sure it's a printing character
00389         if (ichar >= 0 && ichar < 95) 
00390             width += m_rotfont->per_char[ichar].width;
00391     }
00392 
00393     return width;
00394 }
00395 
00396 };

Fluxbox CVS-Jan-2003




      



Got comments about the page? Send them to webmaster.
If you have general Fluxbox related questions ask them on our irc channel or mailing lists.

Show Source








Designed by aLEczapKA