예제 #1
0
static void get_bidi_levels(FriBidiChar *in,int length,int is_rtl,FriBidiLevel *embed)
{
	FriBidiCharType *types = utl_malloc(sizeof(FriBidiCharType)*length);
	FriBidiParType direction = is_rtl ? FRIBIDI_PAR_RTL : FRIBIDI_PAR_LTR;

	fribidi_get_bidi_types(in,length,types);
	fribidi_get_par_embedding_levels(types,length,&direction,embed);

	utl_free(types);
}
예제 #2
0
파일: text_layout.c 프로젝트: Adatan/vlc
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;
}
예제 #3
0
파일: vf_drawtext.c 프로젝트: mark4o/FFmpeg
static int shape_text(AVFilterContext *ctx)
{
    DrawTextContext *s = ctx->priv;
    uint8_t *tmp;
    int ret = AVERROR(ENOMEM);
    static const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT |
                                      FRIBIDI_FLAGS_ARABIC;
    FriBidiChar *unicodestr = NULL;
    FriBidiStrIndex len;
    FriBidiParType direction = FRIBIDI_PAR_LTR;
    FriBidiStrIndex line_start = 0;
    FriBidiStrIndex line_end = 0;
    FriBidiLevel *embedding_levels = NULL;
    FriBidiArabicProp *ar_props = NULL;
    FriBidiCharType *bidi_types = NULL;
    FriBidiStrIndex i,j;

    len = strlen(s->text);
    if (!(unicodestr = av_malloc_array(len, sizeof(*unicodestr)))) {
        goto out;
    }
    len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
                                     s->text, len, unicodestr);

    bidi_types = av_malloc_array(len, sizeof(*bidi_types));
    if (!bidi_types) {
        goto out;
    }

    fribidi_get_bidi_types(unicodestr, len, bidi_types);

    embedding_levels = av_malloc_array(len, sizeof(*embedding_levels));
    if (!embedding_levels) {
        goto out;
    }

    if (!fribidi_get_par_embedding_levels(bidi_types, len, &direction,
                                          embedding_levels)) {
        goto out;
    }

    ar_props = av_malloc_array(len, sizeof(*ar_props));
    if (!ar_props) {
        goto out;
    }

    fribidi_get_joining_types(unicodestr, len, ar_props);
    fribidi_join_arabic(bidi_types, len, embedding_levels, ar_props);
    fribidi_shape(flags, embedding_levels, len, ar_props, unicodestr);

    for (line_end = 0, line_start = 0; line_end < len; line_end++) {
        if (is_newline(unicodestr[line_end]) || line_end == len - 1) {
            if (!fribidi_reorder_line(flags, bidi_types,
                                      line_end - line_start + 1, line_start,
                                      direction, embedding_levels, unicodestr,
                                      NULL)) {
                goto out;
            }
            line_start = line_end + 1;
        }
    }

    /* Remove zero-width fill chars put in by libfribidi */
    for (i = 0, j = 0; i < len; i++)
        if (unicodestr[i] != FRIBIDI_CHAR_FILL)
            unicodestr[j++] = unicodestr[i];
    len = j;

    if (!(tmp = av_realloc(s->text, (len * 4 + 1) * sizeof(*s->text)))) {
        /* Use len * 4, as a unicode character can be up to 4 bytes in UTF-8 */
        goto out;
    }

    s->text = tmp;
    len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
                                     unicodestr, len, s->text);
    ret = 0;

out:
    av_free(unicodestr);
    av_free(embedding_levels);
    av_free(ar_props);
    av_free(bidi_types);
    return ret;
}
예제 #4
0
/**
 * @internal
 * Allocates bidi properties according to ustr. First checks to see if the
 * passed has rtl chars, if not, it returns NULL.
 *
 * Assumes all the segment_idxs are either -1 or legal, and > 0 indexes.
 * Also assumes that the characters at the override points are of weak/neutral
 * bidi type, otherwise unexpected results may occur.
 *
 * @param ustr The string to update according to.
 * @param len The length of the string
 * @param segment_idxs A -1 terminated array of points to start a new bidi analysis at (used for section high level bidi overrides). - NULL means none.
 * @return returns allocated paragraph props on success, NULL otherwise.
 */
