summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.cc122
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.h9
-rw-r--r--chrome/browser/extensions/extension_omnibox_unittest.cc144
3 files changed, 234 insertions, 41 deletions
diff --git a/chrome/browser/extensions/extension_omnibox_api.cc b/chrome/browser/extensions/extension_omnibox_api.cc
index 93b44bd..705771f 100644
--- a/chrome/browser/extensions/extension_omnibox_api.cc
+++ b/chrome/browser/extensions/extension_omnibox_api.cc
@@ -30,6 +30,7 @@ const char kSuggestionDescription[] = "description";
const char kSuggestionDescriptionStyles[] = "descriptionStyles";
const char kDescriptionStylesType[] = "type";
const char kDescriptionStylesOffset[] = "offset";
+const char kDescriptionStylesLength[] = "length";
}; // namespace
// static
@@ -103,47 +104,10 @@ bool OmniboxSendSuggestionsFunction::RunImpl() {
ListValue* styles;
EXTENSION_FUNCTION_VALIDATE(
suggestion_value->GetList(kSuggestionDescriptionStyles, &styles));
-
+ EXTENSION_FUNCTION_VALIDATE(suggestion.ReadStylesFromValue(*styles));
+ } else {
suggestion.description_styles.clear();
-
- int last_offset = -1;
- for (size_t j = 0; j < styles->GetSize(); ++j) {
- DictionaryValue* style;
- std::string type;
- int offset;
- EXTENSION_FUNCTION_VALIDATE(styles->GetDictionary(j, &style));
- EXTENSION_FUNCTION_VALIDATE(
- style->GetString(kDescriptionStylesType, &type));
- EXTENSION_FUNCTION_VALIDATE(
- style->GetInteger(kDescriptionStylesOffset, &offset));
-
- int type_class =
- (type == "none") ? ACMatchClassification::NONE :
- (type == "url") ? ACMatchClassification::URL :
- (type == "match") ? ACMatchClassification::MATCH :
- (type == "dim") ? ACMatchClassification::DIM : -1;
- EXTENSION_FUNCTION_VALIDATE(type_class != -1);
-
- if (offset <= last_offset) {
- error_ = kDescriptionStylesOrderError;
- return false;
- }
- if (static_cast<size_t>(offset) >= suggestion.description.length()) {
- error_ = kDescriptionStylesLengthError;
- return false;
- }
-
- suggestion.description_styles.push_back(
- ACMatchClassification(offset, type_class));
- last_offset = offset;
- }
- }
-
- // Ensure the styles cover the whole range of text.
- if (suggestion.description_styles.empty() ||
- suggestion.description_styles[0].offset != 0) {
- suggestion.description_styles.insert(
- suggestion.description_styles.begin(),
+ suggestion.description_styles.push_back(
ACMatchClassification(0, ACMatchClassification::NONE));
}
}
@@ -160,7 +124,83 @@ ExtensionOmniboxSuggestion::ExtensionOmniboxSuggestion() {}
ExtensionOmniboxSuggestion::~ExtensionOmniboxSuggestion() {}
+bool ExtensionOmniboxSuggestion::ReadStylesFromValue(
+ const ListValue& styles_value) {
+ // Start with a NONE style covering the entire range. As we iterate over the
+ // styles, bisect or overwrite the running style list with each new style.
+ description_styles.clear();
+ description_styles.push_back(
+ ACMatchClassification(0, ACMatchClassification::NONE));
+
+ for (size_t i = 0; i < styles_value.GetSize(); ++i) {
+ DictionaryValue* style;
+ std::string type;
+ int offset;
+ int length;
+ if (!styles_value.GetDictionary(i, &style))
+ return false;
+ if (!style->GetString(kDescriptionStylesType, &type))
+ return false;
+ if (!style->GetInteger(kDescriptionStylesOffset, &offset))
+ return false;
+ if (!style->GetInteger(kDescriptionStylesLength, &length))
+ return false;
+
+ int type_class =
+ (type == "url") ? ACMatchClassification::URL :
+ (type == "match") ? ACMatchClassification::MATCH :
+ (type == "dim") ? ACMatchClassification::DIM : -1;
+ if (type_class == -1)
+ return false;
+
+ InsertNewStyle(type_class, offset, length);
+ }
+
+ return true;
+}
+
+void ExtensionOmniboxSuggestion::InsertNewStyle(int type,
+ size_t offset,
+ size_t length) {
+ // Find the first and last existing styles that this new style overlaps. Those
+ // will have to be removed (if they completely overlap), or bisected.
+ size_t start = 0, end = 0;
+ while (end < description_styles.size()) {
+ if (start < description_styles.size() &&
+ description_styles[start].offset < offset)
+ ++start;
+ if (description_styles[end].offset <= offset + length) {
+ ++end;
+ } else {
+ break;
+ }
+ }
+
+ DCHECK_GT(end, 0u);
+ DCHECK(start == description_styles.size() ||
+ description_styles[start].offset >= offset);
+ DCHECK(end == description_styles.size() ||
+ description_styles[end].offset > offset + length);
+
+ // The last style in the overlapping range will come after our new style.
+ int last_style = description_styles[end - 1].style;
+
+ // Remove all overlapping styles.
+ if (start < end) {
+ description_styles.erase(description_styles.begin() + start,
+ description_styles.begin() + end);
+ }
+
+ // Insert our new style.
+ description_styles.insert(description_styles.begin() + start,
+ ACMatchClassification(offset, type));
+ if (offset + length < description.length()) {
+ description_styles.insert(description_styles.begin() + start + 1,
+ ACMatchClassification(offset + length,
+ last_style));
+ }
+}
+
ExtensionOmniboxSuggestions::ExtensionOmniboxSuggestions() : request_id(0) {}
ExtensionOmniboxSuggestions::~ExtensionOmniboxSuggestions() {}
-
diff --git a/chrome/browser/extensions/extension_omnibox_api.h b/chrome/browser/extensions/extension_omnibox_api.h
index 9d0dc99..98758cb 100644
--- a/chrome/browser/extensions/extension_omnibox_api.h
+++ b/chrome/browser/extensions/extension_omnibox_api.h
@@ -49,6 +49,10 @@ struct ExtensionOmniboxSuggestion {
ExtensionOmniboxSuggestion();
~ExtensionOmniboxSuggestion();
+ // Converts a list of style ranges from the extension into the format expected
+ // by the autocomplete system.
+ bool ReadStylesFromValue(const ListValue& value);
+
// The text that gets put in the edit box.
string16 content;
@@ -57,6 +61,11 @@ struct ExtensionOmniboxSuggestion {
// Contains style ranges for the description.
ACMatchClassifications description_styles;
+
+ private:
+ // Helper function to add the given style to the running list of
+ // |description_styles|.
+ void InsertNewStyle(int type, size_t offset, size_t length);
};
struct ExtensionOmniboxSuggestions {
diff --git a/chrome/browser/extensions/extension_omnibox_unittest.cc b/chrome/browser/extensions/extension_omnibox_unittest.cc
new file mode 100644
index 0000000..ca2d1e0
--- /dev/null
+++ b/chrome/browser/extensions/extension_omnibox_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2010 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.
+
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_omnibox_api.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+void AppendStyle(const std::string& type,
+ int offset, int length,
+ ListValue* styles) {
+ DictionaryValue* style = new DictionaryValue;
+ style->SetString("type", type);
+ style->SetInteger("offset", offset);
+ style->SetInteger("length", length);
+ styles->Append(style);
+}
+
+void CompareClassification(const ACMatchClassifications& expected,
+ const ACMatchClassifications& actual) {
+ EXPECT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < expected.size() && i < actual.size(); ++i) {
+ EXPECT_EQ(expected[i].offset, actual[i].offset) << "Index:" << i;
+ EXPECT_EQ(expected[i].style, actual[i].style) << "Index:" << i;
+ }
+}
+
+} // namespace
+
+// Test output key: n = character with no styling, d = dim, m = match, u = url
+
+// 0123456789
+// mmmm
+// + ddd
+// = nmmmmndddn
+TEST(ExtensionOmniboxTest, DescriptionStylesSimple) {
+ ListValue styles_value;
+ AppendStyle("match", 1, 4, &styles_value);
+ AppendStyle("dim", 6, 3, &styles_value);
+
+ ACMatchClassifications styles_expected;
+ styles_expected.push_back(
+ ACMatchClassification(0, ACMatchClassification::NONE));
+ styles_expected.push_back(
+ ACMatchClassification(1, ACMatchClassification::MATCH));
+ styles_expected.push_back(
+ ACMatchClassification(5, ACMatchClassification::NONE));
+ styles_expected.push_back(
+ ACMatchClassification(6, ACMatchClassification::DIM));
+ styles_expected.push_back(
+ ACMatchClassification(9, ACMatchClassification::NONE));
+
+ ExtensionOmniboxSuggestion suggestions;
+ suggestions.description.resize(10);
+ EXPECT_TRUE(suggestions.ReadStylesFromValue(styles_value));
+ CompareClassification(styles_expected, suggestions.description_styles);
+
+ // Same input, but swap the order. Ensure it still works.
+ styles_value.Clear();
+ AppendStyle("dim", 6, 3, &styles_value);
+ AppendStyle("match", 1, 4, &styles_value);
+ EXPECT_TRUE(suggestions.ReadStylesFromValue(styles_value));
+ CompareClassification(styles_expected, suggestions.description_styles);
+}
+
+// 0123456789
+// uuuuuu
+// + dd
+// + mm
+// + mmmm
+// + dd
+// = mddmunnnnm
+TEST(ExtensionOmniboxTest, DescriptionStylesOverlap) {
+ ListValue styles_value;
+ AppendStyle("url", 0, 5, &styles_value);
+ AppendStyle("dim", 9, 2, &styles_value);
+ AppendStyle("match", 9, 2, &styles_value);
+ AppendStyle("match", 0, 4, &styles_value);
+ AppendStyle("dim", 1, 2, &styles_value);
+
+ ACMatchClassifications styles_expected;
+ styles_expected.push_back(
+ ACMatchClassification(0, ACMatchClassification::MATCH));
+ styles_expected.push_back(
+ ACMatchClassification(1, ACMatchClassification::DIM));
+ styles_expected.push_back(
+ ACMatchClassification(3, ACMatchClassification::MATCH));
+ styles_expected.push_back(
+ ACMatchClassification(4, ACMatchClassification::URL));
+ styles_expected.push_back(
+ ACMatchClassification(5, ACMatchClassification::NONE));
+ styles_expected.push_back(
+ ACMatchClassification(9, ACMatchClassification::MATCH));
+
+ ExtensionOmniboxSuggestion suggestions;
+ suggestions.description.resize(10);
+ EXPECT_TRUE(suggestions.ReadStylesFromValue(styles_value));
+ CompareClassification(styles_expected, suggestions.description_styles);
+
+ // Try moving the "dim/match" style pair at offset 9. Output should be the
+ // same.
+ styles_value.Clear();
+ AppendStyle("url", 0, 5, &styles_value);
+ AppendStyle("match", 0, 4, &styles_value);
+ AppendStyle("dim", 9, 2, &styles_value);
+ AppendStyle("match", 9, 2, &styles_value);
+ AppendStyle("dim", 1, 2, &styles_value);
+ EXPECT_TRUE(suggestions.ReadStylesFromValue(styles_value));
+ CompareClassification(styles_expected, suggestions.description_styles);
+}
+
+// 0123456789
+// uuuuu
+// + mmmmm
+// + mmm
+// + ddd
+// + ddd
+// = dddddnnnnn
+TEST(ExtensionOmniboxTest, DescriptionStylesOverlap2) {
+ ListValue styles_value;
+ AppendStyle("url", 0, 5, &styles_value);
+ AppendStyle("match", 0, 5, &styles_value);
+ AppendStyle("match", 0, 3, &styles_value);
+ AppendStyle("dim", 2, 3, &styles_value);
+ AppendStyle("dim", 0, 3, &styles_value);
+
+ // We don't merge adjacent identical styles, but the autocomplete system
+ // doesn't mind.
+ ACMatchClassifications styles_expected;
+ styles_expected.push_back(
+ ACMatchClassification(0, ACMatchClassification::DIM));
+ styles_expected.push_back(
+ ACMatchClassification(3, ACMatchClassification::DIM));
+ styles_expected.push_back(
+ ACMatchClassification(5, ACMatchClassification::NONE));
+
+ ExtensionOmniboxSuggestion suggestions;
+ suggestions.description.resize(10);
+ EXPECT_TRUE(suggestions.ReadStylesFromValue(styles_value));
+ CompareClassification(styles_expected, suggestions.description_styles);
+}