Files
sharpemu/tests/SharpEmu.Libs.Tests/Font/FontExportsTests.cs
T
h4sht 9be6f85ef0 [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>
2026-07-21 18:18:16 +03:00

73 lines
2.7 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Buffers.Binary;
using SharpEmu.HLE;
using SharpEmu.Libs.Font;
using Xunit;
namespace SharpEmu.Libs.Tests.Font;
public sealed class FontExportsTests
{
private const ulong Base = 0x1_0000_0000;
private const ulong LayoutAddress = Base + 0x100;
private readonly FakeCpuMemory _memory = new(Base, 0x1000);
private readonly CpuContext _ctx;
public FontExportsTests()
{
_ctx = new CpuContext(_memory, Generation.Gen5);
}
// SceFontHorizontalLayout is three floats; the sentinel directly after
// them must survive the call.
[Fact]
public void GetHorizontalLayout_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.GetHorizontalLayout(_ctx));
Span<byte> layout = stackalloc byte[16];
Assert.True(_ctx.Memory.TryRead(LayoutAddress, layout));
Assert.Equal(12.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_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));
}
}