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

Side by Side Diff: chrome/browser/ui/elide_url.cc

Issue 143463006: Remove net dependency from ui/gfx (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: exclude elide_url.cc and tests from the android build Created 6 years, 10 months 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/elide_url.h"
6
7 #include "base/strings/string_split.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "net/base/escape.h"
10 #include "net/base/net_util.h"
11 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
12 #include "ui/gfx/text_elider.h"
13 #include "ui/gfx/text_utils.h"
14
15 using base::UTF8ToUTF16;
16 using gfx::ElideText;
17 using gfx::GetStringWidthF;
18 using gfx::kEllipsisUTF16;
19 using gfx::kForwardSlash;
20
21 namespace {
22
23 // Build a path from the first |num_components| elements in |path_elements|.
24 // Prepends |path_prefix|, appends |filename|, inserts ellipsis if appropriate.
25 base::string16 BuildPathFromComponents(
26 const base::string16& path_prefix,
27 const std::vector<base::string16>& path_elements,
28 const base::string16& filename,
29 size_t num_components) {
30 // Add the initial elements of the path.
31 base::string16 path = path_prefix;
32
33 // Build path from first |num_components| elements.
34 for (size_t j = 0; j < num_components; ++j)
35 path += path_elements[j] + kForwardSlash;
36
37 // Add |filename|, ellipsis if necessary.
38 if (num_components != (path_elements.size() - 1))
39 path += base::string16(kEllipsisUTF16) + kForwardSlash;
40 path += filename;
41
42 return path;
43 }
44
45 // Takes a prefix (Domain, or Domain+subdomain) and a collection of path
46 // components and elides if possible. Returns a string containing the longest
47 // possible elided path, or an empty string if elision is not possible.
48 base::string16 ElideComponentizedPath(
49 const base::string16& url_path_prefix,
50 const std::vector<base::string16>& url_path_elements,
51 const base::string16& url_filename,
52 const base::string16& url_query,
53 const gfx::FontList& font_list,
54 float available_pixel_width) {
55 const size_t url_path_number_of_elements = url_path_elements.size();
56
57 CHECK(url_path_number_of_elements);
58 for (size_t i = url_path_number_of_elements - 1; i > 0; --i) {
59 base::string16 elided_path = BuildPathFromComponents(url_path_prefix,
60 url_path_elements, url_filename, i);
61 if (available_pixel_width >= GetStringWidthF(elided_path, font_list))
62 return ElideText(elided_path + url_query, font_list,
63 available_pixel_width, gfx::ELIDE_AT_END);
64 }
65
66 return base::string16();
67 }
68
69 } // namespace
70
71 // TODO(pkasting): http://crbug.com/77883 This whole function gets
72 // kerning/ligatures/etc. issues potentially wrong by assuming that the width of
73 // a rendered string is always the sum of the widths of its substrings. Also I
74 // suspect it could be made simpler.
75 base::string16 ElideUrl(const GURL& url,
76 const gfx::FontList& font_list,
77 float available_pixel_width,
78 const std::string& languages) {
79 // Get a formatted string and corresponding parsing of the url.
80 url_parse::Parsed parsed;
81 const base::string16 url_string =
82 net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
83 net::UnescapeRule::SPACES, &parsed, NULL, NULL);
84 if (available_pixel_width <= 0)
85 return url_string;
86
87 // If non-standard, return plain eliding.
88 if (!url.IsStandard())
89 return ElideText(url_string, font_list, available_pixel_width,
90 gfx::ELIDE_AT_END);
91
92 // Now start eliding url_string to fit within available pixel width.
93 // Fist pass - check to see whether entire url_string fits.
94 const float pixel_width_url_string = GetStringWidthF(url_string, font_list);
95 if (available_pixel_width >= pixel_width_url_string)
96 return url_string;
97
98 // Get the path substring, including query and reference.
99 const size_t path_start_index = parsed.path.begin;
100 const size_t path_len = parsed.path.len;
101 base::string16 url_path_query_etc = url_string.substr(path_start_index);
102 base::string16 url_path = url_string.substr(path_start_index, path_len);
103
104 // Return general elided text if url minus the query fits.
105 const base::string16 url_minus_query =
106 url_string.substr(0, path_start_index + path_len);
107 if (available_pixel_width >= GetStringWidthF(url_minus_query, font_list))
108 return ElideText(url_string, font_list, available_pixel_width,
109 gfx::ELIDE_AT_END);
110
111 // Get Host.
112 base::string16 url_host = UTF8ToUTF16(url.host());
113
114 // Get domain and registry information from the URL.
115 base::string16 url_domain = UTF8ToUTF16(
116 net::registry_controlled_domains::GetDomainAndRegistry(
117 url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES));
118 if (url_domain.empty())
119 url_domain = url_host;
120
121 // Add port if required.
122 if (!url.port().empty()) {
123 url_host += UTF8ToUTF16(":" + url.port());
124 url_domain += UTF8ToUTF16(":" + url.port());
125 }
126
127 // Get sub domain.
128 base::string16 url_subdomain;
129 const size_t domain_start_index = url_host.find(url_domain);
130 if (domain_start_index != base::string16::npos)
131 url_subdomain = url_host.substr(0, domain_start_index);
132 const base::string16 kWwwPrefix = UTF8ToUTF16("www.");
133 if ((url_subdomain == kWwwPrefix || url_subdomain.empty() ||
134 url.SchemeIsFile())) {
135 url_subdomain.clear();
136 }
137
138 // If this is a file type, the path is now defined as everything after ":".
139 // For example, "C:/aa/aa/bb", the path is "/aa/bb/cc". Interesting, the
140 // domain is now C: - this is a nice hack for eliding to work pleasantly.
141 if (url.SchemeIsFile()) {
142 // Split the path string using ":"
143 std::vector<base::string16> file_path_split;
144 base::SplitString(url_path, ':', &file_path_split);
145 if (file_path_split.size() > 1) { // File is of type "file:///C:/.."
146 url_host.clear();
147 url_domain.clear();
148 url_subdomain.clear();
149
150 const base::string16 kColon = UTF8ToUTF16(":");
151 url_host = url_domain = file_path_split.at(0).substr(1) + kColon;
152 url_path_query_etc = url_path = file_path_split.at(1);
153 }
154 }
155
156 // Second Pass - remove scheme - the rest fits.
157 const float pixel_width_url_host = GetStringWidthF(url_host, font_list);
158 const float pixel_width_url_path = GetStringWidthF(url_path_query_etc,
159 font_list);
160 if (available_pixel_width >=
161 pixel_width_url_host + pixel_width_url_path)
162 return url_host + url_path_query_etc;
163
164 // Third Pass: Subdomain, domain and entire path fits.
165 const float pixel_width_url_domain = GetStringWidthF(url_domain, font_list);
166 const float pixel_width_url_subdomain =
167 GetStringWidthF(url_subdomain, font_list);
168 if (available_pixel_width >=
169 pixel_width_url_subdomain + pixel_width_url_domain +
170 pixel_width_url_path)
171 return url_subdomain + url_domain + url_path_query_etc;
172
173 // Query element.
174 base::string16 url_query;
175 const float kPixelWidthDotsTrailer = GetStringWidthF(
176 base::string16(kEllipsisUTF16), font_list);
177 if (parsed.query.is_nonempty()) {
178 url_query = UTF8ToUTF16("?") + url_string.substr(parsed.query.begin);
179 if (available_pixel_width >=
180 (pixel_width_url_subdomain + pixel_width_url_domain +
181 pixel_width_url_path - GetStringWidthF(url_query, font_list))) {
182 return ElideText(url_subdomain + url_domain + url_path_query_etc,
183 font_list, available_pixel_width, gfx::ELIDE_AT_END);
184 }
185 }
186
187 // Parse url_path using '/'.
188 std::vector<base::string16> url_path_elements;
189 base::SplitString(url_path, kForwardSlash, &url_path_elements);
190
191 // Get filename - note that for a path ending with /
192 // such as www.google.com/intl/ads/, the file name is ads/.
193 size_t url_path_number_of_elements = url_path_elements.size();
194 DCHECK(url_path_number_of_elements != 0);
195 base::string16 url_filename;
196 if ((url_path_elements.at(url_path_number_of_elements - 1)).length() > 0) {
197 url_filename = *(url_path_elements.end() - 1);
198 } else if (url_path_number_of_elements > 1) { // Path ends with a '/'.
199 url_filename = url_path_elements.at(url_path_number_of_elements - 2) +
200 kForwardSlash;
201 url_path_number_of_elements--;
202 }
203 DCHECK(url_path_number_of_elements != 0);
204
205 const size_t kMaxNumberOfUrlPathElementsAllowed = 1024;
206 if (url_path_number_of_elements <= 1 ||
207 url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) {
208 // No path to elide, or too long of a path (could overflow in loop below)
209 // Just elide this as a text string.
210 return ElideText(url_subdomain + url_domain + url_path_query_etc, font_list,
211 available_pixel_width, gfx::ELIDE_AT_END);
212 }
213
214 // Start eliding the path and replacing elements by ".../".
215 const base::string16 kEllipsisAndSlash =
216 base::string16(kEllipsisUTF16) + kForwardSlash;
217 const float pixel_width_ellipsis_slash =
218 GetStringWidthF(kEllipsisAndSlash, font_list);
219
220 // Check with both subdomain and domain.
221 base::string16 elided_path =
222 ElideComponentizedPath(url_subdomain + url_domain, url_path_elements,
223 url_filename, url_query, font_list,
224 available_pixel_width);
225 if (!elided_path.empty())
226 return elided_path;
227
228 // Check with only domain.
229 // If a subdomain is present, add an ellipsis before domain.
230 // This is added only if the subdomain pixel width is larger than
231 // the pixel width of kEllipsis. Otherwise, subdomain remains,
232 // which means that this case has been resolved earlier.
233 base::string16 url_elided_domain = url_subdomain + url_domain;
234 if (pixel_width_url_subdomain > kPixelWidthDotsTrailer) {
235 if (!url_subdomain.empty())
236 url_elided_domain = kEllipsisAndSlash[0] + url_domain;
237 else
238 url_elided_domain = url_domain;
239
240 elided_path = ElideComponentizedPath(url_elided_domain, url_path_elements,
241 url_filename, url_query, font_list,
242 available_pixel_width);
243
244 if (!elided_path.empty())
245 return elided_path;
246 }
247
248 // Return elided domain/.../filename anyway.
249 base::string16 final_elided_url_string(url_elided_domain);
250 const float url_elided_domain_width = GetStringWidthF(url_elided_domain,
251 font_list);
252
253 // A hack to prevent trailing ".../...".
254 if ((available_pixel_width - url_elided_domain_width) >
255 pixel_width_ellipsis_slash + kPixelWidthDotsTrailer +
256 GetStringWidthF(base::ASCIIToUTF16("UV"), font_list)) {
257 final_elided_url_string += BuildPathFromComponents(base::string16(),
258 url_path_elements, url_filename, 1);
259 } else {
260 final_elided_url_string += url_path;
261 }
262
263 return ElideText(final_elided_url_string, font_list, available_pixel_width,
264 gfx::ELIDE_AT_END);
265 }
266
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698