5180 fichiers 38.5 Mo 0 téléchargements 191 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / common / native-text / NativeTextRenderer.test.ts
NativeTextRenderer.test.ts 7.9 Ko Télécharger le fichier
import { describe, expect, it } from 'vitest';
import {
    air32DistanceToMask,
    applyTextFieldControlsToCutoffs,
    blendComponent,
    clampByte,
    compositeRetainedCoverage,
    compositeRetainedToOpaque,
    createRetainedBitmap,
    decodeBase64,
    finiteNumber,
    flattenQuadratic,
    float32Bits,
    float32FromBits,
    floorToTwips,
    interpolateCsmTable,
    midpoint,
    normalizeArgbColor,
    normalizeColor,
    normalizeOpaqueColor,
    normalizeTextColor,
    normalSampleCountToDensity,
    pointLineSquaredDistance,
    premultiplyColor,
    quantizeAlphaMultiplier,
    reduceLcdColor,
    resolveTextFieldCsm,
    roundRationalTiesEven,
    roundTiesEven,
    roundTiesEvenInteger,
    roundToQuarterPixel,
    setNormalRetainedCoverage
} from './NativeTextRenderer';

/**
 * The pure helpers of the native text renderer, called with a spread of inputs (the edges of each range included) and
 * pinned as snapshots. The renderer is spread over several modules; these outputs must not move when the code does.
 */

const attempt = (call: () => unknown) =>
{
    try
    {
        return call();
    }
    catch(error)
    {
        return `${(error as Error).constructor.name}: ${(error as Error).message}`;
    }
};

const round = (value: unknown): unknown => (typeof value === 'number' ? Math.round(value * 1e9) / 1e9 : Array.isArray(value) ? value.map(round) : value);

const table = <T,>(inputs: T[], call: (input: T) => unknown) => inputs.map((input) => [ JSON.stringify(input), round(attempt(() => call(input))) ]);

describe('native text numbers and colours', () =>
{
    it('rounds ties to even', () =>
    {
        expect(table([ -2.5, -1.5, -0.5, 0, 0.4, 0.5, 1.5, 2.5, 3.5, 2.4999, 1e9 + 0.5 ], (value) => [ roundTiesEven(value), roundTiesEvenInteger(value) ])).toMatchSnapshot();
        expect(table([ [ 1, 2 ], [ 3, 2 ], [ 5, 2 ], [ 7, 4 ], [ -5, 2 ], [ 1, 3 ] ] as [ number, number ][], ([ n, d ]) => roundRationalTiesEven(n, d))).toMatchSnapshot();
    });

    it('quantizes and blends alpha', () =>
    {
        expect(table([ 0, 0.001, 0.25, 0.5, 0.999, 1, -1, 2 ], (alpha) => quantizeAlphaMultiplier(alpha))).toMatchSnapshot();
        expect(table([ [ 0, 255, 255, 255 ], [ 255, 0, 255, 128 ], [ 100, 200, 128, 64 ], [ 10, 20, 255, 1 ] ] as number[][], ([ d, f, a, m ]) => blendComponent(d, f, a, m))).toMatchSnapshot();
        expect(table([ [ 0, 0, 0, 255 ], [ 255, 255, 255, 255 ], [ 255, 128, 0, 128 ], [ 10, 20, 30, 0 ] ] as number[][], (color) => premultiplyColor(color as never))).toMatchSnapshot();
        expect(table([ -3, 0, 127.5, 255, 300 ], (value) => clampByte(value))).toMatchSnapshot();
    });

    it('normalizes colours', () =>
    {
        expect(table([ 0, 0xffffff, 0x123456, 0x1000000, -1, 1.5, [ 1, 2, 3 ], [ 1, 2 ], [ 256, 0, 0 ] ] as unknown[], (color) => normalizeColor(color as never))).toMatchSnapshot();
        expect(table([ [ 0xff0000, undefined ], [ 0xff0000, 0.5 ], [ [ 1, 2, 3, 4 ], undefined ], [ [ 1, 2, 3, 4 ], 1 ], [ 0xff0000, 2 ], [ [ 1, 2, 3 ], undefined ], [ -1, undefined ] ] as unknown[][], ([ color, alpha ]) => normalizeTextColor(color as never, alpha as never))).toMatchSnapshot();
        expect(table([ 0xff112233, '#ff112233', 'ff112233', '#12345', 4294967296, -1, 1.5 ] as unknown[], (color) => normalizeArgbColor(color as never, 'background'))).toMatchSnapshot();
        expect(table([ 0xabcdef, [ 9, 8, 7, 255 ], [ 9, 8, 7, 128 ], [ 9, 8, 7 ], 0x1000000 ] as unknown[], (color) => normalizeOpaqueColor(color as never, 'foreground'))).toMatchSnapshot();
        expect(table([ 0, 1.5, Number.NaN, Number.POSITIVE_INFINITY, -2 ], (value) => finiteNumber(value, 'size'))).toMatchSnapshot();
        expect(table([ 0, 1, 7.75, -3.2, 100.125, 0.1 ], (value) => [ floorToTwips(value), roundToQuarterPixel(value) ])).toMatchSnapshot();
        expect(table([ [ 255, 0, 0, 0.5 ], [ 0, 255, 0, 1 ], [ 12, 200, 99 ], [ 0, 0, 0, 0 ] ] as number[][], ([ r, g, b, amount ]) => reduceLcdColor(r, g, b, amount))).toMatchSnapshot();
    });

    it('converts float32 values to bits and back', () =>
    {
        const values = [ 0, 1, -1, 0.1, 3.4028234663852886e38, 1e-45, Math.PI ];

        expect(table(values, (value) => float32Bits(value))).toMatchSnapshot();
        expect(table(values, (value) => float32FromBits(float32Bits(value)))).toMatchSnapshot();
        expect(attempt(() => float32Bits(Number.NaN))).toMatchSnapshot();
        expect(table([ 'AAEC', 'AQID', '', 'AA==', '!!', 'AB' ], (text) => Array.from(decodeBase64(text) as ArrayLike<number>))).toMatchSnapshot();
    });
});

