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

Side by Side Diff: chrome/browser/manifest/manifest_icon_selector_unittest.cc

Issue 2933743002: Move chrome/browser/manifest to content/browser. (Closed)
Patch Set: rebased Created 3 years, 6 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
« no previous file with comments | « chrome/browser/manifest/manifest_icon_selector.cc ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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/manifest/manifest_icon_selector.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/macros.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 using IconPurpose = content::Manifest::Icon::IconPurpose;
15
16 namespace {
17
18 const int kIdealIconSize = 144;
19 const int kMinimumIconSize = 0;
20
21 static content::Manifest::Icon CreateIcon(const std::string& url,
22 const std::string& type,
23 const std::vector<gfx::Size> sizes,
24 IconPurpose purpose) {
25 content::Manifest::Icon icon;
26 icon.src = GURL(url);
27 icon.type = base::UTF8ToUTF16(type);
28 icon.sizes = sizes;
29 icon.purpose.push_back(purpose);
30
31 return icon;
32 }
33
34 } // anonymous namespace
35
36 TEST(ManifestIconSelector, NoIcons) {
37 // No icons should return the empty URL.
38 std::vector<content::Manifest::Icon> icons;
39 GURL url = ManifestIconSelector::FindBestMatchingIcon(
40 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
41 EXPECT_TRUE(url.is_empty());
42 }
43
44 TEST(ManifestIconSelector, NoSizes) {
45 // Icon with no sizes are ignored.
46 std::vector<content::Manifest::Icon> icons;
47 icons.push_back(CreateIcon("http://foo.com/icon.png", "",
48 std::vector<gfx::Size>(), IconPurpose::ANY));
49
50 GURL url = ManifestIconSelector::FindBestMatchingIcon(
51 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
52 EXPECT_TRUE(url.is_empty());
53 }
54
55 TEST(ManifestIconSelector, MIMETypeFiltering) {
56 // Icons with type specified to a MIME type that isn't a valid image MIME type
57 // are ignored.
58 std::vector<gfx::Size> sizes;
59 sizes.push_back(gfx::Size(1024, 1024));
60
61 std::vector<content::Manifest::Icon> icons;
62 icons.push_back(CreateIcon("http://foo.com/icon.png", "image/foo_bar", sizes,
63 IconPurpose::ANY));
64 icons.push_back(
65 CreateIcon("http://foo.com/icon.png", "image/", sizes, IconPurpose::ANY));
66 icons.push_back(
67 CreateIcon("http://foo.com/icon.png", "image/", sizes, IconPurpose::ANY));
68 icons.push_back(CreateIcon("http://foo.com/icon.png", "video/mp4", sizes,
69 IconPurpose::ANY));
70
71 GURL url = ManifestIconSelector::FindBestMatchingIcon(
72 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
73 EXPECT_TRUE(url.is_empty());
74
75 icons.clear();
76 icons.push_back(CreateIcon("http://foo.com/icon.png", "image/png", sizes,
77 IconPurpose::ANY));
78 url = ManifestIconSelector::FindBestMatchingIcon(
79 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
80 EXPECT_EQ("http://foo.com/icon.png", url.spec());
81
82 icons.clear();
83 icons.push_back(CreateIcon("http://foo.com/icon.png", "image/gif", sizes,
84 IconPurpose::ANY));
85 url = ManifestIconSelector::FindBestMatchingIcon(
86 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
87 EXPECT_EQ("http://foo.com/icon.png", url.spec());
88
89 icons.clear();
90 icons.push_back(CreateIcon("http://foo.com/icon.png", "image/jpeg", sizes,
91 IconPurpose::ANY));
92 url = ManifestIconSelector::FindBestMatchingIcon(
93 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
94 EXPECT_EQ("http://foo.com/icon.png", url.spec());
95 }
96
97 TEST(ManifestIconSelector, PurposeFiltering) {
98 // Icons with purpose specified to non-matching purpose are ignored.
99 std::vector<gfx::Size> sizes_48;
100 sizes_48.push_back(gfx::Size(48, 48));
101
102 std::vector<gfx::Size> sizes_96;
103 sizes_96.push_back(gfx::Size(96, 96));
104
105 std::vector<gfx::Size> sizes_144;
106 sizes_144.push_back(gfx::Size(144, 144));
107
108 std::vector<content::Manifest::Icon> icons;
109 icons.push_back(
110 CreateIcon("http://foo.com/icon_48.png", "", sizes_48, IconPurpose::BADGE) );
111 icons.push_back(
112 CreateIcon("http://foo.com/icon_96.png", "", sizes_96, IconPurpose::ANY));
113 icons.push_back(CreateIcon("http://foo.com/icon_144.png", "", sizes_144,
114 IconPurpose::ANY));
115
116 GURL url = ManifestIconSelector::FindBestMatchingIcon(
117 icons, 48, kMinimumIconSize, IconPurpose::BADGE);
118 EXPECT_EQ("http://foo.com/icon_48.png", url.spec());
119
120 url = ManifestIconSelector::FindBestMatchingIcon(
121 icons, 48, kMinimumIconSize, IconPurpose::ANY);
122 EXPECT_EQ("http://foo.com/icon_96.png", url.spec());
123
124 url = ManifestIconSelector::FindBestMatchingIcon(icons, 96, kMinimumIconSize,
125 IconPurpose::BADGE);
126 EXPECT_EQ("http://foo.com/icon_48.png", url.spec());
127
128 url = ManifestIconSelector::FindBestMatchingIcon(icons, 96, 96,
129 IconPurpose::BADGE);
130 EXPECT_TRUE(url.is_empty());
131
132 url = ManifestIconSelector::FindBestMatchingIcon(icons, 144, kMinimumIconSize,
133 IconPurpose::ANY);
134 EXPECT_EQ("http://foo.com/icon_144.png", url.spec());
135 }
136
137 TEST(ManifestIconSelector, IdealSizeIsUsedFirst) {
138 // Each icon is marked with sizes that match the ideal icon size.
139 std::vector<gfx::Size> sizes_48;
140 sizes_48.push_back(gfx::Size(48, 48));
141
142 std::vector<gfx::Size> sizes_96;
143 sizes_96.push_back(gfx::Size(96, 96));
144
145 std::vector<gfx::Size> sizes_144;
146 sizes_144.push_back(gfx::Size(144, 144));
147
148 std::vector<content::Manifest::Icon> icons;
149 icons.push_back(
150 CreateIcon("http://foo.com/icon_48.png", "", sizes_48, IconPurpose::ANY));
151 icons.push_back(
152 CreateIcon("http://foo.com/icon_96.png", "", sizes_96, IconPurpose::ANY));
153 icons.push_back(CreateIcon("http://foo.com/icon_144.png", "", sizes_144,
154 IconPurpose::ANY));
155
156 GURL url = ManifestIconSelector::FindBestMatchingIcon(
157 icons, 48, kMinimumIconSize, IconPurpose::ANY);
158 EXPECT_EQ("http://foo.com/icon_48.png", url.spec());
159
160 url = ManifestIconSelector::FindBestMatchingIcon(icons, 96, kMinimumIconSize,
161 IconPurpose::ANY);
162 EXPECT_EQ("http://foo.com/icon_96.png", url.spec());
163
164 url = ManifestIconSelector::FindBestMatchingIcon(icons, 144, kMinimumIconSize,
165 IconPurpose::ANY);
166 EXPECT_EQ("http://foo.com/icon_144.png", url.spec());
167 }
168
169 TEST(ManifestIconSelector, FirstIconWithIdealSizeIsUsedFirst) {
170 // This test has three icons. The first icon is going to be used because it
171 // contains the ideal size.
172 std::vector<gfx::Size> sizes_1;
173 sizes_1.push_back(gfx::Size(kIdealIconSize, kIdealIconSize));
174 sizes_1.push_back(gfx::Size(kIdealIconSize * 2, kIdealIconSize * 2));
175 sizes_1.push_back(gfx::Size(kIdealIconSize * 3, kIdealIconSize * 3));
176
177 std::vector<gfx::Size> sizes_2;
178 sizes_2.push_back(gfx::Size(1024, 1024));
179
180 std::vector<gfx::Size> sizes_3;
181 sizes_3.push_back(gfx::Size(1024, 1024));
182
183 std::vector<content::Manifest::Icon> icons;
184 icons.push_back(
185 CreateIcon("http://foo.com/icon_x1.png", "", sizes_1, IconPurpose::ANY));
186 icons.push_back(
187 CreateIcon("http://foo.com/icon_x2.png", "", sizes_2, IconPurpose::ANY));
188 icons.push_back(
189 CreateIcon("http://foo.com/icon_x3.png", "", sizes_3, IconPurpose::ANY));
190
191 GURL url = ManifestIconSelector::FindBestMatchingIcon(
192 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
193 EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
194
195 url = ManifestIconSelector::FindBestMatchingIcon(
196 icons, kIdealIconSize * 2, kMinimumIconSize, IconPurpose::ANY);
197 EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
198
199 url = ManifestIconSelector::FindBestMatchingIcon(
200 icons, kIdealIconSize * 3, kMinimumIconSize, IconPurpose::ANY);
201 EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
202 }
203
204 TEST(ManifestIconSelector, FallbackToSmallestLargerIcon) {
205 // If there is no perfect icon, the smallest larger icon will be chosen.
206 std::vector<gfx::Size> sizes_1;
207 sizes_1.push_back(gfx::Size(90, 90));
208
209 std::vector<gfx::Size> sizes_2;
210 sizes_2.push_back(gfx::Size(128, 128));
211
212 std::vector<gfx::Size> sizes_3;
213 sizes_3.push_back(gfx::Size(192, 192));
214
215 std::vector<content::Manifest::Icon> icons;
216 icons.push_back(
217 CreateIcon("http://foo.com/icon_x1.png", "", sizes_1, IconPurpose::ANY));
218 icons.push_back(
219 CreateIcon("http://foo.com/icon_x2.png", "", sizes_2, IconPurpose::ANY));
220 icons.push_back(
221 CreateIcon("http://foo.com/icon_x3.png", "", sizes_3, IconPurpose::ANY));
222
223 GURL url = ManifestIconSelector::FindBestMatchingIcon(
224 icons, 48, kMinimumIconSize, IconPurpose::ANY);
225 EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
226
227 url = ManifestIconSelector::FindBestMatchingIcon(icons, 96, kMinimumIconSize,
228 IconPurpose::ANY);
229 EXPECT_EQ("http://foo.com/icon_x2.png", url.spec());
230
231 url = ManifestIconSelector::FindBestMatchingIcon(icons, 144, kMinimumIconSize,
232 IconPurpose::ANY);
233 EXPECT_EQ("http://foo.com/icon_x3.png", url.spec());
234 }
235
236 TEST(ManifestIconSelector, FallbackToLargestIconLargerThanMinimum) {
237 // When an icon of the correct size has not been found, we fall back to the
238 // closest non-matching sizes. Make sure that the minimum passed is enforced.
239 std::vector<gfx::Size> sizes_1_2;
240 std::vector<gfx::Size> sizes_3;
241
242 sizes_1_2.push_back(gfx::Size(47, 47));
243 sizes_3.push_back(gfx::Size(95, 95));
244
245 std::vector<content::Manifest::Icon> icons;
246 icons.push_back(CreateIcon("http://foo.com/icon_x1.png", "", sizes_1_2,
247 IconPurpose::ANY));
248 icons.push_back(CreateIcon("http://foo.com/icon_x2.png", "", sizes_1_2,
249 IconPurpose::ANY));
250 icons.push_back(
251 CreateIcon("http://foo.com/icon_x3.png", "", sizes_3, IconPurpose::ANY));
252
253 // Icon 3 should match.
254 GURL url = ManifestIconSelector::FindBestMatchingIcon(icons, 1024, 48,
255 IconPurpose::ANY);
256 EXPECT_EQ("http://foo.com/icon_x3.png", url.spec());
257
258 // Nothing matches here as the minimum is 96.
259 url = ManifestIconSelector::FindBestMatchingIcon(icons, 1024, 96,
260 IconPurpose::ANY);
261 EXPECT_TRUE(url.is_empty());
262 }
263
264 TEST(ManifestIconSelector, IdealVeryCloseToMinimumMatches) {
265 std::vector<gfx::Size> sizes;
266 sizes.push_back(gfx::Size(2, 2));
267
268 std::vector<content::Manifest::Icon> icons;
269 icons.push_back(
270 CreateIcon("http://foo.com/icon_x1.png", "", sizes, IconPurpose::ANY));
271
272 GURL url =
273 ManifestIconSelector::FindBestMatchingIcon(icons, 2, 1, IconPurpose::ANY);
274 EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
275 }
276
277 TEST(ManifestIconSelector, SizeVeryCloseToMinimumMatches) {
278 std::vector<gfx::Size> sizes;
279 sizes.push_back(gfx::Size(2, 2));
280
281 std::vector<content::Manifest::Icon> icons;
282 icons.push_back(
283 CreateIcon("http://foo.com/icon_x1.png", "", sizes, IconPurpose::ANY));
284
285 GURL url = ManifestIconSelector::FindBestMatchingIcon(icons, 200, 1,
286 IconPurpose::ANY);
287 EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
288 }
289
290 TEST(ManifestIconSelector, NotSquareIconsAreIgnored) {
291 std::vector<gfx::Size> sizes;
292 sizes.push_back(gfx::Size(1024, 1023));
293
294 std::vector<content::Manifest::Icon> icons;
295 icons.push_back(
296 CreateIcon("http://foo.com/icon.png", "", sizes, IconPurpose::ANY));
297
298 GURL url = ManifestIconSelector::FindBestMatchingIcon(
299 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
300 EXPECT_TRUE(url.is_empty());
301 }
302
303 TEST(ManifestIconSelector, ClosestIconToIdeal) {
304 // Ensure ManifestIconSelector::FindBestMatchingIcon selects the closest icon
305 // to the ideal size when presented with a number of options.
306 int very_small = kIdealIconSize / 4;
307 int small_size = kIdealIconSize / 2;
308 int bit_small = kIdealIconSize - 1;
309 int bit_big = kIdealIconSize + 1;
310 int big = kIdealIconSize * 2;
311 int very_big = kIdealIconSize * 4;
312
313 // (very_small, bit_small) => bit_small
314 {
315 std::vector<gfx::Size> sizes_1;
316 sizes_1.push_back(gfx::Size(very_small, very_small));
317
318 std::vector<gfx::Size> sizes_2;
319 sizes_2.push_back(gfx::Size(bit_small, bit_small));
320
321 std::vector<content::Manifest::Icon> icons;
322 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_1,
323 IconPurpose::ANY));
324 icons.push_back(
325 CreateIcon("http://foo.com/icon.png", "", sizes_2, IconPurpose::ANY));
326
327 GURL url = ManifestIconSelector::FindBestMatchingIcon(
328 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
329 EXPECT_EQ("http://foo.com/icon.png", url.spec());
330 }
331
332 // (very_small, bit_small, small_size) => bit_small
333 {
334 std::vector<gfx::Size> sizes_1;
335 sizes_1.push_back(gfx::Size(very_small, very_small));
336
337 std::vector<gfx::Size> sizes_2;
338 sizes_2.push_back(gfx::Size(bit_small, bit_small));
339
340 std::vector<gfx::Size> sizes_3;
341 sizes_3.push_back(gfx::Size(small_size, small_size));
342
343 std::vector<content::Manifest::Icon> icons;
344 icons.push_back(CreateIcon("http://foo.com/icon_no_1.png", "", sizes_1,
345 IconPurpose::ANY));
346 icons.push_back(
347 CreateIcon("http://foo.com/icon.png", "", sizes_2, IconPurpose::ANY));
348 icons.push_back(CreateIcon("http://foo.com/icon_no_2.png", "", sizes_3,
349 IconPurpose::ANY));
350
351 GURL url = ManifestIconSelector::FindBestMatchingIcon(
352 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
353 EXPECT_EQ("http://foo.com/icon.png", url.spec());
354 }
355
356 // (very_big, big) => big
357 {
358 std::vector<gfx::Size> sizes_1;
359 sizes_1.push_back(gfx::Size(very_big, very_big));
360
361 std::vector<gfx::Size> sizes_2;
362 sizes_2.push_back(gfx::Size(big, big));
363
364 std::vector<content::Manifest::Icon> icons;
365 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_1,
366 IconPurpose::ANY));
367 icons.push_back(
368 CreateIcon("http://foo.com/icon.png", "", sizes_2, IconPurpose::ANY));
369
370 GURL url = ManifestIconSelector::FindBestMatchingIcon(
371 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
372 EXPECT_EQ("http://foo.com/icon.png", url.spec());
373 }
374
375 // (very_big, big, bit_big) => bit_big
376 {
377 std::vector<gfx::Size> sizes_1;
378 sizes_1.push_back(gfx::Size(very_big, very_big));
379
380 std::vector<gfx::Size> sizes_2;
381 sizes_2.push_back(gfx::Size(big, big));
382
383 std::vector<gfx::Size> sizes_3;
384 sizes_3.push_back(gfx::Size(bit_big, bit_big));
385
386 std::vector<content::Manifest::Icon> icons;
387 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_1,
388 IconPurpose::ANY));
389 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_2,
390 IconPurpose::ANY));
391 icons.push_back(
392 CreateIcon("http://foo.com/icon.png", "", sizes_3, IconPurpose::ANY));
393
394 GURL url = ManifestIconSelector::FindBestMatchingIcon(
395 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
396 EXPECT_EQ("http://foo.com/icon.png", url.spec());
397 }
398
399 // (bit_small, very_big) => very_big
400 {
401 std::vector<gfx::Size> sizes_1;
402 sizes_1.push_back(gfx::Size(bit_small, bit_small));
403
404 std::vector<gfx::Size> sizes_2;
405 sizes_2.push_back(gfx::Size(very_big, very_big));
406
407 std::vector<content::Manifest::Icon> icons;
408 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_1,
409 IconPurpose::ANY));
410 icons.push_back(
411 CreateIcon("http://foo.com/icon.png", "", sizes_2, IconPurpose::ANY));
412
413 GURL url = ManifestIconSelector::FindBestMatchingIcon(
414 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
415 EXPECT_EQ("http://foo.com/icon.png", url.spec());
416 }
417
418 // (bit_small, bit_big) => bit_big
419 {
420 std::vector<gfx::Size> sizes_1;
421 sizes_1.push_back(gfx::Size(bit_small, bit_small));
422
423 std::vector<gfx::Size> sizes_2;
424 sizes_2.push_back(gfx::Size(bit_big, bit_big));
425
426 std::vector<content::Manifest::Icon> icons;
427 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_1,
428 IconPurpose::ANY));
429 icons.push_back(
430 CreateIcon("http://foo.com/icon.png", "", sizes_2, IconPurpose::ANY));
431
432 GURL url = ManifestIconSelector::FindBestMatchingIcon(
433 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
434 EXPECT_EQ("http://foo.com/icon.png", url.spec());
435 }
436 }
437
438 TEST(ManifestIconSelector, UseAnyIfNoIdealSize) {
439 // 'any' (ie. gfx::Size(0,0)) should be used if there is no icon of a
440 // ideal size.
441
442 // Icon with 'any' and icon with ideal size => ideal size is chosen.
443 {
444 std::vector<gfx::Size> sizes_1;
445 sizes_1.push_back(gfx::Size(kIdealIconSize, kIdealIconSize));
446 std::vector<gfx::Size> sizes_2;
447 sizes_2.push_back(gfx::Size(0, 0));
448
449 std::vector<content::Manifest::Icon> icons;
450 icons.push_back(
451 CreateIcon("http://foo.com/icon.png", "", sizes_1, IconPurpose::ANY));
452 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_2,
453 IconPurpose::ANY));
454
455 GURL url = ManifestIconSelector::FindBestMatchingIcon(
456 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
457 EXPECT_EQ("http://foo.com/icon.png", url.spec());
458 }
459
460 // Icon with 'any' and icon larger than ideal size => any is chosen.
461 {
462 std::vector<gfx::Size> sizes_1;
463 sizes_1.push_back(gfx::Size(kIdealIconSize + 1, kIdealIconSize + 1));
464 std::vector<gfx::Size> sizes_2;
465 sizes_2.push_back(gfx::Size(0, 0));
466
467 std::vector<content::Manifest::Icon> icons;
468 icons.push_back(CreateIcon("http://foo.com/icon_no.png", "", sizes_1,
469 IconPurpose::ANY));
470 icons.push_back(
471 CreateIcon("http://foo.com/icon.png", "", sizes_2, IconPurpose::ANY));
472
473 GURL url = ManifestIconSelector::FindBestMatchingIcon(
474 icons, kIdealIconSize, kMinimumIconSize, IconPurpose::ANY);
475 EXPECT_EQ("http://foo.com/icon.png", url.spec());
476 }
477
478 // Multiple icons with 'any' => the last one is chosen.
479 {
480 std::vector<gfx::Size> sizes;
481 sizes.push_back(gfx::Size(0, 0));
482
483 std::vector<content::Manifest::Icon> icons;
484 icons.push_back(
485 CreateIcon("http://foo.com/icon_no1.png", "", sizes, IconPurpose::ANY));
486 icons.push_back(
487 CreateIcon("http://foo.com/icon_no2.png", "", sizes, IconPurpose::ANY));
488 icons.push_back(
489 CreateIcon("http://foo.com/icon.png", "", sizes, IconPurpose::ANY));
490
491 GURL url = ManifestIconSelector::FindBestMatchingIcon(
492 icons, kIdealIconSize * 3, kMinimumIconSize, IconPurpose::ANY);
493 EXPECT_EQ("http://foo.com/icon.png", url.spec());
494 }
495 }
OLDNEW
« no previous file with comments | « chrome/browser/manifest/manifest_icon_selector.cc ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698