blob: c915c7595837fb6a841c1358171304127eeffb29 [file]
/* See LICENSE file for copyright and license details. */
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "../gen/bidirectional.h"
#include "../grapheme.h"
#include "util.h"
static inline enum bidi_property
get_bidi_property(uint_least32_t cp)
{
if (likely(cp <= 0x10FFFF)) {
return (enum bidi_property)
bidi_minor[bidi_major[cp >> 8] + (cp & 0xff)];
} else {
return BIDI_PROP_L;
}
}
/*
* NOTES:
* https://unicode.org/reports/tr9/
* https://github.com/omid/Persian-Log2Vis/blob/master/bidi.php
* https://github.com/fribidi/fribidi/blob/master/lib/fribidi.h
*/
#define MAX_DEPTH 125
#include <stdio.h> /* ------------------------------------------------------------------ */
static size_t
determine_paragraph_level(const void *src, size_t srclen,
size_t (*get_codepoint)(const void *, size_t, size_t, uint_least32_t *),
size_t (*set_codepoint)(uint_least32_t, void *, size_t, size_t))
{
enum bidi_property prop;
size_t srcoff, isolate_level;
uint_least32_t cp;
for (srcoff = 0, isolate_level = 0; srcoff < srclen; ) {
srcoff += get_codepoint(src, srclen, srcoff, &cp);
prop = get_bidi_property(cp);
/* BD8/BD9 */
if ((prop == BIDI_PROP_LRI ||
prop == BIDI_PROP_RLI ||
prop == BIDI_PROP_FSI) &&
isolate_level < MAX_DEPTH) {
/* we hit an isolate initiator, increment counter */
isolate_level++;
} else if (prop == BIDI_PROP_PDI && isolate_level > 0) {
isolate_level--;
}
/* P2 */
if (isolate_level > 0) {
continue;
}
/* P3 */
if (prop == BIDI_PROP_L) {
return 0;
} else if (prop == BIDI_PROP_AL ||
prop == BIDI_PROP_R) {
return 1;
}
}
return 0;
}
static size_t
handle_paragraph(const void *src, size_t srclen, enum grapheme_bidirectional_override override,
size_t (*get_codepoint)(const void *, size_t, size_t, uint_least32_t *),
size_t (*set_codepoint)(uint_least32_t, void *, size_t, size_t),
void *dest, size_t destlen)
{
enum bidi_property prop;
size_t srcoff, destoff, paragraph_level;
fprintf(stderr, "paragraph-call: par='%.*s'\n", (int)srclen, (const char *)src);
/* determine paragraph level (rules P1-P3, HL1) */
if (override == GRAPHEME_BIDIRECTIONAL_OVERRIDE_LTR) {
paragraph_level = 0;
} else if (override == GRAPHEME_BIDIRECTIONAL_OVERRIDE_RTL) {
paragraph_level = 1;
} else { /* GRAPHEME_BIDIRECTIONAL_OVERRIDE_NONE and invalid */
paragraph_level = determine_paragraph_level(src, srclen,
get_codepoint,
set_codepoint);
}
fprintf(stderr, "\tparagraph_level=%zu\n", paragraph_level);
/* determine_explicit_levels(...); X1-X8 */
/* prepare_implicit_processing(); X9-X10, BD13 */
/* resolve_weak_types(); W1-W7 */
/* resolve_neutral_and_isolate_formatting_types() N0-N2 */
/* resolve_implicit_levels(); I1-I2 */
/* reorder_resolved_levels(); L1-L4 */
return destoff;
}
static size_t
logical_to_visual(const void *src, size_t srclen, enum grapheme_bidirectional_override override,
size_t (*get_codepoint)(const void *, size_t, size_t, uint_least32_t *),
size_t (*set_codepoint)(uint_least32_t, void *, size_t, size_t),
void *dest, size_t destlen)
{
size_t srcoff, destoff, lastparoff;
uint_least32_t cp;
for (srcoff = destoff = lastparoff = 0; srcoff < srclen; ) {
srcoff += get_codepoint(src, srclen, srcoff, &cp);
/* P1 */
if (get_bidi_property(cp) == BIDI_PROP_B ||
srcoff == srclen ||
(get_codepoint == get_codepoint_utf8 &&
srclen == SIZE_MAX && cp == 0)) {
/*
* we encountered a paragraph separator or
* reached the end of the text.
* Call the paragraph handling function on
* the paragraph including the separator.
*/
if (get_codepoint == get_codepoint_utf8) {
destoff += handle_paragraph((const char *)src + lastparoff,
srcoff - lastparoff, override,
get_codepoint, set_codepoint,
(char *)dest + destoff,
(destoff < destlen) ?
(destlen - destoff) : 0);
} else {
destoff += handle_paragraph((const uint_least32_t *)src + lastparoff,
srcoff - lastparoff, override,
get_codepoint, set_codepoint,
(uint_least32_t *)dest + destoff,
(destoff < destlen) ?
(destlen - destoff) : 0);
}
lastparoff = srcoff;
}
}
return destoff;
}
size_t
grapheme_bidirectional_logical_to_visual(const uint_least32_t *src,
size_t srclen,
enum grapheme_bidirectional_override override,
uint_least32_t *dest,
size_t destlen)
{
return logical_to_visual(src, srclen, override,
get_codepoint, set_codepoint, dest, destlen);
}
size_t
grapheme_bidirectional_logical_to_visual_utf8(const char *src, size_t srclen,
enum grapheme_bidirectional_override override,
char *dest, size_t destlen)
{
return logical_to_visual(src, srclen, override,
get_codepoint_utf8, set_codepoint_utf8,
dest, destlen);
}