public virtual void GenerateGlyphPlan( char[] textBuffer, int startAt, int len, PxScaledGlyphPlanList 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 void Draw() { PxScaledGlyphPlanList glyphPlans = _line._glyphPlans; List <UserCodePointToGlyphIndex> userCharToGlyphIndexMap = _line._userCodePointToGlyphIndexMap; if (_line.ContentChanged) { //TODO: or font face/font-size change //re-calculate char[] textBuffer = _line._charBuffer.ToArray(); glyphPlans.Clear(); userCharToGlyphIndexMap.Clear(); //read glyph plan and userCharToGlyphIndexMap _printer.GenerateGlyphPlan(textBuffer, 0, textBuffer.Length, glyphPlans, userCharToGlyphIndexMap); _line.ContentChanged = false; } if (glyphPlans.Count > 0) { _printer.DrawFromGlyphPlans(glyphPlans, X, Y); //draw caret //not blink in this version int caret_index = _line.CaretCharIndex; //find caret pos based on glyph plan //TODO: check when do gsub (glyph number may not match with user char number) if (caret_index == 0) { _printer.DrawCaret(X, this.Y); } else { //UserCodePointToGlyphIndex map = userCharToGlyphIndexMap[caret_index - 1]; //GlyphPlan p = glyphPlans[map.glyphIndexListOffset_plus1 + map.len - 2]; //_printer.DrawCaret(X + (p.ExactX + p.AdvanceX), this.Y); } } else { _printer.DrawCaret(X, this.Y); } }
public static void CopyGlyphPlans(RenderVxFormattedString renderVx, PxScaledGlyphPlanList glyphPlans) { int n = glyphPlans.Count; //copy var renderVxGlyphPlans = new RenderVxGlyphPlan[n]; float acc_x = 0; float acc_y = 0; float x = 0; float y = 0; float g_x = 0; float g_y = 0; for (int i = 0; i < n; ++i) { PxScaledGlyphPlan glyphPlan = glyphPlans[i]; float ngx = acc_x + glyphPlan.OffsetX; float ngy = acc_y + glyphPlan.OffsetY; //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 = glyphPlan.AdvanceX; acc_x += g_w; //g_x = (float)Math.Round(g_x); g_y = (float)Math.Floor(g_y); renderVxGlyphPlans[i] = new RenderVxGlyphPlan( glyphPlan.glyphIndex, g_x, g_y, g_w ); } renderVx.glyphList = renderVxGlyphPlans; }
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 override void DrawFromGlyphPlans(PxScaledGlyphPlanList glyphPlanList, int startAt, int len, float x, float y) { UpdateVisualOutputSettings(); //draw data in glyph plan //3. render each glyph float sizeInPoints = this.FontSizeInPoints; float scale = _currentTypeface.CalculateScaleToPixelFromPointSize(sizeInPoints); // _glyphMeshCollections.SetCacheInfo(this.Typeface, sizeInPoints, this.HintTechnique); //this draw a single line text span*** int endBefore = startAt + len; Graphics g = this.TargetGraphics; float acc_x = 0; float acc_y = 0; float g_x = 0; float g_y = 0; for (int i = startAt; i < endBefore; ++i) { PxScaledGlyphPlan glyphPlan = glyphPlanList[i]; //check if we have a cache of this glyph //if not -> create it GraphicsPath foundPath; if (!_glyphMeshCollections.TryGetCacheGlyph(glyphPlan.glyphIndex, out foundPath)) { //if not found then create a new one _currentGlyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, sizeInPoints); _txToGdiPath.Reset(); _currentGlyphPathBuilder.ReadShapes(_txToGdiPath); foundPath = _txToGdiPath.ResultGraphicsPath; //register _glyphMeshCollections.RegisterCachedGlyph(glyphPlan.glyphIndex, foundPath); } //------ //then move pen point to the position we want to draw a glyph float ngx = acc_x + (float)Math.Round(glyphPlan.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyphPlan.OffsetY * scale); g_x = (x + (ngx)); g_y = (y + (ngy)); acc_x += (float)Math.Round(glyphPlan.AdvanceX * scale); //g_x = (float)Math.Round(g_x); g_y = (float)Math.Floor(g_y); g.TranslateTransform(g_x, g_y); if (FillBackground) { g.FillPath(_fillBrush, foundPath); } if (DrawOutline) { g.DrawPath(_outlinePen, foundPath); } //and then we reset back *** g.TranslateTransform(-g_x, -g_y); } }
public override void DrawFromGlyphPlans(PxScaledGlyphPlanList glyphPlanList, int startAt, int len, float x, float y) { Painter painter = this.TargetCanvasPainter; if (StartDrawOnLeftTop) { //version 2 //offset y down y += this.FontLineSpacingPx; } //Typeface typeface = _glyphPathBuilder.Typeface; //3. layout glyphs with selected layout technique //TODO: review this again, we should use pixel? float fontSizePoint = this.FontSizeInPoints; //float scale = _currentTypeface.CalculateScaleToPixelFromPointSize(fontSizePoint); float scale = 1; //4. render each glyph float ox = painter.OriginX; float oy = painter.OriginY; int endBefore = startAt + len; Typography.OpenFont.Tables.COLR colrTable = _currentTypeface.COLRTable; Typography.OpenFont.Tables.CPAL cpalTable = _currentTypeface.CPALTable; bool hasColorGlyphs = (colrTable != null) && (cpalTable != null); //--------------------------------------------------- _glyphMeshStore.SetFont(_currentTypeface, fontSizePoint); //--------------------------------------------------- float g_x = 0; float g_y = 0; float baseY = (int)y; if (!hasColorGlyphs) { bool savedUseLcdMode = painter.UseSubPixelLcdEffect; //save,restore later RenderQualtity savedRederQuality = painter.RenderQuality; painter.RenderQuality = RenderQualtity.HighQuality; painter.UseSubPixelLcdEffect = true; Agg.Transform.Affine flipY = Agg.Transform.Affine.NewMatix( Agg.Transform.AffinePlan.Scale(1, -1)); //flip Y VertexStore reusableVxs = new VertexStore(); float acc_x = 0; //acummulate x float acc_y = 0; //acummulate y for (int i = startAt; i < endBefore; ++i) { //----------------------------------- //TODO: review here *** //PERFORMANCE revisit here //if we have create a vxs we can cache it for later use? //----------------------------------- PxScaledGlyphPlan glyphPlan = glyphPlanList[i]; float ngx = acc_x + (float)Math.Round(glyphPlan.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyphPlan.OffsetY * scale); acc_x += (float)Math.Round(glyphPlan.AdvanceX * scale); g_x = ngx; g_y = ngy; painter.SetOrigin(g_x, g_y); //----------------------------------- //invert each glyph //version 3: reusableVxs.Clear(); VertexStore vxs = _glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex); flipY.TransformToVxs(vxs, reusableVxs); painter.Fill(reusableVxs); //version2; //VertexStore vsx = _glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex); //_vxs1 = _invertY.TransformToVxs(vsx, _vxs1); //painter.Fill(_vxs1); //_vxs1.Clear(); //version1 //painter.Fill(_glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex)); } //restore painter.RenderQuality = savedRederQuality; painter.UseSubPixelLcdEffect = savedUseLcdMode; } else { //------------- //this glyph has color information //------------- Color originalFillColor = painter.FillColor; float acc_x = 0; float acc_y = 0; for (int i = startAt; i < endBefore; ++i) { PxScaledGlyphPlan glyphPlan = glyphPlanList[i]; float ngx = acc_x + (float)Math.Round(glyphPlan.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyphPlan.OffsetY * scale); g_x = ngx; g_y = ngy; acc_x += (float)Math.Round(glyphPlan.AdvanceX * scale); painter.SetOrigin(g_x, g_y); //----------------------------------- ushort colorLayerStart; if (colrTable.LayerIndices.TryGetValue(glyphPlan.glyphIndex, out colorLayerStart)) { //TODO: optimize this //we found color info for this glyph ushort colorLayerCount = colrTable.LayerCounts[glyphPlan.glyphIndex]; byte r, g, b, a; for (int c = colorLayerStart; c < colorLayerStart + colorLayerCount; ++c) { ushort gIndex = colrTable.GlyphLayers[c]; int palette = 0; // FIXME: assume palette 0 for now cpalTable.GetColor( cpalTable.Palettes[palette] + colrTable.GlyphPalettes[c], //index out r, out g, out b, out a); //----------- painter.FillColor = new Color(r, g, b);//? a component painter.Fill(_glyphMeshStore.GetGlyphMesh(gIndex)); } } else { //----------------------------------- //TODO: review here *** //PERFORMANCE revisit here //if we have create a vxs we can cache it for later use? //----------------------------------- painter.Fill(_glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex)); } } painter.FillColor = originalFillColor; //restore color } //restore prev origin painter.SetOrigin(ox, oy); }
public void DrawFromGlyphPlans(PxScaledGlyphPlanList glyphPlanList, float x, float y) { DrawFromGlyphPlans(glyphPlanList, 0, glyphPlanList.Count, x, y); }
public abstract void DrawFromGlyphPlans(PxScaledGlyphPlanList glyphPlanList, int startAt, int len, float x, float y);