#include "TGFont.h"
#include "TGClient.h"
#include "THashTable.h"
#include "TVirtualX.h"
#include "TObjString.h"
#include "TGWidget.h"
#include <errno.h>
#include "Riostream.h"
#include "TROOT.h"
#include "TError.h"
#include "TMath.h"
ClassImp(TGFont)
ClassImp(TGFontPool)
ClassImp(TGTextLayout)
#define FONT_FAMILY     0
#define FONT_SIZE       1
#define FONT_WEIGHT     2
#define FONT_SLANT      3
#define FONT_UNDERLINE  4
#define FONT_OVERSTRIKE 5
#define FONT_NUMFIELDS  6
#define XLFD_FOUNDRY        0
#define XLFD_FAMILY         1
#define XLFD_WEIGHT         2
#define XLFD_SLANT          3
#define XLFD_SETWIDTH       4
#define XLFD_ADD_STYLE      5
#define XLFD_PIXEL_SIZE     6
#define XLFD_POINT_SIZE     7
#define XLFD_RESOLUTION_X   8
#define XLFD_RESOLUTION_Y   9
#define XLFD_SPACING        10
#define XLFD_AVERAGE_WIDTH  11
#define XLFD_REGISTRY       12
#define XLFD_ENCODING       13
#define XLFD_NUMFIELDS      14   // Number of fields in XLFD.
struct LayoutChunk_t {
   const char *fStart;     
                           
                           
   Int_t fNumChars;        
   Int_t fNumDisplayChars; 
                           
                           
                           
                           
                           
   Int_t fX;               
   Int_t fY;               
                           
                           
   Int_t fTotalWidth;      
                           
                           
   Int_t fDisplayWidth;    
                           
                           
                           
};
struct XLFDAttributes_t {
   FontAttributes_t fFA; 
   const char *fFoundry; 
   Int_t fSlant;         
   Int_t fSetwidth;      
   Int_t fCharset;       
   Int_t fEncoding;      
};
class TNamedFont : public TObjString, public TRefCnt {
public:
   Int_t fDeletePending;   
   FontAttributes_t fFA;   
};
enum EFontSpacing { kFontProportional = 0,
                    kFontFixed = 1,
                    kFontMono = 1,
                    kFontCharcell = 2 };
enum EFontSetWidth { kFontSWNormal = 0,
                     kFontSWCondence = 1,
                     kFontSWExpand = 2,
                     kFontSWUnknown = 3 };
enum EFontCharset { kFontCSNormal = 0,
                    kFontCSSymbol = 1,
                    kFontCSOther = 2 };
