private bool SerializeGlyf(ushort indexFormat) { Debug.Assert(_glyphs != null && _glyphs.Length != 0); Debug.Assert(indexFormat == 0 || indexFormat == 1); uint locaOffset = 0; var glyphWriter = new WoffWriter(); uint maxCapacity = 5 * _maxNumPoints; // Size without the application of packing. var pointsWriter = new WoffIndexer((int)maxCapacity); // Created here for reuse int glyphCount = _glyphs.Length; for (ushort i = 0; i < glyphCount; i++) { var glyph = _glyphs[i]; uint glyphSize = 0; pointsWriter.Offset = 0; // Reset the offset, it is non-resizable buffer (size is fixed). if (glyph.Serialize(glyphWriter, pointsWriter, out glyphSize) == false) { Trace.TraceError("Glyph Serialization Error: Glyph Index = {0}.", glyph.GlyphIndex); return(false); } _glyphsLocations.Add(locaOffset); locaOffset += glyphSize; } var glyphBuffer = glyphWriter.GetBuffer(); _woffDir.OrigTable = glyphBuffer; _woffDir.OrigLength = (uint)glyphBuffer.Length; return(true); }
/// <summary> /// This function stores just the point data. Coordinates packing algorithm based on the Google/woff2 sources. /// </summary> /// <param name="writer"></param> /// <param name="pointsCapacity"></param> /// <param name="pointsLength"></param> /// <returns>Returns true on success.</returns> private bool PackPoints(WoffIndexer writer, uint pointsCapacity, ref uint pointsLength) { uint flagOffset = 0; int lastFlag = -1; int repeatCount = 0; int lastX = 0; int lastY = 0; uint xBytes = 0; uint yBytes = 0; int nPoints = _contours.Count; for (int i = 0; i < nPoints; ++i) { var point = _contours[i]; int flag = point.IsOnCurve ? kGlyfOnCurve : 0; int dx = point.X - lastX; int dy = point.Y - lastY; if (dx == 0) { flag |= kGlyfThisXIsSame; } else if (dx > -256 && dx < 256) { flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0); xBytes += 1; } else { xBytes += 2; } if (dy == 0) { flag |= kGlyfThisYIsSame; } else if (dy > -256 && dy < 256) { flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0); yBytes += 1; } else { yBytes += 2; } if (flag == lastFlag && repeatCount != 255) { writer[flagOffset - 1] |= kGlyfRepeat; repeatCount++; } else { if (repeatCount != 0) { if ((flagOffset >= pointsCapacity)) { return(false); } writer[flagOffset++] = (byte)repeatCount; } if ((flagOffset >= pointsCapacity)) { return(false); } writer[flagOffset++] = (byte)flag; repeatCount = 0; } lastX = point.X; lastY = point.Y; lastFlag = flag; } if (repeatCount != 0) { if ((flagOffset >= pointsCapacity)) { return(false); } writer[flagOffset++] = (byte)repeatCount; } uint xyBytes = xBytes + yBytes; if ((xyBytes < xBytes || flagOffset + xyBytes < flagOffset || flagOffset + xyBytes > pointsCapacity)) { return(false); } uint xOffset = flagOffset; uint yOffset = flagOffset + xBytes; lastX = 0; lastY = 0; for (int i = 0; i < nPoints; ++i) { int dx = _contours[i].X - lastX; if (dx == 0) { // pass } else if (dx > -256 && dx < 256) { writer[xOffset++] = (byte)Math.Abs(dx); } else { // will always fit for valid input, but overflow is harmless writer.WriteInt16(dx, ref xOffset); } lastX += dx; int dy = _contours[i].Y - lastY; if (dy == 0) { // pass } else if (dy > -256 && dy < 256) { writer[yOffset++] = (byte)Math.Abs(dy); } else { writer.WriteInt16(dy, ref yOffset); } lastY += dy; } pointsLength = yOffset; return(true); }
public bool Serialize(WoffWriter writer, WoffIndexer pointsWriter, out uint glyphSize) { glyphSize = 0; if (writer == null) { return(false); } uint startOffset = writer.Offset; // 1. Write the Glyph Header writer.WriteInt16(_numContours); // int16 numberOfContours for number of contours: >= 0 is simple glyph, < 0 composite glyph. writer.WriteInt16(_xMin); // int16 xMin Minimum x for coordinate data. writer.WriteInt16(_yMin); // int16 yMin Minimum y for coordinate data. writer.WriteInt16(_xMax); // int16 xMax Maximum x for coordinate data. writer.WriteInt16(_yMax); // int16 yMax Maximum y for coordinate data. // 2. Write the Simple Glyph Description, if applicable if (_glyphType == WoffGlyphType.Simple) { // uint16 endPtsOfContours[numberOfContours] // Array of point indices for the last point of each contour, in increasing numeric order. Debug.Assert(_endPtsOfContours != null && _endPtsOfContours.Length == _numContours); if (_endPtsOfContours == null || _endPtsOfContours.Length != _numContours) { Debug.Assert(false, "Invalid condition."); return(false); } for (short i = 0; i < _numContours; i++) { writer.WriteUInt16(_endPtsOfContours[i]); } // uint16 instructionLength Total number of bytes for instructions. // If instructionLength is zero, no instructions are present for this glyph, // and this field is followed directly by the flags field.instructionLength writer.WriteUInt16(_instructionLength); // uint8 instructions[instructionLength] Array of instruction byte code for the glyph. if (_instructionLength != 0) { Debug.Assert(_instructions != null && _instructions.Length == _instructionLength); if (_instructions == null || _instructions.Length != _instructionLength) { Debug.Assert(false, "Invalid condition."); return(false); } writer.Write(_instructions); } // Pack the points Debug.Assert(_numPoints == _contours.Count); int pointsCapacity = 5 * _numPoints; // Size without the application of packing. if (pointsWriter == null) { pointsWriter = new WoffIndexer(pointsCapacity); } else { pointsWriter.Offset = 0; } uint pointsLength = 0; if (PackPoints(pointsWriter, (uint)pointsCapacity, ref pointsLength) == false) { Debug.Assert(false, "Invalid condition."); return(false); } // Serialize the points... writer.Write(pointsWriter.GetBuffer(), 0, (int)pointsLength); } // Write the Simple Glyph Description, if applicable else if (_glyphType == WoffGlyphType.Composite) { Debug.Assert(_componentLength != 0); Debug.Assert(_components != null && _componentLength == _components.Length); if (_componentLength == 0 || _components == null || _componentLength != _components.Length) { Debug.Assert(false, "Invalid condition."); return(false); } // Serialize the Composite Glyph data... writer.Write(_components, 0, _componentLength); } // NOTE: Without the padding the serialization of the glyph fails! var padBytesLength = WoffBuffer.CalcPadBytes((int)writer.Offset, 4); if (padBytesLength > 0) { var paddingBuffer = new byte[4]; writer.Write(paddingBuffer, 0, padBytesLength); } uint endOffset = writer.Offset; if (endOffset <= startOffset) { Debug.Assert(false, "Invalid condition."); return(false); } glyphSize = endOffset - startOffset; return(true); }