示例#1
0
        void InternalDrawString(char[] textBuffer, int startAt, int len, float x, float y)
        {
            UpdateGlyphLayoutSettings();
            //unscale layout, with design unit scale
            _glyphLayout.Layout(textBuffer, startAt, len);
            //
            //
            _outputGlyphPlans.Clear();
            //
            if (this._pxScaleEngine != null)
            {
                //scale to specific font size
                _pxScaleEngine.Layout(_glyphLayout.ResultUnscaledGlyphPositions, _outputGlyphPlans);
            }
            else
            {
                //no custom engine
                //then use default scale
                GlyphLayoutExtensions.GenerateGlyphPlan(
                    _glyphLayout.ResultUnscaledGlyphPositions,
                    _currentFontSizePxScale,
                    false,
                    _outputGlyphPlans);
            }

            DrawFromGlyphPlans(_outputGlyphPlans, x, y);
        }
示例#2
0
        public MeasuredStringBox MeasureString(char[] textBuffer, int startAt, int len)
        {
            //1. update
            UpdateGlyphLayoutSettings();

            //2. unscale layout, in design unit
            this._glyphLayout.Layout(textBuffer, startAt, len);

            //3. scale  to specific font size
            _outputGlyphPlans.Clear();

            GlyphLayoutExtensions.GenerateGlyphPlan(
                _glyphLayout.ResultUnscaledGlyphPositions,
                _currentTypeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints),
                false,
                _outputGlyphPlans);
            //
            float pxscale = this.Typeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints);

            return(new MeasuredStringBox(
                       _outputGlyphPlans.AccumAdvanceX * pxscale,
                       _currentTypeface.Ascender * pxscale,
                       _currentTypeface.Descender * pxscale,
                       _currentTypeface.LineGap * pxscale,
                       Typography.OpenFont.Extensions.TypefaceExtensions.CalculateRecommendLineSpacing(_currentTypeface) * pxscale));
        }
示例#3
0
        public void MeasureString(char[] str, int startAt, int len, int limitWidth, out int charFit, out int charFitWidth)
        {
            //measure string
            if (str.Length < 1)
            {
                charFitWidth = 0;
            }

            _reusableMeasureBoxList.Clear(); //reset

            float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(_fontSizeInPts);
            //NOET:at this moment, simple operation
            //may not be simple...
            //-------------------
            //input string may contain more than 1 script lang
            //user can parse it by other parser
            //but in this code, we use our Typography' parser
            //-------------------
            //user must setup the CustomBreakerBuilder before use

            int   cur_startAt = startAt;
            float accumW      = 0;

            foreach (BreakSpan breakSpan in BreakToLineSegments(str, startAt, len))
            {
                //measure string at specific px scale
                _glyphLayout.Layout(str, breakSpan.startAt, breakSpan.len);
                //
                _reusableGlyphPlanList.Clear();
                GlyphLayoutExtensions.GenerateGlyphPlans(
                    _glyphLayout.ResultUnscaledGlyphPositions,
                    pxscale,
                    true,
                    _reusableGlyphPlanList);
                //measure each glyph
                //limit at specific width
                int glyphCount = _reusableGlyphPlanList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    GlyphPlan glyphPlan = _reusableGlyphPlanList[i];
                    float     right     = glyphPlan.ExactRight * pxscale;
                    if (right >= accumW)
                    {
                        //stop here at this glyph
                        charFit = i - 1;
                        //TODO: review this
                        charFitWidth = (int)System.Math.Round(accumW);
                        return;
                    }
                    else
                    {
                        accumW = right;
                    }
                }
            }

            charFit      = 0;
            charFitWidth = 0;
        }
示例#4
0
        public GlyphPlanList StringToGlyphPlanList(string s, double font_size)
        {
            GlyphPlanList l = new GlyphPlanList();

            m_layout.Layout(s.ToCharArray(), 0, s.Length);
            var scale = m_openfont.CalculateScaleToPixelFromPointSize((float)font_size);

            GlyphLayoutExtensions.GenerateGlyphPlan(m_layout.ResultUnscaledGlyphPositions, scale,
                                                    snapToGrid: true, outputGlyphPlanList: l);
            return(l);
        }
