Size CalculateDrawingStringSize(int length) { if (!_content_unparsed) { //the content is parsed *** if (_mybuffer.Length == length) { return(this.Size); } else { //ca int total = 0; if (_outputUserCharAdvances != null) { for (int i = 0; i < length; ++i) { total += _outputUserCharAdvances[i]; } } return(new Size(total, (int)Math.Round(Root.TextServices.MeasureBlankLineHeight(GetFont())))); } } var textBufferSpan = new TextBufferSpan(_mybuffer, 0, length); return(this.Root.TextServices.MeasureString(ref textBufferSpan, GetFont())); }
// 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); _txtServices.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) { //get each segment MyLineSegment lineSeg = (MyLineSegment)mylineSegs.GetSegment(i); //each line seg may has different script lang _txtServices.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 = _txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, lineSeg.StartAt, lineSeg.Length); int seqLen = seq.Count; for (int s = 0; s < seqLen; ++s) { UnscaledGlyphPlan glyphPlan = seq[s]; 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); }
public Size MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font) { Typeface typeface = ResolveTypeface(font); _txtServices.SetCurrentFont(typeface, font.SizeInPoints); _txtServices.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, out int w, out int h); return(new Size(w, h)); }
public void MeasureString(char[] buffer, int startAt, int len, out int w, out int h) { TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len); Size s = _textServices.MeasureString(ref textBufferSpan, _painter.CurrentFont); w = s.Width; h = s.Height; }
void InternalDrawString(char[] buffer, int startAt, int len, float x, float y) { UpdateGlyphLayoutSettings(); //unscale layout, with design unit scale TextBufferSpan buffSpan = new TextBufferSpan(buffer, startAt, len); GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref buffSpan, _reqFont); DrawFromGlyphPlans(glyphPlanSeq, x, y); }
public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, ILineSegmentList lineSegs, RequestFont font, int[] glyphXAdvances, out int outputTotalW, out int outputLineHeight) { throw new NotImplementedException(); }
public void MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font, int limitWidth, out int charFit, out int charFitWidth) { Typeface typeface = ResolveTypeface(font); _txtServices.SetCurrentFont(typeface, font.SizeInPoints); charFit = 0; _txtServices.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, limitWidth, out charFit, out charFitWidth); }
void InternalDrawString(char[] buffer, int startAt, int len, float x, float y) { //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 DrawFromGlyphPlans(_textServices.CreateGlyphPlanSeq(ref textBufferSpan, _font), startAt, len, x, y); }
public GlyphPlanSequence CreateGlyphPlanSeq(ref TextBufferSpan textBufferSpan, RequestFont font) { Typeface typeface = ResolveTypeface(font); _txtServices.SetCurrentFont(typeface, font.SizeInPoints); _reusableTextBuffer.SetRawCharBuffer(textBufferSpan.GetRawCharBuffer()); return(_txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, textBufferSpan.start, textBufferSpan.len)); }
public void MeasureString(char[] buffer, int startAt, int len, out int w, out int h) { UpdateGlyphLayoutSettings(); _glyphMeshStore.SetFont(_currentTypeface, this.FontSizeInPoints); _glyphMeshStore.SimulateOblique = this.SimulateSlant; TextBufferSpan textBuffSpan = new TextBufferSpan(buffer, startAt, len); Size s = _textServices.MeasureString(ref textBuffSpan, _painter.CurrentFont); w = s.Width; h = s.Height; }
public override void UpdateRunWidth() { ITextService txServices = Root.TextServices; Size size; if (IsLineBreak) { //TODO: review here //we should not store this as a text run //if this is a linebreak it should be encoded at the end of this visual line size = new Size(0, (int)Math.Round(txServices.MeasureBlankLineHeight(GetFont()))); _outputUserCharAdvances = null; } else { //TODO: review here again //1. after GSUB process, output glyph may be more or less //than original input char buffer(mybuffer) if (txServices.SupportsWordBreak) { var textBufferSpan = new TextBufferSpan(_mybuffer); int len = _mybuffer.Length; if (_content_unparsed) { //parse the content first _lineSegs = txServices.BreakToLineSegments(ref textBufferSpan); } // _content_unparsed = false; //output glyph position _outputUserCharAdvances = new int[len]; int outputTotalW, outputLineHeight; txServices.CalculateUserCharGlyphAdvancePos(ref textBufferSpan, _lineSegs, GetFont(), _outputUserCharAdvances, out outputTotalW, out outputLineHeight); size = new Size(outputTotalW, outputLineHeight); } else { _content_unparsed = false; int len = _mybuffer.Length; _outputUserCharAdvances = new int[len]; int outputTotalW, outputLineHeight; var textBufferSpan = new TextBufferSpan(_mybuffer); txServices.CalculateUserCharGlyphAdvancePos(ref textBufferSpan, GetFont(), _outputUserCharAdvances, out outputTotalW, out outputLineHeight); size = new Size(outputTotalW, outputLineHeight); } } //--------- this.SetSize(size.Width, size.Height); MarkHasValidCalculateSize(); }
public Typeface ResolveTypeface(RequestFont font) { //from user's request font //resolve to actual Typeface //get data from... //cache level-1 (attached inside the request font) Typeface typeface = PixelFarm.Drawing.Internal.RequestFontCacheAccess.GetActualFont <Typeface>(font, _system_id); if (typeface != null) { return(typeface); } // //cache level-2 (stored in this Ifonts) if (!_resolvedTypefaceCache.TryGetValue(font.FontKey, out typeface)) { //not found ask the typeface store to load that font //.... typeface = _txtServices.GetTypeface(font.Name, font.Style.ConvToInstalledFontStyle()); if (typeface == null) { throw new NotSupportedException(); } // //cache here (level-1) _resolvedTypefaceCache.Add(font.FontKey, typeface); } //and cache into level-0 float pxSize = Typeface.ConvPointsToPixels(font.SizeInPoints); float pxscale = typeface.CalculateScaleToPixelFromPointSize(font.SizeInPoints); float recommedLineSpacingInPx = typeface.CalculateRecommendLineSpacing() * pxscale; float descentInPx = typeface.Descender * pxscale; float ascentInPx = typeface.Ascender * pxscale; float lineGapInPx = typeface.LineGap * pxscale; PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetActualFont(font, _system_id, typeface); PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetGeneralFontMetricInfo(font, pxSize, ascentInPx, descentInPx, lineGapInPx, recommedLineSpacingInPx); TextBufferSpan w = new TextBufferSpan(new char[] { ' ' }); Size whiteSpaceW = MeasureString(ref w, font); PixelFarm.Drawing.Internal.RequestFontCacheAccess.SetWhitespaceWidth(font, _system_id, whiteSpaceW.Width); return(typeface); }
public void FindCurrentHitWord(out int startAt, out int len) { if (_currentTextRun == null) { startAt = 0; len = 0; return; } // //we read entire line //and send to line parser to parse a word StringBuilder stbuilder = new StringBuilder(); _currentLine.CopyLineContent(stbuilder); string lineContent = stbuilder.ToString(); //find char at TextBufferSpan textBufferSpan = new TextBufferSpan(lineContent.ToCharArray()); using (ILineSegmentList segmentList = this.RootGfx.TextServices.BreakToLineSegments(ref textBufferSpan)) { if (segmentList == null) { startAt = 0; len = 0; return; } int segcount = segmentList.Count; for (int i = 0; i < segcount; ++i) { ILineSegment seg = segmentList[i]; if (seg.StartAt + seg.Length >= caret_char_index) { //stop at this segment startAt = seg.StartAt; len = seg.Length; return; } } } //? startAt = 0; len = 0; }
public ILineSegmentList BreakToLineSegments(ref TextBufferSpan textBufferSpan) { //a text buffer span is separated into multiple line segment list char[] str = textBufferSpan.GetRawCharBuffer(); int cur_startAt = textBufferSpan.start; MyLineSegmentList lineSegments = MyLineSegmentList.GetFreeLineSegmentList(); foreach (BreakSpan breakSpan in _txtServices.BreakToLineSegments(str, textBufferSpan.start, textBufferSpan.len)) { MyLineSegment lineSeg = new MyLineSegment(lineSegments, breakSpan.startAt, breakSpan.len); lineSeg.scriptLang = breakSpan.scLang; lineSegments.AddLineSegment(lineSeg); } return(lineSegments); }
public ILineSegmentList BreakToLineSegments(ref TextBufferSpan textBufferSpan) { _resuableLineSegments.Clear(); //a text buffer span is separated into multiple line segment list char[] str = textBufferSpan.GetRawCharBuffer(); MyLineSegmentList lineSegs = new MyLineSegmentList(textBufferSpan.start, textBufferSpan.len); int cur_startAt = textBufferSpan.start; foreach (BreakSpan breakSpan in _txtServices.BreakToLineSegments(str, textBufferSpan.start, textBufferSpan.len)) { MyLineSegment lineSeg = new MyLineSegment(lineSegs, breakSpan.startAt, breakSpan.len); lineSeg.scriptLang = breakSpan.scLang; _resuableLineSegments.Add(lineSeg); } //TODO: review here, //check if we need to create new array everytime? lineSegs.SetResultLineSegments(_resuableLineSegments.ToArray()); _resuableLineSegments.Clear(); return(lineSegs); }
public void MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font, int maxWidth, out int charFit, out int charFitWidth) { WinGdiTextService.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, font, maxWidth, out charFit, out charFitWidth); }
public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, RequestFont font, int[] outputGlyphAdvances, out int outputTotalW, out int outputLineHeight) { WinGdiTextService.CalculateGlyphAdvancePos(ref textBufferSpan, font, outputGlyphAdvances, out outputTotalW); outputLineHeight = WinGdiTextService.MeasureBlankLineHeight(font); }
// public void CalculateUserCharGlyphAdvancePos(ref TextBufferSpan textBufferSpan, RequestFont font, int[] outputGlyphAdvances, out int outputTotalW, out int outputLineHeight) { CalculateUserCharGlyphAdvancePos(ref textBufferSpan, this.BreakToLineSegments(ref textBufferSpan), font, outputGlyphAdvances, out outputTotalW, out outputLineHeight); }
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); _txtServices.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 _txtServices.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 = _txtServices.GetUnscaledGlyphPlanSequence(_reusableTextBuffer, lineSeg.StartAt, lineSeg.Length); //IMPORTANT //num of glyph may more or less than original user input char buffer // //float g_x = 0; //float g_y = 0; //int baseY = (int)Math.Round(y); //int n = glyphPlanSeq.len; //int endBefore = glyphPlanSeq.startAt + n; ////*** //_glsx.SetAssociatedTextureInfo(_glBmp); //List<float> vboBufferList = new List<float>(); //List<ushort> indexList = new List<ushort>(); //for (int i = glyphPlanSeq.startAt; i < endBefore; ++i) //{ // GlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq); // GlyphPlan glyph = glyphPlanList[i]; // Typography.Rendering.TextureGlyphMapData glyphData; // if (!_fontAtlas.TryGetGlyphDataByCodePoint(glyph.glyphIndex, out glyphData)) // { // //if no glyph data, we should render a missing glyph *** // continue; // } // //if (scaleFromTexture != 1) // //{ // //} // //-------------------------------------- // //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 // //float g_y2 = (float)Math.Floor(g_y); // 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.WriteVboToList( // vboBufferList, // indexList, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // } //} ////--------- int seqLen = seq.Count; for (int s = 0; s < seqLen; ++s) { UnscaledGlyphPlan glyphPlan = seq[s]; 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); }
public void PrepareStringForRenderVx(GLRenderVxFormattedString renderVxFormattedString, char[] buffer, int startAt, int len) { int top = 0; //simulate top int left = 0; //simulate left _vboBuilder.Clear(); _vboBuilder.SetTextureInfo(_glBmp.Width, _glBmp.Height, _glBmp.IsYFlipped, _pcx.OriginKind); //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 px_scale = _px_scale; //-------------------------- TextureKind textureKind = _fontAtlas.TextureKind; float g_left = 0; float g_top = 0; int baseLine = (int)Math.Round((float)top + _font.AscentInPixels); int bottom = (int)Math.Round((float)top + _font.AscentInPixels - _font.DescentInPixels); float acc_x = 0; //local accumulate x float acc_y = 0; //local accumulate y int seqLen = glyphPlanSeq.Count; for (int i = 0; i < seqLen; ++i) { UnscaledGlyphPlan glyph = glyphPlanSeq[i]; Typography.Rendering.TextureGlyphMapData glyphData; if (!_fontAtlas.TryGetGlyphMapData(glyph.glyphIndex, out glyphData)) { //if no glyph data, we should render a missing glyph *** continue; } //-------------------------------------- //TODO: review precise height in float //-------------------------------------- //paint src rect //temp fix, glyph texture img is not flipped //but the associate info is flipped => so //we need remap exact Y from the image Rectangle srcRect = new Rectangle(glyphData.Left, _glBmp.Height - (glyphData.Top + glyphData.Height), glyphData.Width, glyphData.Height); //offset length from 'base-line' float x_offset = acc_x + (float)Math.Round(glyph.OffsetX * px_scale - glyphData.TextureXOffset); float y_offset = acc_y + (float)Math.Round(glyph.OffsetY * px_scale - glyphData.TextureYOffset) + srcRect.Height; //*** //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- g_left = (float)(left + x_offset); g_top = (float)(bottom - y_offset); //*** acc_x += (float)Math.Round(glyph.AdvanceX * px_scale); //g_x = (float)Math.Round(g_x); //*** g_top = (float)Math.Floor(g_top);//adjust to integer num *** // _vboBuilder.WriteVboToList(ref srcRect, g_left, g_top); } //--- //copy vbo result and store into renderVx float[] vertexList = _vboBuilder._buffer.ToArray(); ushort[] indexList = _vboBuilder._indexList.ToArray(); //--- renderVxFormattedString.IndexArrayCount = _vboBuilder._indexList.Count; renderVxFormattedString.IndexArray = _vboBuilder._indexList.ToArray(); renderVxFormattedString.VertexCoords = _vboBuilder._buffer.ToArray(); _vboBuilder.Clear(); }
public void PrepareStringForRenderVx(RenderVxFormattedString renderVx, char[] buffer, int startAt, int len) { 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 float x = 0; float y = 0; y -= ((recommendLineSpacing) * scale); renderVx.RecommmendLineSpacing = (int)(recommendLineSpacing * scale); // 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; //*** _glsx.SetAssociatedTextureInfo(_glBmp); // vboBufferList2.Clear(); indexList2.Clear(); float acc_x = 0; float acc_y = 0; for (int i = glyphPlanSeq.startAt; i < endBefore; ++i) { UnscaledGlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq); UnscaledGlyphPlan glyph = glyphPlanList[i]; Typography.Rendering.TextureFontGlyphData glyphData; if (!_fontAtlas.TryGetGlyphDataByGlyphIndex(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); float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale); //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- g_x = (float)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x g_y = (float)(y + (ngy - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); acc_x += (float)Math.Round(glyph.AdvanceX * scale); //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.WriteVboToList( vboBufferList2, indexList2, ref srcRect, g_x, g_y, scaleFromTexture); break; } } //--------- DrawingGL.GLRenderVxFormattedString renderVxFormattedString = (DrawingGL.GLRenderVxFormattedString)renderVx; renderVxFormattedString.IndexArray = indexList2.ToArray(); renderVxFormattedString.VertexCoords = vboBufferList2.ToArray(); renderVxFormattedString.VertexCount = indexList2.Count; }
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; float g_x = 0; float g_y = 0; int baseY = (int)Math.Round(y); int n = glyphPlanSeq.len; int endBefore = glyphPlanSeq.startAt + n; //------------------------------------- _glsx.LoadTexture1(_glBmp); //------------------------------------- _vboBufferList.Clear(); //clear before use _indexList.Clear(); //clear before use float acc_x = 0; float acc_y = 0; for (int i = glyphPlanSeq.startAt; i < endBefore; ++i) { UnscaledGlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq); UnscaledGlyphPlan glyph = glyphPlanList[i]; Typography.Rendering.TextureFontGlyphData glyphData; if (!_fontAtlas.TryGetGlyphDataByGlyphIndex(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); float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale); //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- g_x = (float)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x g_y = (float)(y + (ngy - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture); acc_x += (float)Math.Round(glyph.AdvanceX * scale); //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.WriteVboToList( _vboBufferList, _indexList, ref srcRect, g_x, g_y, scaleFromTexture); break; } } //------- //we create vbo first //then render _glsx.DrawGlyphImageWithSubPixelRenderingTechnique3(_vboBufferList.ToArray(), _indexList.ToArray()); }
public ILineSegmentList BreakToLineSegments(ref TextBufferSpan textBufferSpan) { throw new NotImplementedException(); }
public void DrawString(Painter p, char[] buffer, int startAt, int len, double x, double y) { //if (_stencilBmp == null) //{ // //create a stencil bmp // _stencilBmp = new ActualBitmap(p.Width, p.Height); // _stencilBlender = new PixelProcessing.SubBitmapBlender(_stencilBmp, new PixelProcessing.PixelBlenderBGRA()); // _backPainter = AggPainter.Create(_stencilBmp); // //------ //} 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); Typeface typeface = _textServices.ResolveTypeface(_font); float scale = typeface.CalculateScaleToPixelFromPointSize(_font.SizeInPoints); int recommendLineSpacing = (int)_font.LineSpacingInPixels; //-------------------------- //TODO: //if (x,y) is left top //we need to adjust y again y -= _font.LineSpacingInPixels; // float scaleFromTexture = _finalTextureScale; TextureKind textureKind = _fontAtlas.TextureKind; float g_x = 0; float g_y = 0; int baseY = (int)Math.Round(y); //------------------------------------- //load texture //_pcx.LoadTexture1(_glBmp); //------------------------------------- float acc_x = 0; float acc_y = 0; p.DrawImage(_fontBmp, 100, 100); int seqLen = glyphPlanSeq.Count; for (int i = 0; i < seqLen; ++i) { UnscaledGlyphPlan glyph = glyphPlanSeq[i]; TextureGlyphMapData glyphData; if (!_fontAtlas.TryGetGlyphMapData(glyph.glyphIndex, out glyphData)) { //if no glyph data, we should render a missing glyph *** continue; } //-------------------------------------- //TODO: review precise height in float //-------------------------------------- int srcX, srcY, srcW, srcH; glyphData.GetRect(out srcX, out srcY, out srcW, out srcH); float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale); //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- g_x = (float)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x g_y = (float)(y + (ngy - glyphData.TextureYOffset + srcH) * scaleFromTexture); acc_x += (float)Math.Round(glyph.AdvanceX * scale); //g_x = (float)Math.Round(g_x); g_y = (float)Math.Floor(g_y); //p.RenderQuality = RenderQuality.Fast; //*** the atlas is inverted so... //p.DrawImage(_fontBmp, g_x, g_y, srcX, _fontBmp.Height - (srcY), srcW, srcH); //p.DrawImage(_fontBmp, g_x, g_y); //1. draw to back buffer //_backPainter.DrawImage(_fontBmp, g_x, g_y, srcX, _fontBmp.Height - (srcY), srcW, srcH); //2. then copy content to this //p.DrawImage(_stencilBmp, 100, 100); p.DrawImage(_fontBmp, g_x, g_y, srcX, _fontBmp.Height - (srcY + srcH), srcW, srcH); switch (textureKind) { default: break; case TextureKind.StencilLcdEffect: { } break; } //copy some part from the bitmap //switch (textureKind) //{ // case TextureKind.Msdf: // _pcx.DrawSubImageWithMsdf(_glBmp, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // case TextureKind.StencilGreyScale: // //stencil gray scale with fill-color // _pcx.DrawGlyphImageWithStecil(_glBmp, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // case TextureKind.Bitmap: // _pcx.DrawSubImage(_glBmp, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; // case TextureKind.StencilLcdEffect: // _pcx.WriteVboToList( // _vboBufferList, // _indexList, // ref srcRect, // g_x, // g_y, // scaleFromTexture); // break; //} } //------- //we create vbo first //then render }
public void DrawString(Painter p, char[] buffer, int startAt, int len, double x, double y) { AggPainter painter = p as AggPainter; if (painter == null) { return; } // int width = painter.Width; int height = painter.Height; if (!_pixelBlenderSetup) { SetupMaskPixelBlender(width, height); _pixelBlenderSetup = true; } 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 = 1;// _fontAtlas.TargetTextureScale; int recommendLineSpacing = (int)_font.LineSpacingInPixels; //-------------------------- //TODO: //if (x,y) is left top //we need to adjust y again y -= _font.LineSpacingInPixels; // float scaleFromTexture = _finalTextureScale; TextureKind textureKind = _fontAtlas.TextureKind; float gx = 0; float gy = 0; int baseY = (int)Math.Round(y); float acc_x = 0; float acc_y = 0; int lineHeight = (int)_font.LineSpacingInPixels;//temp //painter.DestBitmapBlender.OutputPixelBlender = maskPixelBlenderPerCompo; //change to new blender painter.DestBitmapBlender.OutputPixelBlender = _maskPixelBlenderPerCompo; //change to new blender int seqLen = glyphPlanSeq.Count; for (int i = 0; i < seqLen; ++i) { UnscaledGlyphPlan glyph = glyphPlanSeq[i]; TextureGlyphMapData glyphData; if (!_fontAtlas.TryGetGlyphMapData(glyph.glyphIndex, out glyphData)) { //if no glyph data, we should render a missing glyph *** continue; } //-------------------------------------- //TODO: review precise height in float //-------------------------------------- int srcX, srcY, srcW, srcH; glyphData.GetRect(out srcX, out srcY, out srcW, out srcH); float ngx = acc_x + (float)Math.Round(glyph.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyph.OffsetY * scale); //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- gx = (float)(x + (ngx - glyphData.TextureXOffset) * scaleFromTexture); //ideal x gy = (float)(y + (ngy - glyphData.TextureYOffset - srcH + lineHeight) * scaleFromTexture); acc_x += (float)Math.Round(glyph.AdvanceX * scale); gy = (float)Math.Floor(gy) + lineHeight; //clear with solid black color //_maskBufferPainter.Clear(Color.Black); _maskBufferPainter.FillRect(gx - 1, gy - 1, srcW + 2, srcH + 2, Color.Black); //draw 'stencil' glyph on mask-buffer _maskBufferPainter.DrawImage(_fontBmp, gx, gy, srcX, _fontBmp.Height - (srcY), srcW, srcH); //select component to render this need to render 3 times for lcd technique //1. B _maskPixelBlenderPerCompo.SelectedMaskComponent = PixelBlenderColorComponent.B; _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.B; painter.FillRect(gx + 1, gy, srcW, srcH); //2. G _maskPixelBlenderPerCompo.SelectedMaskComponent = PixelBlenderColorComponent.G; _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.G; painter.FillRect(gx + 1, gy, srcW, srcH); //3. R _maskPixelBlenderPerCompo.SelectedMaskComponent = PixelBlenderColorComponent.R; _maskPixelBlenderPerCompo.EnableOutputColorComponent = EnableOutputColorComponent.R; painter.FillRect(gx + 1, gy, srcW, srcH); } }
public PixelFarm.Drawing.Size MeasureString(ref TextBufferSpan textBufferSpan, RequestFont font) { return(WinGdiTextService.MeasureString(textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, textBufferSpan.len, font)); }
//============================================== public static void CalculateGlyphAdvancePos(ref TextBufferSpan textBufferSpan, RequestFont font, int[] outputGlyphAdvances, out int outputTotalW) { unsafe { outputTotalW = 0; int len = textBufferSpan.len; if (len == 0) { return; } WinGdiFont winfont = SetFont(font); //ushort* glyhIndics = stackalloc ushort[len]; //fixed (char* s = &str[startAt]) //{ // NativeTextWin32.GetGlyphIndices( // win32MemDc.DC, // s, // len, // glyhIndics, // 0); //} byte[] encoding = s_en.GetBytes( textBufferSpan.GetRawCharBuffer(), textBufferSpan.start, len); NativeTextWin32.FontABC[] abcWidths = winfont.GetInteralABCArray(); int totalW = 0; for (int i = 0; i < len; ++i) { //ushort glyphIndex = *(glyhIndics + i); int enc_index = encoding[i]; if (enc_index == 0) { break;//? } totalW += outputGlyphAdvances[i] = abcWidths[enc_index].Sum; } } //unsafe //{ // SetFont(font); // NativeTextWin32.GCP_RESULTS gpcResult = new NativeTextWin32.GCP_RESULTS(); // int[] caretpos = new int[len]; // uint[] lpOrder = new uint[len]; // int[] lpDx = new int[len]; // fixed (int* lpdx_h = &lpDx[0]) // fixed (uint* lpOrder_h = &lpOrder[0]) // fixed (int* caretpos_h = &caretpos[0]) // fixed (char* str_h = &str[startAt]) // { // gpcResult.lpCaretPos = caretpos_h; // gpcResult.lpOrder = lpOrder_h; // gpcResult.lpDx = lpdx_h; // //gpcResult. // ////gpcResult.lpCaretPos = // NativeTextWin32.GetCharacterPlacement( // win32MemDc.DC, // str_h, // len, // len, ref gpcResult, 0); // } //} }
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); }
internal Size MeasureStringSize(char[] buffer, int startIndex, int len, RequestFont f) { TextBufferSpan textSpan = new TextBufferSpan(buffer, startIndex, len); return(this.SampleIFonts.MeasureString(ref textSpan, f)); }
public void DrawString(char[] buffer, int startAt, int len, double left, double top) { _vboBuilder.Clear(); _vboBuilder.SetTextureInfo(_glBmp.Width, _glBmp.Height, _glBmp.IsYFlipped, _pcx.OriginKind); // _pcx.FontFillColor = _painter.FontFillColor; _pcx.LoadTexture(_glBmp); //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 px_scale = _px_scale; //-------------------------- //TODO: //if (x,y) is left top //we need to adjust y again float scaleFromTexture = 1; TextureKind textureKind = _fontAtlas.TextureKind; float g_left = 0; float g_top = 0; int baseLine = (int)Math.Round((float)top + _font.AscentInPixels); int bottom = (int)Math.Round((float)top + _font.AscentInPixels - _font.DescentInPixels); float acc_x = 0; //local accumulate x float acc_y = 0; //local accumulate y #if DEBUG if (s_dbugShowMarkers) { if (s_dbugShowGlyphTexture) { //show original glyph texture at top _pcx.DrawImage(_glBmp, 0, 0); } //draw red-line-marker for baseLine _painter.StrokeColor = Color.Red; _painter.DrawLine(left, baseLine, left + 200, baseLine); // //draw magenta-line-marker for bottom line _painter.StrokeColor = Color.Magenta; int bottomLine = (int)Math.Round((float)top + _font.LineSpacingInPixels); _painter.DrawLine(left, bottomLine, left + 200, bottomLine); //draw blue-line-marker for top line _painter.StrokeColor = Color.Blue; _painter.DrawLine(0, top, left + 200, top); } DrawingTechnique = s_dbugDrawTechnique; //for debug only UseVBO = s_dbugUseVBO; //for debug only #endif int seqLen = glyphPlanSeq.Count; for (int i = 0; i < seqLen; ++i) { UnscaledGlyphPlan glyph = glyphPlanSeq[i]; Typography.Rendering.TextureGlyphMapData glyphData; if (!_fontAtlas.TryGetGlyphMapData(glyph.glyphIndex, out glyphData)) { //if no glyph data, we should render a missing glyph *** continue; } //-------------------------------------- //TODO: review precise height in float //-------------------------------------- //paint src rect //temp fix, glyph texture img is not flipped //but the associate info is flipped => so //we need remap exact Y from the image Rectangle srcRect = new Rectangle(glyphData.Left, _glBmp.Height - (glyphData.Top + glyphData.Height), glyphData.Width, glyphData.Height); //offset length from 'base-line' float x_offset = acc_x + (float)Math.Round(glyph.OffsetX * px_scale - glyphData.TextureXOffset); float y_offset = acc_y + (float)Math.Round(glyph.OffsetY * px_scale - glyphData.TextureYOffset) + srcRect.Height; //*** //NOTE: // -glyphData.TextureXOffset => restore to original pos // -glyphData.TextureYOffset => restore to original pos //-------------------------- g_left = (float)(left + x_offset); g_top = (float)(bottom - y_offset); //*** acc_x += (float)Math.Round(glyph.AdvanceX * px_scale); //g_x = (float)Math.Round(g_x); //*** g_top = (float)Math.Floor(g_top);//adjust to integer num *** #if DEBUG if (s_dbugShowMarkers) { if (s_dbugShowGlyphTexture) { //draw yellow-rect-marker on original texture _painter.DrawRectangle(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, Color.Yellow); } //draw debug-rect box at target glyph position _painter.DrawRectangle(g_left, g_top, srcRect.Width, srcRect.Height, Color.Black); _painter.StrokeColor = Color.Blue; //restore } #endif if (textureKind == TextureKind.Msdf) { _pcx.DrawSubImageWithMsdf(_glBmp, ref srcRect, g_left, g_top, scaleFromTexture); } else { switch (DrawingTechnique) { case GlyphTexturePrinterDrawingTechnique.Stencil: if (UseVBO) { _vboBuilder.WriteVboToList( ref srcRect, g_left, g_top); } else { //stencil gray scale with fill-color _pcx.DrawGlyphImageWithStecil(_glBmp, ref srcRect, g_left, g_top, scaleFromTexture); } break; case GlyphTexturePrinterDrawingTechnique.Copy: if (UseVBO) { _vboBuilder.WriteVboToList( ref srcRect, g_left, g_top); } else { _pcx.DrawSubImage(_glBmp, ref srcRect, g_left, g_top, 1); } break; case GlyphTexturePrinterDrawingTechnique.LcdSubPixelRendering: if (UseVBO) { _vboBuilder.WriteVboToList( ref srcRect, g_left, g_top); } else { _pcx.DrawGlyphImageWithSubPixelRenderingTechnique2_GlyphByGlyph( ref srcRect, g_left, g_top, 1); } break; } } } //------------------------------------------- // if (UseVBO) { switch (DrawingTechnique) { case GlyphTexturePrinterDrawingTechnique.Copy: _pcx.DrawGlyphImageWithCopy_VBO(_vboBuilder); break; case GlyphTexturePrinterDrawingTechnique.LcdSubPixelRendering: _pcx.DrawGlyphImageWithSubPixelRenderingTechnique3_DrawElements(_vboBuilder); break; case GlyphTexturePrinterDrawingTechnique.Stencil: _pcx.DrawGlyphImageWithStecil_VBO(_vboBuilder); break; } _vboBuilder.Clear(); } }