54 ClassImp(TGTextLayout);
 
   60 #define FONT_UNDERLINE  4 
   61 #define FONT_OVERSTRIKE 5 
   62 #define FONT_NUMFIELDS  6 
   67 #define XLFD_FOUNDRY        0 
   71 #define XLFD_SETWIDTH       4 
   72 #define XLFD_ADD_STYLE      5 
   73 #define XLFD_PIXEL_SIZE     6 
   74 #define XLFD_POINT_SIZE     7 
   75 #define XLFD_RESOLUTION_X   8 
   76 #define XLFD_RESOLUTION_Y   9 
   77 #define XLFD_SPACING        10 
   78 #define XLFD_AVERAGE_WIDTH  11 
   79 #define XLFD_REGISTRY       12 
   80 #define XLFD_ENCODING       13 
   81 #define XLFD_NUMFIELDS      14   // Number of fields in XLFD. 
   91 struct LayoutChunk_t {
 
   97    Int_t fNumDisplayChars; 
 
  120 struct XLFDAttributes_t {
 
  121    FontAttributes_t fFA; 
 
  122    const char *fFoundry; 
 
  142 class TNamedFont : 
public TObjString, 
public TRefCnt {
 
  144    Int_t            fDeletePending; 
 
  145    FontAttributes_t fFA;            
 
  149 enum EFontSpacing { kFontProportional = 0,
 
  154 enum EFontSetWidth { kFontSWNormal = 0,
 
  157                      kFontSWUnknown = 3 };
 
  159 enum EFontCharset { kFontCSNormal = 0,
 
  177 enum ECharType { kCharNormal, kCharReplace, kCharSkip };
 
  184 struct FontStateMap_t { Int_t fNumKey; 
const char *fStrKey; };
 
  186 static const FontStateMap_t gWeightMap[] = {
 
  187    { kFontWeightNormal,  
"normal" },
 
  188    { kFontWeightBold,    
"bold"   },
 
  189    { kFontWeightUnknown, 0        }
 
  192 static const FontStateMap_t gSlantMap[] = {
 
  193    { kFontSlantRoman,   
"roman"  },
 
  194    { kFontSlantItalic,  
"italic" },
 
  195    { kFontSlantUnknown, 0        }
 
  198 static const FontStateMap_t gUnderlineMap[] = {
 
  203 static const FontStateMap_t gOverstrikeMap[] = {
 
  211 static const FontStateMap_t gXlfdgWeightMap[] = {
 
  212    { kFontWeightNormal, 
"normal"   },
 
  213    { kFontWeightNormal, 
"medium"   },
 
  214    { kFontWeightNormal, 
"book"     },
 
  215    { kFontWeightNormal, 
"light"    },
 
  216    { kFontWeightBold,   
"bold"     },
 
  217    { kFontWeightBold,   
"demi"     },
 
  218    { kFontWeightBold,   
"demibold" },
 
  219    { kFontWeightNormal,  0         }  
 
  222 static const FontStateMap_t gXlfdSlantMap[] = {
 
  223    { kFontSlantRoman,   
"r"  },
 
  224    { kFontSlantItalic,  
"i"  },
 
  225    { kFontSlantOblique, 
"o"  },
 
  226    { kFontSlantRoman,   0    }  
 
  229 static const FontStateMap_t gXlfdSetwidthMap[] = {
 
  230    { kFontSWNormal,   
"normal"        },
 
  231    { kFontSWCondence, 
"narrow"        },
 
  232    { kFontSWCondence, 
"semicondensed" },
 
  233    { kFontSWCondence, 
"condensed"     },
 
  234    { kFontSWUnknown,  0               }
 
  237 static const FontStateMap_t gXlfdCharsetMap[] = {
 
  238    { kFontCSNormal, 
"iso8859" },
 
  239    { kFontCSSymbol, 
"adobe"   },
 
  240    { kFontCSSymbol, 
"sun"     },
 
  247 static char gHexChars[] = 
"0123456789abcdefxtnvr\\";
 
  254 static char gMapChars[] = {
 
  255    0, 0, 0, 0, 0, 0, 0, 
'a', 
'b', 
't', 
'n', 
'v', 
'f', 
'r', 0
 
  258 static int GetControlCharSubst(
int c, 
char buf[4]);
 
  267       gVirtualX->DeleteFont(fFontStruct);
 
  274 void TGFont::GetFontMetrics(FontMetrics_t *m)
 const 
  277       Error(
"GetFontMetrics", 
"argument may not be 0");
 
  282    m->fLinespace = fFM.fAscent + fFM.fDescent;
 
  288 FontStruct_t TGFont::operator()()
 const 
  296 void TGFont::Print(Option_t *option)
 const 
  298    TString opt = option;
 
  300    if ((opt == 
"full") && fNamedHash) {
 
  301       Printf(
"TGFont: %s, %s, ref cnt = %u",
 
  302               fNamedHash->GetName(),
 
  303               fFM.fFixed ? 
"fixed" : 
"prop", References());
 
  305       Printf(
"TGFont: %s, %s, ref cnt = %u", fName.Data(),
 
  306               fFM.fFixed ? 
"fixed" : 
"prop", References());
 
  331 Int_t TGFont::PostscriptFontName(TString *dst)
 const 
  334    TString weightString;
 
  345    family = fFA.fFamily;
 
  346    if (strncasecmp(family, 
"itc ", 4) == 0) {
 
  349    if ((strcasecmp(family, 
"Arial") == 0)
 
  350        || (strcasecmp(family, 
"Geneva") == 0)) {
 
  351       family = 
"Helvetica";
 
  352    } 
else if ((strcasecmp(family, 
"Times New Roman") == 0)
 
  353               || (strcasecmp(family, 
"New York") == 0)) {
 
  355    } 
else if ((strcasecmp(family, 
"Courier New") == 0)
 
  356               || (strcasecmp(family, 
"Monaco") == 0)) {
 
  358    } 
else if (strcasecmp(family, 
"AvantGarde") == 0) {
 
  359       family = 
"AvantGarde";
 
  360    } 
else if (strcasecmp(family, 
"ZapfChancery") == 0) {
 
  361       family = 
"ZapfChancery";
 
  362    } 
else if (strcasecmp(family, 
"ZapfDingbats") == 0) {
 
  363       family = 
"ZapfDingbats";
 
  373       src = dest = (
char*)dst->Data() + len;
 
  375       for (; *src != 
'\0'; src++, dest++) {
 
  376          while (isspace(UChar_t(*src))) {
 
  381          if ((upper != 0) && (islower(UChar_t(*src)))) {
 
  382             *dest = toupper(UChar_t(*src));
 
  388       family = (
char *) dst->Data() + len;
 
  390    if (family != (
char *) dst->Data() + len) {
 
  392       family = (
char *) dst->Data() + len;
 
  394    if (strcasecmp(family, 
"NewCenturySchoolbook") == 0) {
 
  396       dst->Append(
"NewCenturySchlbk");
 
  397       family = (
char *) dst->Data() + len;
 
  403    if (fFA.fWeight == kFontWeightNormal) {
 
  404       if (strcmp(family, 
"Bookman") == 0) {
 
  405          weightString = 
"Light";
 
  406       } 
else if (strcmp(family, 
"AvantGarde") == 0) {
 
  407          weightString = 
"Book";
 
  408       } 
else if (strcmp(family, 
"ZapfChancery") == 0) {
 
  409          weightString = 
"Medium";
 
  412       if ((strcmp(family, 
"Bookman") == 0)
 
  413            || (strcmp(family, 
"AvantGarde") == 0)) {
 
  414          weightString = 
"Demi";
 
  416          weightString = 
"Bold";
 
  423    if (fFA.fSlant == kFontSlantRoman) {
 
  426       if ((strcmp(family, 
"Helvetica") == 0)
 
  427            || (strcmp(family, 
"Courier") == 0)
 
  428            || (strcmp(family, 
"AvantGarde") == 0)) {
 
  429          slantString = 
"Oblique";
 
  431          slantString = 
"Italic";
 
  438    if ((slantString.IsNull()) && (weightString.IsNull())) {
 
  439       if ((strcmp(family, 
"Times") == 0)
 
  440            || (strcmp(family, 
"NewCenturySchlbk") == 0)
 
  441            || (strcmp(family, 
"Palatino") == 0)) {
 
  442          dst->Append(
"-Roman");
 
  446       if (!weightString.IsNull()) dst->Append(weightString);
 
  447       if (!slantString.IsNull()) dst->Append(slantString);
 
  450    return fFA.fPointsize;
 
  476 Int_t TGFont::MeasureChars(
const char *source, Int_t numChars, Int_t maxLength,
 
  477                           Int_t flags, Int_t *length)
 const 
  484    Int_t c, sawNonSpace;
 
  490    if (maxLength <= 0) {
 
  493    newX = curX = termX = 0;
 
  495    sawNonSpace = !isspace(UChar_t(*p));
 
  499    for (c = UChar_t(*p);;) {
 
  501       if (newX > maxLength) {
 
  527    if ((flags & kTextPartialOK) && (numChars > 0) && (curX < maxLength)) {
 
  537    if ((flags & kTextAtLeastOne) && (term == source) && (numChars > 0)) {
 
  540       if (term == source) {
 
  544    } 
else if ((numChars == 0) || !(flags & kTextWholeWords)) {
 
  550    return term - source;
 
  563 Int_t TGFont::TextWidth(
const char *
string, Int_t numChars)
 const 
  568       numChars = strlen(
string);
 
  570    MeasureChars(
string, numChars, 0, 0, &width);
 
  578 Int_t TGFont::XTextWidth(
const char *
string, Int_t numChars)
 const 
  583       numChars = strlen(
string);
 
  585    width = gVirtualX->TextWidth(fFontStruct, 
string, numChars);
 
  605 void TGFont::UnderlineChars(Drawable_t dst, GContext_t gc,
 
  606                             const char *
string, Int_t x, Int_t y,
 
  607                             Int_t firstChar, Int_t lastChar)
 const 
  611    MeasureChars(
string, firstChar, 0, 0, &startX);
 
  612    MeasureChars(
string, lastChar, 0, 0, &endX);
 
  614    gVirtualX->FillRectangle(dst, gc, x + startX, y + fUnderlinePos,
 
  615                             (UInt_t) (endX - startX),
 
  616                             (UInt_t) fUnderlineHeight);
 
  649 TGTextLayout *TGFont::ComputeTextLayout(
const char *
string, Int_t numChars,
 
  650                                         Int_t wrapLength, Int_t justify, Int_t flags,
 
  651                                         UInt_t *width, UInt_t *height)
 const 
  653    const char *start, *end, *special;
 
  654    Int_t n, y=0, charsThisChunk, maxChunks;
 
  655    Int_t baseline, h, curX, newX, maxWidth;
 
  656    TGTextLayout *layout;
 
  657    LayoutChunk_t *chunk;
 
  660    Int_t staticLineLengths[MAX_LINES];
 
  662    Int_t maxLines, curLine, layoutHeight;
 
  664    lineLengths = staticLineLengths;
 
  665    maxLines = MAX_LINES;
 
  667    h = fFM.fAscent + fFM.fDescent;
 
  670       numChars = strlen(
string);
 
  674    layout = 
new TGTextLayout;
 
  675    layout->fFont = 
this;
 
  676    layout->fString = string;
 
  677    layout->fNumChunks = 0;
 
  680    baseline = fFM.fAscent;
 
  687    end = 
string + numChars;
 
  690    flags &= kTextIgnoreTabs | kTextIgnoreNewlines;
 
  691    flags |= kTextWholeWords | kTextAtLeastOne;
 
  694    for (start = 
string; start < end;) {
 
  695       if (start >= special) {
 
  698          for (special = start; special < end; special++) {
 
  699             if (!(flags & kTextIgnoreNewlines)) {
 
  700                if ((*special == 
'\n') || (*special == 
'\r')) {
 
  704             if (!(flags & kTextIgnoreTabs)) {
 
  705                if (*special == 
'\t') {
 
  716       if (start < special) {
 
  717          charsThisChunk = MeasureChars(start, special - start,
 
  718                                        wrapLength - curX, flags, &newX);
 
  720          flags &= ~kTextAtLeastOne;
 
  721          if (charsThisChunk > 0) {
 
  722             chunk = NewChunk(layout, &maxChunks, start,
 
  723                              charsThisChunk, curX, newX, baseline);
 
  725             start += charsThisChunk;
 
  729       if ((start == special) && (special < end)) {
 
  731          LayoutChunk_t *newchunk = 0;
 
  734          if (*special == 
'\t') {
 
  735             newX = curX + fTabWidth;
 
  736             newX -= newX % fTabWidth;
 
  737             newchunk = NewChunk(layout, &maxChunks, start, 1, curX, newX, baseline);
 
  738             if (newchunk) newchunk->fNumDisplayChars = -1;
 
  740             if ((start < end) && ((wrapLength <= 0) || (newX <= wrapLength))) {
 
  745                flags &= ~kTextAtLeastOne;
 
  749             newchunk = NewChunk(layout, &maxChunks, start, 1, curX, 1000000000, baseline);
 
  750             if (newchunk) newchunk->fNumDisplayChars = -1;
 
  760       while ((start < end) && isspace(UChar_t(*start))) {
 
  761          if (!(flags & kTextIgnoreNewlines)) {
 
  762             if ((*start == 
'\n') || (*start == 
'\r')) {
 
  766          if (!(flags & kTextIgnoreTabs)) {
 
  767             if (*start == 
'\t') {
 
  777          charsThisChunk = start - (chunk->fStart + chunk->fNumChars);
 
  778          if (charsThisChunk > 0) {
 
  779             chunk->fNumChars += MeasureChars(chunk->fStart + chunk->fNumChars,
 
  780                                              charsThisChunk, 0, 0, &chunk->fTotalWidth);
 
  781             chunk->fTotalWidth += curX;
 
  785       flags |= kTextAtLeastOne;
 
  790       if (curX > maxWidth) {
 
  797       if (curLine >= maxLines) {
 
  800          newLengths = 
new int[2 * maxLines];
 
  801          memcpy((
void *) newLengths, lineLengths, maxLines * 
sizeof (
int));
 
  803          if (lineLengths != staticLineLengths) {
 
  804             delete[] lineLengths;
 
  806          lineLengths = newLengths;
 
  809       lineLengths[curLine] = curX;
 
  820    if ((layout->fNumChunks > 0) && ((flags & kTextIgnoreNewlines) == 0)) {
 
  821       if (layout->fChunks[layout->fNumChunks - 1].fStart[0] == 
'\n') {
 
  822          chunk = NewChunk(layout, &maxChunks, start, 0, curX, 1000000000, baseline);
 
  823          chunk->fNumDisplayChars = -1;
 
  832    chunk = layout->fChunks;
 
  833    if (chunk) y = chunk->fY;
 
  834    for (n = 0; n < layout->fNumChunks; n++) {
 
  837       if (chunk->fY != y) {
 
  841       extra = maxWidth - lineLengths[curLine];
 
  842       if (justify == kTextCenterX) {
 
  843          chunk->fX += extra / 2;
 
  844       } 
else if (justify == kTextRight) {
 
  850    layout->fWidth = maxWidth;
 
  851    layoutHeight = baseline - fFM.fAscent;
 
  852    if (layout->fNumChunks == 0) {
 
  859       layout->fNumChunks = 1;
 
  860       layout->fChunks = 
new LayoutChunk_t[1];
 
  861       layout->fChunks[0].fStart = string;
 
  862       layout->fChunks[0].fNumChars = 0;
 
  863       layout->fChunks[0].fNumDisplayChars = -1;
 
  864       layout->fChunks[0].fX = 0;
 
  865       layout->fChunks[0].fY = fFM.fAscent;
 
  866       layout->fChunks[0].fTotalWidth = 0;
 
  867       layout->fChunks[0].fDisplayWidth = 0;
 
  870       *width = layout->fWidth;
 
  873       *height = layoutHeight;
 
  875    if (lineLengths != staticLineLengths) {
 
  876       delete[] lineLengths;
 
  885 TGTextLayout::~TGTextLayout()
 
  908 void TGTextLayout::DrawText(Drawable_t dst, GContext_t gc,
 
  909                             Int_t x, Int_t y, Int_t firstChar, Int_t lastChar)
 const 
  911    Int_t i, numDisplayChars, drawX;
 
  912    LayoutChunk_t *chunk;
 
  914    if (lastChar < 0) lastChar = 100000000;
 
  917    for (i = 0; i < fNumChunks; i++) {
 
  918       numDisplayChars = chunk->fNumDisplayChars;
 
  919       if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
 
  920          if (firstChar <= 0) {
 
  924             fFont->MeasureChars(chunk->fStart, firstChar, 0, 0, &drawX);
 
  926          if (lastChar < numDisplayChars) numDisplayChars = lastChar;
 
  927          fFont->DrawChars(dst, gc, chunk->fStart + firstChar, numDisplayChars - firstChar,
 
  928                            x + chunk->fX + drawX, y + chunk->fY);
 
  930       firstChar -= chunk->fNumChars;
 
  931       lastChar -= chunk->fNumChars;
 
  933       if (lastChar <= 0) 
break;
 
  955 void TGTextLayout::UnderlineChar(Drawable_t dst, GContext_t gc,
 
  956                                 Int_t x, Int_t y, Int_t underline)
 const 
  958    int xx, yy, width, height;
 
  960    if ((CharBbox(underline, &xx, &yy, &width, &height) != 0)
 
  962       gVirtualX->FillRectangle(dst, gc, x + xx,
 
  963                                y + yy + fFont->fFM.fAscent + fFont->fUnderlinePos,
 
  964                                (UInt_t) width, (UInt_t) fFont->fUnderlineHeight);
 
  988 Int_t TGTextLayout::PointToChar(Int_t x, Int_t y)
 const 
  990    LayoutChunk_t *chunk, *last;
 
  991    Int_t i, n, dummy, baseline, pos;
 
 1002    last = chunk = fChunks;
 
 1003    for (i = 0; i < fNumChunks; i++) {
 
 1004       baseline = chunk->fY;
 
 1005       if (y < baseline + fFont->fFM.fDescent) {
 
 1006          if (x < chunk->fX) {
 
 1010             return (chunk->fStart - fString);
 
 1026          while ((i < fNumChunks) && (chunk->fY == baseline)) {
 
 1027             if (x < chunk->fX + chunk->fTotalWidth) {
 
 1031                if (chunk->fNumDisplayChars < 0) {
 
 1036                   return (chunk->fStart - fString);
 
 1038                n = fFont->MeasureChars(chunk->fStart, chunk->fNumChars,
 
 1039                                        x + 1 - chunk->fX, kTextPartialOK, &dummy);
 
 1040                return ((chunk->fStart + n - 1) - fString);
 
 1051          pos = (last->fStart + last->fNumChars) - fString;
 
 1052          if (i < fNumChunks) pos--;
 
 1062    return ((last->fStart + last->fNumChars) - fString);
 
 1094 Int_t TGTextLayout::CharBbox(Int_t index, Int_t *x, Int_t *y, Int_t *w, Int_t *h)
 const 
 1096    LayoutChunk_t *chunk;
 
 1097    Int_t i, xx = 0, ww = 0;
 
 1105    for (i = 0; i < fNumChunks; i++) {
 
 1106       if (chunk->fNumDisplayChars < 0) {
 
 1109             ww = chunk->fTotalWidth;
 
 1112       } 
else if (index < chunk->fNumChars) {
 
 1114             fFont->MeasureChars(chunk->fStart, index, 0, 0, &xx);
 
 1118             fFont->MeasureChars(chunk->fStart + index, 1, 0, 0, &ww);
 
 1122       index -= chunk->fNumChars;
 
 1130       xx = chunk->fX + chunk->fTotalWidth;
 
 1143       *y = chunk->fY - fFont->fFM.fAscent;
 
 1146       *h = fFont->fFM.fAscent + fFont->fFM.fDescent;
 
 1155       if (xx + ww > fWidth) {
 
 1176 Int_t TGTextLayout::DistanceToText(Int_t x, Int_t y)
 const 
 1178    Int_t i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
 
 1179    LayoutChunk_t *chunk;
 
 1181    ascent = fFont->fFM.fAscent;
 
 1182    descent = fFont->fFM.fDescent;
 
 1186    for (i = 0; i < fNumChunks; i++) {
 
 1187       if (chunk->fStart[0] == 
'\n') {
 
 1196       y1 = chunk->fY - ascent;
 
 1197       x2 = chunk->fX + chunk->fDisplayWidth;
 
 1198       y2 = chunk->fY + descent;
 
 1202       } 
else if (x >= x2) {
 
 1210       } 
else if (y >= y2) {
 
 1215       if ((xDiff == 0) && (yDiff == 0)) {
 
 1218       dist = (int) TMath::Hypot((Double_t) xDiff, (Double_t) yDiff);
 
 1219       if ((dist < minDist) || !minDist) {
 
 1242 Int_t TGTextLayout::IntersectText(Int_t x, Int_t y, Int_t w, Int_t h)
 const 
 1244    Int_t result, i, x1, y1, x2, y2;
 
 1245    LayoutChunk_t *chunk;
 
 1246    Int_t left, top, right, bottom;
 
 1261    for (i = 0; i < fNumChunks; i++) {
 
 1262       if (chunk->fStart[0] == 
'\n') {
 
 1271       y1 = chunk->fY - fFont->fFM.fAscent;
 
 1272       x2 = chunk->fX + chunk->fDisplayWidth;
 
 1273       y2 = chunk->fY + fFont->fFM.fDescent;
 
 1275       if ((right < x1) || (left >= x2) || (bottom < y1) || (top >= y2)) {
 
 1280       } 
else if ((x1 < left) || (x2 >= right) || (y1 < top) || (y2 >= bottom)) {
 
 1282       } 
else if (result == -1) {
 
 1319 void TGTextLayout::ToPostscript(TString *result)
 const 
 1322    char buf[MAXUSE + 10];
 
 1323    LayoutChunk_t *chunk;
 
 1324    Int_t i, j, used, c, baseline;
 
 1327    baseline = chunk->fY;
 
 1331    for (i = 0; i < fNumChunks; i++) {
 
 1332       if (baseline != chunk->fY) {
 
 1336          baseline = chunk->fY;
 
 1338       if (chunk->fNumDisplayChars <= 0) {
 
 1339          if (chunk->fStart[0] == 
'\t') {
 
 1344          for (j = 0; j < chunk->fNumDisplayChars; j++) {
 
 1345             c = UChar_t(chunk->fStart[j]);
 
 1346             if ((c == 
'(') || (c == 
')') || (c == 
'\\') || (c < 0x20) || (c >= UChar_t(0x7f))) {
 
 1355                sprintf(buf + used, 
"\\%03o", c);
 
 1360             if (used >= MAXUSE) {
 
 1362                result->Append(buf);
 
 1367       if (used >= MAXUSE) {
 
 1372          result->Append(buf);
 
 1381    result->Append(buf);
 
 1395 LayoutChunk_t *TGFont::NewChunk(TGTextLayout *layout, Int_t *maxPtr,
 
 1396                                 const char *start, Int_t numChars,
 
 1397                                 Int_t curX, Int_t newX, Int_t y)
 const 
 1399    LayoutChunk_t *chunk;
 
 1402    maxChunks = *maxPtr;
 
 1403    if (layout->fNumChunks == maxChunks) {
 
 1404       if (maxChunks == 0) {
 
 1409       chunk = 
new LayoutChunk_t[maxChunks];
 
 1411       if (layout->fNumChunks > 0) {
 
 1412          for (i=0; i<layout->fNumChunks; ++i) chunk[i] = layout->fChunks[i];
 
 1413          delete[] layout->fChunks;
 
 1415       layout->fChunks = chunk;
 
 1416       *maxPtr = maxChunks;
 
 1419    chunk = &layout->fChunks[layout->fNumChunks];
 
 1420    chunk->fStart = start;
 
 1421    chunk->fNumChars = numChars;
 
 1422    chunk->fNumDisplayChars = numChars;
 
 1425    chunk->fTotalWidth = newX - curX;
 
 1426    chunk->fDisplayWidth = newX - curX;
 
 1427    layout->fNumChunks++;
 
 1448 void TGFont::DrawCharsExp(Drawable_t dst, GContext_t gc,
 
 1449                           const char *source, Int_t numChars,
 
 1450                           Int_t x, Int_t y)
 const 
 1457    for (i = 0; i < numChars; i++) {
 
 1458       type = fTypes[UChar_t(*p)];
 
 1459       if (type != kCharNormal) {
 
 1460          DrawChars(dst, gc, source, p - source, x, y);
 
 1461          x += gVirtualX->TextWidth(fFontStruct, source, p - source);
 
 1462          if (type == kCharReplace) {
 
 1463             DrawChars(dst, gc, buf, GetControlCharSubst(UChar_t(*p), buf), x, y);
 
 1464             x += fWidths[UChar_t(*p)];
 
 1471    DrawChars(dst, gc, source, p - source, x, y);
 
 1478 void TGFont::DrawChars(Drawable_t dst, GContext_t gc,
 
 1479                        const char *source, Int_t numChars,
 
 1480                        Int_t x, Int_t y)
 const 
 1482    Int_t max_width =  gVirtualX->TextWidth(fFontStruct, 
"@", 1);
 
 1484    if ((x + (max_width * numChars) > 0x7fff)) {
 
 1492       numChars = MeasureChars(source, numChars, 0x7fff - x, 0, &length);
 
 1495    gVirtualX->DrawString(dst, gc, x, y, source, numChars);
 
 1497    if (fFA.fUnderline != 0) {
 
 1498       gVirtualX->FillRectangle(dst, gc, x,  y + fUnderlinePos,
 
 1499                           (UInt_t) gVirtualX->TextWidth(fFontStruct, source, numChars),
 
 1500                           (UInt_t) fBarHeight);
 
 1502    if (fFA.fOverstrike != 0) {
 
 1503       y -= fFM.fDescent + fFM.fAscent / 10;
 
 1504       gVirtualX->FillRectangle(dst, gc, x, y,
 
 1505                           (UInt_t) gVirtualX->TextWidth(fFontStruct, source, numChars),
 
 1506                           (UInt_t) fBarHeight);
 
 1513 TGFontPool::TGFontPool(TGClient *client)
 
 1516    fList   = 
new THashTable(50);
 
 1519    fNamedTable = 
new THashTable(50);
 
 1520    fNamedTable->SetOwner();
 
 1522    fUidTable = 
new THashTable(50);
 
 1523    fUidTable->SetOwner();
 
 1529 TGFontPool::~TGFontPool()
 
 1543 TGFont *TGFontPool::GetFont(
const char *font, Bool_t fixedDefault)
 
 1545    if (!font || !*font) {
 
 1546       Error(
"GetFont", 
"argument may not be 0 or empty");
 
 1550    TGFont *f = (TGFont*)fList->FindObject(font);
 
 1557    TNamedFont *nf = (TNamedFont*)fNamedTable->FindObject(font);
 
 1562       f = GetFontFromAttributes(&nf->fFA, 0);
 
 1567       Int_t errsav = gErrorIgnoreLevel;
 
 1568       gErrorIgnoreLevel = kFatal;
 
 1570       f = GetNativeFont(font, fixedDefault);
 
 1571       gErrorIgnoreLevel = errsav;
 
 1574          FontAttributes_t fa;
 
 1576          if (!ParseFontName(font, &fa)) {
 
 1583          f = GetFontFromAttributes(&fa, 0);
 
 1595    f->MeasureChars(
"0", 1, 0, 0, &f->fTabWidth);
 
 1597    if (!f->fTabWidth) {
 
 1598       f->fTabWidth = f->fFM.fMaxWidth;
 
 1605    if (!f->fTabWidth) {
 
 1612    Int_t descent = f->fFM.fDescent;
 
 1613    f->fUnderlinePos = descent/2;  
 
 1614    f->fUnderlineHeight = f->fFA.fPointsize/10;
 
 1616    if (!f->fUnderlineHeight) {
 
 1617       f->fUnderlineHeight = 1;
 
 1619    if (f->fUnderlinePos + f->fUnderlineHeight > descent) {
 
 1625       f->fUnderlineHeight = descent - f->fUnderlinePos;
 
 1627       if (!f->fUnderlineHeight) {
 
 1629          f->fUnderlineHeight = 1;
 
 1640 TGFont *TGFontPool::GetFont(
const TGFont *font)
 
 1642    TGFont *f = (TGFont*)fList->FindObject(font);
 
 1655 TGFont *TGFontPool::GetFont(FontStruct_t fs)
 
 1657    TGFont *f = FindFont(fs);
 
 1665    f = MakeFont(0, fs, TString::Format(
"unknown-%d", i));
 
 1681 TGFont *TGFontPool::GetFont(
const char *family, Int_t ptsize, Int_t weight, Int_t slant)
 
 1686    tmp = TString::Format(
"%s %d", family, ptsize);
 
 1687    s = FindStateString(gWeightMap, weight);
 
 1692    s = FindStateString(gSlantMap, slant);
 
 1697    return GetFont(tmp.Data());
 
 1703 void TGFontPool::FreeFont(
const TGFont *font)
 
 1705    TGFont *f = (TGFont*) fList->FindObject(font);
 
 1707       if (f->RemoveReference() == 0) {
 
 1708          if (font->fNamedHash) {
 
 1713             TNamedFont *nf = (TNamedFont *) font->fNamedHash;
 
 1715             if ((nf->RemoveReference() == 0) && (nf->fDeletePending != 0)) {
 
 1716                fNamedTable->Remove(nf);
 
 1729 TGFont *TGFontPool::FindFont(FontStruct_t font)
 const 
 1734    while ((f = (TGFont*) next())) {
 
 1735       if (f->fFontStruct == font) {
 
 1746 TGFont *TGFontPool::FindFontByHandle(FontH_t font)
 const 
 1751    while ((f = (TGFont*) next())) {
 
 1752       if (f->fFontH == font) {
 
 1770 const char *TGFontPool::GetUid(
const char *
string)
 
 1772    TObjString *obj = 0;
 
 1773    obj = (TObjString*)fUidTable->FindObject(
string);
 
 1776       obj = 
new TObjString(
string);
 
 1777       fUidTable->Add(obj);
 
 1780    return (
const char *)obj->GetName();
 
 1790 char **TGFontPool::GetAttributeInfo(
const FontAttributes_t *fa)
 
 1793    const char *str = 0;
 
 1795    char **result = 
new char*[FONT_NUMFIELDS];
 
 1797    for (i = 0; i < FONT_NUMFIELDS; ++i) {
 
 1808          num = fa->fPointsize;
 
 1812          str = FindStateString(gWeightMap, fa->fWeight);
 
 1816          str = FindStateString(gSlantMap, fa->fSlant);
 
 1819       case FONT_UNDERLINE:
 
 1820          num = fa->fUnderline;
 
 1823       case FONT_OVERSTRIKE:
 
 1824          num = fa->fOverstrike;
 
 1829          int len = strlen(str)+1;
 
 1830          result[i] = 
new char[len];
 
 1831          strlcpy(result[i], str, len);
 
 1833          result[i] = 
new char[20];
 
 1834          snprintf(result[i], 20, 
"%d", num);
 
 1844 void TGFontPool::FreeAttributeInfo(
char **info)
 
 1849       for (i = 0; i < FONT_NUMFIELDS; ++i) {
 
 1861 void TGFontPool::Print(Option_t *opt)
 const 
 1869 void TGFont::SavePrimitive(std::ostream &out, Option_t * )
 
 1873    if (gROOT->ClassSaved(TGFont::Class())) {
 
 1878       out << 
"   TGFont *ufont;         // will reflect user font changes" << std::endl;
 
 1880    out << 
"   ufont = gClient->GetFont(" << quote << GetName() << quote << 
");" << std::endl;
 
 1885 static char *GetToken(
char *str)
 
 1899    while (*p && ((*p == 
' ') || (*p == 
'\t'))) {   
 
 1914       while (*p && (*p != 
'"')) {
 
 1923       while (*p && (*p != 
' ') && (*p != 
'\t')) {
 
 1947 Bool_t TGFontPool::ParseFontName(
const char *
string, FontAttributes_t *fa)
 
 1952    XLFDAttributes_t xa;
 
 1954    int len = strlen(
string)+1;
 
 1955    char *str = 
new char[len];
 
 1956    strlcpy(str, 
string, len);
 
 1958    if (*str == 
'-' || *str == 
'*') {
 
 1963       result = ParseXLFD(str, &xa);
 
 1979    fa->fFamily = GetUid(s);
 
 1986       fa->fPointsize = strtol(s, &end, 0);
 
 1987       if ((errno == ERANGE) || (end == s)) {
 
 1992    while ((s = GetToken(0))) {
 
 1993       n = FindStateNum(gWeightMap, s);
 
 1994       if ((EFontWeight)n != kFontWeightUnknown) {
 
 1998       n = FindStateNum(gSlantMap, s);
 
 2002       if ((EFontSlant)n != kFontSlantUnknown) {
 
 2006       n = FindStateNum(gUnderlineMap, s);
 
 2011       n = FindStateNum(gOverstrikeMap, s);
 
 2013          fa->fOverstrike = n;
 
 2038 Bool_t TGFontPool::ParseXLFD(
const char *
string, XLFDAttributes_t *xa)
 
 2043    char *field[XLFD_NUMFIELDS + 2];
 
 2046    memset(field, 
'\0', 
sizeof (field));
 
 2049    if (*str == 
'-') str++;
 
 2051    ds.Append((
char *) str);
 
 2052    src = (
char*)ds.Data();
 
 2055    for (i = 0; *src != 
'\0'; src++) {
 
 2056       if (isupper(UChar_t(*src))) {
 
 2057          *src = tolower(UChar_t(*src));
 
 2061          if (i > XLFD_NUMFIELDS) {
 
 2076    if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
 
 2077       if (atoi(field[XLFD_ADD_STYLE]) != 0) {
 
 2078          for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
 
 2079             field[j + 1] = field[j];
 
 2081          field[XLFD_ADD_STYLE] = 0;
 
 2088    if (i < XLFD_FAMILY) {
 
 2091    if (FieldSpecified(field[XLFD_FOUNDRY])) {
 
 2092       xa->fFoundry = GetUid(field[XLFD_FOUNDRY]);
 
 2094    if (FieldSpecified(field[XLFD_FAMILY])) {
 
 2095       xa->fFA.fFamily = GetUid(field[XLFD_FAMILY]);
 
 2097    if (FieldSpecified(field[XLFD_WEIGHT])) {
 
 2098       xa->fFA.fWeight = FindStateNum(gXlfdgWeightMap, field[XLFD_WEIGHT]);
 
 2100    if (FieldSpecified(field[XLFD_SLANT])) {
 
 2101       xa->fSlant = FindStateNum(gXlfdSlantMap, field[XLFD_SLANT]);
 
 2102       if (xa->fSlant == kFontSlantRoman) {
 
 2103          xa->fFA.fSlant = kFontSlantRoman;
 
 2105          xa->fFA.fSlant = kFontSlantItalic;
 
 2108    if (FieldSpecified(field[XLFD_SETWIDTH])) {
 
 2109       xa->fSetwidth = FindStateNum(gXlfdSetwidthMap, field[XLFD_SETWIDTH]);
 
 2115    if (FieldSpecified(field[XLFD_POINT_SIZE])) {
 
 2116       if (field[XLFD_POINT_SIZE][0] == 
'[') {
 
 2126          xa->fFA.fPointsize = atoi(field[XLFD_POINT_SIZE] + 1);
 
 2130          xa->fFA.fPointsize = strtol(field[XLFD_POINT_SIZE], &end, 0);
 
 2131          if (errno == ERANGE || end == field[XLFD_POINT_SIZE]) {
 
 2134          xa->fFA.fPointsize /= 10;
 
 2140    if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
 
 2141       if (field[XLFD_PIXEL_SIZE][0] == 
'[') {
 
 2151          xa->fFA.fPointsize = atoi(field[XLFD_PIXEL_SIZE] + 1);
 
 2155          xa->fFA.fPointsize = strtol(field[XLFD_PIXEL_SIZE], &end, 0);
 
 2156          if (errno == ERANGE || end == field[XLFD_PIXEL_SIZE]) {
 
 2161    xa->fFA.fPointsize = -xa->fFA.fPointsize;
 
 2171    if (FieldSpecified(field[XLFD_REGISTRY])) {
 
 2172       xa->fCharset = FindStateNum(gXlfdCharsetMap, field[XLFD_REGISTRY]);
 
 2174    if (FieldSpecified(field[XLFD_ENCODING])) {
 
 2175       xa->fEncoding = atoi(field[XLFD_ENCODING]);
 
 2189 Int_t TGFontPool::FindStateNum(
const FontStateMap_t *map, 
const char *strKey)
 
 2191    const FontStateMap_t *m;
 
 2193    if (!map->fStrKey) {
 
 2197    for (m = map; m->fStrKey != 0; m++) {
 
 2198       if (strcasecmp(strKey, m->fStrKey) == 0) {
 
 2212 const char *TGFontPool::FindStateString(
const FontStateMap_t *map, Int_t numKey)
 
 2214    for ( ; map->fStrKey != 0; map++) {
 
 2215       if (numKey == map->fNumKey) 
return map->fStrKey;
 
 2231 Bool_t TGFontPool::FieldSpecified(
const char *field)
 
 2240    return (ch != 
'*' && ch != 
'?');
 
 2246 const char *TGFontPool::NameOfFont(TGFont *font)
 
 2248    return font->GetName();
 
 2258 char **TGFontPool::GetFontFamilies()
 
 2261    char *family, *end, *p;
 
 2263    THashTable familyTable(100);
 
 2264    familyTable.SetOwner();
 
 2271    nameList = gVirtualX->ListFonts(
"*", 10000, numNames);
 
 2273    for (i = 0; i < numNames; i++) {
 
 2274       if (nameList[i][0] != 
'-') {
 
 2277       family = strchr(nameList[i] + 1, 
'-');
 
 2282       end = strchr(family, 
'-');
 
 2287       for (p = family; *p != 
'\0'; p++) {
 
 2288          if (isupper(UChar_t(*p))) {
 
 2289             *p = tolower(UChar_t(*p));
 
 2292       if (!familyTable.FindObject(family)) {
 
 2293          familyTable.Add(
new TObjString(family));
 
 2297    UInt_t entries = familyTable.GetEntries();
 
 2298    dst = 
new char*[entries+1];
 
 2300    TIter next(&familyTable);
 
 2304    while ((obj = next())) {
 
 2305       dst[i] = StrDup(obj->GetName());
 
 2310    gVirtualX->FreeFontNames(nameList);
 
 2317 void TGFontPool::FreeFontFamilies(
char **f)
 
 2323    for (i = 0; f[i] != 0; ++i) {
 
 2340 TGFont *TGFontPool::GetFontFromAttributes(FontAttributes_t *fa, TGFont *fontPtr)
 
 2342    Int_t numNames, score, i, scaleable, pixelsize, xaPixelsize;
 
 2343    Int_t bestIdx, bestScore, bestScaleableIdx, bestScaleableScore;
 
 2344    XLFDAttributes_t xa;
 
 2348    FontStruct_t fontStruct;
 
 2349    const char *fmt, *family;
 
 2351    family = fa->fFamily;
 
 2355    pixelsize = -fa->fPointsize;
 
 2357    if (pixelsize < 0) {
 
 2359       d = -pixelsize * 25.4/72;
 
 2360       Int_t xx; Int_t yy; UInt_t ww; UInt_t hh;
 
 2361       gVirtualX->GetWindowSize(gVirtualX->GetDefaultRootWindow(), xx, yy, ww, hh);
 
 2364       d /= gVirtualX->ScreenWidthMM();
 
 2366       pixelsize = (int) d;
 
 2373    fmt = 
"-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*";
 
 2374    buf = TString::Format(fmt, family);
 
 2375    nameList = gVirtualX->ListFonts(buf.Data(), 32768, numNames);
 
 2379       buf = TString::Format(fmt, 
"fixed");
 
 2382       nameList = gVirtualX->ListFonts(buf.Data(), 32768, numNames);
 
 2387          fontStruct = gVirtualX->LoadQueryFont(
"fixed");
 
 2390             fontStruct = gVirtualX->LoadQueryFont(
"*");
 
 2403    bestScore = kMaxInt;
 
 2404    bestScaleableIdx = 0;
 
 2405    bestScaleableScore = kMaxInt;
 
 2407    for (i = 0; i < numNames; i++) {
 
 2410       if (!ParseXLFD(nameList[i], &xa)) {
 
 2413       xaPixelsize = -xa.fFA.fPointsize;
 
 2420       if (xa.fFoundry && (strcasecmp(xa.fFoundry, 
"adobe") != 0)) {
 
 2423       if (!xa.fFA.fPointsize) {
 
 2434          if (xaPixelsize > pixelsize) {
 
 2435             score += (xaPixelsize - pixelsize) * 120;
 
 2437             score += (pixelsize - xaPixelsize) * 100;
 
 2441       score += TMath::Abs(xa.fFA.fWeight - fa->fWeight) * 30;
 
 2442       score += TMath::Abs(xa.fFA.fSlant - fa->fSlant) * 25;
 
 2444       if (xa.fSlant == kFontSlantOblique) {
 
 2450       if (xa.fSetwidth != kFontSWNormal) {
 
 2456       if (xa.fCharset == kFontCSOther) {
 
 2464       if ((xa.fCharset == kFontCSNormal) && (xa.fEncoding != 1)) {
 
 2472          if (score < bestScaleableScore) {
 
 2473             bestScaleableIdx = i;
 
 2474             bestScaleableScore = score;
 
 2477          if (score < bestScore) {
 
 2495    if (bestScaleableScore < bestScore) {
 
 2501       str = nameList[bestScaleableIdx];
 
 2502       for (i = 0; i < XLFD_PIXEL_SIZE - 1; i++) {
 
 2503          str = strchr(str + 1, 
'-');
 
 2506       for (i = XLFD_PIXEL_SIZE - 1; i < XLFD_REGISTRY; i++) {
 
 2507          rest = strchr(rest + 1, 
'-');
 
 2510       buf = TString::Format(
"%.240s-*-%d-*-*-*-*-*%s", nameList[bestScaleableIdx], pixelsize, rest);
 
 2512       fontStruct = gVirtualX->LoadQueryFont(buf.Data());
 
 2513       bestScaleableScore = kMaxInt;
 
 2516       buf = nameList[bestIdx];
 
 2517       fontStruct = gVirtualX->LoadQueryFont(buf.Data());
 
 2524          if (bestScaleableScore < kMaxInt) {
 
 2527             gVirtualX->FreeFontNames(nameList);
 
 2532    gVirtualX->FreeFontNames(nameList);
 
 2535    font = MakeFont(fontPtr, fontStruct, buf);
 
 2536    font->fFA.fUnderline = fa->fUnderline;
 
 2537    font->fFA.fOverstrike = fa->fOverstrike;
 
 2551 TGFont *TGFontPool::GetNativeFont(
const char *name, Bool_t fixedDefault)
 
 2553    FontStruct_t fontStruct;
 
 2554    fixedDefault = fixedDefault && ((*name == 
'-') || (*name == 
'*'));
 
 2555    fontStruct = fClient->GetFontByName(name, fixedDefault);
 
 2561    return MakeFont(0, fontStruct, name);
 
 2576 TGFont *TGFontPool::MakeFont(TGFont *font, FontStruct_t fontStruct,
 
 2577                              const char *fontName)
 
 2581    Int_t i, width, firstChar, lastChar, n, replaceOK;
 
 2584    XLFDAttributes_t xa;
 
 2587       gVirtualX->FreeFontStruct(font->fFontStruct);
 
 2590       newFont = 
new TGFont(fontName);
 
 2593    if (!ParseXLFD(fontName, &xa)) {
 
 2594       newFont->fFA.fFamily = GetUid(fontName);
 
 2596       newFont->fFA = xa.fFA;
 
 2599    if (newFont->fFA.fPointsize < 0) {
 
 2601       Int_t xx; Int_t yy; UInt_t ww; UInt_t hh;
 
 2602       gVirtualX->GetWindowSize(gVirtualX->GetDefaultRootWindow(), xx, yy, ww, hh);
 
 2603       d = -newFont->fFA.fPointsize * 72/25.4;
 
 2604       d *= gVirtualX->ScreenWidthMM();
 
 2607       newFont->fFA.fPointsize = (int) d;
 
 2612    gVirtualX->GetFontProperties(fontStruct, ascent, descent);
 
 2614    newFont->fFM.fAscent = ascent;
 
 2615    newFont->fFM.fDescent = descent;
 
 2616    newFont->fFM.fLinespace = ascent + descent;
 
 2617    newFont->fFM.fMaxWidth = gVirtualX->TextWidth(fontStruct, 
"@", 1);
 
 2618    newFont->fFM.fFixed = kTRUE;
 
 2619    newFont->fFontStruct = fontStruct;
 
 2620    newFont->fFontH      = gVirtualX->GetFontHandle(fontStruct);
 
 2627    for (i = 0; i < 256; i++) {
 
 2628       if ((i == 160) || (i == 173) || (i == 177) ||
 
 2629           (i < firstChar) || (i > lastChar)) {
 
 2630          newFont->fTypes[i] = kCharReplace;
 
 2632          newFont->fTypes[i] = kCharNormal;
 
 2641    char ch[2] = {0, 0};
 
 2643    for (i = 0; i < 256; i++) {
 
 2644       if (newFont->fTypes[i] != kCharNormal) {
 
 2648          n = gVirtualX->TextWidth(fontStruct, ch, 1);
 
 2650       newFont->fWidths[i] = n;
 
 2654          } 
else if (width != n) {
 
 2655             newFont->fFM.fFixed = kFALSE;
 
 2666    for (p = gHexChars; *p != 
'\0'; p++) {
 
 2667       if ((UChar_t(*p) < firstChar) || (UChar_t(*p) > lastChar)) {
 
 2672    for (i = 0; i < 256; i++) {
 
 2673       if (newFont->fTypes[i] == kCharReplace) {
 
 2675             n = GetControlCharSubst(i, buf);
 
 2677                newFont->fWidths[i] += newFont->fWidths[UChar_t(buf[n])];
 
 2680             newFont->fTypes[i] = kCharSkip;
 
 2685    newFont->fUnderlinePos = descent >> 1;
 
 2686    newFont->fBarHeight = newFont->fWidths[(int)
'I']/3;
 
 2688    if (newFont->fBarHeight == 0) {
 
 2689       newFont->fBarHeight = 1;
 
 2692    if (newFont->fUnderlinePos + newFont->fBarHeight > descent) {
 
 2698       newFont->fBarHeight = descent - newFont->fUnderlinePos;
 
 2700       if (!newFont->fBarHeight) {
 
 2701          newFont->fUnderlinePos--;
 
 2702          newFont->fBarHeight = 1;
 
 2722 static Int_t GetControlCharSubst(Int_t c, 
char buf[4])
 
 2726    if (((UInt_t)c < 
sizeof(gMapChars)) && (gMapChars[c] != 0)) {
 
 2727       buf[1] = gMapChars[c];
 
 2731       buf[2] = gHexChars[(c >> 4) & 0xf];
 
 2732       buf[3] = gHexChars[c & 0xf];