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.GenerateGlyphPlans( _glyphLayout.ResultUnscaledGlyphPositions, _currentFontSizePxScale, false, _outputGlyphPlans); } DrawFromGlyphPlans(_outputGlyphPlans, x, y); }
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; }
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); }
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); }
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); }
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); } }
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; }