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; } }
public OpenFontIFonts() { typefaceStore = new TypefaceStore(); typefaceStore.FontCollection = InstalledFontCollection.GetSharedFontCollection(null); glyphLayout = new GlyphLayout(); //create glyph layout with default value userGlyphPlanList = new GlyphPlanList(); userCharToGlyphMapList = new List <UserCharToGlyphIndexMap>(); }
public override void DrawFromGlyphPlans(GlyphPlanList 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; for (int i = startAt; i < endBefore; ++i) { GlyphPlan 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 tx = x + glyphPlan.ExactX; float ty = y + glyphPlan.ExactY; g.TranslateTransform(tx, ty); if (FillBackground) { g.FillPath(_fillBrush, foundPath); } if (DrawOutline) { g.DrawPath(_outlinePen, foundPath); } //and then we reset back *** g.TranslateTransform(-tx, -ty); } }
public GlyphPlanList StringToGlyphPlanList(string s, double font_size) { GlyphPlanList l = new GlyphPlanList(); m_layout.Layout(s.ToCharArray(), 0, s.Length); var scale = m_openfont.CalculateScaleToPixelFromPointSize((float)font_size); GlyphLayoutExtensions.GenerateGlyphPlan(m_layout.ResultUnscaledGlyphPositions, scale, snapToGrid: true, outputGlyphPlanList: l); return(l); }
public virtual void GenerateGlyphPlan( char[] textBuffer, int startAt, int len, GlyphPlanList outputGlyphPlanList, List <UserCharToGlyphIndexMap> charToGlyphMapList) { this.GlyphLayoutMan.Layout(textBuffer, startAt, len); GlyphLayoutExtensions.GenerateGlyphPlan(this.GlyphLayoutMan.ResultUnscaledGlyphPositions, this.Typeface.CalculateScaleToPixelFromPointSize(this.FontSizeInPoints), false, outputGlyphPlanList); }
public void Draw() { GlyphPlanList glyphPlans = _line._glyphPlans; List <UserCharToGlyphIndexMap> userCharToGlyphIndexMap = _line._userCharToGlyphMap; if (_line.ContentChanged) { //re-calculate char[] textBuffer = _line._charBuffer.ToArray(); glyphPlans.Clear(); userCharToGlyphIndexMap.Clear(); //read glyph plan and userCharToGlyphIndexMap _printer.GenerateGlyphPlan(textBuffer, 0, textBuffer.Length, glyphPlans, userCharToGlyphIndexMap); toPxScale = _printer.Typeface.CalculateScaleToPixelFromPointSize(_printer.FontSizeInPoints); _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 { UserCharToGlyphIndexMap map = userCharToGlyphIndexMap[caret_index - 1]; GlyphPlan p = glyphPlans[map.glyphIndexListOffset_plus1 + map.len - 2]; _printer.DrawCaret(X + p.ExactRight, this.Y); } } else { _printer.DrawCaret(X, this.Y); } }
GlyphPlanSequence CreateGlyphPlanSeq(GlyphLayout glyphLayout, TextBuffer buffer, int startAt, int len) { GlyphPlanList planList = GlyphPlanBuffer.UnsafeGetGlyphPlanList(_glyphPlanBuffer); int pre_count = planList.Count; glyphLayout.Typeface = _typeface; glyphLayout.ScriptLang = _scLang; glyphLayout.Layout( TextBuffer.UnsafeGetCharBuffer(buffer), startAt, len); int post_count = planList.Count; return(new GlyphPlanSequence(_glyphPlanBuffer, pre_count, post_count - pre_count)); }
public static void CopyGlyphPlans(RenderVxFormattedString renderVx, GlyphPlanList glyphPlans, float scale) { int n = glyphPlans.Count; //copy var renderVxGlyphPlans = new RenderVxGlyphPlan[n]; for (int i = 0; i < n; ++i) { GlyphPlan glyphPlan = glyphPlans[i]; renderVxGlyphPlans[i] = new RenderVxGlyphPlan( glyphPlan.glyphIndex, glyphPlan.ExactX, glyphPlan.ExactY, glyphPlan.AdvanceX ); } renderVx.glyphList = renderVxGlyphPlans; }
/// <summary> /// draw glyph plan list at (xpos,ypos) of baseline /// </summary> /// <param name="glyphPlanList"></param> /// <param name="x"></param> /// <param name="y"></param> public abstract void DrawFromGlyphPlans(GlyphPlanList glyphPlanList, int startAt, int len, float x, float y);
public override void DrawFromGlyphPlans(GlyphPlanList glyphPlanList, int startAt, int len, float x, float y) { CanvasPainter canvasPainter = this.TargetCanvasPainter; //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); //4. render each glyph float ox = canvasPainter.OriginX; float oy = canvasPainter.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) { 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? //----------------------------------- GlyphPlan glyphPlan = glyphPlanList[i]; g_x = glyphPlan.ExactX + x; g_y = glyphPlan.ExactY + y; canvasPainter.SetOrigin(g_x, g_y); //----------------------------------- canvasPainter.Fill(_glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex)); } } else { //------------- //this glyph has color information //------------- Color originalFillColor = canvasPainter.FillColor; for (int i = startAt; i < endBefore; ++i) { GlyphPlan glyphPlan = glyphPlanList[i]; g_x = glyphPlan.ExactX + x; g_y = glyphPlan.ExactY + y; canvasPainter.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); //----------- canvasPainter.FillColor = new Color(r, g, b);//? a component canvasPainter.Fill(_glyphMeshStore.GetGlyphMesh(gIndex)); } } else { //----------------------------------- //TODO: review here *** //PERFORMANCE revisit here //if we have create a vxs we can cache it for later use? //----------------------------------- canvasPainter.Fill(_glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex)); } } canvasPainter.FillColor = originalFillColor; //restore color } //restore prev origin canvasPainter.SetOrigin(ox, oy); }
////========================================================================= ////msdf texture generator example //private void cmdBuildMsdfTexture_Click(object sender, System.EventArgs e) //{ // string sampleFontFile = Path.Combine("..", "..", "..", "TestFonts", "tahoma.ttf"); // CreateSampleMsdfTextureFont( // sampleFontFile, // 18, // 0, // 255, // "d:\\WImageTest\\sample_msdf.png"); //} //static void CreateSampleMsdfTextureFont(string fontfile, float sizeInPoint, ushort startGlyphIndex, ushort endGlyphIndex, string outputFile) //{ // //sample // var reader = new OpenFontReader(); // using (var fs = new FileStream(fontfile, FileMode.Open)) // { // //1. read typeface from font file // Typeface typeface = reader.Read(fs); // //sample: create sample msdf texture // //------------------------------------------------------------- // var builder = new GlyphPathBuilder(typeface); // //builder.UseTrueTypeInterpreter = this.chkTrueTypeHint.Checked; // //builder.UseVerticalHinting = this.chkVerticalHinting.Checked; // //------------------------------------------------------------- // var atlasBuilder = new SimpleFontAtlasBuilder(); // for (ushort n = startGlyphIndex; n <= endGlyphIndex; ++n) // { // //build glyph // builder.BuildFromGlyphIndex(n, sizeInPoint); // var glyphToContour = new GlyphTranslatorToContour(); // builder.ReadShapes(glyphToContour); // //glyphToContour.Read(builder.GetOutputPoints(), builder.GetOutputContours()); // GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour); // atlasBuilder.AddGlyph(n, glyphImg); // //using (Bitmap bmp = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) // //{ // // var bmpdata = bmp.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // // System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpdata.Scan0, buffer.Length); // // bmp.UnlockBits(bmpdata); // // bmp.Save("d:\\WImageTest\\a001_xn2_" + n + ".png"); // //} // } // var glyphImg2 = atlasBuilder.BuildSingleImage(); // using (Bitmap bmp = new Bitmap(glyphImg2.Width, glyphImg2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) // { // var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg2.Width, glyphImg2.Height), // System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // int[] intBuffer = glyphImg2.GetImageBuffer(); // System.Runtime.InteropServices.Marshal.Copy(intBuffer, 0, bmpdata.Scan0, intBuffer.Length); // bmp.UnlockBits(bmpdata); // bmp.Save("d:\\WImageTest\\a_total.png"); // } // atlasBuilder.SaveFontInfo("d:\\WImageTest\\a_info.xml"); // } //} private void cmdMeasureTextSpan_Click(object sender, System.EventArgs e) { //set some Gdi+ props... g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.Clear(Color.White); //credit: //http://stackoverflow.com/questions/1485745/flip-coordinates-when-drawing-to-control g.ScaleTransform(1.0F, -1.0F); // Flip the Y-Axis g.TranslateTransform(0.0F, -(float)300); // Translate the drawing area accordingly //-------------------------------- //textspan measurement sample //-------------------------------- _currentTextPrinter.HintTechnique = (HintTechnique)lstHintList.SelectedItem; _currentTextPrinter.PositionTechnique = (PositionTechnique)cmbPositionTech.SelectedItem; //render at specific pos float x_pos = 0, y_pos = 100; char[] textBuffer = txtInputChar.Text.ToCharArray(); //Example 1: this is a basic draw sample _currentTextPrinter.FillColor = Color.Black; _currentTextPrinter.TargetGraphics = g; _currentTextPrinter.DrawString( textBuffer, 0, textBuffer.Length, x_pos, y_pos ); // //-------------------------------------------------- //Example 2: print glyph plan to 'user' list-> then draw it (or hold it/ not draw) //you can create you own class to hold userGlyphPlans.*** //2.1 GlyphPlanList userGlyphPlans = new GlyphPlanList(); _currentTextPrinter.GenerateGlyphPlan(textBuffer, 0, textBuffer.Length, userGlyphPlans, null); //2.2 //and we can print the formatted glyph plan later. y_pos -= _currentTextPrinter.FontLineSpacingPx; _currentTextPrinter.FillColor = Color.Red; _currentTextPrinter.DrawFromGlyphPlans( userGlyphPlans, x_pos, y_pos ); //Example 3: MeasureString MeasuredStringBox strBox = _currentTextPrinter.MeasureString(textBuffer, 0, textBuffer.Length); //draw line mark float x_pos2 = x_pos + strBox.width + 10; g.DrawRectangle(Pens.Red, x_pos, y_pos, strBox.width, strBox.CalculateLineHeight()); g.DrawLine(Pens.Blue, x_pos, y_pos, x_pos2, y_pos); //baseline g.DrawLine(Pens.Green, x_pos, y_pos + strBox.descending, x_pos2, y_pos + strBox.descending); //descending g.DrawLine(Pens.Magenta, x_pos, y_pos + strBox.ascending, x_pos2, y_pos + strBox.ascending); //ascending _currentTextPrinter.FillColor = Color.Black; //transform back g.ScaleTransform(1.0F, -1.0F); // Flip the Y-Axis g.TranslateTransform(0.0F, -(float)300); // Translate the drawing area accordingly }
public void DrawFromGlyphPlans(GlyphPlanList glyphPlanList, float xpos, float ypos) { DrawFromGlyphPlans(glyphPlanList, 0, glyphPlanList.Count, xpos, ypos); }
public void DrawString(char[] buffer, int startAt, int len, double x, double y) { _glsx.FontFillColor = painter.FontFillColor; int j = buffer.Length; //create temp buffer span that describe the part of a whole char buffer TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len); //ask text service to parse user input char buffer and create a glyph-plan-sequence (list of glyph-plan) //with specific request font GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref textBufferSpan, font); float scale = _fontAtlas.TargetTextureScale; int recommendLineSpacing = _fontAtlas.OriginalRecommendLineSpacing; //-------------------------- //TODO: //if (x,y) is left top //we need to adjust y again y -= ((_fontAtlas.OriginalRecommendLineSpacing) * scale); EnsureLoadGLBmp(); // float scaleFromTexture = _finalTextureScale; TextureKind textureKind = _fontAtlas.TextureKind; //-------------------------- //TODO: review render steps //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos // ideal_x = (float)(x + (glyph.x * scale - glyphData.TextureXOffset) * scaleFromTexture); // ideal_y = (float)(y + (glyph.y * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); //-------------------------- float g_x = 0; float g_y = 0; int baseY = (int)Math.Round(y); int n = glyphPlanSeq.len; int endBefore = glyphPlanSeq.startAt + n; for (int i = glyphPlanSeq.startAt; i < endBefore; ++i) { GlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq); GlyphPlan glyph = glyphPlanList[i]; Typography.Rendering.TextureFontGlyphData glyphData; if (!_fontAtlas.TryGetGlyphDataByCodePoint(glyph.glyphIndex, out glyphData)) { //if no glyph data, we should render a missing glyph *** continue; } //-------------------------------------- //TODO: review precise height in float //-------------------------------------- PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect); g_x = (float)(x + (glyph.ExactX * scale - glyphData.TextureXOffset) * scaleFromTexture); //ideal x g_y = (float)(y + (glyph.ExactY * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); //for sharp glyph //we adjust g_x,g_y to integer value g_x = (float)Math.Round(g_x); g_y = (float)Math.Floor(g_y); switch (textureKind) { case TextureKind.Msdf: _glsx.DrawSubImageWithMsdf(_glBmp, ref srcRect, g_x, g_y, scaleFromTexture); break; case TextureKind.StencilGreyScale: //stencil gray scale with fill-color _glsx.DrawGlyphImageWithStecil(_glBmp, ref srcRect, g_x, g_y, scaleFromTexture); break; case TextureKind.Bitmap: _glsx.DrawSubImage(_glBmp, ref srcRect, g_x, g_y, scaleFromTexture); break; case TextureKind.StencilLcdEffect: _glsx.DrawGlyphImageWithSubPixelRenderingTechnique(_glBmp, ref srcRect, g_x, g_y, scaleFromTexture); break; } } }
public void DrawFromGlyphPlans(GlyphPlanList glyphPlanList, float x, float y) { DrawFromGlyphPlans(glyphPlanList, 0, glyphPlanList.Count, x, y); }
public static void GetGlyphPos(ActualFont actualFont, char[] buffer, int startAt, int len, GlyphPlanList properGlyphs) { defaultSharpingService.GetGlyphPosImpl(actualFont, buffer, startAt, len, properGlyphs); }
public void Layout(IGlyphPositions posStream, GlyphPlanList outputGlyphPlanList) { if (!UseWithLcdSubPixelRenderingTechnique) { //layout without fit to alignment direction LayoutWithoutHorizontalFitAlign(posStream, outputGlyphPlanList); return; //early exit } //------------------------------ int finalGlyphCount = posStream.Count; float pxscale = _typeface.CalculateScaleToPixelFromPointSize(this._fontSizeInPoints); #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 // _hintedFontStore.SetFont(_typeface, this._fontSizeInPoints); FineABC current_ABC = new FineABC(); FineABC prev_ABC = new FineABC(); 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); GlyphControlParameters controlPars = _hintedFontStore.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? } } //------------------------------------------------------------- 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 GlyphPlan( glyphIndex, final_x, exact_y, current_ABC.final_advW)); // // 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(GlyphPlanList 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); //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; 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? //----------------------------------- GlyphPlan glyphPlan = glyphPlanList[i]; g_x = glyphPlan.ExactX + x; g_y = glyphPlan.ExactY + y; painter.SetOrigin(g_x, g_y); //----------------------------------- //invert each glyph //version 3: painter.Fill(_glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex)); //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; for (int i = startAt; i < endBefore; ++i) { GlyphPlan glyphPlan = glyphPlanList[i]; g_x = glyphPlan.ExactX + x; g_y = glyphPlan.ExactY + y; 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 CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, ILineSegmentList lineSegs, RequestFont font, int[] outputUserInputCharAdvance, out int outputTotalW, out int lineHeight) { //layout //from font //resolve for typeface // Typeface typeface = ResolveTypeface(font); _typographyTxtServices.SetCurrentFont(typeface, font.SizeInPoints); MyLineSegmentList mylineSegs = (MyLineSegmentList)lineSegs; float scale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); outputTotalW = 0; int j = mylineSegs.Count; int pos = 0; //start at 0 _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer()); for (int i = 0; i < j; ++i) { //userGlyphPlanList.Clear(); //userCharToGlyphMapList.Clear(); //get each segment MyLineSegment lineSeg = mylineSegs.GetSegment(i); //each line seg may has different script lang _typographyTxtServices.CurrentScriptLang = lineSeg.scriptLang; // //CACHING ...., reduce number of GSUB/GPOS // //we cache used line segment for a while //we ask for caching context for a specific typeface and font size GlyphPlanSequence seq = _typographyTxtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, lineSeg.StartAt, lineSeg.Length); GlyphPlanList planList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(seq); //IMPORTANT //num of glyph may more or less than original user input char buffer // int endAt = seq.startAt + seq.len; int seq_startAt = seq.startAt; for (int s = seq_startAt; s < endAt; ++s) { GlyphPlan glyphPlan = planList[s]; float tx = glyphPlan.ExactX; float ty = glyphPlan.ExactY; double actualAdvX = glyphPlan.AdvanceX; outputTotalW += outputUserInputCharAdvance[pos + glyphPlan.input_cp_offset] += (int)Math.Round(actualAdvX * scale); } pos += lineSeg.Length; } // lineHeight = (int)Math.Round(typeface.CalculateRecommendLineSpacing() * scale); _reusableTextBuffer.SetRawCharBuffer(null); }
protected abstract void GetGlyphPosImpl(ActualFont actualFont, char[] buffer, int startAt, int len, GlyphPlanList properGlyphs);