Merge "LayoutLib: Font variants" into lmp-preview-dev
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 9ea4538..d73adab 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -21,6 +21,8 @@
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import android.content.res.AssetManager;
+
 import java.awt.Font;
 import java.io.File;
 import java.util.ArrayList;
@@ -47,7 +49,6 @@
     private static final String FONT_SUFFIX_BOLDITALIC = "BoldItalic.ttf";
     private static final String FONT_SUFFIX_BOLD = "Bold.ttf";
     private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
-    private static final String FONT_SUBSTRING_COMPACT = "UI";
 
     /**
      * A class associating {@link Font} with its metadata.
@@ -56,11 +57,6 @@
         Font mFont;
         /** Regular, Bold, Italic, or BoldItalic. */
         int mStyle;
-        /**
-         * The variant of the Font - compact or elegant.
-         * @see Paint#setElegantTextHeight(boolean)
-         */
-        boolean mIsCompact;
     }
 
     // ---- delegate manager ----
@@ -75,6 +71,14 @@
 
     // ---- delegate data ----
     private List<FontInfo> mFonts = new ArrayList<FontInfo>();
+    /**
+     * The variant of the Font Family - compact or elegant.
+     * 0 is unspecified, 1 is compact and 2 is elegant. This needs to be kept in sync with values in
+     * android.graphics.FontFamily
+     *
+     * @see Paint#setElegantTextHeight(boolean)
+     */
+    private FontVariant mVariant;
     // Path of fonts that haven't been created since sFontLoader hasn't been initialized.
     private List<String> mPath = new ArrayList<String>();
 
@@ -93,37 +97,22 @@
         sPostInitDelegate.clear();
     }
 
-    public Font getFont(int style, boolean isCompact) {
+    public Font getFont(int style) {
         FontInfo plainFont = null;
-        FontInfo styledFont = null;  // Font matching the style but not isCompact
         for (FontInfo font : mFonts) {
             if (font.mStyle == style) {
-                if (font.mIsCompact == isCompact) {
-                    return font.mFont;
-                }
-                styledFont = font;
+                return font.mFont;
             }
-            if (font.mStyle == Font.PLAIN) {
-                if (plainFont == null) {
-                    plainFont = font;
-                    continue;
-                }
-                if (font.mIsCompact == isCompact) {
-                    // Override the previous selection of plain font since we've found a better one.
-                    plainFont = font;
-                }
+            if (font.mStyle == Font.PLAIN && plainFont == null) {
+                plainFont = font;
             }
         }
-        if (styledFont != null) {
-            return styledFont.mFont;
-        }
 
         // No font with the mentioned style is found. Try to derive one.
         if (plainFont != null && style > 0 && style < 4) {
-            styledFont = new FontInfo();
+            FontInfo styledFont = new FontInfo();
             styledFont.mFont = plainFont.mFont.deriveFont(style);
             styledFont.mStyle = style;
-            styledFont.mIsCompact = plainFont.mIsCompact;
             // Add the font to the list of fonts so that we don't have to derive it the next time.
             mFonts.add(styledFont);
             return styledFont.mFont;
@@ -131,11 +120,20 @@
         return null;
     }
 
+    public FontVariant getVariant() {
+        return mVariant;
+    }
+
+
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static long nCreateFamily() {
+    /*package*/ static long nCreateFamily(String lang, int variant) {
+        // TODO: support lang. This is required for japanese locale.
         FontFamily_Delegate delegate = new FontFamily_Delegate();
+        // variant can be 0, 1 or 2.
+        assert variant < 3;
+        delegate.mVariant = FontVariant.values()[variant];
         if (sFontLocation != null) {
             delegate.init();
         } else {
@@ -164,6 +162,13 @@
         return false;
     }
 
+    @LayoutlibDelegate
+    /*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                "FontFamily.addFontFromAsset is not supported.", null /*throwable*/, null /*data*/);
+        return false;
+    }
+
     private void init() {
         for (String path : mPath) {
             addFont(path);
@@ -195,13 +200,6 @@
             style = Font.ITALIC;
         }
         fontInfo.mStyle = style;
-
-        // Names of compact fonts end with UI-<style>.ttf. For example, NotoNakshUI-Regular.ttf.
-        // This should go away when this info is passed on by nAddFont().
-        int hyphenIndex = fontName.lastIndexOf('-');
-        fontInfo.mIsCompact = hyphenIndex > 0 &&
-                fontName.substring(0, hyphenIndex).endsWith(FONT_SUBSTRING_COMPACT);
-
     }
 
     private static Font loadFont(String path) {
@@ -214,7 +212,7 @@
             } catch (Exception e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
                         String.format("Unable to load font %1$s", relativePath),
-                        null /*throwable*/, null /*data*/);
+                        e /*throwable*/, null /*data*/);
             }
         } else {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -224,4 +222,12 @@
 
         return null;
     }
