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];