示例#5
0
 public virtual void GenerateGlyphPlan(
     char[] textBuffer,
     int startAt,
     int len,
     GlyphPlanList outputGlyphPlanList,
     List <UserCharToGlyphIndexMap> charToGlyphMapList)
 {
     this.GlyphLayoutMan.Layout(textBuffer, startAt, len);
     GlyphLayoutExtensions.GenerateGlyphPlan(this.GlyphLayoutMan.ResultUnscaledGlyphPositions,
                                             this.Typeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints),
                                             false, outputGlyphPlanList);
 }
示例#6
0
        public void MeasureString(char[] str, int startAt, int len, out int w, out int h)
        {
            //measure string
            //check if we use cache feature or not

            if (str.Length < 1)
            {
                w = h = 0;
            }
            _reusableMeasureBoxList.Clear(); //reset

            float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(_fontSizeInPts);
            //NOET:at this moment, simple operation
            //may not be simple...
            //-------------------
            //input string may contain more than 1 script lang
            //user can parse it by other parser
            //but in this code, we use our Typography' parser
            //-------------------
            //user must setup the CustomBreakerBuilder before use

            int   cur_startAt = startAt;
            float accumW      = 0;
            float accumH      = 0;

            foreach (BreakSpan breakSpan in BreakToLineSegments(str, startAt, len))
            {
                _glyphLayout.Layout(str, breakSpan.startAt, breakSpan.len);
                //
                _reusableGlyphPlanList.Clear();
                GlyphLayoutExtensions.GenerateGlyphPlans(
                    _glyphLayout.ResultUnscaledGlyphPositions,
                    pxscale,
                    true,
                    _reusableGlyphPlanList);
                //measure string size
                var result = new MeasuredStringBox(
                    _reusableGlyphPlanList.AccumAdvanceX * pxscale,
                    _currentTypeface.Ascender * pxscale,
                    _currentTypeface.Descender * pxscale,
                    _currentTypeface.LineGap * pxscale,
                    Typography.OpenFont.Extensions.TypefaceExtensions.CalculateRecommendLineSpacing(_currentTypeface) * pxscale);
                //
                ConcatMeasureBox(ref accumW, ref accumH, ref result);
            }

            w = (int)System.Math.Round(accumW);
            h = (int)System.Math.Round(accumH);
        }
示例#7
0
        GlyphPlanList _outputGlyphPlans = new GlyphPlanList();//for internal use
        public override void DrawString(char[] textBuffer, int startAt, int len, float x, float y)
        {
            //1. update
            UpdateGlyphLayoutSettings();

            //2. unscale layout, in design unit
            this._glyphLayout.Layout(textBuffer, startAt, len);

            //3. scale  to specific font size
            _outputGlyphPlans.Clear();

            GlyphLayoutExtensions.GenerateGlyphPlan(
                _glyphLayout.ResultUnscaledGlyphPositions,
                _currentTypeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints),
                false,
                _outputGlyphPlans);

            DrawFromGlyphPlans(_outputGlyphPlans, x, y);
        }
示例#8
0
        public MeasuredStringBox Measure(char[] textBuffer, int startAt, int len)
        {
            glyphLayout.Typeface = this.CurrentTypeFace;
            float pxscale = CurrentTypeFace.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints);

            glyphLayout.Layout(textBuffer, startAt, len);

            _reusableGlyphPlanList.Clear();
            IGlyphPositions glyphPositions = glyphLayout.ResultUnscaledGlyphPositions;

            GlyphLayoutExtensions.GenerateGlyphPlan(glyphLayout.ResultUnscaledGlyphPositions,
                                                    pxscale,
                                                    false, _reusableGlyphPlanList);
            return(new MeasuredStringBox(
                       _reusableGlyphPlanList.AccumAdvanceX * pxscale,
                       CurrentTypeFace.Ascender * pxscale,
                       CurrentTypeFace.Descender * pxscale,
                       CurrentTypeFace.LineGap * pxscale,
                       Typography.OpenFont.Extensions.TypefaceExtensions.CalculateRecommendLineSpacing(CurrentTypeFace) * pxscale));
        }
