internal IVertexSource GetGlyphForCharacter(char character) { if (ttfTypeFace != null) { // TODO: MAKE SURE THIS IS OFF!!!!!!! It is un-needed and only for debugging //glyphs.Clear(); } IVertexSource vertexSource = null; // TODO: check for multi character glyphs (we don't currently support them in the reader). Glyph glyph = null; if (!glyphs.TryGetValue(character, out glyph)) { // if we have a loaded ttf try to create the glyph data if (ttfTypeFace != null) { glyph = new Glyph(); var translator = new VertexSourceGlyphTranslator(glyph.glyphData); var glyphIndex = ttfTypeFace.LookupIndex(character); var ttfGlyph = ttfTypeFace.GetGlyphByIndex(glyphIndex); translator.Read(ttfGlyph.GlyphPoints, ttfGlyph.EndPoints); glyph.unicode = character; glyph.horiz_adv_x = ttfTypeFace.GetHAdvanceWidthFromGlyphIndex(glyphIndex); glyphs.Add(character, glyph); vertexSource = glyph.glyphData; } } else { vertexSource = glyph.glyphData; } return(vertexSource); }
public static void CollectAllAssociateGlyphIndex(this TtfTypeface typeface, List <ushort> outputGlyphIndexList, ScriptLang scLang, UnicodeLangBits[] selectedRangs = null) { //----------- //general glyph index in the unicode range //if user dose not specific the unicode lanf bit ranges //the we try to select it ourself. UnicodeLangBits[] unicodeLangBitsRanges; if (ScriptLangs.TryGenUnicodeLangBitsArray(scLang.shortname, out unicodeLangBitsRanges)) { //one lang may contains may ranges if (selectedRangs != null) { //select only in range unicodeLangBitsRanges = FilterOnlySelectedRange(unicodeLangBitsRanges, selectedRangs); } foreach (UnicodeLangBits unicodeLangBits in unicodeLangBitsRanges) { UnicodeRangeInfo rngInfo = unicodeLangBits.ToUnicodeRangeInfo(); int endAt = rngInfo.EndAt; for (int codePoint = rngInfo.StartAt; codePoint <= endAt; ++codePoint) { ushort glyghIndex = typeface.LookupIndex(codePoint); if (glyghIndex > 0) { //add this glyph index outputGlyphIndexList.Add(glyghIndex); } } } } //----------- var gsub = new GlyphSubstitution(typeface, scLang.shortname); gsub.CollectAdditionalSubstitutionGlyphIndices(outputGlyphIndexList); }
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 //---------------------------------------------- }