5180 fichiers 38.5 Mo 0 téléchargements 218 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / common / native-text / layoutNativeRuns.ts
layoutNativeRuns.ts 2.6 Ko Télécharger le fichier
/** A piece of text in one style (`style` indexes the caller's fonts). */
export interface NativeRun {
    text: string;
    style: number;
}

/** A run placed on a line: `x` is its left edge in pixels. */
export interface PlacedNativeRun extends NativeRun {
    x: number;
}

export interface NativeRunsLayout {
    lines: PlacedNativeRun[][];
    width: number;
}

/**
 * Lays styled runs out like one AIR TextField: words flow across run boundaries, a line breaks at the last space that fits (the
 * space stays on the line it ends), and a word longer than a whole line is split by characters. `measure` gives the advance of a
 * text in a style; `width` is the line width (Infinity for one line).
 */
export const layoutNativeRuns = (runs: NativeRun[], width: number, measure: (style: number, text: string) => number): NativeRunsLayout => {
    const lines: PlacedNativeRun[][] = [[]];
    let x = 0;

    const place = (style: number, text: string) => {
        const line = lines[lines.length - 1];
        const last = line[line.length - 1];

        if (last && last.style === style) last.text += text;
        else line.push({ text, style, x });

        x += measure(style, text);
    };

    const breakLine = () => {
        lines.push([]);
        x = 0;
    };

    const fitCharacters = (style: number, text: string, room: number) => {
        let count = 0;

        while (count < text.length && measure(style, text.slice(0, count + 1)) <= room) count++;

        return count;
    };

    for (const run of runs) {
        for (const token of run.text.split(/(\s+)/).filter(Boolean)) {
            const tokenWidth = measure(run.style, token);

            if (/^\s+$/.test(token) || x + tokenWidth <= width) {
                place(run.style, token);
                continue;
            }

            if (x > 0 && tokenWidth <= width) {
                breakLine();
                place(run.style, token);
                continue;
            }

            // Longer than a whole line: fill the rest of this line, then as many full lines as it takes.
            let rest = token;

            while (rest) {
                const count = fitCharacters(run.style, rest, width - x) || (x > 0 ? 0 : 1);

                if (count) place(run.style, rest.slice(0, count));

                rest = rest.slice(count);

                if (rest) breakLine();
            }
        }
    }

    const lineWidth = (line: PlacedNativeRun[]) => {
        const last = line[line.length - 1];

        return last ? last.x + measure(last.style, last.text.replace(/\s+$/, '')) : 0;
    };

    return { lines, width: Math.max(0, ...lines.map(lineWidth)) };
};
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