示例#9
0
        public GlyphPlanSequence GetUnscaledGlyphPlanSequence(GlyphLayout glyphLayout,
                                                              TextBuffer buffer, int start, int seqLen)
        {
            //UNSCALED VERSION
            //use current typeface + scriptlang
            int seqHashValue = CalculateHash(buffer, start, seqLen);

            //this func get the raw char from buffer
            //and create glyph list
            //check if we have the string cache in specific value
            //---------
            if (seqLen > _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(seqLen);

            if (!seqCol.TryGetCacheGlyphPlanSeq(seqHashValue, out planSeq))
            {
                //create a new one if we don't has a cache
                //1. layout
                glyphLayout.Layout(
                    buffer.UnsafeGetInternalBuffer(),
                    start,
                    seqLen);

                int pre_count = _planList.Count;
                //create glyph-plan ( UnScaled version) and add it to planList
                GlyphLayoutExtensions.GenerateGlyphPlans(glyphLayout.ResultUnscaledGlyphPositions, 1, false, _planList);
                int post_count = _planList.Count;
                planSeq = new GlyphPlanSequence(_planList, pre_count, post_count - pre_count);
                //
                seqCol.Register(seqHashValue, planSeq);
            }
            return(planSeq);
        }
示例#10
0
        public override void DrawString(char[] textBuffer, int startAt, int len, float x, float y)
        {
            //----------------
            //TODO: use typography text service
            //it should be faster since it has glyph-plan cache
            //----------------

            //1. update
            UpdateGlyphLayoutSettings();

            //2. unscale layout, in design unit
            this._glyphLayout.Layout(textBuffer, startAt, len);

            //3. scale  to specific font size
            _resuableGlyphPlanList.Clear();

            GlyphLayoutExtensions.GenerateGlyphPlans(
                _glyphLayout.ResultUnscaledGlyphPositions,
                _currentTypeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints),
                false,
                _reusablePxScaleGlyphPlanList);

            DrawFromGlyphPlans(_resuableGlyphPlanList, x, y);
        }
        public void Layout(IGlyphPositions posStream, PxScaledGlyphPlanList outputGlyphPlanList)
        {
            float pxscale = _typeface.CalculateScaleToPixelFromPointSize(this._fontSizeInPoints);

            if (!UseWithLcdSubPixelRenderingTechnique)
            {
                //layout without fit to alignment direction
                GlyphLayoutExtensions.GenerateGlyphPlans(posStream, pxscale, false, outputGlyphPlanList);
                return; //early exit
            }
            //------------------------------
            int finalGlyphCount = posStream.Count;

#if DEBUG
            float dbug_onepx = 1 / pxscale;
#endif
            //
            int   cx = 0;
            short cy = 0;
            //
            //at this state, we need exact info at this specific pxscale
            //
            _glyphMeshStore.SetFont(_typeface, this._fontSizeInPoints);
            FineABC current_ABC = new FineABC();
            FineABC prev_ABC    = new FineABC();

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                short  input_offset, offsetX, offsetY, advW; //all from pen-pos
                ushort glyphIndex = posStream.GetGlyph(i, out input_offset, out offsetX, out offsetY, out advW);
                GlyphControlParameters controlPars = _glyphMeshStore.GetControlPars(glyphIndex);
                current_ABC.SetData(pxscale, controlPars, offsetX, offsetY, (ushort)advW);
                //-------------------------------------------------------------

                if (i > 0)
                {
                    //inter-glyph space
                    //ideal space
                    float ideal_space = prev_ABC.s_c + current_ABC.s_a;
                    //actual space
                    float actual_space = prev_ABC.m_c + current_ABC.m_a;

                    if (ideal_space < 0)
                    {
                        //f-f
                        //f-o
                        if (prev_ABC.s_c < 0)
                        {
                            ideal_space = 0 + current_ABC.s_a;
                        }
                        if (ideal_space < 0)
                        {
                            ideal_space = 0;
                        }
                    }
                    if (ideal_space >= 0)
                    {
                        //m-a
                        //i-i
                        //o-p
                        if (actual_space > 1.5 && actual_space - 0.5 > ideal_space)
                        {
                            cx--;
                        }
                        else
                        {
                            if (actual_space < ideal_space)
                            {
                                if (prev_ABC.final_advW + prev_ABC.m_c_adjust < prev_ABC.m_max)
                                {
                                    cx += current_ABC.m_a_adjust;
                                }
                            }
                            else
                            {
                                if (prev_ABC.final_advW - prev_ABC.m_c + prev_ABC.m_c_adjust > prev_ABC.m_max)
                                {
                                    cx += prev_ABC.m_c_adjust;
                                }
                            }
                        }
                    }
                    else
                    {
                        //this should not occur?
                    }
                }
                //-------------------------------------------------------------

                //TODO: review here again***


                float exact_x = (float)(cx + current_ABC.s_offsetX);
                float exact_y = (float)(cy + current_ABC.s_offsetY);

                //check if the current position can create a sharp glyph
                int   exact_x_floor   = (int)exact_x;
                float x_offset_to_fit = current_ABC.s_avg_x_ToFit;

                float final_x = exact_x_floor + x_offset_to_fit;
                if (UseWithLcdSubPixelRenderingTechnique)
                {
                    final_x += 0.33f;
                }

                outputGlyphPlanList.Append(new PxScaledGlyphPlan(
                                               input_offset,
                                               glyphIndex,
                                               (short)current_ABC.final_advW,
                                               (short)Math.Round(current_ABC.s_offsetX),
                                               (short)Math.Round(current_ABC.s_offsetY)
                                               ));
                //
                //
                cx += current_ABC.final_advW;
                //-----------------------------------------------
                prev_ABC = current_ABC;//copy current to prev
#if DEBUG
                prev_ABC.dbugIsPrev = true;
#endif
                // Console.WriteLine(exact_x + "+" + (x_offset_to_fit) + "=>" + final_x);
            }
        }
