void LayoutWithoutHorizontalFitAlign(IGlyphPositions posStream, GlyphPlanList outputGlyphPlanList) { //the default OpenFont layout without fit-to-writing alignment int finalGlyphCount = posStream.Count; float pxscale = _typeface.CalculateScaleToPixelFromPointSize(this._fontSizeInPoints); double cx = 0; short cy = 0; for (int i = 0; i < finalGlyphCount; ++i) { short offsetX, offsetY, advW; //all from pen-pos ushort glyphIndex = posStream.GetGlyph(i, out offsetX, out offsetY, out advW); float s_advW = advW * pxscale; float exact_x = (float)(cx + offsetX * pxscale); float exact_y = (float)(cy + offsetY * pxscale); //outputGlyphPlanList.Append(new GlyphPlan( // glyphIndex, // exact_x, // exact_y, // advW)); //old? outputGlyphPlanList.Append(new GlyphPlan( glyphIndex, exact_x, exact_y, s_advW)); cx += s_advW; } }
/// <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, PxScaledGlyphPlanList outputGlyphPlanList) { //user can implement this with some 'PixelScaleEngine' if (snapToGrid) { 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 PxScaledGlyphPlan( input_offset, glyphIndex, (short)Math.Round(advW * pxscale), (short)Math.Round(offsetX * pxscale), (short)Math.Round(offsetY * pxscale) )); } } else { //not snap to grid //scaled but not snap to grid 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 PxScaledGlyphPlan( input_offset, glyphIndex, advW * pxscale, offsetX * pxscale, offsetY * pxscale )); } } }
static void GenerateScaledGlyphPlans(this GlyphLayout glyphLayout, float pxscale, bool snapToGrid, out float accumW) { //user can implement this with some 'PixelScaleEngine' IGlyphPositions glyphPositions = glyphLayout.ResultUnscaledGlyphPositions; accumW = 0; //acummulate Width if (snapToGrid) { int finalGlyphCount = glyphPositions.Count; for (int i = 0; i < finalGlyphCount; ++i) { short offsetX, offsetY, advW; //all from pen-pos ushort glyphIndex = glyphPositions.GetGlyph(i, out ushort input_offset, out offsetX, out offsetY, out advW); float scaled_advW = (short)Math.Round(advW * pxscale); accumW += scaled_advW; } } else { //not snap to grid //scaled but not snap to grid int finalGlyphCount = glyphPositions.Count; for (int i = 0; i < finalGlyphCount; ++i) { short offsetX, offsetY, advW; //all from pen-pos ushort glyphIndex = glyphPositions.GetGlyph(i, out ushort input_offset, out offsetX, out offsetY, out advW); accumW += advW * pxscale; } } }
/// <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 )); } }
/// <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; } }
/// <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); } }