Example #1
0
        /// <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>
        /// read GlyphPlan latest layout output
        /// </summary>
        private static void ReadOutput(GlyphLayout glyphLayout,
                                       UnscaledGlyphPlanList outputGlyphPlanList)
        {
            Typeface typeface       = glyphLayout.Typeface;
            var      glyphPositions = glyphLayout._glyphPositions;
            //3.read back
            int   finalGlyphCount = glyphPositions.Count;
            int   cx = 0;
            short cy = 0;

            PositionTechnique posTech    = glyphLayout.PositionTechnique;
            ushort            prev_index = 0;

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                GlyphPos glyphPos = glyphPositions[i];
                switch (posTech)
                {
                default: throw new NotSupportedException();

                case PositionTechnique.None:
                    outputGlyphPlanList.Append(new UnscaledGlyphPlan(
                                                   0,
                                                   glyphPos.glyphIndex, glyphPos.advanceW, cx, cy));
                    break;

                case PositionTechnique.OpenFont:
                    outputGlyphPlanList.Append(new UnscaledGlyphPlan(
                                                   0,
                                                   glyphPos.glyphIndex,
                                                   glyphPos.advanceW,
                                                   cx + glyphPos.xoffset,
                                                   (short)(cy + glyphPos.yoffset)));
                    break;

                case PositionTechnique.Kerning:

                    if (i > 0)
                    {
                        cx += typeface.GetKernDistance(prev_index, glyphPos.glyphIndex);
                    }
                    outputGlyphPlanList.Append(new UnscaledGlyphPlan(
                                                   0,
                                                   prev_index = glyphPos.glyphIndex,
                                                   glyphPos.advanceW,
                                                   cx,
                                                   cy));

                    break;
                }
                cx += glyphPos.advanceW;
            }
        }
        void Layout(GlyphIndexList glyphs)
        {
            if (_needPlanUpdate)
            {
                UpdateLayoutPlan();
            }

            //[C]
            //----------------------------------------------
            //glyph substitution
            if (_gsub != null && glyphs.Count > 0)
            {
                //TODO: review perf here
                _gsub.EnableLigation    = this.EnableLigature;
                _gsub.EnableComposition = this.EnableComposition;
                _gsub.DoSubstitution(glyphs);
            }

            //----------------------------------------------
            //after glyph substitution,
            //number of input glyph MAY changed (increase or decrease).***
            //so count again.
            int finalGlyphCount = glyphs.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;
                glyphs.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(input_codepointOffset, glyIndex, orgGlyph);
            }

            PositionTechnique posTech = this.PositionTechnique;

            if (_gpos != null && glyphs.Count > 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
            //----------------------------------------------
        }
Example #4
0
        /// <summary>
        /// read latest layout output
        /// </summary>
        /// <param name="glyphLayout"></param>
        /// <param name="readDel"></param>
        public static void ReadOutput(this GlyphLayout glyphLayout, GlyphReadOutputDelegate readDel)
        {
            Typeface        typeface       = glyphLayout.Typeface;
            List <GlyphPos> glyphPositions = glyphLayout._glyphPositions;
            //3.read back
            int   finalGlyphCount = glyphPositions.Count;
            int   cx = 0;
            short cy = 0;

            PositionTechnique posTech    = glyphLayout.PositionTechnique;
            ushort            prev_index = 0;

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                GlyphPos glyphPos = glyphPositions[i];
                //----------------------------------
                switch (posTech)
                {
                default: throw new NotSupportedException();

                case PositionTechnique.None:
                    readDel(i, new GlyphPlan(glyphPos.glyphIndex, cx, cy, glyphPos.advWidth));
                    break;

                case PositionTechnique.OpenFont:
                    readDel(i, new GlyphPlan(
                                glyphPos.glyphIndex,
                                cx + glyphPos.xoffset,
                                (short)(cy + glyphPos.yoffset),
                                glyphPos.advWidth));
                    break;

                case PositionTechnique.Kerning:

                    if (i > 0)
                    {
                        cx += typeface.GetKernDistance(prev_index, glyphPos.glyphIndex);
                    }
                    readDel(i, new GlyphPlan(
                                prev_index = glyphPos.glyphIndex,
                                cx,
                                cy,
                                glyphPos.advWidth));

                    break;
                }
                cx += glyphPos.advWidth;
            }
        }
Example #5
0
        /// <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
            //----------------------------------------------
        }
Example #6
0
        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
            //----------------------------------------------
        }