コード例 #1
0
 public void AddGlyph(ushort glyphIndex, TtfGlyph glyph)
 {
     if (!glyph.HasOriginalAdvancedWidth)
     {
         glyph.OriginalAdvanceWidth = _typeface.GetHAdvanceWidthFromGlyphIndex(glyphIndex);
     }
     _glyphs.Add(new GlyphPos(glyphIndex, glyph.GlyphClass, glyph.OriginalAdvanceWidth));
 }
コード例 #2
0
ファイル: GDEF.cs プロジェクト: lalanikarim/agg-sharp
        void FillMarkAttachmentClassDefs(TtfGlyph[] inputGlyphs)
        {
            //Mark Attachment Class Definition Table
            //A Mark Class Definition Table is used to assign mark glyphs into different classes
            //that can be used in lookup tables within the GSUB or GPOS table to control how mark glyphs within a glyph sequence are treated by lookups.
            //For more information on the use of mark attachment classes,
            //see the description of lookup flags in the “Lookup Table” section of the chapter, OpenType Layout Common Table Formats.
            ClassDefTable markAttachmentClassDef = this.MarkAttachmentClassDef;

            if (markAttachmentClassDef == null)
            {
                return;
            }
            //-----------------------------------------

            switch (markAttachmentClassDef.Format)
            {
            default:
                Utils.WarnUnimplemented("GDEF MarkAttachmentClassDef Table Format {0}", markAttachmentClassDef.Format);
                break;

            case 1:
            {
                ushort   startGlyph  = markAttachmentClassDef.startGlyph;
                ushort[] classValues = markAttachmentClassDef.classValueArray;

                int len    = classValues.Length;
                int gIndex = startGlyph;
                for (int i = 0; i < len; ++i)
                {
#if DEBUG
                    TtfGlyph dbugTestGlyph = inputGlyphs[gIndex];
#endif
                    inputGlyphs[gIndex].MarkClassDef = classValues[i];
                    gIndex++;
                }
            }
            break;

            case 2:
            {
                ClassDefTable.ClassRangeRecord[] records = markAttachmentClassDef.records;
                int len = records.Length;
                for (int n = 0; n < len; ++n)
                {
                    ClassDefTable.ClassRangeRecord rec = records[n];
                    for (int i = rec.startGlyphId; i <= rec.endGlyphId; ++i)
                    {
#if DEBUG
                        TtfGlyph dbugTestGlyph = inputGlyphs[i];
#endif
                        inputGlyphs[i].MarkClassDef = rec.classNo;
                    }
                }
            }
            break;
            }
        }
