package eu.faircode.email; /* * 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. */ import android.content.Context; import android.graphics.Typeface; import android.text.Layout; import android.text.Spanned; import android.text.TextDirectionHeuristics; import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; import android.text.style.BackgroundColorSpan; import android.text.style.BulletSpan; 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.TypefaceSpan; import android.text.style.URLSpan; import android.text.style.UnderlineSpan; import static android.text.Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE; public class HtmlEx { private Context context; private static final int TO_HTML_PARAGRAPH_FLAG = 0x00000001; public HtmlEx(Context context){ this.context = context; } /** * @deprecated use {@link #toHtml(Spanned, int)} instead. */ @Deprecated public /* static */ String toHtml(Spanned text) { return toHtml(text, TO_HTML_PARAGRAPH_LINES_CONSECUTIVE); } /** * 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 * @param option one of {@link #TO_HTML_PARAGRAPH_LINES_CONSECUTIVE} or * {@link #TO_HTML_PARAGRAPH_LINES_INDIVIDUAL} * @return string containing input converted to HTML */ public /* static */ String toHtml(Spanned text, int option) { StringBuilder out = new StringBuilder(); withinHtml(out, text, option); 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 option) { if ((option & TO_HTML_PARAGRAPH_FLAG) == TO_HTML_PARAGRAPH_LINES_CONSECUTIVE) { encodeTextAlignmentByDiv(out, text, option); return; } withinDiv(out, text, 0, text.length(), option); } private /* static */ void encodeTextAlignmentByDiv(StringBuilder out, Spanned text, int option) { int len = text.length(); int next; for (int i = 0; i < len; 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("
"); } withinBlockquote(out, text, i, next, option); for (QuoteSpan quote : quotes) { out.append("\n"); } } } private /* static */ String getTextDirection(Spanned text, int start, int end) { if (TextDirectionHeuristics.FIRSTSTRONG_LTR.isRtl(text, start, end - start)) { return " dir=\"rtl\""; } else { return " dir=\"ltr\""; } } private /* static */ String getTextStyles(Spanned text, int start, int end, boolean forceNoVerticalMargin, boolean includeTextAlign) { String margin = null; String textAlign = null; if (forceNoVerticalMargin) { margin = "margin-top:0; margin-bottom:0;"; } if (includeTextAlign) { final AlignmentSpan[] alignmentSpans = text.getSpans(start, end, AlignmentSpan.class); // Only use the last AlignmentSpan with flag SPAN_PARAGRAPH for (int i = alignmentSpans.length - 1; i >= 0; i--) { AlignmentSpan s = alignmentSpans[i]; if ((text.getSpanFlags(s) & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH) { final Layout.Alignment alignment = s.getAlignment(); if (alignment == Layout.Alignment.ALIGN_NORMAL) { textAlign = "text-align:start;"; } else if (alignment == Layout.Alignment.ALIGN_CENTER) { textAlign = "text-align:center;"; } else if (alignment == Layout.Alignment.ALIGN_OPPOSITE) { textAlign = "text-align:end;"; } break; } } } if (margin == null && textAlign == null) { return ""; } final StringBuilder style = new StringBuilder(" style=\""); if (margin != null && textAlign != null) { style.append(margin).append(" ").append(textAlign); } else if (margin != null) { style.append(margin); } else if (textAlign != null) { style.append(textAlign); } return style.append("\"").toString(); } private /* static */ void withinBlockquote(StringBuilder out, Spanned text, int start, int end, int option) { if ((option & TO_HTML_PARAGRAPH_FLAG) == TO_HTML_PARAGRAPH_LINES_CONSECUTIVE) { withinBlockquoteConsecutive(out, text, start, end); } else { withinBlockquoteIndividual(out, text, start, end); } } private /* static */ void withinBlockquoteIndividual(StringBuilder out, Spanned text, int start, int end) { Boolean isInBulletList = null; int next; for (int i = start; i <= end; i = next) { next = TextUtils.indexOf(text, '\n', i, end); if (next < 0) { next = end; } if (next == i) { if (isInBulletList != null) { // Current paragraph is no longer a list item; close the previously opened list out.append(isInBulletList ? "\n" : "\n"); isInBulletList = null; } if (i != text.length()) out.append("