static void fixture_init (fixture_t *fixture, gconstpointer user_data) { hb_buffer_t *b; unsigned int i; b = fixture->buffer = hb_buffer_create (); switch (GPOINTER_TO_INT (user_data)) { case BUFFER_EMPTY: break; case BUFFER_ONE_BY_ONE: for (i = 1; i < G_N_ELEMENTS (utf32) - 1; i++) hb_buffer_add (b, utf32[i], i); break; case BUFFER_UTF32: hb_buffer_add_utf32 (b, utf32, G_N_ELEMENTS (utf32), 1, G_N_ELEMENTS (utf32) - 2); break; case BUFFER_UTF16: hb_buffer_add_utf16 (b, utf16, G_N_ELEMENTS (utf16), 1, G_N_ELEMENTS (utf16) - 2); break; case BUFFER_UTF8: hb_buffer_add_utf8 (b, utf8, G_N_ELEMENTS (utf8), 1, G_N_ELEMENTS (utf8) - 2); break; default: g_assert_not_reached (); } }
static bool _raqm_shape (raqm_t *rq) { for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) { run->buffer = hb_buffer_create (); hb_buffer_add_utf32 (run->buffer, rq->text, rq->text_len, run->pos, run->len); hb_buffer_set_script (run->buffer, run->script); hb_buffer_set_language (run->buffer, hb_language_get_default ()); hb_buffer_set_direction (run->buffer, run->direction); hb_shape_full (rq->font, run->buffer, rq->features, rq->features_len, NULL); } return true; }
FT_Error af_get_char_index( AF_StyleMetrics metrics, FT_ULong charcode, FT_ULong *codepoint, FT_Long *y_offset ) { AF_StyleClass style_class; const hb_feature_t* feature; FT_ULong in_idx, out_idx; if ( !metrics ) return FT_THROW( Invalid_Argument ); in_idx = FT_Get_Char_Index( metrics->globals->face, charcode ); style_class = metrics->style_class; feature = features[style_class->coverage]; if ( feature ) { FT_Int upem = (FT_Int)metrics->globals->face->units_per_EM; hb_font_t* font = metrics->globals->hb_font; hb_buffer_t* buf = hb_buffer_create(); uint32_t c = (uint32_t)charcode; hb_glyph_info_t* ginfo; hb_glyph_position_t* gpos; unsigned int gcount; /* we shape at a size of units per EM; this means font units */ hb_font_set_scale( font, upem, upem ); /* XXX: is this sufficient for a single character of any script? */ hb_buffer_set_direction( buf, HB_DIRECTION_LTR ); hb_buffer_set_script( buf, scripts[style_class->script] ); /* we add one character to `buf' ... */ hb_buffer_add_utf32( buf, &c, 1, 0, 1 ); /* ... and apply one feature */ hb_shape( font, buf, feature, 1 ); ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); gpos = hb_buffer_get_glyph_positions( buf, &gcount ); out_idx = ginfo[0].codepoint; /* getting the same index indicates no substitution, */ /* which means that the glyph isn't available in the feature */ if ( in_idx == out_idx ) { *codepoint = 0; *y_offset = 0; } else { *codepoint = out_idx; *y_offset = gpos[0].y_offset; } hb_buffer_destroy( buf ); #ifdef FT_DEBUG_LEVEL_TRACE if ( gcount > 1 ) FT_TRACE1(( "af_get_char_index:" " input character mapped to multiple glyphs\n" )); #endif } else { *codepoint = in_idx; *y_offset = 0; } return FT_Err_Ok; }
static int ShapeParagraphHarfBuzz( filter_t *p_filter, paragraph_t **p_old_paragraph ) { paragraph_t *p_paragraph = *p_old_paragraph; paragraph_t *p_new_paragraph = 0; filter_sys_t *p_sys = p_filter->p_sys; int i_total_glyphs = 0; int i_ret = VLC_EGENERIC; if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 ) { msg_Err( p_filter, "ShapeParagraphHarfBuzz() invalid parameters. " "Paragraph size: %d. Runs count %d", p_paragraph->i_size, p_paragraph->i_runs_count ); return VLC_EGENERIC; } for( int i = 0; i < p_paragraph->i_runs_count; ++i ) { run_desc_t *p_run = p_paragraph->p_runs + i; text_style_t *p_style = p_run->p_style; /* * When using HarfBuzz, this is where font faces are loaded. * In the other two paths (shaping with FriBidi or no * shaping at all), faces are loaded in LoadGlyphs() */ FT_Face p_face = 0; if( !p_run->p_face ) { p_face = LoadFace( p_filter, p_style ); if( !p_face ) { p_face = p_sys->p_face; p_style = &p_sys->style; p_run->p_style = p_style; } p_run->p_face = p_face; } else p_face = p_run->p_face; p_run->p_hb_font = hb_ft_font_create( p_face, 0 ); if( !p_run->p_hb_font ) { msg_Err( p_filter, "ShapeParagraphHarfBuzz(): hb_ft_font_create() error" ); goto error; } p_run->p_buffer = hb_buffer_create(); if( !p_run->p_buffer ) { msg_Err( p_filter, "ShapeParagraphHarfBuzz(): hb_buffer_create() error" ); goto error; } hb_buffer_set_direction( p_run->p_buffer, p_run->direction ); hb_buffer_set_script( p_run->p_buffer, p_run->script ); #ifdef __OS2__ hb_buffer_add_utf16( p_run->p_buffer, p_paragraph->p_code_points + p_run->i_start_offset, p_run->i_end_offset - p_run->i_start_offset, 0, p_run->i_end_offset - p_run->i_start_offset ); #else hb_buffer_add_utf32( p_run->p_buffer, p_paragraph->p_code_points + p_run->i_start_offset, p_run->i_end_offset - p_run->i_start_offset, 0, p_run->i_end_offset - p_run->i_start_offset ); #endif hb_shape( p_run->p_hb_font, p_run->p_buffer, 0, 0 ); p_run->p_glyph_infos = hb_buffer_get_glyph_infos( p_run->p_buffer, &p_run->i_glyph_count ); p_run->p_glyph_positions = hb_buffer_get_glyph_positions( p_run->p_buffer, &p_run->i_glyph_count ); if( p_run->i_glyph_count <= 0 ) { msg_Err( p_filter, "ShapeParagraphHarfBuzz() invalid glyph count in shaped run" ); goto error; } i_total_glyphs += p_run->i_glyph_count; } p_new_paragraph = NewParagraph( p_filter, i_total_glyphs, 0, 0, 0, p_paragraph->i_runs_size ); if( !p_new_paragraph ) { i_ret = VLC_ENOMEM; goto error; } p_new_paragraph->paragraph_type = p_paragraph->paragraph_type; int i_index = 0; for( int i = 0; i < p_paragraph->i_runs_count; ++i ) { run_desc_t *p_run = p_paragraph->p_runs + i; hb_glyph_info_t *p_infos = p_run->p_glyph_infos; hb_glyph_position_t *p_positions = p_run->p_glyph_positions; for( unsigned int j = 0; j < p_run->i_glyph_count; ++j ) { /* * HarfBuzz reverses the order of glyphs in RTL runs. We reverse * it again here to keep the glyphs in their logical order. * For line breaking of paragraphs to work correctly, visual * reordering should be done after line breaking has taken * place. */ int i_run_index = p_run->direction == HB_DIRECTION_LTR ? j : p_run->i_glyph_count - 1 - j; int i_source_index = p_infos[ i_run_index ].cluster + p_run->i_start_offset; p_new_paragraph->p_code_points[ i_index ] = 0; p_new_paragraph->pi_glyph_indices[ i_index ] = p_infos[ i_run_index ].codepoint; p_new_paragraph->p_scripts[ i_index ] = p_paragraph->p_scripts[ i_source_index ]; p_new_paragraph->p_types[ i_index ] = p_paragraph->p_types[ i_source_index ]; p_new_paragraph->p_levels[ i_index ] = p_paragraph->p_levels[ i_source_index ]; p_new_paragraph->pp_styles[ i_index ] = p_paragraph->pp_styles[ i_source_index ]; p_new_paragraph->pi_karaoke_bar[ i_index ] = p_paragraph->pi_karaoke_bar[ i_source_index ]; p_new_paragraph->p_glyph_bitmaps[ i_index ].i_x_offset = p_positions[ i_run_index ].x_offset; p_new_paragraph->p_glyph_bitmaps[ i_index ].i_y_offset = p_positions[ i_run_index ].y_offset; p_new_paragraph->p_glyph_bitmaps[ i_index ].i_x_advance = p_positions[ i_run_index ].x_advance; p_new_paragraph->p_glyph_bitmaps[ i_index ].i_y_advance = p_positions[ i_run_index ].y_advance; ++i_index; } if( AddRun( p_filter, p_new_paragraph, i_index - p_run->i_glyph_count, i_index, p_run->p_face ) ) goto error; } for( int i = 0; i < p_paragraph->i_runs_count; ++i ) { hb_font_destroy( p_paragraph->p_runs[ i ].p_hb_font ); hb_buffer_destroy( p_paragraph->p_runs[ i ].p_buffer ); } FreeParagraph( *p_old_paragraph ); *p_old_paragraph = p_new_paragraph; return VLC_SUCCESS; error: for( int i = 0; i < p_paragraph->i_runs_count; ++i ) { if( p_paragraph->p_runs[ i ].p_hb_font ) hb_font_destroy( p_paragraph->p_runs[ i ].p_hb_font ); if( p_paragraph->p_runs[ i ].p_buffer ) hb_buffer_destroy( p_paragraph->p_runs[ i ].p_buffer ); } if( p_new_paragraph ) FreeParagraph( p_new_paragraph ); return i_ret; }
void AppendStringToBuffer<true, 4>(const FString& InString, const int32 InStartIndex, const int32 InLength, hb_buffer_t* InHarfBuzzTextBuffer) { // A unicode encoding with a TCHAR size of 4 bytes is assumed to be UTF-32 hb_buffer_add_utf32(InHarfBuzzTextBuffer, reinterpret_cast<const uint32_t*>(InString.GetCharArray().GetData()), InString.Len(), InStartIndex, InLength); }
bool GlyphString::shapeHarfBuzz() { if (mState != Analyzed) return false; hb_font_t *hb_font = hb_ft_font_create(mFace, NULL); int totalGlyphs = 0; for (int i = 0; i < mRunInfos.size(); ++i) { RunInfo &runInfo = mRunInfos[i]; runInfo.buffer = hb_buffer_create(); hb_buffer_set_direction(runInfo.buffer, runInfo.direction); hb_buffer_set_script(runInfo.buffer, runInfo.script); hb_buffer_add_utf32(runInfo.buffer, mCodePoints + runInfo.startOffset, runInfo.endOffset - runInfo.startOffset, 0, runInfo.endOffset - runInfo.startOffset); hb_shape(hb_font, runInfo.buffer, NULL, 0); runInfo.glyphInfos = hb_buffer_get_glyph_infos(runInfo.buffer, &runInfo.glyphCount); runInfo.glyphPositions = hb_buffer_get_glyph_positions(runInfo.buffer, &runInfo.glyphCount); totalGlyphs += runInfo.glyphCount; } quint32 *newCodePoints = new quint32[totalGlyphs]; memset(newCodePoints, 0, totalGlyphs * sizeof(*newCodePoints)); int *newGlyphIndices = new int[totalGlyphs]; memset(newGlyphIndices, 0, totalGlyphs * sizeof(*newGlyphIndices)); QImage *newImages = new QImage[totalGlyphs]; Geometry *newGeometries = new Geometry[totalGlyphs]; int *newRuns = new int[totalGlyphs]; memset(newRuns, 0, totalGlyphs * sizeof(*newRuns)); int *newLines = new int[totalGlyphs]; memset(newLines, 0, totalGlyphs * sizeof(*newLines)); hb_script_t *newScripts = new hb_script_t[totalGlyphs]; memset(newScripts, 0, totalGlyphs * sizeof(*newScripts)); FriBidiCharType *newTypes = new FriBidiCharType[totalGlyphs]; memset(newTypes, 0, totalGlyphs * sizeof(*newTypes)); FriBidiLevel *newLevels = new FriBidiLevel[totalGlyphs]; memset(newLevels, 0, totalGlyphs * sizeof(*newLevels)); FriBidiStrIndex *newMap = new FriBidiStrIndex[totalGlyphs]; memset(newMap, 0, totalGlyphs * sizeof(*newMap)); int index = 0; for (int i = 0; i < mRunInfos.size(); ++i) { RunInfo &runInfo = mRunInfos[i]; hb_glyph_info_t *glyphInfos = runInfo.glyphInfos; hb_glyph_position_t *glyphPositions = runInfo.glyphPositions; for (unsigned int j = 0; j < runInfo.glyphCount; ++j) { int runIndex = runInfo.direction == HB_DIRECTION_LTR ? j : runInfo.glyphCount - 1 - j; int sourceIndex = glyphInfos[runIndex].cluster + runInfo.startOffset; //newCodePoints[index] = mCodePoints[sourceIndex]; newGlyphIndices[index] = glyphInfos[runIndex].codepoint; newRuns[index] = mRuns[sourceIndex]; newScripts[index] = mScripts[sourceIndex]; newTypes[index] = mTypes[sourceIndex]; newLevels[index] = mLevels[sourceIndex]; newGeometries[index].xOffset = glyphPositions[runIndex].x_offset / 64; newGeometries[index].yOffset = glyphPositions[runIndex].y_offset / 64; newGeometries[index].xAdvance = glyphPositions[runIndex].x_advance / 64; newGeometries[index].yAdvance = glyphPositions[runIndex].y_advance / 64; ++index; } } delete[] mCodePoints; delete[] mGlyphIndices; delete[] mImages; delete[] mGeometries; delete[] mRuns; delete[] mLines; delete[] mScripts; delete[] mTypes; delete[] mLevels; delete[] mMap; mCodePoints = newCodePoints; mGlyphIndices = newGlyphIndices; mImages = newImages; mGeometries = newGeometries; mRuns = newRuns; mLines = newLines; mScripts = newScripts; mTypes = newTypes; mLevels = newLevels; mMap = newMap; mSize = totalGlyphs; loadGlyphImages(true, true); hb_font_destroy(hb_font); for (int i = 0; i < mRunInfos.size(); ++i) { hb_buffer_destroy(mRunInfos[i].buffer); mRunInfos[i].buffer = 0; mRunInfos[i].glyphInfos = 0; mRunInfos[i].glyphPositions = 0; mRunInfos[i].glyphCount = 0; } mState = Shaped; return true; }