parseGlyph function

dynamic parseGlyph(
  1. dynamic glyph,
  2. dynamic data,
  3. dynamic start
)

Implementation

parseGlyph(glyph, data, start) {
  var p = new Parser(data, start);
  glyph.numberOfContours = p.parseShort();
  glyph.xMin = p.parseShort();
  glyph.yMin = p.parseShort();
  glyph.xMax = p.parseShort();
  glyph.yMax = p.parseShort();
  var flags;
  var flag;

  if (glyph.numberOfContours > 0) {
      // This glyph is not a composite.
      glyph.endPointIndices = [];
      var endPointIndices = glyph.endPointIndices;
      for (var i = 0; i < glyph.numberOfContours; i += 1) {
          endPointIndices.add(p.parseUShort());
      }

      glyph.instructionLength = p.parseUShort();
      glyph.instructions = [];
      for (var i = 0; i < glyph.instructionLength; i += 1) {
          glyph.instructions.add(p.parseByte());
      }

      var numberOfCoordinates = endPointIndices[endPointIndices.length - 1] + 1;
      flags = [];
      for (var i = 0; i < numberOfCoordinates; i += 1) {
          flag = p.parseByte();
          flags.add(flag);
          // If bit 3 is set, we repeat this flag n times, where n is the next byte.
          if ((flag & 8) > 0) {
              var repeatCount = p.parseByte();
              for (var j = 0; j < repeatCount; j += 1) {
                  flags.add(flag);
                  i += 1;
              }
          }
      }

      argument(flags.length == numberOfCoordinates, 'Bad flags.');

      if (endPointIndices.length > 0) {
          var points = [];
          var point;
          // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0.
          if (numberOfCoordinates > 0) {
              for (var i = 0; i < numberOfCoordinates; i += 1) {
                  flag = flags[i];
                  point = {};
                  point["onCurve"] = (flag & 1) == 1;
                  point["lastPointOfContour"] = endPointIndices.indexOf(i) >= 0;
                  points.add(point);
              }

              var px = 0;
              for (var i = 0; i < numberOfCoordinates; i += 1) {
                  flag = flags[i];
                  point = points[i];
                  point["x"] = parseGlyphCoordinate(p, flag, px, 2, 16);
                  px = point["x"];
              }

              var py = 0;
              for (var i = 0; i < numberOfCoordinates; i += 1) {
                  flag = flags[i];
                  point = points[i];
                  point["y"] = parseGlyphCoordinate(p, flag, py, 4, 32);
                  py = point["y"];
              }
          }

          glyph.points = points;
      } else {
          glyph.points = [];
      }
  } else if (glyph.numberOfContours == 0) {
      glyph.points = [];
  } else {
      glyph.isComposite = true;
      glyph.points = [];
      glyph.components = [];
      var moreComponents = true;
      while (moreComponents) {
          flags = p.parseUShort();
          var component = {
            "glyphIndex": p.parseUShort(),
            "xScale": 1,
            "scale01": 0,
            "scale10": 0,
            "yScale": 1,
            "dx": 0,
            "dy": 0
          };
          if ((flags & 1) > 0) {
              // The arguments are words
              if ((flags & 2) > 0) {
                  // values are offset
                  component["dx"] = p.parseShort();
                  component["dy"] = p.parseShort();
              } else {
                  // values are matched points
                  component["matchedPoints"] = [p.parseUShort(), p.parseUShort()];
              }

          } else {
              // The arguments are bytes
              if ((flags & 2) > 0) {
                  // values are offset
                  component["dx"] = p.parseChar();
                  component["dy"] = p.parseChar();
              } else {
                  // values are matched points
                  component["matchedPoints"] = [p.parseByte(), p.parseByte()];
              }
          }

          if ((flags & 8) > 0) {
              // We have a scale
              component["xScale"] = component["yScale"] = p.parseF2Dot14();
          } else if ((flags & 64) > 0) {
              // We have an X / Y scale
              component["xScale"] = p.parseF2Dot14();
              component["yScale"] = p.parseF2Dot14();
          } else if ((flags & 128) > 0) {
              // We have a 2x2 transformation
              component["xScale"] = p.parseF2Dot14();
              component["scale01"] = p.parseF2Dot14();
              component["scale10"] = p.parseF2Dot14();
              component["yScale"] = p.parseF2Dot14();
          }

          glyph.components.add(component);
          moreComponents = !!(flags & 32);
      }
      if (flags & 0x100) {
          // We have instructions
          glyph.instructionLength = p.parseUShort();
          glyph.instructions = [];
          for (var i = 0; i < glyph.instructionLength; i += 1) {
              glyph.instructions.add(p.parseByte());
          }
      }
  }
}