public void Layout(IList <int> inputCodePoints, int startAt, int len) { // //[B] // convert codepoint-list to input glyph-list // clear before use _inputGlyphs.Clear(); int end = startAt + len; for (int i = 0; i < end; ++i) { //find glyph index by specific codepoint ushort glyphIndex = _typeface.LookupIndex(inputCodePoints[i]); if (i + 1 < end) { // Maybe this is a UVS sequence; in that case, //***SKIP*** the second codepoint ushort variationGlyphIndex = _typeface.LookupIndex(inputCodePoints[i], inputCodePoints[i + 1]); if (variationGlyphIndex > 0) { //user glyph index from next codepoint glyphIndex = variationGlyphIndex; //but record as current code point i _inputGlyphs.AddGlyph(i, glyphIndex); ++i; //skip continue; //*** } } _inputGlyphs.AddGlyph(i, glyphIndex); } //continue below... Layout(_inputGlyphs); }
/// <summary> /// do glyph shaping and glyph out /// </summary> /// <param name="str"></param> /// <param name="startAt"></param> /// <param name="len"></param> public void Layout( char[] str, int startAt, int len) { if (_needPlanUpdate) { UpdateLayoutPlan(); } Typeface typeface = this._typeface; //clear before use _inputGlyphs.Clear(); for (int i = 0; i < len; ++i) { //convert input char to input glyphs char c = str[startAt + i]; _inputGlyphs.AddGlyph(c, (ushort)typeface.LookupIndex(c)); } //---------------------------------------------- //glyph substitution if (_gsub != null & len > 0) { //TODO: review perf here _gsub.EnableLigation = this.EnableLigature; _gsub.DoSubstitution(_inputGlyphs); // _inputGlyphs.CreateMapFromUserCharToGlyphIndics(); } //---------------------------------------------- //after glyph substitution, //number of input glyph MAY changed (increase or decrease).*** //so count again. int finalGlyphCount = _inputGlyphs.Count; //---------------------------------------------- //glyph position _glyphPositions.Clear(); for (int i = 0; i < finalGlyphCount; ++i) { //at this stage _inputGlyphs and _glyphPositions //has member 1:1 ushort glyIndex = _inputGlyphs[i]; _glyphPositions.Add(new GlyphPos( glyIndex, typeface.GetGlyphByIndex(glyIndex).GlyphClass, typeface.GetHAdvanceWidthFromGlyphIndex(glyIndex)) ); } PositionTechnique posTech = this.PositionTechnique; if (_gpos != null && len > 1 && posTech == PositionTechnique.OpenFont) { _gpos.DoGlyphPosition(_glyphPositions); } }
/// <summary> /// do glyph shaping and glyph out /// </summary> /// <param name="str"></param> /// <param name="startAt"></param> /// <param name="len"></param> public void Layout( char[] str, int startAt, int len) { if (_needPlanUpdate) { UpdateLayoutPlan(); } //[A] // this is important! // ----------------------- // from @samhocevar's PR: (https://github.com/LayoutFarm/Typography/pull/56/commits/b71c7cf863531ebf5caa478354d3249bde40b96e) // In many places, "char" is not a valid type to handle characters, because it // only supports 16 bits.In order to handle the full range of Unicode characters, // we need to use "int". // This allows characters such as 🙌 or 𐐷 or to be treated as single codepoints even // though they are encoded as two "char"s in a C# string. _reusableCodePointFromUserCharList.Clear(); for (int i = 0; i < len; ++i) { char ch = str[startAt + i]; int codepoint = ch; if (ch >= 0xd800 && ch <= 0xdbff && i + 1 < len) { char nextCh = str[startAt + i + 1]; if (nextCh >= 0xdc00 && nextCh <= 0xdfff) { //please note: //num of codepoint may be less than original user input char ++i; codepoint = char.ConvertToUtf32(ch, nextCh); } } _reusableCodePointFromUserCharList.Add(new CodePointFromUserChar((ushort)i, codepoint)); } // //[B] // convert codepoint-list to input glyph-list // clear before use _inputGlyphs.Clear(); int codePointCount = _reusableCodePointFromUserCharList.Count; for (int i = 0; i < codePointCount; ++i) { CodePointFromUserChar cp = _reusableCodePointFromUserCharList[i]; ushort glyphIndex = _typeface.LookupIndex(cp.codePoint); if (i + 1 < codePointCount) { // Maybe this is a UVS sequence; in that case, //***SKIP*** the second codepoint CodePointFromUserChar nextCp = _reusableCodePointFromUserCharList[i + 1]; ushort variationGlyphIndex = _typeface.LookupIndex(cp.codePoint, nextCp.codePoint); if (variationGlyphIndex > 0) { //user glyph index from next codepoint glyphIndex = variationGlyphIndex; //but record as current code point i _inputGlyphs.AddGlyph(i, glyphIndex); ++i; //skip continue; //*** } } _inputGlyphs.AddGlyph(i, glyphIndex); } //[C] //---------------------------------------------- //glyph substitution if (_gsub != null & len > 0) { //TODO: review perf here _gsub.EnableLigation = this.EnableLigature; _gsub.EnableComposition = this.EnableComposition; _gsub.DoSubstitution(_inputGlyphs); } //---------------------------------------------- //after glyph substitution, //number of input glyph MAY changed (increase or decrease).*** //so count again. int finalGlyphCount = _inputGlyphs.Count; //---------------------------------------------- //[D] //glyph position _glyphPositions.Clear(); _glyphPositions.Typeface = _typeface; for (int i = 0; i < finalGlyphCount; ++i) { //at this stage _inputGlyphs and _glyphPositions //has member 1:1 ushort glyIndex, input_codepointOffset, input_mapLen; _inputGlyphs.GetGlyphIndexAndMap(i, out glyIndex, out input_codepointOffset, out input_mapLen); // Glyph orgGlyph = _typeface.GetGlyphByIndex(glyIndex); //this is original value WITHOUT fit-to-grid adjust _glyphPositions.AddGlyph((short)input_codepointOffset, glyIndex, orgGlyph); } PositionTechnique posTech = this.PositionTechnique; if (_gpos != null && len > 1 && posTech == PositionTechnique.OpenFont) { _gpos.DoGlyphPosition(_glyphPositions); } //---------------------------------------------- //at this point, all positions are layouted at its original scale *** //then we will scale it to target scale later //---------------------------------------------- }
List <int> _codepoints = new List <int>();//not thread-safe*** /// <summary> /// do glyph shaping and glyph out /// </summary> /// <param name="str"></param> /// <param name="startAt"></param> /// <param name="len"></param> public void Layout( char[] str, int startAt, int len) { if (_needPlanUpdate) { UpdateLayoutPlan(); } // this is important! // ----------------------- // from @samhocevar's PR: (https://github.com/LayoutFarm/Typography/pull/56/commits/b71c7cf863531ebf5caa478354d3249bde40b96e) // In many places, "char" is not a valid type to handle characters, because it // only supports 16 bits.In order to handle the full range of Unicode characters, // we need to use "int". // This allows characters such as 🙌 or 𐐷 or to be treated as single codepoints even // though they are encoded as two "char"s in a C# string. _codepoints.Clear(); for (int i = 0; i < len; ++i) { char ch = str[startAt + i]; int codepoint = ch; if (Char.IsHighSurrogate(ch) && i + 1 < len) { char nextCh = str[startAt + i + 1]; if (Char.IsLowSurrogate(nextCh)) { ++i; codepoint = char.ConvertToUtf32(ch, nextCh); } } _codepoints.Add(codepoint); } // clear before use _inputGlyphs.Clear(); // convert codepoints to input glyphs for (int i = 0; i < _codepoints.Count; ++i) { int codepoint = _codepoints[i]; ushort glyphIndex = _typeface.LookupIndex(codepoint); if (i + 1 < _codepoints.Count) { // Maybe this is a UVS sequence; in that case, skip the second codepoint int nextCodepoint = _codepoints[i + 1]; ushort variationGlyphIndex = _typeface.LookupIndex(codepoint, nextCodepoint); if (variationGlyphIndex > 0) { ++i; glyphIndex = variationGlyphIndex; } } _inputGlyphs.AddGlyph(codepoint, glyphIndex); } //---------------------------------------------- //glyph substitution if (_gsub != null & len > 0) { //TODO: review perf here _gsub.EnableLigation = this.EnableLigature; _gsub.EnableComposition = this.EnableComposition; _gsub.DoSubstitution(_inputGlyphs); // _inputGlyphs.CreateMapFromUserCharToGlyphIndices(); } //---------------------------------------------- //after glyph substitution, //number of input glyph MAY changed (increase or decrease).*** //so count again. int finalGlyphCount = _inputGlyphs.Count; //---------------------------------------------- //glyph position _glyphPositions.Clear(); _glyphPositions.Typeface = _typeface; for (int i = 0; i < finalGlyphCount; ++i) { //at this stage _inputGlyphs and _glyphPositions //has member 1:1 ushort glyIndex = _inputGlyphs[i]; // TtfGlyph orgGlyph = _typeface.GetGlyphByIndex(glyIndex); //this is original value WITHOUT fit-to-grid adjust _glyphPositions.AddGlyph(glyIndex, orgGlyph); } PositionTechnique posTech = this.PositionTechnique; if (_gpos != null && len > 1 && posTech == PositionTechnique.OpenFont) { _gpos.DoGlyphPosition(_glyphPositions); } //---------------------------------------------- //at this point, all position is layout at original scale *** //then we will scale it to target scale later //---------------------------------------------- }