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); }
//static void ConcatMeasureBox(ref float accumW, ref float accumH, ref MeasuredStringBox measureBox) //{ // accumW += measureBox.width; // float h = measureBox.CalculateLineHeight(); // if (h > accumH) // { // accumH = h; // } //} public static MeasuredStringBox LayoutAndMeasureString( this GlyphLayout glyphLayout, char[] textBuffer, int startAt, int len, float fontSizeInPoints, float limitW = -1,//-1 unlimit scaled width (px) bool snapToGrid = true) { //1. unscale layout, in design unit glyphLayout.Layout(textBuffer, startAt, len); //2. scale to specific font size Typeface typeface = glyphLayout.Typeface; float pxscale = typeface.CalculateScaleToPixelFromPointSize(fontSizeInPoints); //.... float scaled_accumX = 0; if (limitW < 0) { //no limit scaled_accumX = MeasureGlyphPlans( glyphLayout, pxscale, snapToGrid); return(new MeasuredStringBox( scaled_accumX, typeface.Ascender, typeface.Descender, typeface.LineGap, typeface.ClipedAscender, typeface.ClipedDescender, pxscale)); } else if (limitW > 0) { scaled_accumX = MeasureGlyphPlanWithLimitWidth( glyphLayout, pxscale, limitW, snapToGrid, out int stopAtChar); var mstrbox = new MeasuredStringBox( scaled_accumX, typeface.Ascender, typeface.Descender, typeface.LineGap, typeface.ClipedAscender, typeface.ClipedDescender, pxscale); mstrbox.StopAt = (ushort)stopAtChar; return(mstrbox); } else { return(new MeasuredStringBox( 0, typeface.Ascender, typeface.Descender, typeface.LineGap, typeface.ClipedAscender, typeface.ClipedDescender, pxscale)); } }
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; }