public void NewWrappedLinesShouldNotStartOrEndWithWhiteSpace(string text, HorizontalAlignment horizontalAlignment)
        {
            Font font = CreateFont("\t x");

            var r = new GlyphRenderer();

            IReadOnlyList <GlyphLayout> layout = new TextLayout().GenerateLayout(text.AsSpan(), new TextOptions(new Font(font, 30))
            {
                WrappingLength      = 350,
                HorizontalAlignment = horizontalAlignment
            });

            float lineYPos = layout[0].Location.Y;

            for (int i = 0; i < layout.Count; i++)
            {
                GlyphLayout glyph = layout[i];
                if (lineYPos != glyph.Location.Y)
                {
                    Assert.False(glyph.IsWhiteSpace());
                    Assert.False(layout[i - 1].IsWhiteSpace());
                    lineYPos = glyph.Location.Y;
                }
            }
        }
예제 #2
0
        public ColorTypeface(string name)
        {
            m_gtf = GetGlyphTypeface(first_candidate: name);
            if (m_gtf == null)
            {
                return;
            }

            // Read the actual font data using Typography.OpenFont
            using (var s = m_gtf.GetFontStream())
            {
                var r = new OpenFontReader();
                m_openfont = r.Read(s, 0, ReadFlags.Full);
            }

            // Create a reusable layout for glyphs
            m_layout = new GlyphLayout()
            {
                Typeface = m_openfont,
                EnableBuiltinMathItalicCorrection = false, // not needed
                EnableComposition = true,
                EnableGpos        = true,
                EnableGsub        = true,
                EnableLigature    = true,
                PositionTechnique = PositionTechnique.OpenFont,
            };

            // Cache the glyph index for the zero-width joiner
            foreach (var g in StringToGlyphLayout("\u200d", use_gpos: false))
            {
                m_zwj_glyph = g.glyphIndex;
            }
        }
예제 #3
0
        public void NewWrappedLinesShouldNotStartOrEndWithWhiteSpace(string text, HorizontalAlignment horiAlignment)
        {
            var font = CreateFont("\t x");

            GlyphRenderer r = new GlyphRenderer();

            ImmutableArray <GlyphLayout> layout = new TextLayout().GenerateLayout(text, new RendererOptions(new Font(font, 30), 72)
            {
                WrappingWidth       = 350,
                HorizontalAlignment = horiAlignment
            });

            float lineYPos = layout[0].Location.Y;

            for (int i = 0; i < layout.Length; i++)
            {
                GlyphLayout glyph = layout[i];
                if (lineYPos != glyph.Location.Y)
                {
                    Assert.Equal(false, glyph.IsWhiteSpace);
                    Assert.Equal(false, layout[i - 1].IsWhiteSpace);
                    lineYPos = glyph.Location.Y;
                }
            }
        }
예제 #4
0
        public GlyphPlanSequence Layout(GlyphLayout glyphLayout, TextBuffer buffer, int startAt, int len)
        {
            //this func get the raw char from buffer
            //and create glyph list
            //check if we have the string cache in specific value
            //---------
            if (len > _glyphPlanSeqSet.MaxCacheLen)
            {
                //layout string is too long to be cache
                //it need to split into small buffer
            }

            GlyphPlanSequence planSeq = GlyphPlanSequence.Empty;

            GlyphPlanSeqCollection seqCol = _glyphPlanSeqSet.GetSeqCollectionOrCreateIfNotExist(len);
            int hashValue = CalculateHash(buffer, startAt, len);

            if (!seqCol.TryGetCacheGlyphPlanSeq(hashValue, out planSeq))
            {
                ////not found then create glyph plan seq
                //bool useOutputScale = glyphLayout.UsePxScaleOnReadOutput;

                ////save
                //some font may have 'special' glyph x,y at some font size(eg. for subpixel-rendering position)
                //but in general we store the new glyph plan seq with unscale glyph pos
                //glyphLayout.UsePxScaleOnReadOutput = false;
                planSeq = CreateGlyphPlanSeq(glyphLayout, buffer, startAt, len);
                //glyphLayout.UsePxScaleOnReadOutput = useOutputScale;//restore
                seqCol.Register(hashValue, planSeq);
            }
            //---
            //on unscale font=> we use original
            return(planSeq);
        }
