/** * hb_buffer_normalize_glyphs: * @buffer: an #hb_buffer_t. * * Reorders a glyph buffer to have canonical in-cluster glyph order / position. * The resulting clusters should behave identical to pre-reordering clusters. * * <note>This has nothing to do with Unicode normalization.</note> * * Since: 0.9.2 **/ void hb_buffer_normalize_glyphs (hb_buffer_t *buffer) { assert (buffer->have_positions); assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); unsigned int count = buffer->len; if (unlikely (!count)) return; hb_glyph_info_t *info = buffer->info; unsigned int start = 0; unsigned int end; for (end = start + 1; end < count; end++) if (info[start].cluster != info[end].cluster) { normalize_glyphs_cluster (buffer, start, end, backward); start = end; } normalize_glyphs_cluster (buffer, start, end, backward); }
static bool _raqm_itemize (raqm_t *rq) { FriBidiParType par_type = FRIBIDI_PAR_ON; #ifdef _MSC_VER FriBidiCharType *types = _alloca (rq->text_len); FriBidiLevel *levels = _alloca (rq->text_len); #else FriBidiCharType types[rq->text_len]; FriBidiLevel levels[rq->text_len]; #endif FriBidiRun *runs = NULL; raqm_run_t *last; int max_level; int run_count; bool ok = true; #ifdef RAQM_TESTING switch (rq->base_dir) { case RAQM_DIRECTION_RTL: RAQM_TEST ("Direction is: RTL\n\n"); break; case RAQM_DIRECTION_LTR: RAQM_TEST ("Direction is: LTR\n\n"); break; case RAQM_DIRECTION_TTB: RAQM_TEST ("Direction is: TTB\n\n"); break; case RAQM_DIRECTION_DEFAULT: default: RAQM_TEST ("Direction is: DEFAULT\n\n"); break; } #endif if (rq->base_dir == RAQM_DIRECTION_RTL) par_type = FRIBIDI_PAR_RTL; else if (rq->base_dir == RAQM_DIRECTION_LTR) par_type = FRIBIDI_PAR_LTR; if (rq->base_dir == RAQM_DIRECTION_TTB) { /* Treat every thing as LTR in vertical text */ max_level = 0; memset (types, FRIBIDI_TYPE_LTR, rq->text_len); memset (levels, 0, rq->text_len); } else { fribidi_get_bidi_types (rq->text, rq->text_len, types); max_level = fribidi_get_par_embedding_levels (types, rq->text_len, &par_type, levels); } if (max_level < 0) return false; if (!_raqm_resolve_scripts (rq)) return false; /* Get the number of bidi runs */ run_count = fribidi_reorder_runs (types, rq->text_len, par_type, levels, NULL); /* Populate bidi runs array */ runs = malloc (sizeof (FriBidiRun) * (size_t)run_count); if (!runs) return false; run_count = fribidi_reorder_runs (types, rq->text_len, par_type, levels, runs); #ifdef RAQM_TESTING RAQM_TEST ("Number of runs before script itemization: %d\n\n", run_count); RAQM_TEST ("Fribidi Runs:\n"); for (int i = 0; i < run_count; i++) { RAQM_TEST ("run[%d]:\t start: %d\tlength: %d\tlevel: %d\n", i, runs[i].pos, runs[i].len, runs[i].level); } RAQM_TEST ("\n"); #endif last = NULL; for (int i = 0; i < run_count; i++) { raqm_run_t *run = calloc (1, sizeof (raqm_run_t)); if (!run) return false; if (!rq->runs) rq->runs = run; if (last) last->next = run; run->direction = _raqm_hb_dir (rq, runs[i].level); if (HB_DIRECTION_IS_BACKWARD (run->direction)) { run->pos = runs[i].pos + runs[i].len - 1; run->script = rq->scripts[run->pos]; for (int j = runs[i].len - 1; j >= 0; j--) { hb_script_t script = rq->scripts[runs[i].pos + j]; if (script != run->script) { raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t)); if (!newrun) return false; newrun->pos = runs[i].pos + j; newrun->len = 1; newrun->direction = _raqm_hb_dir (rq, runs[i].level); newrun->script = script; run->next = newrun; run = newrun; } else { run->len++; run->pos = runs[i].pos + j; } } } else { run->pos = runs[i].pos; run->script = rq->scripts[run->pos]; for (int j = 0; j < runs[i].len; j++) { hb_script_t script = rq->scripts[runs[i].pos + j]; if (script != run->script) { raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t)); if (!newrun) return false; newrun->pos = runs[i].pos + j; newrun->len = 1; newrun->direction = _raqm_hb_dir (rq, runs[i].level); newrun->script = script; run->next = newrun; run = newrun; } else run->len++; } } last = run; last->next = NULL; } #ifdef RAQM_TESTING run_count = 0; for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) run_count++; RAQM_TEST ("Number of runs after script itemization: %d\n\n", run_count); run_count = 0; RAQM_TEST ("Final Runs:\n"); for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) { SCRIPT_TO_STRING (run->script); RAQM_TEST ("run[%d]:\t start: %d\tlength: %d\tdirection: %s\tscript: %s\n", run_count++, run->pos, run->len, hb_direction_to_string (run->direction), buff); } RAQM_TEST ("\n"); #endif free (runs); return ok; }