示例#12
0
        public void MeasureString(char[] str, int startAt, int len, int limitWidth, out int charFit, out int charFitWidth)
        {
            //measure string
            if (str.Length < 1)
            {
                charFitWidth = 0;
            }

            _reusableMeasureBoxList.Clear(); //reset

            float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(_fontSizeInPts);
            //NOET:at this moment, simple operation
            //may not be simple...
            //-------------------
            //input string may contain more than 1 script lang
            //user can parse it by other parser
            //but in this code, we use our Typography' parser
            //-------------------
            //user must setup the CustomBreakerBuilder before use

            int   cur_startAt = startAt;
            float accumW      = 0;

            foreach (BreakSpan breakSpan in BreakToLineSegments(str, startAt, len))
            {
                //measure string at specific px scale
                _glyphLayout.Layout(str, breakSpan.startAt, breakSpan.len);
                //

                _reusableScaledGlyphPlanList.Clear();
                GlyphLayoutExtensions.GenerateGlyphPlans(
                    _glyphLayout.ResultUnscaledGlyphPositions,
                    pxscale,
                    true,
                    _reusableScaledGlyphPlanList);
                //measure each glyph
                //limit at specific width
                int glyphCount = _reusableGlyphPlanList.Count;


                float acc_x = 0; //accum_x
                float acc_y = 0; //accum_y
                float g_x   = 0;
                float g_y   = 0;
                float x     = 0;
                float y     = 0;
                for (int i = 0; i < glyphCount; ++i)
                {
                    UnscaledGlyphPlan glyphPlan = _reusableGlyphPlanList[i];

                    float ngx = acc_x + (float)Math.Round(glyphPlan.OffsetX * pxscale);
                    float ngy = acc_y + (float)Math.Round(glyphPlan.OffsetY * pxscale);
                    //NOTE:
                    // -glyphData.TextureXOffset => restore to original pos
                    // -glyphData.TextureYOffset => restore to original pos
                    //--------------------------
                    g_x = (float)(x + (ngx)); //ideal x
                    g_y = (float)(y + (ngy));
                    float g_w = (float)Math.Round(glyphPlan.AdvanceX * pxscale);
                    acc_x += g_w;
                    //g_x = (float)Math.Round(g_x);
                    g_y = (float)Math.Floor(g_y);

                    float right = g_x + g_w;

                    if (right >= accumW)
                    {
                        //stop here at this glyph
                        charFit = i - 1;
                        //TODO: review this
                        charFitWidth = (int)System.Math.Round(accumW);
                        return;
                    }
                    else
                    {
                        accumW = right;
                    }
                }
            }

            charFit      = 0;
            charFitWidth = 0;
        }