コード例 #3
0
        TtfGlyph ReadCompositeGlyph(TtfGlyph[] createdGlyphs, BinaryReader reader, uint tableOffset, int compositeGlyphIndex)
        {
            //------------------------------------------------------
            //https://www.microsoft.com/typography/OTSPEC/glyf.htm
            //Composite Glyph Description

            //This is the table information needed for composite glyphs (numberOfContours is -1).
            //A composite glyph starts with two USHORT values (“flags” and “glyphIndex,” i.e. the index of the first contour in this composite glyph);
            //the data then varies according to “flags”).
            //Type  Name    Description
            //USHORT    flags   component flag
            //USHORT    glyphIndex  glyph index of component
            //VARIABLE  argument1   x-offset for component or point number; type depends on bits 0 and 1 in component flags
            //VARIABLE  argument2   y-offset for component or point number; type depends on bits 0 and 1 in component flags
            //---------
            //see more at https://fontforge.github.io/assets/old/Composites/index.html
            //---------

            //move to composite glyph position
            reader.BaseStream.Seek(tableOffset + GlyphLocations.Offsets[compositeGlyphIndex], SeekOrigin.Begin); //reset
            //------------------------
            short  contoursCount = reader.ReadInt16();                                                           // ignored
            Bounds bounds        = Utils.ReadBounds(reader);

            TtfGlyph            finalGlyph = null;
            CompositeGlyphFlags flags;

            do
            {
                flags = (CompositeGlyphFlags)reader.ReadUInt16();
                ushort glyphIndex = reader.ReadUInt16();
                if (createdGlyphs[glyphIndex] == null)
                {
                    // This glyph is not read yet, resolve it first!
                    long     storedOffset = reader.BaseStream.Position;
                    TtfGlyph missingGlyph = ReadCompositeGlyph(createdGlyphs, reader, tableOffset, glyphIndex);
                    createdGlyphs[glyphIndex]  = missingGlyph;
                    reader.BaseStream.Position = storedOffset;
                }

                TtfGlyph newGlyph = TtfGlyph.Clone(createdGlyphs[glyphIndex]);

                short  arg1     = 0;
                short  arg2     = 0;
                ushort arg1and2 = 0;

                if (HasFlag(flags, CompositeGlyphFlags.ARG_1_AND_2_ARE_WORDS))
                {
                    arg1 = reader.ReadInt16();
                    arg2 = reader.ReadInt16();
                }
                else
                {
                    arg1and2 = reader.ReadUInt16();
                }
                //-----------------------------------------
                float xscale  = 1;
                float scale01 = 0;
                float scale10 = 0;
                float yscale  = 1;

                bool useMatrix = false;
                //-----------------------------------------
                bool hasScale = false;
                if (HasFlag(flags, CompositeGlyphFlags.WE_HAVE_A_SCALE))
                {
                    //If the bit WE_HAVE_A_SCALE is set,
                    //the scale value is read in 2.14 format-the value can be between -2 to almost +2.
                    //The glyph will be scaled by this value before grid-fitting.
                    xscale   = yscale = ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */
                    hasScale = true;
                }
                else if (HasFlag(flags, CompositeGlyphFlags.WE_HAVE_AN_X_AND_Y_SCALE))
                {
                    xscale   = ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */
                    yscale   = ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */
                    hasScale = true;
                }
                else if (HasFlag(flags, CompositeGlyphFlags.WE_HAVE_A_TWO_BY_TWO))
                {
                    //The bit WE_HAVE_A_TWO_BY_TWO allows for linear transformation of the X and Y coordinates by specifying a 2 × 2 matrix.
                    //This could be used for scaling and 90-degree*** rotations of the glyph components, for example.

                    //2x2 matrix

                    //The purpose of USE_MY_METRICS is to force the lsb and rsb to take on a desired value.
                    //For example, an i-circumflex (U+00EF) is often composed of the circumflex and a dotless-i.
                    //In order to force the composite to have the same metrics as the dotless-i,
                    //set USE_MY_METRICS for the dotless-i component of the composite.
                    //Without this bit, the rsb and lsb would be calculated from the hmtx entry for the composite
                    //(or would need to be explicitly set with TrueType instructions).

                    //Note that the behavior of the USE_MY_METRICS operation is undefined for rotated composite components.
                    useMatrix = true;
                    hasScale  = true;
                    xscale    = ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */
                    scale01   = ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */
                    scale10   = ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */
                    yscale    = ((float)reader.ReadInt16()) / (1 << 14); /* Format 2.14 */

                    if (HasFlag(flags, CompositeGlyphFlags.UNSCALED_COMPONENT_OFFSET))
                    {
                    }
                    else
                    {
                    }
                    if (HasFlag(flags, CompositeGlyphFlags.USE_MY_METRICS))
                    {
                    }
                }

                //--------------------------------------------------------------------
                if (HasFlag(flags, CompositeGlyphFlags.ARGS_ARE_XY_VALUES))
                {
                    //Argument1 and argument2 can be either x and y offsets to be added to the glyph or two point numbers.
                    //x and y offsets to be added to the glyph
                    //When arguments 1 and 2 are an x and a y offset instead of points and the bit ROUND_XY_TO_GRID is set to 1,
                    //the values are rounded to those of the closest grid lines before they are added to the glyph.
                    //X and Y offsets are described in FUnits.

                    if (useMatrix)
                    {
                        //use this matrix
                        TtfGlyph.TransformNormalWith2x2Matrix(newGlyph, xscale, scale01, scale10, yscale);
                        TtfGlyph.OffsetXY(newGlyph, (short)(arg1), arg2);
                    }
                    else
                    {
                        if (hasScale)
                        {
                            if (xscale == 1.0 && yscale == 1.0)
                            {
                            }
                            else
                            {
                                TtfGlyph.TransformNormalWith2x2Matrix(newGlyph, xscale, 0, 0, yscale);
                            }
                            TtfGlyph.OffsetXY(newGlyph, arg1, arg2);
                        }
                        else
                        {
                            if (HasFlag(flags, CompositeGlyphFlags.ROUND_XY_TO_GRID))
                            {
                                //TODO: implement round xy to grid***
                                //----------------------------
                            }
                            //just offset***
                            TtfGlyph.OffsetXY(newGlyph, arg1, arg2);
                        }
                    }
                }
                else
                {
                    //two point numbers.
                    //the first point number indicates the point that is to be matched to the new glyph.
                    //The second number indicates the new glyph's “matched” point.
                    //Once a glyph is added,its point numbers begin directly after the last glyphs (endpoint of first glyph + 1)
                }

                //
                if (finalGlyph == null)
                {
                    finalGlyph = newGlyph;
                }
                else
                {
                    //merge
                    TtfGlyph.AppendGlyph(finalGlyph, newGlyph);
                }
            } while (HasFlag(flags, CompositeGlyphFlags.MORE_COMPONENTS));
            //
            if (HasFlag(flags, CompositeGlyphFlags.WE_HAVE_INSTRUCTIONS))
            {
                ushort numInstr = reader.ReadUInt16();
                byte[] insts    = reader.ReadBytes(numInstr);
                finalGlyph.GlyphInstructions = insts;
            }
            //F2DOT14   16-bit signed fixed number with the low 14 bits of fraction (2.14).
            //Transformation Option
            //
            //The C pseudo-code fragment below shows how the composite glyph information is stored and parsed; definitions for “flags” bits follow this fragment:
            //  do {
            //    USHORT flags;
            //    USHORT glyphIndex;
            //    if ( flags & ARG_1_AND_2_ARE_WORDS) {
            //    (SHORT or FWord) argument1;
            //    (SHORT or FWord) argument2;
            //    } else {
            //        USHORT arg1and2; /* (arg1 << 8) | arg2 */
            //    }
            //    if ( flags & WE_HAVE_A_SCALE ) {
            //        F2Dot14  scale;    /* Format 2.14 */
            //    } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) {
            //        F2Dot14  xscale;    /* Format 2.14 */
            //        F2Dot14  yscale;    /* Format 2.14 */
            //    } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) {
            //        F2Dot14  xscale;    /* Format 2.14 */
            //        F2Dot14  scale01;   /* Format 2.14 */
            //        F2Dot14  scale10;   /* Format 2.14 */
            //        F2Dot14  yscale;    /* Format 2.14 */
            //    }
            //} while ( flags & MORE_COMPONENTS )
            //if (flags & WE_HAVE_INSTR){
            //    USHORT numInstr
            //    BYTE instr[numInstr]
            //------------------------------------------------------------


            return(finalGlyph ?? TtfGlyph.Empty);
        }
コード例 #4
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
            //----------------------------------------------
        }