enum ECharType { kCharNormal, kCharReplace, kCharSkip };
struct FontStateMap_t { Int_t fNumKey; char *fStrKey; };
static FontStateMap_t gWeightMap[] = {
   { kFontWeightNormal,  "normal" },
   { kFontWeightBold,    "bold"   },
   { kFontWeightUnknown, 0        }
};
static FontStateMap_t gSlantMap[] = {
   { kFontSlantRoman,   "roman"  },
   { kFontSlantItalic,  "italic" },
   { kFontSlantUnknown, 0        }
};
static FontStateMap_t gUnderlineMap[] = {
   { 1, "underline" },
   { 0, 0           }
};
static FontStateMap_t gOverstrikeMap[] = {
   { 1, "overstrike" },
   { 0, 0            }
};
static FontStateMap_t gXlfdgWeightMap[] = {
   { kFontWeightNormal, "normal"   },
   { kFontWeightNormal, "medium"   },
   { kFontWeightNormal, "book"     },
   { kFontWeightNormal, "light"    },
   { kFontWeightBold,   "bold"     },
   { kFontWeightBold,   "demi"     },
   { kFontWeightBold,   "demibold" },
   { kFontWeightNormal,  0         }  
};
static FontStateMap_t gXlfdSlantMap[] = {
   { kFontSlantRoman,   "r"  },
   { kFontSlantItalic,  "i"  },
   { kFontSlantOblique, "o"  },
   { kFontSlantRoman,   0    }  
};
static FontStateMap_t gXlfdSetwidthMap[] = {
   { kFontSWNormal,   "normal"        },
   { kFontSWCondence, "narrow"        },
   { kFontSWCondence, "semicondensed" },
   { kFontSWCondence, "condensed"     },
   { kFontSWUnknown,  0               }
};
static FontStateMap_t gXlfdCharsetMap[] = {
   { kFontCSNormal, "iso8859" },
   { kFontCSSymbol, "adobe"   },
   { kFontCSSymbol, "sun"     },
   { kFontCSOther,  0         }
};
static char gHexChars[] = "0123456789abcdefxtnvr\\";
static char gMapChars[] = {
   0, 0, 0, 0, 0, 0, 0, 'a', 'b', 't', 'n', 'v', 'f', 'r', 0
};
static int GetControlCharSubst(int c, char buf[4]);
void FontAttributes_t::Init()
{
   
   fFamily = 0;
   fPointsize = 0;
   fWeight = kFontWeightNormal;
   fSlant = kFontSlantRoman;
   fUnderline = 0;
   fOverstrike = 0;
}
TGFont::~TGFont()
{
   
   if (fFontStruct) {
      gVirtualX->DeleteFont(fFontStruct);
   }
}
void TGFont::GetFontMetrics(FontMetrics_t *m) const
{
   
   if (!m) {
      Error("GetFontMetrics", "argument may not be 0");
      return;
   }
   *m = fFM;
   m->fLinespace = fFM.fAscent + fFM.fDescent;
}
FontStruct_t TGFont::operator()() const
{
   
   return fFontStruct;
}
void TGFont::Print(Option_t *option) const
{
   
   TString opt = option;
   if ((opt == "full") && fNamedHash) {
      Printf("TGFont: %s, %s, %s, ref cnt = %u",
              fNamedHash->GetName(),
              fFM.fFixed ? "fixed" : "prop", References());
   } else {
      Printf("TGFont: %s, %s, ref cnt = %u", fName.Data(),
              fFM.fFixed ? "fixed" : "prop", References());
   }
}
Int_t TGFont::PostscriptFontName(TString *dst) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   const char *family;
   TString weightString;
   TString slantString;
   char *src, *dest;
   Int_t upper, len;
   len = dst->Length();
   
   
   
   family = fFA.fFamily;
   if (strncasecmp(family, "itc ", 4) == 0) {
      family = family + 4;
   }
   if ((strcasecmp(family, "Arial") == 0)
       || (strcasecmp(family, "Geneva") == 0)) {
      family = "Helvetica";
   } else if ((strcasecmp(family, "Times New Roman") == 0)
              || (strcasecmp(family, "New York") == 0)) {
      family = "Times";
   } else if ((strcasecmp(family, "Courier New") == 0)
              || (strcasecmp(family, "Monaco") == 0)) {
      family = "Courier";
   } else if (strcasecmp(family, "AvantGarde") == 0) {
      family = "AvantGarde";
   } else if (strcasecmp(family, "ZapfChancery") == 0) {
      family = "ZapfChancery";
   } else if (strcasecmp(family, "ZapfDingbats") == 0) {
      family = "ZapfDingbats";
   } else {
      
      
      
      
      dst->Append(family);
      src = dest = (char*)dst->Data() + len;
      upper = 1;
      for (; *src != '\0'; src++, dest++) {
         while (isspace(UChar_t(*src))) {
            src++;
            upper = 1;
         }
         *dest = *src;
         if ((upper != 0) && (islower(UChar_t(*src)))) {
            *dest = toupper(UChar_t(*src));
         }
         upper = 0;
      }
      *dest = '\0';
      
      family = (char *) dst->Data() + len;
   }
   if (family != (char *) dst->Data() + len) {
      dst->Append(family);
      family = (char *) dst->Data() + len;
   }
   if (strcasecmp(family, "NewCenturySchoolbook") == 0) {
      dst->Append("NewCenturySchlbk");
      family = (char *) dst->Data() + len;
   }
   
   weightString = "";
   if (fFA.fWeight == kFontWeightNormal) {
      if (strcmp(family, "Bookman") == 0) {
         weightString = "Light";
      } else if (strcmp(family, "AvantGarde") == 0) {
         weightString = "Book";
      } else if (strcmp(family, "ZapfChancery") == 0) {
         weightString = "Medium";
      }
   } else {
      if ((strcmp(family, "Bookman") == 0)
           || (strcmp(family, "AvantGarde") == 0)) {
         weightString = "Demi";
      } else {
         weightString = "Bold";
      }
   }
   
   slantString = "";
   if (fFA.fSlant == kFontSlantRoman) {
      ;
   } else {
      if ((strcmp(family, "Helvetica") == 0)
           || (strcmp(family, "Courier") == 0)
           || (strcmp(family, "AvantGarde") == 0)) {
         slantString = "Oblique";
      } else {
         slantString = "Italic";
      }
   }
   
   
   if ((slantString.IsNull()) && (weightString.IsNull())) {
      if ((strcmp(family, "Times") == 0)
           || (strcmp(family, "NewCenturySchlbk") == 0)
           || (strcmp(family, "Palatino") == 0)) {
         dst->Append("-Roman");
      }
   } else {
      dst->Append("-");
      if (!weightString.IsNull()) dst->Append(weightString);
      if (!slantString.IsNull()) dst->Append(slantString);
   }
   return fFA.fPointsize;
}
Int_t TGFont::MeasureChars(const char *source, Int_t numChars, Int_t maxLength,
                          Int_t flags, Int_t *length) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   const char *p;    
   const char *term; 
   Int_t termX;      
   Int_t curX;       
   Int_t newX;       
   Int_t c, sawNonSpace;
   if (!numChars) {
      *length = 0;
      return 0;
   }
   if (maxLength <= 0) {
      maxLength = INT_MAX;
   }
   newX = curX = termX = 0;
   p = term = source;
   sawNonSpace = !isspace(UChar_t(*p));
   
   for (c = UChar_t(*p);;) {
      newX += fWidths[c];
      if (newX > maxLength) {
         break;
      }
      curX = newX;
      numChars--;
      p++;
      if (!numChars) {
         term = p;
         termX = curX;
         break;
      }
      c = UChar_t(*p);
      if (isspace(c)) {
         if (sawNonSpace) {
            term = p;
            termX = curX;
            sawNonSpace = 0;
         }
      } else {
         sawNonSpace = 1;
      }
   }
   
   
   if ((flags & kTextPartialOK) && (numChars > 0) && (curX < maxLength)) {
      
      
      
      numChars--;
      curX = newX;
      p++;
   }
   if ((flags & kTextAtLeastOne) && (term == source) && (numChars > 0)) {
      term = p;
      termX = curX;
      if (term == source) {
         term++;
         termX = newX;
      }
   } else if ((numChars == 0) || !(flags & kTextWholeWords)) {
      term = p;
      termX = curX;
   }
   *length = termX;
   return term - source;
}
Int_t TGFont::TextWidth(const char *string, Int_t numChars) const
{
   
   
   
   
   
   
   
   
   Int_t width;
   if (numChars < 0) {
      numChars = strlen(string);
   }
   MeasureChars(string, numChars, 0, 0, &width);
   return width;
}
Int_t TGFont::XTextWidth(const char *string, Int_t numChars) const
{
   
   int width;
   if (numChars < 0) {
      numChars = strlen(string);
   }
   width = gVirtualX->TextWidth(fFontStruct, string, numChars);
   return width;
}
void TGFont::UnderlineChars(Drawable_t dst, GContext_t gc,
                            const char *string, Int_t x, Int_t y,
                            Int_t firstChar, Int_t lastChar) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   Int_t startX, endX;
   MeasureChars(string, firstChar, 0, 0, &startX);
   MeasureChars(string, lastChar, 0, 0, &endX);
   gVirtualX->FillRectangle(dst, gc, x + startX, y + fUnderlinePos,
                            (UInt_t) (endX - startX),
                            (UInt_t) fUnderlineHeight);
}
TGTextLayout *TGFont::ComputeTextLayout(const char *string, Int_t numChars,
                                        Int_t wrapLength, Int_t justify, Int_t flags,
                                        UInt_t *width, UInt_t *height) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   const char *start, *end, *special;
   Int_t n, y=0, charsThisChunk, maxChunks;
   Int_t baseline, h, curX, newX, maxWidth;
   TGTextLayout *layout;
   LayoutChunk_t *chunk;
