TGFont.cxx

Go to the documentation of this file.
00001 // @(#)root/gui:$Id: TGFont.cxx 35622 2010-09-23 08:29:15Z bellenot $
00002 // Author: Fons Rademakers   20/5/2003
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2003, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 /**************************************************************************
00012 
00013     This source is based on Xclass95, a Win95-looking GUI toolkit.
00014     Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.
00015 
00016     Xclass95 is free software; you can redistribute it and/or
00017     modify it under the terms of the GNU Library General Public
00018     License as published by the Free Software Foundation; either
00019     version 2 of the License, or (at your option) any later version.
00020 
00021 **************************************************************************/
00022 
00023 
00024 //////////////////////////////////////////////////////////////////////////
00025 //                                                                      //
00026 // TGFont and TGFontPool                                                //
00027 //                                                                      //
00028 // Encapsulate fonts used in the GUI system.                            //
00029 // TGFontPool provides a pool of fonts.                                 //
00030 // TGTextLayout is used to keep track of string  measurement            //
00031 // information when  using the text layout facilities.                  //
00032 // It can be displayed with respect to any origin.                      //
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 // The following defines specify the meaning of the fields in a fully
00065 // qualified XLFD.
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 // A LayoutChunk_t represents a contiguous range of text that can be measured
00085 // and displayed by low-level text calls. In general, chunks will be
00086 // delimited by newlines and tabs. Low-level, platform-specific things
00087 // like kerning and non-integer character widths may occur between the
00088 // characters in a single chunk, but not between characters in different
00089 // chunks.
00090 
00091 struct LayoutChunk_t {
00092 
00093    const char *fStart;     // Pointer to simple string to be displayed.
00094                            // This is a pointer into the TGTextLayout's
00095                            // string.
00096    Int_t fNumChars;        // The number of characters in this chunk.
00097    Int_t fNumDisplayChars; // The number of characters to display when
00098                            // this chunk is displayed. Can be less than
00099                            // numChars if extra space characters were
00100                            // absorbed by the end of the chunk. This
00101                            // will be < 0 if this is a chunk that is
00102                            // holding a tab or newline.
00103    Int_t fX;               // The x origin and
00104    Int_t fY;               // the y origin of the first character in this
00105                            // chunk with respect to the upper-left hand
00106                            // corner of the TGTextLayout.
00107    Int_t fTotalWidth;      // Width in pixels of this chunk. Used
00108                            // when hit testing the invisible spaces at
00109                            // the end of a chunk.
00110    Int_t fDisplayWidth;    // Width in pixels of the displayable
00111                            // characters in this chunk. Can be less than
00112                            // width if extra space characters were
00113                            // absorbed by the end of the chunk.
00114 };
00115 
00116 
00117 // The following structure is used to return attributes when parsing an
00118 // XLFD. The extra information is used to find the closest matching font.
00119 
00120 struct XLFDAttributes_t {
00121    FontAttributes_t fFA; // Standard set of font attributes.
00122    const char *fFoundry; // The foundry of the font.
00123    Int_t fSlant;         // The tristate value for the slant
00124    Int_t fSetwidth;      // The proportionate width
00125    Int_t fCharset;       // The character set encoding (the glyph family).
00126    Int_t fEncoding;      // Variations within a charset for the glyphs above character 127.
00127 
00128    XLFDAttributes_t() :  // default constructor
00129       fFA(),
00130       fFoundry(0),
00131       fSlant(0),
00132       fSetwidth(0),
00133       fCharset(0),
00134       fEncoding(0) { }
00135 };
00136 
00137 
00138 // The following data structure is used to keep track of the font attributes
00139 // for each named font that has been defined. The named font is only deleted
00140 // when the last reference to it goes away.
00141 
00142 class TNamedFont : public TObjString, public TRefCnt {
00143 public:
00144    Int_t            fDeletePending; // Non-zero if font should be deleted when last reference goes away.
00145    FontAttributes_t fFA;            // Desired attributes for named font.
00146 };
00147 
00148 // enums
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 // Possible values for entries in the "types" field in a TGFont structure,
00165 // which classifies the types of all characters in the given font. This
00166 // information is used when measuring and displaying characters.
00167 //
00168 // kCharNormal:         Standard character.
00169 // kCharReplace:        This character doesn't print: instead of displaying
00170 //                      character, display a replacement sequence like "\n"
00171 //                      (for those characters where ANSI C defines such a
00172 //                      sequence) or a sequence of the form "\xdd" where dd
00173 //                      is the hex equivalent of the character.
00174 // kCharSkip:           Don't display anything for this character. This is
00175 //                      only used where the font doesn't contain all the
00176 //                      characters needed to generate replacement sequences.
00177 enum ECharType { kCharNormal, kCharReplace, kCharSkip };
00178 
00179 
00180 // The following structures are used as two-way maps between the values for
00181 // the fields in the FontAttributes_t structure and the strings used when
00182 // parsing both option-value format and style-list format font name strings.
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 // The following structures are used when parsing XLFD's into a set of
00209 // FontAttributes_t.
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         }  // Assume anything else is "normal".
00220 };
00221 
00222 static const FontStateMap_t gXlfdSlantMap[] = {
00223    { kFontSlantRoman,   "r"  },
00224    { kFontSlantItalic,  "i"  },
00225    { kFontSlantOblique, "o"  },
00226    { kFontSlantRoman,   0    }  // Assume anything else is "roman".
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 // Characters used when displaying control sequences.
00246 
00247 static char gHexChars[] = "0123456789abcdefxtnvr\\";
00248 
00249 
00250 // The following table maps some control characters to sequences like '\n'
00251 // rather than '\x10'. A zero entry in the table means no such mapping
00252 // exists, and the table only maps characters less than 0x10.
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    // Delete font.
00265 
00266    if (fFontStruct) {
00267       gVirtualX->DeleteFont(fFontStruct);
00268    }
00269 }
00270 
00271 //______________________________________________________________________________
00272 void TGFont::GetFontMetrics(FontMetrics_t *m) const
00273 {
00274    // Get font metrics.
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    // Not inline due to a bug in g++ 2.96 20000731 (Red Hat Linux 7.0)
00289 
00290    return fFontStruct;
00291 }
00292 
00293 //______________________________________________________________________________
00294 void TGFont::Print(Option_t *option) const
00295 {
00296    // Print font info.
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    // Return the name of the corresponding Postscript font for this TGFont.
00314    //
00315    // The return value is the pointsize of the TGFont. The name of the
00316    // Postscript font is appended to ds.
00317    //
00318    // If the font does not exist on the printer, the print job will fail at
00319    // print time. Given a "reasonable" Postscript printer, the following
00320    // TGFont font families should print correctly:
00321    //
00322    //     Avant Garde, Arial, Bookman, Courier, Courier New, Geneva,
00323    //     Helvetica, Monaco, New Century Schoolbook, New York,
00324    //     Palatino, Symbol, Times, Times New Roman, Zapf Chancery,
00325    //     and Zapf Dingbats.
00326    //
00327    // Any other TGFont font families may not print correctly because the
00328    // computed Postscript font name may be incorrect.
00329    //
00330    // dst -- Pointer to an initialized TString object to which the name of the
00331    //        Postscript font that corresponds to the font will be appended.
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    // Convert the case-insensitive TGFont family name to the
00342    // case-sensitive Postscript family name. Take out any spaces and
00343    // capitalize the first letter of each word.
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       // Inline, capitalize the first letter of each word, lowercase the
00367       // rest of the letters in each word, and then take out the spaces
00368       // between the words. This may make the TString shorter, which is
00369       // safe to do.
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       //dst->SetLength(dest - dst->GetString()); // dst->ResetLength(); may be better
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 //      dst->SetLength(len);
00396       dst->Append("NewCenturySchlbk");
00397       family = (char *) dst->Data() + len;
00398    }
00399 
00400    // Get the string to use for the weight.
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    // Get the string to use for the slant.
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    // The string "Roman" needs to be added to some fonts that are not bold
00436    // and not italic.
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    // Determine the number of characters from the string that will fit in the
00458    // given horizontal span. The measurement is done under the assumption that
00459    // DrawChars() will be used to actually display the characters.
00460    //
00461    // The return value is the number of characters from source that fit into
00462    // the span that extends from 0 to maxLength. *length is filled with the
00463    // x-coordinate of the right edge of the last character that did fit.
00464    //
00465    // source    -- Characters to be displayed. Need not be '\0' terminated.
00466    // numChars  -- Maximum number of characters to consider from source string.
00467    // maxLength -- If > 0, maxLength specifies the longest permissible line
00468    //              length; don't consider any character that would cross this
00469    //              x-position. If <= 0, then line length is unbounded and the
00470    //              flags argument is ignored.
00471    // flags     -- Various flag bits OR-ed together:
00472    //              TEXT_PARTIAL_OK means include the last char which only
00473    //              partially fit on this line.
00474    //              TEXT_WHOLE_WORDS means stop on a word boundary, if possible.
00475    //              TEXT_AT_LEAST_ONE means return at least one character even
00476    //              if no characters fit.
00477    // *length   -- Filled with x-location just after the terminating character.
00478 
00479    const char *p;    // Current character.
00480    const char *term; // Pointer to most recent character that may legally be a terminating character.
00481    Int_t termX;      // X-position just after term.
00482    Int_t curX;       // X-position corresponding to p.
00483    Int_t newX;       // X-position corresponding to p+1.
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    // Scan the input string one character at a time, calculating width.
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    // P points to the first character that doesn't fit in the desired
00525    // span. Use the flags to figure out what to return.
00526 
00527    if ((flags & kTextPartialOK) && (numChars > 0) && (curX < maxLength)) {
00528 
00529       // Include the first character that didn't quite fit in the desired
00530       // span. The width returned will include the width of that extra
00531       // character.
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    // A wrapper function for the more complicated interface of MeasureChars.
00557    // Computes how much space the given simple string needs.
00558    //
00559    // The return value is the width (in pixels) of the given string.
00560    //
00561    // string   -- String whose width will be computed.
00562    // numChars -- Number of characters to consider from string, or < 0 for
00563    //             strlen().
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    // Return text widht in pixels
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    // This procedure draws an underline for a given range of characters in a
00596    // given string. It doesn't draw the characters (which are assumed to have
00597    // been displayed previously); it just draws the underline. This procedure
00598    // would mainly be used to quickly underline a few characters without having
00599    // to construct an underlined font. To produce properly underlined text, the
00600    // appropriate underlined font should be constructed and used.
00601    //
00602    // dst       -- Window or pixmap in which to draw.
00603    // gc        -- Graphics context for actually drawing line.
00604    // string    -- String containing characters to be underlined or overstruck.
00605    // x, y      -- Coordinates at which first character of string is drawn.
00606    // firstChar -- Index of first character.
00607    // lastChar  -- Index of one after the last character.
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    // Computes the amount of screen space needed to display a multi-line,
00625    // justified string of text. Records all the measurements that were done
00626    // to determine to size and positioning of the individual lines of text;
00627    // this information can be used by the TGTextLayout::DrawText() procedure
00628    // to display the text quickly (without remeasuring it).
00629    //
00630    // This procedure is useful for simple widgets that want to display
00631    // single-font, multi-line text and want TGFont to handle the details.
00632    //
00633    // The return value is a TGTextLayout token that holds the measurement
00634    // information for the given string. The token is only valid for the given
00635    // string. If the string is freed, the token is no longer valid and must
00636    // also be deleted.
00637    //
00638    // The dimensions of the screen area needed to display the text are stored
00639    // in *width and *height.
00640    //
00641    // string     -- String whose dimensions are to be computed.
00642    // numChars   -- Number of characters to consider from string, or < 0 for
00643    //               strlen().
00644    // wrapLength -- Longest permissible line length, in pixels. <= 0 means no
00645    //               automatic wrapping: just let lines get as long as needed.
00646    // justify    -- How to justify lines.
00647    // flags      -- Flag bits OR-ed together. kTextIgnoreTabs means that tab
00648    //               characters should not be expanded. kTextIgnoreNewlines
00649    //               means that newline characters should not cause a line break.
00650    // width      -- Filled with width of string.
00651    // height     -- Filled with height of string.
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    // Divide the string up into simple strings and measure each string.
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          // Find the next special character in the string.
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       // Special points at the next special character (or the end of the
00713       // string). Process characters between start and special.
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          // Handle the special character.
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                // More chars can still fit on this line.
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       // No more characters are going to go on this line, either because
00755       // no more characters can fit or there are no more characters left.
00756       // Consume all extra spaces at end of line.
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          // Append all the extra spaces on this line to the end of the
00773          // last text chunk.
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       // Save current line length, then move current position to start of
00786       // next line.
00787 
00788       if (curX > maxWidth) {
00789          maxWidth = curX;
00790       }
00791 
00792       // Remember width of this line, so that all chunks on this line
00793       // can be centered or right justified, if necessary.
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    // If last line ends with a newline, then we need to make a 0 width
00815    // chunk on the next line. Otherwise "Hello" and "Hello\n" are the
00816    // same height.
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    // Using maximum line length, shift all the chunks so that the lines are
00827    // all justified correctly.
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       // This fake chunk is used by the other procedures so that they can
00854       // pretend that there is a chunk with no chars in it, which makes
00855       // the coding simpler.
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    // destructor
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    // Use the information in the TGTextLayout object to display a multi-line,
00895    // justified string of text.
00896    //
00897    // This procedure is useful for simple widgets that need to display
00898    // single-font, multi-line text and want TGFont to handle the details.
00899    //
00900    // dst       -- Window or pixmap in which to draw.
00901    // gc        -- Graphics context to use for drawing text.
00902    // x, y      -- Upper-left hand corner of rectangle in which to draw
00903    //              (pixels).
00904    // firstChar -- The index of the first character to draw from the given
00905    //              text item. 0 specfies the beginning.
00906    // lastChar  -- The index just after the last character to draw from the
00907    //              given text item. A number < 0 means to draw all characters.
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    // Use the information in the TGTextLayout object to display an underline
00941    // below an individual character. This procedure does not draw the text,
00942    // just the underline.
00943    //
00944    // This procedure is useful for simple widgets that need to display
00945    // single-font, multi-line text with an individual character underlined
00946    // and want TGFont to handle the details. To display larger amounts of
00947    // underlined text, construct and use an underlined font.
00948    //
00949    // dst       -- Window or pixmap in which to draw.
00950    // gc        -- Graphics context to use for drawing text.
00951    // x, y      -- Upper-left hand corner of rectangle in which to draw
00952    //              (pixels).
00953    // underline -- Index of the single character to underline, or -1 for
00954    //              no underline.
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    // Use the information in the TGTextLayout token to determine the character
00970    // closest to the given point. The point must be specified with respect to
00971    // the upper-left hand corner of the text layout, which is considered to be
00972    // located at (0, 0).
00973    //
00974    // Any point whose y-value is less that 0 will be considered closest to the
00975    // first character in the text layout; any point whose y-value is greater
00976    // than the height of the text layout will be considered closest to the last
00977    // character in the text layout.
00978    //
00979    // Any point whose x-value is less than 0 will be considered closest to the
00980    // first character on that line; any point whose x-value is greater than the
00981    // width of the text layout will be considered closest to the last character
00982    // on that line.
00983    //
00984    // The return value is the index of the character that was closest to the
00985    // point. Given a text layout with no characters, the value 0 will always
00986    // be returned, referring to a hypothetical zero-width placeholder character.
00987 
00988    LayoutChunk_t *chunk, *last;
00989    Int_t i, n, dummy, baseline, pos;
00990 
00991    if (y < 0) {
00992       // Point lies above any line in this layout. Return the index of
00993       // the first char.
00994 
00995       return 0;
00996    }
00997 
00998    // Find which line contains the point.
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             // Point is to the left of all chunks on this line. Return
01006             // the index of the first character on this line.
01007 
01008             return (chunk->fStart - fString);
01009          }
01010          if (x >= fWidth) {
01011 
01012          // If point lies off right side of the text layout, return
01013          // the last char in the last chunk on this line. Without
01014          // this, it might return the index of the first char that
01015          // was located outside of the text layout.
01016 
01017             x = INT_MAX;
01018          }
01019 
01020          // Examine all chunks on this line to see which one contains
01021          // the specified point.
01022 
01023          last = chunk;
01024          while ((i < fNumChunks) && (chunk->fY == baseline)) {
01025             if (x < chunk->fX + chunk->fTotalWidth) {
01026 
01027                // Point falls on one of the characters in this chunk.
01028 
01029                if (chunk->fNumDisplayChars < 0) {
01030 
01031                   // This is a special chunk that encapsulates a single
01032                   // tab or newline char.
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          // Point is to the right of all chars in all the chunks on this
01046          // line. Return the index just past the last char in the last
01047          // chunk on this line.
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    // Point lies below any line in this text layout. Return the index
01058    // just past the last char.
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    // Use the information in the TGTextLayout token to return the bounding box
01067    // for the character specified by index.
01068    //
01069    // The width of the bounding box is the advance width of the character, and
01070    // does not include and left- or right-bearing. Any character that extends
01071    // partially outside of the text layout is considered to be truncated at the
01072    // edge. Any character which is located completely outside of the text
01073    // layout is considered to be zero-width and pegged against the edge.
01074    //
01075    // The height of the bounding box is the line height for this font,
01076    // extending from the top of the ascent to the bottom of the descent.
01077    // Information about the actual height of the individual letter is not
01078    // available.
01079    //
01080    // A text layout that contains no characters is considered to contain a
01081    // single zero-width placeholder character.
01082    //
01083    // The return value is 0 if the index did not specify a character in the
01084    // text layout, or non-zero otherwise. In that case, *bbox is filled with
01085    // the bounding box of the character.
01086    //
01087    // layout -- Layout information, from a previous call to ComputeTextLayout().
01088    // index  -- The index of the character whose bbox is desired.
01089    // x, y   -- Filled with the upper-left hand corner, in pixels, of the
01090    //           bounding box for the character specified by index, if non-NULL.
01091    // w, h   -- Filled with the width and height of the bounding box for the
01092    //           character specified by index, if non-NULL.
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       // Special case to get location just past last char in layout.
01126 
01127       chunk--;
01128       xx = chunk->fX + chunk->fTotalWidth;
01129       ww = 0;
01130    } else {
01131       return 0;
01132    }
01133 
01134    // Ensure that the bbox lies within the text layout. This forces all
01135    // chars that extend off the right edge of the text layout to have
01136    // truncated widths, and all chars that are completely off the right
01137    // edge of the text layout to peg to the edge and have 0 width.
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    // Computes the distance in pixels from the given point to the given
01165    // text layout. Non-displaying space characters that occur at the end of
01166    // individual lines in the text layout are ignored for hit detection
01167    // purposes.
01168    //
01169    // The return value is 0 if the point (x, y) is inside the text layout.
01170    // If the point isn't inside the text layout then the return value is the
01171    // distance in pixels from the point to the text item.
01172    //
01173    // x, y -- Coordinates of point to check, with respect to the upper-left
01174    //         corner of the text layout (in pixels).
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          // Newline characters are not counted when computing distance
01188          // (but tab characters would still be considered).
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    // Determines whether a text layout lies entirely inside, entirely outside,
01229    // or overlaps a given rectangle. Non-displaying space characters that occur
01230    // at the end of individual lines in the text layout are ignored for
01231    // intersection calculations.
01232    //
01233    // The return value is -1 if the text layout is entirely outside of the
01234    // rectangle, 0 if it overlaps, and 1 if it is entirely inside of the
01235    // rectangle.
01236    //
01237    // x, y -- Upper-left hand corner, in pixels, of rectangular area to compare
01238    //         with text layout. Coordinates are with respect to the upper-left
01239    //         hand corner of the text layout itself.
01240    // w, h -- The width and height of the above rectangular area, in pixels.
01241 
01242    Int_t result, i, x1, y1, x2, y2;
01243    LayoutChunk_t *chunk;
01244    Int_t left, top, right, bottom;
01245 
01246    // Scan the chunks one at a time, seeing whether each is entirely in,
01247    // entirely out, or overlapping the rectangle.  If an overlap is
01248    // detected, return immediately; otherwise wait until all chunks have
01249    // been processed and see if they were all inside or all outside.
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          // Newline characters are not counted when computing area
01263          // intersection (but tab characters would still be considered).
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    // Outputs the contents of a text layout in Postscript format. The set of
01294    // lines in the text layout will be rendered by the user supplied Postscript
01295    // function. The function should be of the form:
01296    //
01297    //     justify x y string  function  --
01298    //
01299    // Justify is -1, 0, or 1, depending on whether the following string should
01300    // be left, center, or right justified, x and y is the location for the
01301    // origin of the string, string is the sequence of characters to be printed,
01302    // and function is the name of the caller-provided function; the function
01303    // should leave nothing on the stack.
01304    //
01305    // The meaning of the origin of the string (x and y) depends on the
01306    // justification. For left justification, x is where the left edge of the
01307    // string should appear. For center justification, x is where the center of
01308    // the string should appear. And for right justification, x is where the
01309    // right edge of the string should appear. This behavior is necessary
01310    // because, for example, right justified text on the screen is justified
01311    // with screen metrics. The same string needs to be justified with printer
01312    // metrics on the printer to appear in the correct place with respect to
01313    // other similarly justified strings. In all circumstances, y is the
01314    // location of the baseline for the string.
01315    //
01316    // result is modified to hold the Postscript code that will render the text
01317    // layout.
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             // Tricky point: the "03" is necessary in the sprintf
01347             // below, so that a full three digits of octal are
01348             // always generated. Without the "03", a number
01349             // following this sequence could be interpreted by
01350             // Postscript as part of this sequence.
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          // If there are a whole bunch of returns or tabs in a row,
01366          // then buf[] could get filled up.
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    // Helper function for ComputeTextLayout(). Encapsulates a measured set of
01387    // characters in a chunk that can be quickly drawn.
01388    //
01389    // Returns a pointer to the new chunk in the text layout. The text layout is
01390    // reallocated to hold more chunks as necessary.
01391    //
01392    // Currently, ComputeTextLayout() stores contiguous ranges of "normal"
01393    // characters in a chunk, along with individual tab and newline chars in
01394    // their own chunks. All characters in the text layout are accounted for.
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    // Draw a string of characters on the screen. DrawCharsExp() expands
01435    // control characters that occur in the string to \X or \xXX sequences.
01436    // DrawChars() just draws the strings.
01437    //
01438    // dst      -- Window or pixmap in which to draw.
01439    // gc       -- Graphics context for drawing characters.
01440    // source   -- Characters to be displayed. Need not be'\0' terminated.
01441    //             For DrawChars(), all meta-characters (tabs, control
01442    //             characters, and newlines) should be stripped out of the
01443    //             string that is passed to this function. If they are not
01444    //             stripped out, they will be displayed as regular printing
01445    //             characters.
01446    // numChars -- Number of characters in string.
01447    // x, y     -- Coordinates at which to place origin of string when drawing.
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    // Perform a quick sanity check to ensure we won't overflow the X
01477    // coordinate space.
01478 
01479    Int_t max_width =  gVirtualX->TextWidth(fFontStruct, "@", 1);
01480 
01481    if ((x + (max_width * numChars) > 0x7fff)) {
01482       int length;
01483 
01484       // The string we are being asked to draw is too big and would overflow
01485       // the X coordinate space. Unfortunatley X servers aren't too bright
01486       // and so they won't deal with this case cleanly. We need to truncate
01487       // the string before sending it to X.
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    // Create a font pool.
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    // Cleanup font pool.
01527 
01528    delete fList;
01529 }
01530 
01531 //______________________________________________________________________________
01532 TGFont *TGFontPool::GetFont(const char *font, Bool_t fixedDefault)
01533 {
01534    // Get the specified font.
01535    // The font can be one of the following forms:
01536    //        XLFD (see X documentation)
01537    //        "Family [size [style] [style ...]]"
01538    // Returns 0 if error or no font can be found.
01539    // If fixedDefault is false the "fixed" font will not be substituted
01540    // as fallback when the asked for font does not exist.
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       // Construct a font based on a named font.
01558       nf->AddReference();
01559       f = GetFontFromAttributes(&nf->fFA, 0);
01560 
01561    } else {
01562 
01563       // Native font (aka string in XLFD format)?
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             //fontCache.DeleteHashEntry(cacheHash);
01575 
01576             return 0;
01577          }
01578 
01579          // String contained the attributes inline.
01580          f = GetFontFromAttributes(&fa, 0);
01581       }
01582    }
01583 
01584    fList->Add(f);
01585 
01586    f->SetRefCount(1);
01587    //f->cacheHash = cacheHash;
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    // Make sure the tab width isn't zero (some fonts may not have enough
01598    // information to set a reasonable tab width).
01599 
01600    if (!f->fTabWidth) {
01601       f->fTabWidth = 1;
01602    }
01603 
01604    // Get information used for drawing underlines in generic code on a
01605    // non-underlined font.
01606 
01607    Int_t descent = f->fFM.fDescent;
01608    f->fUnderlinePos = descent/2;  // ==!== could be set by MakeFont()
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       // If this set of values would cause the bottom of the underline
01617       // bar to stick below the descent of the font, jack the underline
01618       // up a bit higher.
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    // Use font, i.e. increases ref count of specified font. Returns 0
01635    // if font is not found.
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    // Use font, i.e. increases ref count of specified font.
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    // Returns font specified bay family, pixel/point size, weight and slant
01671    //  negative value of ptsize means size in pixels
01672    //  positive value of ptsize means size in points
01673    //
01674    //  For example:
01675    //    TGFont *font = fpool->GetFont("helvetica", -9, kFontWeightNormal, kFontSlantRoman);
01676    //    font->Print();
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    // Free font. If ref count is 0 delete font.
01699 
01700    TGFont *f = (TGFont*) fList->FindObject(font);
01701    if (f) {
01702       if (f->RemoveReference() == 0) {
01703          if (font->fNamedHash) {
01704 
01705             // The font is being deleted. Determine if the associated named
01706             // font definition should and/or can be deleted too.
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    // Find font based on its font struct. Returns 0 if font is not found.
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    // Find font based on its font handle. Returns 0 if font is not found.
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    // Given a string, this procedure returns a unique identifier for the string.
01759    //
01760    // This procedure returns a pointer to a new char string corresponding to
01761    // the "string" argument. The new string has a value identical to string
01762    // (strcmp will return 0), but it's guaranteed that any other calls to this
01763    // procedure with a string equal to "string" will return exactly the same
01764    // result (i.e. can compare pointer *values* directly, without having to
01765    // call strcmp on what they point to).
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    // Return information about the font attributes as an array of strings.
01782    //
01783    // An array of FONT_NUMFIELDS strings is returned holding the value of the
01784    // font attributes in the following order:
01785    // family size weight slant underline overstrike
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    // Free attributes info.
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    // List all fonts in the pool.
01856 
01857    fList->Print(opt);
01858 }
01859 
01860 //______________________________________________________________________________
01861 void TGFont::SavePrimitive(ostream &out, Option_t * /*= ""*/)
01862 {
01863     // Save the used font as a C++ statement(s) on output stream out.
01864 
01865    char quote = '"';
01866 
01867    if (gROOT->ClassSaved(TGFont::Class())) {
01868       out << endl;
01869    } else {
01870       //  declare a font object to reflect required user changes
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'))) {   // skip spaces
01893       ++p;
01894    }
01895 
01896    if (!*p) {
01897       return 0;
01898    }
01899 
01900    if (*p == '"') {  // quoted string
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    // Converts a string into a set of font attributes that can be used to
01931    // construct a font.
01932    //
01933    // The string can be one of the following forms:
01934    //        XLFD (see X documentation)
01935    //        "Family [size [style] [style ...]]"
01936    //
01937    // The return value is kFALSE if the object was syntactically
01938    // invalid. Otherwise, fills the font attribute buffer with the values
01939    // parsed from the string and returns kTRUE. The structure must already be
01940    // properly initialized.
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     // This appears to be an XLFD.
01953 
01954       xa.fFA = *fa;
01955       result = ParseXLFD(str, &xa);
01956       if (result) {
01957          *fa = xa.fFA;
01958          delete[] str;
01959          return kTRUE;  //OK
01960       }
01961    }
01962 
01963    // Wasn't an XLFD or "-option value" string. Try it as a
01964    // "font size style" list.
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       // Unknown style.
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    // Break up a fully specified XLFD into a set of font attributes.
02020    //
02021    // Return value is kFALSE if string was not a fully specified XLFD.
02022    // Otherwise, fills font attribute buffer with the values parsed from
02023    // the XLFD and returns kTRUE.
02024    //
02025    // string -- Parseable font description string.
02026    // xa     -- XLFD attributes structure whose fields are to be modified.
02027    //           Structure must already be properly initialized.
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    // An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common,
02059    // but it is (strictly) malformed, because the first * is eliding both
02060    // the Setwidth and the Addstyle fields. If the Addstyle field is a
02061    // number, then assume the above incorrect form was used and shift all
02062    // the rest of the fields up by one, so the number gets interpreted
02063    // as a pixelsize.
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    // Bail if we don't have enough of the fields (up to pointsize).
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    // XLFD_ADD_STYLE ignored.
02101 
02102    // Pointsize in tenths of a point, but treat it as tenths of a pixel.
02103 
02104    if (FieldSpecified(field[XLFD_POINT_SIZE])) {
02105       if (field[XLFD_POINT_SIZE][0] == '[') {
02106 
02107          // Some X fonts have the point size specified as follows:
02108          //
02109          //      [ N1 N2 N3 N4 ]
02110          //
02111          // where N1 is the point size (in points, not decipoints!), and
02112          // N2, N3, and N4 are some additional numbers that I don't know
02113          // the purpose of, so I ignore them.
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    // Pixel height of font. If specified, overrides pointsize.
02128 
02129    if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
02130       if (field[XLFD_PIXEL_SIZE][0] == '[') {
02131 
02132          // Some X fonts have the pixel size specified as follows:
02133          //
02134          //      [ N1 N2 N3 N4 ]
02135          //
02136          // where N1 is the pixel size, and where N2, N3, and N4
02137          // are some additional numbers that I don't know
02138          // the purpose of, so I ignore them.
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    // XLFD_RESOLUTION_X ignored.
02153 
02154    // XLFD_RESOLUTION_Y ignored.
02155 
02156    // XLFD_SPACING ignored.
02157 
02158    // XLFD_AVERAGE_WIDTH ignored.
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    // Given a lookup table, map a string to a number in the table.
02174    //
02175    // If strKey was equal to the string keys of one of the elements in the
02176    // table, returns the numeric key of that element. Returns the numKey
02177    // associated with the last element (the NULL string one) in the table
02178    // if strKey was not equal to any of the string keys in the table.
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    // Given a lookup table, map a number to a string in the table.
02198    //
02199    // If numKey was equal to the numeric key of one of the elements in the
02200    // table, returns the string key of that element. Returns NULL if numKey
02201    // was not equal to any of the numeric keys in the table
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    // Helper function for ParseXLFD(). Determines if a field in the XLFD was
02213    // set to a non-null, non-don't-care value.
02214    //
02215    // The return value is kFALSE if the field in the XLFD was not set and
02216    // should be ignored, kTRUE otherwise.
02217    //
02218    // field -- The field of the XLFD to check. Strictly speaking, only when
02219    //          the string is "*" does it mean don't-care. However, an
02220    //          unspecified or question mark is also interpreted as don't-care.
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    // Given a font, return a textual string identifying it.
02236 
02237    return font->GetName();
02238 }
02239 
02240 //______________________________________________________________________________
02241 char **TGFontPool::GetFontFamilies()
02242 {
02243    // Return information about the font families that are available on the
02244    // current display.
02245    //
02246    // An array of strings is returned holding a list of all the available font
02247    // families. The array is terminated with a NULL pointer.
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    // Delete an array of families allocated GetFontFamilies() method
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    // Given a desired set of attributes for a font, find a font with the
02320    // closest matching attributes and create a new TGFont object.
02321    // The return value is a pointer to a TGFont object that represents the
02322    // font with the desired attributes. If a font with the desired attributes
02323    // could not be constructed, some other font will be substituted
02324    // automatically.
02325    //
02326    // Every call to this procedure returns a new TGFont object, even if the
02327    // specified attributes have already been seen before.
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    // Couldn't find exact match. Now fall back to other available physical fonts.
02359 
02360    fmt = "-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*";
02361    buf = TString::Format(fmt, family);
02362    nameList = gVirtualX->ListFonts(buf.Data(), 32768, numNames);
02363    if (!numNames) {
02364       // Try getting some system font.
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    // Inspect each of the XLFDs and pick the one that most closely
02385    // matches the desired attributes.
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       // Since most people used to use -adobe-* in their XLFDs,
02401       // preserve the preference for "adobe" foundry. Otherwise
02402       // some applications looks may change slightly if another foundry
02403       // is chosen.
02404 
02405       if (strcasecmp(xa.fFoundry, "adobe") != 0) {
02406          score += 3000;
02407       }
02408       if (!xa.fFA.fPointsize) {
02409 
02410          // A scaleable font is almost always acceptable, but the
02411          // corresponding bitmapped font would be better.
02412 
02413          score += 10;
02414          scaleable = 1;
02415       } else {
02416 
02417          // A font that is too small is better than one that is too big.
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          // Italic fonts are preferred over oblique.
02432 
02433          //score += 4;
02434       }
02435       if (xa.fSetwidth != kFontSWNormal) {
02436 
02437          // The normal setwidth is highly preferred.
02438 
02439          score += 2000;
02440       }
02441       if (xa.fCharset == kFontCSOther) {
02442 
02443          // The standard character set is highly preferred over
02444          // foreign languages charsets (because we don't support
02445          // other languages yet).
02446 
02447          score += 11000;
02448       }
02449       if ((xa.fCharset == kFontCSNormal) && (xa.fEncoding != 1)) {
02450 
02451          // The '1' encoding for the characters above 0x7f is highly
02452          // preferred over the other encodings.
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    // Now we know which is the closest matching scaleable font and the
02473    // closest matching bitmapped font. If the scaleable font was a
02474    // better match, try getting the scaleable font; however, if the
02475    // scalable font was not actually available in the desired pointsize,
02476    // fall back to the closest bitmapped font.
02477 
02478    fontStruct = 0;
02479 
02480    if (bestScaleableScore < bestScore) {
02481       char *str, *rest;
02482 
02483       // Fill in the desired pointsize info for this font.
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          // This shouldn't happen because the font name is one of the
02507          // names that X gave us to use, but it does anyhow.
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    // The return value is a pointer to an TGFont object that represents the
02531    // native font. If a native font by the given name could not be found,
02532    // the return value is NULL.
02533    //
02534    // Every call to this procedure returns a new TGFont object, even if the
02535    // name has already been seen before. The caller should call FreeFont
02536    // when the font is no longer needed.
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    // Helper for GetNativeFont() and GetFontFromAttributes(). Creates and
02554    // intializes a new TGFont object.
02555    //
02556    // font       -- If non-NULL, store the information in this existing TGFont
02557    //               object, rather than creating a new one; the existing
02558    //               contents of the font will be released. If NULL, a new
02559    //               TGFont object is created.
02560    // fontStruct -- information about font.
02561    // fontName   -- The string passed to TVirtualX::LoadQueryFont() to construct the
02562    //               fontStruct.
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    // Classify the characters.
02608 
02609    firstChar = 0x20; //fontStruct->min_char_or_byte2;
02610    lastChar = 0xff; //fontStruct->max_char_or_byte2;
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    // Compute the widths for all the normal characters. Any other
02622    // characters are given an initial width of 0. Also, this determines
02623    // if this is a fixed or variable width font, by comparing the widths
02624    // of all the normal characters.
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    // Compute the widths of the characters that should be replaced with
02646    // control character expansions. If the appropriate chars are not
02647    // available in this font, then control character expansions will not
02648    // be used; control chars will be invisible & zero-width.
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       // If this set of cobbled together values would cause the bottom of
02680       // the underline bar to stick below the descent of the font, jack
02681       // the underline up a bit higher.
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    // When displaying text in a widget, a backslashed escape sequence is
02698    // substituted for control characters that occur in the text. Given a
02699    // control character, fill in a buffer with the replacement string that
02700    // should be displayed.
02701    //
02702    // The return value is the length of the substitute string, buf is
02703    // filled with the substitute string; it is not '\0' terminated.
02704    //
02705    // c   -- The control character to be replaced.
02706    // buf -- Buffer that gets replacement string. It only needs to be
02707    //        4 characters long.
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 }

Generated on Tue Jul 5 14:21:59 2011 for ROOT_528-00b_version by  doxygen 1.5.1