From 0a8f80debcffded53db34246881cc5d73ad0cfa5 Mon Sep 17 00:00:00 2001 From: anood Date: Thu, 26 Nov 2015 14:52:13 +0400 Subject: Add fribidi_reorder_runs() This function reorders all runs from logical to final visual order, similar to fribidi_reorder_line() but without reordring the text inside the runs, so that it can be used e.g. with HarfBuzz. --- lib/fribidi-bidi.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/fribidi-bidi.h | 29 +++++++++++++ lib/fribidi-common.h | 14 +++++-- lib/run.h | 11 ----- 4 files changed, 151 insertions(+), 15 deletions(-) diff --git a/lib/fribidi-bidi.c b/lib/fribidi-bidi.c index 89d6546..1bea6e8 100644 --- a/lib/fribidi-bidi.c +++ b/lib/fribidi-bidi.c @@ -993,6 +993,118 @@ out: return status ? max_level + 1 : 0; } + +static void +reverse_run ( + FriBidiRun *arr, + const FriBidiStrIndex len +) +{ + FriBidiStrIndex i; + + fribidi_assert (arr); + + for (i = 0; i < len/2; i++) + { + FriBidiRun temp = arr[i]; + arr[i] = arr[len - 1 - i]; + arr[len - 1 - i] = temp; + } +} + +FRIBIDI_ENTRY FriBidiStrIndex +fribidi_reorder_runs ( + /* input */ + const FriBidiCharType *bidi_types, + const FriBidiStrIndex len, + const FriBidiParType base_dir, + /* input and output */ + FriBidiLevel *embedding_levels, + /* output */ + FriBidiRun *runs +) +{ + FriBidiStrIndex i; + FriBidiLevel level; + FriBidiLevel last_level = -1; + FriBidiLevel max_level = 0; + FriBidiStrIndex run_count = 0; + FriBidiStrIndex run_start = 0; + FriBidiStrIndex run_index = 0; + + if UNLIKELY + (len == 0) + { + goto out; + } + + DBG ("in fribidi_reorder_runs"); + + fribidi_assert (bidi_types); + fribidi_assert (embedding_levels); + + DBG ("reset the embedding levels, 4. whitespace at the end of line"); + { + FriBidiStrIndex i; + + /* L1. Reset the embedding levels of some chars: + 4. any sequence of white space characters at the end of the line. */ + for (i = len - 1; i >= 0 && + FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (bidi_types[i]); i--) + embedding_levels[i] = FRIBIDI_DIR_TO_LEVEL (base_dir); + } + /* Find max_level of the line. We don't reuse the paragraph + * max_level, both for a cleaner API, and that the line max_level + * may be far less than paragraph max_level. */ + for (i = len - 1; i >= 0; i--) + if (embedding_levels[i] > max_level) + max_level = embedding_levels[i]; + + for (i = 0; i < len; i++) + { + if (embedding_levels[i] != last_level) + run_count++; + + last_level = embedding_levels[i]; + } + + if (runs == NULL) + goto out; + + while (run_start < len) + { + int runLength = 0; + while ((run_start + runLength) < len && embedding_levels[run_start] == embedding_levels[run_start + runLength]) + runLength++; + + runs[run_index].pos = run_start; + runs[run_index].level = embedding_levels[run_start]; + runs[run_index].len = runLength; + run_start += runLength; + run_index++; + } + + /* L2. Reorder. */ + for (level = max_level; level > 0; level--) + { + for (i = run_count - 1; i >= 0; i--) + { + if (runs[i].level >= level) + { + int end = i; + for (i--; (i >= 0 && runs[i].level >= level); i--) + ; + reverse_run (runs + i + 1, end - i); + } + } + } + +out: + + return run_count; +} + + /* Editor directions: * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent */ diff --git a/lib/fribidi-bidi.h b/lib/fribidi-bidi.h index dd2de67..6faba16 100644 --- a/lib/fribidi-bidi.h +++ b/lib/fribidi-bidi.h @@ -141,6 +141,35 @@ fribidi_get_par_embedding_levels ( * to reflect where each glyph ends up. */ ) FRIBIDI_GNUC_WARN_UNUSED; +#define fribidi_reorder_runs FRIBIDI_NAMESPACE(reorder_runs) +/* fribidi_reorder_runs - reorder runs of logical string to visual + * + * This function reorders all runs from logical to final visual order. This + * function implements part 4 of rule L1 and rule L2 of the Unicode + * Bidirectional Algorithm available at + * http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels. + * + * You should provide the bidi types as returned by fribidi_get_bidi_types() + * and the resolved embedding levels as set by + * fribidi_get_par_embedding_levels(). Also note that the embedding levels may + * change a bit. To be exact, the embedding level of any sequence of white + * space at the end of line is reset to the paragraph embedding level (That is + * part 4 of rule L1). + * + * The runs array can be NULL and in this case no reordring will happen, only + * the count of the runs will be returned. + * + * Returns: number of the runs. + */ +FRIBIDI_ENTRY FriBidiStrIndex +fribidi_reorder_runs ( + const FriBidiCharType *bidi_types, /* input list of bidi types as returned by fribidi_get_bidi_types() */ + const FriBidiStrIndex len, /* input length of the line */ + const FriBidiParType base_dir, /* resolved paragraph base direction */ + FriBidiLevel *embedding_levels, /* input list of embedding levels, as returned by fribidi_get_par_embedding_levels */ + FriBidiRun *runs /* Fribidi run information ( pos of run, the length of the run ,level of the run) */ +) FRIBIDI_GNUC_WARN_UNUSED; + #include "fribidi-enddecls.h" #endif /* !_FRIBIDI_BIDI_H */ diff --git a/lib/fribidi-common.h b/lib/fribidi-common.h index 6dede39..ffcb27a 100644 --- a/lib/fribidi-common.h +++ b/lib/fribidi-common.h @@ -99,6 +99,7 @@ +#include #define fribidi_debug_status FRIBIDI_NAMESPACE(debug_status) FRIBIDI_ENTRY int fribidi_debug_status ( @@ -112,11 +113,16 @@ fribidi_set_debug ( +typedef struct _FriBidiRunStruct FriBidiRun; - - - - +struct _FriBidiRunStruct +{ + FriBidiRun *prev; + FriBidiRun *next; + FriBidiStrIndex pos, len; + FriBidiCharType type; + FriBidiLevel level; +}; diff --git a/lib/run.h b/lib/run.h index 6028845..0b56cab 100644 --- a/lib/run.h +++ b/lib/run.h @@ -44,17 +44,6 @@ #include -typedef struct _FriBidiRunStruct FriBidiRun; - -struct _FriBidiRunStruct -{ - FriBidiRun *prev; - FriBidiRun *next; - - FriBidiStrIndex pos, len; - FriBidiCharType type; - FriBidiLevel level; -}; #define new_run FRIBIDI_PRIVATESPACE(new_run) -- cgit v1.2.1