+
+
+    // ---- Public helper class ----
+
+    public enum FontVariant {
+        // The order needs to be kept in sync with android.graphics.FontFamily.
+        NONE, COMPACT, ELEGANT
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 911f4e7..d6e97f5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -21,6 +21,7 @@
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import android.graphics.FontFamily_Delegate.FontVariant;
 import android.graphics.Paint.FontMetrics;
 import android.graphics.Paint.FontMetricsInt;
 import android.text.TextUtils;
@@ -30,7 +31,6 @@
 import java.awt.Shape;
 import java.awt.Stroke;
 import java.awt.Toolkit;
-import java.awt.font.FontRenderContext;
 import java.awt.geom.AffineTransform;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -81,7 +81,8 @@
     private float mTextScaleX;
     private float mTextSkewX;
     private int mHintingMode = Paint.HINTING_ON;
-    private boolean mIsCompact = true;
+    // Variant of the font.
+    private FontVariant mFontVariant = FontVariant.NONE;
 
     private Xfermode_Delegate mXfermode;
     private ColorFilter_Delegate mColorFilter;
@@ -437,7 +438,7 @@
     /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
-        return delegate != null && !delegate.mIsCompact;
+        return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
     }
 
     @LayoutlibDelegate
@@ -448,7 +449,7 @@
             return;
         }
 
-        delegate.mIsCompact = !elegant;
+        delegate.mFontVariant = elegant ? FontVariant.ELEGANT : FontVariant.COMPACT;
     }
 
     @LayoutlibDelegate
@@ -1022,31 +1023,31 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_getTextPath(long native_object, int bidiFlags,
-                char[] text, int index, int count, float x, float y, long path) {
+    /*package*/ static void native_getTextPath(long native_object, long native_typeface,
+            int bidiFlags, char[] text, int index, int count, float x, float y, long path) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Paint.getTextPath is not supported.", null, null /*data*/);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_getTextPath(long native_object, int bidiFlags,
-            String text, int start, int end, float x, float y, long path) {
+    /*package*/ static void native_getTextPath(long native_object, long native_typeface,
+            int bidiFlags, String text, int start, int end, float x, float y, long path) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Paint.getTextPath is not supported.", null, null /*data*/);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeGetStringBounds(long nativePaint, String text, int start,
-            int end, int bidiFlags, Rect bounds) {
-        nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bidiFlags,
-                bounds);
+    /*package*/ static void nativeGetStringBounds(long nativePaint, long native_typeface,
+            String text, int start, int end, int bidiFlags, Rect bounds) {
+        nativeGetCharArrayBounds(nativePaint, native_typeface, text.toCharArray(), start,
+                end - start, bidiFlags, bounds);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeGetCharArrayBounds(long nativePaint, char[] text, int index,
-            int count, int bidiFlags, Rect bounds) {
+    /*package*/ static void nativeGetCharArrayBounds(long nativePaint, long native_typeface,
+            char[] text, int index, int count, int bidiFlags, Rect bounds) {
 
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
@@ -1124,7 +1125,7 @@
     private void updateFontObject() {
         if (mTypeface != null) {
             // Get the fonts from the TypeFace object.
-            List<Font> fonts = mTypeface.getFonts(mIsCompact);
+            List<Font> fonts = mTypeface.getFonts(mFontVariant);
 
             // create new font objects as well as FontMetrics, based on the current text size
             // and skew info.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 9746b48..908bb64 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -22,6 +22,7 @@
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.content.res.AssetManager;
+import android.graphics.FontFamily_Delegate.FontVariant;
 
 import java.awt.Font;
 import java.io.File;
@@ -69,17 +70,28 @@
         return sManager.getDelegate(nativeTypeface);
     }
 
-    public List<Font> getFonts(boolean compact) {
+    public List<Font> getFonts(FontVariant variant) {
         List<Font> fonts = new ArrayList<Font>(mFontFamilies.length);
+        // If we are unable to find fonts matching the variant, we return the fonts from the
+        // other variant since we always want to draw something, rather than nothing.
+        // TODO: check this behaviour with platform.
+        List<Font> otherVariantFonts = new ArrayList<Font>();
         for (FontFamily_Delegate ffd : mFontFamilies) {
             if (ffd != null) {
-                Font font = ffd.getFont(mStyle, compact);
+                Font font = ffd.getFont(mStyle);
                 if (font != null) {
-                    fonts.add(font);
+                    if (ffd.getVariant() == variant || ffd.getVariant() == FontVariant.NONE) {
+                        fonts.add(font);
+                    } else {
+                        otherVariantFonts.add(font);
+                    }
                 }
             }
         }
-        return fonts;
+        if (fonts.size() > 0) {
+            return fonts;
+        }
+        return otherVariantFonts;
     }
 
     // ---- native methods ----