예제 #5
0
 public OpenFontIFonts()
 {
     typefaceStore = new TypefaceStore();
     typefaceStore.FontCollection = InstalledFontCollection.GetSharedFontCollection(null);
     glyphLayout            = new GlyphLayout(); //create glyph layout with default value
     userGlyphPlanList      = new GlyphPlanList();
     userCharToGlyphMapList = new List <UserCharToGlyphIndexMap>();
 }
예제 #6
0
 public static void GenerateGlyphPlans(this GlyphLayout glyphLayout,
                                       char[] textBuffer,
                                       int startAt,
                                       int len,
                                       UnscaledGlyphPlanList list)
 {
     //generate glyph plan based on its current setting
     glyphLayout.Layout(textBuffer, startAt, len);
     ReadOutput(glyphLayout, list);
 }
예제 #7
0
        /// <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;
            }
        }
예제 #8
0
        private void Init(string name)
        {
            // Get a GlyphTypeface either from a system typeface or from a
            // file path.
            if (name != null)
            {
                m_gtf = GetGlyphTypeface(name);
            }

            // If not found, look for other possible emoji fonts such as
            // the Firefox one. Fall back to Arial, a font available since
            // Windows 3.1 \o/
            foreach (var f in m_fallback_fonts)
            {
                m_gtf = m_gtf ?? GetGlyphTypeface(f);
            }

            // Read the actual font data using Typography.OpenFont
            using (var s = m_gtf.GetFontStream())
            {
                var r = new Typography.OpenFont.OpenFontReader();
                m_openfont = r.Read(s, Typography.OpenFont.ReadFlags.Full);
            }

            // Create a layout for glyphs
            m_layout                   = new GlyphLayout();
            m_layout.ScriptLang        = ScriptLangs.Default;
            m_layout.Typeface          = m_openfont;
            m_layout.PositionTechnique = PositionTechnique.OpenFont;
            m_layout.FontSizeInPoints  = 0.75f; // 1 pixel

#if FALSE                                       // debug stuff
            var font = m_openfont;

            GlyphIndexList gl = new GlyphIndexList();

            gl.Add(font.LookupIndex(0x1f431)); // U+1F431 CAT FACE
            gl.Add(font.LookupIndex(0x200d));  //  U+200D ZERO WIDTH JOINER
            gl.Add(font.LookupIndex(0x1f453)); // U+1F453 EYEGLASSES

            //gl.Add(font.LookupIndex(0x1f46a)); // U+1F46A FAMILY
            //gl.Add(font.LookupIndex(0x1f3fe)); // U+1F3FE EMOJI MODIFIER FITZPATRICK TYPE-5

            foreach (var lookup_table in font.GSUBTable.LookupList)
            {
                lookup_table.DoSubstitution(gl, 0, gl.Count);
            }
#endif
        }
예제 #9
0
        public virtual void GenerateGlyphPlan(
            char[] textBuffer,
            int startAt,
            int len,
            GlyphPlanList outputGlyphPlanList,
            List <UserCodePointToGlyphIndex> charToGlyphMapList)
        {
            GlyphLayout glyphLayout = this.GlyphLayoutMan;

            glyphLayout.Layout(textBuffer, startAt, len);

            GlyphLayoutExtensions.GenerateGlyphPlans(
                glyphLayout.ResultUnscaledGlyphPositions,
                this.Typeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints),
                false, outputGlyphPlanList);
        }
예제 #10
0
        GlyphPlanSequence CreateGlyphPlanSeq(GlyphLayout glyphLayout, TextBuffer buffer, int startAt, int len)
        {
            GlyphPlanList planList  = GlyphPlanBuffer.UnsafeGetGlyphPlanList(_glyphPlanBuffer);
            int           pre_count = planList.Count;

            glyphLayout.Typeface   = _typeface;
            glyphLayout.ScriptLang = _scLang;
            glyphLayout.Layout(
                TextBuffer.UnsafeGetCharBuffer(buffer),
                startAt,
                len);


            int post_count = planList.Count;

            return(new GlyphPlanSequence(_glyphPlanBuffer, pre_count, post_count - pre_count));
        }
예제 #11
0
        public ColorTypeface(string name)
        {
            m_gtf = GetGlyphTypeface(first_candidate: name);
            if (m_gtf == null)
            {
                return;
            }

            // Read the actual font data using Typography.OpenFont
            using (var s = m_gtf.GetFontStream())
            {
                var r = new Typography.OpenFont.OpenFontReader();
                m_openfont = r.Read(s, 0, Typography.OpenFont.ReadFlags.Full);
            }

            // Create a layout for glyphs
            m_layout                   = new GlyphLayout();
            m_layout.ScriptLang        = ScriptLangs.Default;
            m_layout.Typeface          = m_openfont;
            m_layout.PositionTechnique = PositionTechnique.OpenFont;
        }