#define MAX_LINES 50
   Int_t staticLineLengths[MAX_LINES];
   Int_t *lineLengths;
   Int_t maxLines, curLine, layoutHeight;
   lineLengths = staticLineLengths;
   maxLines = MAX_LINES;
   h = fFM.fAscent + fFM.fDescent;
   if (numChars < 0) {
      numChars = strlen(string);
   }
   maxChunks = 0;
   layout = new TGTextLayout;
   layout->fFont = this;
   layout->fString = string;
   layout->fNumChunks = 0;
   layout->fChunks = 0;
   baseline = fFM.fAscent;
   maxWidth = 0;
   
   curX = 0;
   end = string + numChars;
   special = string;
   flags &= kTextIgnoreTabs | kTextIgnoreNewlines;
   flags |= kTextWholeWords | kTextAtLeastOne;
   curLine = 0;
   for (start = string; start < end;) {
      if (start >= special) {
         
         for (special = start; special < end; special++) {
            if (!(flags & kTextIgnoreNewlines)) {
               if ((*special == '\n') || (*special == '\r')) {
                  break;
               }
            }
            if (!(flags & kTextIgnoreTabs)) {
               if (*special == '\t') {
                  break;
               }
            }
         }
      }
      
      
      chunk = 0;
      if (start < special) {
         charsThisChunk = MeasureChars(start, special - start,
                                       wrapLength - curX, flags, &newX);
         newX += curX;
         flags &= ~kTextAtLeastOne;
         if (charsThisChunk > 0) {
            chunk = NewChunk(layout, &maxChunks, start,
                             charsThisChunk, curX, newX, baseline);
            start += charsThisChunk;
            curX = newX;
         }
      }
      if ((start == special) && (special < end)) {
         
         chunk = 0;
         if (*special == '\t') {
            newX = curX + fTabWidth;
            newX -= newX % fTabWidth;
            NewChunk(layout, &maxChunks, start, 1, curX, newX, baseline)->fNumDisplayChars = -1;
            start++;
            if ((start < end) && ((wrapLength <= 0) || (newX <= wrapLength))) {
               
               curX = newX;
               flags &= ~kTextAtLeastOne;
               continue;
            }
         } else {
            NewChunk(layout, &maxChunks, start, 1, curX, 1000000000, baseline)->fNumDisplayChars = -1;
            start++;
            goto wrapLine;
         }
      }
      
      
      
      while ((start < end) && isspace(UChar_t(*start))) {
         if (!(flags & kTextIgnoreNewlines)) {
            if ((*start == '\n') || (*start == '\r')) {
               break;
            }
         }
         if (!(flags & kTextIgnoreTabs)) {
            if (*start == '\t') {
               break;
            }
         }
         start++;
      }
      if (chunk) {
         
         
         charsThisChunk = start - (chunk->fStart + chunk->fNumChars);
         if (charsThisChunk > 0) {
            chunk->fNumChars += MeasureChars(chunk->fStart + chunk->fNumChars,
                                             charsThisChunk, 0, 0, &chunk->fTotalWidth);
            chunk->fTotalWidth += curX;
         }
      }
wrapLine:
      flags |= kTextAtLeastOne;
      
      
      if (curX > maxWidth) {
         maxWidth = curX;
      }
      
      
      if (curLine >= maxLines) {
         int *newLengths;
         newLengths = new int[2 * maxLines];
         memcpy((void *) newLengths, lineLengths, maxLines * sizeof (int));
         if (lineLengths != staticLineLengths) {
            delete[] lineLengths;
         }
         lineLengths = newLengths;
         maxLines *= 2;
      }
      lineLengths[curLine] = curX;
      curLine++;
      curX = 0;
      baseline += h;
   }
   
   
   
   if ((layout->fNumChunks > 0) && ((flags & kTextIgnoreNewlines) == 0)) {
      if (layout->fChunks[layout->fNumChunks - 1].fStart[0] == '\n') {
         chunk = NewChunk(layout, &maxChunks, start, 0, curX, 1000000000, baseline);
         chunk->fNumDisplayChars = -1;
         baseline += h;
      }
   }
   
   
   curLine = 0;
   chunk = layout->fChunks;
   if (chunk) y = chunk->fY;
   for (n = 0; n < layout->fNumChunks; n++) {
      int extra;
      if (chunk->fY != y) {
         curLine++;
         y = chunk->fY;
      }
      extra = maxWidth - lineLengths[curLine];
      if (justify == kTextCenterX) {
         chunk->fX += extra / 2;
      } else if (justify == kTextRight) {
         chunk->fX += extra;
      }
      ++chunk;
   }
   layout->fWidth = maxWidth;
   layoutHeight = baseline - fFM.fAscent;
   if (layout->fNumChunks == 0) {
      layoutHeight = h;
      
      
      
      layout->fNumChunks = 1;
      layout->fChunks = new LayoutChunk_t[1];
      layout->fChunks[0].fStart = string;
      layout->fChunks[0].fNumChars = 0;
      layout->fChunks[0].fNumDisplayChars = -1;
      layout->fChunks[0].fX = 0;
      layout->fChunks[0].fY = fFM.fAscent;
      layout->fChunks[0].fTotalWidth = 0;
      layout->fChunks[0].fDisplayWidth = 0;
   }
   if (width) {
      *width = layout->fWidth;
   }
   if (height) {
      *height = layoutHeight;
   }
   if (lineLengths != staticLineLengths) {
      delete[] lineLengths;
   }
   return layout;
}
TGTextLayout::~TGTextLayout()
{
   
   if (fChunks) {
      delete[] fChunks;
   }
}
void TGTextLayout::DrawText(Drawable_t dst, GContext_t gc,
                            Int_t x, Int_t y, Int_t firstChar, Int_t lastChar) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   Int_t i, numDisplayChars, drawX;
   LayoutChunk_t *chunk;
   if (lastChar < 0) lastChar = 100000000;
   chunk = fChunks;
   for (i = 0; i < fNumChunks; i++) {
      numDisplayChars = chunk->fNumDisplayChars;
      if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
         if (firstChar <= 0) {
            drawX = 0;
            firstChar = 0;
         } else {
            fFont->MeasureChars(chunk->fStart, firstChar, 0, 0, &drawX);
         }
         if (lastChar < numDisplayChars) numDisplayChars = lastChar;
         fFont->DrawChars(dst, gc, chunk->fStart + firstChar, numDisplayChars - firstChar,
                           x + chunk->fX + drawX, y + chunk->fY);
      }
      firstChar -= chunk->fNumChars;
      lastChar -= chunk->fNumChars;
      if (lastChar <= 0) break;
      chunk++;
   }
}
void TGTextLayout::UnderlineChar(Drawable_t dst, GContext_t gc,
                                Int_t x, Int_t y, Int_t underline) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   int xx, yy, width, height;
   if ((CharBbox(underline, &xx, &yy, &width, &height) != 0)
      && (width != 0)) {
      gVirtualX->FillRectangle(dst, gc, x + xx,
                               y + yy + fFont->fFM.fAscent + fFont->fUnderlinePos,
                               (UInt_t) width, (UInt_t) fFont->fUnderlineHeight);
   }
}
Int_t TGTextLayout::PointToChar(Int_t x, Int_t y) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   LayoutChunk_t *chunk, *last;
   Int_t i, n, dummy, baseline, pos;
   if (y < 0) {
      
      
      return 0;
   }
   
   last = chunk = fChunks;
   for (i = 0; i < fNumChunks; i++) {
      baseline = chunk->fY;
      if (y < baseline + fFont->fFM.fDescent) {
         if (x < chunk->fX) {
            
            
            return (chunk->fStart - fString);
         }
         if (x >= fWidth) {
         
         
         
         
            x = INT_MAX;
         }
         
         
         last = chunk;
         while ((i < fNumChunks) && (chunk->fY == baseline)) {
            if (x < chunk->fX + chunk->fTotalWidth) {
               
               if (chunk->fNumDisplayChars < 0) {
                  
                  
                  return (chunk->fStart - fString);
               }
               n = fFont->MeasureChars(chunk->fStart, chunk->fNumChars,
                                       x + 1 - chunk->fX, kTextPartialOK, &dummy);
               return ((chunk->fStart + n - 1) - fString);
            }
            last = chunk;
            chunk++;
            i++;
         }
         
         
         
         pos = (last->fStart + last->fNumChars) - fString;
         if (i < fNumChunks) pos--;
         return pos;
      }
      last = chunk;
      chunk++;
   }
   
   
   return ((last->fStart + last->fNumChars) - fString);
}
Int_t TGTextLayout::CharBbox(Int_t index, Int_t *x, Int_t *y, Int_t *w, Int_t *h) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   LayoutChunk_t *chunk;
   Int_t i, xx, ww;
   if (index < 0) {
      return 0;
   }
   chunk = fChunks;
   for (i = 0; i < fNumChunks; i++) {
      if (chunk->fNumDisplayChars < 0) {
         if (!index) {
            xx = chunk->fX;
            ww = chunk->fTotalWidth;
            goto check;
         }
      } else if (index < chunk->fNumChars) {
         if (x) {
            fFont->MeasureChars(chunk->fStart, index, 0, 0, &xx);
            xx += chunk->fX;
         }
         if (w) {
            fFont->MeasureChars(chunk->fStart + index, 1, 0, 0, &ww);
         }
         goto check;
      }
      index -= chunk->fNumChars;
      chunk++;
   }
   if (!index) {
      
      chunk--;
      xx = chunk->fX + chunk->fTotalWidth;
      ww = 0;
   } else {
      return 0;
   }
   
   
   
   
