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);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        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);
        }