Closed mgood7123 closed 2 years ago
I can't think of any reason why this would be happening. Normally each call to TextBlock.Paint should paint each run of text just once.
Out of curiosity and as an experiment, what happens if you create a new TextBlock for each paint call (instead of .Clear() and re-using the previous one).
Failing you might need to debug through it to figure out what's going on. Happy to make fixes if you can point out the issue.
I can't think of any reason why this would be happening. Normally each call to TextBlock.Paint should paint each run of text just once.
Out of curiosity and as an experiment, what happens if you create a new TextBlock for each paint call (instead of .Clear() and re-using the previous one).
Failing you might need to debug through it to figure out what's going on. Happy to make fixes if you can point out the issue.
the intent is to get RTK to draw the same block of text multiple times the exact same way each time
eg if it draws once, then all pixels it draws are drawn once
if it draws twice then all pixels that where drawn once, should be drawn twice
if you create a new TextBlock for each paint call
i get the same result
Thinking about this more... the only thing I can think of is if the actual text rasterization is reading back from the target surface and not updating some pixels if not required. And the only case I can think of when this happens is with SubpixelAntialiasing.
What happens if you remove this:
t.Edging = SKFontEdging.SubpixelAntialias;
and/or try with other values.
i tried Alias
, AntiAlias
and SubpixelAntialiasing
and i get the same results for all
var t = new Topten.RichTextKit.TextPaintOptions();
t.Edging = SKFontEdging.Alias;
block.Paint(canvas, new SKPoint(x, y), t);
var t = new Topten.RichTextKit.TextPaintOptions();
t.Edging = SKFontEdging.Antialias;
block.Paint(canvas, new SKPoint(x, y), t);
var t = new Topten.RichTextKit.TextPaintOptions();
t.Edging = SKFontEdging.SubpixelAntialias;
block.Paint(canvas, new SKPoint(x, y), t);
if i use this
void drawText(SKCanvas canvas, int n, int x, int y)
{
SKTypeface t = SKTypeface.FromFamilyName("Arial");
SKFont f = t.ToFont();
using var paint = new SKPaint(f);
paint.Color = SKColors.Silver;
paint.TextSize = 20;
for (int i = 0; i < n; i++)
{
string text = "drawn " + n + " time";
if (i != 0) text += "s";
canvas.DrawText(text, x, y, paint);
}
}
i get this which is what i expect
if i use this
void drawText(SKCanvas canvas, int n, int x, int y)
{
for (int i = 0; i < n; i++)
{
string text = "drawn " + n + " time";
if (i != 0) text += "s";
Topten.RichTextKit.TextBlock block = new();
Topten.RichTextKit.Style style = new();
style.TextColor = SKColors.Silver;
style.FontFamily = "Arial";
style.FontSize = 20;
block.AddText(text, style);
block.Paint(canvas, new SKPoint(x, y));
}
}
i get this
Failing you might need to debug through it to figure out what's going on. Happy to make fixes if you can point out the issue.
i would have no idea where to start debugging text rendering issues
i would have no idea where to start debugging text rendering issues
If you step into the TextBlock.Paint call you'll see it just draws a bunch of font runs. You just need to check the SKPaint options in there match what you're using in the case where it works.
Failing that, if you can send me a complete, ready to run (on Windows) VS project (preferably as a git repo) I'll take a look when I get a chance.
I think the problem is external to RichTextKit and related to using geometry transforms.
The same problem can be demonstrated by changing your non-RichTextKit drawText function so that it uses Translate to position the text (similarly to what RichTextKit does):
void drawText(SKCanvas canvas, int n, int x, int y)
{
SKTypeface t = SKTypeface.FromFamilyName("Arial");
SKFont f = t.ToFont();
using var paint = new SKPaint(f);
paint.Color = SKColors.Silver;
paint.TextSize = 20;
for (int i = 0; i < n; i++)
{
string text = "drawn " + n + " time";
if (i != 0) text += "s";
canvas.Save();
canvas.Translate(new SKPoint(x, y));
canvas.DrawText(text, 0, 0, paint);
canvas.Restore();
}
}
hmmm
Nice. Will you report this to Skia devs? If so, please post a link to issue here.
successfully replicated on skia fiddle
could be a problem with how the overdraw canvas is computing alpha increments
if i manually increment the alpha i get a slight improvement but still not 100% geometry replicated drawing
Topten.RichTextKit.TextBlock block = new();
Topten.RichTextKit.Style style = new();
block.AddText(text, null);
style.TextColor = new SKColor(0, 0, 0, (byte)(i + 1));
style.FontFamily = "Arial";
style.FontSize = 20;
block.ApplyStyle(0, text.Length, style);
block.Paint(offscreenAlphaSurface.Canvas, new SKPoint(x, y));
style.TextColor = SKColors.Silver;
block.ApplyStyle(0, text.Length, style);
block.Paint(offscreenSurface.Canvas, new SKPoint(x, y));
Not sure if this issue should be kept open or not
if use a manual overdraw
public class SKOverdrawCanvas4 : SKCanvasForwarder
{
SKCanvas baseCanvas;
public SKOverdrawCanvas4(SKCanvas canvas)
{
baseCanvas = canvas;
SetNativeObject(canvas);
}
public override void DrawRect(SKRect rect, SKPaint paint)
{
using SKPaint p = new();
p.Color = new(0, 0, 0, 1);
p.BlendMode = SKBlendMode.Plus;
base.DrawRect(rect, p);
}
public override void DrawRect(float x, float y, float w, float h, SKPaint paint)
{
using SKPaint p = new();
p.Color = new(0, 0, 0, 1);
p.BlendMode = SKBlendMode.Plus;
base.DrawRect(x, y, w, h, p);
}
public override void DrawText(SKTextBlob text, float x, float y, SKPaint paint)
{
using SKPaint p = new();
p.Color = new(0, 0, 0, 1);
p.BlendMode = SKBlendMode.Plus;
baseCanvas.DrawText(text, x, y, p);
}
}
then i get this
Topten.RichTextKit.TextBlock block = new();
Topten.RichTextKit.Style style = new();
style.TextColor = new SKColor(0, 255, 0, 255);
style.FontFamily = "Arial";
style.FontSize = textSize + n;
block.AddText(text, style);
block.Paint(canvas, new SKPoint(x, prevY));
and for normal text i get this
SKTypeface t = SKTypeface.FromFamilyName("Arial");
SKFont f = t.ToFont();
using var paint = new SKPaint(f);
paint.Color = new SKColor(0, 255, 0, 255);
paint.TextSize = textSize + n;
canvas.Save();
canvas.Translate(new SKPoint(x, paint.TextSize + prevY));
canvas.DrawText(text, 0, 0, paint);
canvas.Restore();
it is substantially better tho not quite perfect
if we convert the translate + drawText into a single drawText we then get this
also if we use a CPU surface (with translate + draw) instead of a GPU surface we get a much higher quality (at the cost of performance)
if we convert the translate + drawText into a single drawText we then get this
could you modify RIchTexkKit to use this?
Given this is reproducible without invoking RichTextKit, this should be logged as an issue against SkiaSharp (or perhaps Skia). This is not a RichTextKit bug.
could you add a toggle to work around this until it gets fixed in skia?
That would be a non-trivial change for what appears to be a very edge case issue. If you really need this, best bet would be to fork the repo and make the change yourself (until fixed in skia).
alright
is it normal for RTK to do partial drawing?
this is my shader
and if use this
then i get this
and if i use this
then i get this (expected result)
my full code is this