static int AnalyzeParagraph( paragraph_t *p_paragraph ) { fribidi_get_bidi_types( p_paragraph->p_code_points, p_paragraph->i_size, p_paragraph->p_types ); fribidi_get_par_embedding_levels( p_paragraph->p_types, p_paragraph->i_size, &p_paragraph->paragraph_type, p_paragraph->p_levels ); #ifdef HAVE_HARFBUZZ hb_unicode_funcs_t *p_funcs = hb_unicode_funcs_get_default(); for( int i = 0; i < p_paragraph->i_size; ++i ) p_paragraph->p_scripts[ i ] = hb_unicode_script( p_funcs, p_paragraph->p_code_points[ i ] ); hb_script_t i_last_script; int i_last_script_index = -1; int i_last_set_index = -1; /* * For shaping to work, characters that are assigned HB_SCRIPT_COMMON or * HB_SCRIPT_INHERITED should be resolved to the last encountered valid * script value, if any, and to the first one following them otherwise */ for( int i = 0; i < p_paragraph->i_size; ++i ) { if( p_paragraph->p_scripts[ i ] == HB_SCRIPT_COMMON || p_paragraph->p_scripts[ i ] == HB_SCRIPT_INHERITED) { if( i_last_script_index != -1) { p_paragraph->p_scripts[ i ] = i_last_script; i_last_set_index = i; } } else { for( int j = i_last_set_index + 1; j < i; ++j ) p_paragraph->p_scripts[ j ] = p_paragraph->p_scripts[ i ]; i_last_script = p_paragraph->p_scripts[ i ]; i_last_script_index = i; i_last_set_index = i; } } #endif //HAVE_HARFBUZZ return VLC_SUCCESS; }
bool GlyphString::analyze(bool resolveScripts, bool breakOnLevelChange) { if (mState != Initialized) return false; fribidi_get_bidi_types(mCodePoints, mSize, mTypes); fribidi_get_par_embedding_levels(mTypes, mSize, &mParType, mLevels); hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default(); for (int i = 0; i < mSize; ++i) mScripts[i] = hb_unicode_script(ufuncs, mCodePoints[i]); if (resolveScripts) { hb_script_t lastScriptValue; int lastScriptIndex = -1; int lastSetIndex = -1; for (int i = 0; i < mSize; ++i) { if (mScripts[i] == HB_SCRIPT_COMMON || mScripts[i] == HB_SCRIPT_INHERITED) { if (lastScriptIndex != -1) { mScripts[i] = lastScriptValue; lastSetIndex = i; } } else { for (int j = lastSetIndex + 1; j < i; ++j) mScripts[j] = mScripts[i]; lastScriptValue = mScripts[i]; lastScriptIndex = i; lastSetIndex = i; } } } int runID = 0; hb_script_t lastScript = mScripts[0]; int lastLevel = mLevels[0]; int lastRunStart = 0; for (int i = 0; i <= mSize; ++i) { if (i == mSize || mScripts[i] != lastScript || (breakOnLevelChange && mLevels[i] != lastLevel)) { ++runID; RunInfo run; run.startOffset = lastRunStart; run.endOffset = i; run.script = lastScript; run.direction = lastLevel & 1 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR; mRunInfos.push_back(run); if (i < mSize) { lastScript = mScripts[i]; lastLevel = mLevels[i]; lastRunStart = i; } else { break; } } mRuns[i] = runID; } mState = Analyzed; return true; }
/* Resolve the script for each character in the input string, if the character * script is common or inherited it takes the script of the character before it * except paired characters which we try to make them use the same script. We * then split the BiDi runs, if necessary, on script boundaries. */ static bool _raqm_resolve_scripts (raqm_t *rq) { int last_script_index = -1; int last_set_index = -1; hb_script_t last_script_value = HB_SCRIPT_INVALID; raqm_stack_t *stack = NULL; if (rq->scripts) return true; rq->scripts = malloc (sizeof (hb_script_t) * rq->text_len); if (!rq->scripts) return false; for (size_t i = 0; i < rq->text_len; ++i) rq->scripts[i] = hb_unicode_script (hb_unicode_funcs_get_default (), rq->text[i]); #ifdef RAQM_TESTING RAQM_TEST ("Before script detection:\n"); for (size_t i = 0; i < rq->text_len; ++i) { SCRIPT_TO_STRING (rq->scripts[i]); RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); } RAQM_TEST ("\n"); #endif stack = _raqm_stack_new (rq->text_len); if (!stack) return false; for (int i = 0; i < (int) rq->text_len; i++) { if (rq->scripts[i] == HB_SCRIPT_COMMON && last_script_index != -1) { int pair_index = get_pair_index (rq->text[i]); if (pair_index >= 0) { if (IS_OPEN (pair_index)) { /* is a paired character */ rq->scripts[i] = last_script_value; last_set_index = i; _raqm_stack_push (stack, rq->scripts[i], pair_index); } else { /* is a close paired character */ /* find matching opening (by getting the last even index for current * odd index) */ int pi = pair_index & ~1; while (STACK_IS_NOT_EMPTY (stack) && stack->pair_index[stack->size] != pi) { _raqm_stack_pop (stack); } if (STACK_IS_NOT_EMPTY (stack)) { rq->scripts[i] = _raqm_stack_top (stack); last_script_value = rq->scripts[i]; last_set_index = i; } else { rq->scripts[i] = last_script_value; last_set_index = i; } } } else { rq->scripts[i] = last_script_value; last_set_index = i; } } else if (rq->scripts[i] == HB_SCRIPT_INHERITED && last_script_index != -1) { rq->scripts[i] = last_script_value; last_set_index = i; } else { for (int j = last_set_index + 1; j < i; ++j) rq->scripts[j] = rq->scripts[i]; last_script_value = rq->scripts[i]; last_script_index = i; last_set_index = i; } } #ifdef RAQM_TESTING RAQM_TEST ("After script detection:\n"); for (size_t i = 0; i < rq->text_len; ++i) { SCRIPT_TO_STRING (rq->scripts[i]); RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); } RAQM_TEST ("\n"); #endif _raqm_stack_free (stack); return true; }