Evas_BiDi_Paragraph_Props *
evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr, size_t len,
      int *segment_idxs)
{
   Evas_BiDi_Paragraph_Props *bidi_props = NULL;
   EvasBiDiCharType *char_types = NULL;
   EvasBiDiLevel *embedding_levels = NULL;
   const FriBidiChar *ustr;
   FriBidiChar *base_ustr = NULL;

   if (!eina_ustr)
      return NULL;


   if (!evas_bidi_is_rtl_str(eina_ustr)) /* No need to handle bidi */
     {
        len = -1;
        goto cleanup;
     }

   len = eina_unicode_strlen(eina_ustr);
   /* The size of fribidichar s different than eina_unicode, convert */
#ifdef EVAS_FRIBIDI_EINA_UNICODE_UNEQUAL
   base_ustr = calloc(len + 1, sizeof(FriBidiChar));
   base_ustr = _evas_bidi_unicode_to_fribidichar(base_ustr, eina_ustr);
   ustr = base_ustr;
#else
   ustr = (const FriBidiChar *) eina_ustr;
#endif

   bidi_props = evas_bidi_paragraph_props_new();

   /* Prep work for reordering */
   char_types = (EvasBiDiCharType *) malloc(sizeof(EvasBiDiCharType) * len);
   if (!char_types)
      {
         len = -2;
         goto cleanup;
      }
   fribidi_get_bidi_types(ustr, len, char_types);

   embedding_levels = (EvasBiDiLevel *)malloc(sizeof(EvasBiDiLevel) * len);
   if (!embedding_levels)
     {
        len = -2;
        goto cleanup;
     }

   if (segment_idxs)
     {
        size_t pos = 0;
        int *itr;
        EvasBiDiLevel base_level = 0;
        EvasBiDiParType direction;

        for (itr = segment_idxs ; *itr > 0 ; itr++)
          {
             direction = EVAS_BIDI_PARAGRAPH_NEUTRAL;
             if (!fribidi_get_par_embedding_levels(char_types + pos,
                      *itr - pos,
                      &direction,
                      embedding_levels + pos))
               {
                  len = -2;
                  goto cleanup;
               }

             /* Only on the first run */
             if (itr == segment_idxs)
               {
                  bidi_props->direction = direction;
                  /* adjust base_level to be 1 for rtl paragraphs, and 0 for
                   * ltr paragraphs. */
                  base_level =
                     EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(bidi_props) ? 1 : 0;
               }

             /* We want those chars at the override points to be on the base
              * level and we also remove -2 cause we later increment them,
              * just for simpler code paths */
             embedding_levels[*itr] = base_level - 2;
             pos = *itr + 1;
          }

        direction = EVAS_BIDI_PARAGRAPH_NEUTRAL;
        if (!fribidi_get_par_embedding_levels(char_types + pos,
                 len - pos,
                 &direction,
                 embedding_levels + pos))
          {
             len = -2;
             goto cleanup;
          }

        /* Increment all levels by 2 to emulate embedding. */
          {
             EvasBiDiLevel *bitr = embedding_levels, *end;
             end = bitr + len;
             for ( ; bitr < end ; bitr++)
               {
                  *bitr += 2;
               }
          }
     }
   else
     {
        if (!fribidi_get_par_embedding_levels(char_types, len,
                 &bidi_props->direction, embedding_levels))
          {
             len = -2;
             goto cleanup;
          }
     }


   /* clean up */
   if (bidi_props->embedding_levels)
     {
        free(bidi_props->embedding_levels);
     }
   bidi_props->embedding_levels = embedding_levels;

   /* clean up */

   if (bidi_props->char_types)
     {
        free(bidi_props->char_types);
     }
   bidi_props->char_types = char_types;

   if (base_ustr) free(base_ustr);


   return bidi_props;

/* Cleanup */
cleanup:
   if (char_types) free(char_types);
   if (embedding_levels) free(embedding_levels);
   if (base_ustr) free(base_ustr);
   if (bidi_props) evas_bidi_paragraph_props_unref(bidi_props); /* Clean up the bidi props */
   return NULL;
}
예제 #5
0
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;
}
예제 #6
0
파일: raqm.c 프로젝트: dawoodalbadi/libraqm
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;
}