diff --git a/README.md b/README.md
index 3dacaee66..5f8eaebe1 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,6 @@ Here is the libraries
- [okhttp](https://github.com/square/okhttp)
- [roaster](https://github.com/forge/roaster)
- [TapTargetView](https://github.com/KeepSafe/TapTargetView)
-- [TagSoup](http://home.ccil.org/~cowan/tagsoup/)
- [libarchive](http://www.libarchive.org/)
- [XZ Utils](https://tukaani.org/xz/)
diff --git a/app/build.gradle b/app/build.gradle
index 6c3440c7a..b40e7288a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -112,7 +112,6 @@ dependencies {
implementation 'dev.rikka.rikkax.layoutinflater:layoutinflater:1.2.0'
implementation 'dev.rikka.rikkax.preference:simplemenu-preference:1.0.3'
implementation 'dev.rikka.rikkax.material:material-preference:2.0.0'
- implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1'
implementation 'org.greenrobot:greendao:3.3.0'
implementation 'org.jsoup:jsoup:1.15.2'
implementation projects.native
diff --git a/app/src/main/java/com/hippo/ehviewer/EhApplication.java b/app/src/main/java/com/hippo/ehviewer/EhApplication.java
index fbd20b031..031a76533 100644
--- a/app/src/main/java/com/hippo/ehviewer/EhApplication.java
+++ b/app/src/main/java/com/hippo/ehviewer/EhApplication.java
@@ -27,6 +27,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Debug;
+import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
@@ -63,7 +64,6 @@ import com.hippo.image.Image;
import com.hippo.image.ImageBitmap;
import com.hippo.network.StatusCodeException;
import com.hippo.scene.SceneApplication;
-import com.hippo.text.Html;
import com.hippo.unifile.UniFile;
import com.hippo.util.BitmapUtils;
import com.hippo.util.ClipboardUtil;
@@ -338,7 +338,6 @@ public class EhApplication extends SceneApplication {
StatusCodeException.initialize(this);
Settings.initialize(this);
ReadableTime.initialize(this);
- Html.initialize(this);
AppConfig.initialize(this);
SpiderDen.initialize(this);
EhDB.initialize(this);
diff --git a/app/src/main/java/com/hippo/ehviewer/preference/IdentityCookiePreference.java b/app/src/main/java/com/hippo/ehviewer/preference/IdentityCookiePreference.java
index 74b46e65c..a85c9e6f3 100644
--- a/app/src/main/java/com/hippo/ehviewer/preference/IdentityCookiePreference.java
+++ b/app/src/main/java/com/hippo/ehviewer/preference/IdentityCookiePreference.java
@@ -18,6 +18,7 @@ package com.hippo.ehviewer.preference;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.text.Html;
import android.util.AttributeSet;
import androidx.appcompat.app.AlertDialog;
@@ -29,7 +30,6 @@ import com.hippo.ehviewer.client.EhUrl;
import com.hippo.ehviewer.ui.SettingsActivity;
import com.hippo.ehviewer.ui.scene.BaseScene;
import com.hippo.preference.MessagePreference;
-import com.hippo.text.Html;
import com.hippo.util.ClipboardUtil;
import java.util.LinkedList;
@@ -92,7 +92,7 @@ public class IdentityCookiePreference extends MessagePreference {
message = EhCookieStore.KEY_IPD_MEMBER_ID + ": " + ipbMemberId + "
"
+ EhCookieStore.KEY_IPD_PASS_HASH + ": " + ipbPassHash + "
"
+ EhCookieStore.KEY_IGNEOUS + ": " + igneous;
- setDialogMessage(Html.fromHtml(getContext().getString(R.string.settings_eh_identity_cookies_signed, message)));
+ setDialogMessage(Html.fromHtml(getContext().getString(R.string.settings_eh_identity_cookies_signed, message), Html.FROM_HTML_MODE_LEGACY));
message = message.replace("
", "\n");
} else {
setDialogMessage(getContext().getString(R.string.settings_eh_identity_cookies_tourist));
diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AboutFragment.java b/app/src/main/java/com/hippo/ehviewer/ui/fragment/AboutFragment.java
index f3b7929dc..57e66bdf1 100644
--- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AboutFragment.java
+++ b/app/src/main/java/com/hippo/ehviewer/ui/fragment/AboutFragment.java
@@ -17,12 +17,12 @@
package com.hippo.ehviewer.ui.fragment;
import android.os.Bundle;
+import android.text.Html;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import com.hippo.ehviewer.R;
-import com.hippo.text.Html;
public class AboutFragment extends BasePreferenceFragment {
@@ -33,7 +33,7 @@ public class AboutFragment extends BasePreferenceFragment {
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.about_settings);
Preference author = findPreference(KEY_AUTHOR);
- author.setSummary(Html.fromHtml(getString(R.string.settings_about_author_summary).replace('$', '@')));
+ author.setSummary(Html.fromHtml(getString(R.string.settings_about_author_summary).replace('$', '@'), Html.FROM_HTML_MODE_LEGACY));
}
@Override
diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java
index 4fcd1d047..aee49c0f8 100644
--- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java
+++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryCommentsScene.java
@@ -24,9 +24,11 @@ import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Looper;
+import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
@@ -69,7 +71,6 @@ import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.client.parser.VoteCommentParser;
import com.hippo.ehviewer.ui.MainActivity;
import com.hippo.scene.SceneFragment;
-import com.hippo.text.Html;
import com.hippo.text.URLImageGetter;
import com.hippo.util.ClipboardUtil;
import com.hippo.util.ExceptionUtils;
@@ -858,9 +859,11 @@ public final class GalleryCommentsScene extends ToolbarScene
}
private CharSequence generateComment(Context context, ObservedTextView textView, GalleryComment comment) {
- SpannableStringBuilder ssb = Html.fromHtml(comment.comment, new URLImageGetter(textView,
+ Spanned sp = Html.fromHtml(comment.comment, Html.FROM_HTML_MODE_LEGACY, new URLImageGetter(textView,
EhApplication.getConaco(context)), null);
+ SpannableStringBuilder ssb = new SpannableStringBuilder(sp);
+
if (0 != comment.id && 0 != comment.score) {
int score = comment.score;
String scoreString = score > 0 ? "+" + score : Integer.toString(score);
diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java
index 9bbb77c89..f10f55060 100755
--- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java
+++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java
@@ -34,6 +34,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
+import android.text.Html;
import android.text.TextUtils;
import android.util.Pair;
import android.view.LayoutInflater;
@@ -100,7 +101,6 @@ import com.hippo.ehviewer.ui.annotation.WholeLifeCircle;
import com.hippo.ehviewer.widget.GalleryRatingBar;
import com.hippo.scene.Announcer;
import com.hippo.scene.SceneFragment;
-import com.hippo.text.Html;
import com.hippo.text.URLImageGetter;
import com.hippo.util.AppHelper;
import com.hippo.util.ClipboardUtil;
@@ -1063,7 +1063,7 @@ public class GalleryDetailScene extends ToolbarScene implements View.OnClickList
time.setText(ReadableTime.getTimeAgo(comment.time));
ObservedTextView c = v.findViewById(R.id.comment);
c.setMaxLines(5);
- c.setText(Html.fromHtml(comment.comment,
+ c.setText(Html.fromHtml(comment.comment, Html.FROM_HTML_MODE_LEGACY,
new URLImageGetter(c, EhApplication.getConaco(context)), null));
v.setBackgroundColor(Color.TRANSPARENT);
}
diff --git a/app/src/main/java/com/hippo/preference/MessagePreference.java b/app/src/main/java/com/hippo/preference/MessagePreference.java
index 7d3f54640..16175219d 100644
--- a/app/src/main/java/com/hippo/preference/MessagePreference.java
+++ b/app/src/main/java/com/hippo/preference/MessagePreference.java
@@ -18,6 +18,7 @@ package com.hippo.preference;
import android.content.Context;
import android.content.res.TypedArray;
+import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.AttributeSet;
import android.view.View;
@@ -26,7 +27,6 @@ import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import com.hippo.ehviewer.R;
-import com.hippo.text.Html;
public class MessagePreference extends DialogPreference {
@@ -52,7 +52,7 @@ public class MessagePreference extends DialogPreference {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MessagePreference, defStyleAttr, defStyleRes);
String message = a.getString(R.styleable.MessagePreference_dialogMessage);
if (a.getBoolean(R.styleable.MessagePreference_dialogMessageHtml, false)) {
- mDialogMessage = Html.fromHtml(message);
+ mDialogMessage = Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY);
} else {
mDialogMessage = message;
}
diff --git a/app/src/main/java/com/hippo/text/Html.java b/app/src/main/java/com/hippo/text/Html.java
deleted file mode 100644
index e1d31591c..000000000
--- a/app/src/main/java/com/hippo/text/Html.java
+++ /dev/null
@@ -1,1110 +0,0 @@
-/*
- * Copyright (C) 2007 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.hippo.text;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.text.Editable;
-import android.text.Layout;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextUtils;
-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;
-import android.text.style.ParagraphStyle;
-import android.text.style.QuoteSpan;
-import android.text.style.RelativeSizeSpan;
-import android.text.style.StrikethroughSpan;
-import android.text.style.StyleSpan;
-import android.text.style.SubscriptSpan;
-import android.text.style.SuperscriptSpan;
-import android.text.style.TextAppearanceSpan;
-import android.text.style.TypefaceSpan;
-import android.text.style.URLSpan;
-import android.text.style.UnderlineSpan;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-
-import org.ccil.cowan.tagsoup.HTMLSchema;
-import org.ccil.cowan.tagsoup.Parser;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.HashMap;
-import java.util.Locale;
-
-/**
- * This class processes HTML strings into displayable styled text.
- * Not all HTML tags are supported.
- */
-public class Html {
-
- static Resources sResources;
-
- private Html() {
- }
-
- public static void initialize(Context context) {
- sResources = context.getResources();
- }
-
- /**
- * Returns displayable styled text from the provided HTML string.
- * Any <img> tags in the HTML will display as a generic
- * replacement image which your program can then go through and
- * replace with real images.
- *
- *
This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.
- */
- public static Spanned fromHtml(String source) {
- return fromHtml(source, null, null);
- }
-
- /**
- * Returns displayable styled text from the provided HTML string.
- * Any <img> tags in the HTML will use the specified ImageGetter
- * to request a representation of the image (use null if you don't
- * want this) and the specified TagHandler to handle unknown tags
- * (specify null if you don't want this).
- *
- *
This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.
- */
- public static SpannableStringBuilder fromHtml(String source, ImageGetter imageGetter,
- TagHandler tagHandler) {
- Parser parser = new Parser();
- try {
- parser.setProperty(Parser.schemaProperty, HtmlParser.schema);
- } catch (org.xml.sax.SAXNotRecognizedException e) {
- // Should not happen.
- throw new RuntimeException(e);
- } catch (org.xml.sax.SAXNotSupportedException e) {
- // Should not happen.
- throw new RuntimeException(e);
- }
-
- HtmlToSpannedConverter converter =
- new HtmlToSpannedConverter(source, imageGetter, tagHandler,
- parser);
- return converter.convert();
- }
-
- /**
- * Returns an HTML representation of the provided Spanned text. A best effort is
- * made to add HTML tags corresponding to spans. Also note that HTML metacharacters
- * (such as "<" and "&") within the input text are escaped.
- *
- * @param text input text to convert
- * @return string containing input converted to HTML
- */
- public static String toHtml(Spanned text) {
- StringBuilder out = new StringBuilder();
- withinHtml(out, text);
- return out.toString();
- }
-
- /**
- * Returns an HTML escaped representation of the given plain text.
- */
- public static String escapeHtml(CharSequence text) {
- StringBuilder out = new StringBuilder();
- withinStyle(out, text, 0, text.length());
- 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, ParagraphStyle.class);
- ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
- String elements = " ";
- boolean needDiv = false;
-
- for (int j = 0; j < style.length; j++) {
- if (style[j] instanceof AlignmentSpan) {
- Layout.Alignment align =
- ((AlignmentSpan) style[j]).getAlignment();
- needDiv = true;
- if (align == Layout.Alignment.ALIGN_CENTER) {
- elements = "align=\"center\" " + elements;
- } else if (align == Layout.Alignment.ALIGN_OPPOSITE) {
- elements = "align=\"right\" " + elements;
- } else {
- elements = "align=\"left\" " + elements;
- }
- }
- }
- if (needDiv) {
- out.append("
");
- }
-
- withinDiv(out, text, i, next);
-
- if (needDiv) {
- out.append("
");
- }
- }
- }
-
- 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) {
- out.append("");
- }
-
- withinBlockquote(out, text, i, next);
-
- for (QuoteSpan quote : quotes) {
- out.append("
\n");
- }
- }
- }
-
- private static String getOpenParaTagWithDirection(Spanned text, int start, int end) {
- //final int len = end - start;
- //final byte[] levels = new byte[len];
- //final char[] buffer = new char[len];
- //TextUtils.getChars(text, start, end, buffer, 0);
-
- //int paraDir = AndroidBidi.bidi(Layout.DIR_REQUEST_DEFAULT_LTR, buffer, levels, len,
- // false /* no info */);
- //switch(paraDir) {
- // case Layout.DIR_RIGHT_TO_LEFT:
- // return "";
- // case Layout.DIR_LEFT_TO_RIGHT:
- // default:
- // return "
";
- //}
- return "
";
- }
-
- private static void withinBlockquote(StringBuilder out, Spanned text,
- int start, int end) {
- out.append(getOpenParaTagWithDirection(text, start, end));
-
- int next;
- for (int i = start; i < end; i = next) {
- next = TextUtils.indexOf(text, '\n', i, end);
- if (next < 0) {
- next = end;
- }
-
- int nl = 0;
-
- while (next < end && text.charAt(next) == '\n') {
- nl++;
- next++;
- }
-
- if (withinParagraph(out, text, i, next - nl, nl, next == end)) {
- /* Paragraph should be closed */
- out.append("
\n");
- out.append(getOpenParaTagWithDirection(text, next, end));
- }
- }
-
- out.append("\n");
- }
-
- /* Returns true if the caller should close and reopen the paragraph. */
- private static boolean withinParagraph(StringBuilder out, Spanned text,
- int start, int end, int nl,
- boolean last) {
- int next;
- for (int i = start; i < end; i = next) {
- next = text.nextSpanTransition(i, end, CharacterStyle.class);
- CharacterStyle[] style = text.getSpans(i, next,
- CharacterStyle.class);
-
- for (int j = 0; j < style.length; j++) {
- if (style[j] instanceof StyleSpan) {
- int s = ((StyleSpan) style[j]).getStyle();
-
- if ((s & Typeface.BOLD) != 0) {
- out.append("");
- }
- if ((s & Typeface.ITALIC) != 0) {
- out.append("");
- }
- }
- if (style[j] instanceof TypefaceSpan) {
- String s = ((TypefaceSpan) style[j]).getFamily();
-
- if ("monospace".equals(s)) {
- out.append("");
- }
- }
- if (style[j] instanceof SuperscriptSpan) {
- out.append("");
- }
- if (style[j] instanceof SubscriptSpan) {
- out.append("");
- }
- if (style[j] instanceof UnderlineSpan) {
- out.append("");
- }
- if (style[j] instanceof StrikethroughSpan) {
- out.append("");
- }
- if (style[j] instanceof URLSpan) {
- out.append("");
- }
- if (style[j] instanceof ImageSpan) {
- out.append("
");
-
- // Don't output the dummy character underlying the image.
- i = next;
- }
- if (style[j] instanceof AbsoluteSizeSpan) {
- out.append("");
- }
- if (style[j] instanceof ForegroundColorSpan) {
- out.append("");
- }
- }
-
- withinStyle(out, text, i, next);
-
- for (int j = style.length - 1; j >= 0; j--) {
- if (style[j] instanceof ForegroundColorSpan) {
- out.append("");
- }
- if (style[j] instanceof AbsoluteSizeSpan) {
- out.append("");
- }
- if (style[j] instanceof URLSpan) {
- out.append("");
- }
- if (style[j] instanceof StrikethroughSpan) {
- out.append("");
- }
- if (style[j] instanceof UnderlineSpan) {
- out.append("");
- }
- if (style[j] instanceof SubscriptSpan) {
- out.append("");
- }
- if (style[j] instanceof SuperscriptSpan) {
- out.append("");
- }
- if (style[j] instanceof TypefaceSpan) {
- String s = ((TypefaceSpan) style[j]).getFamily();
-
- if (s.equals("monospace")) {
- out.append("");
- }
- }
- if (style[j] instanceof StyleSpan) {
- int s = ((StyleSpan) style[j]).getStyle();
-
- if ((s & Typeface.BOLD) != 0) {
- out.append("");
- }
- if ((s & Typeface.ITALIC) != 0) {
- out.append("");
- }
- }
- }
- }
-
- if (nl == 1) {
- out.append("
\n");
- return false;
- } else {
- for (int i = 2; i < nl; i++) {
- out.append("
");
- }
- return !last;
- }
- }
-
- private static void withinStyle(StringBuilder out, CharSequence text,
- int start, int end) {
- for (int i = start; i < end; i++) {
- char c = text.charAt(i);
-
- if (c == '<') {
- out.append("<");
- } else if (c == '>') {
- out.append(">");
- } else if (c == '&') {
- out.append("&");
- } else if (c >= 0xD800 && c <= 0xDFFF) {
- if (c < 0xDC00 && i + 1 < end) {
- char d = text.charAt(i + 1);
- if (d >= 0xDC00 && d <= 0xDFFF) {
- i++;
- int codepoint = 0x010000 | (int) c - 0xD800 << 10 | (int) d - 0xDC00;
- out.append("").append(codepoint).append(";");
- }
- }
- } else if (c > 0x7E || c < ' ') {
- out.append("").append((int) c).append(";");
- } else if (c == ' ') {
- while (i + 1 < end && text.charAt(i + 1) == ' ') {
- out.append(" ");
- i++;
- }
-
- out.append(' ');
- } else {
- out.append(c);
- }
- }
- }
-
- /**
- * Retrieves images for HTML <img> tags.
- */
- public interface ImageGetter {
- /**
- * This method is called when the HTML parser encounters an
- * <img> tag. The source argument is the
- * string from the "src" attribute; the return value should be
- * a Drawable representation of the image or null
- * for a generic replacement image. Make sure you call
- * setBounds() on your Drawable if it doesn't already have
- * its bounds set.
- */
- Drawable getDrawable(String source);
- }
-
- /**
- * Is notified when HTML tags are encountered that the parser does
- * not know how to interpret.
- */
- public interface TagHandler {
- /**
- * This method will be called whenn the HTML parser encounters
- * a tag that it does not know how to interpret.
- */
- void handleTag(boolean opening, String tag,
- Editable output, XMLReader xmlReader);
- }
-
- /**
- * Lazy initialization holder for HTML parser. This class will
- * a) be preloaded by the zygote, or b) not loaded until absolutely
- * necessary.
- */
- private static class HtmlParser {
- private static final HTMLSchema schema = new HTMLSchema();
- }
-}
-
-class HtmlToSpannedConverter implements ContentHandler {
-
- private static final float[] HEADER_SIZES = {
- 1.5f, 1.4f, 1.3f, 1.2f, 1.1f, 1f,
- };
- private static final HashMap sColorNameMap;
-
- static {
- sColorNameMap = new HashMap<>();
- sColorNameMap.put("aliceblue", 0xFFF0F8FF);
- sColorNameMap.put("antiquewhite", 0xFFFAEBD7);
- sColorNameMap.put("aqua", 0xFFFFFF);
- sColorNameMap.put("aquamarine", 0xFF7FFFD4);
- sColorNameMap.put("azure", 0xFFF0FFFF);
- sColorNameMap.put("beige", 0xFFF5F5DC);
- sColorNameMap.put("bisque", 0xFFFFE4C4);
- sColorNameMap.put("black", 0xFF0);
- sColorNameMap.put("blanchedalmond", 0xFFFFEBCD);
- sColorNameMap.put("blue", 0xFFFF);
- sColorNameMap.put("blueviolet", 0xFF8A2BE2);
- sColorNameMap.put("brown", 0xFFA52A2A);
- sColorNameMap.put("burlywood", 0xFFDEB887);
- sColorNameMap.put("cadetblue", 0xFF5F9EA0);
- sColorNameMap.put("chartreuse", 0xFF7FFF00);
- sColorNameMap.put("chocolate", 0xFFD2691E);
- sColorNameMap.put("coral", 0xFFFF7F50);
- sColorNameMap.put("cornflowerblue", 0xFF6495ED);
- sColorNameMap.put("cornsilk", 0xFFFFF8DC);
- sColorNameMap.put("crimson", 0xFFDC143C);
- sColorNameMap.put("cyan", 0xFFFFFF);
- sColorNameMap.put("darkblue", 0xFF8B);
- sColorNameMap.put("darkcyan", 0xFF8B8B);
- sColorNameMap.put("darkgoldenrod", 0xFFB8860B);
- sColorNameMap.put("darkgray", 0xFFA9A9A9);
- sColorNameMap.put("darkgreen", 0xFF6400);
- sColorNameMap.put("darkkhaki", 0xFFBDB76B);
- sColorNameMap.put("darkmagenta", 0xFF8B008B);
- sColorNameMap.put("darkolivegreen", 0xFF556B2F);
- sColorNameMap.put("darkorange", 0xFFFF8C00);
- sColorNameMap.put("darkorchid", 0xFF9932CC);
- sColorNameMap.put("darkred", 0xFF8B0000);
- sColorNameMap.put("darksalmon", 0xFFE9967A);
- sColorNameMap.put("darkseagreen", 0xFF8FBC8F);
- sColorNameMap.put("darkslateblue", 0xFF483D8B);
- sColorNameMap.put("darkslategray", 0xFF2F4F4F);
- sColorNameMap.put("darkturquoise", 0xFFCED1);
- sColorNameMap.put("darkviolet", 0xFF9400D3);
- sColorNameMap.put("deeppink", 0xFFFF1493);
- sColorNameMap.put("deepskyblue", 0xFFBFFF);
- sColorNameMap.put("dimgray", 0xFF696969);
- sColorNameMap.put("dodgerblue", 0xFF1E90FF);
- sColorNameMap.put("firebrick", 0xFFB22222);
- sColorNameMap.put("floralwhite", 0xFFFFFAF0);
- sColorNameMap.put("forestgreen", 0xFF228B22);
- sColorNameMap.put("fuchsia", 0xFFFF00FF);
- sColorNameMap.put("gainsboro", 0xFFDCDCDC);
- sColorNameMap.put("ghostwhite", 0xFFF8F8FF);
- sColorNameMap.put("gold", 0xFFFFD700);
- sColorNameMap.put("goldenrod", 0xFFDAA520);
- sColorNameMap.put("gray", 0xFF808080);
- sColorNameMap.put("green", 0xFF8000);
- sColorNameMap.put("greenyellow", 0xFFADFF2F);
- sColorNameMap.put("honeydew", 0xFFF0FFF0);
- sColorNameMap.put("hotpink", 0xFFFF69B4);
- sColorNameMap.put("indianred", 0xFFCD5C5C);
- sColorNameMap.put("indigo", 0xFF4B0082);
- sColorNameMap.put("ivory", 0xFFFFFFF0);
- sColorNameMap.put("khaki", 0xFFF0E68C);
- sColorNameMap.put("lavender", 0xFFE6E6FA);
- sColorNameMap.put("lavenderblush", 0xFFFFF0F5);
- sColorNameMap.put("lawngreen", 0xFF7CFC00);
- sColorNameMap.put("lemonchiffon", 0xFFFFFACD);
- sColorNameMap.put("lightblue", 0xFFADD8E6);
- sColorNameMap.put("lightcoral", 0xFFF08080);
- sColorNameMap.put("lightcyan", 0xFFE0FFFF);
- sColorNameMap.put("lightgoldenrodyellow", 0xFFFAFAD2);
- sColorNameMap.put("lightgreen", 0xFF90EE90);
- sColorNameMap.put("lightgrey", 0xFFD3D3D3);
- sColorNameMap.put("lightpink", 0xFFFFB6C1);
- sColorNameMap.put("lightsalmon", 0xFFFFA07A);
- sColorNameMap.put("lightseagreen", 0xFF20B2AA);
- sColorNameMap.put("lightskyblue", 0xFF87CEFA);
- sColorNameMap.put("lightslategray", 0xFF778899);
- sColorNameMap.put("lightsteelblue", 0xFFB0C4DE);
- sColorNameMap.put("lightyellow", 0xFFFFFFE0);
- sColorNameMap.put("lime", 0xFFFF00);
- sColorNameMap.put("limegreen", 0xFF32CD32);
- sColorNameMap.put("linen", 0xFFFAF0E6);
- sColorNameMap.put("magenta", 0xFFFF00FF);
- sColorNameMap.put("maroon", 0xFF800000);
- sColorNameMap.put("mediumaquamarine", 0xFF66CDAA);
- sColorNameMap.put("mediumblue", 0xFFCD);
- sColorNameMap.put("mediumorchid", 0xFFBA55D3);
- sColorNameMap.put("mediumpurple", 0xFF9370DB);
- sColorNameMap.put("mediumseagreen", 0xFF3CB371);
- sColorNameMap.put("mediumslateblue", 0xFF7B68EE);
- sColorNameMap.put("mediumspringgreen", 0xFFFA9A);
- sColorNameMap.put("mediumturquoise", 0xFF48D1CC);
- sColorNameMap.put("mediumvioletred", 0xFFC71585);
- sColorNameMap.put("midnightblue", 0xFF191970);
- sColorNameMap.put("mintcream", 0xFFF5FFFA);
- sColorNameMap.put("mistyrose", 0xFFFFE4E1);
- sColorNameMap.put("moccasin", 0xFFFFE4B5);
- sColorNameMap.put("navajowhite", 0xFFFFDEAD);
- sColorNameMap.put("navy", 0xFF80);
- sColorNameMap.put("oldlace", 0xFFFDF5E6);
- sColorNameMap.put("olive", 0xFF808000);
- sColorNameMap.put("olivedrab", 0xFF6B8E23);
- sColorNameMap.put("orange", 0xFFFFA500);
- sColorNameMap.put("orangered", 0xFFFF4500);
- sColorNameMap.put("orchid", 0xFFDA70D6);
- sColorNameMap.put("palegoldenrod", 0xFFEEE8AA);
- sColorNameMap.put("palegreen", 0xFF98FB98);
- sColorNameMap.put("paleturquoise", 0xFFAFEEEE);
- sColorNameMap.put("palevioletred", 0xFFDB7093);
- sColorNameMap.put("papayawhip", 0xFFFFEFD5);
- sColorNameMap.put("peachpuff", 0xFFFFDAB9);
- sColorNameMap.put("peru", 0xFFCD853F);
- sColorNameMap.put("pink", 0xFFFFC0CB);
- sColorNameMap.put("plum", 0xFFDDA0DD);
- sColorNameMap.put("powderblue", 0xFFB0E0E6);
- sColorNameMap.put("purple", 0xFF800080);
- sColorNameMap.put("red", 0xFFFF0000);
- sColorNameMap.put("rosybrown", 0xFFBC8F8F);
- sColorNameMap.put("royalblue", 0xFF4169E1);
- sColorNameMap.put("saddlebrown", 0xFF8B4513);
- sColorNameMap.put("salmon", 0xFFFA8072);
- sColorNameMap.put("sandybrown", 0xFFF4A460);
- sColorNameMap.put("seagreen", 0xFF2E8B57);
- sColorNameMap.put("seashell", 0xFFFFF5EE);
- sColorNameMap.put("sienna", 0xFFA0522D);
- sColorNameMap.put("silver", 0xFFC0C0C0);
- sColorNameMap.put("skyblue", 0xFF87CEEB);
- sColorNameMap.put("slateblue", 0xFF6A5ACD);
- sColorNameMap.put("slategray", 0xFF708090);
- sColorNameMap.put("snow", 0xFFFFFAFA);
- sColorNameMap.put("springgreen", 0xFFFF7F);
- sColorNameMap.put("steelblue", 0xFF4682B4);
- sColorNameMap.put("tan", 0xFFD2B48C);
- sColorNameMap.put("teal", 0xFF8080);
- sColorNameMap.put("thistle", 0xFFD8BFD8);
- sColorNameMap.put("tomato", 0xFFFF6347);
- sColorNameMap.put("turquoise", 0xFF40E0D0);
- sColorNameMap.put("violet", 0xFFEE82EE);
- sColorNameMap.put("wheat", 0xFFF5DEB3);
- sColorNameMap.put("white", 0xFFFFFFFF);
- sColorNameMap.put("whitesmoke", 0xFFF5F5F5);
- sColorNameMap.put("yellow", 0xFFFFFF00);
- sColorNameMap.put("yellowgreen", 0xFF9ACD32);
- }
-
- private final String mSource;
- private final XMLReader mReader;
- private final SpannableStringBuilder mSpannableStringBuilder;
- private final Html.ImageGetter mImageGetter;
- private final Html.TagHandler mTagHandler;
-
- public HtmlToSpannedConverter(
- String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler,
- Parser parser) {
- mSource = source;
- mSpannableStringBuilder = new SpannableStringBuilder();
- mImageGetter = imageGetter;
- mTagHandler = tagHandler;
- mReader = parser;
- }
-
- private static void handleP(SpannableStringBuilder text) {
- int len = text.length();
-
- if (len >= 1 && text.charAt(len - 1) == '\n') {
- if (len >= 2 && text.charAt(len - 2) == '\n') {
- return;
- }
-
- text.append("\n");
- return;
- }
-
- if (len != 0) {
- text.append("\n\n");
- }
- }
-
- private static void handleBr(SpannableStringBuilder text) {
- text.append("\n");
- }
-
- private static Object getLast(Spanned text, Class kind) {
- /*
- * This knows that the last returned object from getSpans()
- * will be the most recently added.
- */
- Object[] objs = text.getSpans(0, text.length(), kind);
-
- if (objs.length == 0) {
- return null;
- } else {
- return objs[objs.length - 1];
- }
- }
-
- private static void start(SpannableStringBuilder text, Object mark) {
- int len = text.length();
- text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
- }
-
- private static void end(SpannableStringBuilder text, Class kind,
- Object repl) {
- int len = text.length();
- Object obj = getLast(text, kind);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- if (where != len) {
- text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
-
- private static void startImg(SpannableStringBuilder text,
- Attributes attributes, Html.ImageGetter img) {
- String src = attributes.getValue("", "src");
- Drawable d = null;
-
- if (img != null) {
- d = img.getDrawable(src);
- }
-
- if (d == null) {
- d = Resources.getSystem().getDrawable(android.R.drawable.ic_menu_report_image);
- d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
- }
-
- int len = text.length();
- text.append("\uFFFC");
-
- text.setSpan(new ImageSpan(d, src), len, text.length(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
-
- private static void startFont(SpannableStringBuilder 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(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Font.class);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- if (where != len) {
- Font f = (Font) obj;
-
- 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");
- text.setSpan(new TextAppearanceSpan(null, 0, 0, ColorStateList.valueOf(res.getColor(colorRes)), null),
- where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- } else {
- try {
- int c = getHtmlColor(f.mColor);
- text.setSpan(new ForegroundColorSpan(c | 0xFF000000),
- where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- } catch (IllegalArgumentException e) {
- // Ignore
- }
- }
- }
-
- if (f.mFace != null) {
- text.setSpan(new TypefaceSpan(f.mFace), where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- }
-
- private static void startA(SpannableStringBuilder text, Attributes attributes) {
- String href = attributes.getValue("", "href");
-
- int len = text.length();
- text.setSpan(new Href(href), len, len, Spannable.SPAN_MARK_MARK);
- }
-
- private static void endA(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Href.class);
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- if (where != len) {
- Href h = (Href) obj;
-
- if (h.mHref != null) {
- text.setSpan(new URLSpan(h.mHref), where, len,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- }
-
- private static void endHeader(SpannableStringBuilder text) {
- int len = text.length();
- Object obj = getLast(text, Header.class);
-
- int where = text.getSpanStart(obj);
-
- text.removeSpan(obj);
-
- // Back off not to change only the text, not the blank line.
- while (len > where && text.charAt(len - 1) == '\n') {
- len--;
- }
-
- if (where != len) {
- Header h = (Header) obj;
-
- text.setSpan(new RelativeSizeSpan(HEADER_SIZES[h.mLevel]),
- where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- text.setSpan(new StyleSpan(Typeface.BOLD),
- where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
-
- /**
- * Parse the color string, and return the corresponding color-int.
- * If the string cannot be parsed, throws an IllegalArgumentException
- * exception. Supported formats are:
- * #RRGGBB
- * #AARRGGBB
- * rgb(255, 255, 255)
- * or color name
- */
- @ColorInt
- public static int getHtmlColor(@NonNull String colorString) {
- if ((colorString.length() == 7 || colorString.length() == 9) && colorString.charAt(0) == '#') {
- // Use a long to avoid rollovers on #ffXXXXXX
- long color;
- try {
- color = Long.parseLong(colorString.substring(1), 16);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("Unknown color: " + colorString);
- }
- if (colorString.length() == 7) {
- // Set the alpha value
- color |= 0x00000000ff000000;
- }
- return (int) color;
- } else if (colorString.startsWith("rgb(") && colorString.endsWith(")")) {
- String str = colorString.substring(4, colorString.length() - 1);
- String[] colors = str.split("[\\s]*,[\\s]*");
- if (colors.length == 3) {
- try {
- return Color.argb(0xff, Integer.valueOf(colors[0]), Integer.valueOf(colors[1]), Integer.valueOf(colors[2]));
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("Unknown color: " + colorString);
- }
- }
- } else {
- Integer color = sColorNameMap.get(colorString.toLowerCase(Locale.ROOT));
- if (color != null) {
- return color;
- }
- }
- throw new IllegalArgumentException("Unknown color: " + colorString);
- }
-
- public SpannableStringBuilder convert() {
-
- mReader.setContentHandler(this);
- try {
- mReader.parse(new InputSource(new StringReader(mSource)));
- } catch (IOException e) {
- // We are reading from a string. There should not be IO problems.
- throw new RuntimeException(e);
- } catch (SAXException e) {
- // TagSoup doesn't throw parse exceptions.
- throw new RuntimeException(e);
- }
-
- // Fix flags and range for paragraph-type markup.
- Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class);
- for (int i = 0; i < obj.length; i++) {
- int start = mSpannableStringBuilder.getSpanStart(obj[i]);
- int end = mSpannableStringBuilder.getSpanEnd(obj[i]);
-
- // If the last line of the range is blank, back off by one.
- if (end - 2 >= 0) {
- if (mSpannableStringBuilder.charAt(end - 1) == '\n' &&
- mSpannableStringBuilder.charAt(end - 2) == '\n') {
- end--;
- }
- }
-
- if (end == start) {
- mSpannableStringBuilder.removeSpan(obj[i]);
- } else {
- mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH);
- }
- }
-
- return mSpannableStringBuilder;
- }
-
- private void handleStartTag(String tag, Attributes attributes) {
- if (tag.equalsIgnoreCase("br")) {
- // We don't need to handle this. TagSoup will ensure that there's a for each
- // so we can safely emite the linebreaks when we handle the close tag.
- } else if (tag.equalsIgnoreCase("p")) {
- handleP(mSpannableStringBuilder);
- } else if (tag.equalsIgnoreCase("div")) {
- handleP(mSpannableStringBuilder);
- } else if (tag.equalsIgnoreCase("strong")) {
- start(mSpannableStringBuilder, new Bold());
- } else if (tag.equalsIgnoreCase("b")) {
- start(mSpannableStringBuilder, new Bold());
- } else if (tag.equalsIgnoreCase("em")) {
- start(mSpannableStringBuilder, new Italic());
- } else if (tag.equalsIgnoreCase("cite")) {
- start(mSpannableStringBuilder, new Italic());
- } else if (tag.equalsIgnoreCase("dfn")) {
- start(mSpannableStringBuilder, new Italic());
- } else if (tag.equalsIgnoreCase("i")) {
- start(mSpannableStringBuilder, new Italic());
- } else if (tag.equalsIgnoreCase("big")) {
- start(mSpannableStringBuilder, new Big());
- } else if (tag.equalsIgnoreCase("small")) {
- start(mSpannableStringBuilder, new Small());
- } else if (tag.equalsIgnoreCase("font")) {
- startFont(mSpannableStringBuilder, attributes);
- } else if (tag.equalsIgnoreCase("blockquote")) {
- handleP(mSpannableStringBuilder);
- start(mSpannableStringBuilder, new Blockquote());
- } else if (tag.equalsIgnoreCase("tt")) {
- start(mSpannableStringBuilder, new Monospace());
- } else if (tag.equalsIgnoreCase("a")) {
- startA(mSpannableStringBuilder, attributes);
- } else if (tag.equalsIgnoreCase("u")) {
- start(mSpannableStringBuilder, new Underline());
- } else if (tag.equalsIgnoreCase("ins")) {
- start(mSpannableStringBuilder, new Underline());
- } else if (tag.equalsIgnoreCase("strike")) {
- start(mSpannableStringBuilder, new Strike());
- } else if (tag.equalsIgnoreCase("s")) {
- start(mSpannableStringBuilder, new Strike());
- } else if (tag.equalsIgnoreCase("del")) {
- start(mSpannableStringBuilder, new Strike());
- } else if (tag.equalsIgnoreCase("sup")) {
- start(mSpannableStringBuilder, new Super());
- } else if (tag.equalsIgnoreCase("sub")) {
- start(mSpannableStringBuilder, new Sub());
- } else if (tag.length() == 2 &&
- Character.toLowerCase(tag.charAt(0)) == 'h' &&
- tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
- handleP(mSpannableStringBuilder);
- start(mSpannableStringBuilder, new Header(tag.charAt(1) - '1'));
- } else if (tag.equalsIgnoreCase("img")) {
- startImg(mSpannableStringBuilder, attributes, mImageGetter);
- } else if (mTagHandler != null) {
- mTagHandler.handleTag(true, tag, mSpannableStringBuilder, mReader);
- }
- }
-
- private void handleEndTag(String tag) {
- if (tag.equalsIgnoreCase("br")) {
- handleBr(mSpannableStringBuilder);
- } else if (tag.equalsIgnoreCase("p")) {
- handleP(mSpannableStringBuilder);
- } else if (tag.equalsIgnoreCase("div")) {
- handleP(mSpannableStringBuilder);
- } else if (tag.equalsIgnoreCase("strong")) {
- end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD));
- } else if (tag.equalsIgnoreCase("b")) {
- end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD));
- } else if (tag.equalsIgnoreCase("em")) {
- end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
- } else if (tag.equalsIgnoreCase("cite")) {
- end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
- } else if (tag.equalsIgnoreCase("dfn")) {
- end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
- } else if (tag.equalsIgnoreCase("i")) {
- end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
- } else if (tag.equalsIgnoreCase("big")) {
- end(mSpannableStringBuilder, Big.class, new RelativeSizeSpan(1.25f));
- } else if (tag.equalsIgnoreCase("small")) {
- end(mSpannableStringBuilder, Small.class, new RelativeSizeSpan(0.8f));
- } else if (tag.equalsIgnoreCase("font")) {
- endFont(mSpannableStringBuilder);
- } else if (tag.equalsIgnoreCase("blockquote")) {
- handleP(mSpannableStringBuilder);
- end(mSpannableStringBuilder, Blockquote.class, new QuoteSpan());
- } else if (tag.equalsIgnoreCase("tt")) {
- end(mSpannableStringBuilder, Monospace.class,
- new TypefaceSpan("monospace"));
- } else if (tag.equalsIgnoreCase("a")) {
- endA(mSpannableStringBuilder);
- } else if (tag.equalsIgnoreCase("u")) {
- end(mSpannableStringBuilder, Underline.class, new UnderlineSpan());
- } else if (tag.equalsIgnoreCase("ins")) {
- end(mSpannableStringBuilder, Underline.class, new UnderlineSpan());
- } else if (tag.equalsIgnoreCase("strike")) {
- end(mSpannableStringBuilder, Strike.class, new StrikethroughSpan());
- } else if (tag.equalsIgnoreCase("s")) {
- end(mSpannableStringBuilder, Strike.class, new StrikethroughSpan());
- } else if (tag.equalsIgnoreCase("del")) {
- end(mSpannableStringBuilder, Strike.class, new StrikethroughSpan());
- } else if (tag.equalsIgnoreCase("sup")) {
- end(mSpannableStringBuilder, Super.class, new SuperscriptSpan());
- } else if (tag.equalsIgnoreCase("sub")) {
- end(mSpannableStringBuilder, Sub.class, new SubscriptSpan());
- } else if (tag.length() == 2 &&
- Character.toLowerCase(tag.charAt(0)) == 'h' &&
- tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
- handleP(mSpannableStringBuilder);
- endHeader(mSpannableStringBuilder);
- } else if (mTagHandler != null) {
- mTagHandler.handleTag(false, tag, mSpannableStringBuilder, mReader);
- }
- }
-
- @Override
- public void setDocumentLocator(Locator locator) {
- }
-
- @Override
- public void startDocument() throws SAXException {
- }
-
- @Override
- public void endDocument() throws SAXException {
- }
-
- @Override
- public void startPrefixMapping(String prefix, String uri) throws SAXException {
- }
-
- @Override
- public void endPrefixMapping(String prefix) throws SAXException {
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
- handleStartTag(localName, attributes);
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- handleEndTag(localName);
- }
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- StringBuilder sb = new StringBuilder();
-
- /*
- * Ignore whitespace that immediately follows other whitespace;
- * newlines count as spaces.
- */
-
- for (int i = 0; i < length; i++) {
- char c = ch[i + start];
-
- if (c == ' ' || c == '\n') {
- char pred;
- int len = sb.length();
-
- if (len == 0) {
- len = mSpannableStringBuilder.length();
-
- if (len == 0) {
- pred = '\n';
- } else {
- pred = mSpannableStringBuilder.charAt(len - 1);
- }
- } else {
- pred = sb.charAt(len - 1);
- }
-
- if (pred != ' ' && pred != '\n') {
- sb.append(' ');
- }
- } else {
- sb.append(c);
- }
- }
-
- mSpannableStringBuilder.append(sb);
- }
-
- @Override
- public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
- }
-
- @Override
- public void processingInstruction(String target, String data) throws SAXException {
- }
-
- @Override
- public void skippedEntity(String name) throws SAXException {
- }
-
- private static class Bold {
- }
-
- private static class Italic {
- }
-
- private static class Underline {
- }
-
- private static class Strike {
- }
-
- private static class Big {
- }
-
- private static class Small {
- }
-
- private static class Monospace {
- }
-
- private static class Blockquote {
- }
-
- private static class Super {
- }
-
- private static class Sub {
- }
-
- private static class Font {
- public String mColor;
- public String mFace;
-
- public Font(String color, String face) {
- mColor = color;
- mFace = face;
- }
- }
-
- private static class Href {
- public String mHref;
-
- public Href(String href) {
- mHref = href;
- }
- }
-
- private static class Header {
- private final int mLevel;
-
- public Header(int level) {
- mLevel = level;
- }
- }
-}
diff --git a/app/src/main/java/com/hippo/text/URLImageGetter.java b/app/src/main/java/com/hippo/text/URLImageGetter.java
index 9c0541292..3fccd72ce 100644
--- a/app/src/main/java/com/hippo/text/URLImageGetter.java
+++ b/app/src/main/java/com/hippo/text/URLImageGetter.java
@@ -17,6 +17,7 @@
package com.hippo.text;
import android.graphics.drawable.Drawable;
+import android.text.Html;
import com.hippo.conaco.Conaco;
import com.hippo.drawable.UnikeryDrawable;