Loading core/java/android/emoji/EmojiFactory.javadeleted 100644 → 0 +0 −289 Original line number Diff line number Diff line /* * Copyright (C) 2009 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.emoji; import android.graphics.Bitmap; import java.lang.ref.WeakReference; import java.util.LinkedHashMap; import java.util.Map; /** * A class for the factories which produce Emoji (pictgram) images. * This is intended to be used by IME, Email app, etc. * There's no plan to make this public for now. * @hide */ public final class EmojiFactory { // private static final String LOG_TAG = "EmojiFactory"; private int sCacheSize = 100; // HashMap for caching Bitmap object. In order not to make a cache object // blow up, we use LinkedHashMap with size limit. private class CustomLinkedHashMap<K, V> extends LinkedHashMap<K, V> { public CustomLinkedHashMap() { // These magic numbers are gotten from the source code of // LinkedHashMap.java and HashMap.java. super(16, 0.75f, true); } /* * If size() becomes more than sCacheSize, least recently used cache * is erased. * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) */ @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > sCacheSize; } } // A pointer to native EmojiFactory object. private long mNativeEmojiFactory; private String mName; // Cache. private Map<Integer, WeakReference<Bitmap>> mCache; /** * @noinspection UnusedDeclaration */ /* * Private constructor that must received an already allocated native * EmojiFactory int (pointer). * * This can be called from JNI code. */ private EmojiFactory(long nativeEmojiFactory, String name) { mNativeEmojiFactory = nativeEmojiFactory; mName = name; mCache = new CustomLinkedHashMap<Integer, WeakReference<Bitmap>>(); } @Override protected void finalize() throws Throwable { try { nativeDestructor(mNativeEmojiFactory); } finally { super.finalize(); } } public String name() { return mName; } /** * Returns Bitmap object corresponding to the AndroidPua. * * Note that each Bitmap is cached by this class, which means that, if you modify a * Bitmap object (using setPos() method), all same emoji Bitmap will be modified. * If it is unacceptable, please copy the object before modifying it. * * @param pua A unicode codepoint. * @return Bitmap object when this factory knows the Bitmap relevant to the codepoint. * Otherwise null is returned. */ public synchronized Bitmap getBitmapFromAndroidPua(int pua) { WeakReference<Bitmap> cache = mCache.get(pua); if (cache == null) { Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua); // There is no need to cache returned null, since in most cases it means there // is no map from the AndroidPua to a specific image. In other words, it usually does // not include the cost of creating Bitmap object. if (ret != null) { mCache.put(pua, new WeakReference<Bitmap>(ret)); } return ret; } else { Bitmap tmp = cache.get(); if (tmp == null) { Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua); mCache.put(pua, new WeakReference<Bitmap>(ret)); return ret; } else { return tmp; } } } /** * Returns Bitmap object corresponding to the vendor specified sjis. * * See comments in getBitmapFromAndroidPua(). * * @param sjis sjis code specific to each career(vendor) * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise * null is returned. */ public synchronized Bitmap getBitmapFromVendorSpecificSjis(char sjis) { return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificSjis(sjis)); } /** * Returns Bitmap object corresponding to the vendor specific Unicode. * * See comments in getBitmapFromAndroidPua(). * * @param vsp vendor specific PUA. * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise * null is returned. */ public synchronized Bitmap getBitmapFromVendorSpecificPua(int vsp) { return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificPua(vsp)); } /** * Returns Unicode PUA for Android corresponding to the vendor specific sjis. * * @param sjis vendor specific sjis * @return Unicode PUA for Android, or -1 if there's no map for the sjis. */ public int getAndroidPuaFromVendorSpecificSjis(char sjis) { return nativeGetAndroidPuaFromVendorSpecificSjis(mNativeEmojiFactory, sjis); } /** * Returns vendor specific sjis corresponding to the Unicode AndroidPua. * * @param pua Unicode PUA for Android, * @return vendor specific sjis, or -1 if there's no map for the AndroidPua. */ public int getVendorSpecificSjisFromAndroidPua(int pua) { return nativeGetVendorSpecificSjisFromAndroidPua(mNativeEmojiFactory, pua); } /** * Returns Unicode PUA for Android corresponding to the vendor specific Unicode. * * @param vsp vendor specific PUA. * @return Unicode PUA for Android, or -1 if there's no map for the * Unicode. */ public int getAndroidPuaFromVendorSpecificPua(int vsp) { return nativeGetAndroidPuaFromVendorSpecificPua(mNativeEmojiFactory, vsp); } public String getAndroidPuaFromVendorSpecificPua(String vspString) { if (vspString == null) { return null; } int minVsp = nativeGetMinimumVendorSpecificPua(mNativeEmojiFactory); int maxVsp = nativeGetMaximumVendorSpecificPua(mNativeEmojiFactory); int len = vspString.length(); int[] codePoints = new int[vspString.codePointCount(0, len)]; int new_len = 0; for (int i = 0; i < len; i = vspString.offsetByCodePoints(i, 1), new_len++) { int codePoint = vspString.codePointAt(i); if (minVsp <= codePoint && codePoint <= maxVsp) { int newCodePoint = getAndroidPuaFromVendorSpecificPua(codePoint); if (newCodePoint > 0) { codePoints[new_len] = newCodePoint; continue; } } codePoints[new_len] = codePoint; } return new String(codePoints, 0, new_len); } /** * Returns vendor specific Unicode corresponding to the Unicode AndroidPua. * * @param pua Unicode PUA for Android, * @return vendor specific sjis, or -1 if there's no map for the AndroidPua. */ public int getVendorSpecificPuaFromAndroidPua(int pua) { return nativeGetVendorSpecificPuaFromAndroidPua(mNativeEmojiFactory, pua); } public String getVendorSpecificPuaFromAndroidPua(String puaString) { if (puaString == null) { return null; } int minVsp = nativeGetMinimumAndroidPua(mNativeEmojiFactory); int maxVsp = nativeGetMaximumAndroidPua(mNativeEmojiFactory); int len = puaString.length(); int[] codePoints = new int[puaString.codePointCount(0, len)]; int new_len = 0; for (int i = 0; i < len; i = puaString.offsetByCodePoints(i, 1), new_len++) { int codePoint = puaString.codePointAt(i); if (minVsp <= codePoint && codePoint <= maxVsp) { int newCodePoint = getVendorSpecificPuaFromAndroidPua(codePoint); if (newCodePoint > 0) { codePoints[new_len] = newCodePoint; continue; } } codePoints[new_len] = codePoint; } return new String(codePoints, 0, new_len); } /** * Constructs an instance of EmojiFactory corresponding to the name. * * @param class_name Name of the factory. This must include complete package name. * @return A concrete EmojiFactory instance corresponding to factory_name. * If factory_name is invalid, null is returned. */ public static native EmojiFactory newInstance(String class_name); /** * Constructs an instance of available EmojiFactory. * * @return A concrete EmojiFactory instance. If there are several available * EmojiFactory class, preferred one is chosen by the system. If there isn't, null * is returned. */ public static native EmojiFactory newAvailableInstance(); /** * Returns the lowest code point corresponding to an Android * emoji character. */ public int getMinimumAndroidPua() { return nativeGetMinimumAndroidPua(mNativeEmojiFactory); } /** * Returns the highest code point corresponding to an Android * emoji character. */ public int getMaximumAndroidPua() { return nativeGetMaximumAndroidPua(mNativeEmojiFactory); } // native methods private native void nativeDestructor(long nativeEmojiFactory); private native Bitmap nativeGetBitmapFromAndroidPua(long nativeEmojiFactory, int AndroidPua); private native int nativeGetAndroidPuaFromVendorSpecificSjis(long nativeEmojiFactory, char sjis); private native int nativeGetVendorSpecificSjisFromAndroidPua(long nativeEmojiFactory, int pua); private native int nativeGetAndroidPuaFromVendorSpecificPua(long nativeEmojiFactory, int vsp); private native int nativeGetVendorSpecificPuaFromAndroidPua(long nativeEmojiFactory, int pua); private native int nativeGetMaximumVendorSpecificPua(long nativeEmojiFactory); private native int nativeGetMinimumVendorSpecificPua(long nativeEmojiFactory); private native int nativeGetMaximumAndroidPua(long nativeEmojiFactory); private native int nativeGetMinimumAndroidPua(long nativeEmojiFactory); } core/java/android/text/Layout.java +13 −28 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package android.text; import android.annotation.IntDef; import android.emoji.EmojiFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; Loading Loading @@ -103,19 +102,6 @@ public abstract class Layout { private static final ParagraphStyle[] NO_PARA_SPANS = ArrayUtils.emptyArray(ParagraphStyle.class); /* package */ static final EmojiFactory EMOJI_FACTORY = EmojiFactory.newAvailableInstance(); /* package */ static final int MIN_EMOJI, MAX_EMOJI; static { if (EMOJI_FACTORY != null) { MIN_EMOJI = EMOJI_FACTORY.getMinimumAndroidPua(); MAX_EMOJI = EMOJI_FACTORY.getMaximumAndroidPua(); } else { MIN_EMOJI = -1; MAX_EMOJI = -1; } } /** * Return how wide a layout must be in order to display the * specified text with one line per paragraph. Loading Loading @@ -360,9 +346,9 @@ public abstract class Layout { } } boolean hasTabOrEmoji = getLineContainsTab(lineNum); boolean hasTab = getLineContainsTab(lineNum); // Can't tell if we have tabs for sure, currently if (hasTabOrEmoji && !tabStopsIsInitialized) { if (hasTab && !tabStopsIsInitialized) { if (tabStops == null) { tabStops = new TabStops(TAB_INCREMENT, spans); } else { Loading Loading @@ -405,11 +391,11 @@ public abstract class Layout { paint.setHyphenEdit(getHyphen(lineNum)); Directions directions = getLineDirections(lineNum); if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) { if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTab) { // XXX: assumes there's nothing additional to be done canvas.drawText(buf, start, end, x, lbaseline, paint); } else { tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops); tl.set(paint, buf, start, end, dir, directions, hasTab, tabStops); tl.draw(canvas, x, ltop, lbaseline, lbottom); } paint.setHyphenEdit(0); Loading Loading @@ -710,8 +696,7 @@ public abstract class Layout { /** * Returns whether the specified line contains one or more * characters that need to be handled specially, like tabs * or emoji. * characters that need to be handled specially, like tabs. */ public abstract boolean getLineContainsTab(int line); Loading Loading @@ -911,11 +896,11 @@ public abstract class Layout { int start = getLineStart(line); int end = getLineEnd(line); int dir = getParagraphDirection(line); boolean hasTabOrEmoji = getLineContainsTab(line); boolean hasTab = getLineContainsTab(line); Directions directions = getLineDirections(line); TabStops tabStops = null; if (hasTabOrEmoji && mText instanceof Spanned) { if (hasTab && mText instanceof Spanned) { // Just checking this line should be good enough, tabs should be // consistent across all lines in a paragraph. TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class); Loading @@ -925,7 +910,7 @@ public abstract class Layout { } TextLine tl = TextLine.obtain(); tl.set(mPaint, mText, start, end, dir, directions, hasTabOrEmoji, tabStops); tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops); float wid = tl.measure(offset - start, trailing, null); TextLine.recycle(tl); Loading Loading @@ -1031,9 +1016,9 @@ public abstract class Layout { int start = getLineStart(line); int end = full ? getLineEnd(line) : getLineVisibleEnd(line); boolean hasTabsOrEmoji = getLineContainsTab(line); boolean hasTabs = getLineContainsTab(line); TabStops tabStops = null; if (hasTabsOrEmoji && mText instanceof Spanned) { if (hasTabs && mText instanceof Spanned) { // Just checking this line should be good enough, tabs should be // consistent across all lines in a paragraph. TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class); Loading @@ -1049,7 +1034,7 @@ public abstract class Layout { int dir = getParagraphDirection(line); TextLine tl = TextLine.obtain(); tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops); tl.set(mPaint, mText, start, end, dir, directions, hasTabs, tabStops); float width = tl.metrics(null); TextLine.recycle(tl); return width; Loading @@ -1066,12 +1051,12 @@ public abstract class Layout { private float getLineExtent(int line, TabStops tabStops, boolean full) { int start = getLineStart(line); int end = full ? getLineEnd(line) : getLineVisibleEnd(line); boolean hasTabsOrEmoji = getLineContainsTab(line); boolean hasTabs = getLineContainsTab(line); Directions directions = getLineDirections(line); int dir = getParagraphDirection(line); TextLine tl = TextLine.obtain(); tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops); tl.set(mPaint, mText, start, end, dir, directions, hasTabs, tabStops); float width = tl.metrics(null); TextLine.recycle(tl); return width; Loading core/java/android/text/StaticLayout.java +1 −1 Original line number Diff line number Diff line Loading @@ -1308,7 +1308,7 @@ public class StaticLayout extends Layout { private static final int INITIAL_SIZE = 16; public int[] breaks = new int[INITIAL_SIZE]; public float[] widths = new float[INITIAL_SIZE]; public int[] flags = new int[INITIAL_SIZE]; // hasTabOrEmoji public int[] flags = new int[INITIAL_SIZE]; // hasTab // breaks, widths, and flags should all have the same length } Loading core/java/android/text/TextLine.java +9 −65 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ class TextLine { * @param limit the limit of the line relative to the text * @param dir the paragraph direction of this line * @param directions the directions information of this line * @param hasTabs true if the line might contain tabs or emoji * @param hasTabs true if the line might contain tabs * @param tabStops the tabStops. Can be null. */ void set(TextPaint paint, CharSequence text, int start, int limit, int dir, Loading Loading @@ -204,7 +204,6 @@ class TextLine { float h = 0; int[] runs = mDirections.mDirections; RectF emojiRect = null; int lastRunIndex = runs.length - 2; for (int i = 0; i < runs.length; i += 2) { Loading @@ -218,41 +217,23 @@ class TextLine { int segstart = runStart; for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) { int codept = 0; Bitmap bm = null; if (mHasTabs && j < runLimit) { codept = mChars[j]; if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) { if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) { codept = Character.codePointAt(mChars, j); if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) { bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept); } else if (codept > 0xffff) { if (codept > 0xFFFF) { ++j; continue; } } } if (j == runLimit || codept == '\t' || bm != null) { if (j == runLimit || codept == '\t') { h += drawRun(c, segstart, j, runIsRtl, x+h, top, y, bottom, i != lastRunIndex || j != mLen); if (codept == '\t') { h = mDir * nextTab(h * mDir); } else if (bm != null) { float bmAscent = ascent(j); float bitmapHeight = bm.getHeight(); float scale = -bmAscent / bitmapHeight; float width = bm.getWidth() * scale; if (emojiRect == null) { emojiRect = new RectF(); } emojiRect.set(x + h, y + bmAscent, x + h + width, y); c.drawBitmap(bm, null, emojiRect, mPaint); h += width; j++; } segstart = j + 1; } Loading Loading @@ -313,22 +294,18 @@ class TextLine { int segstart = runStart; for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) { int codept = 0; Bitmap bm = null; if (mHasTabs && j < runLimit) { codept = chars[j]; if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) { if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) { codept = Character.codePointAt(chars, j); if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) { bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept); } else if (codept > 0xffff) { if (codept > 0xFFFF) { ++j; continue; } } } if (j == runLimit || codept == '\t' || bm != null) { if (j == runLimit || codept == '\t') { boolean inSegment = target >= segstart && target < j; boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl; Loading @@ -353,13 +330,6 @@ class TextLine { } } if (bm != null) { float bmAscent = ascent(j); float wid = bm.getWidth() * -bmAscent / bm.getHeight(); h += mDir * wid; j++; } segstart = j + 1; } } Loading Loading @@ -705,7 +675,7 @@ class TextLine { /** * Utility function for measuring and rendering text. The text must * not include a tab or emoji. * not include a tab. * * @param wp the working paint * @param start the start of the text Loading Loading @@ -860,7 +830,7 @@ class TextLine { /** * Utility function for handling a unidirectional run. The run must not * contain tabs or emoji but can contain styles. * contain tabs but can contain styles. * * * @param start the line-relative start of the run Loading Loading @@ -993,32 +963,6 @@ class TextLine { } } /** * Returns the ascent of the text at start. This is used for scaling * emoji. * * @param pos the line-relative position * @return the ascent of the text at start */ float ascent(int pos) { if (mSpanned == null) { return mPaint.ascent(); } pos += mStart; MetricAffectingSpan[] spans = mSpanned.getSpans(pos, pos + 1, MetricAffectingSpan.class); if (spans.length == 0) { return mPaint.ascent(); } TextPaint wp = mWorkPaint; wp.set(mPaint); for (MetricAffectingSpan span : spans) { span.updateMeasureState(wp); } return wp.ascent(); } /** * Returns the next tab position. * Loading core/jni/Android.mk +0 −2 Original line number Diff line number Diff line Loading @@ -49,7 +49,6 @@ LOCAL_SRC_FILES:= \ android_database_SQLiteConnection.cpp \ android_database_SQLiteGlobal.cpp \ android_database_SQLiteDebug.cpp \ android_emoji_EmojiFactory.cpp \ android_view_DisplayEventReceiver.cpp \ android_view_DisplayListCanvas.cpp \ android_view_GraphicBuffer.cpp \ Loading Loading @@ -201,7 +200,6 @@ LOCAL_C_INCLUDES += \ external/tremor/Tremor \ external/jpeg \ external/harfbuzz_ng/src \ frameworks/opt/emoji \ libcore/include \ $(call include-path-for, audio-utils) \ frameworks/minikin/include \ Loading Loading
core/java/android/emoji/EmojiFactory.javadeleted 100644 → 0 +0 −289 Original line number Diff line number Diff line /* * Copyright (C) 2009 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.emoji; import android.graphics.Bitmap; import java.lang.ref.WeakReference; import java.util.LinkedHashMap; import java.util.Map; /** * A class for the factories which produce Emoji (pictgram) images. * This is intended to be used by IME, Email app, etc. * There's no plan to make this public for now. * @hide */ public final class EmojiFactory { // private static final String LOG_TAG = "EmojiFactory"; private int sCacheSize = 100; // HashMap for caching Bitmap object. In order not to make a cache object // blow up, we use LinkedHashMap with size limit. private class CustomLinkedHashMap<K, V> extends LinkedHashMap<K, V> { public CustomLinkedHashMap() { // These magic numbers are gotten from the source code of // LinkedHashMap.java and HashMap.java. super(16, 0.75f, true); } /* * If size() becomes more than sCacheSize, least recently used cache * is erased. * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) */ @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > sCacheSize; } } // A pointer to native EmojiFactory object. private long mNativeEmojiFactory; private String mName; // Cache. private Map<Integer, WeakReference<Bitmap>> mCache; /** * @noinspection UnusedDeclaration */ /* * Private constructor that must received an already allocated native * EmojiFactory int (pointer). * * This can be called from JNI code. */ private EmojiFactory(long nativeEmojiFactory, String name) { mNativeEmojiFactory = nativeEmojiFactory; mName = name; mCache = new CustomLinkedHashMap<Integer, WeakReference<Bitmap>>(); } @Override protected void finalize() throws Throwable { try { nativeDestructor(mNativeEmojiFactory); } finally { super.finalize(); } } public String name() { return mName; } /** * Returns Bitmap object corresponding to the AndroidPua. * * Note that each Bitmap is cached by this class, which means that, if you modify a * Bitmap object (using setPos() method), all same emoji Bitmap will be modified. * If it is unacceptable, please copy the object before modifying it. * * @param pua A unicode codepoint. * @return Bitmap object when this factory knows the Bitmap relevant to the codepoint. * Otherwise null is returned. */ public synchronized Bitmap getBitmapFromAndroidPua(int pua) { WeakReference<Bitmap> cache = mCache.get(pua); if (cache == null) { Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua); // There is no need to cache returned null, since in most cases it means there // is no map from the AndroidPua to a specific image. In other words, it usually does // not include the cost of creating Bitmap object. if (ret != null) { mCache.put(pua, new WeakReference<Bitmap>(ret)); } return ret; } else { Bitmap tmp = cache.get(); if (tmp == null) { Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua); mCache.put(pua, new WeakReference<Bitmap>(ret)); return ret; } else { return tmp; } } } /** * Returns Bitmap object corresponding to the vendor specified sjis. * * See comments in getBitmapFromAndroidPua(). * * @param sjis sjis code specific to each career(vendor) * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise * null is returned. */ public synchronized Bitmap getBitmapFromVendorSpecificSjis(char sjis) { return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificSjis(sjis)); } /** * Returns Bitmap object corresponding to the vendor specific Unicode. * * See comments in getBitmapFromAndroidPua(). * * @param vsp vendor specific PUA. * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise * null is returned. */ public synchronized Bitmap getBitmapFromVendorSpecificPua(int vsp) { return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificPua(vsp)); } /** * Returns Unicode PUA for Android corresponding to the vendor specific sjis. * * @param sjis vendor specific sjis * @return Unicode PUA for Android, or -1 if there's no map for the sjis. */ public int getAndroidPuaFromVendorSpecificSjis(char sjis) { return nativeGetAndroidPuaFromVendorSpecificSjis(mNativeEmojiFactory, sjis); } /** * Returns vendor specific sjis corresponding to the Unicode AndroidPua. * * @param pua Unicode PUA for Android, * @return vendor specific sjis, or -1 if there's no map for the AndroidPua. */ public int getVendorSpecificSjisFromAndroidPua(int pua) { return nativeGetVendorSpecificSjisFromAndroidPua(mNativeEmojiFactory, pua); } /** * Returns Unicode PUA for Android corresponding to the vendor specific Unicode. * * @param vsp vendor specific PUA. * @return Unicode PUA for Android, or -1 if there's no map for the * Unicode. */ public int getAndroidPuaFromVendorSpecificPua(int vsp) { return nativeGetAndroidPuaFromVendorSpecificPua(mNativeEmojiFactory, vsp); } public String getAndroidPuaFromVendorSpecificPua(String vspString) { if (vspString == null) { return null; } int minVsp = nativeGetMinimumVendorSpecificPua(mNativeEmojiFactory); int maxVsp = nativeGetMaximumVendorSpecificPua(mNativeEmojiFactory); int len = vspString.length(); int[] codePoints = new int[vspString.codePointCount(0, len)]; int new_len = 0; for (int i = 0; i < len; i = vspString.offsetByCodePoints(i, 1), new_len++) { int codePoint = vspString.codePointAt(i); if (minVsp <= codePoint && codePoint <= maxVsp) { int newCodePoint = getAndroidPuaFromVendorSpecificPua(codePoint); if (newCodePoint > 0) { codePoints[new_len] = newCodePoint; continue; } } codePoints[new_len] = codePoint; } return new String(codePoints, 0, new_len); } /** * Returns vendor specific Unicode corresponding to the Unicode AndroidPua. * * @param pua Unicode PUA for Android, * @return vendor specific sjis, or -1 if there's no map for the AndroidPua. */ public int getVendorSpecificPuaFromAndroidPua(int pua) { return nativeGetVendorSpecificPuaFromAndroidPua(mNativeEmojiFactory, pua); } public String getVendorSpecificPuaFromAndroidPua(String puaString) { if (puaString == null) { return null; } int minVsp = nativeGetMinimumAndroidPua(mNativeEmojiFactory); int maxVsp = nativeGetMaximumAndroidPua(mNativeEmojiFactory); int len = puaString.length(); int[] codePoints = new int[puaString.codePointCount(0, len)]; int new_len = 0; for (int i = 0; i < len; i = puaString.offsetByCodePoints(i, 1), new_len++) { int codePoint = puaString.codePointAt(i); if (minVsp <= codePoint && codePoint <= maxVsp) { int newCodePoint = getVendorSpecificPuaFromAndroidPua(codePoint); if (newCodePoint > 0) { codePoints[new_len] = newCodePoint; continue; } } codePoints[new_len] = codePoint; } return new String(codePoints, 0, new_len); } /** * Constructs an instance of EmojiFactory corresponding to the name. * * @param class_name Name of the factory. This must include complete package name. * @return A concrete EmojiFactory instance corresponding to factory_name. * If factory_name is invalid, null is returned. */ public static native EmojiFactory newInstance(String class_name); /** * Constructs an instance of available EmojiFactory. * * @return A concrete EmojiFactory instance. If there are several available * EmojiFactory class, preferred one is chosen by the system. If there isn't, null * is returned. */ public static native EmojiFactory newAvailableInstance(); /** * Returns the lowest code point corresponding to an Android * emoji character. */ public int getMinimumAndroidPua() { return nativeGetMinimumAndroidPua(mNativeEmojiFactory); } /** * Returns the highest code point corresponding to an Android * emoji character. */ public int getMaximumAndroidPua() { return nativeGetMaximumAndroidPua(mNativeEmojiFactory); } // native methods private native void nativeDestructor(long nativeEmojiFactory); private native Bitmap nativeGetBitmapFromAndroidPua(long nativeEmojiFactory, int AndroidPua); private native int nativeGetAndroidPuaFromVendorSpecificSjis(long nativeEmojiFactory, char sjis); private native int nativeGetVendorSpecificSjisFromAndroidPua(long nativeEmojiFactory, int pua); private native int nativeGetAndroidPuaFromVendorSpecificPua(long nativeEmojiFactory, int vsp); private native int nativeGetVendorSpecificPuaFromAndroidPua(long nativeEmojiFactory, int pua); private native int nativeGetMaximumVendorSpecificPua(long nativeEmojiFactory); private native int nativeGetMinimumVendorSpecificPua(long nativeEmojiFactory); private native int nativeGetMaximumAndroidPua(long nativeEmojiFactory); private native int nativeGetMinimumAndroidPua(long nativeEmojiFactory); }
core/java/android/text/Layout.java +13 −28 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package android.text; import android.annotation.IntDef; import android.emoji.EmojiFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; Loading Loading @@ -103,19 +102,6 @@ public abstract class Layout { private static final ParagraphStyle[] NO_PARA_SPANS = ArrayUtils.emptyArray(ParagraphStyle.class); /* package */ static final EmojiFactory EMOJI_FACTORY = EmojiFactory.newAvailableInstance(); /* package */ static final int MIN_EMOJI, MAX_EMOJI; static { if (EMOJI_FACTORY != null) { MIN_EMOJI = EMOJI_FACTORY.getMinimumAndroidPua(); MAX_EMOJI = EMOJI_FACTORY.getMaximumAndroidPua(); } else { MIN_EMOJI = -1; MAX_EMOJI = -1; } } /** * Return how wide a layout must be in order to display the * specified text with one line per paragraph. Loading Loading @@ -360,9 +346,9 @@ public abstract class Layout { } } boolean hasTabOrEmoji = getLineContainsTab(lineNum); boolean hasTab = getLineContainsTab(lineNum); // Can't tell if we have tabs for sure, currently if (hasTabOrEmoji && !tabStopsIsInitialized) { if (hasTab && !tabStopsIsInitialized) { if (tabStops == null) { tabStops = new TabStops(TAB_INCREMENT, spans); } else { Loading Loading @@ -405,11 +391,11 @@ public abstract class Layout { paint.setHyphenEdit(getHyphen(lineNum)); Directions directions = getLineDirections(lineNum); if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) { if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTab) { // XXX: assumes there's nothing additional to be done canvas.drawText(buf, start, end, x, lbaseline, paint); } else { tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops); tl.set(paint, buf, start, end, dir, directions, hasTab, tabStops); tl.draw(canvas, x, ltop, lbaseline, lbottom); } paint.setHyphenEdit(0); Loading Loading @@ -710,8 +696,7 @@ public abstract class Layout { /** * Returns whether the specified line contains one or more * characters that need to be handled specially, like tabs * or emoji. * characters that need to be handled specially, like tabs. */ public abstract boolean getLineContainsTab(int line); Loading Loading @@ -911,11 +896,11 @@ public abstract class Layout { int start = getLineStart(line); int end = getLineEnd(line); int dir = getParagraphDirection(line); boolean hasTabOrEmoji = getLineContainsTab(line); boolean hasTab = getLineContainsTab(line); Directions directions = getLineDirections(line); TabStops tabStops = null; if (hasTabOrEmoji && mText instanceof Spanned) { if (hasTab && mText instanceof Spanned) { // Just checking this line should be good enough, tabs should be // consistent across all lines in a paragraph. TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class); Loading @@ -925,7 +910,7 @@ public abstract class Layout { } TextLine tl = TextLine.obtain(); tl.set(mPaint, mText, start, end, dir, directions, hasTabOrEmoji, tabStops); tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops); float wid = tl.measure(offset - start, trailing, null); TextLine.recycle(tl); Loading Loading @@ -1031,9 +1016,9 @@ public abstract class Layout { int start = getLineStart(line); int end = full ? getLineEnd(line) : getLineVisibleEnd(line); boolean hasTabsOrEmoji = getLineContainsTab(line); boolean hasTabs = getLineContainsTab(line); TabStops tabStops = null; if (hasTabsOrEmoji && mText instanceof Spanned) { if (hasTabs && mText instanceof Spanned) { // Just checking this line should be good enough, tabs should be // consistent across all lines in a paragraph. TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class); Loading @@ -1049,7 +1034,7 @@ public abstract class Layout { int dir = getParagraphDirection(line); TextLine tl = TextLine.obtain(); tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops); tl.set(mPaint, mText, start, end, dir, directions, hasTabs, tabStops); float width = tl.metrics(null); TextLine.recycle(tl); return width; Loading @@ -1066,12 +1051,12 @@ public abstract class Layout { private float getLineExtent(int line, TabStops tabStops, boolean full) { int start = getLineStart(line); int end = full ? getLineEnd(line) : getLineVisibleEnd(line); boolean hasTabsOrEmoji = getLineContainsTab(line); boolean hasTabs = getLineContainsTab(line); Directions directions = getLineDirections(line); int dir = getParagraphDirection(line); TextLine tl = TextLine.obtain(); tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops); tl.set(mPaint, mText, start, end, dir, directions, hasTabs, tabStops); float width = tl.metrics(null); TextLine.recycle(tl); return width; Loading
core/java/android/text/StaticLayout.java +1 −1 Original line number Diff line number Diff line Loading @@ -1308,7 +1308,7 @@ public class StaticLayout extends Layout { private static final int INITIAL_SIZE = 16; public int[] breaks = new int[INITIAL_SIZE]; public float[] widths = new float[INITIAL_SIZE]; public int[] flags = new int[INITIAL_SIZE]; // hasTabOrEmoji public int[] flags = new int[INITIAL_SIZE]; // hasTab // breaks, widths, and flags should all have the same length } Loading
core/java/android/text/TextLine.java +9 −65 Original line number Diff line number Diff line Loading @@ -128,7 +128,7 @@ class TextLine { * @param limit the limit of the line relative to the text * @param dir the paragraph direction of this line * @param directions the directions information of this line * @param hasTabs true if the line might contain tabs or emoji * @param hasTabs true if the line might contain tabs * @param tabStops the tabStops. Can be null. */ void set(TextPaint paint, CharSequence text, int start, int limit, int dir, Loading Loading @@ -204,7 +204,6 @@ class TextLine { float h = 0; int[] runs = mDirections.mDirections; RectF emojiRect = null; int lastRunIndex = runs.length - 2; for (int i = 0; i < runs.length; i += 2) { Loading @@ -218,41 +217,23 @@ class TextLine { int segstart = runStart; for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) { int codept = 0; Bitmap bm = null; if (mHasTabs && j < runLimit) { codept = mChars[j]; if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) { if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) { codept = Character.codePointAt(mChars, j); if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) { bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept); } else if (codept > 0xffff) { if (codept > 0xFFFF) { ++j; continue; } } } if (j == runLimit || codept == '\t' || bm != null) { if (j == runLimit || codept == '\t') { h += drawRun(c, segstart, j, runIsRtl, x+h, top, y, bottom, i != lastRunIndex || j != mLen); if (codept == '\t') { h = mDir * nextTab(h * mDir); } else if (bm != null) { float bmAscent = ascent(j); float bitmapHeight = bm.getHeight(); float scale = -bmAscent / bitmapHeight; float width = bm.getWidth() * scale; if (emojiRect == null) { emojiRect = new RectF(); } emojiRect.set(x + h, y + bmAscent, x + h + width, y); c.drawBitmap(bm, null, emojiRect, mPaint); h += width; j++; } segstart = j + 1; } Loading Loading @@ -313,22 +294,18 @@ class TextLine { int segstart = runStart; for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) { int codept = 0; Bitmap bm = null; if (mHasTabs && j < runLimit) { codept = chars[j]; if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) { if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) { codept = Character.codePointAt(chars, j); if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) { bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept); } else if (codept > 0xffff) { if (codept > 0xFFFF) { ++j; continue; } } } if (j == runLimit || codept == '\t' || bm != null) { if (j == runLimit || codept == '\t') { boolean inSegment = target >= segstart && target < j; boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl; Loading @@ -353,13 +330,6 @@ class TextLine { } } if (bm != null) { float bmAscent = ascent(j); float wid = bm.getWidth() * -bmAscent / bm.getHeight(); h += mDir * wid; j++; } segstart = j + 1; } } Loading Loading @@ -705,7 +675,7 @@ class TextLine { /** * Utility function for measuring and rendering text. The text must * not include a tab or emoji. * not include a tab. * * @param wp the working paint * @param start the start of the text Loading Loading @@ -860,7 +830,7 @@ class TextLine { /** * Utility function for handling a unidirectional run. The run must not * contain tabs or emoji but can contain styles. * contain tabs but can contain styles. * * * @param start the line-relative start of the run Loading Loading @@ -993,32 +963,6 @@ class TextLine { } } /** * Returns the ascent of the text at start. This is used for scaling * emoji. * * @param pos the line-relative position * @return the ascent of the text at start */ float ascent(int pos) { if (mSpanned == null) { return mPaint.ascent(); } pos += mStart; MetricAffectingSpan[] spans = mSpanned.getSpans(pos, pos + 1, MetricAffectingSpan.class); if (spans.length == 0) { return mPaint.ascent(); } TextPaint wp = mWorkPaint; wp.set(mPaint); for (MetricAffectingSpan span : spans) { span.updateMeasureState(wp); } return wp.ascent(); } /** * Returns the next tab position. * Loading
core/jni/Android.mk +0 −2 Original line number Diff line number Diff line Loading @@ -49,7 +49,6 @@ LOCAL_SRC_FILES:= \ android_database_SQLiteConnection.cpp \ android_database_SQLiteGlobal.cpp \ android_database_SQLiteDebug.cpp \ android_emoji_EmojiFactory.cpp \ android_view_DisplayEventReceiver.cpp \ android_view_DisplayListCanvas.cpp \ android_view_GraphicBuffer.cpp \ Loading Loading @@ -201,7 +200,6 @@ LOCAL_C_INCLUDES += \ external/tremor/Tremor \ external/jpeg \ external/harfbuzz_ng/src \ frameworks/opt/emoji \ libcore/include \ $(call include-path-for, audio-utils) \ frameworks/minikin/include \ Loading