diff options
author | Deepanshu Gupta <deepanshu@google.com> | 2014-05-19 16:14:23 -0700 |
---|---|---|
committer | Deepanshu Gupta <deepanshu@google.com> | 2014-05-27 18:01:34 -0700 |
commit | baef8c1ffe5c900fb0da9512654bf249b5fc9269 (patch) | |
tree | d407f1e4f160cae5eb0b4d1c1bbaeb189d686b50 /tools | |
parent | 80962666b88d4cba9eaf53832040651ce1766ec2 (diff) | |
download | frameworks_base-baef8c1ffe5c900fb0da9512654bf249b5fc9269.zip frameworks_base-baef8c1ffe5c900fb0da9512654bf249b5fc9269.tar.gz frameworks_base-baef8c1ffe5c900fb0da9512654bf249b5fc9269.tar.bz2 |
Layoutlib fixes for L [DO NOT MERGE]
This adds the new delegates that were missing. This starts the work on
changes related to Minikin Fonts.
There are some changes related to TypedArray that still need to be
fixed.
Change-Id: Ic2397b64aa3f1f48926e849b14689c47d9ee7f8c
(cherry picked from commit 7ca3612094270183243938e79337c84effea7ad0)
Diffstat (limited to 'tools')
12 files changed, 419 insertions, 600 deletions
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java index 31d1594..f4a9f52 100644 --- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java +++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java @@ -97,6 +97,13 @@ public class Resources_Theme_Delegate { return found; } + @LayoutlibDelegate + /*package*/ static TypedArray resolveAttributes(Resources thisResources, Theme thisTheme, + int[] values, int[] attrs) { + // FIXME + return null; + } + // ---- private helper methods ---- private static boolean setupResources(Theme thisTheme) { diff --git a/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java index 0a7899a..5d89f83 100644 --- a/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java +++ b/tools/layoutlib/bridge/src/android/content/res/TypedArray_Delegate.java @@ -27,4 +27,10 @@ public class TypedArray_Delegate { // pass return false; } + + @LayoutlibDelegate + /*package*/ static TypedArray obtain(Resources res, int len) { + // FIXME + return null; + } } diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java index 802cf1c..33813d1 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java +++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java @@ -18,9 +18,11 @@ package android.graphics; import java.awt.Font; import java.awt.Graphics2D; +import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.Rectangle2D; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -36,12 +38,12 @@ import android.graphics.Paint_Delegate.FontInfo; @SuppressWarnings("deprecation") public class BidiRenderer { - /* package */ static class ScriptRun { + /*package*/ static class ScriptRun { int start; int limit; boolean isRtl; int scriptCode; - FontInfo font; + Font font; public ScriptRun(int start, int limit, boolean isRtl) { this.start = start; @@ -51,9 +53,10 @@ public class BidiRenderer { } } - private Graphics2D mGraphics; - private Paint_Delegate mPaint; + private final Graphics2D mGraphics; + private final Paint_Delegate mPaint; private char[] mText; + private List<Font> mFonts; // Bounds of the text drawn so far. private RectF mBounds; private float mBaseline; @@ -63,11 +66,15 @@ public class BidiRenderer { * @param paint The Paint to use to get the fonts. Should not be null. * @param text Unidirectional text. Should not be null. */ - /* package */ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) { + /*package*/ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) { assert (paint != null); mGraphics = graphics; mPaint = paint; mText = text; + mFonts = new ArrayList<Font>(paint.getFonts().size()); + for (FontInfo fontInfo : paint.getFonts()) { + mFonts.add(fontInfo.mFont); + } } /** @@ -94,7 +101,7 @@ public class BidiRenderer { // the script runs. mBounds = new RectF(x, y, x, y); mBaseline = y; - for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mPaint.getFonts())) { + for (ScriptRun run : getScriptRuns(mText, start, limit, isRtl, mFonts)) { int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT; flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT; renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw); @@ -108,16 +115,15 @@ public class BidiRenderer { * much as possible. This also implements a fallback mechanism to render characters that cannot * be drawn using the preferred font. */ - private void renderScript(int start, int limit, FontInfo preferredFont, int flag, + private void renderScript(int start, int limit, Font preferredFont, int flag, float[] advances, int advancesIndex, boolean draw) { - List<FontInfo> fonts = mPaint.getFonts(); - if (fonts == null || preferredFont == null) { + if (mFonts.size() == 0 || preferredFont == null) { return; } while (start < limit) { boolean foundFont = false; - int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(mText, start, limit); + int canDisplayUpTo = preferredFont.canDisplayUpTo(mText, start, limit); if (canDisplayUpTo == -1) { // We can draw all characters in the text. render(start, limit, preferredFont, flag, advances, advancesIndex, draw); @@ -133,8 +139,8 @@ public class BidiRenderer { // The current character cannot be drawn with the preferred font. Cycle through all the // fonts to check which one can draw it. int charCount = Character.isHighSurrogate(mText[start]) ? 2 : 1; - for (FontInfo font : fonts) { - canDisplayUpTo = font.mFont.canDisplayUpTo(mText, start, start + charCount); + for (Font font : mFonts) { + canDisplayUpTo = font.canDisplayUpTo(mText, start, start + charCount); if (canDisplayUpTo == -1) { render(start, start+charCount, font, flag, advances, advancesIndex, draw); start += charCount; @@ -160,15 +166,19 @@ public class BidiRenderer { * Renders the text to the right of the bounds with the given font. * @param font The font to render the text with. */ - private void render(int start, int limit, FontInfo font, int flag, float[] advances, + private void render(int start, int limit, Font font, int flag, float[] advances, int advancesIndex, boolean draw) { - // Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with - // the anti-aliasing set. - FontRenderContext f = font.mMetrics.getFontRenderContext(); - FontRenderContext frc = new FontRenderContext(f.getTransform(), mPaint.isAntiAliased(), - f.usesFractionalMetrics()); - GlyphVector gv = font.mFont.layoutGlyphVector(frc, mText, start, limit, flag); + FontRenderContext frc; + if (mGraphics != null) { + frc = mGraphics.getFontRenderContext(); + } else { + frc = Toolkit.getDefaultToolkit().getFontMetrics(font).getFontRenderContext(); + // Metrics obtained this way don't have anti-aliasing set. So, + // we create a new FontRenderContext with anti-aliasing set. + frc = new FontRenderContext(font.getTransform(), mPaint.isAntiAliased(), frc.usesFractionalMetrics()); + } + GlyphVector gv = font.layoutGlyphVector(frc, mText, start, limit, flag); int ng = gv.getNumGlyphs(); int[] ci = gv.getGlyphCharIndices(0, ng, null); if (advances != null) { @@ -206,7 +216,7 @@ public class BidiRenderer { } /* package */ static List<ScriptRun> getScriptRuns(char[] text, int start, int limit, - boolean isRtl, List<FontInfo> fonts) { + boolean isRtl, List<Font> fonts) { LinkedList<ScriptRun> scriptRuns = new LinkedList<ScriptRun>(); int count = limit - start; @@ -225,10 +235,10 @@ public class BidiRenderer { // TODO: Replace this method with one which returns the font based on the scriptCode. private static void setScriptFont(char[] text, ScriptRun run, - List<FontInfo> fonts) { - for (FontInfo fontInfo : fonts) { - if (fontInfo.mFont.canDisplayUpTo(text, run.start, run.limit) == -1) { - run.font = fontInfo; + List<Font> fonts) { + for (Font font : fonts) { + if (font.canDisplayUpTo(text, run.start, run.limit) == -1) { + run.font = font; return; } } diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 56c0de9..e9daffd 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -979,7 +979,6 @@ public final class Canvas_Delegate { final float startX, final float startY, final int flags, long paint, long typeface) { - // TODO: use typeface. draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, new GcSnapshot.Drawable() { @Override @@ -1097,7 +1096,7 @@ public final class Canvas_Delegate { /** * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint. * <p>Note that the drawable may actually be executed several times if there are - * layers involved (see {@link #saveLayer(RectF, int, int)}. + * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. */ private static void draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode, GcSnapshot.Drawable drawable) { @@ -1117,7 +1116,7 @@ public final class Canvas_Delegate { * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}. * <p>Note that the drawable may actually be executed several times if there are - * layers involved (see {@link #saveLayer(RectF, int, int)}. + * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. */ private static void draw(long nCanvas, GcSnapshot.Drawable drawable) { // get the delegate from the native int. @@ -1190,12 +1189,6 @@ public final class Canvas_Delegate { return mSnapshot.clipRect(left, top, right, bottom, regionOp); } - private void setBitmap(Bitmap_Delegate bitmap) { - mBitmap = bitmap; - assert mSnapshot.size() == 1; - mSnapshot.setBitmap(mBitmap); - } - private static void drawBitmap( long nativeCanvas, Bitmap_Delegate bitmap, diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java new file mode 100644 index 0000000..5e7543a --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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. + */ + +package android.graphics; + +import com.android.ide.common.rendering.api.LayoutLog; +import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.impl.DelegateManager; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import java.awt.Font; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static android.graphics.Typeface_Delegate.SYSTEM_FONTS; + +/** + * Delegate implementing the native methods of android.graphics.FontFamily + * + * Through the layoutlib_create tool, the original native methods of FontFamily have been replaced + * by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original FontFamily class. + * + * @see DelegateManager + */ +public class FontFamily_Delegate { + + // FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked + // separately. + 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. + */ + private static final class FontInfo { + 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 ---- + private static final DelegateManager<FontFamily_Delegate> sManager = + new DelegateManager<FontFamily_Delegate>(FontFamily_Delegate.class); + + // ---- delegate helper data ---- + private static String sFontLocation; + private static final List<FontFamily_Delegate> sPostInitDelegate = new + ArrayList<FontFamily_Delegate>(); + + + // ---- delegate data ---- + private List<FontInfo> mFonts = new ArrayList<FontInfo>(); + // Path of fonts that haven't been created since sFontLoader hasn't been initialized. + private List<String> mPath = new ArrayList<String>(); + + + // ---- Public Helper methods ---- + + public static FontFamily_Delegate getDelegate(long nativeFontFamily) { + return sManager.getDelegate(nativeFontFamily); + } + + public static synchronized void setFontLocation(String fontLocation) { + sFontLocation = fontLocation; + for (FontFamily_Delegate fontFamily : sPostInitDelegate) { + fontFamily.init(); + } + sPostInitDelegate.clear(); + } + + public Font getFont(int style, boolean isCompact) { + 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; + } + 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 (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(); + 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; + } + return null; + } + + // ---- native methods ---- + + @LayoutlibDelegate + /*package*/ static long nCreateFamily() { + FontFamily_Delegate delegate = new FontFamily_Delegate(); + if (sFontLocation != null) { + delegate.init(); + } else { + sPostInitDelegate.add(delegate); + } + return sManager.addNewDelegate(delegate); + } + + @LayoutlibDelegate + /*package*/ static void nUnrefFamily(long nativePtr) { + sManager.removeJavaReferenceFor(nativePtr); + } + + @LayoutlibDelegate + /*package*/ static boolean nAddFont(long nativeFamily, String path) { + FontFamily_Delegate delegate = getDelegate(nativeFamily); + if (delegate != null) { + if (sFontLocation == null) { + delegate.mPath.add(path); + return true; + } + return delegate.addFont(path); + } + return false; + } + + private void init() { + for (String path : mPath) { + addFont(path); + } + mPath = null; + } + + private boolean addFont(String path) { + Font font = loadFont(path); + if (font == null) { + return false; + } + FontInfo fontInfo = new FontInfo(); + fontInfo.mFont = font; + addFontMetadata(fontInfo, path); + // TODO ensure that mFonts doesn't have the font with this style already. + mFonts.add(fontInfo); + return true; + } + + private static void addFontMetadata(FontInfo fontInfo, String path) { + int style = Font.PLAIN; + String fontName = path.substring(path.lastIndexOf('/'), path.length()); + if (fontName.endsWith(FONT_SUFFIX_BOLDITALIC)) { + style = Font.BOLD | Font.ITALIC; + } else if (fontName.endsWith(FONT_SUFFIX_BOLD)) { + style = Font.BOLD; + } else if (fontName.endsWith(FONT_SUFFIX_ITALIC)) { + 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) { + if (path.startsWith(SYSTEM_FONTS) ) { + String relativePath = path.substring(SYSTEM_FONTS.length()); + File f = new File(sFontLocation, relativePath); + + try { + return Font.createFont(Font.TRUETYPE_FONT, f); + } catch (Exception e) { + Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN, + String.format("Unable to load font %1$s", relativePath), + null /*throwable*/, null /*data*/); + } + } else { + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Only platform fonts located in " + SYSTEM_FONTS + "can be loaded.", + null /*throwable*/, null /*data*/); + } + + return null; + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index 8862f5b..f42f48f 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -203,6 +203,16 @@ public final class Matrix_Delegate { } @LayoutlibDelegate + /*package*/ static boolean native_isAffine(long native_object) { + Matrix_Delegate d = sManager.getDelegate(native_object); + if (d == null) { + return true; + } + + return (d.computeTypeMask() & kPerspective_Mask) == 0; + } + + @LayoutlibDelegate /*package*/ static boolean native_rectStaysRect(long native_object) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index 83df745..911f4e7 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -53,7 +53,7 @@ import java.util.Locale; public class Paint_Delegate { /** - * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}. + * Class associating a {@link Font} and its {@link java.awt.FontMetrics}. */ /*package*/ static final class FontInfo { Font mFont; @@ -66,8 +66,6 @@ public class Paint_Delegate { // ---- delegate helper data ---- private List<FontInfo> mFonts; - private final FontRenderContext mFontContext = new FontRenderContext( - new AffineTransform(), true, true); // ---- delegate data ---- private int mFlags; @@ -83,6 +81,7 @@ public class Paint_Delegate { private float mTextScaleX; private float mTextSkewX; private int mHintingMode = Paint.HINTING_ON; + private boolean mIsCompact = true; private Xfermode_Delegate mXfermode; private ColorFilter_Delegate mColorFilter; @@ -101,8 +100,7 @@ public class Paint_Delegate { } /** - * Returns the list of {@link Font} objects. The first item is the main font, the rest - * are fall backs for characters not present in the main font. + * Returns the list of {@link Font} objects. */ public List<FontInfo> getFonts() { return mFonts; @@ -437,12 +435,20 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static boolean isElegantTextHeight(Paint thisPaint) { - return false; + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + return delegate != null && !delegate.mIsCompact; } @LayoutlibDelegate /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) { - // TODO + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + return; + } + + delegate.mIsCompact = !elegant; } @LayoutlibDelegate @@ -621,7 +627,6 @@ public class Paint_Delegate { int inc = count > 0 ? 1 : -1; int measureIndex = 0; - float measureAcc = 0; for (int i = index; i != index + count; i += inc, measureIndex++) { int start, end; if (i < index) { @@ -640,7 +645,6 @@ public class Paint_Delegate { measuredWidth[measureIndex] = res; } - measureAcc += res; if (res > maxWidth) { // we should not return this char index, but since it's 0-based // and we need to return a count, we simply return measureIndex; @@ -818,7 +822,7 @@ public class Paint_Delegate { return filter; } - delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);; + delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter); // since none of those are supported, display a fidelity warning right away if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) { @@ -940,52 +944,17 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int native_getTextWidths(long native_object, char[] text, int index, - int count, int bidiFlags, float[] widths) { - // get the delegate from the native int. - Paint_Delegate delegate = sManager.getDelegate(native_object); - if (delegate == null) { - return 0; - } - - 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 (widths != null) { - widths[i] = adv; - } - - found = true; - break; - } - } - - if (found == false) { - // no advance for this char. - if (widths != null) { - widths[i] = 0.f; - } - } - } - - return (int) totalAdvance; - } - - return 0; + /*package*/ static int native_getTextWidths(long native_object, long native_typeface, + char[] text, int index, int count, int bidiFlags, float[] widths) { + return (int) native_getTextRunAdvances(native_object, native_typeface, text, index, count, + index, count, bidiFlags, widths, 0); } @LayoutlibDelegate - /*package*/ static int native_getTextWidths(long native_object, String text, int start, - int end, int bidiFlags, float[] widths) { - return native_getTextWidths(native_object, text.toCharArray(), start, end - start, - bidiFlags, widths); + /*package*/ static int native_getTextWidths(long native_object, long native_typeface, + String text, int start, int end, int bidiFlags, float[] widths) { + return native_getTextWidths(native_object, native_typeface, text.toCharArray(), start, + end - start, bidiFlags, widths); } @LayoutlibDelegate @@ -997,15 +966,20 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static float native_getTextRunAdvances(long native_object, + long native_typeface /*ignored*/, char[] text, int index, int count, int contextIndex, int contextCount, int flags, float[] advances, int advancesIndex) { + // native_typeface is passed here since Framework's old implementation did not have the + // typeface object associated with the Paint. Since, we follow the new framework way, + // we store the typeface with the paint and use it directly. + 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 || delegate.mFonts == null || delegate.mFonts.size() == 0) { + if (delegate == null) { return 0.f; } boolean isRtl = isRtl(flags); @@ -1017,7 +991,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static float native_getTextRunAdvances(long native_object, + /*package*/ static float native_getTextRunAdvances(long native_object, long native_typeface, String text, int start, int end, int contextStart, int contextEnd, int flags, float[] advances, int advancesIndex) { // FIXME: support contextStart and contextEnd @@ -1025,8 +999,8 @@ public class Paint_Delegate { char[] buffer = TemporaryBuffer.obtain(count); TextUtils.getChars(text, start, end, buffer, 0); - return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart, - contextEnd - contextStart, flags, advances, advancesIndex); + return native_getTextRunAdvances(native_object, native_typeface, buffer, 0, count, + contextStart, contextEnd - contextStart, flags, advances, advancesIndex); } @LayoutlibDelegate @@ -1076,7 +1050,7 @@ public class Paint_Delegate { // get the delegate from the native int. Paint_Delegate delegate = sManager.getDelegate(nativePaint); - if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) { + if (delegate == null) { return; } delegate.measureText(text, index, count, isRtl(bidiFlags)).roundOut(bounds); @@ -1150,7 +1124,7 @@ public class Paint_Delegate { private void updateFontObject() { if (mTypeface != null) { // Get the fonts from the TypeFace object. - List<Font> fonts = mTypeface.getFonts(); + List<Font> fonts = mTypeface.getFonts(mIsCompact); // 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 60cd157..ed8f3b4 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -19,7 +19,6 @@ package android.graphics; import com.android.ide.common.rendering.api.LayoutLog; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; -import com.android.layoutlib.bridge.impl.FontLoader; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import android.content.res.AssetManager; @@ -44,100 +43,67 @@ import java.util.List; */ public final class Typeface_Delegate { - private static final String SYSTEM_FONTS = "/system/fonts/"; + public static final String SYSTEM_FONTS = "/system/fonts/"; // ---- delegate manager ---- private static final DelegateManager<Typeface_Delegate> sManager = new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class); // ---- delegate helper data ---- - private static final String DEFAULT_FAMILY = "sans-serif"; - - private static FontLoader sFontLoader; - private static final List<Typeface_Delegate> sPostInitDelegate = - new ArrayList<Typeface_Delegate>(); + private static String sFontLocation; // ---- delegate data ---- - private final String mFamily; + private final long[] mFontFamilies; // the reference to FontFamily_Delegate. private int mStyle; - private List<Font> mFonts; + private static long sDefaultTypeface; // ---- Public Helper methods ---- - - public static synchronized void init(FontLoader fontLoader) { - sFontLoader = fontLoader; - - for (Typeface_Delegate delegate : sPostInitDelegate) { - delegate.init(); - } - sPostInitDelegate.clear(); + public static synchronized void setFontLocation(String fontLocation) { + sFontLocation = fontLocation; + FontFamily_Delegate.setFontLocation(fontLocation); } public static Typeface_Delegate getDelegate(long nativeTypeface) { return sManager.getDelegate(nativeTypeface); } - public static List<Font> getFonts(Typeface typeface) { - return getFonts(typeface.native_instance); - } - - public static List<Font> getFonts(long native_int) { - Typeface_Delegate delegate = sManager.getDelegate(native_int); - if (delegate == null) { - return null; + public List<Font> getFonts(boolean compact) { + List<Font> fonts = new ArrayList<Font>(mFontFamilies.length); + for (long fontFamily : mFontFamilies) { + FontFamily_Delegate ffd = FontFamily_Delegate.getDelegate(fontFamily); + if (ffd != null) { + Font font = ffd.getFont(mStyle, compact); + if (font != null) { + fonts.add(font); + } + } } - - return delegate.getFonts(); - } - - public List<Font> getFonts() { - return mFonts; + return fonts; } // ---- native methods ---- @LayoutlibDelegate /*package*/ static synchronized long nativeCreate(String familyName, int style) { - if (familyName == null) { - familyName = DEFAULT_FAMILY; - } - if (style < 0) { - style = Typeface.NORMAL; - } - - Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style); - if (sFontLoader != null) { - newDelegate.init(); - } else { - // font loader has not been initialized yet, add the delegate to a list of delegates - // to init when the font loader is initialized. - // There won't be any rendering before this happens anyway. - sPostInitDelegate.add(newDelegate); - } - - return sManager.addNewDelegate(newDelegate); + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Could not find font with family \"" + familyName + "\".", + null /*throwable*/, null /*data*/); + return 0; } @LayoutlibDelegate /*package*/ static synchronized long nativeCreateFromTypeface(long native_instance, int style) { Typeface_Delegate delegate = sManager.getDelegate(native_instance); if (delegate == null) { - return 0; + delegate = sManager.getDelegate(sDefaultTypeface); } - - Typeface_Delegate newDelegate = new Typeface_Delegate(delegate.mFamily, style); - if (sFontLoader != null) { - newDelegate.init(); - } else { - // font loader has not been initialized yet, add the delegate to a list of delegates - // to init when the font loader is initialized. - // There won't be any rendering before this happens anyway. - sPostInitDelegate.add(newDelegate); + if (delegate == null) { + return 0; } - return sManager.addNewDelegate(newDelegate); + return sManager.addNewDelegate(new Typeface_Delegate(delegate.mFontFamilies, style)); } @LayoutlibDelegate @@ -149,31 +115,15 @@ public final class Typeface_Delegate { @LayoutlibDelegate /*package*/ static synchronized long nativeCreateFromFile(String path) { - if (path.startsWith(SYSTEM_FONTS) ) { - String relativePath = path.substring(SYSTEM_FONTS.length()); - File f = new File(sFontLoader.getOsFontsLocation(), relativePath); - - try { - Font font = Font.createFont(Font.TRUETYPE_FONT, f); - if (font != null) { - Typeface_Delegate newDelegate = new Typeface_Delegate(font); - return sManager.addNewDelegate(newDelegate); - } - } catch (Exception e) { - Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN, - String.format("Unable to load font %1$s", relativePath), - null /*throwable*/, null /*data*/); - } - } else { - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Typeface.createFromFile() can only work with platform fonts located in " + - SYSTEM_FONTS, - null /*throwable*/, null /*data*/); - } - + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Typeface.createFromFile() is not supported.,", null, null); + return 0; + } - // return a copy of the base font - return nativeCreate(null, 0); + @LayoutlibDelegate + /*package*/ static synchronized long nativeCreateFromArray(long[] familyArray) { + Typeface_Delegate delegate = new Typeface_Delegate(familyArray, Typeface.NORMAL); + return sManager.addNewDelegate(delegate); } @LayoutlibDelegate @@ -191,24 +141,21 @@ public final class Typeface_Delegate { return delegate.mStyle; } - // ---- Private delegate/helper methods ---- - - private Typeface_Delegate(String family, int style) { - mFamily = family; - mStyle = style; + @LayoutlibDelegate + /*package*/ static void nativeSetDefault(long native_instance) { + sDefaultTypeface = native_instance; } - private Typeface_Delegate(Font font) { - mFamily = font.getFamily(); - mStyle = Typeface.NORMAL; + @LayoutlibDelegate + /*package*/ static File getSystemFontConfigLocation() { + return new File(sFontLocation); + } - mFonts = sFontLoader.getFallbackFonts(mStyle); + // ---- Private delegate/helper methods ---- - // insert the font glyph first. - mFonts.add(0, font); + private Typeface_Delegate(long[] fontFamilies, int style) { + mFontFamilies = fontFamilies; + mStyle = style; } - private void init() { - mFonts = sFontLoader.getFont(mFamily, mStyle); - } } diff --git a/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java b/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java new file mode 100644 index 0000000..a193330 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/util/Xml_Delegate.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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. + */ + +package android.util; + +import com.android.layoutlib.bridge.impl.DelegateManager; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import org.kxml2.io.KXmlParser; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +/** + * Delegate overriding some methods of android.util.Xml + * + * Through the layoutlib_create tool, the original methods of Xml have been replaced + * by calls to methods of the same name in this delegate class. + * + * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager} + * around to map int to instance of the delegate. + */ +public class Xml_Delegate { + + @LayoutlibDelegate + /*package*/ static XmlPullParser newPullParser() { + try { + KXmlParser parser = new KXmlParser(); + // The prebuilt kxml2 library with the IDE doesn't support DOCECL. +// parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + return parser; + } catch (XmlPullParserException e) { + throw new AssertionError(); + } + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index fa8050f..ffab4de 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -26,7 +26,6 @@ import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; import com.android.ide.common.rendering.api.Result.Status; import com.android.ide.common.rendering.api.SessionParams; -import com.android.layoutlib.bridge.impl.FontLoader; import com.android.layoutlib.bridge.impl.RenderDrawable; import com.android.layoutlib.bridge.impl.RenderSessionImpl; import com.android.layoutlib.bridge.util.DynamicIdMap; @@ -61,7 +60,7 @@ import java.util.concurrent.locks.ReentrantLock; /** * Main entry point of the LayoutLib Bridge. * <p/>To use this bridge, simply instantiate an object of type {@link Bridge} and call - * {@link #createScene(SceneParams)} + * {@link #createSession(SessionParams)} */ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { @@ -147,8 +146,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { if (getClass() != obj.getClass()) return false; IntArray other = (IntArray) obj; - if (!Arrays.equals(mArray, other.mArray)) return false; - return true; + return Arrays.equals(mArray, other.mArray); } } @@ -251,14 +249,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { } // load the fonts. - FontLoader fontLoader = FontLoader.create(fontLocation.getAbsolutePath()); - if (fontLoader != null) { - Typeface_Delegate.init(fontLoader); - } else { - log.error(LayoutLog.TAG_BROKEN, - "Failed create FontLoader in layout lib.", null); - return false; - } + Typeface_Delegate.setFontLocation(fontLocation.getAbsolutePath()); // now parse com.android.internal.R (and only this one as android.R is a subset of // the internal version), and put the content in the maps. diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java deleted file mode 100644 index cc7338a..0000000 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -package com.android.layoutlib.bridge.impl; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import android.graphics.Typeface; - -import java.awt.Font; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Provides {@link Font} object to the layout lib. - * <p/> - * The fonts are loaded from the SDK directory. Family/style mapping is done by parsing the - * fonts.xml file located alongside the ttf files. - */ -public final class FontLoader { - private static final String FONTS_SYSTEM = "system_fonts.xml"; - private static final String FONTS_VENDOR = "vendor_fonts.xml"; - private static final String FONTS_FALLBACK = "fallback_fonts.xml"; - - private static final String NODE_FAMILYSET = "familyset"; - private static final String NODE_FAMILY = "family"; - private static final String NODE_NAME = "name"; - private static final String NODE_FILE = "file"; - - private static final String ATTRIBUTE_VARIANT = "variant"; - private static final String ATTRIBUTE_VALUE_ELEGANT = "elegant"; - private static final String FONT_SUFFIX_NONE = ".ttf"; - private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf"; - private static final String FONT_SUFFIX_BOLD = "-Bold.ttf"; - // FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked - // separately. - private static final String FONT_SUFFIX_ITALIC = "Italic.ttf"; - private static final String FONT_SUFFIX_BOLDITALIC = "-BoldItalic.ttf"; - - // This must match the values of Typeface styles so that we can use them for indices in this - // array. - private static final int[] AWT_STYLES = new int[] { - Font.PLAIN, - Font.BOLD, - Font.ITALIC, - Font.BOLD | Font.ITALIC - }; - private static int[] DERIVE_BOLD_ITALIC = new int[] { - Typeface.ITALIC, Typeface.BOLD, Typeface.NORMAL - }; - private static int[] DERIVE_ITALIC = new int[] { Typeface.NORMAL }; - private static int[] DERIVE_BOLD = new int[] { Typeface.NORMAL }; - - private static final List<FontInfo> mMainFonts = new ArrayList<FontInfo>(); - private static final List<FontInfo> mFallbackFonts = new ArrayList<FontInfo>(); - - private final String mOsFontsLocation; - - public static FontLoader create(String fontOsLocation) { - try { - SAXParserFactory parserFactory = SAXParserFactory.newInstance(); - parserFactory.setNamespaceAware(true); - - // parse the system fonts - FontHandler handler = parseFontFile(parserFactory, fontOsLocation, FONTS_SYSTEM); - List<FontInfo> systemFonts = handler.getFontList(); - - - // parse the fallback fonts - handler = parseFontFile(parserFactory, fontOsLocation, FONTS_FALLBACK); - List<FontInfo> fallbackFonts = handler.getFontList(); - - return new FontLoader(fontOsLocation, systemFonts, fallbackFonts); - } catch (ParserConfigurationException e) { - // return null below - } catch (SAXException e) { - // return null below - } catch (FileNotFoundException e) { - // return null below - } catch (IOException e) { - // return null below - } - - return null; - } - - private static FontHandler parseFontFile(SAXParserFactory parserFactory, - String fontOsLocation, String fontFileName) - throws ParserConfigurationException, SAXException, IOException, FileNotFoundException { - - SAXParser parser = parserFactory.newSAXParser(); - File f = new File(fontOsLocation, fontFileName); - - FontHandler definitionParser = new FontHandler( - fontOsLocation + File.separator); - parser.parse(new FileInputStream(f), definitionParser); - return definitionParser; - } - - private FontLoader(String fontOsLocation, - List<FontInfo> fontList, List<FontInfo> fallBackList) { - mOsFontsLocation = fontOsLocation; - mMainFonts.addAll(fontList); - mFallbackFonts.addAll(fallBackList); - } - - - public String getOsFontsLocation() { - return mOsFontsLocation; - } - - /** - * Returns a {@link Font} object given a family name and a style value (constant in - * {@link Typeface}). - * @param family the family name - * @param style a 1-item array containing the requested style. Based on the font being read - * the actual style may be different. The array contains the actual style after - * the method returns. - * @return the font object or null if no match could be found. - */ - public synchronized List<Font> getFont(String family, int style) { - List<Font> result = new ArrayList<Font>(); - - if (family == null) { - return result; - } - - - // get the font objects from the main list based on family. - for (FontInfo info : mMainFonts) { - if (info.families.contains(family)) { - result.add(info.font[style]); - break; - } - } - - // add all the fallback fonts for the given style - for (FontInfo info : mFallbackFonts) { - result.add(info.font[style]); - } - - return result; - } - - - public synchronized List<Font> getFallbackFonts(int style) { - List<Font> result = new ArrayList<Font>(); - // add all the fallback fonts - for (FontInfo info : mFallbackFonts) { - result.add(info.font[style]); - } - return result; - } - - - private final static class FontInfo { - final Font[] font = new Font[4]; // Matches the 4 type-face styles. - final Set<String> families; - - FontInfo() { - families = new HashSet<String>(); - } - } - - private final static class FontHandler extends DefaultHandler { - private final String mOsFontsLocation; - - private FontInfo mFontInfo = null; - private final StringBuilder mBuilder = new StringBuilder(); - private List<FontInfo> mFontList = new ArrayList<FontInfo>(); - private boolean isCompactFont = true; - - private FontHandler(String osFontsLocation) { - super(); - mOsFontsLocation = osFontsLocation; - } - - public List<FontInfo> getFontList() { - return mFontList; - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) - */ - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) - throws SAXException { - if (NODE_FAMILYSET.equals(localName)) { - mFontList = new ArrayList<FontInfo>(); - } else if (NODE_FAMILY.equals(localName)) { - if (mFontList != null) { - mFontInfo = null; - } - } else if (NODE_NAME.equals(localName)) { - if (mFontList != null && mFontInfo == null) { - mFontInfo = new FontInfo(); - } - } else if (NODE_FILE.equals(localName)) { - if (mFontList != null && mFontInfo == null) { - mFontInfo = new FontInfo(); - } - if (ATTRIBUTE_VALUE_ELEGANT.equals(attributes.getValue(ATTRIBUTE_VARIANT))) { - isCompactFont = false; - } else { - isCompactFont = true; - } - } - - mBuilder.setLength(0); - - super.startElement(uri, localName, name, attributes); - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) - */ - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - if (isCompactFont) { - mBuilder.append(ch, start, length); - } - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) - */ - @Override - public void endElement(String uri, String localName, String name) throws SAXException { - if (NODE_FAMILY.equals(localName)) { - if (mFontInfo != null) { - // if has a normal font file, add to the list - if (mFontInfo.font[Typeface.NORMAL] != null) { - mFontList.add(mFontInfo); - - // create missing font styles, order is important. - if (mFontInfo.font[Typeface.BOLD_ITALIC] == null) { - computeDerivedFont(Typeface.BOLD_ITALIC, DERIVE_BOLD_ITALIC); - } - if (mFontInfo.font[Typeface.ITALIC] == null) { - computeDerivedFont(Typeface.ITALIC, DERIVE_ITALIC); - } - if (mFontInfo.font[Typeface.BOLD] == null) { - computeDerivedFont(Typeface.BOLD, DERIVE_BOLD); - } - } - - mFontInfo = null; - } - } else if (NODE_NAME.equals(localName)) { - // handle a new name for an existing Font Info - if (mFontInfo != null) { - String family = trimXmlWhitespaces(mBuilder.toString()); - mFontInfo.families.add(family); - } - } else if (NODE_FILE.equals(localName)) { - // handle a new file for an existing Font Info - if (isCompactFont && mFontInfo != null) { - String fileName = trimXmlWhitespaces(mBuilder.toString()); - Font font = getFont(fileName); - if (font != null) { - if (fileName.endsWith(FONT_SUFFIX_REGULAR)) { - mFontInfo.font[Typeface.NORMAL] = font; - } else if (fileName.endsWith(FONT_SUFFIX_BOLD)) { - mFontInfo.font[Typeface.BOLD] = font; - } else if (fileName.endsWith(FONT_SUFFIX_BOLDITALIC)) { - mFontInfo.font[Typeface.BOLD_ITALIC] = font; - } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) { - mFontInfo.font[Typeface.ITALIC] = font; - } else if (fileName.endsWith(FONT_SUFFIX_NONE)) { - mFontInfo.font[Typeface.NORMAL] = font; - } - } - } - } - } - - private Font getFont(String fileName) { - try { - File file = new File(mOsFontsLocation, fileName); - if (file.exists()) { - return Font.createFont(Font.TRUETYPE_FONT, file); - } - } catch (Exception e) { - - } - - return null; - } - - private void computeDerivedFont( int toCompute, int[] basedOnList) { - for (int basedOn : basedOnList) { - if (mFontInfo.font[basedOn] != null) { - mFontInfo.font[toCompute] = - mFontInfo.font[basedOn].deriveFont(AWT_STYLES[toCompute]); - return; - } - } - - // we really shouldn't stop there. This means we don't have a NORMAL font... - assert false; - } - - private String trimXmlWhitespaces(String value) { - if (value == null) { - return null; - } - - // look for carriage return and replace all whitespace around it by just 1 space. - int index; - - while ((index = value.indexOf('\n')) != -1) { - // look for whitespace on each side - int left = index - 1; - while (left >= 0) { - if (Character.isWhitespace(value.charAt(left))) { - left--; - } else { - break; - } - } - - int right = index + 1; - int count = value.length(); - while (right < count) { - if (Character.isWhitespace(value.charAt(right))) { - right++; - } else { - break; - } - } - - // remove all between left and right (non inclusive) and replace by a single space. - String leftString = null; - if (left >= 0) { - leftString = value.substring(0, left + 1); - } - String rightString = null; - if (right < count) { - rightString = value.substring(right); - } - - if (leftString != null) { - value = leftString; - if (rightString != null) { - value += " " + rightString; - } - } else { - value = rightString != null ? rightString : ""; - } - } - - // now we un-escape the string - int length = value.length(); - char[] buffer = value.toCharArray(); - - for (int i = 0 ; i < length ; i++) { - if (buffer[i] == '\\') { - if (buffer[i+1] == 'n') { - // replace the char with \n - buffer[i+1] = '\n'; - } - - // offset the rest of the buffer since we go from 2 to 1 char - System.arraycopy(buffer, i+1, buffer, i, length - i - 1); - length--; - } - } - - return new String(buffer, 0, length); - } - - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index bb72a1e..1f7a28e 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -125,15 +125,19 @@ public final class CreateInfo implements ICreateInfo { "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;", "android.content.res.Resources$Theme#obtainStyledAttributes", "android.content.res.Resources$Theme#resolveAttribute", + "android.content.res.Resources$Theme#resolveAttributes", "android.content.res.Resources#localeToLanguageTag", "android.content.res.AssetManager#newTheme", "android.content.res.AssetManager#deleteTheme", "android.content.res.AssetManager#applyThemeStyle", "android.content.res.TypedArray#getValueAt", + "android.content.res.TypedArray#obtain", "android.graphics.BitmapFactory#finishDecode", + "android.graphics.Typeface#getSystemFontConfigLocation", "android.os.Handler#sendMessageAtTime", "android.os.HandlerThread#run", "android.text.format.DateFormat#is24HourFormat", + "android.util.Xml#newPullParser", "android.view.Choreographer#getRefreshRate", "android.view.Display#updateDisplayInfoLocked", "android.view.Display#getWindowManager", @@ -170,6 +174,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.DiscretePathEffect", "android.graphics.DrawFilter", "android.graphics.EmbossMaskFilter", + "android.graphics.FontFamily", "android.graphics.LayerRasterizer", "android.graphics.LightingColorFilter", "android.graphics.LinearGradient", |