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