Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Unified Diff: ui/android/java/src/org/chromium/ui/text/SpanApplier.java

Issue 736163002: Upstream SpanApplier.java and SpanApplierTest.java (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: minor tweaks to SpanApplier upstream Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/android/BUILD.gn ('k') | ui/android/javatests/src/org/chromium/ui/text/SpanApplierTest.java » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
+ }
+}
+
« no previous file with comments | « ui/android/BUILD.gn ('k') | ui/android/javatests/src/org/chromium/ui/text/SpanApplierTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698