/// <summary> /// Deserializes this structure from binary data. /// </summary> /// <param name="reader">The <see cref="BinaryReader"/> to read the data from.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception> /// <exception cref="ArgumentNullException"><paramref name="font"/> is null.</exception> public override void ReadFrom(BinaryReader reader, TinyFont font) { if (reader == null) { throw new ArgumentNullException("reader"); } if (font == null) { throw new ArgumentNullException("font"); } _mask = reader.ReadUInt16(); _reserved = reader.ReadUInt16(); _fontPlanes.Clear(); ushort positionMask = _mask; while (positionMask != 0) { if ((positionMask & 1) != 0) { FontPlane plane = new FontPlane(); plane.ReadFrom(reader, font); _fontPlanes.Add(plane); } positionMask >>= 1; } }
/// <summary> /// Ensures this structure contains valid data. /// </summary> /// <param name="font">The <see cref="TinyFont"/> containing this appendix.</param> public override void Update(TinyFont font) { UpdateAssert(_setsData.Count <= ushort.MaxValue, "Too many metadata sets."); UpdateAssert(_setsData.Count == _setsOffsets.ItemsCount, "Metadata set offset count mismatch."); SortedDictionary <MetadataSetOffset, byte[]> sortedSets = new SortedDictionary <MetadataSetOffset, byte[]>(); for (int i = 0; i < _setsOffsets.ItemsCount; i++) { sortedSets.Add(_setsOffsets[i], _setsData[i]); } _setsOffsets.Clear(); _setsOffsets.AddRange(sortedSets.Keys); _setsData.Clear(); _setsData.AddRange(sortedSets.Values); int offset = 0; for (int i = 0; i < _setsData.Count; i++) { UpdateAssert(offset <= ushort.MaxValue, "Too large metadata set."); _setsOffsets[i].Offset = (ushort)offset; offset += _setsData[i].Length; } _setsOffsets.Sentinel.Id = 0xFF; _setsOffsets.Sentinel.Offset = offset; }
private void FillOpenType(TinyFont font) { HashSet <ushort> userGlyphs = new HashSet <ushort>(); foreach (CharacterImportInfo info in EnumerateAllImports()) { if (info.Mapping.Glyph.HasValue) { userGlyphs.Add(info.Mapping.Glyph.Value); } } Dictionary <ushort, BuilderState> allGeneratedGlyphs = new Dictionary <ushort, BuilderState>(); foreach (FeatureImportInfo feature in _features.Where(f => f.Type == FeatureImportType.Substitution)) { foreach (ushort generatedGlyph in _compiler.GetGeneratedGlyphIds(feature.BuilderState.GlyphTypeface, feature.Script, feature.Language, feature.Feature)) { allGeneratedGlyphs[generatedGlyph] = feature.BuilderState; } } GlyphClassesAppendix classes = font.GetOrAddNewAppendix <GlyphClassesAppendix>(); SubstitutionAppendix substitution = font.GetOrAddNewAppendix <SubstitutionAppendix>(); PositioningAppendix positioning = font.GetOrAddNewAppendix <PositioningAppendix>(); Dictionary <ushort, BuilderState> glyphsToAdd = new Dictionary <ushort, BuilderState>(); foreach (FeatureImportInfo feature in _features.Where(f => f.Type == FeatureImportType.Substitution)) { foreach (ushort generatedGlyph in _compiler.CompileFeature(feature.BuilderState.GlyphTypeface, feature.Script, feature.Language, feature.Feature, substitution, classes, allGeneratedGlyphs.Keys.Concat(userGlyphs))) { glyphsToAdd[generatedGlyph] = feature.BuilderState; } } foreach (KeyValuePair <ushort, BuilderState> toAddPair in glyphsToAdd) { if (!userGlyphs.Contains(toAddPair.Key)) { int character; if (toAddPair.Value.GlyphToCharacterMap.TryGetValue(toAddPair.Key, out character)) { _characterImportList[character] = new CharacterImportInfo(toAddPair.Value, new CharacterGlyphPair(character, toAddPair.Key)); } else if (toAddPair.Key < toAddPair.Value.GlyphTypeface.GlyphCount) { _glyphImportList.Add(new CharacterImportInfo(toAddPair.Value, new CharacterGlyphPair(null, toAddPair.Key))); } userGlyphs.Add(toAddPair.Key); } } foreach (FeatureImportInfo feature in _features.Where(f => f.Type == FeatureImportType.Positioning)) { _compiler.CompileFeature(feature.BuilderState.GlyphTypeface, feature.Script, feature.Language, feature.Feature, positioning, classes, allGeneratedGlyphs.Keys.Concat(userGlyphs), feature.BuilderState.EmSize); } }
/// <summary> /// Deserializes this structure from binary data. /// </summary> /// <param name="reader">The <see cref="BinaryReader"/> to read the data from.</param> /// <param name="font">The <see cref="TinyFont"/> containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception> public override void ReadFrom(BinaryReader reader, TinyFont font) { if (reader == null) { throw new ArgumentNullException("reader"); } while (true) { MetadataSetOffset offset = new MetadataSetOffset(); offset.ReadFrom(reader); if (offset.Id == 0xFF) { _setsOffsets.Sentinel = offset; break; } _setsOffsets.Add(offset); } for (int i = 0; i < _setsOffsets.ItemsCount; i++) { byte[] data = reader.ReadBytes(_setsOffsets[i + 1].Offset - _setsOffsets[i].Offset); Sets.Add(data); } }
/// <summary> /// Gets size of this appendix. /// </summary> /// <param name="font">Tiny Font containing this appendix.</param> /// <returns>Size in bytes.</returns> public override int GetSize(TinyFont font) { return(sizeof(ushort) + sizeof(ushort) + _coverages.Count * Coverage.SizeOf + _coverageGlyphCount * sizeof(int)); //sizeof(ushort) * (_coverageGlyphCount % 2); }
/// <summary> /// Deserializes this structure from binary data. /// </summary> /// <param name="reader">The <see cref="BinaryReader"/> to read the data from.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception> public override void ReadFrom(BinaryReader reader, TinyFont font) { if (reader == null) { throw new ArgumentNullException("reader"); } _coverageCount = reader.ReadUInt16(); _coverageGlyphCount = reader.ReadUInt16(); _coverages.Clear(); _coverages.Capacity = _coverageCount; for (int i = 0; i < _coverageCount; i++) { Coverage coverage = new Coverage(); coverage.ReadFrom(reader); _coverages.Add(coverage); } _coverageGlyphs.Clear(); _coverageGlyphs.Capacity = _coverageGlyphCount; for (int i = 0; i < _coverageGlyphCount; i++) { CoverageGlyphs.Add(reader.ReadInt32()); } //if (_coverageGlyphCount % 2 == 1) // reader.ReadUInt16(); }
/// <summary> /// Gets total size in bytes of this appendix. /// </summary> /// <param name="font"></param> /// <returns></returns> public override int GetSize(TinyFont font) { return(sizeof(ushort) + sizeof(ushort) + _featureOffsets.Count * FeatureOffset.SizeOf + _features.Sum(f => f.GetSize()) + (_parametersHeap == null ? 0 : _parametersHeap.Length)); }
/// <summary> /// Serializes this structure into binary data. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data to.</param> /// <param name="font">The <see cref="TinyFont"/> containing this appendix.</param> public override void WriteTo(BinaryWriter writer, TinyFont font) { if (_data != null) { writer.Write(_data); } }
/// <summary> /// Serializes this structure into binary data. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data to.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception> public override void WriteTo(BinaryWriter writer, TinyFont font) { if (writer == null) { throw new ArgumentNullException("writer"); } writer.Write(_featureCount); writer.Write(_heapSize); foreach (FeatureOffset featureOffset in _featureOffsets) { featureOffset.WriteTo(writer); } foreach (Feature feature in _features) { feature.WriteTo(writer); } if (_parametersHeap != null) { writer.Write(_parametersHeap); } }
/// <summary> /// Creates new instance of Tiny Font from binary reader. /// </summary> /// <param name="reader">Source or serialized data.</param> /// <returns>New instance of Tiny Font.</returns> public static TinyFont Load(BinaryReader reader) { TinyFont font = new TinyFont(); font.ReadFrom(reader); return(font); }
/// <summary> /// Ensures this structure contains valid data. /// </summary> /// <param name="font">The <see cref="TinyFont"/> containing this appendix.</param> public override void Update(TinyFont font) { if (_data != null && _data.Length > MaximumAppendixSize) { throw new InvalidOperationException(); } }
/// <summary> /// Deserializes this structure from binary data. /// </summary> /// <param name="reader">The <see cref="BinaryReader"/> to read the data from.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception> public override void ReadFrom(BinaryReader reader, TinyFont font) { if (reader == null) { throw new ArgumentNullException("reader"); } _offsets.Clear(); for (int i = 0; i < font.TotalCharactersCount; i++) { _offsets.Add(reader.ReadUInt16()); } _attachmentListSize = reader.ReadUInt16(); _lists.Clear(); foreach (ushort offset in _offsets) { if (offset > 0) { AttachmentList list = new AttachmentList(); list.ReadFrom(reader); _lists.Add(list); } } }
/// <summary> /// Creates new instance of Character Info. /// </summary> /// <param name="font">Tiny Font containing character.</param> /// <param name="rangeIndex">Index to character range containing this character.</param> /// <param name="c">Characeter.</param> /// <param name="plane">Font plane describing plane to which this character belongs.</param> /// <param name="planeNumber">Number of <paramref name="plane"/> containg this character.</param> internal CharacterInfo(TinyFont font, int rangeIndex, char c, FontPlane plane, int planeNumber) { Contract.Assert(plane != null, "Plane for specified character does not exists."); _font = font; _characterAntialiasingData = plane.CharacterAntialiasingData; _characterBitmapData = plane.CharacterBitmapData; _c = (char)c; _planeNumber = planeNumber; _rangeIndex = rangeIndex; _range = plane.CharacterRanges[_rangeIndex]; checked { _characterIndex = (int)_range.IndexOfFirstCharacter + _c - _range.FirstCharacter; _character = plane.Characters[_characterIndex]; _offset = (int)(_range.Offset + _character.Offset); if (_font.Description.IsExtended) { _antialiasOffset = (int)(plane.CharacterRangesAntialiasing[_rangeIndex].Offset + plane.CharactersAntialiasing[_characterIndex].Offset); } else { _antialiasOffset = -1; } } }
private void FillVerticalMetrics(TinyFont font) { GlyphMetadataAppendix metadata = font.GetOrAddNewAppendix <GlyphMetadataAppendix>(); List <sbyte> marginTop = new List <sbyte>(); List <sbyte> marginBottom = new List <sbyte>(); foreach (CharacterImportInfo info in from import in _characterImportList.Values orderby import.Mapping.Character select import) { marginTop.Add(Helper.FitIntoInt8(info.EmSideBearing.Top, Trace)); marginBottom.Add(Helper.FitIntoInt8(info.EmSideBearing.Bottom, Trace)); } foreach (CharacterImportInfo info in _glyphImportList) { marginTop.Add(Helper.FitIntoInt8(info.EmSideBearing.Top, Trace)); marginBottom.Add(Helper.FitIntoInt8(info.EmSideBearing.Bottom, Trace)); } GlyphMetadataAppendix.MetadataSetOffset offsetTop = new GlyphMetadataAppendix.MetadataSetOffset(); offsetTop.Id = GlyphMetadataAppendix.MarginTopSet; offsetTop.Bits = GlyphMetadataAppendix.MetadataSetBitLength.Eight; metadata.Sets.Add(marginTop.Select(m => (byte)m).ToArray()); metadata.SetsOffsets.Add(offsetTop); GlyphMetadataAppendix.MetadataSetOffset offsetBottom = new GlyphMetadataAppendix.MetadataSetOffset(); offsetBottom.Id = GlyphMetadataAppendix.MarginBottomSet; offsetBottom.Bits = GlyphMetadataAppendix.MetadataSetBitLength.Eight; metadata.Sets.Add(marginBottom.Select(m => (byte)m).ToArray()); metadata.SetsOffsets.Add(offsetBottom); }
internal int GetSize(TinyFont font) { return(FontMetrics.SizeOf + FontDescription.SizeOf + BitmapDescription.SizeOf + _characterRanges.Count * CharacterRangeDescription.SizeOf + _characters.Count * CharacterDescription.SizeOf + _characterBitmapData.Length + (font.Description.IsExtended ? AntialiasingMetrics.SizeOf : 0) + _characterRangesAntialiasing.Count * CharacterRangeAntialiasing.SizeOf + _charactersAntialiasing.Count * CharacterAntialiasing.SizeOf + (_characterAntialiasingData == null ? 0 : _characterAntialiasingData.Length)); }
/// <summary> /// Serializes this structure into binary data. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data to.</param> /// <param name="font">The <see cref="TinyFont"/> containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception> public override void WriteTo(BinaryWriter writer, TinyFont font) { if (writer == null) { throw new ArgumentNullException("writer"); } foreach (MetadataSetOffset offset in _setsOffsets) { offset.WriteTo(writer); } foreach (byte[] data in _setsData) { writer.Write(data); } }
/// <summary> /// Ensures this structure contains valid data. /// </summary> /// <param name="font">Tiny Font containing this appendix.</param> public override void Update(TinyFont font) { UpdateAssert(_features.ItemsCount <= ushort.MaxValue, "Too many features."); UpdateAssert(_features.ItemsCount == _featureOffsets.ItemsCount, "Feature offset count mismatch."); UpdateAssert(_parametersHeap == null || _parametersHeap.Length <= ushort.MaxValue, "The parameters heap is too large."); _featureCount = (ushort)_features.ItemsCount; _heapSize = (ushort)(_parametersHeap == null ? 0 : _parametersHeap.Length); for (int i = 0; i < _features.ItemsCount; i++) { _features[i].Update(); } _features.Sentinel.StateCount = 0; _features.Sentinel.Rules.Clear(); _features.Sentinel.StateOffsets.Clear(); _features.Sentinel.StateOffsets.Sentinel = 0; SortedDictionary <FeatureOffset, Feature> sortedFeatures = new SortedDictionary <FeatureOffset, Feature>(); for (int i = 0; i < _featureCount; i++) { sortedFeatures.Add(_featureOffsets[i], _features[i]); } _featureOffsets.Clear(); _featureOffsets.AddRange(sortedFeatures.Keys); _features.Clear(); _features.AddRange(sortedFeatures.Values); int offset = 0; for (int i = 0; i < _features.Count; i++) { UpdateAssert(offset <= ushort.MaxValue, "Too large feature."); _featureOffsets[i].Offset = (ushort)offset; offset += _features[i].GetSize(); } _featureOffsets.Sentinel.Tag = 0xFFFFFFFF; }
/// <summary> /// Serializes this structure into binary data. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data to.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception> public override void WriteTo(BinaryWriter writer, TinyFont font) { if (writer == null) { throw new ArgumentNullException("writer"); } foreach (ushort offset in _offsets) { writer.Write(offset); } writer.Write(_attachmentListSize); foreach (AttachmentList list in _lists) { list.WriteTo(writer); } }
/// <summary> /// Ensures this structure contains valid data. /// </summary> /// <param name="font">Tiny Font containing this appendix.</param> public override void Update(TinyFont font) { UpdateAssert(_lists.Count <= ushort.MaxValue, "Too many attachment points lists."); _offsets.Clear(); int offset = 1; foreach (AttachmentList list in _lists) { list.Update(); _offsets.Add((ushort)offset); offset += (list.GetSize() / sizeof(ushort)); UpdateAssert(offset <= ushort.MaxValue, "Too many attachment points."); } _attachmentListSize = (ushort)(offset - 1); }
/// <summary> /// Ensures this structure contains valid data. /// </summary> /// <param name="font">Tiny Font containing this appendix.</param> public override void Update(TinyFont font) { UpdateAssert(_coverages.Count <= ushort.MaxValue, "Too many coverages."); UpdateAssert(_coverageGlyphs.Count <= ushort.MaxValue, "Too many coverage glyphs."); _coverageCount = (ushort)_coverages.Count; _coverageGlyphCount = (ushort)_coverageGlyphs.Count; foreach (Coverage coverage in _coverages) { UpdateAssert(coverage.Offset + coverage.Count <= _coverageGlyphs.Count, "Out of range coverage."); _coverageGlyphs.Sort(coverage.Offset, coverage.Count, Comparer <int> .Default); } foreach (Coverage coverage in _coverages) { UpdateAssert(Helper.IsSorted(_coverageGlyphs, coverage.Offset, coverage.Count, Comparer <int> .Default), "Incompatible overlapping coverages."); } }
/// <summary> /// Assembles new Tiny Font from imports. /// </summary> /// <returns>Tiny Font.</returns> public TinyFont Build() { TinyFont font = new TinyFont(); if (_features.Count > 0) { FillOpenType(font); // can add new characters/glyphs } FillMetrics(font.Metrics); for (ushort plane = 0; plane <= LastPlane; plane++) { FillCharacters(font, from import in _characterImportList.Values orderby import.Mapping.Character select import, plane); } for (int i = 0; i < _glyphImportList.Count; i++) { _glyphImportList[i].Mapping.Character = i + LastPlaneFirstCharacter; } if (_glyphImportList.Count > 0) { FillCharacters(font, _glyphImportList, LastPlane); } #if TERKA_FEATURES if (_importGraphemeClusterBoundaries) { FillGraphemeClusterBoundaries(font); } if (_importVerticalMetrics) { FillVerticalMetrics(font); } #endif font.Update(); RemapGlyphsToCharacters(font); return(font); }
/// <summary> /// Serializes this structure into binary data. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data to.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception> /// <exception cref="ArgumentNullException"><paramref name="font"/> is null.</exception> public override void WriteTo(BinaryWriter writer, TinyFont font) { if (writer == null) { throw new ArgumentNullException("writer"); } if (font == null) { throw new ArgumentNullException("font"); } writer.Write(_mask); writer.Write(_reserved); foreach (FontPlane plane in _fontPlanes) { plane.WriteTo(writer, font); } }
/// <summary> /// Deserializes this structure from binary data. /// </summary> /// <param name="reader">The <see cref="BinaryReader"/> to read the data from.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception> public override void ReadFrom(BinaryReader reader, TinyFont font) { if (reader == null) { throw new ArgumentNullException("reader"); } _featureCount = reader.ReadUInt16(); _heapSize = reader.ReadUInt16(); _featureOffsets.Clear(); _featureOffsets.Capacity = _featureCount; for (int i = 0; i < _featureCount; i++) { FeatureOffset offset = new FeatureOffset(); offset.ReadFrom(reader); _featureOffsets.Add(offset); } _featureOffsets.Sentinel.ReadFrom(reader); _features.Clear(); _features.Capacity = _featureCount; for (int i = 0; i < _featureCount; i++) { Feature feature = new Feature(); feature.ReadFrom(reader); _features.Add(feature); } _features.Sentinel.ReadFrom(reader); if (_heapSize > 0) { _parametersHeap = reader.ReadBytes(_heapSize); } }
/// <summary> /// Ensures this structure contains valid data. /// </summary> /// <param name="font">Tiny Font containing this appendix.</param> public override void Update(TinyFont font) { ushort positionMask = _mask; int removedMask = 0; int i = 0; while (positionMask != 0) { if ((positionMask & 1) != 0) { UpdateAssert(i < _fontPlanes.Count, "Too few planes."); UpdateAssert(_fontPlanes[i] != null, "Plane not initialized."); _fontPlanes[i].Update(); if (!_fontPlanes[i].HasContent) { removedMask |= 1 << i; _fontPlanes.RemoveAt(i); } else { // we need to keep all metrics in sync, but bitmap ~ offset can be different short planeOffset = _fontPlanes[i].Metrics.Offset; _fontPlanes[i].Metrics = (FontMetrics)font.Metrics.Clone(); _fontPlanes[i].Metrics.Offset = planeOffset; i++; } } positionMask >>= 1; } _mask &= (ushort)~removedMask; }
/// <summary> /// Serializes this structure into binary data. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data to.</param> /// <param name="font">Tiny Font containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception> public override void WriteTo(BinaryWriter writer, TinyFont font) { if (writer == null) { throw new ArgumentNullException("writer"); } writer.Write(_coverageCount); writer.Write(_coverageGlyphCount); for (int i = 0; i < _coverages.Count; i++) { _coverages[i].WriteTo(writer); } for (int i = 0; i < _coverageGlyphs.Count; i++) { writer.Write(_coverageGlyphs[i]); } //if (_coverageGlyphCount % 2 == 1) // writer.Write((ushort)0); }
/// <summary> /// Serializes this structure into binary data. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to write the data to.</param> /// <param name="font">The <see cref="TinyFont"/> containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="writer"/> is null.</exception> public void WriteTo(BinaryWriter writer, TinyFont font) { if (writer == null) { throw new ArgumentNullException(); } if (font == null) { throw new ArgumentNullException(); } _metrics.WriteTo(writer); _description.WriteTo(writer); _characterBitmapDescription.WriteTo(writer); WriteBasicTo(writer); if (font.Description.IsExtended) { WriteExtendedTo(writer); } }
/// <summary> /// Deserializes this structure from binary data. /// </summary> /// <param name="reader">The <see cref="BinaryReader"/> to read the data from.</param> /// <param name="font">The <see cref="TinyFont"/> containing this appendix.</param> /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception> public void ReadFrom(BinaryReader reader, TinyFont font) { if (reader == null) { throw new ArgumentNullException(); } if (font == null) { throw new ArgumentNullException(); } _metrics.ReadFrom(reader); _description.ReadFrom(reader); _characterBitmapDescription.ReadFrom(reader); ReadBasicFrom(reader); if (font.Description.IsExtended) { ReadExtendedFrom(reader); } }
private void FillGraphemeClusterBoundaries(TinyFont font) { GlyphMetadataAppendix metadata = font.GetOrAddNewAppendix <GlyphMetadataAppendix>(); byte[] clusterBoundaries = Resources.GraphemeBreakProperty; BitArray data = new BitArray(0); foreach (CharacterInfo info in font.EnumerateAllCharacterInfos()) { byte property = FindClusterProperty(clusterBoundaries, info.Codepoint); data.AppendLsb(property, 4); } byte[] setData = new byte[(data.Length + 7) / 8]; data.CopyTo(setData, 0); metadata.Sets.Add(setData); GlyphMetadataAppendix.MetadataSetOffset offset = new GlyphMetadataAppendix.MetadataSetOffset(); offset.Id = GlyphMetadataAppendix.GraphemeSet; offset.Bits = GlyphMetadataAppendix.MetadataSetBitLength.Four; metadata.SetsOffsets.Add(offset); }
private void FillCharacters(TinyFont font, IEnumerable <CharacterImportInfo> imports, ushort planeNumber) { Contract.Requires(font != null, "Font cannot be null."); Contract.Requires(font.Metrics != null, "Font metrics cannot be null."); if (font.Metrics.Height == 0) { Trace.TraceEvent(TraceEventType.Warning, 0, "TinyFont has a height of zero. No glyphs will be included."); return; } FontPlane plane = planeNumber == 0 ? font.FontPlanes[0] : new FontPlane(); Contract.Requires(plane != null, "Plane cannot be null."); FillDescription(plane.Description); uint numberOfCharacters = 0; bool antialiasing = font.Description.IsExtended; short firstNonBlankLine = short.MaxValue; int maxCharacterWidth = font.Metrics.MaximumCharacterWidth; BitArray antialiasingData = new BitArray(0); List <BitArray> bitmapData = new List <BitArray>(font.Metrics.Height); for (int i = 0; i < font.Metrics.Height; i++) { bitmapData.Add(new BitArray(0)); } int lastCharacter = -1; CharacterRangeDescription rangeDescription = null; CharacterRangeAntialiasing rangeAntialiasing = null; foreach (CharacterImportInfo import in imports) { Contract.Assert(import.Mapping.Character.Value >= 0 && import.Mapping.Character.Value <= LastPlaneLastCharacter, "All content must have valid two bytes characters."); Contract.Assert(import.Mapping.Character.Value > lastCharacter, "Content must be ordered by characters and cannot overlap."); int character = import.Mapping.Character.Value; // If character does not belong to this plane, skip it if ((character >> 16) != planeNumber) { continue; } if (lastCharacter != (character - 1)) { if (rangeDescription != null) { rangeDescription.LastCharacter = (char)lastCharacter; plane.CharacterRanges.Add(rangeDescription); if (antialiasing) { plane.CharacterRangesAntialiasing.Add(rangeAntialiasing); } } rangeDescription = new CharacterRangeDescription(); rangeDescription.Offset = (uint)bitmapData[0].Length; rangeDescription.FirstCharacter = (char)character; rangeDescription.IndexOfFirstCharacter = numberOfCharacters; if (antialiasing) { rangeAntialiasing = new CharacterRangeAntialiasing(); rangeAntialiasing.Offset = (uint)(antialiasingData.Length / BitsPerByte); } } lastCharacter = character; maxCharacterWidth = Math.Max(maxCharacterWidth, import.InkBox.Width); ++numberOfCharacters; CharacterDescription characterDescription = new CharacterDescription(); characterDescription.LeftMargin = Helper.FitIntoInt8(import.EmSideBearing.Left, Trace); characterDescription.RightMargin = Helper.FitIntoInt8(import.EmSideBearing.Right, Trace); characterDescription.Offset = checked ((ushort)(bitmapData[0].Length - rangeDescription.Offset)); plane.Characters.Add(characterDescription); if (import.BitmapData != null) { AppendBitmap(bitmapData, import); short glyphFirstNonBlankLine = Helper.FitIntoInt16(import.InkBox.Y, Trace); if (firstNonBlankLine > glyphFirstNonBlankLine) { firstNonBlankLine = glyphFirstNonBlankLine; } } if (antialiasing) { CharacterAntialiasing characterAntialiasing = new CharacterAntialiasing(); characterAntialiasing.Offset = import.AntialiasData == null ? CharacterAntialiasing.NoData : checked ((ushort)(antialiasingData.Length / BitsPerByte - rangeAntialiasing.Offset)); plane.CharactersAntialiasing.Add(characterAntialiasing); if (import.AntialiasData != null) { AppendAntialiasing(antialiasingData, import); int bitPadding = antialiasingData.Length % BitsPerByte; if (bitPadding > 0) { antialiasingData.Length += BitsPerByte - bitPadding; } } } } if (numberOfCharacters > 0) { if (rangeDescription != null) { rangeDescription.LastCharacter = (char)lastCharacter; plane.CharacterRanges.Add(rangeDescription); if (antialiasing) { plane.CharacterRangesAntialiasing.Add(rangeAntialiasing); } } plane.Metrics.Offset = firstNonBlankLine; plane.CharacterBitmap.Width = (uint)bitmapData[0].Length; plane.CharacterBitmap.Height = (uint)(bitmapData.Count - firstNonBlankLine); plane.CharacterBitmap.BitsPerPixel = 1; plane.CharacterBitmapData = ToBitmapData(bitmapData, firstNonBlankLine); if (antialiasing) { plane.CharacterAntialiasingData = ToAntialiasingData(antialiasingData); plane.CharacterAntialiasingMetrics.Size = (uint)plane.CharacterAntialiasingData.Length; } font.Metrics.MaximumCharacterWidth = Helper.FitIntoInt16(maxCharacterWidth, Trace); font.FontPlanes[planeNumber] = plane; } }
private void RemapGlyphsToCharacters(TinyFont font) { Dictionary <ushort, int> mapping = new Dictionary <ushort, int>(); foreach (CharacterImportInfo info in _glyphImportList) { if (info.Mapping.Glyph.HasValue) { mapping[info.Mapping.Glyph.Value] = info.Mapping.Character.Value; } } foreach (CharacterImportInfo info in _characterImportList.Values) { if (info.Mapping.Glyph.HasValue) { mapping[info.Mapping.Glyph.Value] = info.Mapping.Character.Value; } } byte plane; ushort planeLess; foreach (StateMachineAppendix substition in font.Appendices.OfType <StateMachineAppendix>()) { foreach (StateMachineAppendix.Feature feature in substition.Features) { foreach (StateMachineAppendix.Rule rule in feature.Rules) { if (rule.Condition == StateMachineAppendix.RuleCondition.Glyph) { RemapGlyph(mapping, rule.ConditionParameter, out plane, out planeLess); rule.ConditionPlane = plane; rule.ConditionParameter = planeLess; } switch (rule.Action) { case StateMachineAppendix.RuleAction.GlyphOverwrite: case StateMachineAppendix.RuleAction.GlyphRewrite_2_1: case StateMachineAppendix.RuleAction.GlyphRewrite_3_1: case StateMachineAppendix.RuleAction.GlyphInsertion: { RemapGlyph(mapping, rule.ActionParameter, out plane, out planeLess); rule.ActionPlane = plane; rule.ActionParameter = planeLess; } break; case StateMachineAppendix.RuleAction.GlyphRewrite_N_M: int offset = rule.ActionParameter + sizeof(ushort); int glyphCount = BitConverter.ToUInt16(substition.ParametersHeap, offset); offset += sizeof(ushort); for (int i = 0; i < glyphCount; i++, offset += sizeof(int)) { int glyph = BitConverter.ToInt32(substition.ParametersHeap, offset); glyph = RemapGlyph(mapping, (ushort)glyph, out plane, out planeLess); BitConverter.GetBytes(glyph).CopyTo(substition.ParametersHeap, offset); } break; } } } } foreach (GlyphClassesAppendix coverage in font.Appendices.OfType <GlyphClassesAppendix>()) { for (int i = 0; i < coverage.CoverageGlyphs.Count; i++) { coverage.CoverageGlyphs[i] = RemapGlyph(mapping, (ushort)coverage.CoverageGlyphs[i], out plane, out planeLess); } } }