| Index: ui/android/java/src/org/chromium/ui/text/SpanApplier.java
|
| diff --git a/ui/android/java/src/org/chromium/ui/text/SpanApplier.java b/ui/android/java/src/org/chromium/ui/text/SpanApplier.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1418bca99a631654e749b7de59e711f0a1875630
|
| --- /dev/null
|
| +++ b/ui/android/java/src/org/chromium/ui/text/SpanApplier.java
|
| @@ -0,0 +1,120 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.ui.text;
|
| +
|
| +import android.text.SpannableString;
|
| +
|
| +import java.util.Arrays;
|
| +
|
| +/**
|
| + * Applies spans to an HTML-looking string and returns the resulting SpannableString.
|
| + * Note: This does not support duplicate, nested or overlapping spans.
|
| + *
|
| + * Example:
|
| + *
|
| + * String input = "Click to view the <tos>terms of service</tos> or <pn>privacy notice</pn>";
|
| + * ClickableSpan tosSpan = ...;
|
| + * ClickableSpan privacySpan = ...;
|
| + * SpannableString output = SpanApplier.applySpans(input,
|
| + * new Span("<tos>", "</tos>", tosSpan), new Span("<pn>", "</pn>", privacySpan));
|
| + */
|
| +public class SpanApplier {
|
| +
|
| + /**
|
| + * Associates a span with the range of text between a start and an end tag.
|
| + */
|
| + public static final class SpanInfo implements Comparable<SpanInfo> {
|
| + final String mStartTag;
|
| + final String mEndTag;
|
| + final Object mSpan;
|
| + int mStartTagIndex;
|
| + int mEndTagIndex;
|
| +
|
| + /**
|
| + * @param startTag The start tag, e.g. "<tos>".
|
| + * @param endTag The end tag, e.g. "</tos>".
|
| + * @param span The span to apply to the text between the start and end tags.
|
| + */
|
| + public SpanInfo(String startTag, String endTag, Object span) {
|
| + mStartTag = startTag;
|
| + mEndTag = endTag;
|
| + mSpan = span;
|
| + }
|
| +
|
| + @Override
|
| + public int compareTo(SpanInfo other) {
|
| + return this.mStartTagIndex < other.mStartTagIndex ? -1
|
| + : (this.mStartTagIndex == other.mStartTagIndex ? 0 : 1);
|
| + }
|
| +
|
| + @Override
|
| + public boolean equals(Object other) {
|
| + if (!(other instanceof SpanInfo)) return false;
|
| +
|
| + return compareTo((SpanInfo) other) == 0;
|
| + }
|
| +
|
| + @Override
|
| + public int hashCode() {
|
| + return 0;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Applies spans to an HTML-looking string and returns the resulting SpannableString.
|
| + * If a span cannot be applied (e.g. because the start tag isn't in the input string), then
|
| + * a RuntimeException will be thrown.
|
| + *
|
| + * @param input The input string.
|
| + * @param spans The Spans which will be applied to the string.
|
| + * @return A SpannableString with the given spans applied.
|
| + */
|
| + public static SpannableString applySpans(String input, SpanInfo... spans) {
|
| + for (SpanInfo span : spans) {
|
| + span.mStartTagIndex = input.indexOf(span.mStartTag);
|
| + span.mEndTagIndex = input.indexOf(span.mEndTag,
|
| + span.mStartTagIndex + span.mStartTag.length());
|
| + }
|
| +
|
| + // Sort the spans from first to last.
|
| + Arrays.sort(spans);
|
| +
|
| + // Copy the input text to the output, but omit the start and end tags.
|
| + // Update startTagIndex and endTagIndex for each Span as we go.
|
| + int inputIndex = 0;
|
| + StringBuilder output = new StringBuilder(input.length());
|
| +
|
| + for (SpanInfo span : spans) {
|
| + // Fail if there is a span without a start or end tag or if there are nested
|
| + // or overlapping spans.
|
| + if (span.mStartTagIndex == -1 || span.mEndTagIndex == -1
|
| + || span.mStartTagIndex < inputIndex) {
|
| + span.mStartTagIndex = -1;
|
| + String error = String.format("Input string is missing tags %s%s: %s",
|
| + span.mStartTag, span.mEndTag, input);
|
| + throw new IllegalArgumentException(error);
|
| + }
|
| +
|
| + output.append(input, inputIndex, span.mStartTagIndex);
|
| + inputIndex = span.mStartTagIndex + span.mStartTag.length();
|
| + span.mStartTagIndex = output.length();
|
| +
|
| + output.append(input, inputIndex, span.mEndTagIndex);
|
| + inputIndex = span.mEndTagIndex + span.mEndTag.length();
|
| + span.mEndTagIndex = output.length();
|
| + }
|
| + output.append(input, inputIndex, input.length());
|
| +
|
| + SpannableString spannableString = new SpannableString(output);
|
| + for (SpanInfo span : spans) {
|
| + if (span.mStartTagIndex != -1) {
|
| + spannableString.setSpan(span.mSpan, span.mStartTagIndex, span.mEndTagIndex, 0);
|
| + }
|
| + }
|
| +
|
| + return spannableString;
|
| + }
|
| +}
|
| +
|
|
|