check:
   if (y) {
      *y = chunk->fY - fFont->fFM.fAscent;
   }
   if (h) {
      *h = fFont->fFM.fAscent + fFont->fFM.fDescent;
   }
   if (xx > fWidth) {
      xx = fWidth;
   }
   if (x) {
      *x = xx;
   }
   if (w) {
      if (xx + ww > fWidth) {
         ww = fWidth - xx;
      }
      *w = ww;
   }
   return 1;
}
Int_t TGTextLayout::DistanceToText(Int_t x, Int_t y) const
{
   
   
   
   
   
   
   
   
   
   
   
   Int_t i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
   LayoutChunk_t *chunk;
   ascent = fFont->fFM.fAscent;
   descent = fFont->fFM.fDescent;
   minDist = 0;
   chunk = fChunks;
   for (i = 0; i < fNumChunks; i++) {
      if (chunk->fStart[0] == '\n') {
         
         
         chunk++;
         continue;
      }
      x1 = chunk->fX;
      y1 = chunk->fY - ascent;
      x2 = chunk->fX + chunk->fDisplayWidth;
      y2 = chunk->fY + descent;
      if (x < x1) {
         xDiff = x1 - x;
      } else if (x >= x2) {
         xDiff = x - x2 + 1;
      } else {
         xDiff = 0;
      }
      if (y < y1) {
         yDiff = y1 - y;
      } else if (y >= y2) {
         yDiff = y - y2 + 1;
      } else {
         yDiff = 0;
      }
      if ((xDiff == 0) && (yDiff == 0)) {
         return 0;
      }
      dist = (int) TMath::Hypot((Double_t) xDiff, (Double_t) yDiff);
      if ((dist < minDist) || !minDist) {
         minDist = dist;
      }
      chunk++;
   }
   return minDist;
}
Int_t TGTextLayout::IntersectText(Int_t x, Int_t y, Int_t w, Int_t h) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   Int_t result, i, x1, y1, x2, y2;
   LayoutChunk_t *chunk;
   Int_t left, top, right, bottom;
   
   
   
   
   chunk = fChunks;
   left = x;
   top = y;
   right = x + w;
   bottom = y + h;
   result = 0;
   for (i = 0; i < fNumChunks; i++) {
      if (chunk->fStart[0] == '\n') {
         
         
         chunk++;
         continue;
      }
      x1 = chunk->fX;
      y1 = chunk->fY - fFont->fFM.fAscent;
      x2 = chunk->fX + chunk->fDisplayWidth;
      y2 = chunk->fY + fFont->fFM.fDescent;
      if ((right < x1) || (left >= x2) || (bottom < y1) || (top >= y2)) {
         if (result == 1) {
            return 0;
         }
         result = -1;
      } else if ((x1 < left) || (x2 >= right) || (y1 < top) || (y2 >= bottom)) {
         return 0;
      } else if (result == -1) {
         return 0;
      } else {
         result = 1;
      }
      chunk++;
   }
   return result;
}
void TGTextLayout::ToPostscript(TString *result) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
#define MAXUSE 128
   char buf[MAXUSE + 10];
   LayoutChunk_t *chunk;
   Int_t i, j, used, c, baseline;
   chunk = fChunks;
   baseline = chunk->fY;
   used = 0;
   buf[used++] = '(';
   for (i = 0; i < fNumChunks; i++) {
      if (baseline != chunk->fY) {
         buf[used++] = ')';
         buf[used++] = '\n';
         buf[used++] = '(';
         baseline = chunk->fY;
      }
      if (chunk->fNumDisplayChars <= 0) {
         if (chunk->fStart[0] == '\t') {
            buf[used++] = '\\';
            buf[used++] = 't';
         }
      } else {
         for (j = 0; j < chunk->fNumDisplayChars; j++) {
            c = UChar_t(chunk->fStart[j]);
            if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20) || (c >= UChar_t(0x7f))) {
            
            
            
            
            
               sprintf(buf + used, "\\%03o", c);
               used += 4;
            } else {
               buf[used++] = c;
            }
            if (used >= MAXUSE) {
               buf[used] = '\0';
               result->Append(buf);
               used = 0;
            }
         }
      }
      if (used >= MAXUSE) {
         
         
         buf[used] = '\0';
         result->Append(buf);
         used = 0;
      }
      chunk++;
   }
   buf[used++] = ')';
   buf[used++] = '\n';
   buf[used]   = '\0';
   result->Append(buf);
}
LayoutChunk_t *TGFont::NewChunk(TGTextLayout *layout, Int_t *maxPtr,
                                const char *start, Int_t numChars,
                                Int_t curX, Int_t newX, Int_t y) const
{
   
   
   
   
   
   
   
   
   
   LayoutChunk_t *chunk;
   Int_t i, maxChunks;
   maxChunks = *maxPtr;
   if (layout->fNumChunks == maxChunks) {
      if (maxChunks == 0) {
         maxChunks = 1;
      } else {
         maxChunks *= 2;
      }
      chunk = new LayoutChunk_t[maxChunks];
      if (layout->fNumChunks > 0) {
         for (i=0; i<layout->fNumChunks; ++i) chunk[i] = layout->fChunks[i];
         delete[] layout->fChunks;
      }
      layout->fChunks = chunk;
      *maxPtr = maxChunks;
   }
   chunk = &layout->fChunks[layout->fNumChunks];
   chunk->fStart = start;
   chunk->fNumChars = numChars;
   chunk->fNumDisplayChars = numChars;
   chunk->fX = curX;
   chunk->fY = y;
   chunk->fTotalWidth = newX - curX;
   chunk->fDisplayWidth = newX - curX;
   layout->fNumChunks++;
   return chunk;
}
void TGFont::DrawCharsExp(Drawable_t dst, GContext_t gc,
                          const char *source, Int_t numChars,
                          Int_t x, Int_t y) const
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   const char *p;
   Int_t i, type;
   char buf[4];
   p = source;
   for (i = 0; i < numChars; i++) {
      type = fTypes[UChar_t(*p)];
      if (type != kCharNormal) {
         DrawChars(dst, gc, source, p - source, x, y);
         x += gVirtualX->TextWidth(fFontStruct, source, p - source);
         if (type == kCharReplace) {
            DrawChars(dst, gc, buf, GetControlCharSubst(UChar_t(*p), buf), x, y);
            x += fWidths[UChar_t(*p)];
         }
         source = p + 1;
      }
      p++;
   }
   DrawChars(dst, gc, source, p - source, x, y);
}
void TGFont::DrawChars(Drawable_t dst, GContext_t gc,
                       const char *source, Int_t numChars,
                       Int_t x, Int_t y) const
{
   
   
   Int_t max_width =  gVirtualX->TextWidth(fFontStruct, "@", 1);
   if ((x + (max_width * numChars) > 0x7fff)) {
      int length;
      
      
      
      
      numChars = MeasureChars(source, numChars, 0x7fff - x, 0, &length);
   }
   gVirtualX->DrawString(dst, gc, x, y, source, numChars);
   if (fFA.fUnderline != 0) {
      gVirtualX->FillRectangle(dst, gc, x,  y + fUnderlinePos,
                          (UInt_t) gVirtualX->TextWidth(fFontStruct, source, numChars),
                          (UInt_t) fBarHeight);
   }
   if (fFA.fOverstrike != 0) {
      y -= fFM.fDescent + fFM.fAscent / 10;
      gVirtualX->FillRectangle(dst, gc, x, y,
                          (UInt_t) gVirtualX->TextWidth(fFontStruct, source, numChars),
                          (UInt_t) fBarHeight);
   }
}
TGFontPool::TGFontPool(TGClient *client)
{
   
   fClient = client;
   fList   = new THashTable(50);
   fList->SetOwner();
   fNamedTable = new THashTable(50);
   fNamedTable->SetOwner();
   fUidTable = new THashTable(50);
   fUidTable->SetOwner();
}
TGFontPool::~TGFontPool()
{
   
   delete fList;
}
TGFont *TGFontPool::GetFont(const char *font, Bool_t fixedDefault)
{
   
   
   
   
   
   
   
   if (!font || !*font) {
      Error("GetFont", "argument may not be 0 or empty");
      return 0;
   }
   TGFont *f = (TGFont*)fList->FindObject(font);
   if (f) {
      f->AddReference();
      return f;
   }
   TNamedFont *nf = (TNamedFont*)fNamedTable->FindObject(font);
   if (nf) {
      
      nf->AddReference();
      f = GetFontFromAttributes(&nf->fFA, 0);
   } else {
      
      Int_t errsav = gErrorIgnoreLevel;
      gErrorIgnoreLevel = kFatal;
      f = GetNativeFont(font, fixedDefault);
      gErrorIgnoreLevel = errsav;
      if (!f) {
         FontAttributes_t fa;
         if (!ParseFontName(font, &fa)) {
            
            return 0;
         }
         
         f = GetFontFromAttributes(&fa, 0);
      }
   }
   fList->Add(f);
   f->SetRefCount(1);
   
   f->fNamedHash = nf;
   f->MeasureChars("0", 1, 0, 0, &f->fTabWidth);
   if (!f->fTabWidth) {
      f->fTabWidth = f->fFM.fMaxWidth;
   }
   f->fTabWidth *= 8;
   
   
   if (!f->fTabWidth) {
      f->fTabWidth = 1;
   }
   
   
   Int_t descent = f->fFM.fDescent;
   f->fUnderlinePos = descent/2;  
   f->fUnderlineHeight = f->fFA.fPointsize/10;
   if (!f->fUnderlineHeight) {
      f->fUnderlineHeight = 1;
   }
   if (f->fUnderlinePos + f->fUnderlineHeight > descent) {
      
      
      
      f->fUnderlineHeight = descent - f->fUnderlinePos;
      if (!f->fUnderlineHeight) {
         f->fUnderlinePos--;
         f->fUnderlineHeight = 1;
      }
   }
   return f;
}
TGFont *TGFontPool::GetFont(const TGFont *font)
{
   
   
   TGFont *f = (TGFont*)fList->FindObject(font);
   if (f) {
      f->AddReference();
      return f;
   }
   return 0;
}
TGFont *TGFontPool::GetFont(FontStruct_t fs)
{
   
   TGFont *f = FindFont(fs);
   if (f) {
      f->AddReference();
      return f;
   }
   static int i = 0;
   f = new TGFont(Form("unknown-%d", i));
   f->fFontStruct = fs;
   f->fFontH      = gVirtualX->GetFontHandle(fs);
   gVirtualX->GetFontProperties(fs, f->fFM.fAscent, f->fFM.fDescent);
   f->fFM.fLinespace = f->fFM.fAscent + f->fFM.fDescent;
   f->fFM.fMaxWidth = gVirtualX->TextWidth(fs, "@", 1);
   f->fFM.fFixed = (f->fFM.fMaxWidth == gVirtualX->TextWidth(fs, "i", 1)) ? kTRUE : kFALSE;
   fList->Add(f);
   i++;
   return f;
}
TGFont *TGFontPool::GetFont(const char *family, Int_t ptsize, Int_t weight, Int_t slant)
{
   
   char *s;
   TString tmp;
   tmp.Form("%s %d", family, ptsize);
   s = FindStateString(gWeightMap, weight);
   if (s) {
      tmp += " ";
      tmp + s;
   }
   s = FindStateString(gSlantMap, slant);
   if (s) {
      tmp += " ";
      tmp += s;
   }
   return GetFont(tmp.Data());
}
void TGFontPool::FreeFont(const TGFont *font)
{
   
   TGFont *f = (TGFont*) fList->FindObject(font);
   if (f) {
      if (f->RemoveReference() == 0) {
         if (font->fNamedHash) {
            
            
            TNamedFont *nf = (TNamedFont *) font->fNamedHash;
            if ((nf->RemoveReference() == 0) && (nf->fDeletePending != 0)) {
               fNamedTable->Remove(nf);
               delete nf;
            }
         }
         fList->Remove(f);
         delete font;
      }
   }
}
TGFont *TGFontPool::FindFont(FontStruct_t font) const
{
   
   TIter next(fList);
   TGFont *f = 0;
   while ((f = (TGFont*) next())) {
      if (f->fFontStruct == font) {
         return f;
      }
   }
   return 0;
}
TGFont *TGFontPool::FindFontByHandle(FontH_t font) const
{
   
   TIter next(fList);
   TGFont *f = 0;
   while ((f = (TGFont*) next())) {
      if (f->fFontH == font) {
         return f;
      }
   }
   return 0;
}
const char *TGFontPool::GetUid(const char *string)
{
   
   
   
   
   
   
   
   
   TObjString *obj = 0;
   obj = (TObjString*)fUidTable->FindObject(string);
   if (!obj) {
      obj = new TObjString(string);
      fUidTable->Add(obj);
   }
   return (const char *)obj->GetName();
}
char **TGFontPool::GetAttributeInfo(const FontAttributes_t *fa)
{
   
   
   
   
   
   Int_t i, num;
   const char *str = 0;
   char **result = new char*[FONT_NUMFIELDS];
   for (i = 0; i < FONT_NUMFIELDS; ++i) {
      str = 0;
      num = 0;
      switch (i) {
      case FONT_FAMILY:
         str = fa->fFamily;
         if (!str) str = "";
         break;
      case FONT_SIZE:
         num = fa->fPointsize;
         break;
      case FONT_WEIGHT:
         str = FindStateString(gWeightMap, fa->fWeight);
         break;
      case FONT_SLANT:
         str = FindStateString(gSlantMap, fa->fSlant);
         break;
      case FONT_UNDERLINE:
         num = fa->fUnderline;
         break;
      case FONT_OVERSTRIKE:
         num = fa->fOverstrike;
         break;
      }
      if (str) {
         result[i] = new char[strlen(str)+1];
         strcpy(result[i], str);
      } else {
         result[i] = new char[20];
         sprintf(result[i], "%d", num);
      }
   }
   return result;
}
void TGFontPool::FreeAttributeInfo(char **info)
{
   
   Int_t i;
   if (info) {
      for (i = 0; i < FONT_NUMFIELDS; ++i) {
         if (info[i]) {
            delete[] info[i];
         }
      }
      delete[] info;
   }
}
void TGFontPool::Print(Option_t *opt) const
{
   
   fList->Print(opt);
}
void TGFont::SavePrimitive(ostream &out, Option_t * )
{
    
   char quote = '"';
   if (gROOT->ClassSaved(TGFont::Class())) {
      out << endl;
   } else {
      
      out << endl;
      out << "   TGFont *ufont;         // will reflect user font changes" << endl;
   }
   out << "   ufont = gClient->GetFont(" << quote << GetName() << quote << ");" << endl;
}
static char *GetToken(char *str)
{
   static char *p = 0;
   char *retp;
   if (str) p = str;
   if (!p) {
      return 0;
   }
   if (!*p) {
      return 0;
   }
   while (*p && ((*p == ' ') || (*p == '\t'))) {   
      ++p;
   }
   if (!*p) {
      return 0;
   }
   if (*p == '"') {  
      retp = ++p;
      if (!*p) {
         return 0;
      }
      while (*p && (*p != '"')) {
         ++p;
      }
      if (*p == '"') {
         *p++ = '\0';
      }
   } else {
      retp = p;
      while (*p && (*p != ' ') && (*p != '\t')) {
         ++p;
      }
      if (*p) {
         *p++ = '\0';
      }
   }
   return retp;
}
Bool_t TGFontPool::ParseFontName(const char *string, FontAttributes_t *fa)
{
   
   
   
   
   
   
   
   
   
   
   
   char *s;
   int n, result;
   XLFDAttributes_t xa;
   char *str = new char[strlen(string)+1];
   strcpy(str, string);
   if (*str == '-' || *str == '*') {
    
      xa.fFA = *fa;
      result = ParseXLFD(str, &xa);
      if (result) {
         *fa = xa.fFA;
         delete[] str;
         return kTRUE;  
      }
   }
   
   
   s = GetToken(str);
   if (!s) {
      delete[] str;
      return kFALSE;
   }
   fa->fFamily = GetUid(s);
   s = GetToken(0);
   if (s) {
      char *end;
      fa->fPointsize = strtol(s, &end, 0);
      if ((errno == ERANGE) || (end == s)) {
         return kFALSE;
      }
   }
   while ((s = GetToken(0))) {
      n = FindStateNum(gWeightMap, s);
      if (n != kFontWeightUnknown) {
         fa->fWeight = n;
         continue;
      }
      n = FindStateNum(gSlantMap, s);
      if (n != kFontSlantUnknown) {
         fa->fSlant = n;
         continue;
      }
      n = FindStateNum(gUnderlineMap, s);
      if (n) {
         fa->fUnderline = n;
         continue;
      }
      n = FindStateNum(gOverstrikeMap, s);
      if (n) {
         fa->fOverstrike = n;
         continue;
      }
      
      delete[] str;
      return kFALSE;
   }
   delete[] str;
   return kTRUE;
}
Bool_t TGFontPool::ParseXLFD(const char *string, XLFDAttributes_t *xa)
{
   
   
   
   
   
   
   
   
   
   char *src;
   const char *str;
   int i, j;
   char *field[XLFD_NUMFIELDS + 2];
   TString ds("");
   memset(field, '\0', sizeof (field));
   str = string;
   if (*str == '-') str++;
   ds.Append((char *) str);
   src = (char*)ds.Data();
   field[0] = src;
   for (i = 0; *src != '\0'; src++) {
      if (isupper(UChar_t(*src))) {
         *src = tolower(UChar_t(*src));
      }
      if (*src == '-') {
         i++;
         if (i > XLFD_NUMFIELDS) {
           break;
         }
         *src = '\0';
         field[i] = src + 1;
      }
   }
   
   
   
   
   
   
   if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
      if (atoi(field[XLFD_ADD_STYLE]) != 0) {
         for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
            field[j + 1] = field[j];
         }
         field[XLFD_ADD_STYLE] = 0;
         i++;
      }
   }
   
   if (i < XLFD_FAMILY) {
      return kFALSE;
   }
   if (FieldSpecified(field[XLFD_FOUNDRY])) {
      xa->fFoundry = GetUid(field[XLFD_FOUNDRY]);
   }
   if (FieldSpecified(field[XLFD_FAMILY])) {
      xa->fFA.fFamily = GetUid(field[XLFD_FAMILY]);
   }
   if (FieldSpecified(field[XLFD_WEIGHT])) {
      xa->fFA.fWeight = FindStateNum(gXlfdgWeightMap, field[XLFD_WEIGHT]);
   }
   if (FieldSpecified(field[XLFD_SLANT])) {
      xa->fSlant = FindStateNum(gXlfdSlantMap, field[XLFD_SLANT]);
      if (xa->fSlant == kFontSlantRoman) {
         xa->fFA.fSlant = kFontSlantRoman;
      } else {
         xa->fFA.fSlant = kFontSlantItalic;
      }
   }
   if (FieldSpecified(field[XLFD_SETWIDTH])) {
      xa->fSetwidth = FindStateNum(gXlfdSetwidthMap, field[XLFD_SETWIDTH]);
   }
   
   
   if (FieldSpecified(field[XLFD_POINT_SIZE])) {
      if (field[XLFD_POINT_SIZE][0] == '[') {
         
         
         
         
         
         
         
         xa->fFA.fPointsize = atoi(field[XLFD_POINT_SIZE] + 1);
      } else {
         char *end;
         xa->fFA.fPointsize = strtol(field[XLFD_POINT_SIZE], &end, 0);
         if (errno == ERANGE || end == field[XLFD_POINT_SIZE]) {
            return kFALSE;
         }
         xa->fFA.fPointsize /= 10;
      }
   }
   
   if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
      if (field[XLFD_PIXEL_SIZE][0] == '[') {
         
         
         
         
         
         
         
         xa->fFA.fPointsize = atoi(field[XLFD_PIXEL_SIZE] + 1);
      } else {
         char *end;
         xa->fFA.fPointsize = strtol(field[XLFD_PIXEL_SIZE], &end, 0);
         if (errno == ERANGE || end == field[XLFD_PIXEL_SIZE]) {
            return kFALSE;
         }
      }
   }
   xa->fFA.fPointsize = -xa->fFA.fPointsize;
   
   
   
   
   if (FieldSpecified(field[XLFD_REGISTRY])) {
      xa->fCharset = FindStateNum(gXlfdCharsetMap, field[XLFD_REGISTRY]);
   }
   if (FieldSpecified(field[XLFD_ENCODING])) {
      xa->fEncoding = atoi(field[XLFD_ENCODING]);
   }
   return kTRUE;
}
Int_t TGFontPool::FindStateNum(const FontStateMap_t *map, const char *strKey)
{
   
   
   
   
   
   
   const FontStateMap_t *m;
   if (!map->fStrKey) {
      return 0;
   }
   for (m = map; m->fStrKey != 0; m++) {
      if (strcasecmp(strKey, m->fStrKey) == 0) {
         return m->fNumKey;
      }
   }
   return m->fNumKey;
}
char *TGFontPool::FindStateString(const FontStateMap_t *map, Int_t numKey)
{
   
   
   
   
   
   for ( ; map->fStrKey != 0; map++) {
      if (numKey == map->fNumKey) return map->fStrKey;
   }
   return 0;
}
Bool_t TGFontPool::FieldSpecified(const char *field)
{
   
   
   
   
   
   
   
   
   
   char ch;
   if (!field) {
      return kFALSE;
   }
   ch = field[0];
   return (ch != '*' && ch != '?');
}
const char *TGFontPool::NameOfFont(TGFont *font)
{
   
   return font->GetName();
}
char **TGFontPool::GetFontFamilies()
{
   
   
   
   
   
   Int_t i, numNames;
   char *family, *end, *p;
   THashTable familyTable(100);
   familyTable.SetOwner();
   char **nameList;
   char **dst;
   nameList = gVirtualX->ListFonts("*", 10000, numNames);
   for (i = 0; i < numNames; i++) {
      if (nameList[i][0] != '-') {
         continue;
      }
      family = strchr(nameList[i] + 1, '-');
      if (!family) {
         continue;
      }
      family++;
      end = strchr(family, '-');
      if (!end) {
         continue;
      }
      *end = '\0';
      for (p = family; *p != '\0'; p++) {
         if (isupper(UChar_t(*p))) {
            *p = tolower(UChar_t(*p));
         }
      }
      if (!familyTable.FindObject(family)) {
         familyTable.Add(new TObjString(family));
      }
   }
   UInt_t entries = familyTable.GetEntries();
   dst = new char*[entries+1];
   TIter next(&familyTable);
   i = 0;
   TObject *obj;
   while ((obj = next())) {
      dst[i] = StrDup(obj->GetName());
      i++;
   }
   dst[i] = 0;
   gVirtualX->FreeFontNames(nameList);
   return dst;
}
void TGFontPool::FreeFontFamilies(char **f)
{
   
   Int_t i;
   if (!f) return;
   for (i = 0; f[i] != 0; ++i) {
      delete[] f[i];
   }
   delete[] f;
}
TGFont *TGFontPool::GetFontFromAttributes(FontAttributes_t *fa, TGFont *fontPtr)
{
   
   
   
   
   
   
   
   
   
   Int_t numNames, score, i, scaleable, pixelsize, xaPixelsize;
   Int_t bestIdx, bestScore, bestScaleableIdx, bestScaleableScore;
   XLFDAttributes_t xa;
   TString buf;
   char **nameList;
   TGFont *font;
   FontStruct_t fontStruct;
   const char *fmt, *family;
   family = fa->fFamily;
   if (!family) {
      family = "*";
   }
   pixelsize = -fa->fPointsize;
   if (pixelsize < 0) {
      double d;
      d = -pixelsize * 25.4/72;
      Int_t xx; Int_t yy; UInt_t ww; UInt_t hh;
      gVirtualX->GetWindowSize(gVirtualX->GetDefaultRootWindow(), xx, yy, ww, hh);
      d *= ww;
      d /= gVirtualX->ScreenWidthMM();
      d += 0.5;
      pixelsize = (int) d;
   }
   fontStruct = 0;
   
   fmt = "-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*";
   buf.Form(fmt, family);
   nameList = gVirtualX->ListFonts(buf.Data(), 32768, numNames);
   if (!numNames) {
      
      buf.Format(fmt, "fixed");
      nameList = gVirtualX->ListFonts(buf.Data(), 32768, numNames);
      if (!numNames) {
getsystem:
         fontStruct = gVirtualX->LoadQueryFont("fixed");
         if (!fontStruct) {
            fontStruct = gVirtualX->LoadQueryFont("*");
            if (!fontStruct) {
               return 0;
            }
         }
         goto end;
      }
   }
   
   
   bestIdx = 0;
   bestScore = kMaxInt;
   bestScaleableIdx = 0;
   bestScaleableScore = kMaxInt;
   for (i = 0; i < numNames; i++) {
      score = 0;
      scaleable = 0;
      if (!ParseXLFD(nameList[i], &xa)) {
         continue;
      }
      xaPixelsize = -xa.fFA.fPointsize;
      
      
      
      
      if (strcasecmp(xa.fFoundry, "adobe") != 0) {
         score += 3000;
      }
      if (!xa.fFA.fPointsize) {
         
         
         score += 10;
         scaleable = 1;
      } else {
         
         if (xaPixelsize > pixelsize) {
            score += (xaPixelsize - pixelsize) * 120;
         } else {
            score += (pixelsize - xaPixelsize) * 100;
         }
      }
      score += TMath::Abs(xa.fFA.fWeight - fa->fWeight) * 30;
      score += TMath::Abs(xa.fFA.fSlant - fa->fSlant) * 25;
      if (xa.fSlant == kFontSlantOblique) {
         
         
      }
      if (xa.fSetwidth != kFontSWNormal) {
         
         score += 2000;
      }
      if (xa.fCharset == kFontCSOther) {
         
         
         
         score += 11000;
      }
      if ((xa.fCharset == kFontCSNormal) && (xa.fEncoding != 1)) {
         
         
         score += 8000;
      }
      if (scaleable) {
         if (score < bestScaleableScore) {
            bestScaleableIdx = i;
            bestScaleableScore = score;
         }
      } else {
         if (score < bestScore) {
            bestIdx = i;
            bestScore = score;
         }
      }
      if (!score) {
         break;
      }
   }
   
   
   
   
   
   fontStruct = 0;
   if (bestScaleableScore < bestScore) {
      char *str, *rest;
      
tryscale:
      str = nameList[bestScaleableIdx];
      for (i = 0; i < XLFD_PIXEL_SIZE - 1; i++) {
         str = strchr(str + 1, '-');
      }
      rest = str;
      for (i = XLFD_PIXEL_SIZE - 1; i < XLFD_REGISTRY; i++) {
         rest = strchr(rest + 1, '-');
      }
      *str = '\0';
      buf.Form("%.240s-*-%d-*-*-*-*-*%s", nameList[bestScaleableIdx], pixelsize, rest);
      *str = '-';
      fontStruct = gVirtualX->LoadQueryFont(buf.Data());
      bestScaleableScore = kMaxInt;
   }
   if (!fontStruct) {
      buf = nameList[bestIdx];
      fontStruct = gVirtualX->LoadQueryFont(buf.Data());
      if (!fontStruct) {
         
         
         if (bestScaleableScore < kMaxInt) {
            goto tryscale;
         } else {
            gVirtualX->FreeFontNames(nameList);
            goto getsystem;
         }
      }
   }
   gVirtualX->FreeFontNames(nameList);
end:
   font = MakeFont(fontPtr, fontStruct, buf);
   font->fFA.fUnderline = fa->fUnderline;
   font->fFA.fOverstrike = fa->fOverstrike;
   return font;
}
TGFont *TGFontPool::GetNativeFont(const char *name, Bool_t fixedDefault)
{
   
   
   
   
   
   
   
   FontStruct_t fontStruct;
   fixedDefault = fixedDefault && ((*name == '-') || (*name == '*'));
   fontStruct = fClient->GetFontByName(name, fixedDefault);
   if (!fontStruct) {
      return 0;
   }
   return MakeFont(0, fontStruct, name);
}
TGFont *TGFontPool::MakeFont(TGFont *font, FontStruct_t fontStruct,
                             const char *fontName)
{
   
   
   
   
   
   
   
   
   
   
   TGFont *newFont;
   Int_t i, width, firstChar, lastChar, n, replaceOK;
   char *p;
   char buf[4];
   XLFDAttributes_t xa;
   if (font) {
      gVirtualX->FreeFontStruct(font->fFontStruct);
      newFont = font;
   } else {
      newFont = new TGFont(fontName);
   }
   xa.fFA.Init();
   if (!ParseXLFD(fontName, &xa)) {
      newFont->fFA.Init();
      newFont->fFA.fFamily = GetUid(fontName);
   } else {
      newFont->fFA = xa.fFA;
   }
   if (newFont->fFA.fPointsize < 0) {
      double d;
      Int_t xx; Int_t yy; UInt_t ww; UInt_t hh;
      gVirtualX->GetWindowSize(gVirtualX->GetDefaultRootWindow(), xx, yy, ww, hh);
      d = -newFont->fFA.fPointsize * 72/25.4;
      d *= gVirtualX->ScreenWidthMM();
      d /= ww;
      d += 0.5;
      newFont->fFA.fPointsize = (int) d;
   }
   Int_t ascent;
   Int_t descent;
   gVirtualX->GetFontProperties(fontStruct, ascent, descent);
   newFont->fFM.fAscent = ascent;
   newFont->fFM.fDescent = descent;
   newFont->fFM.fLinespace = ascent + descent;
   newFont->fFM.fMaxWidth = gVirtualX->TextWidth(fontStruct, "@", 1);
   newFont->fFM.fFixed = kTRUE;
   newFont->fFontStruct = fontStruct;
   newFont->fFontH      = gVirtualX->GetFontHandle(fontStruct);
   
   firstChar = 0x20; 
   lastChar = 0xff; 
   for (i = 0; i < 256; i++) {
      if ((i == 0177) || (i < firstChar) || (i > lastChar)) {
         newFont->fTypes[i] = kCharReplace;
      } else {
         newFont->fTypes[i] = kCharNormal;
      }
   }
   
   
   
   
   char ch[2] = {0, 0};
   width = 0;
   for (i = 0; i < 256; i++) {
      if (newFont->fTypes[i] != kCharNormal) {
         n = 0;
      } else {
         ch[0] = i;
         n = gVirtualX->TextWidth(fontStruct, ch, 1);
      }
      newFont->fWidths[i] = n;
      if (n) {
         if (!width) {
            width = n;
         } else if (width != n) {
            newFont->fFM.fFixed = kFALSE;
         }
      }
   }
   
   
   
   
   replaceOK = kTRUE;
   for (p = gHexChars; *p != '\0'; p++) {
      if ((UChar_t(*p) < firstChar) || (UChar_t(*p) > lastChar)) {
         replaceOK = kFALSE;
         break;
      }
   }
   for (i = 0; i < 256; i++) {
      if (newFont->fTypes[i] == kCharReplace) {
         if (replaceOK) {
            n = GetControlCharSubst(i, buf);
            for (; --n >= 0;) {
               newFont->fWidths[i] += newFont->fWidths[UChar_t(buf[n])];
            }
         } else {
            newFont->fTypes[i] = kCharSkip;
         }
      }
   }
   newFont->fUnderlinePos = descent >> 1;
   newFont->fBarHeight = newFont->fWidths[(int)'I']/3;
   if (newFont->fBarHeight == 0) {
      newFont->fBarHeight = 1;
   }
   if (newFont->fUnderlinePos + newFont->fBarHeight > descent) {
      
      
      
      newFont->fBarHeight = descent - newFont->fUnderlinePos;
      if (!newFont->fBarHeight) {
         newFont->fUnderlinePos--;
         newFont->fBarHeight = 1;
      }
   }
   return newFont;
}
static Int_t GetControlCharSubst(Int_t c, char buf[4])
{
   
   
   
   
   
   
   
   
   
   
   
   buf[0] = '\\';
   if (((UInt_t)c < sizeof(gMapChars)) && (gMapChars[c] != 0)) {
      buf[1] = gMapChars[c];
      return 2;
   } else {
      buf[1] = 'x';
      buf[2] = gHexChars[(c >> 4) & 0xf];
      buf[3] = gHexChars[c & 0xf];
      return 4;
   }
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.