예제 #12
0
        private void Init(string name)
        {
            m_gtf = GetGlyphTypeface(first_candidate: name);
            if (m_gtf == null)
            {
                return;
            }

            // Read the actual font data using Typography.OpenFont
            using (var s = m_gtf.GetFontStream())
            {
                var r = new Typography.OpenFont.OpenFontReader();
                m_openfont = r.Read(s, Typography.OpenFont.ReadFlags.Full);
            }

            // Create a layout for glyphs
            m_layout                   = new GlyphLayout();
            m_layout.ScriptLang        = ScriptLangs.Default;
            m_layout.Typeface          = m_openfont;
            m_layout.PositionTechnique = PositionTechnique.OpenFont;

#if FALSE // debug stuff
            var font = m_openfont;

            GlyphIndexList gl = new GlyphIndexList();

            gl.Add(font.LookupIndex(0x1f431)); // U+1F431 CAT FACE
            gl.Add(font.LookupIndex(0x200d));  //  U+200D ZERO WIDTH JOINER
            gl.Add(font.LookupIndex(0x1f453)); // U+1F453 EYEGLASSES

            //gl.Add(font.LookupIndex(0x1f46a)); // U+1F46A FAMILY
            //gl.Add(font.LookupIndex(0x1f3fe)); // U+1F3FE EMOJI MODIFIER FITZPATRICK TYPE-5

            foreach (var lookup_table in font.GSUBTable.LookupList)
            {
                lookup_table.DoSubstitution(gl, 0, gl.Count);
            }
#endif
        }
