<commit_before>/*
 * Copyright (C) 2011 <NAME> <<EMAIL>>
 *
 * This file is part of libass.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <fribidi/fribidi.h>

#include "ass_render.h"
#include "ass_shaper.h"

/**
 * \brief Print version information
 */
void ass_shaper_info(ASS_Library *lib)
{
    ass_msg(lib, MSGL_V, "Complex text layout enabled, using FriBidi "
            FRIBIDI_VERSION);
}

/**
 * \brief Shape an event's text. Calculates directional runs and shapes them.
 * \param text_info event's text
 * \param ctypes returns character types
 * \param emblevels returns embedding levels (directional runs)
 */
void ass_shaper_shape(TextInfo *text_info, FriBidiCharType *ctypes,
                      FriBidiLevel *emblevels)
{
    int i, last_break;
    FriBidiParType dir;
    FriBidiChar *event_text = calloc(sizeof(*event_text), text_info->length);
    GlyphInfo *glyphs = text_info->glyphs;

    // Get bidi character types and embedding levels
    last_break = 0;
    for (i = 0; i < text_info->length; i++) {
        event_text[i] = glyphs[i].symbol;
        // embedding levels should be calculated paragraph by paragraph
        if (glyphs[i].symbol == '\n' || i == text_info->length - 1) {
            //printf("paragraph from %d to %d\n", last_break, i);
            dir = FRIBIDI_PAR_ON;
            fribidi_get_bidi_types(event_text + last_break, i - last_break + 1,
                    ctypes + last_break);
            fribidi_get_par_embedding_levels(ctypes + last_break,
                    i - last_break + 1, &dir, emblevels + last_break);
            last_break = i + 1;
        }
    }

#if 0
    printf("levels ");
    for (i = 0; i < text_info->length; i++) {
        printf("%d:%d ", ctypes[i], emblevels[i]);
    }
    printf("\n");
#endif

    // Call FriBidi's glyph mirroring shaper.
    // This shaper implements rule L4 of the bidi algorithm
    fribidi_shape_mirroring(emblevels, text_info->length, event_text);
    for (i = 0; i < text_info->length; i++) {
        glyphs[i].symbol = event_text[i];
    }

    // XXX: insert HarfBuzz shaper here

    // Skip direction override characters
    // NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't
    // been implemented yet
    for (i = 0; i < text_info->length; i++) {
        if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) {
            glyphs[i].symbol = 0;
            glyphs[i].skip++;
        }
    }

    free(event_text);
}

void ass_shaper_reorder(TextInfo *text_info, FriBidiCharType *ctypes,
                        FriBidiLevel *emblevels, FriBidiStrIndex *cmap)
{
    int i;
    FriBidiParType dir;

    // Initialize reorder map
    for (i = 0; i < text_info->length; i++)
        cmap[i] = i;

    // Create reorder map line-by-line<commit_msg>Hook up FriBidi's simple Arabic shaper<commit_after>/*
 * Copyright (C) 2011 <NAME> <<EMAIL>>
 *
 * This file is part of libass.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <fribidi/fribidi.h>

#include "ass_render.h"
#include "ass_shaper.h"

/**
 * \brief Print version information
 */
void ass_shaper_info(ASS_Library *lib)
{
    ass_msg(lib, MSGL_V, "Complex text layout enabled, using FriBidi "
            FRIBIDI_VERSION);
}

/**
 * \brief Shape an event's text. Calculates directional runs and shapes them.
 * \param text_info event's text
 * \param ctypes returns character types
 * \param emblevels returns embedding levels (directional runs)
 */
void ass_shaper_shape(TextInfo *text_info, FriBidiCharType *ctypes,
                      FriBidiLevel *emblevels)
{
    int i, last_break;
    FriBidiParType dir;
    FriBidiChar *event_text = calloc(sizeof(*event_text), text_info->length);
    FriBidiJoiningType *joins = calloc(sizeof(*joins), text_info->length);
    GlyphInfo *glyphs = text_info->glyphs;

    // Get bidi character types and embedding levels
    last_break = 0;
    for (i = 0; i < text_info->length; i++) {
        event_text[i] = glyphs[i].symbol;
        // embedding levels should be calculated paragraph by paragraph
        if (glyphs[i].symbol == '\n' || i == text_info->length - 1) {
            //printf("paragraph from %d to %d\n", last_break, i);
            dir = FRIBIDI_PAR_ON;
            fribidi_get_bidi_types(event_text + last_break, i - last_break + 1,
                    ctypes + last_break);
            fribidi_get_par_embedding_levels(ctypes + last_break,
                    i - last_break + 1, &dir, emblevels + last_break);
            last_break = i + 1;
        }
    }

#if 0
    printf("levels ");
    for (i = 0; i < text_info->length; i++) {
        printf("%d:%d ", ctypes[i], emblevels[i]);
    }
    printf("\n");
#endif

    // Use FriBidi's shaper for mirroring and simple Arabic shaping
    fribidi_get_joining_types(event_text, text_info->length, joins);
    fribidi_join_arabic(ctypes, text_info->length, emblevels, joins);
    fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, emblevels,
            text_info->length, joins, event_text);

    // XXX: insert HarfBuzz shaper here

    // Update glyphs
    for (i = 0; i < text_info->length; i++) {
        glyphs[i].symbol = event_text[i];
        // Skip direction override characters
        // NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't
        // been implemented yet
        if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) {
            glyphs[i].symbol = 0;
            glyphs[i].skip++;
        }
    }

    free(joins);
    free(event_text);
}

void ass_shaper_reorder(TextInfo *text_info, FriBidiCharType *ctypes,
                        FriBidiLevel *emblevels, FriBidiStrIndex *cmap)
{
    int i;
    FriBidiParType dir;

    // Initialize reorder map
    for (i = 0; i < text_info->length; i++)
        cmap[i] = i;

    // Create reorder map line-by-line
{'fraction_non_alphanumeric': 0.10382059800664452, 'fraction_numerical': 0.006644518272425249, 'mean_word_length': 2.828828828828829, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7515303', 'n_tokens_mistral': 2424, 'n_tokens_neox': 2264, 'n_words': 720}