00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 #include "TGFont.h"
00037 #include "TGClient.h"
00038 #include "THashTable.h"
00039 #include "TVirtualX.h"
00040 #include "TObjString.h"
00041 #include "TGWidget.h"
00042 #include <errno.h>
00043 #include <stdlib.h>
00044 #include <limits.h>
00045 
00046 #include "Riostream.h"
00047 #include "TROOT.h"
00048 #include "TError.h"
00049 #include "TMath.h"
00050 
00051 
00052 ClassImp(TGFont)
00053 ClassImp(TGFontPool)
00054 ClassImp(TGTextLayout)
00055 
00056 #define FONT_FAMILY     0
00057 #define FONT_SIZE       1
00058 #define FONT_WEIGHT     2
00059 #define FONT_SLANT      3
00060 #define FONT_UNDERLINE  4
00061 #define FONT_OVERSTRIKE 5
00062 #define FONT_NUMFIELDS  6
00063 
00064 
00065 
00066 
00067 #define XLFD_FOUNDRY        0
00068 #define XLFD_FAMILY         1
00069 #define XLFD_WEIGHT         2
00070 #define XLFD_SLANT          3
00071 #define XLFD_SETWIDTH       4
00072 #define XLFD_ADD_STYLE      5
00073 #define XLFD_PIXEL_SIZE     6
00074 #define XLFD_POINT_SIZE     7
00075 #define XLFD_RESOLUTION_X   8
00076 #define XLFD_RESOLUTION_Y   9
00077 #define XLFD_SPACING        10
00078 #define XLFD_AVERAGE_WIDTH  11
00079 #define XLFD_REGISTRY       12
00080 #define XLFD_ENCODING       13
00081 #define XLFD_NUMFIELDS      14   // Number of fields in XLFD.
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 struct LayoutChunk_t {
00092 
00093    const char *fStart;     
00094                            
00095                            
00096    Int_t fNumChars;        
00097    Int_t fNumDisplayChars; 
00098                            
00099                            
00100                            
00101                            
00102                            
00103    Int_t fX;               
00104    Int_t fY;               
00105                            
00106                            
00107    Int_t fTotalWidth;      
00108                            
00109                            
00110    Int_t fDisplayWidth;    
00111                            
00112                            
00113                            
00114 };
00115 
00116 
00117 
00118 
00119 
00120 struct XLFDAttributes_t {
00121    FontAttributes_t fFA; 
00122    const char *fFoundry; 
00123    Int_t fSlant;         
00124    Int_t fSetwidth;      
00125    Int_t fCharset;       
00126    Int_t fEncoding;      
00127 
00128    XLFDAttributes_t() :  
00129       fFA(),
00130       fFoundry(0),
00131       fSlant(0),
00132       fSetwidth(0),
00133       fCharset(0),
00134       fEncoding(0) { }
00135 };
00136 
00137 
00138 
00139 
00140 
00141 
00142 class TNamedFont : public TObjString, public TRefCnt {
00143 public:
00144    Int_t            fDeletePending; 
00145    FontAttributes_t fFA;            
00146 };
00147 
00148 
00149 enum EFontSpacing { kFontProportional = 0,
00150                     kFontFixed = 1,
00151                     kFontMono = 1,
00152                     kFontCharcell = 2 };
00153 
00154 enum EFontSetWidth { kFontSWNormal = 0,
00155                      kFontSWCondence = 1,
00156                      kFontSWExpand = 2,
00157                      kFontSWUnknown = 3 };
00158 
00159 enum EFontCharset { kFontCSNormal = 0,
00160                     kFontCSSymbol = 1,
00161                     kFontCSOther = 2 };
00162 
00163 
00164 
00165 
00166 
00167 
00168 
00169 
00170 
00171 
00172 
00173 
00174 
00175 
00176 
00177 enum ECharType { kCharNormal, kCharReplace, kCharSkip };
00178 
00179 
00180 
00181 
00182 
00183 
00184 struct FontStateMap_t { Int_t fNumKey; const char *fStrKey; };
00185 
00186 static const FontStateMap_t gWeightMap[] = {
00187    { kFontWeightNormal,  "normal" },
00188    { kFontWeightBold,    "bold"   },
00189    { kFontWeightUnknown, 0        }
00190 };
00191 
00192 static const FontStateMap_t gSlantMap[] = {
00193    { kFontSlantRoman,   "roman"  },
00194    { kFontSlantItalic,  "italic" },
00195    { kFontSlantUnknown, 0        }
00196 };
00197 
00198 static const FontStateMap_t gUnderlineMap[] = {
00199    { 1, "underline" },
00200    { 0, 0           }
00201 };
00202 
00203 static const FontStateMap_t gOverstrikeMap[] = {
00204    { 1, "overstrike" },
00205    { 0, 0            }
00206 };
00207 
00208 
00209 
00210 
00211 static const FontStateMap_t gXlfdgWeightMap[] = {
00212    { kFontWeightNormal, "normal"   },
00213    { kFontWeightNormal, "medium"   },
00214    { kFontWeightNormal, "book"     },
00215    { kFontWeightNormal, "light"    },
00216    { kFontWeightBold,   "bold"     },
00217    { kFontWeightBold,   "demi"     },
00218    { kFontWeightBold,   "demibold" },
00219    { kFontWeightNormal,  0         }  
00220 };
00221 
00222 static const FontStateMap_t gXlfdSlantMap[] = {
00223    { kFontSlantRoman,   "r"  },
00224    { kFontSlantItalic,  "i"  },
00225    { kFontSlantOblique, "o"  },
00226    { kFontSlantRoman,   0    }  
00227 };
00228 
00229 static const FontStateMap_t gXlfdSetwidthMap[] = {
00230    { kFontSWNormal,   "normal"        },
00231    { kFontSWCondence, "narrow"        },
00232    { kFontSWCondence, "semicondensed" },
00233    { kFontSWCondence, "condensed"     },
00234    { kFontSWUnknown,  0               }
00235 };
00236 
00237 static const FontStateMap_t gXlfdCharsetMap[] = {
00238    { kFontCSNormal, "iso8859" },
00239    { kFontCSSymbol, "adobe"   },
00240    { kFontCSSymbol, "sun"     },
00241    { kFontCSOther,  0         }
00242 };
00243 
00244 
00245 
00246 
00247 static char gHexChars[] = "0123456789abcdefxtnvr\\";
00248 
00249 
00250 
00251 
00252 
00253 
00254 static char gMapChars[] = {
00255    0, 0, 0, 0, 0, 0, 0, 'a', 'b', 't', 'n', 'v', 'f', 'r', 0
00256 };
00257 
00258 static int GetControlCharSubst(int c, char buf[4]);
00259 
00260 
00261 
00262 TGFont::~TGFont()
00263 {
00264    
00265 
00266    if (fFontStruct) {
00267       gVirtualX->DeleteFont(fFontStruct);
00268    }
00269 }
00270 
00271 
00272 void TGFont::GetFontMetrics(FontMetrics_t *m) const
00273 {
00274    
00275 
00276    if (!m) {
00277       Error("GetFontMetrics", "argument may not be 0");
00278       return;
00279    }
00280 
00281    *m = fFM;
00282    m->fLinespace = fFM.fAscent + fFM.fDescent;
00283 }
00284 
00285 
00286 FontStruct_t TGFont::operator()() const
00287 {
00288    
00289 
00290    return fFontStruct;
00291 }
00292 
00293 
00294 void TGFont::Print(Option_t *option) const
00295 {
00296    
00297 
00298    TString opt = option;
00299 
00300    if ((opt == "full") && fNamedHash) {
00301       Printf("TGFont: %s, %s, ref cnt = %u",
00302               fNamedHash->GetName(),
00303               fFM.fFixed ? "fixed" : "prop", References());
00304    } else {
00305       Printf("TGFont: %s, %s, ref cnt = %u", fName.Data(),
00306               fFM.fFixed ? "fixed" : "prop", References());
00307    }
00308 }
00309 
00310 
00311 Int_t TGFont::PostscriptFontName(TString *dst) const
00312 {
00313    
00314    
00315    
00316    
00317    
00318    
00319    
00320    
00321    
00322    
00323    
00324    
00325    
00326    
00327    
00328    
00329    
00330    
00331    
00332 
00333    const char *family;
00334    TString weightString;
00335    TString slantString;
00336    char *src, *dest;
00337    Int_t upper, len;
00338 
00339    len = dst->Length();
00340 
00341    
00342    
00343    
00344 
00345    family = fFA.fFamily;
00346    if (strncasecmp(family, "itc ", 4) == 0) {
00347       family = family + 4;
00348    }
00349    if ((strcasecmp(family, "Arial") == 0)
00350        || (strcasecmp(family, "Geneva") == 0)) {
00351       family = "Helvetica";
00352    } else if ((strcasecmp(family, "Times New Roman") == 0)
00353               || (strcasecmp(family, "New York") == 0)) {
00354       family = "Times";
00355    } else if ((strcasecmp(family, "Courier New") == 0)
00356               || (strcasecmp(family, "Monaco") == 0)) {
00357       family = "Courier";
00358    } else if (strcasecmp(family, "AvantGarde") == 0) {
00359       family = "AvantGarde";
00360    } else if (strcasecmp(family, "ZapfChancery") == 0) {
00361       family = "ZapfChancery";
00362    } else if (strcasecmp(family, "ZapfDingbats") == 0) {
00363       family = "ZapfDingbats";
00364    } else {
00365 
00366       
00367       
00368       
00369       
00370 
00371       dst->Append(family);
00372 
00373       src = dest = (char*)dst->Data() + len;
00374       upper = 1;
00375       for (; *src != '\0'; src++, dest++) {
00376          while (isspace(UChar_t(*src))) {
00377             src++;
00378             upper = 1;
00379          }
00380          *dest = *src;
00381          if ((upper != 0) && (islower(UChar_t(*src)))) {
00382             *dest = toupper(UChar_t(*src));
00383          }
00384          upper = 0;
00385       }
00386       *dest = '\0';
00387       
00388       family = (char *) dst->Data() + len;
00389    }
00390    if (family != (char *) dst->Data() + len) {
00391       dst->Append(family);
00392       family = (char *) dst->Data() + len;
00393    }
00394    if (strcasecmp(family, "NewCenturySchoolbook") == 0) {
00395 
00396       dst->Append("NewCenturySchlbk");
00397       family = (char *) dst->Data() + len;
00398    }
00399 
00400    
00401 
00402    weightString = "";
00403    if (fFA.fWeight == kFontWeightNormal) {
00404       if (strcmp(family, "Bookman") == 0) {
00405          weightString = "Light";
00406       } else if (strcmp(family, "AvantGarde") == 0) {
00407          weightString = "Book";
00408       } else if (strcmp(family, "ZapfChancery") == 0) {
00409          weightString = "Medium";
00410       }
00411    } else {
00412       if ((strcmp(family, "Bookman") == 0)
00413            || (strcmp(family, "AvantGarde") == 0)) {
00414          weightString = "Demi";
00415       } else {
00416          weightString = "Bold";
00417       }
00418    }
00419 
00420    
00421 
00422    slantString = "";
00423    if (fFA.fSlant == kFontSlantRoman) {
00424       ;
00425    } else {
00426       if ((strcmp(family, "Helvetica") == 0)
00427            || (strcmp(family, "Courier") == 0)
00428            || (strcmp(family, "AvantGarde") == 0)) {
00429          slantString = "Oblique";
00430       } else {
00431          slantString = "Italic";
00432       }
00433    }
00434 
00435    
00436    
00437 
00438    if ((slantString.IsNull()) && (weightString.IsNull())) {
00439       if ((strcmp(family, "Times") == 0)
00440            || (strcmp(family, "NewCenturySchlbk") == 0)
00441            || (strcmp(family, "Palatino") == 0)) {
00442          dst->Append("-Roman");
00443       }
00444    } else {
00445       dst->Append("-");
00446       if (!weightString.IsNull()) dst->Append(weightString);
00447       if (!slantString.IsNull()) dst->Append(slantString);
00448    }
00449 
00450    return fFA.fPointsize;
00451 }
00452 
00453 
00454 Int_t TGFont::MeasureChars(const char *source, Int_t numChars, Int_t maxLength,
00455                           Int_t flags, Int_t *length) const
00456 {
00457    
00458    
00459    
00460    
00461    
00462    
00463    
00464    
00465    
00466    
00467    
00468    
00469    
00470    
00471    
00472    
00473    
00474    
00475    
00476    
00477    
00478 
00479    const char *p;    
00480    const char *term; 
00481    Int_t termX;      
00482    Int_t curX;       
00483    Int_t newX;       
00484    Int_t c, sawNonSpace;
00485 
00486    if (!numChars) {
00487       *length = 0;
00488       return 0;
00489    }
00490    if (maxLength <= 0) {
00491       maxLength = INT_MAX;
00492    }
00493    newX = curX = termX = 0;
00494    p = term = source;
00495    sawNonSpace = !isspace(UChar_t(*p));
00496 
00497    
00498 
00499    for (c = UChar_t(*p);;) {
00500       newX += fWidths[c];
00501       if (newX > maxLength) {
00502          break;
00503       }
00504       curX = newX;
00505       numChars--;
00506       p++;
00507       if (!numChars) {
00508          term = p;
00509          termX = curX;
00510          break;
00511       }
00512       c = UChar_t(*p);
00513       if (isspace(c)) {
00514          if (sawNonSpace) {
00515             term = p;
00516             termX = curX;
00517             sawNonSpace = 0;
00518          }
00519       } else {
00520          sawNonSpace = 1;
00521       }
00522    }
00523 
00524    
00525    
00526 
00527    if ((flags & kTextPartialOK) && (numChars > 0) && (curX < maxLength)) {
00528 
00529       
00530       
00531       
00532 
00533       numChars--;
00534       curX = newX;
00535       p++;
00536    }
00537    if ((flags & kTextAtLeastOne) && (term == source) && (numChars > 0)) {
00538       term = p;
00539       termX = curX;
00540       if (term == source) {
00541          term++;
00542          termX = newX;
00543       }
00544    } else if ((numChars == 0) || !(flags & kTextWholeWords)) {
00545       term = p;
00546       termX = curX;
00547    }
00548    *length = termX;
00549 
00550    return term - source;
00551 }
00552 
00553 
00554 Int_t TGFont::TextWidth(const char *string, Int_t numChars) const
00555 {
00556    
00557    
00558    
00559    
00560    
00561    
00562    
00563    
00564 
00565    Int_t width;
00566 
00567    if (numChars < 0) {
00568       numChars = strlen(string);
00569    }
00570    MeasureChars(string, numChars, 0, 0, &width);
00571 
00572    return width;
00573 }
00574 
00575 
00576 Int_t TGFont::XTextWidth(const char *string, Int_t numChars) const
00577 {
00578    
00579 
00580    int width;
00581 
00582    if (numChars < 0) {
00583       numChars = strlen(string);
00584    }
00585    width = gVirtualX->TextWidth(fFontStruct, string, numChars);
00586 
00587    return width;
00588 }
00589 
00590 
00591 void TGFont::UnderlineChars(Drawable_t dst, GContext_t gc,
00592                             const char *string, Int_t x, Int_t y,
00593                             Int_t firstChar, Int_t lastChar) const
00594 {
00595    
00596    
00597    
00598    
00599    
00600    
00601    
00602    
00603    
00604    
00605    
00606    
00607    
00608 
00609    Int_t startX, endX;
00610 
00611    MeasureChars(string, firstChar, 0, 0, &startX);
00612    MeasureChars(string, lastChar, 0, 0, &endX);
00613 
00614    gVirtualX->FillRectangle(dst, gc, x + startX, y + fUnderlinePos,
00615                             (UInt_t) (endX - startX),
00616                             (UInt_t) fUnderlineHeight);
00617 }
00618 
00619 
00620 TGTextLayout *TGFont::ComputeTextLayout(const char *string, Int_t numChars,
00621                                         Int_t wrapLength, Int_t justify, Int_t flags,
00622                                         UInt_t *width, UInt_t *height) const
00623 {
00624    
00625    
00626    
00627    
00628    
00629    
00630    
00631    
00632    
00633    
00634    
00635    
00636    
00637    
00638    
00639    
00640    
00641    
00642    
00643    
00644    
00645    
00646    
00647    
00648    
00649    
00650    
00651    
00652 
00653    const char *start, *end, *special;
00654    Int_t n, y=0, charsThisChunk, maxChunks;
00655    Int_t baseline, h, curX, newX, maxWidth;
00656    TGTextLayout *layout;
00657    LayoutChunk_t *chunk;
00658 
00659 #define MAX_LINES 50
00660    Int_t staticLineLengths[MAX_LINES];
00661    Int_t *lineLengths;
00662    Int_t maxLines, curLine, layoutHeight;
00663 
00664    lineLengths = staticLineLengths;
00665    maxLines = MAX_LINES;
00666 
00667    h = fFM.fAscent + fFM.fDescent;
00668 
00669    if (numChars < 0) {
00670       numChars = strlen(string);
00671    }
00672    maxChunks = 0;
00673 
00674    layout = new TGTextLayout;
00675    layout->fFont = this;
00676    layout->fString = string;
00677    layout->fNumChunks = 0;
00678    layout->fChunks = 0;
00679 
00680    baseline = fFM.fAscent;
00681    maxWidth = 0;
00682 
00683    
00684 
00685    curX = 0;
00686 
00687    end = string + numChars;
00688    special = string;
00689 
00690    flags &= kTextIgnoreTabs | kTextIgnoreNewlines;
00691    flags |= kTextWholeWords | kTextAtLeastOne;
00692    curLine = 0;
00693 
00694    for (start = string; start < end;) {
00695       if (start >= special) {
00696          
00697 
00698          for (special = start; special < end; special++) {
00699             if (!(flags & kTextIgnoreNewlines)) {
00700                if ((*special == '\n') || (*special == '\r')) {
00701                   break;
00702                }
00703             }
00704             if (!(flags & kTextIgnoreTabs)) {
00705                if (*special == '\t') {
00706                   break;
00707                }
00708             }
00709          }
00710       }
00711 
00712       
00713       
00714 
00715       chunk = 0;
00716       if (start < special) {
00717          charsThisChunk = MeasureChars(start, special - start,
00718                                        wrapLength - curX, flags, &newX);
00719          newX += curX;
00720          flags &= ~kTextAtLeastOne;
00721          if (charsThisChunk > 0) {
00722             chunk = NewChunk(layout, &maxChunks, start,
00723                              charsThisChunk, curX, newX, baseline);
00724 
00725             start += charsThisChunk;
00726             curX = newX;
00727          }
00728       }
00729       if ((start == special) && (special < end)) {
00730 
00731          
00732 
00733          chunk = 0;
00734          if (*special == '\t') {
00735             newX = curX + fTabWidth;
00736             newX -= newX % fTabWidth;
00737             NewChunk(layout, &maxChunks, start, 1, curX, newX, baseline)->fNumDisplayChars = -1;
00738             start++;
00739             if ((start < end) && ((wrapLength <= 0) || (newX <= wrapLength))) {
00740 
00741                
00742 
00743                curX = newX;
00744                flags &= ~kTextAtLeastOne;
00745                continue;
00746             }
00747          } else {
00748             NewChunk(layout, &maxChunks, start, 1, curX, 1000000000, baseline)->fNumDisplayChars = -1;
00749             start++;
00750             goto wrapLine;
00751          }
00752       }
00753 
00754       
00755       
00756       
00757 
00758       while ((start < end) && isspace(UChar_t(*start))) {
00759          if (!(flags & kTextIgnoreNewlines)) {
00760             if ((*start == '\n') || (*start == '\r')) {
00761                break;
00762             }
00763          }
00764          if (!(flags & kTextIgnoreTabs)) {
00765             if (*start == '\t') {
00766                break;
00767             }
00768          }
00769          start++;
00770       }
00771       if (chunk) {
00772          
00773          
00774 
00775          charsThisChunk = start - (chunk->fStart + chunk->fNumChars);
00776          if (charsThisChunk > 0) {
00777             chunk->fNumChars += MeasureChars(chunk->fStart + chunk->fNumChars,
00778                                              charsThisChunk, 0, 0, &chunk->fTotalWidth);
00779             chunk->fTotalWidth += curX;
00780          }
00781       }
00782 wrapLine:
00783       flags |= kTextAtLeastOne;
00784 
00785       
00786       
00787 
00788       if (curX > maxWidth) {
00789          maxWidth = curX;
00790       }
00791 
00792       
00793       
00794 
00795       if (curLine >= maxLines) {
00796          int *newLengths;
00797 
00798          newLengths = new int[2 * maxLines];
00799          memcpy((void *) newLengths, lineLengths, maxLines * sizeof (int));
00800 
00801          if (lineLengths != staticLineLengths) {
00802             delete[] lineLengths;
00803          }
00804          lineLengths = newLengths;
00805          maxLines *= 2;
00806       }
00807       lineLengths[curLine] = curX;
00808       curLine++;
00809 
00810       curX = 0;
00811       baseline += h;
00812    }
00813 
00814    
00815    
00816    
00817 
00818    if ((layout->fNumChunks > 0) && ((flags & kTextIgnoreNewlines) == 0)) {
00819       if (layout->fChunks[layout->fNumChunks - 1].fStart[0] == '\n') {
00820          chunk = NewChunk(layout, &maxChunks, start, 0, curX, 1000000000, baseline);
00821          chunk->fNumDisplayChars = -1;
00822          baseline += h;
00823       }
00824    }
00825 
00826    
00827    
00828 
00829    curLine = 0;
00830    chunk = layout->fChunks;
00831    if (chunk) y = chunk->fY;
00832    for (n = 0; n < layout->fNumChunks; n++) {
00833       int extra;
00834 
00835       if (chunk->fY != y) {
00836          curLine++;
00837          y = chunk->fY;
00838       }
00839       extra = maxWidth - lineLengths[curLine];
00840       if (justify == kTextCenterX) {
00841          chunk->fX += extra / 2;
00842       } else if (justify == kTextRight) {
00843          chunk->fX += extra;
00844       }
00845       ++chunk;
00846    }
00847 
00848    layout->fWidth = maxWidth;
00849    layoutHeight = baseline - fFM.fAscent;
00850    if (layout->fNumChunks == 0) {
00851       layoutHeight = h;
00852 
00853       
00854       
00855       
00856 
00857       layout->fNumChunks = 1;
00858       layout->fChunks = new LayoutChunk_t[1];
00859       layout->fChunks[0].fStart = string;
00860       layout->fChunks[0].fNumChars = 0;
00861       layout->fChunks[0].fNumDisplayChars = -1;
00862       layout->fChunks[0].fX = 0;
00863       layout->fChunks[0].fY = fFM.fAscent;
00864       layout->fChunks[0].fTotalWidth = 0;
00865       layout->fChunks[0].fDisplayWidth = 0;
00866    }
00867    if (width) {
00868       *width = layout->fWidth;
00869    }
00870    if (height) {
00871       *height = layoutHeight;
00872    }
00873    if (lineLengths != staticLineLengths) {
00874       delete[] lineLengths;
00875    }
00876 
00877    return layout;
00878 }
00879 
00880 
00881 TGTextLayout::~TGTextLayout()
00882 {
00883    
00884 
00885    if (fChunks) {
00886       delete[] fChunks;
00887    }
00888 }
00889 
00890 
00891 void TGTextLayout::DrawText(Drawable_t dst, GContext_t gc,
00892                             Int_t x, Int_t y, Int_t firstChar, Int_t lastChar) const
00893 {
00894    
00895    
00896    
00897    
00898    
00899    
00900    
00901    
00902    
00903    
00904    
00905    
00906    
00907    
00908 
00909    Int_t i, numDisplayChars, drawX;
00910    LayoutChunk_t *chunk;
00911 
00912    if (lastChar < 0) lastChar = 100000000;
00913    chunk = fChunks;
00914 
00915    for (i = 0; i < fNumChunks; i++) {
00916       numDisplayChars = chunk->fNumDisplayChars;
00917       if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
00918          if (firstChar <= 0) {
00919             drawX = 0;
00920             firstChar = 0;
00921          } else {
00922             fFont->MeasureChars(chunk->fStart, firstChar, 0, 0, &drawX);
00923          }
00924          if (lastChar < numDisplayChars) numDisplayChars = lastChar;
00925          fFont->DrawChars(dst, gc, chunk->fStart + firstChar, numDisplayChars - firstChar,
00926                            x + chunk->fX + drawX, y + chunk->fY);
00927       }
00928       firstChar -= chunk->fNumChars;
00929       lastChar -= chunk->fNumChars;
00930 
00931       if (lastChar <= 0) break;
00932       chunk++;
00933    }
00934 }
00935 
00936 
00937 void TGTextLayout::UnderlineChar(Drawable_t dst, GContext_t gc,
00938                                 Int_t x, Int_t y, Int_t underline) const
00939 {
00940    
00941    
00942    
00943    
00944    
00945    
00946    
00947    
00948    
00949    
00950    
00951    
00952    
00953    
00954    
00955 
00956    int xx, yy, width, height;
00957 
00958    if ((CharBbox(underline, &xx, &yy, &width, &height) != 0)
00959       && (width != 0)) {
00960       gVirtualX->FillRectangle(dst, gc, x + xx,
00961                                y + yy + fFont->fFM.fAscent + fFont->fUnderlinePos,
00962                                (UInt_t) width, (UInt_t) fFont->fUnderlineHeight);
00963    }
00964 }
00965 
00966 
00967 Int_t TGTextLayout::PointToChar(Int_t x, Int_t y) const
00968 {
00969    
00970    
00971    
00972    
00973    
00974    
00975    
00976    
00977    
00978    
00979    
00980    
00981    
00982    
00983    
00984    
00985    
00986    
00987 
00988    LayoutChunk_t *chunk, *last;
00989    Int_t i, n, dummy, baseline, pos;
00990 
00991    if (y < 0) {
00992       
00993       
00994 
00995       return 0;
00996    }
00997 
00998    
00999 
01000    last = chunk = fChunks;
01001    for (i = 0; i < fNumChunks; i++) {
01002       baseline = chunk->fY;
01003       if (y < baseline + fFont->fFM.fDescent) {
01004          if (x < chunk->fX) {
01005             
01006             
01007 
01008             return (chunk->fStart - fString);
01009          }
01010          if (x >= fWidth) {
01011 
01012          
01013          
01014          
01015          
01016 
01017             x = INT_MAX;
01018          }
01019 
01020          
01021          
01022 
01023          last = chunk;
01024          while ((i < fNumChunks) && (chunk->fY == baseline)) {
01025             if (x < chunk->fX + chunk->fTotalWidth) {
01026 
01027                
01028 
01029                if (chunk->fNumDisplayChars < 0) {
01030 
01031                   
01032                   
01033 
01034                   return (chunk->fStart - fString);
01035                }
01036                n = fFont->MeasureChars(chunk->fStart, chunk->fNumChars,
01037                                        x + 1 - chunk->fX, kTextPartialOK, &dummy);
01038                return ((chunk->fStart + n - 1) - fString);
01039             }
01040             last = chunk;
01041             chunk++;
01042             i++;
01043          }
01044 
01045          
01046          
01047          
01048 
01049          pos = (last->fStart + last->fNumChars) - fString;
01050          if (i < fNumChunks) pos--;
01051          return pos;
01052       }
01053       last = chunk;
01054       chunk++;
01055    }
01056 
01057    
01058    
01059 
01060    return ((last->fStart + last->fNumChars) - fString);
01061 }
01062 
01063 
01064 Int_t TGTextLayout::CharBbox(Int_t index, Int_t *x, Int_t *y, Int_t *w, Int_t *h) const
01065 {
01066    
01067    
01068    
01069    
01070    
01071    
01072    
01073    
01074    
01075    
01076    
01077    
01078    
01079    
01080    
01081    
01082    
01083    
01084    
01085    
01086    
01087    
01088    
01089    
01090    
01091    
01092    
01093 
01094    LayoutChunk_t *chunk;
01095    Int_t i, xx = 0, ww = 0;
01096 
01097    if (index < 0) {
01098       return 0;
01099    }
01100 
01101    chunk = fChunks;
01102 
01103    for (i = 0; i < fNumChunks; i++) {
01104       if (chunk->fNumDisplayChars < 0) {
01105          if (!index) {
01106             xx = chunk->fX;
01107             ww = chunk->fTotalWidth;
01108             goto check;
01109          }
01110       } else if (index < chunk->fNumChars) {
01111          if (x) {
01112             fFont->MeasureChars(chunk->fStart, index, 0, 0, &xx);
01113             xx += chunk->fX;
01114          }
01115          if (w) {
01116             fFont->MeasureChars(chunk->fStart + index, 1, 0, 0, &ww);
01117          }
01118          goto check;
01119       }
01120       index -= chunk->fNumChars;
01121       chunk++;
01122    }
01123    if (!index) {
01124 
01125       
01126 
01127       chunk--;
01128       xx = chunk->fX + chunk->fTotalWidth;
01129       ww = 0;
01130    } else {
01131       return 0;
01132    }
01133 
01134    
01135    
01136    
01137    
01138 
01139 check:
01140    if (y) {
01141       *y = chunk->fY - fFont->fFM.fAscent;
01142    }
01143    if (h) {
01144       *h = fFont->fFM.fAscent + fFont->fFM.fDescent;
01145    }
01146    if (xx > fWidth) {
01147       xx = fWidth;
01148    }
01149    if (x) {
01150       *x = xx;
01151    }
01152    if (w) {
01153       if (xx + ww > fWidth) {
01154          ww = fWidth - xx;
01155       }
01156       *w = ww;
01157    }
01158    return 1;
01159 }
01160 
01161 
01162 Int_t TGTextLayout::DistanceToText(Int_t x, Int_t y) const
01163 {
01164    
01165    
01166    
01167    
01168    
01169    
01170    
01171    
01172    
01173    
01174    
01175 
01176    Int_t i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
01177    LayoutChunk_t *chunk;
01178 
01179    ascent = fFont->fFM.fAscent;
01180    descent = fFont->fFM.fDescent;
01181 
01182    minDist = 0;
01183    chunk = fChunks;
01184    for (i = 0; i < fNumChunks; i++) {
01185       if (chunk->fStart[0] == '\n') {
01186 
01187          
01188          
01189 
01190          chunk++;
01191          continue;
01192       }
01193       x1 = chunk->fX;
01194       y1 = chunk->fY - ascent;
01195       x2 = chunk->fX + chunk->fDisplayWidth;
01196       y2 = chunk->fY + descent;
01197 
01198       if (x < x1) {
01199          xDiff = x1 - x;
01200       } else if (x >= x2) {
01201          xDiff = x - x2 + 1;
01202       } else {
01203          xDiff = 0;
01204       }
01205 
01206       if (y < y1) {
01207          yDiff = y1 - y;
01208       } else if (y >= y2) {
01209          yDiff = y - y2 + 1;
01210       } else {
01211          yDiff = 0;
01212       }
01213       if ((xDiff == 0) && (yDiff == 0)) {
01214          return 0;
01215       }
01216       dist = (int) TMath::Hypot((Double_t) xDiff, (Double_t) yDiff);
01217       if ((dist < minDist) || !minDist) {
01218          minDist = dist;
01219       }
01220       chunk++;
01221    }
01222    return minDist;
01223 }
01224 
01225 
01226 Int_t TGTextLayout::IntersectText(Int_t x, Int_t y, Int_t w, Int_t h) const
01227 {
01228    
01229    
01230    
01231    
01232    
01233    
01234    
01235    
01236    
01237    
01238    
01239    
01240    
01241 
01242    Int_t result, i, x1, y1, x2, y2;
01243    LayoutChunk_t *chunk;
01244    Int_t left, top, right, bottom;
01245 
01246    
01247    
01248    
01249    
01250 
01251    chunk = fChunks;
01252 
01253    left = x;
01254    top = y;
01255    right = x + w;
01256    bottom = y + h;
01257 
01258    result = 0;
01259    for (i = 0; i < fNumChunks; i++) {
01260       if (chunk->fStart[0] == '\n') {
01261 
01262          
01263          
01264 
01265          chunk++;
01266          continue;
01267       }
01268       x1 = chunk->fX;
01269       y1 = chunk->fY - fFont->fFM.fAscent;
01270       x2 = chunk->fX + chunk->fDisplayWidth;
01271       y2 = chunk->fY + fFont->fFM.fDescent;
01272 
01273       if ((right < x1) || (left >= x2) || (bottom < y1) || (top >= y2)) {
01274          if (result == 1) {
01275             return 0;
01276          }
01277          result = -1;
01278       } else if ((x1 < left) || (x2 >= right) || (y1 < top) || (y2 >= bottom)) {
01279          return 0;
01280       } else if (result == -1) {
01281          return 0;
01282       } else {
01283          result = 1;
01284       }
01285       chunk++;
01286    }
01287    return result;
01288 }
01289 
01290 
01291 void TGTextLayout::ToPostscript(TString *result) const
01292 {
01293    
01294    
01295    
01296    
01297    
01298    
01299    
01300    
01301    
01302    
01303    
01304    
01305    
01306    
01307    
01308    
01309    
01310    
01311    
01312    
01313    
01314    
01315    
01316    
01317    
01318 
01319 #define MAXUSE 128
01320    char buf[MAXUSE + 10];
01321    LayoutChunk_t *chunk;
01322    Int_t i, j, used, c, baseline;
01323 
01324    chunk = fChunks;
01325    baseline = chunk->fY;
01326    used = 0;
01327    buf[used++] = '(';
01328 
01329    for (i = 0; i < fNumChunks; i++) {
01330       if (baseline != chunk->fY) {
01331          buf[used++] = ')';
01332          buf[used++] = '\n';
01333          buf[used++] = '(';
01334          baseline = chunk->fY;
01335       }
01336       if (chunk->fNumDisplayChars <= 0) {
01337          if (chunk->fStart[0] == '\t') {
01338             buf[used++] = '\\';
01339             buf[used++] = 't';
01340          }
01341       } else {
01342          for (j = 0; j < chunk->fNumDisplayChars; j++) {
01343             c = UChar_t(chunk->fStart[j]);
01344             if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20) || (c >= UChar_t(0x7f))) {
01345 
01346             
01347             
01348             
01349             
01350             
01351 
01352                sprintf(buf + used, "\\%03o", c);
01353                used += 4;
01354             } else {
01355                buf[used++] = c;
01356             }
01357             if (used >= MAXUSE) {
01358                buf[used] = '\0';
01359                result->Append(buf);
01360                used = 0;
01361             }
01362          }
01363       }
01364       if (used >= MAXUSE) {
01365          
01366          
01367 
01368          buf[used] = '\0';
01369          result->Append(buf);
01370          used = 0;
01371       }
01372       chunk++;
01373    }
01374    buf[used++] = ')';
01375    buf[used++] = '\n';
01376    buf[used]   = '\0';
01377 
01378    result->Append(buf);
01379 }
01380 
01381 
01382 LayoutChunk_t *TGFont::NewChunk(TGTextLayout *layout, Int_t *maxPtr,
01383                                 const char *start, Int_t numChars,
01384                                 Int_t curX, Int_t newX, Int_t y) const
01385 {
01386    
01387    
01388    
01389    
01390    
01391    
01392    
01393    
01394    
01395 
01396    LayoutChunk_t *chunk;
01397    Int_t i, maxChunks;
01398 
01399    maxChunks = *maxPtr;
01400    if (layout->fNumChunks == maxChunks) {
01401       if (maxChunks == 0) {
01402          maxChunks = 1;
01403       } else {
01404          maxChunks *= 2;
01405       }
01406       chunk = new LayoutChunk_t[maxChunks];
01407 
01408       if (layout->fNumChunks > 0) {
01409          for (i=0; i<layout->fNumChunks; ++i) chunk[i] = layout->fChunks[i];
01410          delete[] layout->fChunks;
01411       }
01412       layout->fChunks = chunk;
01413       *maxPtr = maxChunks;
01414    }
01415 
01416    chunk = &layout->fChunks[layout->fNumChunks];
01417    chunk->fStart = start;
01418    chunk->fNumChars = numChars;
01419    chunk->fNumDisplayChars = numChars;
01420    chunk->fX = curX;
01421    chunk->fY = y;
01422    chunk->fTotalWidth = newX - curX;
01423    chunk->fDisplayWidth = newX - curX;
01424    layout->fNumChunks++;
01425 
01426    return chunk;
01427 }
01428 
01429 
01430 void TGFont::DrawCharsExp(Drawable_t dst, GContext_t gc,
01431                           const char *source, Int_t numChars,
01432                           Int_t x, Int_t y) const
01433 {
01434    
01435    
01436    
01437    
01438    
01439    
01440    
01441    
01442    
01443    
01444    
01445    
01446    
01447    
01448 
01449    const char *p;
01450    Int_t i, type;
01451    char buf[4];
01452 
01453    p = source;
01454    for (i = 0; i < numChars; i++) {
01455       type = fTypes[UChar_t(*p)];
01456       if (type != kCharNormal) {
01457          DrawChars(dst, gc, source, p - source, x, y);
01458          x += gVirtualX->TextWidth(fFontStruct, source, p - source);
01459          if (type == kCharReplace) {
01460             DrawChars(dst, gc, buf, GetControlCharSubst(UChar_t(*p), buf), x, y);
01461             x += fWidths[UChar_t(*p)];
01462          }
01463          source = p + 1;
01464       }
01465       p++;
01466    }
01467 
01468    DrawChars(dst, gc, source, p - source, x, y);
01469 }
01470 
01471 
01472 void TGFont::DrawChars(Drawable_t dst, GContext_t gc,
01473                        const char *source, Int_t numChars,
01474                        Int_t x, Int_t y) const
01475 {
01476    
01477    
01478 
01479    Int_t max_width =  gVirtualX->TextWidth(fFontStruct, "@", 1);
01480 
01481    if ((x + (max_width * numChars) > 0x7fff)) {
01482       int length;
01483 
01484       
01485       
01486       
01487       
01488 
01489       numChars = MeasureChars(source, numChars, 0x7fff - x, 0, &length);
01490    }
01491 
01492    gVirtualX->DrawString(dst, gc, x, y, source, numChars);
01493 
01494    if (fFA.fUnderline != 0) {
01495       gVirtualX->FillRectangle(dst, gc, x,  y + fUnderlinePos,
01496                           (UInt_t) gVirtualX->TextWidth(fFontStruct, source, numChars),
01497                           (UInt_t) fBarHeight);
01498    }
01499    if (fFA.fOverstrike != 0) {
01500       y -= fFM.fDescent + fFM.fAscent / 10;
01501       gVirtualX->FillRectangle(dst, gc, x, y,
01502                           (UInt_t) gVirtualX->TextWidth(fFontStruct, source, numChars),
01503                           (UInt_t) fBarHeight);
01504    }
01505 }
01506 
01507 
01508 TGFontPool::TGFontPool(TGClient *client)
01509 {
01510    
01511 
01512    fClient = client;
01513    fList   = new THashTable(50);
01514    fList->SetOwner();
01515 
01516    fNamedTable = new THashTable(50);
01517    fNamedTable->SetOwner();
01518 
01519    fUidTable = new THashTable(50);
01520    fUidTable->SetOwner();
01521 }
01522 
01523 
01524 TGFontPool::~TGFontPool()
01525 {
01526    
01527 
01528    delete fList;
01529 }
01530 
01531 
01532 TGFont *TGFontPool::GetFont(const char *font, Bool_t fixedDefault)
01533 {
01534    
01535    
01536    
01537    
01538    
01539    
01540    
01541 
01542    if (!font || !*font) {
01543       Error("GetFont", "argument may not be 0 or empty");
01544       return 0;
01545    }
01546 
01547    TGFont *f = (TGFont*)fList->FindObject(font);
01548 
01549    if (f) {
01550       f->AddReference();
01551       return f;
01552    }
01553 
01554    TNamedFont *nf = (TNamedFont*)fNamedTable->FindObject(font);
01555 
01556    if (nf) {
01557       
01558       nf->AddReference();
01559       f = GetFontFromAttributes(&nf->fFA, 0);
01560 
01561    } else {
01562 
01563       
01564       Int_t errsav = gErrorIgnoreLevel;
01565       gErrorIgnoreLevel = kFatal;
01566 
01567       f = GetNativeFont(font, fixedDefault);
01568       gErrorIgnoreLevel = errsav;
01569 
01570       if (!f) {
01571          FontAttributes_t fa;
01572 
01573          if (!ParseFontName(font, &fa)) {
01574             
01575 
01576             return 0;
01577          }
01578 
01579          
01580          f = GetFontFromAttributes(&fa, 0);
01581       }
01582    }
01583 
01584    fList->Add(f);
01585 
01586    f->SetRefCount(1);
01587    
01588    f->fNamedHash = nf;
01589 
01590    f->MeasureChars("0", 1, 0, 0, &f->fTabWidth);
01591 
01592    if (!f->fTabWidth) {
01593       f->fTabWidth = f->fFM.fMaxWidth;
01594    }
01595    f->fTabWidth *= 8;
01596 
01597    
01598    
01599 
01600    if (!f->fTabWidth) {
01601       f->fTabWidth = 1;
01602    }
01603 
01604    
01605    
01606 
01607    Int_t descent = f->fFM.fDescent;
01608    f->fUnderlinePos = descent/2;  
01609    f->fUnderlineHeight = f->fFA.fPointsize/10;
01610 
01611    if (!f->fUnderlineHeight) {
01612       f->fUnderlineHeight = 1;
01613    }
01614    if (f->fUnderlinePos + f->fUnderlineHeight > descent) {
01615 
01616       
01617       
01618       
01619 
01620       f->fUnderlineHeight = descent - f->fUnderlinePos;
01621 
01622       if (!f->fUnderlineHeight) {
01623          f->fUnderlinePos--;
01624          f->fUnderlineHeight = 1;
01625       }
01626    }
01627 
01628    return f;
01629 }
01630 
01631 
01632 TGFont *TGFontPool::GetFont(const TGFont *font)
01633 {
01634    
01635    
01636 
01637    TGFont *f = (TGFont*)fList->FindObject(font);
01638 
01639    if (f) {
01640       f->AddReference();
01641       return f;
01642    }
01643 
01644    return 0;
01645 }
01646 
01647 
01648 TGFont *TGFontPool::GetFont(FontStruct_t fs)
01649 {
01650    
01651 
01652    TGFont *f = FindFont(fs);
01653 
01654    if (f) {
01655       f->AddReference();
01656       return f;
01657    }
01658 
01659    static int i = 0;
01660    f = MakeFont(0, fs, TString::Format("unknown-%d", i));
01661    fList->Add(f);
01662    i++;
01663 
01664    return f;
01665 }
01666 
01667 
01668 TGFont *TGFontPool::GetFont(const char *family, Int_t ptsize, Int_t weight, Int_t slant)
01669 {
01670    
01671    
01672    
01673    
01674    
01675    
01676    
01677 
01678    const char *s;
01679    TString tmp;
01680 
01681    tmp = TString::Format("%s %d", family, ptsize);
01682    s = FindStateString(gWeightMap, weight);
01683    if (s) {
01684       tmp += " ";
01685       tmp + s;
01686    }
01687    s = FindStateString(gSlantMap, slant);
01688    if (s) {
01689       tmp += " ";
01690       tmp += s;
01691    }
01692    return GetFont(tmp.Data());
01693 }
01694 
01695 
01696 void TGFontPool::FreeFont(const TGFont *font)
01697 {
01698    
01699 
01700    TGFont *f = (TGFont*) fList->FindObject(font);
01701    if (f) {
01702       if (f->RemoveReference() == 0) {
01703          if (font->fNamedHash) {
01704 
01705             
01706             
01707 
01708             TNamedFont *nf = (TNamedFont *) font->fNamedHash;
01709 
01710             if ((nf->RemoveReference() == 0) && (nf->fDeletePending != 0)) {
01711                fNamedTable->Remove(nf);
01712                delete nf;
01713             }
01714          }
01715          fList->Remove(f);
01716          delete font;
01717       }
01718    }
01719 }
01720 
01721 
01722 TGFont *TGFontPool::FindFont(FontStruct_t font) const
01723 {
01724    
01725 
01726    TIter next(fList);
01727    TGFont *f = 0;
01728 
01729    while ((f = (TGFont*) next())) {
01730       if (f->fFontStruct == font) {
01731          return f;
01732       }
01733    }
01734 
01735    return 0;
01736 }
01737 
01738 
01739 TGFont *TGFontPool::FindFontByHandle(FontH_t font) const
01740 {
01741    
01742 
01743    TIter next(fList);
01744    TGFont *f = 0;
01745 
01746    while ((f = (TGFont*) next())) {
01747       if (f->fFontH == font) {
01748          return f;
01749       }
01750    }
01751 
01752    return 0;
01753 }
01754 
01755 
01756 const char *TGFontPool::GetUid(const char *string)
01757 {
01758    
01759    
01760    
01761    
01762    
01763    
01764    
01765    
01766 
01767    TObjString *obj = 0;
01768    obj = (TObjString*)fUidTable->FindObject(string);
01769 
01770    if (!obj) {
01771       obj = new TObjString(string);
01772       fUidTable->Add(obj);
01773    }
01774 
01775    return (const char *)obj->GetName();
01776 }
01777 
01778 
01779 char **TGFontPool::GetAttributeInfo(const FontAttributes_t *fa)
01780 {
01781    
01782    
01783    
01784    
01785    
01786 
01787    Int_t i, num;
01788    const char *str = 0;
01789 
01790    char **result = new char*[FONT_NUMFIELDS];
01791 
01792    for (i = 0; i < FONT_NUMFIELDS; ++i) {
01793       str = 0;
01794       num = 0;
01795 
01796       switch (i) {
01797       case FONT_FAMILY:
01798          str = fa->fFamily;
01799          if (!str) str = "";
01800          break;
01801 
01802       case FONT_SIZE:
01803          num = fa->fPointsize;
01804          break;
01805 
01806       case FONT_WEIGHT:
01807          str = FindStateString(gWeightMap, fa->fWeight);
01808          break;
01809 
01810       case FONT_SLANT:
01811          str = FindStateString(gSlantMap, fa->fSlant);
01812          break;
01813 
01814       case FONT_UNDERLINE:
01815          num = fa->fUnderline;
01816          break;
01817 
01818       case FONT_OVERSTRIKE:
01819          num = fa->fOverstrike;
01820          break;
01821       }
01822 
01823       if (str) {
01824          result[i] = new char[strlen(str)+1];
01825          strlcpy(result[i], str, strlen(str)+1);
01826       } else {
01827          result[i] = new char[20];
01828          snprintf(result[i], 20, "%d", num);
01829       }
01830    }
01831 
01832    return result;
01833 }
01834 
01835 
01836 void TGFontPool::FreeAttributeInfo(char **info)
01837 {
01838    
01839 
01840    Int_t i;
01841 
01842    if (info) {
01843       for (i = 0; i < FONT_NUMFIELDS; ++i) {
01844          if (info[i]) {
01845             delete[] info[i];
01846          }
01847       }
01848       delete[] info;
01849    }
01850 }
01851 
01852 
01853 void TGFontPool::Print(Option_t *opt) const
01854 {
01855    
01856 
01857    fList->Print(opt);
01858 }
01859 
01860 
01861 void TGFont::SavePrimitive(ostream &out, Option_t * )
01862 {
01863     
01864 
01865    char quote = '"';
01866 
01867    if (gROOT->ClassSaved(TGFont::Class())) {
01868       out << endl;
01869    } else {
01870       
01871       out << endl;
01872       out << "   TGFont *ufont;         // will reflect user font changes" << endl;
01873    }
01874    out << "   ufont = gClient->GetFont(" << quote << GetName() << quote << ");" << endl;
01875 }
01876 
01877 
01878 static char *GetToken(char *str)
01879 {
01880    static char *p = 0;
01881    char *retp;
01882 
01883    if (str) p = str;
01884 
01885    if (!p) {
01886       return 0;
01887    }
01888    if (!*p) {
01889       return 0;
01890    }
01891 
01892    while (*p && ((*p == ' ') || (*p == '\t'))) {   
01893       ++p;
01894    }
01895 
01896    if (!*p) {
01897       return 0;
01898    }
01899 
01900    if (*p == '"') {  
01901       retp = ++p;
01902 
01903       if (!*p) {
01904          return 0;
01905       }
01906 
01907       while (*p && (*p != '"')) {
01908          ++p;
01909       }
01910 
01911       if (*p == '"') {
01912          *p++ = '\0';
01913       }
01914    } else {
01915       retp = p;
01916       while (*p && (*p != ' ') && (*p != '\t')) {
01917          ++p;
01918       }
01919       if (*p) {
01920          *p++ = '\0';
01921       }
01922    }
01923 
01924    return retp;
01925 }
01926 
01927 
01928 Bool_t TGFontPool::ParseFontName(const char *string, FontAttributes_t *fa)
01929 {
01930    
01931    
01932    
01933    
01934    
01935    
01936    
01937    
01938    
01939    
01940    
01941 
01942    char *s;
01943    int n, result;
01944 
01945    XLFDAttributes_t xa;
01946 
01947    char *str = new char[strlen(string)+1];
01948    strlcpy(str, string, strlen(string)+1);
01949 
01950    if (*str == '-' || *str == '*') {
01951 
01952     
01953 
01954       xa.fFA = *fa;
01955       result = ParseXLFD(str, &xa);
01956       if (result) {
01957          *fa = xa.fFA;
01958          delete[] str;
01959          return kTRUE;  
01960       }
01961    }
01962 
01963    
01964    
01965 
01966    s = GetToken(str);
01967    if (!s) {
01968       delete[] str;
01969       return kFALSE;
01970    }
01971    fa->fFamily = GetUid(s);
01972 
01973    s = GetToken(0);
01974 
01975    if (s) {
01976       char *end;
01977 
01978       fa->fPointsize = strtol(s, &end, 0);
01979       if ((errno == ERANGE) || (end == s)) {
01980          return kFALSE;
01981       }
01982    }
01983 
01984    while ((s = GetToken(0))) {
01985       n = FindStateNum(gWeightMap, s);
01986       if (n != kFontWeightUnknown) {
01987          fa->fWeight = n;
01988          continue;
01989       }
01990       n = FindStateNum(gSlantMap, s);
01991       if (n != kFontSlantUnknown) {
01992          fa->fSlant = n;
01993          continue;
01994       }
01995       n = FindStateNum(gUnderlineMap, s);
01996       if (n) {
01997          fa->fUnderline = n;
01998          continue;
01999       }
02000       n = FindStateNum(gOverstrikeMap, s);
02001       if (n) {
02002          fa->fOverstrike = n;
02003          continue;
02004       }
02005 
02006       
02007 
02008       delete[] str;
02009       return kFALSE;
02010    }
02011 
02012    delete[] str;
02013    return kTRUE;
02014 }
02015 
02016 
02017 Bool_t TGFontPool::ParseXLFD(const char *string, XLFDAttributes_t *xa)
02018 {
02019    
02020    
02021    
02022    
02023    
02024    
02025    
02026    
02027    
02028 
02029    char *src;
02030    const char *str;
02031    int i, j;
02032    char *field[XLFD_NUMFIELDS + 2];
02033    TString ds("");
02034 
02035    memset(field, '\0', sizeof (field));
02036 
02037    str = string;
02038    if (*str == '-') str++;
02039 
02040    ds.Append((char *) str);
02041    src = (char*)ds.Data();
02042 
02043    field[0] = src;
02044    for (i = 0; *src != '\0'; src++) {
02045       if (isupper(UChar_t(*src))) {
02046          *src = tolower(UChar_t(*src));
02047       }
02048       if (*src == '-') {
02049          i++;
02050          if (i > XLFD_NUMFIELDS) {
02051            break;
02052          }
02053          *src = '\0';
02054          field[i] = src + 1;
02055       }
02056    }
02057 
02058    
02059    
02060    
02061    
02062    
02063    
02064 
02065    if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
02066       if (atoi(field[XLFD_ADD_STYLE]) != 0) {
02067          for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
02068             field[j + 1] = field[j];
02069          }
02070          field[XLFD_ADD_STYLE] = 0;
02071          i++;
02072       }
02073    }
02074 
02075    
02076 
02077    if (i < XLFD_FAMILY) {
02078       return kFALSE;
02079    }
02080    if (FieldSpecified(field[XLFD_FOUNDRY])) {
02081       xa->fFoundry = GetUid(field[XLFD_FOUNDRY]);
02082    }
02083    if (FieldSpecified(field[XLFD_FAMILY])) {
02084       xa->fFA.fFamily = GetUid(field[XLFD_FAMILY]);
02085    }
02086    if (FieldSpecified(field[XLFD_WEIGHT])) {
02087       xa->fFA.fWeight = FindStateNum(gXlfdgWeightMap, field[XLFD_WEIGHT]);
02088    }
02089    if (FieldSpecified(field[XLFD_SLANT])) {
02090       xa->fSlant = FindStateNum(gXlfdSlantMap, field[XLFD_SLANT]);
02091       if (xa->fSlant == kFontSlantRoman) {
02092          xa->fFA.fSlant = kFontSlantRoman;
02093       } else {
02094          xa->fFA.fSlant = kFontSlantItalic;
02095       }
02096    }
02097    if (FieldSpecified(field[XLFD_SETWIDTH])) {
02098       xa->fSetwidth = FindStateNum(gXlfdSetwidthMap, field[XLFD_SETWIDTH]);
02099    }
02100    
02101 
02102    
02103 
02104    if (FieldSpecified(field[XLFD_POINT_SIZE])) {
02105       if (field[XLFD_POINT_SIZE][0] == '[') {
02106 
02107          
02108          
02109          
02110          
02111          
02112          
02113          
02114 
02115          xa->fFA.fPointsize = atoi(field[XLFD_POINT_SIZE] + 1);
02116       } else {
02117          char *end;
02118 
02119          xa->fFA.fPointsize = strtol(field[XLFD_POINT_SIZE], &end, 0);
02120          if (errno == ERANGE || end == field[XLFD_POINT_SIZE]) {
02121             return kFALSE;
02122          }
02123          xa->fFA.fPointsize /= 10;
02124       }
02125    }
02126 
02127    
02128 
02129    if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
02130       if (field[XLFD_PIXEL_SIZE][0] == '[') {
02131 
02132          
02133          
02134          
02135          
02136          
02137          
02138          
02139 
02140          xa->fFA.fPointsize = atoi(field[XLFD_PIXEL_SIZE] + 1);
02141       } else {
02142          char *end;
02143 
02144          xa->fFA.fPointsize = strtol(field[XLFD_PIXEL_SIZE], &end, 0);
02145          if (errno == ERANGE || end == field[XLFD_PIXEL_SIZE]) {
02146             return kFALSE;
02147          }
02148       }
02149    }
02150    xa->fFA.fPointsize = -xa->fFA.fPointsize;
02151 
02152    
02153 
02154    
02155 
02156    
02157 
02158    
02159 
02160    if (FieldSpecified(field[XLFD_REGISTRY])) {
02161       xa->fCharset = FindStateNum(gXlfdCharsetMap, field[XLFD_REGISTRY]);
02162    }
02163    if (FieldSpecified(field[XLFD_ENCODING])) {
02164       xa->fEncoding = atoi(field[XLFD_ENCODING]);
02165    }
02166 
02167    return kTRUE;
02168 }
02169 
02170 
02171 Int_t TGFontPool::FindStateNum(const FontStateMap_t *map, const char *strKey)
02172 {
02173    
02174    
02175    
02176    
02177    
02178    
02179 
02180    const FontStateMap_t *m;
02181 
02182    if (!map->fStrKey) {
02183       return 0;
02184    }
02185 
02186    for (m = map; m->fStrKey != 0; m++) {
02187       if (strcasecmp(strKey, m->fStrKey) == 0) {
02188          return m->fNumKey;
02189       }
02190    }
02191    return m->fNumKey;
02192 }
02193 
02194 
02195 const char *TGFontPool::FindStateString(const FontStateMap_t *map, Int_t numKey)
02196 {
02197    
02198    
02199    
02200    
02201    
02202 
02203    for ( ; map->fStrKey != 0; map++) {
02204       if (numKey == map->fNumKey) return map->fStrKey;
02205    }
02206    return 0;
02207 }
02208 
02209 
02210 Bool_t TGFontPool::FieldSpecified(const char *field)
02211 {
02212    
02213    
02214    
02215    
02216    
02217    
02218    
02219    
02220    
02221 
02222    char ch;
02223 
02224    if (!field) {
02225       return kFALSE;
02226    }
02227    ch = field[0];
02228 
02229    return (ch != '*' && ch != '?');
02230 }
02231 
02232 
02233 const char *TGFontPool::NameOfFont(TGFont *font)
02234 {
02235    
02236 
02237    return font->GetName();
02238 }
02239 
02240 
02241 char **TGFontPool::GetFontFamilies()
02242 {
02243    
02244    
02245    
02246    
02247    
02248 
02249    Int_t i, numNames;
02250    char *family, *end, *p;
02251 
02252    THashTable familyTable(100);
02253    familyTable.SetOwner();
02254 
02255    char **nameList;
02256    char **dst;
02257 
02258    nameList = gVirtualX->ListFonts("*", 10000, numNames);
02259 
02260    for (i = 0; i < numNames; i++) {
02261       if (nameList[i][0] != '-') {
02262          continue;
02263       }
02264       family = strchr(nameList[i] + 1, '-');
02265       if (!family) {
02266          continue;
02267       }
02268       family++;
02269       end = strchr(family, '-');
02270       if (!end) {
02271          continue;
02272       }
02273       *end = '\0';
02274       for (p = family; *p != '\0'; p++) {
02275          if (isupper(UChar_t(*p))) {
02276             *p = tolower(UChar_t(*p));
02277          }
02278       }
02279       if (!familyTable.FindObject(family)) {
02280          familyTable.Add(new TObjString(family));
02281       }
02282    }
02283 
02284    UInt_t entries = familyTable.GetEntries();
02285    dst = new char*[entries+1];
02286 
02287    TIter next(&familyTable);
02288    i = 0;
02289    TObject *obj;
02290 
02291    while ((obj = next())) {
02292       dst[i] = StrDup(obj->GetName());
02293       i++;
02294    }
02295    dst[i] = 0;
02296 
02297    gVirtualX->FreeFontNames(nameList);
02298    return dst;
02299 }
02300 
02301 
02302 void TGFontPool::FreeFontFamilies(char **f)
02303 {
02304    
02305 
02306    Int_t i;
02307 
02308    if (!f) return;
02309 
02310    for (i = 0; f[i] != 0; ++i) {
02311       delete[] f[i];
02312    }
02313    delete[] f;
02314 }
02315 
02316 
02317 TGFont *TGFontPool::GetFontFromAttributes(FontAttributes_t *fa, TGFont *fontPtr)
02318 {
02319    
02320    
02321    
02322    
02323    
02324    
02325    
02326    
02327    
02328 
02329    Int_t numNames, score, i, scaleable, pixelsize, xaPixelsize;
02330    Int_t bestIdx, bestScore, bestScaleableIdx, bestScaleableScore;
02331    XLFDAttributes_t xa;
02332    TString buf;
02333    char **nameList;
02334    TGFont *font;
02335    FontStruct_t fontStruct;
02336    const char *fmt, *family;
02337 
02338    family = fa->fFamily;
02339    if (!family) {
02340       family = "*";
02341    }
02342    pixelsize = -fa->fPointsize;
02343 
02344    if (pixelsize < 0) {
02345       double d;
02346       d = -pixelsize * 25.4/72;
02347       Int_t xx; Int_t yy; UInt_t ww; UInt_t hh;
02348       gVirtualX->GetWindowSize(gVirtualX->GetDefaultRootWindow(), xx, yy, ww, hh);
02349       d *= ww;
02350 
02351       d /= gVirtualX->ScreenWidthMM();
02352       d += 0.5;
02353       pixelsize = (int) d;
02354    }
02355 
02356    fontStruct = 0;
02357 
02358    
02359 
02360    fmt = "-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*";
02361    buf = TString::Format(fmt, family);
02362    nameList = gVirtualX->ListFonts(buf.Data(), 32768, numNames);
02363    if (!numNames) {
02364       
02365 
02366       buf = TString::Format(fmt, "fixed");
02367       nameList = gVirtualX->ListFonts(buf.Data(), 32768, numNames);
02368 
02369       if (!numNames) {
02370 
02371 getsystem:
02372          fontStruct = gVirtualX->LoadQueryFont("fixed");
02373 
02374          if (!fontStruct) {
02375             fontStruct = gVirtualX->LoadQueryFont("*");
02376             if (!fontStruct) {
02377                return 0;
02378             }
02379          }
02380          goto end;
02381       }
02382    }
02383 
02384    
02385    
02386 
02387    bestIdx = 0;
02388    bestScore = kMaxInt;
02389    bestScaleableIdx = 0;
02390    bestScaleableScore = kMaxInt;
02391 
02392    for (i = 0; i < numNames; i++) {
02393       score = 0;
02394       scaleable = 0;
02395       if (!ParseXLFD(nameList[i], &xa)) {
02396          continue;
02397       }
02398       xaPixelsize = -xa.fFA.fPointsize;
02399 
02400       
02401       
02402       
02403       
02404 
02405       if (strcasecmp(xa.fFoundry, "adobe") != 0) {
02406          score += 3000;
02407       }
02408       if (!xa.fFA.fPointsize) {
02409 
02410          
02411          
02412 
02413          score += 10;
02414          scaleable = 1;
02415       } else {
02416 
02417          
02418 
02419          if (xaPixelsize > pixelsize) {
02420             score += (xaPixelsize - pixelsize) * 120;
02421          } else {
02422             score += (pixelsize - xaPixelsize) * 100;
02423          }
02424       }
02425 
02426       score += TMath::Abs(xa.fFA.fWeight - fa->fWeight) * 30;
02427       score += TMath::Abs(xa.fFA.fSlant - fa->fSlant) * 25;
02428 
02429       if (xa.fSlant == kFontSlantOblique) {
02430 
02431          
02432 
02433          
02434       }
02435       if (xa.fSetwidth != kFontSWNormal) {
02436 
02437          
02438 
02439          score += 2000;
02440       }
02441       if (xa.fCharset == kFontCSOther) {
02442 
02443          
02444          
02445          
02446 
02447          score += 11000;
02448       }
02449       if ((xa.fCharset == kFontCSNormal) && (xa.fEncoding != 1)) {
02450 
02451          
02452          
02453 
02454          score += 8000;
02455       }
02456       if (scaleable) {
02457          if (score < bestScaleableScore) {
02458             bestScaleableIdx = i;
02459             bestScaleableScore = score;
02460          }
02461       } else {
02462          if (score < bestScore) {
02463             bestIdx = i;
02464             bestScore = score;
02465          }
02466       }
02467       if (!score) {
02468          break;
02469       }
02470    }
02471 
02472    
02473    
02474    
02475    
02476    
02477 
02478    fontStruct = 0;
02479 
02480    if (bestScaleableScore < bestScore) {
02481       char *str, *rest;
02482 
02483       
02484 
02485 tryscale:
02486       str = nameList[bestScaleableIdx];
02487       for (i = 0; i < XLFD_PIXEL_SIZE - 1; i++) {
02488          str = strchr(str + 1, '-');
02489       }
02490       rest = str;
02491       for (i = XLFD_PIXEL_SIZE - 1; i < XLFD_REGISTRY; i++) {
02492          rest = strchr(rest + 1, '-');
02493       }
02494       *str = '\0';
02495       buf = TString::Format("%.240s-*-%d-*-*-*-*-*%s", nameList[bestScaleableIdx], pixelsize, rest);
02496       *str = '-';
02497       fontStruct = gVirtualX->LoadQueryFont(buf.Data());
02498       bestScaleableScore = kMaxInt;
02499    }
02500    if (!fontStruct) {
02501       buf = nameList[bestIdx];
02502       fontStruct = gVirtualX->LoadQueryFont(buf.Data());
02503 
02504       if (!fontStruct) {
02505 
02506          
02507          
02508 
02509          if (bestScaleableScore < kMaxInt) {
02510             goto tryscale;
02511          } else {
02512             gVirtualX->FreeFontNames(nameList);
02513             goto getsystem;
02514          }
02515       }
02516    }
02517    gVirtualX->FreeFontNames(nameList);
02518 
02519 end:
02520    font = MakeFont(fontPtr, fontStruct, buf);
02521    font->fFA.fUnderline = fa->fUnderline;
02522    font->fFA.fOverstrike = fa->fOverstrike;
02523 
02524    return font;
02525 }
02526 
02527 
02528 TGFont *TGFontPool::GetNativeFont(const char *name, Bool_t fixedDefault)
02529 {
02530    
02531    
02532    
02533    
02534    
02535    
02536    
02537 
02538    FontStruct_t fontStruct;
02539    fixedDefault = fixedDefault && ((*name == '-') || (*name == '*'));
02540    fontStruct = fClient->GetFontByName(name, fixedDefault);
02541 
02542    if (!fontStruct) {
02543       return 0;
02544    }
02545 
02546    return MakeFont(0, fontStruct, name);
02547 }
02548 
02549 
02550 TGFont *TGFontPool::MakeFont(TGFont *font, FontStruct_t fontStruct,
02551                              const char *fontName)
02552 {
02553    
02554    
02555    
02556    
02557    
02558    
02559    
02560    
02561    
02562    
02563 
02564    TGFont *newFont;
02565 
02566    Int_t i, width, firstChar, lastChar, n, replaceOK;
02567    char *p;
02568    char buf[4];
02569    XLFDAttributes_t xa;
02570 
02571    if (font) {
02572       gVirtualX->FreeFontStruct(font->fFontStruct);
02573       newFont = font;
02574    } else {
02575       newFont = new TGFont(fontName);
02576    }
02577 
02578    if (!ParseXLFD(fontName, &xa)) {
02579       newFont->fFA.fFamily = GetUid(fontName);
02580    } else {
02581       newFont->fFA = xa.fFA;
02582    }
02583 
02584    if (newFont->fFA.fPointsize < 0) {
02585       double d;
02586       Int_t xx; Int_t yy; UInt_t ww; UInt_t hh;
02587       gVirtualX->GetWindowSize(gVirtualX->GetDefaultRootWindow(), xx, yy, ww, hh);
02588       d = -newFont->fFA.fPointsize * 72/25.4;
02589       d *= gVirtualX->ScreenWidthMM();
02590       d /= ww;
02591       d += 0.5;
02592       newFont->fFA.fPointsize = (int) d;
02593    }
02594 
02595    Int_t ascent;
02596    Int_t descent;
02597    gVirtualX->GetFontProperties(fontStruct, ascent, descent);
02598 
02599    newFont->fFM.fAscent = ascent;
02600    newFont->fFM.fDescent = descent;
02601    newFont->fFM.fLinespace = ascent + descent;
02602    newFont->fFM.fMaxWidth = gVirtualX->TextWidth(fontStruct, "@", 1);
02603    newFont->fFM.fFixed = kTRUE;
02604    newFont->fFontStruct = fontStruct;
02605    newFont->fFontH      = gVirtualX->GetFontHandle(fontStruct);
02606 
02607    
02608 
02609    firstChar = 0x20; 
02610    lastChar = 0xff; 
02611 
02612    for (i = 0; i < 256; i++) {
02613       if ((i == 160) || (i == 173) || (i == 177) ||
02614           (i < firstChar) || (i > lastChar)) {
02615          newFont->fTypes[i] = kCharReplace;
02616       } else {
02617          newFont->fTypes[i] = kCharNormal;
02618       }
02619    }
02620 
02621    
02622    
02623    
02624    
02625 
02626    char ch[2] = {0, 0};
02627    width = 0;
02628    for (i = 0; i < 256; i++) {
02629       if (newFont->fTypes[i] != kCharNormal) {
02630          n = 0;
02631       } else {
02632          ch[0] = i;
02633          n = gVirtualX->TextWidth(fontStruct, ch, 1);
02634       }
02635       newFont->fWidths[i] = n;
02636       if (n) {
02637          if (!width) {
02638             width = n;
02639          } else if (width != n) {
02640             newFont->fFM.fFixed = kFALSE;
02641          }
02642       }
02643    }
02644 
02645    
02646    
02647    
02648    
02649 
02650    replaceOK = kTRUE;
02651    for (p = gHexChars; *p != '\0'; p++) {
02652       if ((UChar_t(*p) < firstChar) || (UChar_t(*p) > lastChar)) {
02653          replaceOK = kFALSE;
02654          break;
02655       }
02656    }
02657    for (i = 0; i < 256; i++) {
02658       if (newFont->fTypes[i] == kCharReplace) {
02659          if (replaceOK) {
02660             n = GetControlCharSubst(i, buf);
02661             for (; --n >= 0;) {
02662                newFont->fWidths[i] += newFont->fWidths[UChar_t(buf[n])];
02663             }
02664          } else {
02665             newFont->fTypes[i] = kCharSkip;
02666          }
02667       }
02668    }
02669 
02670    newFont->fUnderlinePos = descent >> 1;
02671    newFont->fBarHeight = newFont->fWidths[(int)'I']/3;
02672 
02673    if (newFont->fBarHeight == 0) {
02674       newFont->fBarHeight = 1;
02675    }
02676 
02677    if (newFont->fUnderlinePos + newFont->fBarHeight > descent) {
02678 
02679       
02680       
02681       
02682 
02683       newFont->fBarHeight = descent - newFont->fUnderlinePos;
02684 
02685       if (!newFont->fBarHeight) {
02686          newFont->fUnderlinePos--;
02687          newFont->fBarHeight = 1;
02688       }
02689    }
02690 
02691    return newFont;
02692 }
02693 
02694 
02695 static Int_t GetControlCharSubst(Int_t c, char buf[4])
02696 {
02697    
02698    
02699    
02700    
02701    
02702    
02703    
02704    
02705    
02706    
02707    
02708 
02709    buf[0] = '\\';
02710 
02711    if (((UInt_t)c < sizeof(gMapChars)) && (gMapChars[c] != 0)) {
02712       buf[1] = gMapChars[c];
02713       return 2;
02714    } else {
02715       buf[1] = 'x';
02716       buf[2] = gHexChars[(c >> 4) & 0xf];
02717       buf[3] = gHexChars[c & 0xf];
02718       return 4;
02719    }
02720 }