예제 #13
0
        private void WriteFont(SWFFont font, int fid)
        {
            WriteBuffer fontTag = this.OpenTag(Tag.DefineFont3, font.Name + "; id=" + fid);

            char[] codes = font.CodePoints;

            /* Tag.DefineFont3 */
            {
                fontTag.WriteUI16((uint)fid);

                fontTag.WriteBit(font.HasLayout);

                fontTag.WriteBit(false); /* ISSUE 50: ShiftJIS support */
                fontTag.WriteBit(font.IsSmall);
                fontTag.WriteBit(false); /* ISSUE 51: ANSI support, though I think this might never be false. */

                fontTag.WriteBit(true);  /* ISSUE 52: We always write wide offsets. This is because we're too lazy to measure our table. */
                fontTag.WriteBit(true);  /* Spec says must be true. */

                fontTag.WriteBit(font.IsItalic);
                fontTag.WriteBit(font.IsBold);

                fontTag.WriteUI8((uint)font.LanguageCode);

                fontTag.WriteString(font.Name, true);

                fontTag.WriteUI16((uint)font.GlyphCount);

                byte[][] shapeData       = new byte[font.GlyphCount][];
                int      totalShapeBytes = 0;
                for (int i = 0; i < font.GlyphCount; i++)
                {
                    Tag format;
                    shapeData[i] = ShapeWriter.ShapeToBytes(font.GetGlyphShape(codes[i]), out format);

                    if (format != Tag.DefineFont3)
                    {
                        throw new SWFModellerException(SWFModellerError.Internal, "Can't write non-font shapes as glyphs");
                    }

                    totalShapeBytes += shapeData[i].Length;
                }

                int startOffset = font.GlyphCount * 4 + 4; /* 4 bytes per offset (wide offsets) + 4 for the code table offset */
                int nextOffset  = startOffset;
                foreach (byte[] shapeBytes in shapeData)
                {
                    fontTag.WriteUI32((uint)nextOffset);
                    nextOffset += shapeBytes.Length;
                }

                fontTag.WriteUI32((uint)(startOffset + totalShapeBytes));

                foreach (byte[] shapeBytes in shapeData)
                {
                    fontTag.WriteBytes(shapeBytes);
                }

                foreach (char code in codes)
                {
                    fontTag.WriteUI16((uint)code);
                }

                if (font.HasLayout)
                {
                    fontTag.WriteSI16(font.Ascent.Value);
                    fontTag.WriteSI16(font.Descent.Value);
                    fontTag.WriteSI16(font.Leading.Value);

                    Rect[] bounds    = new Rect[font.GlyphCount];
                    int    boundsPos = 0;
                    foreach (char c in codes)
                    {
                        GlyphLayout gl = font.GetLayout(c);
                        fontTag.WriteSI16(gl.Advance);
                        bounds[boundsPos++] = gl.Bounds;
                    }

                    foreach (Rect bound in bounds)
                    {
                        fontTag.WriteRect(bound);
                        fontTag.Align8();
                    }

                    fontTag.WriteUI16((uint)font.KerningTable.Length);
                    foreach (KerningPair kern in font.KerningTable)
                    {
                        fontTag.WriteUI16(kern.LeftChar);
                        fontTag.WriteUI16(kern.RightChar);
                        fontTag.WriteSI16(kern.Adjustment);
                    }
                }
            }

            this.CloseTag();

            if (font.HasPixelAlignment)
            {
                WriteBuffer zonesTag = this.OpenTag(Tag.DefineFontAlignZones, font.Name + "; id=" + fid);

                zonesTag.WriteUI16((uint)fid);

                if (font.ThicknessHint == null)
                {
                    throw new SWFModellerException(SWFModellerError.Internal, "Can't have pixel aligmnent without a font thickness hint.");
                }

                zonesTag.WriteUBits((uint)font.ThicknessHint, 2);
                zonesTag.WriteUBits(0, 6); /* Reserved */

                foreach (char c in codes)
                {
                    PixelAlignment pa = font.GetPixelAligment(c);

                    if (pa.ZoneInfo.Length != 2)
                    {
                        throw new SWFModellerException(SWFModellerError.Internal, "Pixel aligment should always have 2 zones.");
                    }

                    zonesTag.WriteUI8((uint)pa.ZoneInfo.Length);

                    foreach (PixelAlignment.ZoneData zi in pa.ZoneInfo)
                    {
                        /* These int values are just unparsed 16-bit floats. */
                        zonesTag.WriteUI16((uint)zi.AlignmentCoord);
                        zonesTag.WriteUI16((uint)zi.Range);
                    }

                    zonesTag.WriteUBits(0, 6); /* Reserved */
                    zonesTag.WriteBit(pa.HasY);
                    zonesTag.WriteBit(pa.HasX);
                }

                this.CloseTag();
            }

            if (font.HasExtraNameInfo)
            {
                WriteBuffer nameTag = this.OpenTag(Tag.DefineFontName, font.FullName + "; id=" + fid);

                nameTag.WriteUI16((uint)fid);
                nameTag.WriteString(font.FullName);
                nameTag.WriteString(font.Copyright);

                this.CloseTag();
            }
        }
 private static void AddGlyph(Dictionary <char, GlyphLayout> glyphDict, GlyphLayout glyph)
 {
     glyphDict.Add(glyph.Character, glyph);
 }
예제 #15
0
 internal TextShapingService(TextServiceHub hub)
 {
     this._hub = hub;
     //create glyph layout instance with default setting
     _glyphLayout = new GlyphLayout();
 }