示例#13
0
        /// <summary>
        /// generate glyph run into a given textRun
        /// </summary>
        /// <param name="outputTextRun"></param>
        /// <param name="charBuffer"></param>
        /// <param name="start"></param>
        /// <param name="len"></param>
        public void GenerateGlyphRuns(TextRun outputTextRun, char[] charBuffer, int start, int len)
        {
            // layout glyphs with selected layout technique
            float sizeInPoints = this.FontSizeInPoints;

            outputTextRun.typeface     = this.CurrentTypeFace;
            outputTextRun.sizeInPoints = sizeInPoints;

            //in this version we store original glyph into the mesh collection
            //and then we scale it later, so I just specific font size=0 (you can use any value)
            _glyphMeshCollection.SetCacheInfo(this.CurrentTypeFace, 0, this.HintTechnique);


            glyphLayout.Typeface = this.CurrentTypeFace;
            glyphLayout.Layout(charBuffer, start, len);

            float pxscale = this.CurrentTypeFace.CalculateScaleToPixelFromPointSize(sizeInPoints);

            outputGlyphPlans.Clear();
            GlyphLayoutExtensions.GenerateGlyphPlan(
                glyphLayout.ResultUnscaledGlyphPositions,
                pxscale, false, outputGlyphPlans);

            // render each glyph
            int planCount = outputGlyphPlans.Count;

            for (var i = 0; i < planCount; ++i)
            {
                pathTranslator.Reset();
                //----
                //glyph path
                //----
                GlyphPlan glyphPlan = outputGlyphPlans[i];
                //
                //1. check if we have this glyph in cache?
                //if yes, not need to build it again
                ProcessedGlyph processGlyph;
                float[]        tessData = null;

                if (!_glyphMeshCollection.TryGetCacheGlyph(glyphPlan.glyphIndex, out processGlyph))
                {
                    //if not found the  create a new one and register it
                    var writablePath = new WritablePath();
                    pathTranslator.SetOutput(writablePath);
                    currentGlyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, sizeInPoints);
                    currentGlyphPathBuilder.ReadShapes(pathTranslator);

                    //-------
                    //do tess
                    int[]   endContours;
                    float[] flattenPoints = _curveFlattener.Flatten(writablePath._points, out endContours);
                    int     nTessElems;
                    tessData = _tessTool.TessPolygon(flattenPoints, endContours, out nTessElems);
                    //-------
                    processGlyph = new ProcessedGlyph(tessData, (ushort)nTessElems);
                    _glyphMeshCollection.RegisterCachedGlyph(glyphPlan.glyphIndex, processGlyph);
                }

                outputTextRun.AddGlyph(
                    new GlyphRun(glyphPlan,
                                 processGlyph.tessData,
                                 processGlyph.tessNElements));
            }
        }