void CTextRenderer::UpdateTextCache_BiDi(array<CHarfbuzzGlyph>* pGlyphChain, const char* pText) { //Use ICU for bidirectional text //note: bidirectional texts appear for example when a latin username is displayed in a arabic text UErrorCode ICUError = U_ZERO_ERROR; UnicodeString UTF16Text = icu::UnicodeString::fromUTF8(pText); UBiDi* pICUBiDi = ubidi_openSized(UTF16Text.length(), 0, &ICUError); //Perform the BiDi algorithm //TODO: change UBIDI_DEFAULT_LTR by some variable dependend of the user config ubidi_setPara(pICUBiDi, UTF16Text.getBuffer(), UTF16Text.length(), (Localization()->GetWritingDirection() == CLocalization::DIRECTION_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR), 0, &ICUError); if(U_SUCCESS(ICUError)) { UBiDiLevel ICULevel = 1&ubidi_getParaLevel(pICUBiDi); UBiDiDirection Direction = ubidi_getDirection(pICUBiDi); if(Direction != UBIDI_MIXED) { UpdateTextCache_Font(pGlyphChain, UTF16Text.getBuffer(), 0, UTF16Text.length(), (Direction == UBIDI_RTL)); } else { int CharStart = 0; UBiDiLevel level; int NumberOfParts = ubidi_countRuns(pICUBiDi, &ICUError); if(U_SUCCESS(ICUError)) { for(int i=0; i<NumberOfParts; i++) { int Start; int SubLength; Direction = ubidi_getVisualRun(pICUBiDi, i, &Start, &SubLength); UpdateTextCache_Font(pGlyphChain, UTF16Text.getBuffer(), Start, SubLength, (Direction == UBIDI_RTL)); } } else { dbg_msg("TextRenderer", "BiDi algorithm failed (ubidi_countRuns): %s", u_errorName(ICUError)); return; } } } else { dbg_msg("TextRenderer", "BiDi algorithm failed: %s", u_errorName(ICUError)); return; } }
void text_itemizer::itemize_direction(unsigned start, unsigned end) { direction_runs_.clear(); UErrorCode error = U_ZERO_ERROR; int32_t length = end - start; UBiDi *bidi = ubidi_openSized(length, 0, &error); if (!bidi || U_FAILURE(error)) { MAPNIK_LOG_ERROR(text_itemizer) << "Failed to create bidi object: " << u_errorName(error) << "\n"; return; } ubidi_setPara(bidi, text_.getBuffer() + start, length, UBIDI_DEFAULT_LTR, 0, &error); if (U_SUCCESS(error)) { UBiDiDirection direction = ubidi_getDirection(bidi); if (direction != UBIDI_MIXED) { direction_runs_.emplace_back(direction, start, end); } else { // mixed-directional int32_t count = ubidi_countRuns(bidi, &error); if(U_SUCCESS(error)) { for(int i=0; i<count; ++i) { int32_t vis_length; int32_t run_start; direction = ubidi_getVisualRun(bidi, i, &run_start, &vis_length); run_start += start; //Add offset to compensate offset in setPara direction_runs_.emplace_back(direction, run_start, run_start+vis_length); } } } } else { MAPNIK_LOG_ERROR(text_itemizer) << "ICU error: " << u_errorName(error) << "\n"; //TODO: Exception } ubidi_close(bidi); }
TextGroup::TextGroup(const std::string &input, hb_script_t script, const std::string &lang, hb_direction_t overallDirection) :script_(script) ,lang_(lang) ,overallDirection_(overallDirection) { if(hb_script_get_horizontal_direction(script_) == HB_DIRECTION_LTR) { addRun(input, HB_DIRECTION_LTR); } else { auto text = UnicodeString::fromUTF8(input); auto length = text.length(); printf("Hominlinx-->TextGroup::TextGroup str unicodelen[%d] ====text[0x%x]\n",length, text.charAt(0) ); UErrorCode err = U_ZERO_ERROR; UBiDi *bidi = ubidi_openSized(length, 0, &err);//Bidrectional text ubidi_setPara(bidi, text.getBuffer(), length, hbDirectionToUBIDILevel(overallDirection_), 0, &err); auto direction = ubidi_getDirection(bidi); if(direction != UBIDI_MIXED) { addRun(input, uciDirectionToHB(direction)); } else { auto count = ubidi_countRuns(bidi, &err); for(int i=0; i < count; ++i) { int32_t start, length; direction = ubidi_getVisualRun(bidi, i, &start, &length); addRun(text, direction, start, start + length); } } ubidi_close(bidi); } }
JNIEXPORT void JNICALL Java_java_text_Bidi_nativeBidiChars (JNIEnv *env, jclass cls, jobject jbidi, jcharArray text, jint tStart, jbyteArray embs, jint eStart, jint length, jint dir) { UErrorCode err = U_ZERO_ERROR; UBiDi* bidi = ubidi_openSized(length, length, &err); if (!U_FAILURE(err)) { jchar *cText = (jchar*)(*env)->GetPrimitiveArrayCritical(env, text, NULL); if (cText) { UBiDiLevel baseLevel = (UBiDiLevel)dir; jbyte *cEmbs = 0; uint8_t *cEmbsAdj = 0; if (embs != NULL) { cEmbs = (jbyte*)(*env)->GetPrimitiveArrayCritical(env, embs, NULL); if (cEmbs) { cEmbsAdj = (uint8_t*)(cEmbs + eStart); } } ubidi_setPara(bidi, cText + tStart, length, baseLevel, cEmbsAdj, &err); if (cEmbs) { (*env)->ReleasePrimitiveArrayCritical(env, embs, cEmbs, JNI_ABORT); } (*env)->ReleasePrimitiveArrayCritical(env, text, cText, JNI_ABORT); if (!U_FAILURE(err)) { jint resDir = (jint)ubidi_getDirection(bidi); jint resLevel = (jint)ubidi_getParaLevel(bidi); jint resRunCount = 0; jintArray resRuns = 0; jintArray resCWS = 0; if (resDir == UBIDI_MIXED) { resRunCount = (jint)ubidi_countRuns(bidi, &err); if (!U_FAILURE(err)) { if (resRunCount) { jint* cResRuns = (jint*)calloc(resRunCount * 2, sizeof(jint)); if (cResRuns) { UTextOffset limit = 0; UBiDiLevel level; jint *p = cResRuns; while (limit < length) { ubidi_getLogicalRun(bidi, limit, &limit, &level); *p++ = (jint)limit; *p++ = (jint)level; } { const DirProp *dp = bidi->dirProps; jint ccws = 0; jint n = 0; p = cResRuns; do { if ((*(p+1) ^ resLevel) & 0x1) { while (n < *p) { if (dp[n++] == WS) { ++ccws; } } } else { n = *p; } p += 2; } while (n < length); resCWS = (*env)->NewIntArray(env, ccws); if (resCWS) { jint* cResCWS = (jint*)(*env)->GetPrimitiveArrayCritical(env, resCWS, NULL); if (cResCWS) { jint ccws = 0; jint n = 0; p = cResRuns; do { if ((*(p+1) ^ resLevel) & 0x1) { while (n < *p) { if (dp[n] == WS) { cResCWS[ccws++] = n; } ++n; } } else { n = *p; } p += 2; } while (n < length); (*env)->ReleasePrimitiveArrayCritical(env, resCWS, cResCWS, 0); } } } resRuns = (*env)->NewIntArray(env, resRunCount * 2); if (resRuns) { (*env)->SetIntArrayRegion(env, resRuns, 0, resRunCount * 2, cResRuns); } free(cResRuns); } } } } resetBidi(env, cls, jbidi, resDir, resLevel, length, resRuns, resCWS); } } ubidi_close(bidi); } }
extern "C" jint Java_java_text_Bidi_ubidi_1getDirection(JNIEnv*, jclass, jlong ptr) { return ubidi_getDirection(uBiDi(ptr)); }
nsresult nsBidi::GetDirection(nsBidiDirection* aDirection) { *aDirection = nsBidiDirection(ubidi_getDirection(mBiDi)); return NS_OK; }