Fix text rendering

There are still some errors
1. Little vertical clippping for extra tall glyphs.
2. Breaking into scripts isn't perfect which results in incorrect layout
of text.

Change-Id: I54de3c05eca5e8affb1135c120eea24c3afe8a47
diff --git a/bridge/src/android/graphics/Paint_Delegate.java b/bridge/src/android/graphics/Paint_Delegate.java
index c9c9800..41953ed 100644
--- a/bridge/src/android/graphics/Paint_Delegate.java
+++ b/bridge/src/android/graphics/Paint_Delegate.java
@@ -32,7 +32,6 @@
 import java.awt.Toolkit;
 import java.awt.font.FontRenderContext;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -576,7 +575,7 @@
             return 0;
         }
 
-        return delegate.measureText(text, index, count, bidiFlags);
+        return delegate.measureText(text, index, count, isRtl(bidiFlags));
     }
 
     @LayoutlibDelegate
@@ -615,7 +614,7 @@
             }
 
             // measure from start to end
-            float res = delegate.measureText(text, start, end - start + 1, bidiFlags);
+            float res = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
 
             if (measuredWidth != null) {
                 measuredWidth[measureIndex] = res;
@@ -980,51 +979,27 @@
     /*package*/ static float native_getTextRunAdvances(int native_object,
             char[] text, int index, int count, int contextIndex, int contextCount,
             int flags, float[] advances, int advancesIndex) {
+
+        if (advances != null)
+            for (int i = advancesIndex; i< advancesIndex+count; i++)
+                advances[i]=0;
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
+        if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
             return 0.f;
         }
+        boolean isRtl = isRtl(flags);
 
-        if (delegate.mFonts.size() > 0) {
-            // FIXME: handle multi-char characters (see measureText)
-            float totalAdvance = 0;
-            for (int i = 0; i < count; i++) {
-                char c = text[i + index];
-                boolean found = false;
-                for (FontInfo info : delegate.mFonts) {
-                    if (info.mFont.canDisplay(c)) {
-                        float adv = info.mMetrics.charWidth(c);
-                        totalAdvance += adv;
-                        if (advances != null) {
-                            advances[i] = adv;
-                        }
-
-                        found = true;
-                        break;
-                    }
-                }
-
-                if (found == false) {
-                    // no advance for this char.
-                    if (advances != null) {
-                        advances[i] = 0.f;
-                    }
-                }
-            }
-
-            return totalAdvance;
-        }
-
-        return 0;
-
+        int limit = index + count;
+        return new BidiRenderer(null, delegate, text).renderText(
+                index, limit, isRtl, advances, advancesIndex, false, 0, 0);
     }
 
     @LayoutlibDelegate
     /*package*/ static float native_getTextRunAdvances(int native_object,
             String text, int start, int end, int contextStart, int contextEnd,
             int flags, float[] advances, int advancesIndex) {
-        // FIXME: support contextStart, contextEnd and direction flag
+        // FIXME: support contextStart and contextEnd
         int count = end - start;
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
@@ -1080,19 +1055,12 @@
 
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
+        if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
             return;
         }
-
-        // FIXME should test if the main font can display all those characters.
-        // See MeasureText
-        if (delegate.mFonts.size() > 0) {
-            FontInfo mainInfo = delegate.mFonts.get(0);
-
-            Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count,
-                    delegate.mFontContext);
-            bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight());
-        }
+        int w = (int) delegate.measureText(text, index, count, isRtl(bidiFlags));
+        int h= delegate.getFonts().get(0).mMetrics.getHeight();
+        bounds.set(0, 0, w, h);
     }
 
     @LayoutlibDelegate
@@ -1176,6 +1144,7 @@
                     info.mFont = info.mFont.deriveFont(new AffineTransform(
                             mTextScaleX, mTextSkewX, 0, 1, 0, 0));
                 }
+                // The metrics here don't have anti-aliasing set.
                 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
 
                 infoList.add(info);
@@ -1185,64 +1154,9 @@
         }
     }
 
-    /*package*/ float measureText(char[] text, int index, int count, int bidiFlags) {
-        // TODO: find out what bidiFlags actually does.
-
-        // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText
-        // Any change to this method should be reflected there as well
-
-        if (mFonts.size() > 0) {
-            FontInfo mainFont = mFonts.get(0);
-            int i = index;
-            int lastIndex = index + count;
-            float total = 0f;
-            while (i < lastIndex) {
-                // always start with the main font.
-                int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
-                if (upTo == -1) {
-                    // shortcut to exit
-                    return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
-                } else if (upTo > 0) {
-                    total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-                    i = upTo;
-                    // don't call continue at this point. Since it is certain the main font
-                    // cannot display the font a index upTo (now ==i), we move on to the
-                    // fallback fonts directly.
-                }
-
-                // no char supported, attempt to read the next char(s) with the
-                // fallback font. In this case we only test the first character
-                // and then go back to test with the main font.
-                // Special test for 2-char characters.
-                boolean foundFont = false;
-                for (int f = 1 ; f < mFonts.size() ; f++) {
-                    FontInfo fontInfo = mFonts.get(f);
-
-                    // need to check that the font can display the character. We test
-                    // differently if the char is a high surrogate.
-                    int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                    upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
-                    if (upTo == -1) {
-                        total += fontInfo.mMetrics.charsWidth(text, i, charCount);
-                        i += charCount;
-                        foundFont = true;
-                        break;
-
-                    }
-                }
-
-                // in case no font can display the char, measure it with the main font.
-                if (foundFont == false) {
-                    int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                    total += mainFont.mMetrics.charsWidth(text, i, size);
-                    i += size;
-                }
-            }
-
-            return total;
-        }
-
-        return 0;
+    /*package*/ float measureText(char[] text, int index, int count, boolean isRtl) {
+        return new BidiRenderer(null, this, text).renderText(
+                index, index + count, isRtl, null, 0, false, 0, 0);
     }
 
     private float getFontMetrics(FontMetrics metrics) {
@@ -1281,4 +1195,14 @@
         }
     }
 
+    private static boolean isRtl(int flag) {
+        switch(flag) {
+        case Paint.BIDI_RTL:
+        case Paint.BIDI_FORCE_RTL:
+        case Paint.BIDI_DEFAULT_RTL:
+            return true;
+        default:
+            return false;
+        }
+    }
 }