예제 #16
0
        private void button3_Click(object sender, EventArgs e)
        {
            //it should be faster if we use 'mesh' cache
            //instead of read-transform it every time like code above(button2_click)

            LoadFont();

            float font_size_in_Point = 20;

            _glyphMeshStore.SetFont(_latinModernMathFont, font_size_in_Point);//20= font size
            _glyphMeshStore.FlipGlyphUpward = true;

            float px_scale = _latinModernMathFont.CalculateScaleToPixelFromPointSize(font_size_in_Point);

            using (Tools.BorrowAggPainter(_memBmp, out var p))
            {
                p.Clear(PixelFarm.Drawing.Color.White);

                float prevX = p.OriginX;
                float prevY = p.OriginY;


                int line_left = 10;
                int line_top  = 50;

                p.SetOrigin(line_left, line_top);//*** test

                //draw reference point
                p.FillRect(0, 0, 5, 5, PixelFarm.Drawing.Color.Red);

                char[] test_str    = "‽_x‾".ToCharArray();
                int    inline_left = 0;
                int    inline_top  = 0;

                //----------
                GlyphLayout glyphLayout = new GlyphLayout();
                glyphLayout.ScriptLang = new ScriptLang("math");
                glyphLayout.Typeface   = _latinModernMathFont;


                //temp fix for some typeface

                glyphLayout.SetGlyphIndexNotFoundHandler((glyph_layout, codepoint, next_codepoint) =>
                {
                    switch (codepoint)
                    {
                    //overline unicode
                    case 8254: return(2246);    //overline-combine, this will break into 3 parts in math layout process
                    }
                    return(0);
                });


                //
                glyphLayout.Layout(test_str, 0, test_str.Length);

                List <UnscaledGlyphPlan> glyphPlans = new List <UnscaledGlyphPlan>();

                foreach (UnscaledGlyphPlan glypyPlan in glyphLayout.GetUnscaledGlyphPlanIter())
                {
                    glyphPlans.Add(glypyPlan);
                }
                //--------
                for (int i = 0; i < glyphPlans.Count; ++i)
                {
                    //ushort glyphIndex = _latinModernMathFont.GetGlyphIndex((int)test_str[i]);
                    ////do some glyph-substitution
                    //ushort advW = _latinModernMathFont.GetAdvanceWidth((int)test_str[i]);//unscale glyph width
                    //now scale it to specific font size

                    UnscaledGlyphPlan glyphPlan = glyphPlans[i];
                    int         advW_s          = (int)System.Math.Round(px_scale * glyphPlan.AdvanceX);
                    VertexStore v1 = _glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex);
                    p.SetOrigin(line_left + inline_left, line_top + inline_top);
                    p.Fill(v1, PixelFarm.Drawing.Color.Black);
                    inline_left += advW_s;//move
                }
                //restore
                p.SetOrigin(prevX, prevY);
            }

            //-----------
            CopyBitmapToScreen();
        }
예제 #17
0
 public TextServices()
 {
     typefaceStore = new TypefaceStore();
     typefaceStore.FontCollection = InstalledFontCollection.GetSharedFontCollection(null);
     _glyphLayout = new GlyphLayout();
 }
예제 #18
0
        /// <summary>
        /// Renders the glyph to the configured rasterizer.
        /// </summary>
        /// <param name="glyphLayout">The glyph layout.</param>
        /// <param name="scalingFactor">The scaling factor.</param>
        internal void RenderGlyph(GlyphLayout glyphLayout, int scalingFactor)
        {
            int   x     = glyphLayout.TopLeft.X;
            int   y     = glyphLayout.TopLeft.Y;
            Glyph glyph = glyphLayout.glyph;

            var rasterizer = new ToPixelRasterizer(x, y, scalingFactor, FontToPixelDivisor, _rasterizer);

            ushort[] contours = glyph.EndPoints;
            short[]  xs       = glyph.X;
            short[]  ys       = glyph.Y;
            bool[]   onCurves = glyph.On;

            int npoints      = xs.Length;
            int startContour = 0;
            int cpoint_index = 0;

            rasterizer.BeginRead(contours.Length);

            int lastMoveX = 0;
            int lastMoveY = 0;

            int controlPointCount = 0;

            for (int i = 0; i < contours.Length; i++)
            {
                int         nextContour        = contours[startContour] + 1;
                bool        isFirstPoint       = true;
                Point <int> secondControlPoint = new Point <int>();
                Point <int> thirdControlPoint  = new Point <int>();
                bool        justFromCurveMode  = false;

                for (; cpoint_index < nextContour; ++cpoint_index)
                {
                    short vpoint_x = xs[cpoint_index];
                    short vpoint_y = ys[cpoint_index];
                    if (onCurves[cpoint_index])
                    {
                        //on curve
                        if (justFromCurveMode)
                        {
                            switch (controlPointCount)
                            {
                            case 1:
                            {
                                rasterizer.Curve3(
                                    secondControlPoint.x,
                                    secondControlPoint.y,
                                    vpoint_x,
                                    vpoint_y);
                            }
                            break;

                            case 2:
                            {
                                rasterizer.Curve4(
                                    secondControlPoint.x, secondControlPoint.y,
                                    thirdControlPoint.x, thirdControlPoint.y,
                                    vpoint_x, vpoint_y);
                            }
                            break;

                            default:
                            {
                                throw new NotSupportedException();
                            }
                            }
                            controlPointCount = 0;
                            justFromCurveMode = false;
                        }
                        else
                        {
                            if (isFirstPoint)
                            {
                                isFirstPoint = false;
                                lastMoveX    = vpoint_x;
                                lastMoveY    = vpoint_y;
                                rasterizer.MoveTo(lastMoveX, lastMoveY);
                            }
                            else
                            {
                                rasterizer.LineTo(vpoint_x, vpoint_y);
                            }
                        }
                    }
                    else
                    {
                        switch (controlPointCount)
                        {
                        case 0:
                        {
                            secondControlPoint = new Point <int>(vpoint_x, vpoint_y);
                        }
                        break;

                        case 1:
                        {
                            //we already have prev second control point
                            //so auto calculate line to
                            //between 2 point
                            Point <int> mid = GetMidPoint(secondControlPoint, vpoint_x, vpoint_y);
                            //----------
                            //generate curve3
                            rasterizer.Curve3(
                                secondControlPoint.x, secondControlPoint.y,
                                mid.x, mid.y);
                            //------------------------
                            controlPointCount--;
                            //------------------------
                            //printf("[%d] bzc2nd,  x: %d,y:%d \n", mm, vpoint.x, vpoint.y);
                            secondControlPoint = new Point <int>(vpoint_x, vpoint_y);
                        }
                        break;

                        default:
                        {
                            throw new NotSupportedException("Too many control points");
                        }
                        }

                        controlPointCount++;
                        justFromCurveMode = true;
                    }
                }
                //--------
                //close figure
                //if in curve mode
                if (justFromCurveMode)
                {
                    switch (controlPointCount)
                    {
                    case 0: break;

                    case 1:
                    {
                        rasterizer.Curve3(
                            secondControlPoint.x, secondControlPoint.y,
                            lastMoveX, lastMoveY);
                    }
                    break;

                    case 2:
                    {
                        rasterizer.Curve4(
                            secondControlPoint.x, secondControlPoint.y,
                            thirdControlPoint.x, thirdControlPoint.y,
                            lastMoveX, lastMoveY);
                    }
                    break;

                    default:
                    { throw new NotSupportedException("Too many control points"); }
                    }
                    justFromCurveMode = false;
                    controlPointCount = 0;
                }
                rasterizer.CloseFigure();
                //--------
                startContour++;
            }
            rasterizer.EndRead();
        }