describe('native text csm, density and geometry', () =>
{
    it('interpolates the csm table and applies the field controls', () =>
    {
        expect(table([ 4, 8, 11, 12.5, 24, 48, 100 ], (size) => interpolateCsmTable(size) as unknown)).toMatchSnapshot();
        expect(table([ [ 12, 0, 0, 'dark', 0 ], [ 12, 100, 0, 'dark', 0 ], [ 12, -100, 100, 'dark', 0 ], [ 24, 50, 50, 'light', 0 ], [ 9, 0, 0, 'dark', 3 ], [ 12, 400, -400, 'dark', 0 ] ] as unknown[][], ([ size, thickness, sharpness, type, hint ]) => resolveTextFieldCsm(size as number, thickness as number, sharpness as number, type as string, hint as number))).toMatchSnapshot();
        expect(attempt(() => applyTextFieldControlsToCutoffs(interpolateCsmTable(12) as never, 12, 0, 0))).toMatchSnapshot();
        expect(attempt(() => applyTextFieldControlsToCutoffs(interpolateCsmTable(12) as never, 12, 60, -40))).toMatchSnapshot();
    });

    it('turns distances and sample counts into coverage', () =>
    {
        expect(table([ [ 0, 0.5, 0.5 ], [ 0.5, 0.5, 0.5 ], [ -0.3, 0.2, 0.9 ], [ 2, 0.2, 0.9 ], [ 1, 0.1, 0.1 ] ] as number[][], ([ d, outside, inside ]) => air32DistanceToMask(d, outside, inside))).toMatchSnapshot();
        expect(table([ 0, 1, 2, 5, 8, 9, 16, 64 ], (count) => attempt(() => normalSampleCountToDensity(count)))).toMatchSnapshot();
    });

    it('measures points and flattens a quadratic curve', () =>
    {
        expect(midpoint({ x: 1, y: 2 }, { x: 4, y: 8 })).toMatchSnapshot();
        expect(table([ [ 0, 0 ], [ 5, 5 ], [ -3, 4 ], [ 10, 0 ] ] as number[][], ([ x, y ]) => pointLineSquaredDistance(x, y, { x: 0, y: 0 }, { x: 10, y: 0 }))).toMatchSnapshot();
        expect(pointLineSquaredDistance(3, 4, { x: 1, y: 1 }, { x: 1, y: 1 })).toMatchSnapshot();

        for(const mode of [ 'perpendicular', 'second-euclidean', 'second-max', 'second-sum' ])
        {
            const lines: { from: { x: number; y: number }; to: { x: number; y: number } }[] = [];

            flattenQuadratic(lines, { x: 0, y: 0 }, { x: 5, y: 10 }, { x: 10, y: 0 }, 0.25, mode, 0);

            expect([ mode, lines.length, lines.slice(0, 4).map((line) => [ round(line.from.x), round(line.from.y), round(line.to.x), round(line.to.y) ]) ]).toMatchSnapshot();
        }
    });
});

describe('native text retained bitmap', () =>
{
    it('composites coverage onto a retained bitmap and onto an opaque background', () =>
    {
        const retained = createRetainedBitmap(3, 2);

        expect(retained.length).toBe(3 * 2 * 4);

        compositeRetainedCoverage(retained, 0, [ 255, 0, 0, 255 ], 255);
        compositeRetainedCoverage(retained, 4, [ 0, 255, 0, 200 ], 128);
        compositeRetainedCoverage(retained, 8, [ 0, 0, 255, 255 ], 40);
        compositeRetainedCoverage(retained, 8, [ 255, 255, 255, 255 ], 100);
        setNormalRetainedCoverage(retained, 12, [ 10, 20, 30, 255 ], 77);
        setNormalRetainedCoverage(retained, 16, [ 200, 100, 50, 255 ], 255);
        expect(attempt(() => setNormalRetainedCoverage(retained, 20, [ 200, 100, 50, 128 ], 255))).toMatchSnapshot("translucent");

        expect(Array.from(retained)).toMatchSnapshot('retained');
        expect(Array.from(compositeRetainedToOpaque(retained, [ 255, 255, 255, 255 ]))).toMatchSnapshot('on white');
        expect(Array.from(compositeRetainedToOpaque(retained, [ 0, 0, 0, 255 ]))).toMatchSnapshot('on black');
        expect(attempt(() => compositeRetainedToOpaque(new Uint8Array(5), [ 0, 0, 0, 255 ]))).toMatchSnapshot('not rgba');
    });
});
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser