Loading core/java/android/text/Html.java +62 −57 Original line number Diff line number Diff line Loading @@ -54,6 +54,9 @@ import android.text.style.UnderlineSpan; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; Loading Loading @@ -691,6 +694,22 @@ class HtmlToSpannedConverter implements ContentHandler { private static Pattern sBackgroundColorPattern; private static Pattern sTextDecorationPattern; /** * Name-value mapping of HTML/CSS colors which have different values in {@link Color}. */ private static final Map<String, Integer> sColorMap; static { sColorMap = new HashMap<>(); sColorMap.put("darkgray", 0xFFA9A9A9); sColorMap.put("gray", 0xFF808080); sColorMap.put("lightgray", 0xFFD3D3D3); sColorMap.put("darkgrey", 0xFFA9A9A9); sColorMap.put("grey", 0xFF808080); sColorMap.put("lightgrey", 0xFFD3D3D3); sColorMap.put("green", 0xFF008000); } private static Pattern getTextAlignPattern() { if (sTextAlignPattern == null) { sTextAlignPattern = Pattern.compile("(?:\\s+|\\A)text-align\\s*:\\s*(\\S*)\\b"); Loading Loading @@ -948,7 +967,7 @@ class HtmlToSpannedConverter implements ContentHandler { final int len = text.length(); if (margin > 0) { appendNewlines(text, margin); text.setSpan(new Newline(margin), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Newline(margin)); } String style = attributes.getValue("", "style"); Loading @@ -957,14 +976,11 @@ class HtmlToSpannedConverter implements ContentHandler { if (m.find()) { String alignment = m.group(1); if (alignment.equalsIgnoreCase("start")) { text.setSpan(new Alignment(Layout.Alignment.ALIGN_NORMAL), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Alignment(Layout.Alignment.ALIGN_NORMAL)); } else if (alignment.equalsIgnoreCase("center")) { text.setSpan(new Alignment(Layout.Alignment.ALIGN_CENTER), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Alignment(Layout.Alignment.ALIGN_CENTER)); } else if (alignment.equalsIgnoreCase("end")) { text.setSpan(new Alignment(Layout.Alignment.ALIGN_OPPOSITE), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Alignment(Layout.Alignment.ALIGN_OPPOSITE)); } } } Loading Loading @@ -1053,7 +1069,7 @@ class HtmlToSpannedConverter implements ContentHandler { private static void start(Editable text, Object mark) { int len = text.length(); text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK); text.setSpan(mark, len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } private static void end(Editable text, Class kind, Object repl) { Loading @@ -1064,25 +1080,22 @@ class HtmlToSpannedConverter implements ContentHandler { } } private static void startCssStyle(Editable text, Attributes attributes) { private void startCssStyle(Editable text, Attributes attributes) { String style = attributes.getValue("", "style"); if (style != null) { final int len = text.length(); Matcher m = getForegroundColorPattern().matcher(style); if (m.find()) { int c = Color.getHtmlColor(m.group(1)); int c = getHtmlColor(m.group(1)); if (c != -1) { text.setSpan(new Foreground(c | 0xFF000000), len, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Foreground(c | 0xFF000000)); } } m = getBackgroundColorPattern().matcher(style); if (m.find()) { int c = Color.getHtmlColor(m.group(1)); int c = getHtmlColor(m.group(1)); if (c != -1) { text.setSpan(new Background(c | 0xFF000000), len, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Background(c | 0xFF000000)); } } Loading @@ -1090,7 +1103,7 @@ class HtmlToSpannedConverter implements ContentHandler { if (m.find()) { String textDecoration = m.group(1); if (textDecoration.equalsIgnoreCase("line-through")) { text.setSpan(new Strikethrough(), len, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Strikethrough()); } } } Loading Loading @@ -1134,58 +1147,41 @@ class HtmlToSpannedConverter implements ContentHandler { Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } private static void startFont(Editable text, Attributes attributes) { private void startFont(Editable text, Attributes attributes) { String color = attributes.getValue("", "color"); String face = attributes.getValue("", "face"); int len = text.length(); text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK); } private static void endFont(Editable text) { int len = text.length(); Font f = getLast(text, Font.class); int where = text.getSpanStart(f); text.removeSpan(f); if (where != len) { if (!TextUtils.isEmpty(f.mColor)) { if (f.mColor.startsWith("@")) { Resources res = Resources.getSystem(); String name = f.mColor.substring(1); int colorRes = res.getIdentifier(name, "color", "android"); if (colorRes != 0) { ColorStateList colors = res.getColorStateList(colorRes, null); text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else { int c = Color.getHtmlColor(f.mColor); if (!TextUtils.isEmpty(color)) { int c = getHtmlColor(color); if (c != -1) { text.setSpan(new ForegroundColorSpan(c | 0xFF000000), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); start(text, new Foreground(c | 0xFF000000)); } } if (!TextUtils.isEmpty(face)) { start(text, new Font(face)); } } if (f.mFace != null) { text.setSpan(new TypefaceSpan(f.mFace), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); private static void endFont(Editable text) { Font font = getLast(text, Font.class); if (font != null) { setSpanFromMark(text, font, new TypefaceSpan(font.mFace)); } Foreground foreground = getLast(text, Foreground.class); if (foreground != null) { setSpanFromMark(text, foreground, new ForegroundColorSpan(foreground.mForegroundColor)); } } private static void startA(Editable text, Attributes attributes) { String href = attributes.getValue("", "href"); int len = text.length(); text.setSpan(new Href(href), len, len, Spannable.SPAN_MARK_MARK); start(text, new Href(href)); } private static void endA(Editable text) { int len = text.length(); Href h = getLast(text, Href.class); if (h != null) { if (h.mHref != null) { Loading @@ -1194,6 +1190,17 @@ class HtmlToSpannedConverter implements ContentHandler { } } private int getHtmlColor(String color) { if ((mFlags & Html.FROM_HTML_OPTION_USE_CSS_COLORS) == Html.FROM_HTML_OPTION_USE_CSS_COLORS) { Integer i = sColorMap.get(color.toLowerCase(Locale.US)); if (i != null) { return i; } } return Color.getHtmlColor(color); } public void setDocumentLocator(Locator locator) { } Loading Loading @@ -1278,11 +1285,9 @@ class HtmlToSpannedConverter implements ContentHandler { private static class Bullet { } private static class Font { public String mColor; public String mFace; public Font(String color, String face) { mColor = color; public Font(String face) { mFace = face; } } Loading Loading
core/java/android/text/Html.java +62 −57 Original line number Diff line number Diff line Loading @@ -54,6 +54,9 @@ import android.text.style.UnderlineSpan; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; Loading Loading @@ -691,6 +694,22 @@ class HtmlToSpannedConverter implements ContentHandler { private static Pattern sBackgroundColorPattern; private static Pattern sTextDecorationPattern; /** * Name-value mapping of HTML/CSS colors which have different values in {@link Color}. */ private static final Map<String, Integer> sColorMap; static { sColorMap = new HashMap<>(); sColorMap.put("darkgray", 0xFFA9A9A9); sColorMap.put("gray", 0xFF808080); sColorMap.put("lightgray", 0xFFD3D3D3); sColorMap.put("darkgrey", 0xFFA9A9A9); sColorMap.put("grey", 0xFF808080); sColorMap.put("lightgrey", 0xFFD3D3D3); sColorMap.put("green", 0xFF008000); } private static Pattern getTextAlignPattern() { if (sTextAlignPattern == null) { sTextAlignPattern = Pattern.compile("(?:\\s+|\\A)text-align\\s*:\\s*(\\S*)\\b"); Loading Loading @@ -948,7 +967,7 @@ class HtmlToSpannedConverter implements ContentHandler { final int len = text.length(); if (margin > 0) { appendNewlines(text, margin); text.setSpan(new Newline(margin), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Newline(margin)); } String style = attributes.getValue("", "style"); Loading @@ -957,14 +976,11 @@ class HtmlToSpannedConverter implements ContentHandler { if (m.find()) { String alignment = m.group(1); if (alignment.equalsIgnoreCase("start")) { text.setSpan(new Alignment(Layout.Alignment.ALIGN_NORMAL), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Alignment(Layout.Alignment.ALIGN_NORMAL)); } else if (alignment.equalsIgnoreCase("center")) { text.setSpan(new Alignment(Layout.Alignment.ALIGN_CENTER), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Alignment(Layout.Alignment.ALIGN_CENTER)); } else if (alignment.equalsIgnoreCase("end")) { text.setSpan(new Alignment(Layout.Alignment.ALIGN_OPPOSITE), len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Alignment(Layout.Alignment.ALIGN_OPPOSITE)); } } } Loading Loading @@ -1053,7 +1069,7 @@ class HtmlToSpannedConverter implements ContentHandler { private static void start(Editable text, Object mark) { int len = text.length(); text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK); text.setSpan(mark, len, len, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } private static void end(Editable text, Class kind, Object repl) { Loading @@ -1064,25 +1080,22 @@ class HtmlToSpannedConverter implements ContentHandler { } } private static void startCssStyle(Editable text, Attributes attributes) { private void startCssStyle(Editable text, Attributes attributes) { String style = attributes.getValue("", "style"); if (style != null) { final int len = text.length(); Matcher m = getForegroundColorPattern().matcher(style); if (m.find()) { int c = Color.getHtmlColor(m.group(1)); int c = getHtmlColor(m.group(1)); if (c != -1) { text.setSpan(new Foreground(c | 0xFF000000), len, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Foreground(c | 0xFF000000)); } } m = getBackgroundColorPattern().matcher(style); if (m.find()) { int c = Color.getHtmlColor(m.group(1)); int c = getHtmlColor(m.group(1)); if (c != -1) { text.setSpan(new Background(c | 0xFF000000), len, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Background(c | 0xFF000000)); } } Loading @@ -1090,7 +1103,7 @@ class HtmlToSpannedConverter implements ContentHandler { if (m.find()) { String textDecoration = m.group(1); if (textDecoration.equalsIgnoreCase("line-through")) { text.setSpan(new Strikethrough(), len, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); start(text, new Strikethrough()); } } } Loading Loading @@ -1134,58 +1147,41 @@ class HtmlToSpannedConverter implements ContentHandler { Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } private static void startFont(Editable text, Attributes attributes) { private void startFont(Editable text, Attributes attributes) { String color = attributes.getValue("", "color"); String face = attributes.getValue("", "face"); int len = text.length(); text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK); } private static void endFont(Editable text) { int len = text.length(); Font f = getLast(text, Font.class); int where = text.getSpanStart(f); text.removeSpan(f); if (where != len) { if (!TextUtils.isEmpty(f.mColor)) { if (f.mColor.startsWith("@")) { Resources res = Resources.getSystem(); String name = f.mColor.substring(1); int colorRes = res.getIdentifier(name, "color", "android"); if (colorRes != 0) { ColorStateList colors = res.getColorStateList(colorRes, null); text.setSpan(new TextAppearanceSpan(null, 0, 0, colors, null), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else { int c = Color.getHtmlColor(f.mColor); if (!TextUtils.isEmpty(color)) { int c = getHtmlColor(color); if (c != -1) { text.setSpan(new ForegroundColorSpan(c | 0xFF000000), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); start(text, new Foreground(c | 0xFF000000)); } } if (!TextUtils.isEmpty(face)) { start(text, new Font(face)); } } if (f.mFace != null) { text.setSpan(new TypefaceSpan(f.mFace), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); private static void endFont(Editable text) { Font font = getLast(text, Font.class); if (font != null) { setSpanFromMark(text, font, new TypefaceSpan(font.mFace)); } Foreground foreground = getLast(text, Foreground.class); if (foreground != null) { setSpanFromMark(text, foreground, new ForegroundColorSpan(foreground.mForegroundColor)); } } private static void startA(Editable text, Attributes attributes) { String href = attributes.getValue("", "href"); int len = text.length(); text.setSpan(new Href(href), len, len, Spannable.SPAN_MARK_MARK); start(text, new Href(href)); } private static void endA(Editable text) { int len = text.length(); Href h = getLast(text, Href.class); if (h != null) { if (h.mHref != null) { Loading @@ -1194,6 +1190,17 @@ class HtmlToSpannedConverter implements ContentHandler { } } private int getHtmlColor(String color) { if ((mFlags & Html.FROM_HTML_OPTION_USE_CSS_COLORS) == Html.FROM_HTML_OPTION_USE_CSS_COLORS) { Integer i = sColorMap.get(color.toLowerCase(Locale.US)); if (i != null) { return i; } } return Color.getHtmlColor(color); } public void setDocumentLocator(Locator locator) { } Loading Loading @@ -1278,11 +1285,9 @@ class HtmlToSpannedConverter implements ContentHandler { private static class Bullet { } private static class Font { public String mColor; public String mFace; public Font(String color, String face) { mColor = color; public Font(String face) { mFace = face; } } Loading