mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-30 22:49:53 +08:00
[Font] Implement sceFontGetVerticalLayout (#492)
Add sceFontGetVerticalLayout (NID: 3BrWWFU+4ts) to the Font module, completing the vertical-text counterpart to the existing GetHorizontalLayout. The SceFontVerticalLayout structure is three floats (baseline, lineAdvance, decorationExtent) interpreted for vertical writing such as CJK text rendered top-to-bottom. - Write baseline=8.0f, lineAdvance=16.0f, decorationExtent=0.0f - Validate output pointer and return INVALID_ARGUMENT on null - Return MEMORY_FAULT when guest writes fail Tests: - GetVerticalLayout_WritesExactlyThreeFloats with sentinel guard - GetVerticalLayout_NullBuffer_ReturnsInvalidArgument NID sourced via: python scripts/aerolib_catalog.py lookup sceFontGetVerticalLayout Co-authored-by: tru3 <tru3@tru3.com>
This commit is contained in:
@@ -153,6 +153,37 @@ public static class FontExports
|
||||
return SetSuccess(ctx);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "3BrWWFU+4ts",
|
||||
ExportName = "sceFontGetVerticalLayout",
|
||||
Target = Generation.Gen5,
|
||||
LibraryName = "libSceFont")]
|
||||
public static int GetVerticalLayout(CpuContext ctx)
|
||||
{
|
||||
var layoutAddress = ctx[CpuRegister.Rsi];
|
||||
if (layoutAddress == 0)
|
||||
{
|
||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
// Baseline (horizontal offset), line advance, decoration extent.
|
||||
// Mirrors the same three-float layout as GetHorizontalLayout, but
|
||||
// interpreted for vertical writing (e.g. CJK text rendered top-to-bottom).
|
||||
var values = new[] { 8.0f, 16.0f, 0.0f };
|
||||
for (var index = 0; index < values.Length; index++)
|
||||
{
|
||||
if (!TryWriteUInt32(
|
||||
ctx,
|
||||
layoutAddress + (ulong)(index * sizeof(float)),
|
||||
BitConverter.SingleToUInt32Bits(values[index])))
|
||||
{
|
||||
return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||
}
|
||||
}
|
||||
|
||||
return SetSuccess(ctx);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "cKYtVmeSTcw",
|
||||
ExportName = "sceFontOpenFontSet",
|
||||
|
||||
@@ -41,4 +41,32 @@ public sealed class FontExportsTests
|
||||
Assert.Equal(0.0f, BinaryPrimitives.ReadSingleLittleEndian(layout[8..]));
|
||||
Assert.Equal(Sentinel, BinaryPrimitives.ReadUInt32LittleEndian(layout[12..]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVerticalLayout_WritesExactlyThreeFloats()
|
||||
{
|
||||
const uint Sentinel = 0xDEADBEEF;
|
||||
Span<byte> sentinelBytes = stackalloc byte[sizeof(uint)];
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(sentinelBytes, Sentinel);
|
||||
Assert.True(_ctx.Memory.TryWrite(LayoutAddress + 12, sentinelBytes));
|
||||
|
||||
_ctx[CpuRegister.Rsi] = LayoutAddress;
|
||||
Assert.Equal(0, FontExports.GetVerticalLayout(_ctx));
|
||||
|
||||
Span<byte> layout = stackalloc byte[16];
|
||||
Assert.True(_ctx.Memory.TryRead(LayoutAddress, layout));
|
||||
Assert.Equal(8.0f, BinaryPrimitives.ReadSingleLittleEndian(layout));
|
||||
Assert.Equal(16.0f, BinaryPrimitives.ReadSingleLittleEndian(layout[4..]));
|
||||
Assert.Equal(0.0f, BinaryPrimitives.ReadSingleLittleEndian(layout[8..]));
|
||||
Assert.Equal(Sentinel, BinaryPrimitives.ReadUInt32LittleEndian(layout[12..]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVerticalLayout_NullBuffer_ReturnsInvalidArgument()
|
||||
{
|
||||
_ctx[CpuRegister.Rsi] = 0;
|
||||
Assert.Equal(
|
||||
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
|
||||
FontExports.GetVerticalLayout(_ctx));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user