예제 #19
0
        private void ReadFont(Tag fontType)
        {
            int fontID = this.sdtr.ReadUI16();

            /* Bunch of flags */
            bool hasLayout     = this.sdtr.ReadBit();
            bool isShiftJIS    = this.sdtr.ReadBit();
            bool isSmallText   = this.sdtr.ReadBit();
            bool isANSI        = this.sdtr.ReadBit();
            bool isWideOffsets = this.sdtr.ReadBit();
            bool isWideCodes   = this.sdtr.ReadBit();
            bool isItalic      = this.sdtr.ReadBit();
            bool isBold        = this.sdtr.ReadBit();

            if (!isWideCodes)
            {
                throw new SWFModellerException(SWFModellerError.SWFParsing,
                                               "Non-wide codes in font encodings are not valid.", swf.Context);
            }

            if (isShiftJIS)
            {
                /* ISSUE 50 */
                throw new SWFModellerException(SWFModellerError.UnimplementedFeature,
                                               "ShiftJIS character encoding is not supported.", swf.Context);
            }

            int    language  = this.sdtr.ReadUI8();
            string name      = this.sdtr.ReadLengthedUTF8(this.sdtr.ReadUI8());
            int    numGlyphs = this.sdtr.ReadUI16();

#if DEBUG
            this.Log("id=" + fontID + ", name=" + name);
#endif

            SWFFont font = new SWFFont(
                (SWFFont.Language)language,
                name,
                isBold,
                isItalic,
                isSmallText,
                numGlyphs);

            int startOffset = (int)this.sdtr.Offset; /* The offset table measures from this point. */

            int[] shapeOffsets = new int[numGlyphs];
            for (int i = 0; i < numGlyphs; i++)
            {
                shapeOffsets[i] = isWideOffsets ? (int)this.sdtr.ReadUI32() : this.sdtr.ReadUI16();
            }

            int codeTableOffset = isWideOffsets ? (int)this.sdtr.ReadUI32() : this.sdtr.ReadUI16();

            IShape[] shapes = new IShape[numGlyphs];

            for (int i = 0; i < numGlyphs; i++)
            {
                int shapeOffset = (int)sdtr.Offset - startOffset;
                if (shapeOffsets[i] != shapeOffset)
                {
                    throw new SWFModellerException(SWFModellerError.SWFParsing, "Bad font data.", swf.Context);
                }

                int end = codeTableOffset;
                if (i < numGlyphs - 1)
                {
                    end = shapeOffsets[i + 1];
                }

                int len = end - shapeOffset;

                byte[] shapeData = this.sdtr.ReadByteBlock(len);

                shapes[i] = new ShapeParser().Parse(fontType, shapeData, this);
            }

            char[] codes = new char[numGlyphs];

            for (int i = 0; i < numGlyphs; i++)
            {
                codes[i] = (char)this.sdtr.ReadUI16();
                font.AddGlyph(codes[i], shapes[i]);
            }


            if (hasLayout)
            {
                font.Ascent  = this.sdtr.ReadSI16();
                font.Descent = this.sdtr.ReadSI16();
                font.Leading = this.sdtr.ReadSI16();

                GlyphLayout[] layouts = new GlyphLayout[numGlyphs];

                for (int i = 0; i < numGlyphs; i++)
                {
                    layouts[i] = new GlyphLayout()
                    {
                        Advance = this.sdtr.ReadSI16()
                    };
                }

                for (int i = 0; i < numGlyphs; i++)
                {
                    layouts[i].Bounds = this.sdtr.ReadRect();
                    font.AddLayout(codes[i], layouts[i]);
                }

                int           kerningCount = this.sdtr.ReadUI16();
                KerningPair[] kernTable    = new KerningPair[kerningCount];

                for (int i = 0; i < kerningCount; i++)
                {
                    kernTable[i] = new KerningPair()
                    {
                        LeftChar   = (char)(isWideCodes ? this.sdtr.ReadUI16() : this.sdtr.ReadUI8()),
                        RightChar  = (char)(isWideCodes ? this.sdtr.ReadUI16() : this.sdtr.ReadUI8()),
                        Adjustment = this.sdtr.ReadSI16()
                    };
                }

                font.KerningTable = kernTable;
            }

            fontDict.Add(fontID, font);
            swf.AddFont(font);
        }
