From ea98db414033aa17aee720135e2f9ee0a08696cc Mon Sep 17 00:00:00 2001
From: Ken Bloom <kbloom at gmail com>
Date: Sat, 4 Sep 2010 15:01:33 +0200
Subject: added support for bidirectional text

---
 configure.in         | 27 +++++++++++++++++++++++++--
 src/FbTk/FbString.cc | 37 +++++++++++++++++++++++++++++++++++++
 src/FbTk/FbString.hh |  5 +++++
 src/FbTk/Font.cc     | 49 +++++++++++++++++++++++++++----------------------
 4 files changed, 94 insertions(+), 24 deletions(-)

diff --git a/configure.in b/configure.in
index 2766054..263beaf 100644
--- a/configure.in
+++ b/configure.in
@@ -163,8 +163,6 @@ dnl Check if iconv uses const in prototype declaration
     fi
 fi
 
-
-
 AC_CHECK_LIB(nsl, t_open, LIBS="$LIBS -lnsl")
 AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")
 
@@ -603,6 +601,31 @@ fi
 # )
 
 
+enableval="yes"
+AC_MSG_CHECKING([whether to have FRIBIDI support])
+AC_ARG_ENABLE(fribidi,
+	AC_HELP_STRING([--enable-fribidi],
+								 [FRIBIDI support [default=yes]]), ,
+							[enableval=yes])
+if test "x$enableval" = "xyes"; then
+	AC_MSG_RESULT([yes])
+	AC_CHECK_LIB(fribidi, fribidi_version_info,
+		AC_MSG_CHECKING([for fribidi/fribidi.h])
+		AC_TRY_COMPILE(
+#include <fribidi/fribidi.h>
+      , fribidi_version_info,
+			AC_MSG_RESULT([yes])
+			AC_DEFINE(HAVE_FRIBIDI, [1], [Define to 1 if you have FRIBIDI])
+			LIBS="$LIBS -lfribidi",
+		AC_MSG_RESULT([no])))
+else
+  AC_MSG_RESULT([no])
+  CONFIGOPTS="$CONFIGOPTS --disable-fribidi"
+fi
+
+
+
+
 
 AC_ARG_WITH(
   menu,
diff --git a/src/FbTk/FbString.cc b/src/FbTk/FbString.cc
index 0164afd..1cef002 100644
--- a/src/FbTk/FbString.cc
+++ b/src/FbTk/FbString.cc
@@ -45,6 +45,11 @@
 
 #include <iostream>
 
+#ifdef HAVE_FRIBIDI
+#include <fribidi/fribidi.h>
+#endif
+
+
 using std::string;
 
 #ifdef DEBUG
@@ -239,6 +244,37 @@ bool haveUTF8() {
 }
 
 
+#ifdef HAVE_FRIBIDI
+
+FbString BidiLog2Vis (const FbString& src){
+	FriBidiChar * us, * out_us;
+	FriBidiCharType base;
+	FbString r;
+	char * out;
+
+	us = new FriBidiChar[src.size()+1];
+	out_us = new FriBidiChar[src.size()+1];
+
+	unsigned int len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, const_cast<char *>(src.c_str()), src.length(), us);
+
+	base = FRIBIDI_TYPE_N;
+	fribidi_log2vis(us, len, &base, out_us, NULL, NULL, NULL);
+
+	out = new char[4*src.size()+1];
+
+	fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, out_us, len, out);
+
+	r = out;
+
+	delete[] out_us;
+	delete[] us;
+	delete[] out;
+
+	return r;
+}
+
+#endif
+
 } // end namespace StringUtil
 
 StringConvertor::StringConvertor(EncodingTarget target):
@@ -289,4 +325,5 @@ string StringConvertor::recode(const string &src) {
 #endif
 }
 
+
 } // end namespace FbTk
diff --git a/src/FbTk/FbString.hh b/src/FbTk/FbString.hh
index 1e473cc..e1a5dc5 100644
--- a/src/FbTk/FbString.hh
+++ b/src/FbTk/FbString.hh
@@ -52,6 +52,11 @@ std::string FbStrToX(const FbString &src);
 FbString LocaleStrToFb(const std::string &src);
 std::string FbStrToLocale(const FbString &src);
 
+#ifdef HAVE_FRIBIDI
+/// Make Bidi
+FbString BidiLog2Vis (const FbString& src);
+#endif
+
 bool haveUTF8();
 
 } // namespace FbStringUtil
diff --git a/src/FbTk/Font.cc b/src/FbTk/Font.cc
index cbd8250..28341a7 100644
--- a/src/FbTk/Font.cc
+++ b/src/FbTk/Font.cc
@@ -248,7 +248,13 @@ bool Font::load(const string &name) {
 }
 
 unsigned int Font::textWidth(const FbString &text, unsigned int size) const {
-    return m_fontimp->textWidth(text, size);
+#ifdef HAVE_FRIBIDI
+    const FbString visualOrder(FbTk::FbStringUtil::BidiLog2Vis(text));
+#else
+    const FbString &visualOrder = text;
+#endif
+
+    return m_fontimp->textWidth(visualOrder, size);
 }
 
 unsigned int Font::height() const {
@@ -273,31 +279,30 @@ void Font::drawText(const FbDrawable &w, int screen, GC gc,
     if (text.empty() || len == 0)
         return;
 
-    // so we don't end up in a loop with m_shadow
-    static bool first_run = true;
+#ifdef HAVE_FRIBIDI
+    const FbString visualOrder(FbTk::FbStringUtil::BidiLog2Vis(text));
+#else
+    const FbString &visualOrder = text;
+#endif
+
 
     // draw "effects" first
-    if (first_run) {
-        if (m_shadow) {
-            FbTk::GContext shadow_gc(w);
-            shadow_gc.setForeground(m_shadow_color);
-            first_run = false;
-            drawText(w, screen, shadow_gc.gc(), text, len,
-                     x + m_shadow_offx, y + m_shadow_offy, orient);
-            first_run = true;
-        } else if (m_halo) {
-            FbTk::GContext halo_gc(w);
-            halo_gc.setForeground(m_halo_color);
-            first_run = false;
-            drawText(w, screen, halo_gc.gc(), text, len, x + 1, y + 1, orient);
-            drawText(w, screen, halo_gc.gc(), text, len, x - 1, y + 1, orient);
-            drawText(w, screen, halo_gc.gc(), text, len, x - 1, y - 1, orient);
-            drawText(w, screen, halo_gc.gc(), text, len, x + 1, y - 1, orient);
-            first_run = true;
-        }
+    if (m_shadow) {
+        FbTk::GContext shadow_gc(w);
+        shadow_gc.setForeground(m_shadow_color);
+        m_fontimp->drawText(w, screen, shadow_gc.gc(), visualOrder, len,
+                 x + m_shadow_offx, y + m_shadow_offy, orient);
+    } else if (m_halo) {
+        FbTk::GContext halo_gc(w);
+        halo_gc.setForeground(m_halo_color);
+        m_fontimp->drawText(w, screen, halo_gc.gc(), visualOrder, len, x + 1, y + 1, orient);
+        m_fontimp->drawText(w, screen, halo_gc.gc(), visualOrder, len, x - 1, y + 1, orient);
+        m_fontimp->drawText(w, screen, halo_gc.gc(), visualOrder, len, x - 1, y - 1, orient);
+        m_fontimp->drawText(w, screen, halo_gc.gc(), visualOrder, len, x + 1, y - 1, orient);
     }
 
-    m_fontimp->drawText(w, screen, gc, text, len, x, y, orient);
+    m_fontimp->drawText(w, screen, gc, visualOrder, len, x, y, orient);
+
 
 }
 
-- 
cgit v0.11.2