summaryrefslogtreecommitdiffstats
path: root/core/java/android/text
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-18 17:39:46 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-18 17:39:46 -0700
commit105925376f8d0f6b318c9938c7b83ef7fef094da (patch)
tree3b19ee2bd8704cb9c6a0da7e42dec6759183de6d /core/java/android/text
parentba87e3e6c985e7175152993b5efcc7dd2f0e1c93 (diff)
downloadframeworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.zip
frameworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.tar.gz
frameworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.tar.bz2
auto import from //branches/cupcake_rel/...@140373
Diffstat (limited to 'core/java/android/text')
-rw-r--r--core/java/android/text/Html.java69
-rw-r--r--core/java/android/text/Layout.java105
-rw-r--r--core/java/android/text/StaticLayout.java39
3 files changed, 195 insertions, 18 deletions
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 8495714..6f0be3a 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -28,6 +28,8 @@ import org.xml.sax.XMLReader;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.AlignmentSpan;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
@@ -41,6 +43,7 @@ import android.text.style.SuperscriptSpan;
import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
+import android.util.Log;
import com.android.internal.util.XmlUtils;
import java.io.IOException;
@@ -137,11 +140,52 @@ public class Html {
*/
public static String toHtml(Spanned text) {
StringBuilder out = new StringBuilder();
+ withinHtml(out, text);
+ return out.toString();
+ }
+
+ private static void withinHtml(StringBuilder out, Spanned text) {
int len = text.length();
int next;
for (int i = 0; i < text.length(); i = next) {
- next = text.nextSpanTransition(i, len, QuoteSpan.class);
+ next = text.nextSpanTransition(i, len, ParagraphStyle.class);
+ ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
+ if (style.length > 0) {
+ out.append("<div ");
+ }
+ for(int j = 0; j < style.length; j++) {
+ if (style[j] instanceof AlignmentSpan) {
+ out.append("align=\"");
+ Layout.Alignment align =
+ ((AlignmentSpan) style[j]).getAlignment();
+ if (align == Layout.Alignment.ALIGN_CENTER) {
+ out.append("center");
+ } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
+ out.append("right");
+ } else {
+ out.append("left");
+ }
+ out.append("\" ");
+ }
+ }
+ if (style.length > 0) {
+ out.append(">");
+ }
+
+ withinDiv(out, text, i, next);
+
+ if (style.length > 0) {
+ out.append("</div>");
+ }
+ }
+ }
+
+ private static void withinDiv(StringBuilder out, Spanned text,
+ int start, int end) {
+ int next;
+ for (int i = start; i < end; i = next) {
+ next = text.nextSpanTransition(i, end, QuoteSpan.class);
QuoteSpan[] quotes = text.getSpans(i, next, QuoteSpan.class);
for (QuoteSpan quote: quotes) {
@@ -154,8 +198,6 @@ public class Html {
out.append("</blockquote>\n");
}
}
-
- return out.toString();
}
private static void withinBlockquote(StringBuilder out, Spanned text,
@@ -234,11 +276,32 @@ public class Html {
// Don't output the dummy character underlying the image.
i = next;
}
+ if (style[j] instanceof AbsoluteSizeSpan) {
+ out.append("<font size =\"");
+ out.append(((AbsoluteSizeSpan) style[j]).getSize() / 6);
+ out.append("\">");
+ }
+ if (style[j] instanceof ForegroundColorSpan) {
+ out.append("<font color =\"#");
+ String color = Integer.toHexString(((ForegroundColorSpan)
+ style[j]).getForegroundColor() + 0x01000000);
+ while (color.length() < 6) {
+ color = "0" + color;
+ }
+ out.append(color);
+ out.append("\">");
+ }
}
withinStyle(out, text, i, next);
for (int j = style.length - 1; j >= 0; j--) {
+ if (style[j] instanceof ForegroundColorSpan) {
+ out.append("</font>");
+ }
+ if (style[j] instanceof AbsoluteSizeSpan) {
+ out.append("</font>");
+ }
if (style[j] instanceof URLSpan) {
out.append("</a>");
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 95acf9d..23e740d 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,6 +16,8 @@
package android.text;
+import android.emoji.EmojiFactory;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -36,6 +38,20 @@ import android.view.KeyEvent;
* For text that will not change, use a {@link StaticLayout}.
*/
public abstract class Layout {
+ /* 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 would be necessary to display the
* specified text with one line per paragraph.
@@ -445,7 +461,9 @@ public abstract class Layout {
public abstract int getParagraphDirection(int line);
/**
- * Returns whether the specified line contains one or more tabs.
+ * Returns whether the specified line contains one or more
+ * characters that need to be handled specially, like tabs
+ * or emoji.
*/
public abstract boolean getLineContainsTab(int line);
@@ -1352,6 +1370,26 @@ public abstract class Layout {
h = dir * nextTab(text, start, end, h * dir, parspans);
segstart = j + 1;
+ } else if (hasTabs && buf[j] >= 0xD800 && buf[j] <= 0xDFFF && j + 1 < there) {
+ int emoji = Character.codePointAt(buf, j);
+
+ if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
+ Bitmap bm = EMOJI_FACTORY.
+ getBitmapFromAndroidPua(emoji);
+
+ if (bm != null) {
+ h += Styled.drawText(canvas, text,
+ start + segstart, start + j,
+ dir, (i & 1) != 0, x + h,
+ top, y, bottom, paint, workPaint,
+ start + j != end);
+
+ canvas.drawBitmap(bm, x + h, y - bm.getHeight(), paint);
+ h += bm.getWidth();
+ j++;
+ segstart = j + 1;
+ }
+ }
}
}
@@ -1394,7 +1432,22 @@ public abstract class Layout {
int segstart = here;
for (int j = hasTabs ? here : there; j <= there; j++) {
- if (j == there || buf[j] == '\t') {
+ int codept = 0;
+ Bitmap bm = null;
+
+ if (hasTabs && j < there) {
+ codept = buf[j];
+ }
+
+ if (codept >= 0xD800 && codept <= 0xDFFF && j + 1 < there) {
+ codept = Character.codePointAt(buf, j);
+
+ if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
+ bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
+ }
+ }
+
+ if (j == there || codept == '\t' || bm != null) {
float segw;
if (offset < start + j ||
@@ -1449,6 +1502,16 @@ public abstract class Layout {
h = dir * nextTab(text, start, end, h * dir, tabs);
}
+ if (bm != null) {
+ if (dir == DIR_RIGHT_TO_LEFT) {
+ h -= bm.getWidth();
+ } else {
+ h += bm.getWidth();
+ }
+
+ j++;
+ }
+
segstart = j + 1;
}
}
@@ -1488,7 +1551,22 @@ public abstract class Layout {
}
for (int i = hasTabs ? 0 : len; i <= len; i++) {
- if (i == len || buf[i] == '\t') {
+ int codept = 0;
+ Bitmap bm = null;
+
+ if (hasTabs && i < len) {
+ codept = buf[i];
+ }
+
+ if (codept >= 0xD800 && codept <= 0xDFFF && i < len) {
+ codept = Character.codePointAt(buf, i);
+
+ if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
+ bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
+ }
+ }
+
+ if (i == len || codept == '\t' || bm != null) {
workPaint.baselineShift = 0;
h += Styled.measureText(paint, workPaint, text,
@@ -1505,8 +1583,14 @@ public abstract class Layout {
}
}
- if (i != len)
- h = nextTab(text, start, end, h, tabs);
+ if (i != len) {
+ if (bm == null) {
+ h = nextTab(text, start, end, h, tabs);
+ } else {
+ h += bm.getWidth();
+ i++;
+ }
+ }
if (fm != null) {
if (fm.ascent < ab) {
@@ -1522,6 +1606,17 @@ public abstract class Layout {
if (fm.bottom > bot) {
bot = fm.bottom;
}
+
+ if (bm != null) {
+ int ht = -bm.getHeight();
+
+ if (ht < ab) {
+ ab = ht;
+ }
+ if (ht < top) {
+ top = ht;
+ }
+ }
}
here = i + 1;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 0fef40b..720d15a 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,6 +16,7 @@
package android.text;
+import android.graphics.Bitmap;
import android.graphics.Paint;
import com.android.internal.util.ArrayUtils;
import android.util.Log;
@@ -421,11 +422,16 @@ extends Layout
// dump(chdirs, n, "final");
- // extra: enforce that all tabs go the primary direction
+ // extra: enforce that all tabs and surrogate characters go the
+ // primary direction
+ // TODO: actually do directions right for surrogates
for (int j = 0; j < n; j++) {
- if (chs[j] == '\t')
+ char c = chs[j];
+
+ if (c == '\t' || (c >= 0xD800 && c <= 0xDFFF)) {
chdirs[j] = SOR;
+ }
}
// extra: enforce that object replacements go to the
@@ -548,16 +554,29 @@ extends Layout
char c = chs[j - start];
float before = w;
- switch (c) {
- case '\n':
- break;
-
- case '\t':
+ if (c == '\n') {
+ ;
+ } else if (c == '\t') {
w = Layout.nextTab(sub, start, end, w, null);
tab = true;
- break;
-
- default:
+ } else if (c >= 0xD800 && c <= 0xDFFF && j + 1 < next) {
+ int emoji = Character.codePointAt(chs, j - start);
+
+ if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
+ Bitmap bm = EMOJI_FACTORY.
+ getBitmapFromAndroidPua(emoji);
+
+ if (bm != null) {
+ w += bm.getWidth();
+ tab = true;
+ j++;
+ } else {
+ w += widths[j - start + (end - start)];
+ }
+ } else {
+ w += widths[j - start + (end - start)];
+ }
+ } else {
w += widths[j - start + (end - start)];
}