예제 #20
0
        void Issue118(PaintEventArgs e)
        {
            Text = "Issue 118 Demo";
            const string s = "0123456789";
            const float  z = 80;
            const bool   f = true;
            var          m = GetType().Assembly;
            var          t = new OpenFontReader().Read
                                 (m.GetManifestResourceStream
                                     (Array.Find(m.GetManifestResourceNames(), n => n.EndsWith("otf"))));

            t.UpdateAllCffGlyphBounds();
            var c = t.CalculateScaleToPixelFromPointSize(z);
            var l = new GlyphLayout {
                Typeface = t
            };
            var q = new GlyphLayout {
                Typeface = t
            };

            l.Layout(s.ToCharArray(), 0, s.Length);
            var        p = l.ResultUnscaledGlyphPositions;
            var        b = new B(t);
            var        r = new SampleWinForms.GlyphTranslatorToGdiPath();
            var        h = Pens.Black.Brush;
            var        u = Pens.Blue;
            var        v = Pens.Red;
            const bool _ = true;
            var        j = true;

            using (var g = e.Graphics)
            {
                if (f)
                {
                    g.ScaleTransform(1, -1);
                    g.TranslateTransform(0, -Height / 2);
                }
                for (var i = 0; i < s.Length; i++, j ^= true)
                {
                    var o = q.LayoutAndMeasureString(new[] { s[i] }, 0, 1, z);
                    var n = p.GetGlyph(i, out var x, out var y, out var w);
                    var a = g.Save();
                    var d = t.GetGlyphByIndex(n).Bounds;
                    var k = R.FromLTRB(d.XMin * c, d.YMin * c, d.XMax * c, d.YMax * c);
                    g.TranslateTransform(x * c, y * c);
                    b.Build(s[i], z);
                    b.ReadShapes(r);
                    r.ResultGraphicsPath.CloseFigure();
                    g.FillPath(h, r.ResultGraphicsPath);
                    if (_ || j)
                    {
                        g.DrawRectangle(u, 0, 0, o.width, o.ascending - o.descending);
                    }
                    if (_ || !j)
                    {
                        g.DrawRectangle(v, k.X, k.Y, k.Width, k.Height);
                    }
                    g.Restore(a);
                    g.TranslateTransform(w * c, 0);
                }

                g.ResetTransform();
                g.DrawString("Blue = LayoutAndMeasureString, Red = Glyph.Bounds", Font, h, 0, 0);
            }
        }