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

Side by Side Diff: ui/gfx/content_analysis_unittest.cc

Issue 13947013: Complete (but inefficient) implementation of the image retargetting method. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 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 (c) 2012 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 "ui/gfx/content_analysis.h"
6
7 #include <algorithm>
8 #include <cmath>
9 #include <cstdlib>
10 #include <fstream>
11 #include <iostream>
12 #include <limits>
13 #include <numeric>
14 #include <vector>
15
16 #include "base/file_util.h"
17 #include "base/files/file_path.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "third_party/skia/include/core/SkColor.h"
22 #include "ui/gfx/canvas.h"
23 #include "ui/gfx/color_analysis.h"
24 #include "ui/gfx/color_utils.h"
25 #include "ui/gfx/image/image.h"
26 #include "ui/gfx/rect.h"
27 #include "ui/gfx/size.h"
28
29 namespace {
30
31 #ifndef M_PI
32 #define M_PI 3.14159265358979323846
33 #endif
34
35 void DumpBitmapToFile(const SkBitmap& bitmap) {
Alexei Svitkine (slow) 2013/04/09 18:02:23 If you're not using these in your tests, please re
motek. 2013/04/11 16:18:38 Done.
36 SkAutoLockPixels bitmap_lock(bitmap);
37 scoped_refptr<base::RefCountedMemory> png_bytes =
38 gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes();
39 base::FilePath file_path;
40 if (file_util::CreateTemporaryFile(&file_path)) {
41 file_util::WriteFile(file_path,
42 reinterpret_cast<const char*>(png_bytes->front()),
43 png_bytes->size());
44 DLOG(INFO) << "Image content writen out to " << file_path.value();
45 } else {
46 NOTREACHED();
47 }
48 }
49
50 void DumpBitmapBytesToFile(const SkBitmap& bitmap) {
51 SkAutoLockPixels bitmap_lock(bitmap);
52 base::FilePath file_path;
53 if (file_util::CreateTemporaryFile(&file_path)) {
54 file_util::WriteFile(file_path,
55 static_cast<const char*>(bitmap.getPixels()),
56 bitmap.getSafeSize());
57 DLOG(INFO) << "Image content writen out to " << file_path.value();
58 } else {
59 NOTREACHED();
60 }
61 }
62
63 template<class InputIterator>
64 void DumpVectorToFile(InputIterator first, InputIterator last) {
65 base::FilePath file_path;
66 if (file_util::CreateTemporaryFile(&file_path)) {
67 std::ofstream outfile;
68 outfile.open(file_path.value().c_str());
69 for (; first < last; ++first) {
70 outfile << *first;
71 outfile << "\n";
72 }
73 outfile.close();
74 DLOG(INFO) << "Vector content writen out to " << file_path.value();
75 }
76 }
77
78 unsigned long ImagePixelSum(const SkBitmap& bitmap, const gfx::Rect& rect) {
79 // Get the sum of pixel values in the rectangle. Applicable only to
80 // monochrome bitmaps.
81 DCHECK_EQ(SkBitmap::kA8_Config, bitmap.config());
82 unsigned long total = 0;
83 for (int r = rect.y(); r < rect.bottom(); ++r) {
84 const uint8* row_data = static_cast<const uint8*>(
85 bitmap.getPixels()) + r * bitmap.rowBytes();
86 for (int c = rect.x(); c < rect.right(); ++c)
87 total += row_data[c];
88 }
89
90 return total;
91 }
92
93 bool CompareImageFragments(const SkBitmap& bitmap_left,
94 const SkBitmap& bitmap_right,
95 const gfx::Size& comparison_area,
96 const gfx::Point& origin_left,
97 const gfx::Point& origin_right) {
98 SkAutoLockPixels left_lock(bitmap_left);
99 SkAutoLockPixels right_lock(bitmap_right);
100 for (int r = 0; r < comparison_area.height(); ++r) {
101 for (int c = 0; c < comparison_area.width(); ++c) {
102 SkColor clr_left = bitmap_left.getColor(origin_left.x() + c,
103 origin_left.y() + r);
104 SkColor clr_right = bitmap_right.getColor(origin_right.x() + c,
105 origin_right.y() + r);
106 if (clr_left != clr_right)
107 return false;
108 }
109 }
110
111 return true;
112 }
113
114 }
Alexei Svitkine (slow) 2013/04/09 18:02:23 Add " // namespace"
motek. 2013/04/11 16:18:38 Done.
115
116 class ContentAnalysisTest : public testing::Test {
117 };
118
119 TEST_F(ContentAnalysisTest, ApplyGradientMagnitudeOnImpulse) {
120 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true);
121
122 // The image consists of vertical non-overlapping stripes 100 pixels wide.
123 canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetARGB(0, 10, 10, 10));
124 canvas.FillRect(gfx::Rect(400, 300, 1, 1), SkColorSetRGB(255, 255, 255));
125
126 SkBitmap source =
127 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
128
129 SkBitmap reduced_color;
130 reduced_color.setConfig(
131 SkBitmap::kA8_Config, source.width(), source.height());
132 reduced_color.allocPixels();
133
134 gfx::Vector3dF transform(0.299f, 0.587f, 0.114f);
135 EXPECT_TRUE(color_utils::ApplyColorReduction(
136 source, transform, true, &reduced_color));
137
138 float sigma = 2.5f;
139 color_utils::ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma);
140
141 // Expect everything to be within 8 * sigma.
142 int tail_length = static_cast<int>(8.0f * sigma + 0.5f);
143 gfx::Rect echo_rect(399 - tail_length, 299 - tail_length,
144 2 * tail_length + 1, 2 * tail_length + 1);
145 unsigned long data_sum = ImagePixelSum(reduced_color, echo_rect);
146 unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600));
147 EXPECT_GT(data_sum, 0U);
148 EXPECT_EQ(data_sum, all_sum);
149
150 sigma = 5.0f;
151 color_utils::ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma);
152
153 // Expect everything to be within 8 * sigma.
154 tail_length = static_cast<int>(8.0f * sigma + 0.5f);
155 echo_rect = gfx::Rect(399 - tail_length, 299 - tail_length,
156 2 * tail_length + 1, 2 * tail_length + 1);
157 data_sum = ImagePixelSum(reduced_color, echo_rect);
158 all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600));
159 EXPECT_GT(data_sum, 0U);
160 EXPECT_EQ(data_sum, all_sum);
161 }
162
163 TEST_F(ContentAnalysisTest, ApplyGradientMagnitudeOnFrame) {
164 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true);
165
166 // The image consists of a single white block in the centre.
167 gfx::Rect draw_rect(300, 200, 200, 200);
168 canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetARGB(0, 0, 0, 0));
169 canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255));
170
171 SkBitmap source =
172 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
173
174 SkBitmap reduced_color;
175 reduced_color.setConfig(
176 SkBitmap::kA8_Config, source.width(), source.height());
177 reduced_color.allocPixels();
178
179 gfx::Vector3dF transform(0.299f, 0.587f, 0.114f);
180 EXPECT_TRUE(color_utils::ApplyColorReduction(
181 source, transform, true, &reduced_color));
182
183 float sigma = 2.5f;
184 color_utils::ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma);
185
186 int tail_length = static_cast<int>(8.0f * sigma + 0.5f);
187 gfx::Rect outer_rect(draw_rect.x() - tail_length,
188 draw_rect.y() - tail_length,
189 draw_rect.width() + 2 * tail_length,
190 draw_rect.height() + 2 * tail_length);
191 gfx::Rect inner_rect(draw_rect.x() + tail_length,
192 draw_rect.y() + tail_length,
193 draw_rect.width() - 2 * tail_length,
194 draw_rect.height() - 2 * tail_length);
195 unsigned long data_sum = ImagePixelSum(reduced_color, outer_rect);
196 unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600));
197 EXPECT_GT(data_sum, 0U);
198 EXPECT_EQ(data_sum, all_sum);
199 EXPECT_EQ(ImagePixelSum(reduced_color, inner_rect), 0U);
200 }
201
202 TEST_F(ContentAnalysisTest, ExtractImageProfileInformation) {
203 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true);
204
205 // The image consists of a white frame drawn in the centre.
206 gfx::Rect draw_rect(100, 100, 200, 100);
207 gfx::Rect image_rect(0, 0, 800, 600);
208 canvas.FillRect(image_rect, SkColorSetARGB(0, 0, 0, 0));
209 canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255));
210
211 SkBitmap source =
212 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
213 SkBitmap reduced_color;
214 reduced_color.setConfig(
215 SkBitmap::kA8_Config, source.width(), source.height());
216 reduced_color.allocPixels();
217
218 gfx::Vector3dF transform(1, 0, 0);
219 EXPECT_TRUE(color_utils::ApplyColorReduction(
220 source, transform, true, &reduced_color));
221 std::vector<float> column_profile;
222 std::vector<float> row_profile;
223 color_utils::ExtractImageProfileInformation(reduced_color,
224 image_rect,
225 gfx::Size(),
226 false,
227 &row_profile,
228 &column_profile);
229 EXPECT_EQ(0, std::accumulate(column_profile.begin(),
230 column_profile.begin() + draw_rect.x() - 1,
231 0));
232 EXPECT_EQ(column_profile[draw_rect.x()], 255U * (draw_rect.height() + 1));
233 EXPECT_EQ(2 * 255 * (draw_rect.width() - 2),
234 std::accumulate(column_profile.begin() + draw_rect.x() + 1,
235 column_profile.begin() + draw_rect.right() - 1,
236 0));
237
238 EXPECT_EQ(0, std::accumulate(row_profile.begin(),
239 row_profile.begin() + draw_rect.y() - 1,
240 0));
241 EXPECT_EQ(row_profile[draw_rect.y()], 255U * (draw_rect.width() + 1));
242 EXPECT_EQ(2 * 255 * (draw_rect.height() - 2),
243 std::accumulate(row_profile.begin() + draw_rect.y() + 1,
244 row_profile.begin() + draw_rect.bottom() - 1,
245 0));
246
247 gfx::Rect test_rect(150, 80, 400, 100);
248 color_utils::ExtractImageProfileInformation(reduced_color,
249 test_rect,
250 gfx::Size(),
251 false,
252 &row_profile,
253 &column_profile);
254
255 // Some overlap with the drawn rectagle. If you work it out on a piece of
256 // paper, sums should be as follows.
257 EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) +
258 255 * (draw_rect.right() - test_rect.x()),
259 std::accumulate(row_profile.begin(), row_profile.end(), 0));
260 EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) +
261 255 * (draw_rect.right() - test_rect.x()),
262 std::accumulate(column_profile.begin(), column_profile.end(), 0));
263 }
264
265 TEST_F(ContentAnalysisTest, ExtractImageProfileInformationWithClosing) {
266 gfx::Canvas canvas(gfx::Size(800, 600), ui::SCALE_FACTOR_100P, true);
267
268 // The image consists of a two white frames drawn side by side, with a
269 // single-pixel vertical gap in between.
270 gfx::Rect image_rect(0, 0, 800, 600);
271 canvas.FillRect(image_rect, SkColorSetARGB(0, 0, 0, 0));
272 canvas.DrawRect(gfx::Rect(300, 250, 99, 100), SkColorSetRGB(255, 255, 255));
273 canvas.DrawRect(gfx::Rect(401, 250, 99, 100), SkColorSetRGB(255, 255, 255));
274
275 SkBitmap source =
276 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
277 SkBitmap reduced_color;
278 reduced_color.setConfig(
279 SkBitmap::kA8_Config, source.width(), source.height());
280 reduced_color.allocPixels();
281
282 gfx::Vector3dF transform(1, 0, 0);
283 EXPECT_TRUE(color_utils::ApplyColorReduction(
284 source, transform, true, &reduced_color));
285 std::vector<float> column_profile;
286 std::vector<float> row_profile;
287
288 color_utils::ExtractImageProfileInformation(reduced_color,
289 image_rect,
290 gfx::Size(),
291 true,
292 &row_profile,
293 &column_profile);
294 // Column profiles should have two spikes in the middle, with a single
295 // 0-valued value between them.
296 EXPECT_GT(column_profile[398], 0.0f);
297 EXPECT_GT(column_profile[399], column_profile[398]);
298 EXPECT_GT(column_profile[402], 0.0f);
299 EXPECT_GT(column_profile[401], column_profile[402]);
300 EXPECT_EQ(column_profile[401], column_profile[399]);
301 EXPECT_EQ(column_profile[402], column_profile[398]);
302 EXPECT_EQ(column_profile[400], 0.0f);
303 EXPECT_EQ(column_profile[299], 0.0f);
304 EXPECT_EQ(column_profile[502], 0.0f);
305
306 // Now the same with closing applied. The space in the middle will be closed.
307 color_utils::ExtractImageProfileInformation(reduced_color,
308 image_rect,
309 gfx::Size(200, 100),
310 true,
311 &row_profile,
312 &column_profile);
313 EXPECT_GT(column_profile[398], 0);
314 EXPECT_GT(column_profile[400], 0);
315 EXPECT_GT(column_profile[402], 0);
316 EXPECT_EQ(column_profile[299], 0);
317 EXPECT_EQ(column_profile[502], 0);
318 EXPECT_EQ(column_profile[399], column_profile[401]);
319 EXPECT_EQ(column_profile[398], column_profile[402]);
320 }
321
322 TEST_F(ContentAnalysisTest, AutoSegmentPeaks) {
323 std::vector<float> profile_info;
324
325 EXPECT_EQ(color_utils::AutoSegmentPeaks(profile_info),
326 std::numeric_limits<float>::max());
327 profile_info.resize(1000, 1.0f);
328 EXPECT_EQ(color_utils::AutoSegmentPeaks(profile_info), 1.0f);
329 std::srand(42);
330 std::generate(profile_info.begin(), profile_info.end(), std::rand);
331 float threshold = color_utils::AutoSegmentPeaks(profile_info);
332 EXPECT_GT(threshold, 0); // Not much to expect.
333
334 // There should be roughly 50% above and below the threshold.
335 // Random is not really random thanks to srand, so we can sort-of compare.
336 int above_count = std::count_if(
337 profile_info.begin(),
338 profile_info.end(),
339 std::bind2nd(std::greater<float>(), threshold));
340 EXPECT_GT(above_count, 475); // Not much to expect.
341 EXPECT_LT(above_count, 525);
342
343 for (unsigned i = 0; i < profile_info.size(); ++i) {
344 float y = std::sin(M_PI * i / 250.0f);
345 profile_info[i] = y > 0 ? y : 0;
346 }
347 threshold = color_utils::AutoSegmentPeaks(profile_info);
348
349 above_count = std::count_if(
350 profile_info.begin(),
351 profile_info.end(),
352 std::bind2nd(std::greater<float>(), threshold));
353 EXPECT_LT(above_count, 500); // Negative y expected to fall below threshold.
354
355 // Expect two peaks around between 0 and 250 and 500 and 750.
356 std::vector<bool> thresholded_values(profile_info.size(), false);
357 std::transform(profile_info.begin(),
358 profile_info.end(),
359 thresholded_values.begin(),
360 std::bind2nd(std::greater<float>(), threshold));
361 EXPECT_TRUE(thresholded_values[125]);
362 EXPECT_TRUE(thresholded_values[625]);
363 int transitions = 0;
364 for (unsigned i = 1; i < thresholded_values.size(); ++i) {
365 if (thresholded_values[i] != thresholded_values[i-1])
366 transitions++;
367 }
368 EXPECT_EQ(transitions, 4); // We have two contiguous peaks. Good going!
369 }
370
371 TEST_F(ContentAnalysisTest, ComputeDecimatedImage) {
372 gfx::Size image_size(1600, 1200);
373 gfx::Canvas canvas(image_size, ui::SCALE_FACTOR_100P, true);
374
375 // Make some content we will later want to keep.
376 canvas.FillRect(gfx::Rect(100, 200, 100, 100), SkColorSetARGB(0, 125, 0, 0));
377 canvas.FillRect(gfx::Rect(300, 200, 100, 100), SkColorSetARGB(0, 0, 200, 0));
378 canvas.FillRect(gfx::Rect(500, 200, 100, 100), SkColorSetARGB(0, 0, 0, 225));
379 canvas.FillRect(gfx::Rect(100, 400, 600, 100),
380 SkColorSetARGB(0, 125, 200, 225));
381
382 std::vector<bool> rows(image_size.height(), false);
383 std::fill_n(rows.begin() + 200, 100, true);
384 std::fill_n(rows.begin() + 400, 100, true);
385
386 std::vector<bool> columns(image_size.width(), false);
387 std::fill_n(columns.begin() + 100, 100, true);
388 std::fill_n(columns.begin() + 300, 100, true);
389 std::fill_n(columns.begin() + 500, 100, true);
390
391 SkBitmap source =
392 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
393 scoped_ptr<SkBitmap> result(
394 color_utils::ComputeDecimatedImage(source, rows, columns));
395 EXPECT_FALSE(result.get() == NULL);
396 EXPECT_EQ(300, result->width());
397 EXPECT_EQ(200, result->height());
398
399 // The call should have removed all empty spaces.
400 ASSERT_TRUE(CompareImageFragments(source,
401 *result,
402 gfx::Size(100, 100),
403 gfx::Point(100, 200),
404 gfx::Point(0, 0)));
405 ASSERT_TRUE(CompareImageFragments(source,
406 *result,
407 gfx::Size(100, 100),
408 gfx::Point(300, 200),
409 gfx::Point(100, 0)));
410 ASSERT_TRUE(CompareImageFragments(source,
411 *result,
412 gfx::Size(100, 100),
413 gfx::Point(500, 200),
414 gfx::Point(200, 0)));
415 ASSERT_TRUE(CompareImageFragments(source,
416 *result,
417 gfx::Size(100, 100),
418 gfx::Point(100, 400),
419 gfx::Point(0, 0)));
420 }
421
422 TEST_F(ContentAnalysisTest, CreateRetargettedThumbnailImage) {
423 gfx::Size image_size(1200, 1300);
424 gfx::Canvas canvas(image_size, ui::SCALE_FACTOR_100P, true);
425
426 // The following will create a 'fake image' consisting of color blocks placed
427 // on a neutral background. The entire layout is supposed to mimic a
428 // screenshot of a web page.
429 // The tested function is supposed to locate the interesing areas in the
430 // middle.
431 const int margin_horizontal = 60;
432 const int margin_vertical = 20;
433 canvas.FillRect(gfx::Rect(image_size), SkColorSetRGB(200, 210, 210));
434 const gfx::Rect header_rect(margin_horizontal,
435 margin_vertical,
436 image_size.width() - 2 * margin_horizontal,
437 100);
438 const gfx::Rect footer_rect(margin_horizontal,
439 image_size.height() - margin_vertical - 100,
440 image_size.width() - 2 * margin_horizontal,
441 100);
442 const gfx::Rect body_rect(margin_horizontal,
443 header_rect.bottom() + margin_vertical,
444 image_size.width() - 2 * margin_horizontal,
445 footer_rect.y() - header_rect.bottom() -
446 2 * margin_vertical);
447 canvas.FillRect(header_rect, SkColorSetRGB(200, 40, 10));
448 canvas.FillRect(footer_rect, SkColorSetRGB(10, 40, 180));
449 canvas.FillRect(body_rect, SkColorSetRGB(150, 180, 40));
450
451 // 'Fine print' at the bottom.
452 const int fine_print = 8;
453 const SkColor print_color = SkColorSetRGB(45, 30, 30);
454 for (int y = footer_rect.y() + fine_print;
455 y < footer_rect.bottom() - fine_print;
456 y += 2 * fine_print) {
457 for (int x = footer_rect.x() + fine_print;
458 x < footer_rect.right() - fine_print;
459 x += 2 * fine_print) {
460 canvas.DrawRect(gfx::Rect(x, y, fine_print, fine_print), print_color);
461 }
462 }
463
464 // Blocky content at the top.
465 const int block_size = header_rect.height() - margin_vertical;
466 for (int x = header_rect.x() + margin_horizontal;
467 x < header_rect.right() - block_size;
468 x += block_size + margin_horizontal) {
469 const int half_block = block_size / 2 - 5;
470 const SkColor block_color = SkColorSetRGB(255, 255, 255);
471 const int y = header_rect.y() + margin_vertical / 2;
472 int second_col = x + half_block + 10;
473 int second_row = y + half_block + 10;
474 canvas.FillRect(gfx::Rect(x, y, half_block, block_size), block_color);
475 canvas.FillRect(gfx::Rect(second_col, y, half_block, half_block),
476 block_color);
477 canvas.FillRect(gfx::Rect(second_col, second_row, half_block, half_block),
478 block_color);
479 }
480
481 // Now the main body. Mostly text with some 'pictures'.
482 for (int y = body_rect.y() + fine_print;
483 y < body_rect.bottom() - fine_print;
484 y += 2 * fine_print) {
485 for (int x = body_rect.x() + fine_print;
486 x < body_rect.right() - fine_print;
487 x += 2 * fine_print) {
488 canvas.DrawRect(gfx::Rect(x, y, fine_print, fine_print), print_color);
489 }
490 }
491
492 for (int line = 0; line < 3; ++line) {
493 int alignment = line % 2;
494 const int y = body_rect.y() +
495 body_rect.height() / 3 * line + margin_vertical;
496 const int x = body_rect.x() +
497 alignment * body_rect.width() / 2 + margin_vertical;
498 gfx::Rect pict_rect(x, y,
499 body_rect.width() / 2 - 2 * margin_vertical,
500 body_rect.height() / 3 - 2 * margin_vertical);
501 canvas.FillRect(pict_rect, SkColorSetRGB(255, 255, 255));
502 canvas.DrawRect(pict_rect, SkColorSetRGB(0, 0, 0));
503 }
504
505 SkBitmap source =
506 skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
507
508 scoped_ptr<SkBitmap> result(color_utils::CreateRetargettedThumbnailImage(
509 source, gfx::Size(424, 264), 2.5));
510 EXPECT_FALSE(result.get() == NULL);
511
512 // Given the nature of computation We can't really assert much here about the
513 // image itself. We know it should have been computed, should be smaller than
514 // the original and it must not be zero.
515 EXPECT_LT(result->width(), image_size.width());
516 EXPECT_LT(result->height(), image_size.height());
517
518 int histogram[256];
519 color_utils::BuildLumaHistogram(*result, histogram);
520 int non_zero_color_count = std::count_if(
521 histogram, histogram + 256, std::bind2nd(std::greater<int>(), 0));
522 EXPECT_GT(non_zero_color_count, 4);
523 }
OLDNEW
« ui/gfx/content_analysis.cc ('K') | « ui/gfx/content_analysis.cc ('k') | ui/ui.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698