// =========================================================================== //  ©2013-2026 WebSupergoo. All rights reserved. // //  This source code is for use exclusively with the ABCpdf product with //  which it is distributed, under the terms of the license for that //  product. Details can be found at // //    http://www.websupergoo.com/ // //  This copyright notice must not be deleted and must be reproduced alongside //  any sections of code extracted from this module. // =========================================================================== using System; using System.IO; using System.Collections.Generic; using System.Globalization; namespace WebSupergoo.ABCpdf14.Drawing.Text {   #region BuiltInFontMetrics   internal sealed class BuiltInFontMetrics : FontMetrics {     #region AdobeFromUnicode     internal static readonly int[] AdobeFromUnicode = {                                 0,     1,     2,     3,     4,     5,     6,     7,     8,     9, //     0                                 10,   11,   12,   13,   14,   15,   16,   17,   18,   19, //   10                                 20,   21,   22,   23,   24,   25,   26,   27,   28,   29, //   20                                 30,   31,   32,   33,   34,   35,   36,   37,   38,   39, //   30                                 40,   41,   42,   43,   44,   45,   46,   47,   48,   49, //   40                                 50,   51,   52,   53,   54,   55,   56,   57,   58,   59, //   50                                 60,   61,   62,   63,   64,   65,   66,   67,   68,   69, //   60                                 70,   71,   72,   73,   74,   75,   76,   77,   78,   79, //   70                                 80,   81,   82,   83,   84,   85,   86,   87,   88,   89, //   80                                 90,   91,   92,   93,   94,   95,   96,   97,   98,   99, //   90                                 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, // 100                                 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, // 110                                 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, // 120                                 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, // 130                                 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, // 140                                 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 150                                 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, // 160                                 170, 171, 172,   45, 174, 175, 176, 177, 178, 179, // 170 - 173/-                                 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, // 180                                 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, // 190                                 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, // 200                                 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, // 210                                 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, // 220                                 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 230                                 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, // 240                                 250, 251, 252, 253, 254, 255,   88,   88,   88,   88, // 250                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 260                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 270                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 280                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 290                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 300                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 310                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 320                                 88,   88,   88,   88,   88,   88,   88,   88, 140, 156, // 330 - 338/OE, 339/oe                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 340                                 88,   88, 138,   88,   88,   88,   88,   88,   88,   88, // 350 - 352/S caron                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 360                                 88,   88,   88,   88,   88,   88, 159,   88,   88,   88, // 370 - 376/Y dieresis                                 88, 142, 158,   88,   88,   88,   88,   88,   88,   88, // 380 - 381/Z caron, 382/z caron                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 390                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 400                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 410                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 420                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 430                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 440                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 450                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 460                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 470                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 480                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 490                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 500                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 510                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 520                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 530                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 540                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 550                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 560                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 570                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 580                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 590                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 600                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 610                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 620                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 630                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 640                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 650                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 660                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 670                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 680                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 690                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 700                                 136,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 710 - 710/circumflex                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 720                                 225,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 730 - 730/breve                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 740                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 750                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 760                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 770                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 780                                 88,   88,   88,   88,   88,   88,   88,   88,   88,   88, // 790                                 88 };     #endregion     internal static readonly char[] DelimiterToken = { ' ', '\t' };     internal static readonly char[] DelimiterSemicolon = { ';' };     internal BuiltInFontMetrics(Stream stream) {       using (StreamReader streamReader = new StreamReader(stream)) {         string line = null;         while ((line = streamReader.ReadLine()) != null) {           if (line.StartsWith("Comment"))             continue;           string[] token = line.Split(DelimiterToken, 5);           if (token.Length == 0)             continue;           switch (token[0]) {             case "StartFontMetrics":               FontMetricsVersion = token[1];               break;             case "MetricsSets":               MetricsSets = int.Parse(token[1]);               break;             case "FontName":               FontName = token[1];               break;             case "FullName":               FullName = token[1];               break;             case "FamilyName":               FamilyName = token[1];               break;             case "Weight":               Weight = token[1];               break;             case "FontBBox":               FontBBox_llx  = double.Parse(token[1]);               FontBBox_lly = double.Parse(token[2]);               FontBBox_urx = double.Parse(token[3]);               FontBBox_ury = double.Parse(token[4]);               break;             case "Version":               Version = token[1];               break;             case "Notice":               Notice = line.Substring(7);               break;             case "EncodingScheme":               EncodingScheme = token[1];               break;             case "CharacterSet":               CharacterSet = token[1];               break;             case "IsBaseFont":               IsBaseFont = bool.Parse(token[1]);               break;             case "CapHeight":               CapHeight = double.Parse(token[1]);               break;             case "XHeight":               XHeight = double.Parse(token[1]);               break;             case "Ascender":               Ascender = double.Parse(token[1]);               break;             case "Descender":               Descender = double.Parse(token[1]);               break;             case "StdHW":               StdHW = double.Parse(token[1]);               break;             case "StdVW":               StdVW = double.Parse(token[1]);               break;             case "UnderlinePosition":               UnderlinePosition = double.Parse(token[1]);               break;             case "UnderlineThickness":               UnderlineThickness = double.Parse(token[1]);               break;             case "ItalicAngle":               ItalicAngle = double.Parse(token[1]);               break;             case "IsFixedPitch":               IsFixedPitch = bool.Parse(token[1]);               break;             case "StartCharMetrics":               CharMetricsCount = int.Parse(token[1]);               ParseCharMetrics(streamReader);               break;             default:               break;           }         }       }     }     internal override System.Drawing.SizeF MeasureString(string s, double size, TextState state) {       if (s.Length == 0)         return new System.Drawing.SizeF(0, 0);       double width = 0;              foreach (char c in s) {         short ch = (short)c;         CharMetrics cm = GetCharMetrics(ch);         if (cm != null)           width += cm.WidthX;         if (c == ' ')           width += state.WordSpacing;       }              width += (s.Length - 1) * state.CharacterSpacing;       double capHeight = CapHeight;       if (double.IsNaN(capHeight))         capHeight = FontBBox_ury - FontBBox_lly;              return new System.Drawing.SizeF(         (float)(GetSizeFactor(size) * width / 1000),         (float)(GetSizeFactor(size) * CapHeight / 1000));     }     internal CharMetrics GetCharMetrics(int ch) {       if (ch >= CharMetrics.Length) {         if (ch == 8364)           return CharMetrics[128];         else           return null;       }       return CharMetrics[ch];     }     internal override double GetSizeFactor(double size) {       if (FontName == "Symbol" || FontName == "ZapfDingbats") {         CharMetrics cm  = GetCharMetrics(74);         return size * 1000 / (cm.BBox_ury - cm.BBox_lly);       }       else {         return size * 1000 / CapHeight;       }     }     internal void ParseCharMetrics(StreamReader reader) {       if (CharMetricsCount > 0) {         CharMetrics = new CharMetrics[BuiltInFontMetrics.AdobeFromUnicode.Length];         string line = null;         while ((line = reader.ReadLine()) != null) {           if (line.StartsWith("EndCharMetrics"))             return;           new BuiltInCharMetrics(line, this);         }       }       CharMetrics[173] = CharMetrics[45];     }   }   #endregion   #region BuiltInCharMetrics   internal class BuiltInCharMetrics : CharMetrics {     internal BuiltInCharMetrics(string line, FontMetrics afm) {       string[] lineToken = line.Split(BuiltInFontMetrics.DelimiterSemicolon, 10);       for (int expr = 0; expr < lineToken.Length; expr++) {         if (lineToken[expr].Length == 0)           continue;                  string[] token = lineToken[expr].Trim().Split(BuiltInFontMetrics.DelimiterToken, 5);         switch (token[0]) {           case "C":             CharacterCode = int.Parse(token[1], NumberFormatInfo.InvariantInfo);             break;           case "CH":             CharacterCode = int.Parse(token[1], NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo);             break;           case "WX":           case "W0X":             WidthX = double.Parse(token[1], NumberFormatInfo.InvariantInfo);             break;           case "N":             Name = token[1];             break;           case "B":             BBox_llx = double.Parse(token[1]);             BBox_lly = double.Parse(token[2]);             BBox_urx = double.Parse(token[3]);             BBox_ury = double.Parse(token[4]);             break;           case "L":             if (Ligatures == null)               Ligatures = new List<Ligature>(10);             Ligatures.Add(new Ligature(token[1], token[2]));             break;           default:             break;         }       }       int index = CharacterCode;       if (afm.FontName != "Symbol" && afm.FontName != "ZapfDingbats") {         switch (index) {           case  39:  // quoteright             index =   0;             break;           case  96:   // quoteleft             index =   0;             break;           case 127:           case 128:           case 129:           case 130:           case 131:           case 132:           case 133:           case 134:           case 135:           case 136:           case 137:           case 138:           case 139:           case 140:           case 141:           case 142:           case 143:           case 144:           case 145:           case 146:           case 147:           case 148:           case 149:           case 150:           case 151:           case 152:           case 153:           case 154:           case 155:           case 156:           case 157:           case 158:           case 159:           case 160:             index =  -1;             break;           case 164:             index =   0;             break;  // fraction "/"           case 166:             index =   0;             break;  // florin           case 168:             index = 164;             break;  // currency "¤"           case 169:             index =  39;             break;  // quotesingle "'"           case 170:             index =   0;             break;  // quotedblleft           case 172:             index =   0;             break;  // guilsinglleft           case 173:             index =   0;             break;  // guilsinglright           case 174:             index =   0;  break;  // fi           case 175:             index =   0;             break;  // fl           case 176:             index =  -1;             break;  // does not exist!           case 177:             index =   0;             break;  // endash "-"           case 178:             index =   0;             break;  // dagger           case 179:             index =   0;             break;  // daggerdbl           case 180:             index = 183;             break;  // periodcentered           case 183:             index =   0;             break;  // bullet           case 184:             index =   0;             break;  // quotesinglbase           case 185:             index =   0;             break;  // quotedblbase           case 186:             index =   0;             break;  // quotedblright           case 188:             index =   0;             break;  // ellipsis           case 189:             index =   0;             break;  // perthousand           case 190:           case 192:             index =  -1;             break;           case 193:             index =  96;             break;  // grave "`"           case 194:             index = 180;             break;  // acute "´"           case 195:             index =   0;             break;  // circumflex "^"           case 196:             index =   0;             break;  // tilde "~"           case 197:             index = 175;             break;  // macron           case 198:             index =   0;             break;  // breve           case 199:             index =   0;             break;  // dotaccent           case 200:             index = 168;             break;  // dieresis "¨"           case 201:             index =  -1;             break;  // does not exist!           case 202:             index =   0;             break;  // ring           case 203:             index = 184;             break;  // cedilla "¨"           case 204:             index =  -1;             break;  // does not exist!           case 205:             index =   0;             break;  // hungarumlaut           case 206:             index =   0;             break;  // ogonek           case 207:             index =   0;             break;  // caron           case 208:             index =   0;             break;  // emdash           case 209:           case 210:           case 211:           case 212:           case 213:           case 214:           case 215:           case 216:           case 217:           case 218:           case 219:           case 220:           case 221:           case 222:           case 223:           case 224:             index =  -1;             break;           case 225:             index = 198;             break;  // AE           case 226:             index =  -1;             break;           case 227:             index = 170;             break;  // ordfeminine           case 228:           case 229:           case 230:           case 231:             index =  -1;             break;           case 232:             index =   0;             break;  // Lslash           case 233:             index = 216;             break;  // Oslash           case 234:             index =   0;             break;  // OE           case 235:             index = 186;             break;  // ordmasculine           case 236:           case 237:           case 238:           case 239:           case 240:             index =  -1;             break;           case 241:             index = 230;             break;  // ae           case 242:             index =  -1;             break;  // does not exist!           case 243:           case 244:             index =  -1;             break;           case 245:             index =   0;             break;  // dotlessi           case 246:           case 247:             index =  -1;             break;           case 248:             index =   0;             break;  // lslash           case 249:             index = 248;             break;  // oslash           case 250:             index =   0;             break;  // oe           case 251:             index = 223;             break;  // germandbls           case -1: {             switch (Name) {               case "brokenbar":      index = 166;  break;               case "copyright":      index = 169;  break;               case "logicalnot":     index = 172;  break;               case "registered":     index = 174;  break;               case "degree":         index = 176;  break;               case "plusminus":      index = 177;  break;               case "twosuperior":    index = 178;  break;               case "threesuperior":  index = 179;  break;               case "mu":             index = 181;  break;               case "onesuperior":    index = 185;  break;               case "onequarter":     index = 188;  break;               case "onehalf":        index = 189;  break;               case "threequarters":  index = 190;  break;               case "Agrave":         index = 192;  break;               case "Aacute":         index = 193;  break;               case "Acircumflex":    index = 194;  break;               case "Atilde":         index = 195;  break;               case "Adieresis":      index = 196;  break;               case "Aring":          index = 197;  break;               case "Ccedilla":       index = 199;  break;               case "Egrave":         index = 200;  break;               case "Eacute":         index = 201;  break;               case "Ecircumflex":    index = 202;  break;               case "Edieresis":      index = 203;  break;               case "Igrave":         index = 204;  break;               case "Iacute":         index = 205;  break;               case "Icircumflex":    index = 206;  break;               case "Idieresis":      index = 207;  break;               case "Eth":            index = 208;  break;               case "Ntilde":         index = 209;  break;               case "Ograve":         index = 210;  break;               case "Oacute":         index = 211;  break;               case "Ocircumflex":    index = 212;  break;               case "Otilde":         index = 213;  break;               case "Odieresis":      index = 214;  break;               case "multiply":       index = 215;  break;               case "Ugrave":         index = 217;  break;               case "Uacute":         index = 218;  break;               case "Ucircumflex":    index = 219;  break;               case "Udieresis":      index = 220;  break;               case "Yacute":         index = 221;  break;               case "Thorn":          index = 222;  break;               case "agrave":         index = 224;  break;               case "aacute":         index = 225;  break;               case "acircumflex":    index = 226;  break;               case "atilde":         index = 227;  break;               case "adieresis":      index = 228;  break;               case "aring":          index = 229;  break;               case "ccedilla":       index = 231;  break;               case "egrave":         index = 232;  break;               case "eacute":         index = 233;  break;               case "ecircumflex":    index = 234;  break;               case "edieresis":      index = 235;  break;               case "igrave":         index = 236;  break;               case "iacute":         index = 237;  break;               case "icircumflex":    index = 238;  break;               case "idieresis":      index = 239;  break;               case "eth":            index = 240;  break;               case "ntilde":         index = 241;  break;               case "ograve":         index = 242;  break;               case "oacute":         index = 243;  break;               case "ocircumflex":    index = 244;  break;               case "otilde":         index = 245;  break;               case "odieresis":      index = 246;  break;               case "divide":         index = 247;  break;               case "ugrave":         index = 249;  break;               case "uacute":         index = 250;  break;               case "ucircumflex":    index = 251;  break;               case "udieresis":      index = 252;  break;               case "yacute":         index = 253;  break;               case "thorn":          index = 254;  break;               case "ydieresis":      index = 255;  break;               case "Amacron":        index = 256;  break;               case "Abreve":         index = 258;  break;               case "abreve":         index = 259;  break;               case "Aogonek":        index = 260;  break;               case "aogonek":        index = 261;  break;               case "Cacute":         index = 262;  break;               case "cacute":         index = 263;  break;               case "Ccaron":         index = 268;  break;               case "ccaron":         index = 269;  break;               case "Dcaron":         index = 270;  break;               case "dcaron":         index = 271;  break;               case "Dcroat":         index = 272;  break;               case "dcroat":         index = 273;  break;               case "Emacron":        index = 274;  break;               case "emacron":        index = 275;  break;               case "Edotaccent":     index = 278;  break;               case "edotaccent":     index = 279;  break;               case "Eogonek":        index = 280;  break;               case "eogonek":        index = 281;  break;               case "Ecaron":         index = 282;  break;               case "ecaron":         index = 283;  break;               case "Gbreve":         index = 286;  break;               case "gbreve":         index = 287;  break;               case "Gcommaaccent":   index = 290;  break;               case "gcommaaccent":   index = 291;  break;                                    case "Imacron":        index = 298;  break;               case "imacron":        index = 299;  break;               case "Euro":           index = 128;  break;               default:        index = 0;   break;             }             break;           }         }       }              if (index > 0)         afm.CharMetrics[index] = this;     }   }   #endregion }