static wchar_t* bidi_string(wchar_t *logical) { FriBidiCharType base = FRIBIDI_TYPE_ON; size_t len; len = wcslen(logical); FriBidiChar *visual; FriBidiStrIndex *ltov, *vtol; FriBidiLevel *levels; FriBidiStrIndex new_len; fribidi_boolean log2vis; visual = (FriBidiChar *) malloc (sizeof (FriBidiChar) * (len + 1)); ltov = NULL; vtol = NULL; levels = NULL; /* Create a bidi string. */ log2vis = fribidi_log2vis ((FriBidiChar *)logical, len, &base, /* output */ visual, ltov, vtol, levels); visual[len] = 0; if (!log2vis) { //msSetError(MS_IDENTERR, "Failed to create bidi string.", //"msGetFriBidiEncodedString()"); return NULL; } visual[len] = 0; new_len = len; visual[len] = 0; return (wchar_t *)visual; }
static Variant HHVM_FUNCTION( fribidi_log2vis, const String& logical_str, int64_t direction, int64_t charset ) { char * visual_str; int logical_str_len, visual_str_len, ustr_len; FriBidiParType base_direction; FriBidiLevel status; FriBidiChar *logical_ustr, *visual_ustr; logical_str_len = logical_str.length(); if (!_direction_is_valid(direction)) { raise_warning("Uknown direction."); return false; } if (!_charset_is_valid(charset)) { raise_warning("Uknown charset."); return false; } // Convert input string to internal Unicode logical_ustr = (FriBidiChar*) emalloc(sizeof(FriBidiChar) * logical_str_len); ustr_len = fribidi_charset_to_unicode( (FriBidiCharSet)charset, logical_str.c_str(), logical_str_len, logical_ustr ); // Visualize the Unicode string base_direction = direction; visual_ustr = (FriBidiChar*) emalloc(sizeof(FriBidiChar) * ustr_len); status = fribidi_log2vis( logical_ustr, ustr_len, &base_direction, visual_ustr, nullptr, nullptr, nullptr); efree(logical_ustr); // Return false if FriBidi failed if (status == 0) { efree(visual_ustr); return false; } // Convert back from internal Unicode to original character set visual_str_len = 4 * ustr_len; visual_str = (char *) emalloc(sizeof(char) * visual_str_len); visual_str_len = fribidi_unicode_to_charset( (FriBidiCharSet)charset, visual_ustr, ustr_len, visual_str); efree(visual_ustr); String result(visual_str, visual_str_len, CopyString); efree(visual_str); return result; }
/** Get the width of a string. */ int GetStringWidth(FontType ft, const char *str) { #ifdef USE_XFT XGlyphInfo extents; #endif #ifdef USE_FRIBIDI FriBidiChar *temp_i; FriBidiChar *temp_o; FriBidiParType type = FRIBIDI_PAR_ON; int unicodeLength; #endif int len; char *output; int result; char *utf8String; /* Convert to UTF-8 if necessary. */ utf8String = GetUTF8String(str); /* Length of the UTF-8 string. */ len = strlen(utf8String); /* Apply the bidi algorithm if requested. */ #ifdef USE_FRIBIDI temp_i = AllocateStack((len + 1) * sizeof(FriBidiChar)); temp_o = AllocateStack((len + 1) * sizeof(FriBidiChar)); unicodeLength = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, utf8String, len, temp_i); fribidi_log2vis(temp_i, unicodeLength, &type, temp_o, NULL, NULL, NULL); output = AllocateStack(4 * len + 1); fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, temp_o, unicodeLength, (char*)output); len = strlen(output); #else output = utf8String; #endif /* Get the width of the string. */ #ifdef USE_XFT JXftTextExtentsUtf8(display, fonts[ft], (const unsigned char*)output, len, &extents); result = extents.xOff; #else result = XTextWidth(fonts[ft], output, len); #endif /* Clean up. */ #ifdef USE_FRIBIDI ReleaseStack(temp_i); ReleaseStack(temp_o); ReleaseStack(output); #endif ReleaseUTF8String(utf8String); return result; }
bool Language::update() { canvas.clear(clan::Colorf(0.0f,0.0f,0.2f)); std::string text; text = document_element.get_child_string("ENGLISH"); font_english.draw_text(canvas, 10, 60, text); text = document_element.get_child_string("CHINESE"); font_chinese.draw_text(canvas, 10, 130, text); #ifdef ENABLE_THIS_IF_YOU_WANT_TO_USE_FRIBIDI text = document_element.get_child_string("ARABIC"); /* input */ std::wstring text_16 = clan::StringHelp::utf8_to_ucs2(text); FriBidiChar *fri_str = (FriBidiChar *) text_16.c_str(); FriBidiStrIndex fri_len = text_16.length(); FriBidiCharType fri_base_dir = FRIBIDI_TYPE_ON; FriBidiCharType *fri_pbase_dir = &fri_base_dir; /* output */ std::vector<wchar_t> output_buffer; output_buffer.resize(text_16.length() + 1); FriBidiChar *fri_visual_str = &output_buffer[0]; FriBidiStrIndex *fri_position_L_to_V_list = NULL; FriBidiStrIndex *fri_position_V_to_L_list = NULL; FriBidiLevel *fri_embedding_level_list = NULL; fribidi_boolean fri_result; fri_result = fribidi_log2vis(fri_str, fri_len, fri_pbase_dir, fri_visual_str, fri_position_L_to_V_list, fri_position_V_to_L_list, fri_embedding_level_list); if (fri_result) { output_buffer[text_16.length()] = 0; std::string new_text = clan::StringHelp::ucs2_to_utf8(&output_buffer[0]); font_arabic.draw_text(canvas, 10, 230, new_text); } #endif window.flip(1); return !quit; }
std::wstring getVisualLine(const std::wstring&instring) { std::wstring outstring; const FriBidiCharSet enc= FRIBIDI_CHAR_SET_UTF8; FriBidiParType direction=FRIBIDI_PAR_ON; size_t len2=instring.size()*2; const FriBidiChar*str_in = (const FriBidiChar*)instring.c_str(); FriBidiChar*str_out = new FriBidiChar[len2]; /* reshape the UTF32 string */ FriBidiLevel lvl = fribidi_log2vis(str_in, instring.size(), &direction, str_out, 0, 0, 0); if(lvl) { wchar_t*output=(wchar_t*)str_out; outstring=std::wstring(output, instring.size()); } else { outstring=instring; } delete[]str_out; return outstring; }
std::wstring getVisualLine(const std::string&instring) { std::wstring outstring; const FriBidiCharSet enc= FRIBIDI_CHAR_SET_UTF8; FriBidiParType direction=FRIBIDI_PAR_ON; size_t len2=instring.size()*2; FriBidiChar*str_in = new FriBidiChar[len2]; FriBidiChar*str_out = new FriBidiChar[len2]; /* convert UTF8 to UTF32 */ FriBidiStrIndex ulen = fribidi_charset_to_unicode(enc, instring.c_str(), instring.size(), str_in); /* reshape the UTF32 string */ FriBidiLevel lvl = fribidi_log2vis(str_in, ulen, &direction, str_out, 0, 0, 0); if(lvl) { outstring=std::wstring((wchar_t*)str_out); } else { //outstring=instring; } delete[]str_in; delete[]str_out; return outstring; }
int bjoining_log2cuni ( unichar *str, int ulen, unichar *cstr, int *clen, int options) { int f = 1; int len = ulen; FriBidiCharType ptype = FRIBIDI_TYPE_ON; unichar *vis = malloc ((len + 1) * sizeof (unichar)); f = f && bjoining_compose (str, &len); if (0 == (options & (B_LOGICAL_OUTPUT | B_LOGICAL_OUTPUT_LOG2CUNI))) { f = f && fribidi_log2vis ((FriBidiChar *) str, len, &ptype, (FriBidiChar *) vis, NULL, NULL, NULL); } else { memmove (vis, str, len * sizeof str[0]); } if (0 == (options & B_KEEP_BIDI_MARKS)) len = fribidi_remove_bidi_marks (vis, len, NULL, NULL, NULL); f = f && bjoining_vis2cuni (vis, len, cstr, clen, options); if (f) cstr[*clen] = '\0'; else clen = 0; free (vis); return f; }
static void benchmark ( const char *S_, int niter ) { int len, i; FriBidiChar us[MAX_STR_LEN], out_us[MAX_STR_LEN]; FriBidiStrIndex positionLtoV[MAX_STR_LEN], positionVtoL[MAX_STR_LEN]; FriBidiLevel embedding_list[MAX_STR_LEN]; FriBidiParType base; double time0, time1; { int j; len = strlen (S_); for (i = 0, j = 0; i < len; i++) { if (S_[i] == '_') switch (S_[++i]) { case '>': us[j++] = FRIBIDI_CHAR_LRM; break; case '<': us[j++] = FRIBIDI_CHAR_RLM; break; case 'l': us[j++] = FRIBIDI_CHAR_LRE; break; case 'r': us[j++] = FRIBIDI_CHAR_RLE; break; case 'L': us[j++] = FRIBIDI_CHAR_LRO; break; case 'R': us[j++] = FRIBIDI_CHAR_RLO; break; case 'o': us[j++] = FRIBIDI_CHAR_PDF; break; case '_': us[j++] = '_'; break; default: us[j++] = '_'; i--; break; } else us[j++] = S_[i]; if (us[j] >= 'A' && us[j] <= 'F') us[j] += FRIBIDI_CHAR_ARABIC_ALEF - 'A'; else if (us[j] >= 'G' && us[j] <= 'Z') us[j] += FRIBIDI_CHAR_HEBREW_ALEF - 'G'; else if (us[j] >= '6' && us[j] <= '9') us[j] += FRIBIDI_CHAR_ARABIC_ZERO - '0'; } len = j; } /* Start timer */ time0 = utime (); for (i = 0; i < niter; i++) { /* Create a bidi string */ base = FRIBIDI_PAR_ON; if (!fribidi_log2vis (us, len, &base, /* output */ out_us, positionVtoL, positionLtoV, embedding_list)) die2 ("something failed in fribidi_log2vis.\n" "perhaps memory allocation failure.", NULL); } /* stop timer */ time1 = utime (); /* output result */ printf ("Length = %d\n", len); printf ("Iterations = %d\n", niter); printf ("%d len*iterations in %f seconds\n", len * niter, time1 - time0); printf ("= %.0f kilo.length.iterations/second\n", 1.0 * len * niter / 1000 / (time1 - time0)); return; }
GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color, int maxWidth ) const { uint32_t code; int n; int penX = 0; int width1 = 0, width2 = 0; int yMin = 0, yMax = 0; uint32_t *pString = (uint32_t*)rString.u_str(); // Check if freetype has been initialized if( !m_face ) { return NULL; } // Get the length of the string int len = rString.length(); // Use fribidi if available #ifdef HAVE_FRIBIDI uint32_t *pFribidiString = NULL; if( len > 0 ) { pFribidiString = new uint32_t[len+1]; FriBidiCharType baseDir = FRIBIDI_TYPE_ON; fribidi_log2vis( (FriBidiChar*)pString, len, &baseDir, (FriBidiChar*)pFribidiString, 0, 0, 0 ); pString = pFribidiString; } #endif // Array of glyph bitmaps and position FT_BitmapGlyphRec **glyphs = new FT_BitmapGlyphRec*[len]; int *pos = new int[len]; // Does the font support kerning ? FT_Bool useKerning = FT_HAS_KERNING( m_face ); int previous = 0; // Index of the last glyph when the text is truncated with trailing ... int maxIndex = 0; // Position of the first trailing dot int firstDotX = 0; /// Get the dot glyph Glyph_t &dotGlyph = getGlyph( '.' ); // First, render all the glyphs for( n = 0; n < len; n++ ) { code = *(pString++); // Get the glyph for this character Glyph_t &glyph = getGlyph( code ); glyphs[n] = (FT_BitmapGlyphRec*)(glyph.m_glyph); // Retrieve kerning distance and move pen position if( useKerning && previous && glyph.m_index ) { FT_Vector delta; FT_Get_Kerning( m_face, previous, glyph.m_index, ft_kerning_default, &delta ); penX += delta.x >> 6; } pos[n] = penX; width1 = penX + glyph.m_size.xMax - glyph.m_size.xMin; yMin = __MIN( yMin, glyph.m_size.yMin ); yMax = __MAX( yMax, glyph.m_size.yMax ); // Next position penX += glyph.m_advance; // Save glyph index previous = glyph.m_index; if( maxWidth != -1 ) { // Check if the truncated text with the '...' fit in the maxWidth int curX = penX; if( useKerning ) { FT_Vector delta; FT_Get_Kerning( m_face, glyph.m_index, dotGlyph.m_index, ft_kerning_default, &delta ); curX += delta.x >> 6; } int dotWidth = 2 * dotGlyph.m_advance + dotGlyph.m_size.xMax - dotGlyph.m_size.xMin; if( curX + dotWidth < maxWidth ) { width2 = curX + dotWidth; maxIndex++; firstDotX = curX; } }
/** * This function receives a string and creates a subpicture for it. It * also calculates the size needed for this string, and renders the * needed glyphs into memory. It is used as pf_add_string callback in * the vout method by this module */ static subpicture_t *RenderText( filter_t *p_filter, block_t *p_block ) { filter_sys_t *p_sys = p_filter->p_sys; subpicture_t *p_subpic = 0; subpicture_data_t *p_string = 0; line_desc_t *p_line = 0, *p_next = 0, *p_prev = 0; int i, i_pen_y, i_pen_x, i_error, i_glyph_index, i_previous; uint32_t *psz_unicode, *psz_unicode_orig = 0, i_char, *psz_line_start; int i_string_length; char *psz_string; vlc_iconv_t iconv_handle = (vlc_iconv_t)(-1); FT_BBox line; FT_BBox glyph_size; FT_Vector result; FT_Glyph tmp_glyph; /* Sanity check */ if( !p_block ) return NULL; psz_string = p_block->p_buffer; if( !psz_string || !*psz_string ) goto error; result.x = 0; result.y = 0; line.xMin = 0; line.xMax = 0; line.yMin = 0; line.yMax = 0; /* Create and initialize a subpicture */ p_subpic = p_filter->pf_sub_buffer_new( p_filter ); if( !p_subpic ) goto error; p_subpic->i_start = p_block->i_pts; p_subpic->i_stop = p_block->i_pts + p_block->i_length; p_subpic->b_ephemer = (p_block->i_length == 0); p_subpic->b_absolute = VLC_FALSE; /* Create and initialize private data for the subpicture */ p_string = malloc( sizeof(subpicture_data_t) ); if( !p_string ) { msg_Err( p_filter, "out of memory" ); goto error; } p_string->p_lines = 0; p_string->psz_text = strdup( psz_string ); psz_unicode = psz_unicode_orig = malloc( ( strlen(psz_string) + 1 ) * sizeof(uint32_t) ); if( psz_unicode == NULL ) { msg_Err( p_filter, "out of memory" ); goto error; } #if defined(WORDS_BIGENDIAN) iconv_handle = vlc_iconv_open( "UCS-4BE", "UTF-8" ); #else iconv_handle = vlc_iconv_open( "UCS-4LE", "UTF-8" ); #endif if( iconv_handle == (vlc_iconv_t)-1 ) { msg_Warn( p_filter, "unable to do convertion" ); goto error; } { char *p_in_buffer, *p_out_buffer; size_t i_in_bytes, i_out_bytes, i_out_bytes_left, i_ret; i_in_bytes = strlen( psz_string ); i_out_bytes = i_in_bytes * sizeof( uint32_t ); i_out_bytes_left = i_out_bytes; p_in_buffer = psz_string; p_out_buffer = (char *)psz_unicode; i_ret = vlc_iconv( iconv_handle, &p_in_buffer, &i_in_bytes, &p_out_buffer, &i_out_bytes_left ); vlc_iconv_close( iconv_handle ); if( i_in_bytes ) { msg_Warn( p_filter, "failed to convert string to unicode (%s), " "bytes left %d", strerror(errno), i_in_bytes ); goto error; } *(uint32_t*)p_out_buffer = 0; i_string_length = (i_out_bytes - i_out_bytes_left) / sizeof(uint32_t); } #if defined(HAVE_FRIBIDI) { uint32_t *p_fribidi_string; FriBidiCharType base_dir = FRIBIDI_TYPE_ON; p_fribidi_string = malloc( (i_string_length + 1) * sizeof(uint32_t) ); fribidi_log2vis( (FriBidiChar*)psz_unicode, i_string_length, &base_dir, (FriBidiChar*)p_fribidi_string, 0, 0, 0 ); free( psz_unicode_orig ); psz_unicode = psz_unicode_orig = p_fribidi_string; p_fribidi_string[ i_string_length ] = 0; } #endif /* Calculate relative glyph positions and a bounding box for the * entire string */ p_line = NewLine( psz_string ); if( p_line == NULL ) { msg_Err( p_filter, "out of memory" ); goto error; } p_string->p_lines = p_line; i_pen_x = 0; i_pen_y = 0; i_previous = 0; i = 0; psz_line_start = psz_unicode; #define face p_sys->p_face #define glyph face->glyph while( *psz_unicode ) { i_char = *psz_unicode++; if( i_char == '\r' ) /* ignore CR chars wherever they may be */ { continue; } if( i_char == '\n' ) { psz_line_start = psz_unicode; p_next = NewLine( psz_string ); if( p_next == NULL ) { msg_Err( p_filter, "out of memory" ); goto error; } p_line->p_next = p_next; p_line->i_width = line.xMax; p_line->i_height = face->size->metrics.height >> 6; p_line->pp_glyphs[ i ] = NULL; p_prev = p_line; p_line = p_next; result.x = __MAX( result.x, line.xMax ); result.y += face->size->metrics.height >> 6; i_pen_x = 0; i_previous = 0; line.xMin = 0; line.xMax = 0; line.yMin = 0; line.yMax = 0; i_pen_y += face->size->metrics.height >> 6; #if 0 msg_Dbg( p_filter, "Creating new line, i is %d", i ); #endif i = 0; continue; } i_glyph_index = FT_Get_Char_Index( face, i_char ); if( p_sys->i_use_kerning && i_glyph_index && i_previous ) { FT_Vector delta; FT_Get_Kerning( face, i_previous, i_glyph_index, ft_kerning_default, &delta ); i_pen_x += delta.x >> 6; }
// The start of the Application int Language::start(const std::vector<std::string> &args) { quit = false; // Set the window clan::DisplayWindowDescription desc; desc.set_title("ClanLib Language Example"); desc.set_size(clan::Size(640, 480), true); desc.set_allow_resize(true); clan::DisplayWindow window(desc); // Connect the Window close event clan::Slot slot_quit = window.sig_window_close().connect(this, &Language::on_window_close); // Connect a keyboard handler to on_key_up() clan::Slot slot_input_up = (window.get_ic().get_keyboard()).sig_key_up().connect(this, &Language::on_input_up); // Get the graphic context clan::Canvas canvas(window); clan::File file("Resources/test.xml"); clan::DomDocument document(file); clan::DomElement document_element = document.get_document_element(); if (document_element.is_null()) throw clan::Exception("Cannot obtain the document element"); clan::Font font_english(canvas, "arial", 32); clan::FontDescription desc_chinese; desc_chinese.set_typeface_name("simsun"); desc_chinese.set_height(48); desc_chinese.set_charset(clan::FontDescription::charset_chinesebig5); clan::Font font_chinese(canvas, desc_chinese); clan::FontDescription desc_arabic; desc_arabic.set_typeface_name("arial"); desc_arabic.set_height(48); desc_arabic.set_charset(clan::FontDescription::charset_arabic); clan::Font font_arabic(canvas, desc_arabic); // Run until someone presses escape while (!quit) { canvas.clear(clan::Colorf(0.0f,0.0f,0.2f)); std::string text; text = document_element.get_child_string("ENGLISH"); font_english.draw_text(canvas, 10, 30, text); text = document_element.get_child_string("CHINESE"); font_chinese.draw_text(canvas, 10, 130, text); #ifdef ENABLE_THIS_IF_YOU_WANT_TO_USE_FRIBIDI text = document_element.get_child_string("ARABIC"); /* input */ std::wstring text_16 = StringHelp::utf8_to_ucs2(text); FriBidiChar *fri_str = (FriBidiChar *) text_16.c_str(); FriBidiStrIndex fri_len = text_16.length(); FriBidiCharType fri_base_dir = FRIBIDI_TYPE_ON; FriBidiCharType *fri_pbase_dir = &fri_base_dir; /* output */ std::vector<wchar_t> output_buffer; output_buffer.resize(text_16.length() + 1); FriBidiChar *fri_visual_str = &output_buffer[0]; FriBidiStrIndex *fri_position_L_to_V_list = NULL; FriBidiStrIndex *fri_position_V_to_L_list = NULL; FriBidiLevel *fri_embedding_level_list = NULL; fribidi_boolean fri_result; fri_result = fribidi_log2vis(fri_str, fri_len, fri_pbase_dir, fri_visual_str, fri_position_L_to_V_list, fri_position_V_to_L_list, fri_embedding_level_list); if (fri_result) { output_buffer[text_16.length()] = 0; std::string new_text = clan::StringHelp::ucs2_to_utf8(&output_buffer[0]); font_arabic.draw_text(gc, 10, 230, new_text); } #endif window.flip(1); clan::KeepAlive::process(0); } return 0; }
/** Display a string. */ void RenderString(Drawable d, FontType font, ColorType color, int x, int y, int width, const char *str) { #ifdef USE_ICONV static char isUTF8 = -1; #endif XRectangle rect; Region renderRegion; int len; char *output; #ifdef USE_FRIBIDI FriBidiChar *temp_i; FriBidiChar *temp_o; FriBidiParType type = FRIBIDI_PAR_ON; int unicodeLength; #endif #ifdef USE_XFT XGlyphInfo extents; #endif char *utf8String; /* Early return for empty strings. */ if(!str || !str[0]) { return; } /* Convert to UTF-8 if necessary. */ utf8String = GetUTF8String(str); /* Get the length of the UTF-8 string. */ len = strlen(utf8String); /* Apply the bidi algorithm if requested. */ #ifdef USE_FRIBIDI temp_i = AllocateStack((len + 1) * sizeof(FriBidiChar)); temp_o = AllocateStack((len + 1) * sizeof(FriBidiChar)); unicodeLength = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, utf8String, len, temp_i); fribidi_log2vis(temp_i, unicodeLength, &type, temp_o, NULL, NULL, NULL); output = AllocateStack(4 * len + 1); fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, temp_o, unicodeLength, (char*)output); len = strlen(output); #else output = utf8String; #endif /* Get the bounds for the string based on the specified width. */ rect.x = x; rect.y = y; rect.height = GetStringHeight(font); #ifdef USE_XFT JXftTextExtentsUtf8(display, fonts[font], (const unsigned char*)output, len, &extents); rect.width = extents.xOff; #else rect.width = XTextWidth(fonts[font], output, len); #endif rect.width = Min(rect.width, width) + 2; /* Combine the width bounds with the region to use. */ renderRegion = XCreateRegion(); XUnionRectWithRegion(&rect, renderRegion, renderRegion); /* Display the string. */ #ifdef USE_XFT JXftDrawChange(xd, d); JXftDrawSetClip(xd, renderRegion); JXftDrawStringUtf8(xd, GetXftColor(color), fonts[font], x, y + fonts[font]->ascent, (const unsigned char*)output, len); JXftDrawChange(xd, rootWindow); #else JXSetForeground(display, fontGC, colors[color]); JXSetRegion(display, fontGC, renderRegion); JXSetFont(display, fontGC, fonts[font]->fid); JXDrawString(display, d, fontGC, x, y + fonts[font]->ascent, output, len); #endif /* Free any memory used for UTF conversion. */ #ifdef USE_FRIBIDI ReleaseStack(temp_i); ReleaseStack(temp_o); ReleaseStack(output); #endif ReleaseUTF8String(utf8String); XDestroyRegion(renderRegion); }
void ZLTextParagraphCursor::Builder::processTextEntry(const ZLTextEntry &textEntry) { const std::size_t dataLength = textEntry.dataLength(); if (dataLength == 0) { return; } myUcs4String.clear(); ZLUnicodeUtil::utf8ToUcs4(myUcs4String, textEntry.data(), dataLength); int len = myUcs4String.size(); myUcs4String.push_back(0); myBidiLevels.clear(); myBidiLevels.assign(len + 1, 0); int firstNonSpace = 0; while ((firstNonSpace < len) && ZLUnicodeUtil::isSpace(myUcs4String[firstNonSpace])) { myBidiLevels[firstNonSpace++] = myLatestBidiLevel; } int lastNonSpace = len - 1; if (lastNonSpace > firstNonSpace - 1) { while (ZLUnicodeUtil::isSpace(myUcs4String[lastNonSpace])) { --lastNonSpace; } fribidi_log2vis((FriBidiChar*)&myUcs4String[firstNonSpace], lastNonSpace - firstNonSpace + 1, &myBidiCharType, 0, 0, 0, &myBidiLevels[firstNonSpace]); } myLatestBidiLevel = myBidiLevels[lastNonSpace]; for (int i = lastNonSpace; i < len; ++i) { myBidiLevels[i] = myLatestBidiLevel; } myBreaksTable.clear(); myBreaksTable.assign(dataLength, 0); const char *start = textEntry.data(); const char *end = start + dataLength; set_linebreaks_utf8((const utf8_t*)start, dataLength, myLanguage.c_str(), &myBreaksTable[0]); ZLUnicodeUtil::Ucs4Char ch = 0, previousCh; enum { NO_SPACE, SPACE, NON_BREAKABLE_SPACE } spaceState = NO_SPACE; int charLength = 0; int index = 0; const char *wordStart = start; updateBidiLevel(myBidiLevels[0]); for (const char *ptr = start; ptr < end; ptr += charLength, ++index) { previousCh = ch; charLength = ZLUnicodeUtil::firstChar(ch, ptr); if (ZLUnicodeUtil::isSpace(ch)) { if ((spaceState == NO_SPACE) && (ptr != wordStart)) { addWord(wordStart, myOffset + (wordStart - start), ptr - wordStart); } spaceState = SPACE; } else if (ZLUnicodeUtil::isNBSpace(ch)) { if (spaceState == NO_SPACE) { if (ptr != wordStart) { addWord(wordStart, myOffset + (wordStart - start), ptr - wordStart); } spaceState = NON_BREAKABLE_SPACE; } } else { switch (spaceState) { case SPACE: if ((myBreaksTable[ptr - start - 1] == LINEBREAK_NOBREAK) || (previousCh == '-')) { myElements.push_back(ZLTextElementPool::Pool.NBHSpaceElement); } else { myElements.push_back(ZLTextElementPool::Pool.HSpaceElement); } wordStart = ptr; break; case NON_BREAKABLE_SPACE: myElements.push_back(ZLTextElementPool::Pool.NBHSpaceElement); wordStart = ptr; break; case NO_SPACE: if ((ptr > start) && ((((myBreaksTable[ptr - start - 1] != LINEBREAK_NOBREAK) && (previousCh != '-')) && (ptr != wordStart)) || (myBidiLevels[index - 1] != myBidiLevels[index]))) { addWord(wordStart, myOffset + (wordStart - start), ptr - wordStart); wordStart = ptr; } break; } spaceState = NO_SPACE; } updateBidiLevel(myBidiLevels[index]); } switch (spaceState) { case SPACE: myElements.push_back(ZLTextElementPool::Pool.HSpaceElement); break; case NON_BREAKABLE_SPACE: myElements.push_back(ZLTextElementPool::Pool.NBHSpaceElement); break; case NO_SPACE: addWord(wordStart, myOffset + (wordStart - start), end - wordStart); break; } myOffset += dataLength; }
int main (int argc, char *argv[]) { int exit_val; fribidi_boolean file_found; char *s; FILE *IN; text_width = 80; do_break = FRIBIDI_TRUE; do_pad = FRIBIDI_TRUE; do_mirror = FRIBIDI_TRUE; do_clean = FRIBIDI_FALSE; do_reorder_nsm = FRIBIDI_FALSE; show_input = FRIBIDI_FALSE; show_visual = FRIBIDI_TRUE; show_basedir = FRIBIDI_FALSE; show_ltov = FRIBIDI_FALSE; show_vtol = FRIBIDI_FALSE; show_levels = FRIBIDI_FALSE; show_changes = FRIBIDI_FALSE; char_set = "UTF-8"; bol_text = NULL; eol_text = NULL; input_base_direction = FRIBIDI_TYPE_ON; if ((s = getenv ("COLUMNS"))) { int i; i = atoi (s); if (i > 0) text_width = i; } #define CHARSETDESC 257 #define CAPRTL 258 /* Parse the command line with getopt library */ /* Must set argv[0], getopt uses it to generate error messages */ argv[0] = appname; while (1) { int option_index = 0, c; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, 'V'}, {"verbose", 0, 0, 'v'}, {"debug", 0, 0, 'd'}, {"test", 0, 0, 't'}, {"charset", 1, 0, 'c'}, #ifndef FRIBIDI_NO_CHARSETS {"charsetdesc", 1, 0, CHARSETDESC}, {"caprtl", 0, 0, CAPRTL}, #endif {"showinput", 0, &show_input, FRIBIDI_TRUE}, {"nopad", 0, &do_pad, FRIBIDI_FALSE}, {"nobreak", 0, &do_break, FRIBIDI_FALSE}, {"width", 1, 0, 'w'}, {"bol", 1, 0, 'B'}, {"eol", 1, 0, 'E'}, {"nomirror", 0, &do_mirror, FRIBIDI_FALSE}, {"reordernsm", 0, &do_reorder_nsm, FRIBIDI_TRUE}, {"clean", 0, &do_clean, FRIBIDI_TRUE}, {"ltr", 0, (int *) &input_base_direction, FRIBIDI_TYPE_L}, {"rtl", 0, (int *) &input_base_direction, FRIBIDI_TYPE_R}, {"wltr", 0, (int *) &input_base_direction, FRIBIDI_TYPE_WL}, {"wrtl", 0, (int *) &input_base_direction, FRIBIDI_TYPE_WR}, {"basedir", 0, &show_basedir, FRIBIDI_TRUE}, {"ltov", 0, &show_ltov, FRIBIDI_TRUE}, {"vtol", 0, &show_vtol, FRIBIDI_TRUE}, {"levels", 0, &show_levels, FRIBIDI_TRUE}, {"changes", 0, &show_changes, FRIBIDI_TRUE}, {"novisual", 0, &show_visual, FRIBIDI_FALSE}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "hVvdtc:w:B:E:", long_options, &option_index); if (c == -1) break; switch (c) { case 0: break; case 'h': help (); break; case 'V': version (); break; case 'v': show_basedir = FRIBIDI_TRUE; show_ltov = FRIBIDI_TRUE; show_vtol = FRIBIDI_TRUE; show_levels = FRIBIDI_TRUE; show_changes = FRIBIDI_TRUE; break; case 'w': text_width = atoi (optarg); if (text_width <= 0) die ("invalid screen width `%s'\n", optarg); break; case 'B': bol_text = optarg; break; case 'E': eol_text = optarg; break; case 'd': if (!fribidi_set_debug (FRIBIDI_TRUE)) die ("%s lib must be compiled with DEBUG option to enable\nturn debug info on.\n", FRIBIDI_PACKAGE); break; case 't': do_clean = FRIBIDI_TRUE; show_input = FRIBIDI_TRUE; do_break = FRIBIDI_FALSE; do_reorder_nsm = FRIBIDI_TRUE; break; case 'c': char_set = strdup (optarg); break; #ifndef FRIBIDI_NO_CHARSETS case CAPRTL: char_set = "CapRTL"; break; case CHARSETDESC: char_set = strdup (optarg); char_set_num = fribidi_parse_charset (char_set); if (!char_set_num) die ("unrecognized character set `%s'\n", char_set); if (!fribidi_char_set_desc (char_set_num)) die ("no description available for character set `%s'\n", fribidi_char_set_name (char_set_num)); else printf ("Descriptions for character set %s:\n" "\n" "%s", fribidi_char_set_title (char_set_num), fribidi_char_set_desc (char_set_num)); exit (0); break; #endif case ':': case '?': die (NULL); break; default: break; } } #ifdef FRIBIDI_NO_CHARSETS to_ucs4 = iconv_open ("WCHAR_T", char_set); from_ucs4 = iconv_open (char_set, "WCHAR_T"); #else char_set_num = fribidi_parse_charset (char_set); #endif #ifdef FRIBIDI_NO_CHARSETS if (to_ucs4 == (iconv_t) (-1) || from_ucs4 == (iconv_t) (-1)) #else if (!char_set_num) #endif die ("unrecognized character set `%s'\n", char_set); fribidi_set_mirroring (do_mirror); fribidi_set_reorder_nsm (do_reorder_nsm); exit_val = 0; file_found = FRIBIDI_FALSE; while (optind < argc || !file_found) { char *S_; S_ = optind < argc ? argv[optind++] : "-"; file_found = FRIBIDI_TRUE; /* Open the infile for reading */ if (S_[0] == '-' && !S_[1]) { IN = stdin; } else { IN = fopen (S_, "r"); if (!IN) { fprintf (stderr, "%s: %s: no such file or directory\n", appname, S_); exit_val = 1; continue; } } /* Read and process input one line at a time */ { char S_[MAX_STR_LEN]; int padding_width, break_width; padding_width = show_input ? (text_width - 10) / 2 : text_width; break_width = do_break ? padding_width : 3 * MAX_STR_LEN; while (fgets (S_, sizeof (S_) - 1, IN)) { char *new_line, *nl_found; FriBidiChar logical[MAX_STR_LEN]; char outstring[MAX_STR_LEN]; FriBidiCharType base; FriBidiStrIndex len; nl_found = ""; S_[sizeof (S_) - 1] = 0; len = strlen (S_); /* chop */ if (S_[len - 1] == '\n') { len--; S_[len] = '\0'; new_line = "\n"; } else new_line = ""; #ifdef FRIBIDI_NO_CHARSETS { char *st = S_, *ust = (char *) logical; int in_len = (int) len; len = sizeof logical; iconv (to_ucs4, &st, &in_len, &ust, (int *) &len); len = (FriBidiChar *) ust - logical; } #else len = fribidi_charset_to_unicode (char_set_num, S_, len, logical); #endif { FriBidiChar *visual; FriBidiStrIndex *ltov, *vtol; FriBidiLevel *levels; FriBidiStrIndex new_len; fribidi_boolean log2vis; visual = show_visual ? ALLOCATE (FriBidiChar, len + 1) : NULL; ltov = show_ltov ? ALLOCATE (FriBidiStrIndex, len + 1) : NULL; vtol = show_vtol ? ALLOCATE (FriBidiStrIndex, len + 1) : NULL; levels = show_levels ? ALLOCATE (FriBidiLevel, len + 1) : NULL; /* Create a bidi string. */ base = input_base_direction; log2vis = fribidi_log2vis (logical, len, &base, /* output */ visual, ltov, vtol, levels); if (log2vis) { if (show_input) printf ("%-*s => ", padding_width, S_); new_len = len; /* Remove explicit marks, if asked for. */ if (do_clean) len = fribidi_remove_bidi_marks (visual, len, ltov, vtol, levels); if (show_visual) { printf (nl_found); if (bol_text) printf ("%s", bol_text); /* Convert it to input charset and print. */ { FriBidiStrIndex idx, st; for (idx = 0; idx < len;) { FriBidiStrIndex wid, inlen; wid = break_width; st = idx; #ifndef FRIBIDI_NO_CHARSETS if (char_set_num != FRIBIDI_CHAR_SET_CAP_RTL) #endif while (wid > 0 && idx < len) wid -= fribidi_wcwidth (visual[idx++]); #ifndef FRIBIDI_NO_CHARSETS else while (wid > 0 && idx < len) { wid--; idx++; } #endif if (wid < 0 && idx > st + 1) idx--; inlen = idx - st; #ifdef FRIBIDI_NO_CHARSETS { char *str = outstring, *ust = (char *) (visual + st); int in_len = inlen * sizeof visual[0]; new_len = sizeof outstring; iconv (from_ucs4, &ust, &in_len, &str, (int *) &new_len); *str = '\0'; new_len = str - outstring; } #else new_len = fribidi_unicode_to_charset (char_set_num, visual + st, inlen, outstring); #endif if (FRIBIDI_IS_RTL (base)) printf ("%*s", (int) (do_pad ? (padding_width + strlen (outstring) - (break_width - wid)) : 0), outstring); else printf ("%s", outstring); if (idx < len) printf ("\n"); } } if (eol_text) printf ("%s", eol_text); nl_found = "\n"; } if (show_basedir) { printf (nl_found); printf ("Base direction: %s", (FRIBIDI_DIR_TO_LEVEL (base) ? "R" : "L")); nl_found = "\n"; } if (show_ltov) { FriBidiStrIndex i; printf (nl_found); for (i = 0; i < len; i++) printf ("%ld ", (long) ltov[i]); nl_found = "\n"; } if (show_vtol) { FriBidiStrIndex i; printf (nl_found); for (i = 0; i < len; i++) printf ("%ld ", (long) vtol[i]); nl_found = "\n"; } if (show_levels) { FriBidiStrIndex i; printf (nl_found); for (i = 0; i < len; i++) printf ("%d ", (int) levels[i]); nl_found = "\n"; } if (show_changes) { FriBidiStrIndex change_start, change_len; fribidi_find_string_changes (logical, len, visual, new_len, &change_start, &change_len); printf ("%sChange start[length] = %d[%d]", nl_found, change_start, change_len); nl_found = "\n"; } } else { exit_val = 2; } if (show_visual) free (visual); if (show_ltov) free (ltov); if (show_vtol) free (vtol); if (show_levels) free (levels); } if (*nl_found) printf (new_line); } } } return exit_val; }
char *FBidiConvert( const char *logical_str, const char *charset, int str_len, Bool *is_rtl, int *out_len, superimpose_char_t *comb_chars, int *l_to_v) { char *visual_str; FriBidiCharSet fribidi_charset; FriBidiChar *logical_unicode_str; FriBidiChar *visual_unicode_str; FriBidiParType pbase_dir = FRIBIDI_TYPE_ON; FriBidiStrIndex *pos_l_to_v; int i; if (logical_str == NULL || charset == NULL) { return NULL; } if (str_len < 0) { str_len = strlen(logical_str); } if (is_rtl != NULL) { *is_rtl = False; } fribidi_charset = fribidi_parse_charset((char *)charset); if (fribidi_charset == FRIBIDI_CHAR_SET_NOT_FOUND) { return NULL; } /* it is possible that we allocate a bit more here, if utf-8 */ logical_unicode_str = (FriBidiChar *)safemalloc((str_len + 1) * sizeof(FriBidiChar)); /* convert to unicode first */ str_len = fribidi_charset_to_unicode( fribidi_charset, (char *)logical_str, str_len, logical_unicode_str); visual_unicode_str = (FriBidiChar *)safemalloc((str_len + 1) * sizeof(FriBidiChar)); /* apply bidi algorithm, convert logical string to visual string */ /* also keep track of how characters are reordered here, to reorder combing characters accordingly */ pos_l_to_v = (FriBidiStrIndex *)safemalloc((str_len + 1) * sizeof(FriBidiStrIndex)); fribidi_log2vis( logical_unicode_str, str_len, &pbase_dir, visual_unicode_str, pos_l_to_v, NULL, NULL); /* remap mapping from logical to visual to "compensate" for BIDI */ if (comb_chars != NULL) { for (i = 0; comb_chars[i].c.byte1 != 0 || comb_chars[i].c.byte2 != 0; i++) { /* if input string is zero characters => only combining chars, set position to zero */ comb_chars[i].position = str_len != 0 ? pos_l_to_v[comb_chars[i].position] : 0; } } if (l_to_v != NULL) { /* values in the previuos mapping gives the position of input characters after combining step */ /* mapping from BIDI conversion maps from the positions in the output from combining */ int orig_len; int *l_to_v_temp; for (i = 0; l_to_v[i] != -1; i++) { } orig_len = i; l_to_v_temp = (int *)safemalloc(orig_len * sizeof(int)); for (i = 0; i < orig_len; i++) { l_to_v_temp[i] = pos_l_to_v[l_to_v[i]]; } for (i = 0; i < orig_len; i++) { l_to_v[i] = l_to_v_temp[i]; } free(l_to_v_temp); } free(pos_l_to_v); /* character shape/join - will get pulled into fribidi with time */ str_len = shape_n_join(visual_unicode_str, str_len); visual_str = (char *)safemalloc((4 * str_len + 1) * sizeof(char)); /* convert from unicode finally */ *out_len = fribidi_unicode_to_charset( fribidi_charset, visual_unicode_str, str_len, visual_str); if (is_rtl != NULL && fribidi_get_bidi_type(*visual_unicode_str) == FRIBIDI_TYPE_RTL) { *is_rtl = True; } free(logical_unicode_str); free(visual_unicode_str); return visual_str; }