diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-18 17:39:46 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-18 17:39:46 -0700 |
commit | 105925376f8d0f6b318c9938c7b83ef7fef094da (patch) | |
tree | 3b19ee2bd8704cb9c6a0da7e42dec6759183de6d /core/java/android/text | |
parent | ba87e3e6c985e7175152993b5efcc7dd2f0e1c93 (diff) | |
download | frameworks_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.java | 69 | ||||
-rw-r--r-- | core/java/android/text/Layout.java | 105 | ||||
-rw-r--r-- | core/java/android/text/StaticLayout.java | 39 |
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)]; } |