/// <summary>
        /// generate scaled from unscale glyph size to specific scale
        /// </summary>
        /// <param name="glyphPositions"></param>
        /// <param name="pxscale"></param>
        /// <param name="outputGlyphPlanList"></param>
        public static void GenerateUnscaledGlyphPlans(IGlyphPositions glyphPositions, UnscaledGlyphPlanList outputGlyphPlanList)
        {
            //user can implement this with some 'PixelScaleEngine'

            int finalGlyphCount = glyphPositions.Count;

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                short  input_offset, offsetX, offsetY, advW; //all from pen-pos
                ushort glyphIndex = glyphPositions.GetGlyph(i, out input_offset, out offsetX, out offsetY, out advW);

                outputGlyphPlanList.Append(new UnscaledGlyphPlan(
                                               input_offset,
                                               glyphIndex,
                                               advW,
                                               offsetX,
                                               offsetY
                                               ));
            }
        }
        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));
        }
Exemple #3
0
        /// <summary>
        /// generate scaled from unscale glyph size to specific scale
        /// </summary>
        /// <param name="glyphPositions"></param>
        /// <param name="pxscale"></param>
        /// <param name="outputGlyphPlanList"></param>
        public static void GenerateGlyphPlans(IGlyphPositions glyphPositions,
                                              float pxscale,
                                              bool snapToGrid,
                                              GlyphPlanList outputGlyphPlanList)
        {
            //user can implement this with some 'PixelScaleEngine'

            //double cx = 0;
            //short cy = 0;
            //the default OpenFont layout without fit-to-writing alignment
            int    finalGlyphCount = glyphPositions.Count;
            double cx = 0;
            short  cy = 0;

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                short  input_offset, offsetX, offsetY, advW; //all from pen-pos
                ushort glyphIndex = glyphPositions.GetGlyph(i, out input_offset, out offsetX, out offsetY, out advW);

                float s_advW = advW * pxscale;

                if (snapToGrid)
                {
                    //TEST,
                    //if you want to snap each glyph to grid (1px or 0.5px) by ROUNDING
                    //we can do it here,this produces a predictable caret position result
                    //
                    s_advW += (int)Math.Round(s_advW);
                }
                float exact_x = (float)(cx + offsetX * pxscale);
                float exact_y = (float)(cy + offsetY * pxscale);

                outputGlyphPlanList.Append(new GlyphPlan(
                                               input_offset,
                                               glyphIndex,
                                               exact_x,
                                               exact_y,
                                               advW));
                cx += s_advW;
            }
        }
        static float MeasureGlyphPlans(this GlyphLayout glyphLayout,
                                       float pxscale,
                                       bool snapToGrid)
        {
            //user can implement this with some 'PixelScaleEngine'
            IGlyphPositions glyphPositions = glyphLayout.ResultUnscaledGlyphPositions;
            float           accumW         = 0; //acummulate Width

            if (snapToGrid)
            {
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out short offsetX,
                                                                out short offsetY,
                                                                out short advW);
                    accumW += (short)Math.Round(advW * pxscale);
                }
            }
            else
            {
                //not snap to grid
                //scaled but not snap to grid
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out short offsetX,
                                                                out short offsetY,
                                                                out short advW);
                    accumW += advW * pxscale;
                }
            }
            return(accumW);
        }
        /// <summary>
        /// fetch layout result, unscaled version, put to IUnscaledGlyphPlanList
        /// </summary>
        /// <param name="glyphPositions"></param>
        /// <param name="pxscale"></param>
        /// <param name="outputGlyphPlanList"></param>
        public void GenerateUnscaledGlyphPlans(IUnscaledGlyphPlanList outputGlyphPlanList)
        {
            IGlyphPositions glyphPositions  = _glyphPositions;
            int             finalGlyphCount = glyphPositions.Count;

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                short  offsetX, offsetY, advW;
                ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                            out ushort input_offset,
                                                            out offsetX,
                                                            out offsetY,
                                                            out advW);
                //
                outputGlyphPlanList.Append(new UnscaledGlyphPlan(
                                               input_offset,
                                               glyphIndex,
                                               advW,
                                               offsetX,
                                               offsetY
                                               ));
            }
        }
        public IEnumerable <UnscaledGlyphPlan> GetUnscaledGlyphPlanIter()
        {
            //this for iterator version
            IGlyphPositions glyphPositions  = _glyphPositions;
            int             finalGlyphCount = glyphPositions.Count;

            for (int i = 0; i < finalGlyphCount; ++i)
            {
                short  offsetX, offsetY, advW;
                ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                            out ushort input_offset,
                                                            out offsetX,
                                                            out offsetY,
                                                            out advW);

                yield return(new UnscaledGlyphPlan(
                                 input_offset,
                                 glyphIndex,
                                 advW,
                                 offsetX,
                                 offsetY
                                 ));
            }
        }
        static float MeasureGlyphPlanWithLimitWidth(this GlyphLayout glyphLayout,
                                                    float pxscale,
                                                    float limitWidth,
                                                    bool snapToGrid,
                                                    out int stopAtGlyphIndex)
        {
            //user can implement this with some 'PixelScaleEngine'
            IGlyphPositions glyphPositions = glyphLayout.ResultUnscaledGlyphPositions;
            float           accumW         = 0; //acummulate Width

            stopAtGlyphIndex = 0;

            if (snapToGrid)
            {
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out short offsetX,
                                                                out short offsetY,
                                                                out short advW);

                    stopAtGlyphIndex = i; //***
                    //
                    short w = (short)Math.Round(advW * pxscale);
                    if (accumW + w > limitWidth)
                    {
                        //stop
                        break;
                    }
                    else
                    {
                        accumW += w;
                    }
                }
            }
            else
            {
                //not snap to grid
                //scaled but not snap to grid
                int finalGlyphCount = glyphPositions.Count;
                for (int i = 0; i < finalGlyphCount; ++i)
                {
                    //all from pen-pos
                    ushort glyphIndex = glyphPositions.GetGlyph(i,
                                                                out ushort input_offset,
                                                                out short offsetX,
                                                                out short offsetY,
                                                                out short advW);


                    stopAtGlyphIndex = i; //***

                    float w = advW * pxscale;
                    if (accumW + w > limitWidth)
                    {
                        //stop
                        break;
                    }
                    else
                    {
                        accumW += w;
                    }
                }
            }
            return(accumW);


            ////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;

            //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;
            //foreach (Typography.TextLayout.BreakSpan breakSpan in BreakToLineSegments(str, startAt, len))
            //{

            //    //measure string at specific px scale
            //    _glyphLayout.Layout(str, breakSpan.startAt, breakSpan.len);
            //    //

            //    _reusableGlyphPlanList.Clear();
            //    _glyphLayout.GenerateUnscaledGlyphPlans(_reusableGlyphPlanList);
            //    //measure ...


            //    //measure each glyph
            //    //limit at specific width
            //    int glyphCount = _reusableGlyphPlanList.Count;



            //    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;
        }
        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);
            }
        }