fix retained glyph bottom clipping
This commit is contained in:
@@ -34,8 +34,23 @@ public readonly record struct AdvTextLayoutPresentationBinding(
|
||||
int ResetCursorX,
|
||||
int ResetCursorY);
|
||||
|
||||
/// <summary>
|
||||
/// Transient publication crop. Native records retain measured cell edges, but a backend mask/effect can
|
||||
/// carry ink outside that cell. Keeping the expanded crop separate preserves the native layout ABI.
|
||||
/// </summary>
|
||||
public readonly record struct AdvRetainedGlyphPresentationRect(
|
||||
int Left,
|
||||
int Top,
|
||||
int Right,
|
||||
int Bottom)
|
||||
{
|
||||
public int Width => Right - Left;
|
||||
public int Height => Bottom - Top;
|
||||
}
|
||||
|
||||
public readonly record struct AdvRetainedGlyphPlacement(
|
||||
AdvRetainedGlyphRecord Record,
|
||||
AdvRetainedGlyphPresentationRect PresentationRect,
|
||||
int LayoutOriginX,
|
||||
int LayoutOriginY);
|
||||
|
||||
|
||||
@@ -38,7 +38,30 @@ public sealed class RetainedAdvTextLayoutPresentation
|
||||
int first = _glyphs.Count;
|
||||
foreach (AdvRetainedGlyphRecord record in records)
|
||||
_glyphs.Add(new AdvRetainedGlyphPlacement(
|
||||
record, layoutOriginX, layoutOriginY));
|
||||
record,
|
||||
new AdvRetainedGlyphPresentationRect(
|
||||
record.Left, record.Top, record.Right, record.Bottom),
|
||||
layoutOriginX,
|
||||
layoutOriginY));
|
||||
return first;
|
||||
}
|
||||
|
||||
public int Append(
|
||||
IReadOnlyList<AdvRetainedGlyphRecord> records,
|
||||
IReadOnlyList<AdvRetainedGlyphPresentationRect> presentationRects,
|
||||
int layoutOriginX,
|
||||
int layoutOriginY)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(records);
|
||||
ArgumentNullException.ThrowIfNull(presentationRects);
|
||||
if (presentationRects.Count != records.Count)
|
||||
throw new ArgumentException(
|
||||
"Every retained glyph record requires one presentation rectangle.",
|
||||
nameof(presentationRects));
|
||||
int first = _glyphs.Count;
|
||||
for (int index = 0; index < records.Count; index++)
|
||||
_glyphs.Add(new AdvRetainedGlyphPlacement(
|
||||
records[index], presentationRects[index], layoutOriginX, layoutOriginY));
|
||||
return first;
|
||||
}
|
||||
|
||||
@@ -71,16 +94,16 @@ public sealed class RetainedAdvTextLayoutPresentation
|
||||
private void Bind(GfxState gfx, int index)
|
||||
{
|
||||
AdvRetainedGlyphPlacement placement = _glyphs[index];
|
||||
AdvRetainedGlyphRecord record = placement.Record;
|
||||
if (record.Width <= 0 || record.Height <= 0) return;
|
||||
AdvRetainedGlyphPresentationRect rect = placement.PresentationRect;
|
||||
if (rect.Width <= 0 || rect.Height <= 0) return;
|
||||
gfx.BindDraw(
|
||||
checked(Binding.FirstObjectHandle + index),
|
||||
Binding.SourceSurfaceSlot,
|
||||
record.Left,
|
||||
record.Top,
|
||||
record.Width,
|
||||
record.Height,
|
||||
checked(placement.LayoutOriginX + record.Left),
|
||||
checked(placement.LayoutOriginY + record.Top));
|
||||
rect.Left,
|
||||
rect.Top,
|
||||
rect.Width,
|
||||
rect.Height,
|
||||
checked(placement.LayoutOriginX + rect.Left),
|
||||
checked(placement.LayoutOriginY + rect.Top));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public readonly record struct GlyphTextLayoutOptions(
|
||||
|
||||
public sealed record GlyphTextLayoutResult(
|
||||
IReadOnlyList<AdvRetainedGlyphRecord> Records,
|
||||
IReadOnlyList<AdvRetainedGlyphPresentationRect> PresentationRects,
|
||||
int CursorX,
|
||||
int CursorY,
|
||||
int ConsumedGlyphs,
|
||||
@@ -40,6 +41,8 @@ public sealed class RetainedGlyphLayoutEngine
|
||||
ArgumentNullException.ThrowIfNull(destination);
|
||||
ArgumentNullException.ThrowIfNull(glyphs);
|
||||
var records = new List<AdvRetainedGlyphRecord>(glyphs.Count);
|
||||
var presentationRects =
|
||||
new List<AdvRetainedGlyphPresentationRect>(glyphs.Count);
|
||||
int cursorX = options.CursorX;
|
||||
int cursorY = options.CursorY;
|
||||
int wrappedLines = 0;
|
||||
@@ -81,11 +84,59 @@ public sealed class RetainedGlyphLayoutEngine
|
||||
AgeGlyphMaskCompositor.DrawGlyph(
|
||||
destination, mask, cursorX, cursorY, request.PixelHeight, options.Style);
|
||||
records.Add(new AdvRetainedGlyphRecord(0, cursorX, cursorY, right, bottom));
|
||||
presentationRects.Add(PresentationRect(
|
||||
destination.Height,
|
||||
mask,
|
||||
cursorX,
|
||||
cursorY,
|
||||
right,
|
||||
bottom,
|
||||
request.PixelHeight,
|
||||
options.Style));
|
||||
cursorX = checked(cursorX + mask.CellAdvanceX);
|
||||
cursorY = checked(cursorY + mask.CellAdvanceY);
|
||||
}
|
||||
|
||||
return new GlyphTextLayoutResult(
|
||||
records, cursorX, cursorY, records.Count, wrappedLines, observed, stopped);
|
||||
records, presentationRects, cursorX, cursorY, records.Count,
|
||||
wrappedLines, observed, stopped);
|
||||
}
|
||||
|
||||
private static AdvRetainedGlyphPresentationRect PresentationRect(
|
||||
int surfaceHeight,
|
||||
GlyphMask mask,
|
||||
int cellLeft,
|
||||
int cellTop,
|
||||
int cellRight,
|
||||
int cellBottom,
|
||||
int topToBaseline,
|
||||
AdvTextStyle style)
|
||||
{
|
||||
int minimumEffectY = 0;
|
||||
int maximumEffectY = 0;
|
||||
if (style.RenderMode == 1)
|
||||
{
|
||||
minimumEffectY = Math.Min(0, style.EffectOffsetY);
|
||||
maximumEffectY = Math.Max(0, style.EffectOffsetY);
|
||||
}
|
||||
else if (style.RenderMode == 3)
|
||||
{
|
||||
foreach ((int _, int y) in AgeGlyphMaskCompositor.GetMode3OutlineOffsets(
|
||||
style.EffectOffsetX, style.EffectOffsetY))
|
||||
{
|
||||
minimumEffectY = Math.Min(minimumEffectY, y);
|
||||
maximumEffectY = Math.Max(maximumEffectY, y);
|
||||
}
|
||||
}
|
||||
|
||||
int inkTop = checked(
|
||||
cellTop + topToBaseline - mask.OriginY + minimumEffectY);
|
||||
int inkBottom = checked(
|
||||
cellTop + topToBaseline - mask.OriginY + mask.Height + maximumEffectY);
|
||||
return new AdvRetainedGlyphPresentationRect(
|
||||
cellLeft,
|
||||
Math.Clamp(Math.Min(cellTop, inkTop), 0, surfaceHeight),
|
||||
cellRight,
|
||||
Math.Clamp(Math.Max(cellBottom, inkBottom), 0, surfaceHeight));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user