From: Tomasz Bochenski Date: Thu, 8 Sep 2016 14:08:10 +0000 (+0200) Subject: [Base-utils][Ubidi][ACR-808] Module implementation added. X-Git-Tag: submit/tizen/20170214.045940~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F70%2F87570%2F25;p=platform%2Fcore%2Fapi%2Fbase-utils.git [Base-utils][Ubidi][ACR-808] Module implementation added. Change-Id: I18bee9118b3dfb59b279d7e98449c52c4624cb12 Signed-off-by: Tomasz Bochenski Signed-off-by: Tomasz Bochenski --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7374727..f0d3397 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,6 +37,7 @@ SET(BASEUTILS_SRCS utils_i18n_parse_position.cpp utils_i18n_ushape.c utils_i18n_utmscale.c + utils_i18n_ubidi.c ) ADD_LIBRARY(${target_name} SHARED ${BASEUTILS_SRCS} @@ -84,5 +85,6 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${INC_DIR}/utils_i18n_field_position.h INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${INC_DIR}/utils_i18n_parse_position.h DESTINATION ${INCLUDE_INSTALL_DIR}/base) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${INC_DIR}/utils_i18n_ushape.h DESTINATION ${INCLUDE_INSTALL_DIR}/base) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${INC_DIR}/utils_i18n_utmscale.h DESTINATION ${INCLUDE_INSTALL_DIR}/base) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${INC_DIR}/utils_i18n_ubidi.h DESTINATION ${INCLUDE_INSTALL_DIR}/base) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${INC_DIR}/utils_i18n.h DESTINATION ${INCLUDE_INSTALL_DIR}/base) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${pc_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) diff --git a/src/include/utils_i18n.h b/src/include/utils_i18n.h index eb6d380..0376423 100644 --- a/src/include/utils_i18n.h +++ b/src/include/utils_i18n.h @@ -42,6 +42,7 @@ #include #include #include +#include /** * @file utils_i18n.h @@ -56,7 +57,29 @@ extern "C" { /** * @ingroup CAPI_BASE_UTILS_MODULE * @defgroup CAPI_BASE_UTILS_I18N_MODULE i18n - * @brief The i18n module contains uchar, ucollator, unormalization, usearch, ustring, ucalendar, udate, udatepg, ulocale, unumber, alpha_idx, formattable, measure unit, measure, format, measure format, field position, parse position, ushape and utmscale. + * @brief The i18n module contains: + * - uchar + * - ucollator + * - unormalization + * - usearch + * - ustring + * - ucalendar + * - udate + * - udatepg + * - ulocale + * - unumber + * - alpha_idx + * - formattable + * - measure unit + * - measure + * - format + * - measure format + * - field position + * - parse position + * - ushape + * - utmscale + * - ubidi + * * This module provides flexible generation of number or date format patterns and helps you format and parse dates/number for any locale. * The i18n module provides various features based on data from ICU. The following table shows the version of ICU used in each Tizen platform. * @@ -178,6 +201,10 @@ extern "C" { * * * + * + * + * + * *
@ref CAPI_BASE_UTILS_I18N_UTMSCALE_MODULEThe Universal Time Scale
@ref CAPI_BASE_UTILS_I18N_UBIDI_MODULEUbidi module provides implementation of the Unicode Bidirectional Algorithm.
* * @section CAPI_BASE_UTILS_I18N_MODULE_MAPPING_TABLE Mapping Table @@ -2924,6 +2951,7 @@ extern "C" { * u_shapeArabic * * + * * @ref CAPI_BASE_UTILS_I18N_UTMSCALE_MODULE * #i18n_utmscale_get_time_scale_value * utmscale_getTimeScaleValue @@ -2938,6 +2966,211 @@ extern "C" { * #i18n_utmscale_to_int64 * utmscale_toInt64 * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_destroy + * ubidi_close + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_count_paragraphs + * ubidi_countParagraphs + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_count_runs + * ubidi_countRuns + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_base_direction + * ubidi_getBaseDirection + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_class_cb + * ubidi_getClassCallback + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_customized_class + * ubidi_getCustomizedClass + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_direction + * ubidi_getDirection + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_length + * ubidi_getLength + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_level_at + * ubidi_getLevelAt + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_levels + * ubidi_getLevels + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_logical_index + * ubidi_getLogicalIndex + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_logical_map + * ubidi_getLogicalMap + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_logical_run + * ubidi_getLogicalRun + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_paragraph + * ubidi_getParagraph + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_paragraph_by_index + * ubidi_getParagraphByIndex + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_para_level + * ubidi_getParaLevel + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_processed_length + * ubidi_getProcessedLength + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_reordering_mode + * ubidi_getReorderingMode + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_reordering_options + * ubidi_getReorderingOptions + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_result_length + * ubidi_getResultLength + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_text + * ubidi_getText + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_visual_index + * ubidi_getVisualIndex + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_visual_map + * ubidi_getVisualMap + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_get_visual_run + * ubidi_getVisualRun + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_invert_map + * ubidi_invertMap + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_is_inverse + * ubidi_isInverse + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_is_order_paragraphs_ltr + * ubidi_isOrderParagraphsLTR + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_create + * ubidi_open + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_create_sized + * ubidi_openSized + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_order_paragraphs_ltr + * ubidi_orderParagraphsLTR + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_reorder_logical + * ubidi_reorderLogical + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_reorder_visual + * ubidi_reorderVisual + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_set_class_cb + * ubidi_setClassCallback + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_set_context + * ubidi_setContext + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_set_inverse + * ubidi_setInverse + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_set_line + * ubidi_setLine + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_set_para + * ubidi_setPara + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_set_reordering_mode + * ubidi_setReorderingMode + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_set_reordering_options + * ubidi_setReorderingOptions + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_write_reordered + * ubidi_writeReordered + * + * + * @ref CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * #i18n_ubidi_write_reverse + * ubidi_writeReverse + * * */ diff --git a/src/include/utils_i18n_types.h b/src/include/utils_i18n_types.h index bf016a1..d571a6a 100644 --- a/src/include/utils_i18n_types.h +++ b/src/include/utils_i18n_types.h @@ -3512,6 +3512,408 @@ typedef enum { I18N_UTMSCALE_VALUE_MAX /**< The number of time scale values, in other words limit of this enum.*/ } i18n_utmscale_value_e; +/** + * @} + */ + + +/** + * @addtogroup CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * @{ + */ + +/** + * @brief Value returned by i18n_ubidi_class_cb() callbacks when there is no need to override the standard ubidi class for a given code point. + * @since_tizen 3.0 + */ +#define I18N_UBIDI_CLASS_DEFAULT I18N_UCHAR_U_CHAR_DIRECTION_COUNT + +/** + * @brief Paragraph level setting: Constant indicating that the base direction depends on the first + * strong directional character in the text according to the Unicode Bidirectional Algorithm. + * If no strong directional character is present, then set the paragraph level to 0 + * (left-to-right). + * @details If this value is used in conjunction with reordering modes + * #I18N_UBIDI_REORDER_INVERSE_LIKE_DIRECT or #I18N_UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL, + * the text to reorder is assumed to be visual LTR, and the text after reordering is + * required to be the corresponding logical string with appropriate contextual direction. + * The direction of the result string will be RTL if either the rightmost or leftmost + * strong character of the source text is RTL or Arabic Letter, the direction will be LTR + * otherwise. + * + * If reordering option #I18N_UBIDI_OPTION_INSERT_MARKS is set, an RLM may be + * added at the beginning of the result string to ensure round trip (that the result + * string, when reordered back to visual, will produce the original source text). + * @since_tizen 3.0 + * @see I18N_UBIDI_REORDER_INVERSE_LIKE_DIRECT + * @see I18N_UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL + */ +#define I18N_UBIDI_DEFAULT_LTR 0xfe + +/** + * @brief Paragraph level setting: + * + * Constant indicating that the base direction depends on the first + * strong directional character in the text according to the Unicode Bidirectional Algorithm. + * If no strong directional character is present, then set the paragraph level to 1 + * (right-to-left). + * @details If this value is used in conjunction with reordering modes + * #I18N_UBIDI_REORDER_INVERSE_LIKE_DIRECT or #I18N_UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL, + * the text to reorder is assumed to be visual LTR, and the text after reordering is + * required to be the corresponding logical string with appropriate contextual direction. + * The direction of the result string will be RTL if either the rightmost or leftmost + * strong character of the source text is RTL or Arabic Letter, or if the text contains no + * strong character; the direction will be LTR otherwise. + * + * If reordering option + * #I18N_UBIDI_OPTION_INSERT_MARKS is set, an RLM may be added at the beginning of the + * result string to ensure round trip (that the result string, when reordered back to + * visual, will produce the original source text). + * @since_tizen 3.0 + * @see I18N_UBIDI_REORDER_INVERSE_LIKE_DIRECT + * @see I18N_UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL + */ + #define I18N_UBIDI_DEFAULT_RTL 0xff + +/** + * @brief Option bit for i18n_ubidi_write_reordered(): replace characters with the "mirrored" + * property in RTL runs by their mirror-image mappings. + * @since_tizen 3.0 + * @see i18n_ubidi_write_reordered() + */ +#define I18N_UBIDI_DO_MIRRORING 2 + +/** + * @brief Option bit for i18n_ubidi_write_reordered(): surround the run with LRMs if necessary; + * this is part of the approximate "inverse ubidi" algorithm. + * @details This option does not imply corresponding adjustment of the index mappings. + * @since_tizen 3.0 + * @see i18n_ubidi_set_inverse() + * @see i18n_ubidi_write_reordered() + */ +#define I18N_UBIDI_INSERT_LRM_FOR_NUMERIC 4 + +/** + * @brief Option bit for i18n_ubidi_write_reordered(): keep combining characters after their base + * characters in RTL runs. + * @since_tizen 3.0 + * @see i18n_ubidi_write_reordered() + */ +#define I18N_UBIDI_KEEP_BASE_COMBINING 1 + +/** + * @brief Bit flag for level input. + * @details Overrides directional properties. + * @since_tizen 3.0 + */ +#define I18N_UBIDI_LEVEL_OVERRIDE 0x80 + +/** + * @brief Special value which can be returned by the mapping functions when a logical index has no + * corresponding visual index or vice-versa. + * @details This may happen for the logical-to-visual mapping of a ubidi control when option + * #I18N_UBIDI_OPTION_REMOVE_CONTROLS is specified. This can also happen for the + * visual-to-logical mapping of a ubidi mark (LRM or RLM) inserted by option + * #I18N_UBIDI_OPTION_INSERT_MARKS. + * @since_tizen 3.0 + * @see i18n_ubidi_get_visual_index() + * @see i18n_ubidi_get_visual_map() + * @see i18n_ubidi_get_logical_index() + * @see i18n_ubidi_get_logical_map() + */ +#define I18N_UBIDI_MAP_NOWHERE (-1) + +/** + * @brief Maximum explicit embedding level. + * @details The maximum resolved level can be up to #I18N_UBIDI_MAX_EXPLICIT_LEVEL + 1. + * @since_tizen 3.0 + */ +#define I18N_UBIDI_MAX_EXPLICIT_LEVEL 125 + +/** + * @brief Option bit for i18n_ubidi_write_reordered(): write the output in reverse order. + * @details This has the same effect as calling i18n_ubidi_write_reordered() first without this + * option, and then calling i18n_ubidi_write_reordered() without mirroring. Doing this + * in the same step is faster and avoids a temporary buffer. An example for using this + * option is output to a character terminal that is designed for RTL scripts and stores + * text in reverse order. + * @since_tizen 3.0 + * @see i18n_ubidi_write_reordered() + */ +#define I18N_UBIDI_OUTPUT_REVERSE 16 + +/** + * @brief Option bit for i18n_ubidi_write_reordered(): remove ubidi control characters (this does + * not affect #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC). + * @details This option does not imply corresponding adjustment of the index mappings. + * @since_tizen 3.0 + * @see i18n_ubidi_write_reordered() + */ +#define I18N_UBIDI_REMOVE_BIDI_CONTROLS 8 + +/** + * @brief An #i18n_ubidi_h handle. + * @details Use i18n_ubidi_* functions to operate on Ubidi objects. + * @since_tizen 3.0 + */ +typedef void* i18n_ubidi_h; + +/** + * @brief Callback type declaration for overriding default ubidi class values with custom ones. + * @details Usually, the function pointer will be propagated to an #i18n_ubidi_h handle by calling + * the i18n_ubidi_set_class_cb() function; then the callback will be invoked by the UBA + * implementation any time the class of a character is to be determined. + * @since_tizen 3.0 + * + * @param[in] context A pointer to the callback private data + * @param[in] c The code point to get a ubidi class for + * + * @retval direction The directional property / ubidi class for the given code point @a c if + * the default class has been overridden, or #I18N_UBIDI_CLASS_DEFAULT if + * the standard ubidi class value for code point @a c is to be used. + * + * @see i18n_ubidi_set_class_cb() + * @see i18n_ubidi_get_class_cb() + */ +typedef i18n_uchar_direction_e (*i18n_ubidi_class_cb)(const void *context, i18n_uchar32 c); + +/** + * @brief The type of the level values in this ubidi implementation. + * @details It holds an embedding level and indicates the visual direction by its bit 0 + * (even/odd value). + * + * It can also hold non-level values for the @c para_level and @c embedding_levels + * arguments of i18n_ubidi_set_para(); there: + * - bit 7 of an @c embedding_levels[] value indicates whether the using application is + * specifying the level of a character to override whatever the ubidi implementation would + * resolve it to. + * - @c para_level can be set to the pseudo-level values #I18N_UBIDI_DEFAULT_LTR and + * #I18N_UBIDI_DEFAULT_RTL. + * + * The related constants are not real, valid level values. I18N_UBIDI_DEFAULT_XXX can be + * used to specify a default for the paragraph level for when the i18n_ubidi_set_para() + * function shall determine it but there is no strongly typed character in the input. + * + * Note that the value for #I18N_UBIDI_DEFAULT_LTR is even and the one for + * #I18N_UBIDI_DEFAULT_RTL is odd, just like with normal LTR and RTL level values - these + * special values are designed that way. Also, the implementation assumes that + * #I18N_UBIDI_MAX_EXPLICIT_LEVEL is odd. + * + * @see i18n_ubidi_set_para() + * @see I18N_UBIDI_DEFAULT_LTR + * @see I18N_UBIDI_DEFAULT_RTL + * @see I18N_UBIDI_LEVEL_OVERRIDE + * @see I18N_UBIDI_MAX_EXPLICIT_LEVEL + */ +typedef uint8_t i18n_ubidi_level_t; + + +/** + * @brief Enumeration for text direction. + * @since_tizen 3.0 + */ +typedef enum { + /** + * Left-to-right text. This is a 0 value. + * - As return value for i18n_ubidi_get_direction(), it means that the source string contains + * no right-to-left characters, or that the source string is empty and the paragraph level is + * even. + * - As return value for i18n_ubidi_get_base_direction(), it means that the first strong + * character of the source string has a left-to-right direction. + */ + I18N_UBIDI_LTR, + + /** + * Right-to-left text. This is a 1 value. + * - As return value for i18n_ubidi_get_direction(), it means that the source string contains + * no left-to-right characters, or that the source string is empty and the paragraph level is odd. + * - As return value for i18n_ubidi_get_base_direction(), it means that the first strong character + * of the source string has a right-to-left direction. + */ + I18N_UBIDI_RTL, + + /** + * Mixed-directional text. + * + * As return value for i18n_ubidi_get_direction(), it means that the + * source string contains both left-to-right and right-to-left characters. + */ + I18N_UBIDI_MIXED, + + /** + * No strongly directional text. + * + * As return value for i18n_ubidi_get_direction(), it means that + * the source string is missing or empty, or contains neither left-to-right nor right-to-left + * characters. + */ + I18N_UBIDI_NEUTRAL +} i18n_ubidi_direction_e; + + +/** + * @brief Enumeration for reordering mode. + * @details These values indicate which variant of the ubidi algorithm to use. + * @since_tizen 3.0 + * @see i18n_ubidi_set_reordering_mode() + * @see i18n_ubidi_set_inverse() + */ +typedef enum { + /** + * Regular Logical to Visual ubidi algorithm according to Unicode. This is a 0 value. + */ + I18N_UBIDI_REORDER_DEFAULT = 0, + + /** + * Logical to Visual algorithm which handles numbers in a way which mimicks the behavior of + * Windows XP. + */ + I18N_UBIDI_REORDER_NUMBERS_SPECIAL, + + /** + * Logical to Visual algorithm grouping numbers with adjacent R characters (reversible + * algorithm). + */ + I18N_UBIDI_REORDER_GROUP_NUMBERS_WITH_R, + + /** + * Reorder runs only to transform a Logical LTR string to the Logical RTL string with the same + * display, or vice-versa. + * + * If this mode is set together with option #I18N_UBIDI_OPTION_INSERT_MARKS, some ubidi + * controls in the source text may be removed and other controls may be added to produce the + * minimum combination which has the required display. + */ + I18N_UBIDI_REORDER_RUNS_ONLY, + + /** + * Visual to Logical algorithm which handles numbers like L (same algorithm as selected by + * i18n_ubidi_set_inverse(true). + */ + I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L, + + /** + * Visual to Logical algorithm equivalent to the regular Logical to Visual algorithm. + */ + I18N_UBIDI_REORDER_INVERSE_LIKE_DIRECT, + + /** + * Inverse ubidi (Visual to Logical) algorithm for the #I18N_UBIDI_REORDER_NUMBERS_SPECIAL + * ubidi algorithm. + */ + I18N_UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL, + + /** + * Number of values for reordering mode. + */ + I18N_UBIDI_REORDER_COUNT +} i18n_ubidi_reordering_mode_e; + + +/** + * @brief Enumeration for reordering options. + * @details These values indicate which options are specified to affect the ubidi algorithm. + * @since_tizen 3.0 + * @see i18n_ubidi_set_reordering_options() + * @see i18n_ubidi_set_inverse() + */ +typedef enum { + /** + * Option value for i18n_ubidi_set_reordering_options(): disable all the options which can be set + * with this function. + */ + I18N_UBIDI_OPTION_DEFAULT = 0, + + /** + * Option bit for i18n_ubidi_set_reordering_options(): insert ubidi marks (LRM or RLM) when + * needed to ensure correct result of a reordering to a Logical order. This option must be set + * or reset before calling i18n_ubidi_set_para(). + * + * This option is significant only with reordering modes which generate a result with Logical + * order, specifically: + * - #I18N_UBIDI_REORDER_RUNS_ONLY + * - #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L + * - #I18N_UBIDI_REORDER_INVERSE_LIKE_DIRECT + * - #I18N_UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * + * If this option is set in conjunction with reordering mode + * #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L or with calling i18n_ubidi_set_inverse(true), it + * implies option #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC in calls to function + * i18n_ubidi_write_reordered(). + * + * For other reordering modes, a minimum number of LRM or RLM characters will be added to the + * source text after reordering it so as to ensure round trip, i.e. when applying the inverse + * reordering mode on the resulting logical text with removal of ubidi marks (option + * #I18N_UBIDI_OPTION_REMOVE_CONTROLS set before calling i18n_ubidi_set_para() or option + * #I18N_UBIDI_REMOVE_BIDI_CONTROLS in i18n_ubidi_write_reordered(), the result will be identical + * to the source text in the first transformation. + * + * This option will be ignored if specified together with option + * #I18N_UBIDI_OPTION_REMOVE_CONTROLS. It inhibits option #I18N_UBIDI_REMOVE_BIDI_CONTROLS in + * calls to function i18n_ubidi_write_reordered() and it implies option + * #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC in calls to function i18n_ubidi_write_reordered() if the + * reordering mode is #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L. + * + * @see i18n_ubidi_set_reordering_mode() + * @see i18n_ubidi_set_reordering_options() + */ + I18N_UBIDI_OPTION_INSERT_MARKS = 1, + + /** + * Option bit for i18n_ubidi_set_reordering_options(): remove ubidi control characters. + * + * This option must be set or reset before calling i18n_ubidi_set_para(). + * + * This option nullifies option #I18N_UBIDI_OPTION_INSERT_MARKS. It inhibits option + * #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC in calls to function i18n_write_reordered() and it implies + * option #I18N_UBIDI_REMOVE_BIDI_CONTROLS in calls to that function. + * + * @see i18n_ubidi_set_reordering_mode() + * @see i18n_ubidi_set_reordering_options() + */ + I18N_UBIDI_OPTION_REMOVE_CONTROLS = 2, + + /** + * Option bit for i18n_ubidi_set_reordering_options(): process the output as part of a stream + * to be continued. + * + * This option must be set or reset before calling i18n_ubidi_set_para(). + * + * This option specifies that the caller is interested in processing large text object in parts. + * The results of the successive calls are expected to be concatenated by the caller. Only the + * call for the last part will have this option bit off. + * + * When this option bit is on, i18n_ubidi_set_para() may process less than the full source text + * in order to truncate the text at a meaningful boundary. The caller should call + * i18n_ubidi_get_processed_length() immediately after calling i18n_ubidi_set_para() + * in order to determine how much of the source text has been processed. + * Source text beyond that length should be resubmitted in following calls to + * i18n_ubidi_set_para(). + * The processed length may be less than the length of the source text if a character preceding + * the last character of the source text constitutes a reasonable boundary (like a block + * separator) for text to be continued. If the last character of the source text constitutes a + * reasonable boundary, the whole text will be processed at once. + * If nowhere in the source text there exists such a reasonable boundary, the processed length + * will be zero. + * The caller should check for such an occurrence and do one of the following: + * - submit a larger amount of text with a better chance to include a reasonable boundary. + * - resubmit the same text after turning off option #I18N_UBIDI_OPTION_STREAMING. + * + * In all cases, this option should be turned off before processing the last part of the text. + * + * When the #I18N_UBIDI_OPTION_STREAMING option is used, it is recommended to call + * i18n_ubidi_order_paragraphs_ltr() with argument order_paragraphs_ltr set to true before + * calling i18n_ubidi_set_para() so that later paragraphs may be concatenated to previous + * paragraphs on the right. + * + * @see i18n_ubidi_set_reordering_mode() + * @see i18n_ubidi_set_reordering_options() + * @see i18n_ubidi_get_processed_length() + * @see i18n_ubidi_order_paragraphs_ltr() + */ + I18N_UBIDI_OPTION_STREAMING = 4 +} i18n_ubidi_reordering_option_e; + /** * @} */ diff --git a/src/include/utils_i18n_ubidi.h b/src/include/utils_i18n_ubidi.h new file mode 100644 index 0000000..3c635db --- /dev/null +++ b/src/include/utils_i18n_ubidi.h @@ -0,0 +1,1317 @@ +/* +* Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Copyright (C) 1999-2013, International Business Machines Corporation +* and others. All Rights Reserved. +*/ + +#ifndef __UTILS_I18N_UBIDI_H__ +#define __UTILS_I18N_UBIDI_H__ + +#include + +/** + * @file utils_i18n_ubidi.h + * @version 0.1 + * @brief utils_i18n_ubidi + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup CAPI_BASE_UTILS_I18N_MODULE + * @defgroup CAPI_BASE_UTILS_I18N_UBIDI_MODULE Ubidi + * @brief Ubidi module provides an implementation of the Unicode Bidirectional Algorithm. + * + * @section CAPI_BASE_UTILS_I18N_UBIDI_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_BASE_UTILS_I18N_UBIDI_MODULE_OVERVIEW Overview + * @details Ubidi module provides an implementation of the Unicode Bidirectional Algorithm. The + * algorithm is defined in the Unicode Standard Annex #9. + * Note: Libraries that perform a bidirectional algorithm and reorder strings accordingly + * are sometimes called "Storage Layout Engines". + * ubidi and shaping APIs can be used at the core of such "Storage Layout Engines". + */ + +/** + * @addtogroup CAPI_BASE_UTILS_I18N_UBIDI_MODULE + * @{ + */ + +/** + * @brief This function must be called to free the memory associated with an #i18n_ubidi_h handle. + * @details Important: A parent #i18n_ubidi_h handle must not be destroyed or reused if it still has + * children. If an #i18n_ubidi_h handle has become the child of + * another one (its parent) by calling i18n_ubidi_set_line(), then the child object must be + * destroyed or reused (by calling i18n_ubidi_set_para() or i18n_ubidi_set_line()) before + * the parent object. + * @since_tizen 3.0 + * + * @param[in] ubidi #i18n_ubidi_h handle to be destroyed + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_para() + * @see i18n_ubidi_set_line() + */ +int i18n_ubidi_destroy(i18n_ubidi_h ubidi); + +/** + * @brief Gets the number of paragraphs. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] count The number of paragraphs + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_count_paragraphs(i18n_ubidi_h ubidi, int32_t *count); + +/** + * @brief Gets the number of runs. + * @details This function may invoke the actual reordering on the #i18n_ubidi_h handle, after + * i18n_ubidi_set_para() may have resolved only the levels of the text. Therefore, + * i18n_ubidi_count_runs() may have to allocate memory, and may fail doing so. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] count The number of runs + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @retval #I18N_ERROR_OUT_OF_MEMORY Out of memory + */ +int i18n_ubidi_count_runs(i18n_ubidi_h ubidi, int32_t *count); + +/** + * @brief Gets the base direction of the text provided according to the Unicode Bidirectional + * Algorithm. + * @details The base direction is derived from the first character in the string with bidirectional + * character type L, R, or AL. If the first such character has type L, #I18N_UBIDI_LTR is + * returned. If the first such character has type R or AL, #I18N_UBIDI_RTL is returned. + * If the string does not contain any character of these types, then #I18N_UBIDI_NEUTRAL + * is returned. + * + * This is a lightweight function for use when only the base direction is needed and no + * further bidi processing of the text is needed. + * @since_tizen 3.0 + * + * @param[in] text A pointer to the @a text whose base direction is needed. Note: the @a text + * must be (at least) @a length long. + * @param[in] length The length of the @a text; if @a length == -1 then the text must be + * zero-terminated + * @param[out] direction Base direction of the @a text + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_get_base_direction(const i18n_uchar *text, int32_t length, + i18n_ubidi_direction_e *direction); + +/** + * @brief Gets the current callback function used for ubidi class determination. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph #i18n_ubidi_h object + * @param[out] fn The callback function pointer. This can be @c NULL. + * @param[out] context The callback's private context. This can be @c NULL. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_class_cb() + */ +int i18n_ubidi_get_class_cb(i18n_ubidi_h ubidi, i18n_ubidi_class_cb *fn, + const void **context); + +/** + * @brief Retrieves the ubidi class for a given code point. + * @details If an #i18n_ubidi_class_cb callback is defined and returns a value other than + * #I18N_UBIDI_CLASS_DEFAULT, that value is used; otherwise the default class + * determination mechanism is invoked. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph #i18n_ubidi_h object + * @param[in] c The code point whose ubidi class must be retrieved + * @param[out] direction The ubidi class for character @a c based on the given @a ubidi instance + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_class_cb() + */ +int i18n_ubidi_get_customized_class(i18n_ubidi_h ubidi, i18n_uchar32 c, + i18n_uchar_direction_e *direction); + +/** + * @brief Gets the directionality of the text. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] direction A value of #I18N_UBIDI_LTR, #I18N_UBIDI_RTL or #I18N_UBIDI_MIXED + * that indicates if the entire text represented by this object is + * unidirectional, and which direction, or if it is mixed-directional. + * Note - The value #I18N_UBIDI_NEUTRAL is never returned from this + * method. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_direction_e + */ +int i18n_ubidi_get_direction(const i18n_ubidi_h ubidi, i18n_ubidi_direction_e *direction); + +/** + * @brief Gets the length of the text. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] length The length of the text that the #i18n_ubidi_h object was created for + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_get_length(const i18n_ubidi_h ubidi, int32_t *length); + +/** + * @brief Gets the level for one character. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[in] char_index The index of a character. It must be in the range + * [0..i18n_ubidi_get_processed_length(@a ubidi)-1] + * @param[out] level The level for the character at @a char_index (0 if @a char_index is not in + * the valid range) + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_level_t + * @see i18n_ubidi_get_processed_length() + */ +int i18n_ubidi_get_level_at(const i18n_ubidi_h ubidi, int32_t char_index, + i18n_ubidi_level_t *level); + +/** + * @brief Gets an array of levels for each character. + * @details Note that this function may allocate memory under some circumstances, unlike + * i18n_ubidi_get_level_at(). + * @since_tizen 3.0 + * @remarks @a levels should not be freed. + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object, whose text length must be + * strictly positive + * @param[out] levels The levels array for the text, or @c NULL if an error occurs + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @retval #I18N_ERROR_OUT_OF_MEMORY Out of memory + * @see i18n_ubidi_level_t + * @see i18n_ubidi_get_processed_length() + */ +int i18n_ubidi_get_levels(i18n_ubidi_h ubidi, const i18n_ubidi_level_t **levels); + +/** + * @brief Gets the logical text position from a visual position. + * @details If such a mapping is used many times on the same #i18n_ubidi_h object, then calling + * i18n_ubidi_get_visual_map() is more efficient. + * + * The value returned may be #I18N_UBIDI_MAP_NOWHERE if there is no logical position + * because the corresponding text character is a ubidi mark inserted in the output by + * option #I18N_UBIDI_OPTION_INSERT_MARKS. + * + * This is the inverse function to i18n_ubidi_get_visual_index(). + * + * When the visual output is altered by using options of i18n_ubidi_write_reordered() such + * as #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC, #I18N_UBIDI_KEEP_BASE_COMBINING, + * #I18N_UBIDI_OUTPUT_REVERSE, #I18N_UBIDI_REMOVE_BIDI_CONTROLS, the logical position + * returned may not be correct. + * It is advised to use, when possible, reordering options such as + * #I18N_UBIDI_OPTION_INSERT_MARKS and #I18N_UBIDI_OPTION_REMOVE_CONTROLS. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[in] visual_index The visual position of a character + * @param[out] logical_index The index of this character in the text + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_visual_map() + * @see i18n_ubidi_get_visual_index() + * @see i18n_ubidi_get_result_length() + */ +int i18n_ubidi_get_logical_index(i18n_ubidi_h ubidi, int32_t visual_index, int32_t *logical_index); + +/** + * @brief Gets a logical-to-visual index map (array) for the characters in the #i18n_ubidi_h (paragraph or + * line) object. + * @details Some values in the map may be #I18N_UBIDI_MAP_NOWHERE if the corresponding text + * characters are ubidi controls removed from the visual output by the option + * #I18N_UBIDI_OPTION_REMOVE_CONTROLS. + * + * When the visual output is altered by using options of i18n_ubidi_write_reordered() + * such as #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC, #I18N_UBIDI_KEEP_BASE_COMBINING, + * #I18N_UBIDI_OUTPUT_REVERSE, #I18N_UBIDI_REMOVE_BIDI_CONTROLS, the visual positions + * returned may not be correct. It is advised to use, when possible, reordering options + * such as #I18N_UBIDI_OPTION_INSERT_MARKS and #I18N_UBIDI_OPTION_REMOVE_CONTROLS. + * + * Note that in right-to-left runs, this mapping places second surrogates before first + * ones (which is generally a bad idea) and combining characters before base characters. + * Use of i18n_ubidi_write_reordered(), optionally with the #I18N_UBIDI_KEEP_BASE_COMBINING + * option can be considered instead of using the mapping, in order to avoid these issues. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] index_map A pointer to an array of i18n_ubidi_get_processed_length() + * indexes which will reflect the reordering of the characters. + * If option #I18N_UBIDI_OPTION_INSERT_MARKS is set, the number of + * elements allocated in the @a index_map must be no less than + * i18n_ubidi_get_result_length(). + * + * The array does not need to be initialized. + * + * The index map will result in + * index_map[logical_index] == visual_index. + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_visual_map() + * @see i18n_ubidi_get_visual_index() + * @see i18n_ubidi_get_processed_length() + * @see i18n_ubidi_get_result_length() + */ +int i18n_ubidi_get_logical_map(i18n_ubidi_h ubidi, int32_t *index_map); + +/** + * @brief Gets a logical run. + * @details This function returns information about a run and is used to retrieve runs in logical + * order. + * + * This is especially useful for line-breaking on a paragraph. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[in] logical_position A logical position within the source text + * @param[out] logical_limit The limit of the corresponding run. The l-value that you + * point to here may be the same expression (variable) as + * the one for @a logical_position. + * This pointer can be @c NULL if this value is not necessary. + * @param[out] level The level of the corresponding run. This pointer can be + * @c NULL if this value is not necessary. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_processed_length() + */ +int i18n_ubidi_get_logical_run(const i18n_ubidi_h ubidi, + int32_t logical_position, + int32_t *logical_limit, + i18n_ubidi_level_t *level); + +/** + * @brief Gets a paragraph, given a position within the text. + * @details This function returns information about a paragraph. + * + * Note: if the paragraph index is known, it is more efficient to retrieve the paragraph + * information using i18n_ubidi_get_paragraph_by_index(). + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[in] char_index The index of a character within the text, in the range + * [0..i18n_ubidi_get_processed_length(@a ubidi)-1] + * @param[out] para_start The index of the first character of the paragraph in the text. + * This pointer can be @c NULL if this value is not necessary. + * @param[out] para_limit The limit of the paragraph. The l-value that you point to here + * may be the same expression (variable) as the one for + * @a char_index. This pointer can be @c NULL if this value is not + * necessary. + * @param[out] para_level The level of the paragraph. This pointer can be @c NULL if this + * value is not necessary. + * @param[out] index The index of the paragraph containing the specified position + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_processed_length() + */ +int i18n_ubidi_get_paragraph(const i18n_ubidi_h ubidi, + int32_t char_index, + int32_t *para_start, + int32_t *para_limit, + i18n_ubidi_level_t *para_level, + int32_t *index); + +/** + * @brief Gets a paragraph, given the index of this paragraph. + * @details This function returns information about paragraphs. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph #i18n_ubidi_h object + * @param[in] para_index The number of the paragraph, in the range + * [0..i18n_ubidi_count_paragraphs(@a ubidi)-1] + * @param[out] para_start The index of the first character of the paragraph in the text. + * This pointer can be @c NULL if this value is not necessary. + * @param[out] para_limit The limit of the paragraph. This pointer can be @c NULL if this + * value is not necessary. + * @param[out] para_level The level of the paragraph. This pointer can be @c NULL if this + * value is not necessary. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_get_paragraph_by_index(const i18n_ubidi_h ubidi, + int32_t para_index, + int32_t *para_start, + int32_t *para_limit, + i18n_ubidi_level_t *para_level); + +/** + * @brief Gets the paragraph level of the text. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] level The paragraph level. If there are multiple paragraphs, their + * level may vary if the required para_level is + * #I18N_UBIDI_DEFAULT_LTR or #I18N_UBIDI_DEFAULT_RTL. In that case, + * the level of the first paragraph is returned. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_level_t + * @see i18n_ubidi_get_paragraph() + * @see i18n_ubidi_get_paragraph_by_index() + */ +int i18n_ubidi_get_para_level(const i18n_ubidi_h ubidi, i18n_ubidi_level_t *level); + +/** + * @brief Gets the length of the source text processed by the last call to i18n_ubidi_set_para(). + * @details This length may be different from the length of the source text if option + * #I18N_UBIDI_OPTION_STREAMING has been set. + * + * Note that whenever the length of the text affects the execution or the result of a + * function, it is the processed length which must be considered, except for + * i18n_ubidi_set_para() (which receives unprocessed source text) and i18n_ubidi_get_length() + * (which returns the original length of the source text). + * + * In particular, the processed @a length is the one to consider in the following cases: + * - maximum value of the limit argument of i18n_ubidi_set_line() + * - maximum value of the char_index argument of i18n_ubidi_get_paragraph() + * - maximum value of the char_index argument of i18n_ubidi_get_level_at() + * - number of elements in the array returned by i18n_ubidi_get_levels() + * - maximum value of the logical_start argument of i18n_ubidi_get_logical_run() + * - maximum value of the logical_index argument of i18n_ubidi_get_visual_index() + * - number of elements filled in the @a index_map argument of i18n_ubidi_get_logical_map() + * - length of text processed by i18n_ubidi_write_reordered() + * + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph #i18n_ubidi_h object + * @param[out] length The length of the part of the source text processed by the last + * call to i18n_ubidi_set_para() + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_para() + * @see I18N_UBIDI_OPTION_STREAMING + */ +int i18n_ubidi_get_processed_length(const i18n_ubidi_h ubidi, int32_t *length); + +/** + * @brief Gets the requested reordering mode for a given #i18n_ubidi_h object. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object + * @param[out] mode The current reordering mode of the @a ubidi object + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_reordering_mode() + */ +int i18n_ubidi_get_reordering_mode(i18n_ubidi_h ubidi, i18n_ubidi_reordering_mode_e *mode); + +/** + * @brief Gets the reordering options applied to a given #i18n_ubidi_h object. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object + * @param[out] options The current reordering options of the @a ubidi object; + * #i18n_ubidi_reordering_option_e values combined with bitwise 'or' + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_reordering_options() + */ +int i18n_ubidi_get_reordering_options(i18n_ubidi_h ubidi, uint32_t *options); + +/** + * @brief Gets the length of the reordered text resulting from the last call to + * i18n_ubidi_set_para(). + * @details This length may be different from the length of the source text if option + * #I18N_UBIDI_OPTION_INSERT_MARKS or option #I18N_UBIDI_OPTION_REMOVE_CONTROLS has been set. + * + * This resulting @a length is the one to consider in the following cases: + * - maximum value of the visual_index argument of i18n_ubidi_get_logical_index() + * - number of elements of the a index_map argument of i18n_ubidi_get_visual_map() + * + * Note that this @a length stays identical to the source text length if ubidi marks are + * inserted or removed using option bits of i18n_ubidi_write_reordered(), or if option + * #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L has been set. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph #i18n_ubidi_h object + * @param[out] length The length of the reordered text resulting from the last call to + * i18n_ubidi_set_para() + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_para() + * @see I18N_UBIDI_OPTION_INSERT_MARKS + * @see I18N_UBIDI_OPTION_REMOVE_CONTROLS + */ +int i18n_ubidi_get_result_length(const i18n_ubidi_h ubidi, int32_t *length); + +/** + * @brief Gets the pointer to the given #i18n_ubidi_h object's text. + * @since_tizen 3.0 + * @remarks @a text should be freed with free(). + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] text The pointer to the text that the @a ubidi object was created for + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @retval #I18N_ERROR_OUT_OF_MEMORY Out of memory + * @see i18n_ubidi_set_para() + * @see i18n_ubidi_set_line() + */ +int i18n_ubidi_get_text(const i18n_ubidi_h ubidi, char **text); + +/** + * @brief Gets the visual position from a logical text position. + * @details If such a mapping is used many times on the same #i18n_ubidi_h object, then calling + * i18n_ubidi_get_logical_map() is more efficient. + * + * The value returned may be #I18N_UBIDI_MAP_NOWHERE if there is no visual position because + * the corresponding text character is an ubidi control removed from output by the option + * #I18N_UBIDI_OPTION_REMOVE_CONTROLS. + * + * When the visual output is altered by using options of i18n_ubidi_write_reordered() + * such as #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC, #I18N_UBIDI_KEEP_BASE_COMBINING, + * #I18N_UBIDI_OUTPUT_REVERSE, #I18N_UBIDI_REMOVE_BIDI_CONTROLS, the visual position + * returned may not be correct. + * It is advised to use, when possible, reordering options such as + * #I18N_UBIDI_OPTION_INSERT_MARKS and #I18N_UBIDI_OPTION_REMOVE_CONTROLS. + * + * Note that in right-to-left runs, this mapping places second surrogates before first ones + * (which is generally a bad idea) and combining characters before base characters. Use of + * i18n_ubidi_write_reordered(), optionally with the #I18N_UBIDI_KEEP_BASE_COMBINING + * option can be considered instead of using the mapping, in order to avoid these issues. + * @since_tizen 3.0 + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[in] logical_index The index of a character in the text + * @param[out] visual_index The visual position of this character + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_logical_map() + * @see i18n_ubidi_get_logical_index() + * @see i18n_ubidi_get_processed_length() + */ +int i18n_ubidi_get_visual_index(i18n_ubidi_h ubidi, int32_t logical_index, int32_t *visual_index); + +/** + * @brief Gets a visual-to-logical index map (array) for the characters in the #i18n_ubidi_h + * (paragraph or line) object. + * @details Some values in the map may be #I18N_UBIDI_MAP_NOWHERE if the corresponding text + * characters are ubidi marks inserted in the visual output by the option + * #I18N_UBIDI_OPTION_INSERT_MARKS. + * + * When the visual output is altered by using options of i18n_ubidi_write_reordered() + * such as #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC, #I18N_UBIDI_KEEP_BASE_COMBINING, + * #I18N_UBIDI_OUTPUT_REVERSE, #I18N_UBIDI_REMOVE_BIDI_CONTROLS, the logical positions + * returned may not be correct. It is advised to use, when possible, reordering options + * such as #I18N_UBIDI_OPTION_INSERT_MARKS and #I18N_UBIDI_OPTION_REMOVE_CONTROLS. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[out] index_map Pointer to an array of i18n_ubidi_get_result_length() indexes + * which will reflect the reordering of the characters. If option + * #I18N_UBIDI_OPTION_REMOVE_CONTROLS is set, the number of + * elements allocated in @a index_map must be no less than + * i18n_ubidi_get_processed_length(). The array does not need to + * be initialized. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_logical_map() + * @see i18n_ubidi_get_logical_index() + * @see i18n_ubidi_get_processed_length() + * @see i18n_ubidi_get_result_length() + */ +int i18n_ubidi_get_visual_map(i18n_ubidi_h ubidi, int32_t *index_map); + +/** + * @brief Gets one run's logical start, length, and directionality, which can be 0 for LTR or 1 for + * RTL. + * @details In an RTL run, the character at the logical start is visually on the right of the + * displayed run. + * The @a length is the number of characters in the run. + * i18n_ubidi_count_runs() should be called before the runs are retrieved. + * + * Note that in right-to-left runs, code like this places second surrogates before first + * ones (which is generally a bad idea) and combining characters before base characters. + * + * Use of i18n_ubidi_write_reordered(), optionally with the #I18N_UBIDI_KEEP_BASE_COMBINING + * option, can be considered in order to avoid these issues. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph or line #i18n_ubidi_h object + * @param[in] run_index The number of the run in visual order, in the range + * [0..i18n_ubidi_count_runs(@a ubidi)-1] + * @param[out] logical_index The first logical character index in the text. The pointer + * may be @c NULL if this index is not needed + * @param[out] length The number of characters (at least one) in the run. + * The pointer may be @c NULL if this is not needed. + * @param[out] direction The directionality of the run, #I18N_UBIDI_LTR == 0 or + * #I18N_UBIDI_RTL == 1, never #I18N_UBIDI_MIXED, never + * #I18N_UBIDI_NEUTRAL. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_count_runs() + */ +int i18n_ubidi_get_visual_run(i18n_ubidi_h ubidi, + int32_t run_index, + int32_t *logical_index, + int32_t *length, + i18n_ubidi_direction_e *direction); + +/** + * @brief Inverts an index map. + * @details The index mapping of the first map is inverted and written to the second one. + * @since_tizen 3.0 + * @remarks The @a dest_map array should be provided by the user. + * + * @param[in] src_map An array with @a length elements which defines the original mapping + * from a source array containing @a length elements to a destination + * array. Some elements of the source array may have no mapping in + * the destination array. In that case, their value will be the + * special value #I18N_UBIDI_MAP_NOWHERE. + * All elements must be >=0 or equal to #I18N_UBIDI_MAP_NOWHERE. + * Some elements may have a value >= length, if the destination array + * has more elements than the source array. There must be no + * duplicate indexes (two or more elements with the same value + * except #I18N_UBIDI_MAP_NOWHERE). + * @param[in] length The length of each array + * @param[out] dest_map An array with a number of elements equal to 1 + the highest + * value in @a src_map. @a dest_map will be filled with the inverse + * mapping. If element with index i in @a src_map has a value k + * different from #I18N_UBIDI_MAP_NOWHERE, this means that element i + * of the source array maps to element k in the destination array. + * The inverse map will have value i in its k-th element. + * For all elements of the destination array which do not map to an + * element in the source array, the corresponding element in the + * inverse map will have a value equal to #I18N_UBIDI_MAP_NOWHERE. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see I18N_UBIDI_MAP_NOWHERE + */ +int i18n_ubidi_invert_map(const int32_t *src_map, int32_t length, int32_t *dest_map); + +/** + * @brief Gets whether the given #i18n_ubidi_h object is set to perform the inverse ubidi algorithm. + * @details Note: calling this function after setting the reordering mode with + * i18n_ubidi_set_reordering_mode() will return @c true if the reordering mode was set + * to #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L, @c false for all other values. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object + * @param[out] is_inverse @c true if the @a ubidi object is set to perform the inverse ubidi + * algorithm by handling numbers as L + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_inverse() + * @see i18n_ubidi_set_reordering_mode() + */ +int i18n_ubidi_is_inverse(i18n_ubidi_h ubidi, i18n_ubool *is_inverse); + +/** + * @brief Gets whether the given #i18n_ubidi_h object is set to allocate level 0 to block separators. + * @details This function gets the information whether the given #i18n_ubidi_h object is set to allocate level 0 to block separators. + * so that successive paragraphs progress from left to right. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object + * @param[out] is_order @c true if the @a ubidi object is set to allocate level 0 to block + * separators + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_order_paragraphs_ltr() + */ +int i18n_ubidi_is_order_paragraphs_ltr(i18n_ubidi_h ubidi, i18n_ubool *is_order); + +/** + * @brief Creates an ubidi object. + * @details Such an object is initially empty. It is assigned the ubidi properties of a piece of text + * containing one or more paragraphs by i18n_ubidi_set_para() or the ubidi properties of + * a line within a paragraph by i18n_ubidi_set_line(). + * + * This object can be reused for as long as it is not deallocated by calling + * i18n_ubidi_destroy(). + * + * i18n_ubidi_set_para() and i18n_ubidi_set_line() will allocate additional memory for + * internal structures as necessary. + * @since_tizen 3.0 + * @remarks @a ubidi should be destroyed with i18n_ubidi_destroy(). + * + * @param[out] ubidi An empty #i18n_ubidi_h object + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_create(i18n_ubidi_h *ubidi); + +/** + * @brief Creates an ubidi structure with preallocated memory for internal structures. + * @details This function provides an ubidi object like i18n_ubidi_create() with no arguments, + * but it also preallocates memory for internal structures according to the sizings + * supplied by the caller. + * + * Subsequent functions will not allocate any more memory, and are thus guaranteed not + * to fail because of lack of memory. + * + * The preallocation can be limited to some of the + * internal memory by setting some values to 0 here. That means that if, e.g., + * @a max_run_count cannot be reasonably predetermined and should not be set to @a max_length + * (the only failproof value) to avoid wasting memory, then @a max_run_count could be set to + * 0 here and the internal structures that are associated with it will be allocated on + * demand, just like with i18n_ubidi_create(). + * @since_tizen 3.0 + * @remarks @a ubidi should be destroyed with i18n_ubidi_destroy(). + * + * @param[in] max_length The maximum text or line length that internal memory will be + * preallocated for. An attempt to associate this object with a + * longer text will fail, unless this value is 0, which + * leaves the allocation up to the implementation. + * @param[in] max_run_count The maximum anticipated number of same-level runs that internal + * memory will be preallocated for. An attempt to access visual + * runs on an object that was not preallocated for as many runs + * as the text was actually resolved to will fail, unless this + * value is 0, which leaves the allocation up to the + * implementation. + * The number of runs depends on the actual text and maybe + * anywhere between 1 and @a max_length. It is typically small + * @param[out] ubidi An empty #i18n_ubidi_h handle with preallocated memory + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_create_sized(int32_t max_length, int32_t max_run_count, i18n_ubidi_h *ubidi); + +/** + * @brief Sets whether block separators must be allocated level zero, so that successive + * paragraphs will progress from left to right. + * @details This function must be called before i18n_ubidi_set_para(). Paragraph separators (B) may + * appear in the text. Setting them to level zero means that all paragraph separators + * (including one possibly appearing in the last text position) are kept in the reordered + * text after the text that they follow in the source text. When this feature is not + * enabled, a paragraph separator at the last position of the text before reordering will + * go to the first position of the reordered text when the paragraph level is odd. + * @since_tizen 3.0 + * @param[in] ubidi An #i18n_ubidi_h object + * @param[in] order_paragraphs_ltr Specifies whether paragraph separators (B) must receive + * level 0, so that successive paragraphs progress from left + * to right + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_para() + */ +int i18n_ubidi_order_paragraphs_ltr(i18n_ubidi_h ubidi, i18n_ubool order_paragraphs_ltr); + +/** + * @brief Performs logical reordering. + * @details This is a convenience function that does not use an #i18n_ubidi_h object. + * It is intended to be used for when an application has determined the levels of objects + * (character sequences) and just needs to have them reordered (L2). This is equivalent to + * using i18n_ubidi_get_logical_map() on an #i18n_ubidi_h object. + * + * The index map will result in index_map[logical_index] == visual_index. + * @since_tizen 3.0 + * + * @param[in] levels An array with @a length levels that have been determined by the + * application + * @param[in] length The number of levels in the array, or, semantically, the number + * of objects to be reordered. @a length must be > 0. + * @param[out] index_map Pointer to an array of @a length indexes which will reflect the + * reordering of the characters. The array does not need to be + * initialized. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_reorder_logical(const i18n_ubidi_level_t *levels, int32_t length, + int32_t *index_map); + +/** + * @brief Performs visual reordering. + * @details This is a convenience function that does not use an #i18n_ubidi_h object. + * It is intended to be used for when an application has determined the levels of objects + * (character sequences) and just needs to have them reordered (L2). This is equivalent + * to using i18n_ubidi_get_visual_map() on an #i18n_ubidi_h handle. + * The index map will result in @a index_map[visual_index] == logical_index. + * @since_tizen 3.0 + * + * @param[in] levels An array with @a length levels that have been determined by the + * application + * @param[in] length The number of levels in the array, or, semantically, the number + * of objects to be reordered. @a length must be > 0. + * @param[out] index_map Pointer to an array of @a length indexes which will reflect the + * reordering of the characters. The array does not need to be + * initialized. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_reorder_visual(const i18n_ubidi_level_t *levels, int32_t length, int32_t *index_map); + +/** + * @brief Sets the callback function and callback data used by the UBA implementation for ubidi class + * determination. + * @details This may be useful for assigning ubidi classes to PUA characters, or for special + * application needs. For instance, an application may want to handle all spaces like L + * or R characters (according to the base direction) when creating the visual ordering of + * logical lines which are part of a report organized in columns: there should not be + * interaction between adjacent cells. + * @since_tizen 3.0 + * + * @param[in] ubidi The paragraph #i18n_ubidi_h object + * @param[in] new_fn The new callback function pointer + * @param[in] new_context The new callback context pointer. This can be @c NULL. + * @param[out] old_fn The old callback function pointer. This can be @c NULL. + * @param[out] old_context The old callback's context. This can be @c NULL. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_class_cb() + */ +int i18n_ubidi_set_class_cb(i18n_ubidi_h ubidi, + i18n_ubidi_class_cb new_fn, + const void *new_context, + i18n_ubidi_class_cb *old_fn, + const void **old_context); +/** + * @brief Sets the context before a call to i18n_ubidi_set_para(). + * @details i18n_ubidi_set_para() computes the left-right directionality for a given piece of text + * which is supplied as one of its arguments. Sometimes this piece of text (the "main + * text") should be considered in context, because text appearing before ("prologue") + * and/or after ("epilogue") the main text may affect the result of this computation. + * + * This function specifies the prologue and/or the epilogue for the next call to + * i18n_ubidi_set_para(). The characters specified as prologue and epilogue should not + * be modified by the calling program until the call to i18n_ubidi_set_para() has returned. + * If successive calls to i18n_ubidi_set_para() all need specification of a context, + * i18n_ubidi_set_context() must be called before each call to i18n_ubidi_set_para(). + * In other words, a context is not "remembered" after the following successful call to + * i18n_ubidi_set_para(). + * + * If a call to i18n_ubidi_set_para() specifies #I18N_UBIDI_DEFAULT_LTR or + * #I18N_UBIDI_DEFAULT_RTL as para_level and is preceded by a call to + * i18n_ubidi_set_context() which specifies a prologue, the paragraph level will be + * computed taking into consideration the text in the prologue. + * + * When i18n_ubidi_set_para() is called without a previous call to i18n_ubidi_set_context(), + * the main text is handled as if preceded and followed by strong directional characters + * at the current paragraph level. Calling i18n_ubidi_set_context() with specification of + * a prologue will change this behavior by handling the main text as if preceded by the + * last strong character appearing in the prologue, if any. Calling + * i18n_ubidi_set_context() with specification of an epilogue will change the behavior of + * i18n_ubidi_set_para() by handling the main text as if followed by the first strong + * character or digit appearing in the epilogue, if any. + * + * Note 1: if i18n_ubidi_set_context() is called repeatedly without calling + * i18n_ubidi_set_para(), the earlier calls have no effect, only the last call will be + * remembered for the next call to i18n_ubidi_set_para(). + * + * Note 2: calling i18n_ubidi_set_context(ubidi, NULL, 0, NULL, 0) cancels any previous + * setting of non-empty prologue or epilogue. The next call to i18n_ubidi_set_para() will + * process no prologue or epilogue. + * + * Note 3: users must be aware that even after setting the context before a call to + * i18n_ubidi_set_para() to perform e.g. a logical to visual transformation, the resulting + * string may not be identical to what it would have been if all the text, including + * prologue and epilogue, had been processed together. + * Example (upper case letters represent RTL characters): + * + * prologue = "abc DE"\n + * epilogue = none\n + * main text = "FGH xyz"\n + * para_level = I18N_UBIDI_LTR\n + * display without prologue = "HGF xyz" ("HGF" is adjacent to "xyz")\n + * display with prologue = "abc HGFED xyz" ("HGF" is not adjacent to "xyz")\n + * @since_tizen 3.0 + * + * @param[in] ubidi A paragraph #i18n_ubidi_h object + * @param[in] prologue Pointer to the text which precedes the text that will be specified + * in a coming call to i18n_ubidi_set_para(). If there is no prologue + * to consider, then @a pro_length must be zero and this pointer can be + * @c NULL. + * @param[in] pro_length The length of the @a prologue; if @a pro_length == -1 then the prologue + * must be zero-terminated. Otherwise @a pro_length must be >= 0. + * If @a pro_length == 0, it means that there is no prologue to consider. + * @param[in] epilogue A pointer to the text which follows the text that will be specified + * in a coming call to i18n_ubidi_set_para(). If there is no epilogue + * to consider, then @a epi_length must be zero and this pointer can be + * @c NULL. + * @param[in] epi_length The length of the @a epilogue; if @a epi_length == -1 then the epilogue + * must be zero-terminated. Otherwise @a epi_length must be >= 0. + * If @a epi_length == 0, it means that there is no epilogue to consider. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_para() + */ +int i18n_ubidi_set_context(i18n_ubidi_h ubidi, + const i18n_uchar *prologue, + int32_t pro_length, + const i18n_uchar *epilogue, + int32_t epi_length); + +/** + * @brief Modifies the operation of the ubidi algorithm such that it approximates an "inverse ubidi" + * algorithm. + * @details This function must be called before i18n_ubidi_set_para(). + * + * The normal operation of the ubidi algorithm as described in the Unicode Technical Report + * is to take text stored in logical (keyboard, typing) order and to determine the + * reordering of it for visual rendering. Some legacy systems store text in visual order, + * and for operations with standard, Unicode-based algorithms, the text needs to be + * transformed to logical order. This is effectively the inverse algorithm of the + * described ubidi algorithm. + * Note that there is no standard algorithm for this "inverse ubidi" and that the current + * implementation provides only an approximation of "inverse ubidi". + * + * With @a is_inverse set to @c true, this function changes the behavior of some of the + * subsequent functions in a way that they can be used for the inverse ubidi algorithm. + * Specifically, runs of text with numeric characters will be treated in a special way and + * may need to be surrounded with LRM characters when they are written in reordered + * sequence. + * + * Output runs should be retrieved using i18n_ubidi_get_visual_run(). Since the actual + * input for "inverse ubidi" is visually ordered text and i18n_ubidi_get_visual_run() gets + * the reordered runs, these are actually the runs of the logically ordered output. + * Calling this function with argument @a is_inverse set to @c true is equivalent to calling + * i18n_ubidi_set_reordering_mode() with argument reordering_mode set to + * #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L. + * + * Calling this function with argument @a is_inverse set to @c false is equivalent to calling + * i18n_ubidi_set_reordering_mode() with argument reordering_mode set to + * #I18N_UBIDI_REORDER_DEFAULT. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object + * @param[in] is_inverse Specifies "forward" or "inverse" ubidi operation + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_para() + * @see i18n_ubidi_write_reordered() + * @see i18n_ubidi_set_reordering_mode() + */ +int i18n_ubidi_set_inverse(i18n_ubidi_h ubidi, i18n_ubool is_inverse); + +/** + * @brief Sets an #i18n_ubidi_h object to contain the reordering information, especially the resolved levels, + * for all the characters in a line of text. + * @details This line of text is specified by referring to an #i18n_ubidi_h object representing this + * information for a piece of text containing one or more paragraphs, and by specifying + * a range of indexes in this text. + * + * In the new line object, the indexes will range from 0 to @a limit - @a start - 1. + * + * This is used after calling i18n_ubidi_set_para() for a piece of text, and after + * line-breaking on that text. It is not necessary if each paragraph is treated as a + * single line. + * + * After line-breaking, rules (L1) and (L2) for the treatment of trailing WS and for + * reordering are performed on an #i18n_ubidi_h object that represents a line. + * + * Important: @a line_bidi shares data with @a para_bidi. You must destroy or reuse + * @a line_bidi before @a para_bidi. In other words, you must destroy or reuse the + * #i18n_ubidi_h object for a line before the object for its parent paragraph. + * + * The text pointer that was stored in @a para_bidi is also copied, and @a start is added to + * it so that it points to the beginning of the line for this object. + * @since_tizen 3.0 + * + * @param[in] para_bidi The parent paragraph object. It must have been set by a + * successful call to i18n_ubidi_set_para() + * @param[in] start The line's first index into the text + * @param[in] limit The index after the last line's index (its last index + 1) + * @param[in] line_bidi The object that will now represent a line of the text + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_set_para() + * @see i18n_ubidi_get_processed_length() + */ +int i18n_ubidi_set_line(const i18n_ubidi_h para_bidi, int32_t start, int32_t limit, + i18n_ubidi_h line_bidi); + +/** + * @brief Performs the Unicode bidi algorithm. + * @details It is defined in the Unicode Standard Anned #9, version 13, also described in The + * Unicode Standard, Version 4.0 . + * + * This function takes a piece of plain text containing one or more paragraphs, with or + * without externally specified embedding levels from styled text and computes the + * left-right-directionality of each character. + * + * If the entire text is all of the same directionality, then the function may not perform + * all the steps described by the algorithm, i.e., some levels may not be the same as if + * all steps were performed. This is not relevant for unidirectional text. + * For example, in pure LTR text with numbers the numbers would get a resolved level of 2 + * higher than the surrounding text according to the algorithm. This implementation may + * set all resolved levels to the same value in such a case. + * + * The text can be composed of multiple paragraphs. Occurrence of a block separator in + * the text terminates a paragraph, and whatever comes next starts a new paragraph. + * The exception to this rule is when a Carriage Return (CR) is followed by a Line Feed + * (LF). Both CR and LF are block separators, but in that case, the pair of characters is + * considered as terminating the preceding paragraph, and a new paragraph will be started + * by a character coming after the LF. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object allocated with i18n_ubidi_create() which + * will be set to contain the reordering information, especially + * the resolved levels for all the characters in the @a text + * @param[in] text A pointer to the text that the ubidi algorithm will be performed + * on. This pointer is stored in the #i18n_ubidi_h handle and can + * be retrieved with i18n_ubidi_get_text(). + * Note: The @a text must be (at least) @a length long. + * @param[in] length The length of the @a text; if @a length == -1 then the text must be + * zero-terminated + * @param[in] para_level Specifies the default level for the @a text; it is typically 0 + * (LTR) or 1 (RTL). If the function shall determine the paragraph + * level from the text, then @a para_level can be set to either + * #I18N_UBIDI_DEFAULT_LTR or #I18N_UBIDI_DEFAULT_RTL; if the text + * contains multiple paragraphs, the paragraph level shall be + * determined separately for each paragraph; if a paragraph does + * not include any strongly typed character, then the desired + * default is used (0 for LTR or 1 for RTL). Any other value + * between 0 and #I18N_UBIDI_MAX_EXPLICIT_LEVEL is also valid, with + * odd levels indicating RTL. + * @param[in] embedding_levels May be used to preset the embedding and override levels, + * ignoring characters like LRE and PDF in the text. + * A level overrides the directional property of its corresponding + * (same index) character if the level has the + * #I18N_UBIDI_LEVEL_OVERRIDE bit set. + * Caution: A copy of this pointer, not of the levels, will be stored in the + * #i18n_ubidi_h object; the @a embedding_levels array must not be + * deallocated before the #i18n_ubidi_h structure is destroyed or reused, + * and the @a embedding_levels should not be modified to avoid unexpected + * results on subsequent ubidi operations. However, the i18n_ubidi_set_para() + * and i18n_ubidi_set_line() functions may modify some or all of the levels. + * + * After the #i18n_ubidi_h object is reused or destroyed, the caller must + * take care of the deallocation of the @a embedding_levels array. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_set_para(i18n_ubidi_h ubidi, + const i18n_uchar *text, + int32_t length, + i18n_ubidi_level_t para_level, + i18n_ubidi_level_t *embedding_levels); + +/** + * @brief Modifies the operation of the ubidi algorithm such that it implements some variant to the + * basic ubidi algorithm or approximates an "inverse ubidi" algorithm, depending on different + * values of the "reordering mode". + * @details This function must be called before i18n_ubidi_set_para(), and stays in effect until + * called again with a different argument. + * + * The normal operation of the ubidi algorithm as described in the Unicode Standard Annex + * #9 is to take text stored in logical (keyboard, typing) order and to determine how to + * reorder it for visual rendering. + * + * With the @a reordering_mode set to a value other than #I18N_UBIDI_REORDER_DEFAULT, this + * function changes the behavior of some of the subsequent functions in a way such that + * they implement an inverse ubidi algorithm or some other algorithm variants. + * + * Some legacy systems store text in visual order, and for operations with standard, + * Unicode-based algorithms, the text needs to be transformed into logical order. This is + * effectively the inverse algorithm of the described ubidi algorithm. + * Note that there is no standard algorithm for this "inverse ubidi", so a number of + * variants are implemented here. + * + * In other cases, it may be desirable to emulate some variant of the Logical to Visual + * algorithm (e.g. one used in MS Windows), or perform a Logical to Logical transformation. + * - When the @a reordering_mode is set to #I18N_UBIDI_REORDER_DEFAULT, the standard ubidi + * Logical to Visual algorithm is applied. + * - When the @a reordering_mode is set to #I18N_UBIDI_REORDER_NUMBERS_SPECIAL, the + * algorithm used to perform ubidi transformations when calling i18n_ubidi_set_para() + * should approximate the algorithm used in Microsoft Windows XP rather than strictly + * conform to the Unicode bidi algorithm. The differences between the basic algorithm + * and the algorithm addressed by this option are as follows: + * - Within text at an even embedding level, the sequence "123AB" (where AB + * represent R or AL letters) is transformed to "123BA" by the Unicode algorithm + * and to "BA123" by the Windows algorithm. + * - Arabic-Indic numbers (AN) are handled by the Windows algorithm just like + * regular numbers (EN). + * - When the @a reordering_mode is set to #I18N_UBIDI_REORDER_GROUP_NUMBERS_WITH_R, + * numbers located between LTR text and RTL text are associated with the RTL text. + * For instance, an LTR paragraph with content "abc 123 DEF" (where upper case letters + * represent RTL characters) will be transformed to "abc FED 123" (and not "abc 123 + * FED"), "DEF 123 abc" will be transformed to "123 FED abc" and "123 FED abc" + * will be transformed to "DEF 123 abc". This makes the algorithm reversible and makes + * it useful when round trip (from visual to logical and back to visual) must be + * achieved without adding LRM characters. However, this is a variation from the + * standard Unicode bidi algorithm. The source text should not contain ubidi control + * characters other than LRM or RLM. + * - When the @a reordering_mode is set to #I18N_UBIDI_REORDER_RUNS_ONLY, a "Logical to + * Logical" transformation must be performed: + * - If the default text level of the source text (argument para_level in + * i18n_ubidi_set_para() ) is even, the source text will be handled as LTR logical + * text and will be transformed to the RTL logical text which has the same LTR + * visual display. + * - If the default level of the source text is odd, the source text will be + * handled as RTL logical text and will be transformed to the LTR logical text + * which has the same LTR visual display. + * This mode may be needed when logical text which is basically Arabic or Hebrew, with + * possible included numbers or phrases in English, has to be displayed as if it had + * an even embedding level (this can happen if the displaying application treats all + * text as if it was basically LTR). + * This mode may also be needed in the reverse case, when logical text which is + * basically English, with possible included phrases in Arabic or Hebrew, has to be + * displayed as if it had an odd embedding level. Both cases could be handled by + * adding LRE or RLE at the head of the text, if the display subsystem supports these + * formatting controls. If it does not, the problem may be handled by transforming + * the source text in this mode before displaying it, so that it will be displayed + * properly. + * + * The source text should not contain ubidi control characters other than + * LRM or RLM. + * - When the @a reordering_mode is set to #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L, an + * "inverse ubidi" algorithm is applied. Runs of text with numeric characters will be + * treated like LTR letters and may need to be surrounded with LRM characters when + * they are written in reordered sequence (the option #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC + * can be used with function i18n_ubidi_write_reordered() to this end. This mode is + * equivalent to calling i18n_ubidi_set_inverse() with argument is_inverse set to @c true. + * - When the @a reordering_mode is set to #I18N_UBIDI_REORDER_INVERSE_LIKE_DIRECT, the + * "direct" Logical to Visual Ubidi algorithm is used as an approximation of an + * "inverse ubidi" algorithm. This mode is similar to mode + * #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L but is closer to the regular ubidi algorithm. + * For example, an LTR paragraph with the content "FED 123 456 CBA" (where upper case + * represents RTL characters) will be transformed to "ABC 456 123 DEF", as opposed to + * "DEF 123 456 ABC" with mode #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L. + * When used in conjunction with option #I18N_UBIDI_OPTION_INSERT_MARKS, this mode + * generally adds ubidi marks to the output significantly more sparingly than mode + * #I18N_UBIDI_REORDER_INVERSE_NUMBERS_AS_L with option + * #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC in calls to i18n_ubidi_write_reordered(). + * - When the reordering mode is set to #I18N_UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL, + * the Logical to Visual ubidi algorithm used in Windows XP is used as an approximation + * of an "inverse ubidi" algorithm. + * For example, an LTR paragraph with the content "abc FED123" (where upper case + * represents RTL characters) will be transformed to "abc 123DEF." + * + * In all the reordering modes specifying an "inverse ubidi" algorithm (i.e. those with + * a name starting with I18N_UBIDI_REORDER_INVERSE), output runs should be retrieved + * using i18n_ubidi_get_visual_run(), and the output text with + * i18n_ubidi_write_reordered(). The caller should keep in mind that in + * "inverse ubidi" modes the input is actually visually ordered text and reordered + * output returned by i18n_ubidi_get_visual_run() or i18n_ubidi_write_reordered() are + * actually runs or character string of logically ordered output. + * For all the "inverse ubidi" modes, the source text should not contain ubidi control + * characters other than LRM or RLM. + * + * Note that option #I18N_UBIDI_OUTPUT_REVERSE of i18n_ubidi_write_reordered() has no useful + * meaning and should not be used in conjunction with any value of the @a reordering_mode + * specifying "inverse ubidi" or with value #I18N_UBIDI_REORDER_RUNS_ONLY. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object + * @param[in] reordering_mode Specifies the required variant of the ubidi algorithm + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_reordering_mode_e + * @see i18n_ubidi_set_inverse() + * @see i18n_ubidi_set_para() + * @see i18n_ubidi_write_reordered() + */ +int i18n_ubidi_set_reordering_mode(i18n_ubidi_h ubidi, + i18n_ubidi_reordering_mode_e reordering_mode); + +/** + * @brief Specifies which of the reordering options should be applied during ubidi transformations. + * @since_tizen 3.0 + * + * @param[in] ubidi An #i18n_ubidi_h object + * @param[in] reordering_options A bitwise 'or' combination of zero or more of: + * #I18N_UBIDI_OPTION_DEFAULT, #I18N_UBIDI_OPTION_INSERT_MARKS, + * #I18N_UBIDI_OPTION_REMOVE_CONTROLS, + * #I18N_UBIDI_OPTION_STREAMING. + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_reordering_options() + */ +int i18n_ubidi_set_reordering_options(i18n_ubidi_h ubidi, uint32_t reordering_options); + +/** + * @brief Takes an #i18n_ubidi_h object containing the reordering information for a piece of text (one + * or more paragraphs) set by i18n_ubidi_set_para() or for a line of text set by + * i18n_ubidi_set_line() and write a reordered string to the destination buffer. + * @details This function preserves the integrity of characters with multiple code units and + * (optionally) combining characters. Characters in RTL runs can be replaced by + * mirror-image characters in the destination buffer. Note that "real" mirroring has to be + * done in a rendering engine by glyph selection and that for many "mirrored" characters + * there are no Unicode characters as mirror-image equivalents. There are also options to + * insert or remove ubidi control characters; see the description of the @a dest_size and + * @a options parameters and of the option bit flags. + * @since_tizen 3.0 + * @remarks The @a dest array should be provided by the user. + * + * @param[in] ubidi An #i18n_ubidi_h object that is set by + * i18n_ubidi_set_para() or i18n_ubidi_set_line() and contains + * the reordering information for the text that it was defined for, + * as well as a pointer to that text. + * @param[in] options A bit set of options for the reordering that control how the + * reordered text is written. The options include mirroring the + * characters on a code point basis and inserting LRM characters, + * which is used especially for transforming visually stored text to + * logically stored text (although this is still an imperfect + * implementation of an "inverse ubidi" algorithm because it uses the + * "forward ubidi" algorithm at its core). The available options + * are: #I18N_UBIDI_DO_MIRRORING, #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC, + * #I18N_UBIDI_KEEP_BASE_COMBINING, #I18N_UBIDI_OUTPUT_REVERSE, + * #I18N_UBIDI_REMOVE_BIDI_CONTROLS. + * @param[in] dest_size The size of the @a dest buffer, in number of i18n_uchars. If the + * #I18N_UBIDI_INSERT_LRM_FOR_NUMERIC option is set, then the + * destination length could be as large as + * i18n_ubidi_get_length(@a ubidi)+2*i18n_ubidi_count_runs(@a ubidi). + * If the #I18N_UBIDI_REMOVE_BIDI_CONTROLS option is set, then the + * destination length may be less than i18n_ubidi_get_length(@a ubidi). + * If none of these options is set, then the destination length + * will be exactly i18n_ubidi_get_processed_length(@a ubidi). + * @param[out] dest A pointer to where the reordered text is to be copied. The + * source text and the destination buffer @a dest must not overlap. + * @param[out] output_length The length of the output string + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + * @see i18n_ubidi_get_processed_length() + */ +int i18n_ubidi_write_reordered(i18n_ubidi_h ubidi, + uint16_t options, + int32_t dest_size, + i18n_uchar *dest, + int32_t *output_length); + +/** + * @brief Reverses a Right-To-Left run of Unicode text. + * @details This function preserves the integrity of characters with multiple code units and + * (optionally) combining characters. Characters can be replaced by mirror-image + * characters in the destination buffer. Note that "real" mirroring has to be done in a + * rendering engine by glyph selection and that for many "mirrored" characters there are + * no Unicode characters as mirror-image equivalents. There are also options to insert + * or remove ubidi control characters. + * + * This function is the implementation for reversing RTL runs as part of + * i18n_ubidi_write_reordered(). For detailed descriptions of the parameters, see there. + * Since no ubidi controls are inserted here, the output string length will never exceed + * @a src_length. + * @since_tizen 3.0 + * + * @param[in] src A pointer to the RTL run text + * @param[in] src_length The length of the RTL run + * @param[in] options A bit set of options for the reordering that control how the + * reordered text is written. See the options parameter + * in i18n_ubidi_write_reordered(). + * @param[in] dest_size The size of the @a dest buffer, in number of i18n_uchars. If the + * #I18N_UBIDI_REMOVE_BIDI_CONTROLS option is set, then the + * destination length may be less than @a src_length. If this + * option is not set, then the destination length will be + * exactly @a src_length. + * @param[out] dest A pointer to where the reordered text is to be copied. + * @a src and @a dest arrays (of length @a src_length and @a dest_size, + * respectively) must not overlap. + * @param[out] output_length The length of the output string + * + * @remarks do not free @a dest with free() function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #I18N_ERROR_NONE Successful + * @retval #I18N_ERROR_INVALID_PARAMETER Invalid function parameter + */ +int i18n_ubidi_write_reverse(const i18n_uchar *src, + int32_t src_length, + uint16_t options, + int32_t dest_size, + i18n_uchar *dest, + int32_t *output_length); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif diff --git a/src/utils_i18n_ubidi.c b/src/utils_i18n_ubidi.c new file mode 100644 index 0000000..ff38fa9 --- /dev/null +++ b/src/utils_i18n_ubidi.c @@ -0,0 +1,535 @@ +/* +* Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#include +#include +#include + +#include +#include +#include + +int i18n_ubidi_destroy(i18n_ubidi_h ubidi) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + ubidi_close(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_count_paragraphs(i18n_ubidi_h ubidi, int32_t *count) +{ + retv_if(ubidi == NULL || count == NULL, I18N_ERROR_INVALID_PARAMETER); + + *count = ubidi_countParagraphs(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_count_runs(i18n_ubidi_h ubidi, int32_t *count) +{ + retv_if(ubidi == NULL || count == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *count = ubidi_countRuns(ubidi, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_base_direction(const i18n_uchar *text, int32_t length, + i18n_ubidi_direction_e *direction) +{ + retv_if(text == NULL || direction == NULL || length < -1, I18N_ERROR_INVALID_PARAMETER); + + *direction = ubidi_getBaseDirection(text, length); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_class_cb(i18n_ubidi_h ubidi, i18n_ubidi_class_cb *fn, const void **context) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + enum UCharDirection (*_fn)(const void *, UChar32); + ubidi_getClassCallback(ubidi, &_fn, context); + if (fn) + *fn = (i18n_uchar_direction_e (*)(const void *, i18n_uchar32)) _fn; + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_customized_class(i18n_ubidi_h ubidi, i18n_uchar32 c, + i18n_uchar_direction_e *direction) +{ + retv_if(ubidi == NULL || direction == NULL, I18N_ERROR_INVALID_PARAMETER); + + *direction = ubidi_getCustomizedClass(ubidi, c); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_direction(const i18n_ubidi_h ubidi, i18n_ubidi_direction_e *direction) +{ + retv_if(ubidi == NULL || direction == NULL, I18N_ERROR_INVALID_PARAMETER); + + *direction = ubidi_getDirection(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_length(const i18n_ubidi_h ubidi, int32_t *length) +{ + retv_if(ubidi == NULL || length == NULL, I18N_ERROR_INVALID_PARAMETER); + + *length = ubidi_getLength(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_level_at(const i18n_ubidi_h ubidi, int32_t char_index, i18n_ubidi_level_t *level) +{ + retv_if(ubidi == NULL || level == NULL, I18N_ERROR_INVALID_PARAMETER); + + *level = ubidi_getLevelAt(ubidi, char_index); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_levels(i18n_ubidi_h ubidi, const i18n_ubidi_level_t **levels) +{ + retv_if(ubidi == NULL || levels == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *levels = ubidi_getLevels(ubidi, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_logical_index(i18n_ubidi_h ubidi, int32_t visual_index, int32_t *logical_index) +{ + retv_if(ubidi == NULL || logical_index == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *logical_index = ubidi_getLogicalIndex(ubidi, visual_index, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_logical_map(i18n_ubidi_h ubidi, int32_t *index_map) +{ + retv_if(ubidi == NULL || index_map == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + ubidi_getLogicalMap(ubidi, index_map, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_logical_run(const i18n_ubidi_h ubidi, + int32_t logical_position, + int32_t *logical_limit, + i18n_ubidi_level_t *level) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + ubidi_getLogicalRun(ubidi, logical_position, logical_limit, level); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_paragraph(const i18n_ubidi_h ubidi, + int32_t char_index, + int32_t *para_start, + int32_t *para_limit, + i18n_ubidi_level_t *para_level, + int32_t *index) +{ + retv_if(ubidi == NULL || index == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *index = ubidi_getParagraph(ubidi, char_index, para_start, para_limit, para_level, + &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_paragraph_by_index(const i18n_ubidi_h ubidi, + int32_t para_index, + int32_t *para_start, + int32_t *para_limit, + i18n_ubidi_level_t *para_level) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + ubidi_getParagraphByIndex(ubidi, para_index, para_start, para_limit, para_level, + &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_para_level(const i18n_ubidi_h ubidi, i18n_ubidi_level_t *level) +{ + retv_if(ubidi == NULL || level == NULL, I18N_ERROR_INVALID_PARAMETER); + + *level = ubidi_getParaLevel(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_processed_length(const i18n_ubidi_h ubidi, int32_t *length) +{ + retv_if(ubidi == NULL || length == NULL, I18N_ERROR_INVALID_PARAMETER); + + *length = ubidi_getProcessedLength(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_reordering_mode(i18n_ubidi_h ubidi, i18n_ubidi_reordering_mode_e *mode) +{ + retv_if(ubidi == NULL || mode == NULL, I18N_ERROR_INVALID_PARAMETER); + + *mode = ubidi_getReorderingMode(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_reordering_options(i18n_ubidi_h ubidi, uint32_t *options) +{ + retv_if(ubidi == NULL || options == NULL, I18N_ERROR_INVALID_PARAMETER); + + *options = ubidi_getReorderingOptions(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_result_length(const i18n_ubidi_h ubidi, int32_t *length) +{ + retv_if(ubidi == NULL || length == NULL, I18N_ERROR_INVALID_PARAMETER); + + *length = ubidi_getResultLength(ubidi); + + return I18N_ERROR_NONE; +} + + +int i18n_ubidi_get_text(const i18n_ubidi_h ubidi, char **text) +{ + retv_if(ubidi == NULL || text == NULL, I18N_ERROR_INVALID_PARAMETER); + + *text = NULL; + + const UChar *_ubidi_text = ubidi_getText(ubidi); + retv_if(_ubidi_text == NULL, I18N_ERROR_INVALID_PARAMETER); + + int32_t ulen = u_strlen(_ubidi_text); + retv_if(ulen <= 0, I18N_ERROR_INVALID_PARAMETER); + + /* + * UTF-16 uses at least two bytes, growing up to four bytes as necessary, + * that is why we multiply UChar by 4. + */ + char _text[4*ulen+1]; + u_austrcpy(_text, _ubidi_text); + + int32_t len = strlen(_text); + + *text = (char *)malloc(len + 1); + retv_if(*text == NULL, I18N_ERROR_OUT_OF_MEMORY); + + strcpy(*text, _text); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_get_visual_index(i18n_ubidi_h ubidi, int32_t logical_index, int32_t *visual_index) +{ + retv_if(ubidi == NULL || visual_index == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *visual_index = ubidi_getVisualIndex(ubidi, logical_index, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_visual_map(i18n_ubidi_h ubidi, int32_t *index_map) +{ + retv_if(ubidi == NULL || index_map == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + ubidi_getVisualMap(ubidi, index_map, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_get_visual_run(i18n_ubidi_h ubidi, + int32_t run_index, + int32_t *logical_index, + int32_t *length, + i18n_ubidi_direction_e *direction) +{ + retv_if(ubidi == NULL || direction == NULL, I18N_ERROR_INVALID_PARAMETER); + + int32_t count_runs; + i18n_error_code_e i18n_error = i18n_ubidi_count_runs(ubidi, &count_runs); + if(i18n_error != I18N_ERROR_NONE) + return i18n_error; + + retv_if(run_index < 0 || run_index > count_runs-1, I18N_ERROR_INVALID_PARAMETER); + + *direction = ubidi_getVisualRun(ubidi, run_index, logical_index, length); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_invert_map(const int32_t *scr_map, int32_t length, int32_t *dest_map) +{ + retv_if(scr_map == NULL || dest_map == NULL, I18N_ERROR_INVALID_PARAMETER); + + ubidi_invertMap(scr_map, dest_map, length); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_is_inverse(i18n_ubidi_h ubidi, i18n_ubool *is_inverse) +{ + retv_if(ubidi == NULL || is_inverse == NULL, I18N_ERROR_INVALID_PARAMETER); + + *is_inverse = ubidi_isInverse(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_is_order_paragraphs_ltr(i18n_ubidi_h ubidi, i18n_ubool *is_order) +{ + retv_if(ubidi == NULL || is_order == NULL, I18N_ERROR_INVALID_PARAMETER); + + *is_order = ubidi_isOrderParagraphsLTR(ubidi); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_create(i18n_ubidi_h *ubidi) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + *ubidi = ubidi_open(); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_create_sized(int32_t max_length, int32_t max_run_count, i18n_ubidi_h *ubidi) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *ubidi = ubidi_openSized(max_length, max_run_count, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_order_paragraphs_ltr(i18n_ubidi_h ubidi, i18n_ubool order_paragraphs_ltr) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + ubidi_orderParagraphsLTR(ubidi, order_paragraphs_ltr); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_reorder_logical(const i18n_ubidi_level_t *levels, int32_t length, int32_t *index_map) +{ + retv_if(levels == NULL || index_map == NULL || length <= 0, I18N_ERROR_INVALID_PARAMETER); + + ubidi_reorderLogical(levels, length, index_map); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_reorder_visual(const i18n_ubidi_level_t *levels, int32_t length, int32_t *index_map) +{ + retv_if(levels == NULL || index_map == NULL || length <= 0, I18N_ERROR_INVALID_PARAMETER); + + ubidi_reorderVisual(levels, length, index_map); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_set_class_cb(i18n_ubidi_h ubidi, + i18n_ubidi_class_cb new_fn, + const void *new_context, + i18n_ubidi_class_cb *old_fn, + const void **old_context) +{ + retv_if(ubidi == NULL || new_fn == NULL, I18N_ERROR_INVALID_PARAMETER); + + enum UCharDirection (*_old_fn)(const void *, UChar32); + const void *_old_context; + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + ubidi_setClassCallback(ubidi, (enum UCharDirection (*)(const void*, UChar32)) new_fn, new_context, + &_old_fn, &_old_context, &icu_error); + if (old_fn) + *old_fn = (i18n_uchar_direction_e (*)(const void *, i18n_uchar32)) _old_fn; + if (old_context) + *old_context = _old_context; + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_set_context(i18n_ubidi_h ubidi, + const i18n_uchar *prologue, + int32_t pro_length, + const i18n_uchar *epilogue, + int32_t epi_length) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + ubidi_setContext(ubidi, prologue, pro_length, epilogue, epi_length, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_set_inverse(i18n_ubidi_h ubidi, i18n_ubool is_inverse) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + ubidi_setInverse(ubidi, is_inverse); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_set_line(const i18n_ubidi_h para_bidi, + int32_t start, + int32_t limit, + i18n_ubidi_h line_bidi) +{ + retv_if(para_bidi == NULL || line_bidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + ubidi_setLine(para_bidi, start, limit, line_bidi, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_set_para(i18n_ubidi_h ubidi, + const i18n_uchar *text, + int32_t length, + i18n_ubidi_level_t para_level, + i18n_ubidi_level_t *embedding_levels) +{ + retv_if(ubidi == NULL || text == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + ubidi_setPara(ubidi, text, length, para_level, embedding_levels, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_set_reordering_mode(i18n_ubidi_h ubidi, i18n_ubidi_reordering_mode_e reordering_mode) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + ubidi_setReorderingMode(ubidi, reordering_mode); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_set_reordering_options(i18n_ubidi_h ubidi, uint32_t reordering_options) +{ + retv_if(ubidi == NULL, I18N_ERROR_INVALID_PARAMETER); + + ubidi_setReorderingOptions(ubidi, reordering_options); + + return I18N_ERROR_NONE; +} + +int i18n_ubidi_write_reordered(i18n_ubidi_h ubidi, + uint16_t options, + int32_t dest_size, + i18n_uchar *dest, + int32_t *output_length) +{ + retv_if(ubidi == NULL || dest == NULL || output_length == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *output_length = ubidi_writeReordered(ubidi, dest, dest_size, options, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +} + +int i18n_ubidi_write_reverse(const i18n_uchar *src, + int32_t src_length, + uint16_t options, + int32_t dest_size, + i18n_uchar *dest, + int32_t *output_length) +{ + retv_if(src == NULL || dest == NULL || output_length == NULL, I18N_ERROR_INVALID_PARAMETER); + + i18n_error_code_e i18n_error; + UErrorCode icu_error = U_ZERO_ERROR; + *output_length = ubidi_writeReverse(src, src_length, dest, dest_size, options, &icu_error); + ERR_MAPPING(icu_error, i18n_error); + I18N_ERR(i18n_error); + + return i18n_error; +}