OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdio.h> | 5 #include <stdio.h> |
6 #include <cmath> | 6 #include <cmath> |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include <GLES2/gl2.h> | 10 #include <GLES2/gl2.h> |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 float x3 = x2 * x; | 132 float x3 = x2 * x; |
133 if (x <= 1) { | 133 if (x <= 1) { |
134 return (a + 2) * x3 - (a + 3) * x2 + 1; | 134 return (a + 2) * x3 - (a + 3) * x2 + 1; |
135 } else if (x < 2) { | 135 } else if (x < 2) { |
136 return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a; | 136 return a * x3 - 5 * a * x2 + 8 * a * x - 4 * a; |
137 } else { | 137 } else { |
138 return 0.0f; | 138 return 0.0f; |
139 } | 139 } |
140 } | 140 } |
141 | 141 |
142 // Look up a single R/G/B/A value. | 142 // Look up a single channel value. Works for 4-channel and single channel |
143 // Clamp x/y. | 143 // bitmaps. Clamp x/y. |
144 int Channel(SkBitmap* pixels, int x, int y, int c) { | 144 int Channel(SkBitmap* pixels, int x, int y, int c) { |
145 uint32* data = | 145 if (pixels->bytesPerPixel() == 4) { |
146 pixels->getAddr32(std::max(0, std::min(x, pixels->width() - 1)), | 146 uint32* data = |
147 std::max(0, std::min(y, pixels->height() - 1))); | 147 pixels->getAddr32(std::max(0, std::min(x, pixels->width() - 1)), |
148 return (*data) >> (c * 8) & 0xff; | 148 std::max(0, std::min(y, pixels->height() - 1))); |
| 149 return (*data) >> (c * 8) & 0xff; |
| 150 } else { |
| 151 DCHECK_EQ(pixels->bytesPerPixel(), 1); |
| 152 DCHECK_EQ(c, 0); |
| 153 return *pixels->getAddr8(std::max(0, std::min(x, pixels->width() - 1)), |
| 154 std::max(0, std::min(y, pixels->height() - 1))); |
| 155 } |
149 } | 156 } |
150 | 157 |
151 // Set a single R/G/B/A value. | 158 // Set a single channel value. Works for 4-channel and single channel |
| 159 // bitmaps. Clamp x/y. |
152 void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) { | 160 void SetChannel(SkBitmap* pixels, int x, int y, int c, int v) { |
153 DCHECK_GE(x, 0); | 161 DCHECK_GE(x, 0); |
154 DCHECK_GE(y, 0); | 162 DCHECK_GE(y, 0); |
155 DCHECK_LT(x, pixels->width()); | 163 DCHECK_LT(x, pixels->width()); |
156 DCHECK_LT(y, pixels->height()); | 164 DCHECK_LT(y, pixels->height()); |
157 uint32* data = pixels->getAddr32(x, y); | 165 if (pixels->bytesPerPixel() == 4) { |
158 v = std::max(0, std::min(v, 255)); | 166 uint32* data = pixels->getAddr32(x, y); |
159 *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8)); | 167 v = std::max(0, std::min(v, 255)); |
| 168 *data = (*data & ~(0xffu << (c * 8))) | (v << (c * 8)); |
| 169 } else { |
| 170 DCHECK_EQ(pixels->bytesPerPixel(), 1); |
| 171 DCHECK_EQ(c, 0); |
| 172 uint8* data = pixels->getAddr8(x, y); |
| 173 v = std::max(0, std::min(v, 255)); |
| 174 *data = v; |
| 175 } |
160 } | 176 } |
161 | 177 |
162 // Print all the R, G, B or A values from an SkBitmap in a | 178 // Print all the R, G, B or A values from an SkBitmap in a |
163 // human-readable format. | 179 // human-readable format. |
164 void PrintChannel(SkBitmap* pixels, int c) { | 180 void PrintChannel(SkBitmap* pixels, int c) { |
165 for (int y = 0; y < pixels->height(); y++) { | 181 for (int y = 0; y < pixels->height(); y++) { |
166 std::string formatted; | 182 std::string formatted; |
167 for (int x = 0; x < pixels->width(); x++) { | 183 for (int x = 0; x < pixels->width(); x++) { |
168 formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c))); | 184 formatted.append(base::StringPrintf("%3d, ", Channel(pixels, x, y, c))); |
169 } | 185 } |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 } | 387 } |
372 } | 388 } |
373 | 389 |
374 if (HasFailure() && !previous_error) { | 390 if (HasFailure() && !previous_error) { |
375 LOG(ERROR) << "Invalid scaler stages: " << message; | 391 LOG(ERROR) << "Invalid scaler stages: " << message; |
376 LOG(ERROR) << "Scaler stages:"; | 392 LOG(ERROR) << "Scaler stages:"; |
377 LOG(ERROR) << PrintStages(scaler_stages); | 393 LOG(ERROR) << PrintStages(scaler_stages); |
378 } | 394 } |
379 } | 395 } |
380 | 396 |
381 // Compare two bitmaps, make sure that each component of each pixel | 397 // Compares two bitmaps taking color types into account. Checks whether each |
382 // is no more than |maxdiff| apart. If they are not similar enough, | 398 // component of each pixel is no more than |maxdiff| apart. If bitmaps are not |
383 // prints out |truth|, |other|, |source|, |scaler_stages| and |message|. | 399 // similar enough, prints out |truth|, |other|, |source|, |scaler_stages| |
| 400 // and |message|. |
384 void Compare(SkBitmap* truth, | 401 void Compare(SkBitmap* truth, |
385 SkBitmap* other, | 402 SkBitmap* other, |
386 int maxdiff, | 403 int maxdiff, |
387 SkBitmap* source, | 404 SkBitmap* source, |
388 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, | 405 const std::vector<GLHelperScaling::ScalerStage>& scaler_stages, |
389 std::string message) { | 406 std::string message) { |
390 EXPECT_EQ(truth->width(), other->width()); | 407 EXPECT_EQ(truth->width(), other->width()); |
391 EXPECT_EQ(truth->height(), other->height()); | 408 EXPECT_EQ(truth->height(), other->height()); |
| 409 bool swizzle = (truth->colorType() == kRGBA_8888_SkColorType && |
| 410 other->colorType() == kBGRA_8888_SkColorType) || |
| 411 (truth->colorType() == kBGRA_8888_SkColorType && |
| 412 other->colorType() == kRGBA_8888_SkColorType); |
| 413 EXPECT_TRUE(swizzle || truth->colorType() == other->colorType()); |
| 414 int bpp = truth->bytesPerPixel(); |
392 for (int x = 0; x < truth->width(); x++) { | 415 for (int x = 0; x < truth->width(); x++) { |
393 for (int y = 0; y < truth->height(); y++) { | 416 for (int y = 0; y < truth->height(); y++) { |
394 for (int c = 0; c < 4; c++) { | 417 for (int c = 0; c < bpp; c++) { |
395 int a = Channel(truth, x, y, c); | 418 int a = Channel(truth, x, y, c); |
396 int b = Channel(other, x, y, c); | 419 // swizzle when comparing if needed |
| 420 int b = swizzle && (c == 0 || c == 2) |
| 421 ? Channel(other, x, y, (c + 2) & 2) |
| 422 : Channel(other, x, y, c); |
397 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c | 423 EXPECT_NEAR(a, b, maxdiff) << " x=" << x << " y=" << y << " c=" << c |
398 << " " << message; | 424 << " " << message; |
399 if (std::abs(a - b) > maxdiff) { | 425 if (std::abs(a - b) > maxdiff) { |
400 LOG(ERROR) << "-------expected--------"; | 426 LOG(ERROR) << "-------expected--------"; |
401 PrintChannel(truth, c); | 427 for (int i = 0; i < bpp; i++) { |
| 428 LOG(ERROR) << "Channel " << i << ":"; |
| 429 PrintChannel(truth, i); |
| 430 } |
402 LOG(ERROR) << "-------actual--------"; | 431 LOG(ERROR) << "-------actual--------"; |
403 PrintChannel(other, c); | 432 for (int i = 0; i < bpp; i++) { |
| 433 LOG(ERROR) << "Channel " << i << ":"; |
| 434 PrintChannel(other, i); |
| 435 } |
404 if (source) { | 436 if (source) { |
405 LOG(ERROR) << "-------before scaling--------"; | 437 LOG(ERROR) << "-------original--------"; |
406 PrintChannel(source, c); | 438 for (int i = 0; i < source->bytesPerPixel(); i++) { |
| 439 LOG(ERROR) << "Channel " << i << ":"; |
| 440 PrintChannel(source, i); |
| 441 } |
407 } | 442 } |
408 LOG(ERROR) << "-----Scaler stages------"; | 443 LOG(ERROR) << "-----Scaler stages------"; |
409 LOG(ERROR) << PrintStages(scaler_stages); | 444 LOG(ERROR) << PrintStages(scaler_stages); |
410 return; | 445 return; |
411 } | 446 } |
412 } | 447 } |
413 } | 448 } |
414 } | 449 } |
415 } | 450 } |
416 | 451 |
417 // Get a single R, G, B or A value as a float. | 452 // Get a single R, G, B or A value as a float. |
418 float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { | 453 float ChannelAsFloat(SkBitmap* pixels, int x, int y, int c) { |
419 return Channel(pixels, x, y, c) / 255.0; | 454 return Channel(pixels, x, y, c) / 255.0; |
420 } | 455 } |
421 | 456 |
422 // Works like a GL_LINEAR lookup on an SkBitmap. | 457 // Works like a GL_LINEAR lookup on an SkBitmap. |
423 float Bilinear(SkBitmap* pixels, float x, float y, int c) { | 458 float Bilinear(SkBitmap* pixels, float x, float y, int c) { |
424 x -= 0.5; | 459 x -= 0.5; |
425 y -= 0.5; | 460 y -= 0.5; |
426 int base_x = static_cast<int>(floorf(x)); | 461 int base_x = static_cast<int>(floorf(x)); |
427 int base_y = static_cast<int>(floorf(y)); | 462 int base_y = static_cast<int>(floorf(y)); |
428 x -= base_x; | 463 x -= base_x; |
429 y -= base_y; | 464 y -= base_y; |
430 return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + | 465 return (ChannelAsFloat(pixels, base_x, base_y, c) * (1 - x) * (1 - y) + |
431 ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + | 466 ChannelAsFloat(pixels, base_x + 1, base_y, c) * x * (1 - y) + |
432 ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + | 467 ChannelAsFloat(pixels, base_x, base_y + 1, c) * (1 - x) * y + |
433 ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); | 468 ChannelAsFloat(pixels, base_x + 1, base_y + 1, c) * x * y); |
434 } | 469 } |
435 | 470 |
| 471 // Encodes an RGBA bitmap to grayscale. |
| 472 // Reference implementation for |
| 473 // GLHelper::CopyToTextureImpl::EncodeTextureAsGrayscale. |
| 474 void EncodeToGrayscaleSlow(SkBitmap* input, SkBitmap* output) { |
| 475 const float kRGBtoGrayscaleColorWeights[3] = {0.213f, 0.715f, 0.072f}; |
| 476 CHECK_EQ(kAlpha_8_SkColorType, output->colorType()); |
| 477 CHECK_EQ(input->width(), output->width()); |
| 478 CHECK_EQ(input->height(), output->height()); |
| 479 CHECK_EQ(input->colorType(), kRGBA_8888_SkColorType); |
| 480 |
| 481 for (int dst_y = 0; dst_y < output->height(); dst_y++) { |
| 482 for (int dst_x = 0; dst_x < output->width(); dst_x++) { |
| 483 float c0 = ChannelAsFloat(input, dst_x, dst_y, 0); |
| 484 float c1 = ChannelAsFloat(input, dst_x, dst_y, 1); |
| 485 float c2 = ChannelAsFloat(input, dst_x, dst_y, 2); |
| 486 float value = c0 * kRGBtoGrayscaleColorWeights[0] + |
| 487 c1 * kRGBtoGrayscaleColorWeights[1] + |
| 488 c2 * kRGBtoGrayscaleColorWeights[2]; |
| 489 SetChannel( |
| 490 output, dst_x, dst_y, 0, static_cast<int>(value * 255.0f + 0.5f)); |
| 491 } |
| 492 } |
| 493 } |
| 494 |
436 // Very slow bicubic / bilinear scaler for reference. | 495 // Very slow bicubic / bilinear scaler for reference. |
437 void ScaleSlow(SkBitmap* input, | 496 void ScaleSlow(SkBitmap* input, |
438 SkBitmap* output, | 497 SkBitmap* output, |
439 content::GLHelper::ScalerQuality quality) { | 498 content::GLHelper::ScalerQuality quality) { |
440 float xscale = static_cast<float>(input->width()) / output->width(); | 499 float xscale = static_cast<float>(input->width()) / output->width(); |
441 float yscale = static_cast<float>(input->height()) / output->height(); | 500 float yscale = static_cast<float>(input->height()) / output->height(); |
442 float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; | 501 float clamped_xscale = xscale < 1.0 ? 1.0 : 1.0 / xscale; |
443 float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; | 502 float clamped_yscale = yscale < 1.0 ? 1.0 : 1.0 / yscale; |
444 for (int dst_y = 0; dst_y < output->height(); dst_y++) { | 503 for (int dst_y = 0; dst_y < output->height(); dst_y++) { |
445 for (int dst_x = 0; dst_x < output->width(); dst_x++) { | 504 for (int dst_x = 0; dst_x < output->width(); dst_x++) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 dst_x, | 567 dst_x, |
509 dst_y, | 568 dst_y, |
510 channel, | 569 channel, |
511 static_cast<int>(value * 255.0f + 0.5f)); | 570 static_cast<int>(value * 255.0f + 0.5f)); |
512 } | 571 } |
513 } | 572 } |
514 } | 573 } |
515 } | 574 } |
516 | 575 |
517 void FlipSKBitmap(SkBitmap* bitmap) { | 576 void FlipSKBitmap(SkBitmap* bitmap) { |
| 577 int bpp = bitmap->bytesPerPixel(); |
| 578 DCHECK(bpp == 4 || bpp == 1); |
518 int top_line = 0; | 579 int top_line = 0; |
519 int bottom_line = bitmap->height() - 1; | 580 int bottom_line = bitmap->height() - 1; |
520 while (top_line < bottom_line) { | 581 while (top_line < bottom_line) { |
521 for (int x = 0; x < bitmap->width(); x++) { | 582 for (int x = 0; x < bitmap->width(); x++) { |
522 std::swap(*bitmap->getAddr32(x, top_line), | 583 bpp == 4 ? std::swap(*bitmap->getAddr32(x, top_line), |
523 *bitmap->getAddr32(x, bottom_line)); | 584 *bitmap->getAddr32(x, bottom_line)) |
| 585 : std::swap(*bitmap->getAddr8(x, top_line), |
| 586 *bitmap->getAddr8(x, bottom_line)); |
524 } | 587 } |
525 top_line++; | 588 top_line++; |
526 bottom_line--; | 589 bottom_line--; |
527 } | 590 } |
528 } | 591 } |
529 | 592 |
| 593 // Swaps red and blue channels in each pixel in a 32-bit bitmap. |
| 594 void SwizzleSKBitmap(SkBitmap* bitmap) { |
| 595 int bpp = bitmap->bytesPerPixel(); |
| 596 DCHECK(bpp == 4); |
| 597 for (int y = 0; y < bitmap->height(); y++) { |
| 598 for (int x = 0; x < bitmap->width(); x++) { |
| 599 // Swap channels 0 and 2 (red and blue) |
| 600 int c0 = Channel(bitmap, x, y, 0); |
| 601 int c2 = Channel(bitmap, x, y, 2); |
| 602 SetChannel(bitmap, x, y, 2, c0); |
| 603 SetChannel(bitmap, x, y, 0, c2); |
| 604 } |
| 605 } |
| 606 } |
| 607 |
530 // gl_helper scales recursively, so we'll need to do that | 608 // gl_helper scales recursively, so we'll need to do that |
531 // in the reference implementation too. | 609 // in the reference implementation too. |
532 void ScaleSlowRecursive(SkBitmap* input, | 610 void ScaleSlowRecursive(SkBitmap* input, |
533 SkBitmap* output, | 611 SkBitmap* output, |
534 content::GLHelper::ScalerQuality quality) { | 612 content::GLHelper::ScalerQuality quality) { |
535 if (quality == content::GLHelper::SCALER_QUALITY_FAST || | 613 if (quality == content::GLHelper::SCALER_QUALITY_FAST || |
536 quality == content::GLHelper::SCALER_QUALITY_GOOD) { | 614 quality == content::GLHelper::SCALER_QUALITY_GOOD) { |
537 ScaleSlow(input, output, quality); | 615 ScaleSlow(input, output, quality); |
538 return; | 616 return; |
539 } | 617 } |
(...skipping 28 matching lines...) Expand all Loading... |
568 } | 646 } |
569 } | 647 } |
570 | 648 |
571 SkBitmap tmp; | 649 SkBitmap tmp; |
572 tmp.allocN32Pixels(xtmp, ytmp); | 650 tmp.allocN32Pixels(xtmp, ytmp); |
573 | 651 |
574 ScaleSlowRecursive(input, &tmp, quality); | 652 ScaleSlowRecursive(input, &tmp, quality); |
575 ScaleSlowRecursive(&tmp, output, quality); | 653 ScaleSlowRecursive(&tmp, output, quality); |
576 } | 654 } |
577 | 655 |
| 656 // Creates an RGBA SkBitmap |
| 657 scoped_ptr<SkBitmap> CreateTestBitmap(int width, |
| 658 int height, |
| 659 int test_pattern) { |
| 660 scoped_ptr<SkBitmap> bitmap(new SkBitmap); |
| 661 bitmap->allocPixels(SkImageInfo::Make( |
| 662 width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); |
| 663 |
| 664 for (int x = 0; x < width; ++x) { |
| 665 for (int y = 0; y < height; ++y) { |
| 666 switch (test_pattern) { |
| 667 case 0: // Smooth test pattern |
| 668 SetChannel(bitmap.get(), x, y, 0, x * 10); |
| 669 SetChannel(bitmap.get(), x, y, 0, y == 0 ? x * 50 : x * 10); |
| 670 SetChannel(bitmap.get(), x, y, 1, y * 10); |
| 671 SetChannel(bitmap.get(), x, y, 2, (x + y) * 10); |
| 672 SetChannel(bitmap.get(), x, y, 3, 255); |
| 673 break; |
| 674 case 1: // Small blocks |
| 675 SetChannel(bitmap.get(), x, y, 0, x & 1 ? 255 : 0); |
| 676 SetChannel(bitmap.get(), x, y, 1, y & 1 ? 255 : 0); |
| 677 SetChannel(bitmap.get(), x, y, 2, (x + y) & 1 ? 255 : 0); |
| 678 SetChannel(bitmap.get(), x, y, 3, 255); |
| 679 break; |
| 680 case 2: // Medium blocks |
| 681 SetChannel(bitmap.get(), x, y, 0, 10 + x / 2 * 50); |
| 682 SetChannel(bitmap.get(), x, y, 1, 10 + y / 3 * 50); |
| 683 SetChannel(bitmap.get(), x, y, 2, (x + y) / 5 * 50 + 5); |
| 684 SetChannel(bitmap.get(), x, y, 3, 255); |
| 685 break; |
| 686 } |
| 687 } |
| 688 } |
| 689 return bitmap.Pass(); |
| 690 } |
| 691 |
| 692 // Binds texture and framebuffer and loads the bitmap pixels into the texture. |
| 693 void BindTextureAndFrameBuffer(WebGLId texture, |
| 694 WebGLId framebuffer, |
| 695 SkBitmap* bitmap, |
| 696 int width, |
| 697 int height) { |
| 698 context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| 699 context_->bindTexture(GL_TEXTURE_2D, texture); |
| 700 context_->texImage2D(GL_TEXTURE_2D, |
| 701 0, |
| 702 GL_RGBA, |
| 703 width, |
| 704 height, |
| 705 0, |
| 706 GL_RGBA, |
| 707 GL_UNSIGNED_BYTE, |
| 708 bitmap->getPixels()); |
| 709 } |
| 710 |
| 711 // Create a test image, transform it using |
| 712 // GLHelper::CropScaleReadbackAndCleanTexture and a reference implementation |
| 713 // and compare the results. |
| 714 void TestCropScaleReadbackAndCleanTexture(int xsize, |
| 715 int ysize, |
| 716 int scaled_xsize, |
| 717 int scaled_ysize, |
| 718 int test_pattern, |
| 719 SkColorType out_color_type, |
| 720 bool swizzle, |
| 721 size_t quality_index) { |
| 722 DCHECK(out_color_type == kAlpha_8_SkColorType || |
| 723 out_color_type == kRGBA_8888_SkColorType || |
| 724 out_color_type == kBGRA_8888_SkColorType); |
| 725 WebGLId src_texture = context_->createTexture(); |
| 726 WebGLId framebuffer = context_->createFramebuffer(); |
| 727 scoped_ptr<SkBitmap> input_pixels = |
| 728 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); |
| 729 BindTextureAndFrameBuffer( |
| 730 src_texture, framebuffer, input_pixels.get(), xsize, ysize); |
| 731 |
| 732 std::string message = base::StringPrintf( |
| 733 "input size: %dx%d " |
| 734 "output size: %dx%d " |
| 735 "pattern: %d , quality: %s, " |
| 736 "out_color_type: %d", |
| 737 xsize, |
| 738 ysize, |
| 739 scaled_xsize, |
| 740 scaled_ysize, |
| 741 test_pattern, |
| 742 kQualityNames[quality_index], |
| 743 out_color_type); |
| 744 |
| 745 // Transform the bitmap using GLHelper::CropScaleReadbackAndCleanTexture. |
| 746 SkBitmap output_pixels; |
| 747 output_pixels.allocPixels(SkImageInfo::Make( |
| 748 scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); |
| 749 base::RunLoop run_loop; |
| 750 gfx::Size encoded_texture_size; |
| 751 helper_->CropScaleReadbackAndCleanTexture( |
| 752 src_texture, |
| 753 gfx::Size(xsize, ysize), |
| 754 gfx::Rect(xsize, ysize), |
| 755 gfx::Size(scaled_xsize, scaled_ysize), |
| 756 static_cast<unsigned char*>(output_pixels.getPixels()), |
| 757 out_color_type, |
| 758 base::Bind(&callcallback, run_loop.QuitClosure()), |
| 759 kQualities[quality_index]); |
| 760 run_loop.Run(); |
| 761 // CropScaleReadbackAndCleanTexture flips the pixels. Flip them back. |
| 762 FlipSKBitmap(&output_pixels); |
| 763 |
| 764 // If the bitmap shouldn't have changed - compare against input. |
| 765 if (xsize == scaled_xsize && ysize == scaled_ysize && |
| 766 out_color_type != kAlpha_8_SkColorType) { |
| 767 const std::vector<GLHelperScaling::ScalerStage> dummy_stages; |
| 768 Compare(input_pixels.get(), |
| 769 &output_pixels, |
| 770 0, |
| 771 NULL, |
| 772 dummy_stages, |
| 773 message + " comparing against input"); |
| 774 return; |
| 775 } |
| 776 |
| 777 // Now transform the bitmap using the reference implementation. |
| 778 SkBitmap scaled_pixels; |
| 779 scaled_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, |
| 780 scaled_ysize, |
| 781 kRGBA_8888_SkColorType, |
| 782 kPremul_SkAlphaType)); |
| 783 SkBitmap truth_pixels; |
| 784 // Step 1: Scale |
| 785 ScaleSlowRecursive( |
| 786 input_pixels.get(), &scaled_pixels, kQualities[quality_index]); |
| 787 // Step 2: Encode to grayscale if needed. |
| 788 if (out_color_type == kAlpha_8_SkColorType) { |
| 789 truth_pixels.allocPixels(SkImageInfo::Make( |
| 790 scaled_xsize, scaled_ysize, out_color_type, kPremul_SkAlphaType)); |
| 791 EncodeToGrayscaleSlow(&scaled_pixels, &truth_pixels); |
| 792 } else { |
| 793 truth_pixels = scaled_pixels; |
| 794 } |
| 795 |
| 796 // Now compare the results. |
| 797 SkAutoLockPixels lock_input(truth_pixels); |
| 798 const std::vector<GLHelperScaling::ScalerStage> dummy_stages; |
| 799 Compare(&truth_pixels, |
| 800 &output_pixels, |
| 801 2, |
| 802 input_pixels.get(), |
| 803 dummy_stages, |
| 804 message + " comparing against transformed/scaled"); |
| 805 |
| 806 context_->deleteTexture(src_texture); |
| 807 context_->deleteFramebuffer(framebuffer); |
| 808 } |
| 809 |
578 // Scaling test: Create a test image, scale it using GLHelperScaling | 810 // Scaling test: Create a test image, scale it using GLHelperScaling |
579 // and a reference implementation and compare the results. | 811 // and a reference implementation and compare the results. |
580 void TestScale(int xsize, | 812 void TestScale(int xsize, |
581 int ysize, | 813 int ysize, |
582 int scaled_xsize, | 814 int scaled_xsize, |
583 int scaled_ysize, | 815 int scaled_ysize, |
584 int test_pattern, | 816 int test_pattern, |
585 size_t quality, | 817 size_t quality_index, |
586 bool flip) { | 818 bool flip) { |
587 WebGLId src_texture = context_->createTexture(); | 819 WebGLId src_texture = context_->createTexture(); |
588 WebGLId framebuffer = context_->createFramebuffer(); | 820 WebGLId framebuffer = context_->createFramebuffer(); |
589 SkBitmap input_pixels; | 821 scoped_ptr<SkBitmap> input_pixels = |
590 input_pixels.allocN32Pixels(xsize, ysize); | 822 CreateTestBitmap(xsize, ysize, test_pattern).Pass(); |
591 | 823 BindTextureAndFrameBuffer( |
592 for (int x = 0; x < xsize; ++x) { | 824 src_texture, framebuffer, input_pixels.get(), xsize, ysize); |
593 for (int y = 0; y < ysize; ++y) { | |
594 switch (test_pattern) { | |
595 case 0: // Smooth test pattern | |
596 SetChannel(&input_pixels, x, y, 0, x * 10); | |
597 SetChannel(&input_pixels, x, y, 1, y * 10); | |
598 SetChannel(&input_pixels, x, y, 2, (x + y) * 10); | |
599 SetChannel(&input_pixels, x, y, 3, 255); | |
600 break; | |
601 case 1: // Small blocks | |
602 SetChannel(&input_pixels, x, y, 0, x & 1 ? 255 : 0); | |
603 SetChannel(&input_pixels, x, y, 1, y & 1 ? 255 : 0); | |
604 SetChannel(&input_pixels, x, y, 2, (x + y) & 1 ? 255 : 0); | |
605 SetChannel(&input_pixels, x, y, 3, 255); | |
606 break; | |
607 case 2: // Medium blocks | |
608 SetChannel(&input_pixels, x, y, 0, 10 + x / 2 * 50); | |
609 SetChannel(&input_pixels, x, y, 1, 10 + y / 3 * 50); | |
610 SetChannel(&input_pixels, x, y, 2, (x + y) / 5 * 50 + 5); | |
611 SetChannel(&input_pixels, x, y, 3, 255); | |
612 break; | |
613 } | |
614 } | |
615 } | |
616 | |
617 context_->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); | |
618 context_->bindTexture(GL_TEXTURE_2D, src_texture); | |
619 context_->texImage2D(GL_TEXTURE_2D, | |
620 0, | |
621 GL_RGBA, | |
622 xsize, | |
623 ysize, | |
624 0, | |
625 GL_RGBA, | |
626 GL_UNSIGNED_BYTE, | |
627 input_pixels.getPixels()); | |
628 | 825 |
629 std::string message = base::StringPrintf( | 826 std::string message = base::StringPrintf( |
630 "input size: %dx%d " | 827 "input size: %dx%d " |
631 "output size: %dx%d " | 828 "output size: %dx%d " |
632 "pattern: %d quality: %s", | 829 "pattern: %d quality: %s", |
633 xsize, | 830 xsize, |
634 ysize, | 831 ysize, |
635 scaled_xsize, | 832 scaled_xsize, |
636 scaled_ysize, | 833 scaled_ysize, |
637 test_pattern, | 834 test_pattern, |
638 kQualityNames[quality]); | 835 kQualityNames[quality_index]); |
639 | 836 |
640 std::vector<GLHelperScaling::ScalerStage> stages; | 837 std::vector<GLHelperScaling::ScalerStage> stages; |
641 helper_scaling_->ComputeScalerStages(kQualities[quality], | 838 helper_scaling_->ComputeScalerStages(kQualities[quality_index], |
642 gfx::Size(xsize, ysize), | 839 gfx::Size(xsize, ysize), |
643 gfx::Rect(0, 0, xsize, ysize), | 840 gfx::Rect(0, 0, xsize, ysize), |
644 gfx::Size(scaled_xsize, scaled_ysize), | 841 gfx::Size(scaled_xsize, scaled_ysize), |
645 flip, | 842 flip, |
646 false, | 843 false, |
647 &stages); | 844 &stages); |
648 ValidateScalerStages(kQualities[quality], | 845 ValidateScalerStages(kQualities[quality_index], |
649 stages, | 846 stages, |
650 gfx::Size(scaled_xsize, scaled_ysize), | 847 gfx::Size(scaled_xsize, scaled_ysize), |
651 message); | 848 message); |
652 | 849 |
653 WebGLId dst_texture = | 850 WebGLId dst_texture = |
654 helper_->CopyAndScaleTexture(src_texture, | 851 helper_->CopyAndScaleTexture(src_texture, |
655 gfx::Size(xsize, ysize), | 852 gfx::Size(xsize, ysize), |
656 gfx::Size(scaled_xsize, scaled_ysize), | 853 gfx::Size(scaled_xsize, scaled_ysize), |
657 flip, | 854 flip, |
658 kQualities[quality]); | 855 kQualities[quality_index]); |
659 | 856 |
660 SkBitmap output_pixels; | 857 SkBitmap output_pixels; |
661 output_pixels.allocN32Pixels(scaled_xsize, scaled_ysize); | 858 output_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, |
| 859 scaled_ysize, |
| 860 kRGBA_8888_SkColorType, |
| 861 kPremul_SkAlphaType)); |
662 | 862 |
663 helper_->ReadbackTextureSync( | 863 helper_->ReadbackTextureSync( |
664 dst_texture, | 864 dst_texture, |
665 gfx::Rect(0, 0, scaled_xsize, scaled_ysize), | 865 gfx::Rect(0, 0, scaled_xsize, scaled_ysize), |
666 static_cast<unsigned char*>(output_pixels.getPixels()), | 866 static_cast<unsigned char*>(output_pixels.getPixels()), |
667 kRGBA_8888_SkColorType); | 867 kRGBA_8888_SkColorType); |
668 if (flip) { | 868 if (flip) { |
669 // Flip the pixels back. | 869 // Flip the pixels back. |
670 FlipSKBitmap(&output_pixels); | 870 FlipSKBitmap(&output_pixels); |
671 } | 871 } |
| 872 |
| 873 // If the bitmap shouldn't have changed - compare against input. |
672 if (xsize == scaled_xsize && ysize == scaled_ysize) { | 874 if (xsize == scaled_xsize && ysize == scaled_ysize) { |
673 Compare(&input_pixels, | 875 Compare(input_pixels.get(), |
674 &output_pixels, | 876 &output_pixels, |
675 2, | 877 0, |
676 NULL, | 878 NULL, |
677 stages, | 879 stages, |
678 message + " comparing against input"); | 880 message + " comparing against input"); |
| 881 return; |
679 } | 882 } |
| 883 |
| 884 // Now scale the bitmap using the reference implementation. |
680 SkBitmap truth_pixels; | 885 SkBitmap truth_pixels; |
681 truth_pixels.allocN32Pixels(scaled_xsize, scaled_ysize); | 886 truth_pixels.allocPixels(SkImageInfo::Make(scaled_xsize, |
682 | 887 scaled_ysize, |
683 ScaleSlowRecursive(&input_pixels, &truth_pixels, kQualities[quality]); | 888 kRGBA_8888_SkColorType, |
| 889 kPremul_SkAlphaType)); |
| 890 ScaleSlowRecursive( |
| 891 input_pixels.get(), &truth_pixels, kQualities[quality_index]); |
684 Compare(&truth_pixels, | 892 Compare(&truth_pixels, |
685 &output_pixels, | 893 &output_pixels, |
686 2, | 894 2, |
687 &input_pixels, | 895 input_pixels.get(), |
688 stages, | 896 stages, |
689 message + " comparing against scaled"); | 897 message + " comparing against scaled"); |
690 | 898 |
691 context_->deleteTexture(src_texture); | 899 context_->deleteTexture(src_texture); |
692 context_->deleteTexture(dst_texture); | 900 context_->deleteTexture(dst_texture); |
693 context_->deleteFramebuffer(framebuffer); | 901 context_->deleteFramebuffer(framebuffer); |
694 } | 902 } |
695 | 903 |
696 // Create a scaling pipeline and check that it is made up of | 904 // Create a scaling pipeline and check that it is made up of |
697 // valid scaling operations. | 905 // valid scaling operations. |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1006 base::Bind(&callcallback, | 1214 base::Bind(&callcallback, |
1007 run_loop.QuitClosure())); | 1215 run_loop.QuitClosure())); |
1008 run_loop.Run(); | 1216 run_loop.Run(); |
1009 } else { | 1217 } else { |
1010 helper_->ReadbackTextureSync(src_texture, | 1218 helper_->ReadbackTextureSync(src_texture, |
1011 gfx::Rect(src_size), | 1219 gfx::Rect(src_size), |
1012 pixels, | 1220 pixels, |
1013 color_type); | 1221 color_type); |
1014 } | 1222 } |
1015 } | 1223 } |
1016 | |
1017 // Test basic format readback. | 1224 // Test basic format readback. |
1018 bool TestTextureFormatReadback(const gfx::Size& src_size, | 1225 bool TestTextureFormatReadback(const gfx::Size& src_size, |
1019 SkColorType color_type, | 1226 SkColorType color_type, |
1020 bool async) { | 1227 bool async) { |
1021 SkImageInfo info = | 1228 SkImageInfo info = |
1022 SkImageInfo::Make(src_size.width(), | 1229 SkImageInfo::Make(src_size.width(), |
1023 src_size.height(), | 1230 src_size.height(), |
1024 color_type, | 1231 color_type, |
1025 kPremul_SkAlphaType); | 1232 kPremul_SkAlphaType); |
1026 if (!helper_->IsReadbackConfigSupported(color_type)) { | 1233 if (!helper_->IsReadbackConfigSupported(color_type)) { |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1200 unsigned char* Y = truth_frame->data(media::VideoFrame::kYPlane); | 1407 unsigned char* Y = truth_frame->data(media::VideoFrame::kYPlane); |
1201 unsigned char* U = truth_frame->data(media::VideoFrame::kUPlane); | 1408 unsigned char* U = truth_frame->data(media::VideoFrame::kUPlane); |
1202 unsigned char* V = truth_frame->data(media::VideoFrame::kVPlane); | 1409 unsigned char* V = truth_frame->data(media::VideoFrame::kVPlane); |
1203 int32 y_stride = truth_frame->stride(media::VideoFrame::kYPlane); | 1410 int32 y_stride = truth_frame->stride(media::VideoFrame::kYPlane); |
1204 int32 u_stride = truth_frame->stride(media::VideoFrame::kUPlane); | 1411 int32 u_stride = truth_frame->stride(media::VideoFrame::kUPlane); |
1205 int32 v_stride = truth_frame->stride(media::VideoFrame::kVPlane); | 1412 int32 v_stride = truth_frame->stride(media::VideoFrame::kVPlane); |
1206 memset(Y, 0x00, y_stride * output_ysize); | 1413 memset(Y, 0x00, y_stride * output_ysize); |
1207 memset(U, 0x80, u_stride * output_ysize / 2); | 1414 memset(U, 0x80, u_stride * output_ysize / 2); |
1208 memset(V, 0x80, v_stride * output_ysize / 2); | 1415 memset(V, 0x80, v_stride * output_ysize / 2); |
1209 | 1416 |
| 1417 const float kRGBtoYColorWeights[] = {0.257f, 0.504f, 0.098f, 0.0625f}; |
| 1418 const float kRGBtoUColorWeights[] = {-0.148f, -0.291f, 0.439f, 0.5f}; |
| 1419 const float kRGBtoVColorWeights[] = {0.439f, -0.368f, -0.071f, 0.5f}; |
| 1420 |
1210 for (int y = 0; y < ysize; y++) { | 1421 for (int y = 0; y < ysize; y++) { |
1211 for (int x = 0; x < xsize; x++) { | 1422 for (int x = 0; x < xsize; x++) { |
1212 Y[(y + ymargin) * y_stride + x + xmargin] = float_to_byte( | 1423 Y[(y + ymargin) * y_stride + x + xmargin] = float_to_byte( |
1213 ChannelAsFloat(&input_pixels, x, y, 0) * 0.257 + | 1424 ChannelAsFloat(&input_pixels, x, y, 0) * kRGBtoYColorWeights[0] + |
1214 ChannelAsFloat(&input_pixels, x, y, 1) * 0.504 + | 1425 ChannelAsFloat(&input_pixels, x, y, 1) * kRGBtoYColorWeights[1] + |
1215 ChannelAsFloat(&input_pixels, x, y, 2) * 0.098 + 0.0625); | 1426 ChannelAsFloat(&input_pixels, x, y, 2) * kRGBtoYColorWeights[2] + |
| 1427 kRGBtoYColorWeights[3]); |
1216 } | 1428 } |
1217 } | 1429 } |
1218 | 1430 |
1219 for (int y = 0; y < ysize / 2; y++) { | 1431 for (int y = 0; y < ysize / 2; y++) { |
1220 for (int x = 0; x < xsize / 2; x++) { | 1432 for (int x = 0; x < xsize / 2; x++) { |
1221 U[(y + ymargin / 2) * u_stride + x + xmargin / 2] = float_to_byte( | 1433 U[(y + ymargin / 2) * u_stride + x + xmargin / 2] = |
1222 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * -0.148 + | 1434 float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * |
1223 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * -0.291 + | 1435 kRGBtoUColorWeights[0] + |
1224 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * 0.439 + 0.5); | 1436 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * |
1225 V[(y + ymargin / 2) * v_stride + x + xmargin / 2] = float_to_byte( | 1437 kRGBtoUColorWeights[1] + |
1226 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * 0.439 + | 1438 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * |
1227 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * -0.368 + | 1439 kRGBtoUColorWeights[2] + |
1228 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * -0.071 + | 1440 kRGBtoUColorWeights[3]); |
1229 0.5); | 1441 V[(y + ymargin / 2) * v_stride + x + xmargin / 2] = |
| 1442 float_to_byte(Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 0) * |
| 1443 kRGBtoVColorWeights[0] + |
| 1444 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 1) * |
| 1445 kRGBtoVColorWeights[1] + |
| 1446 Bilinear(&input_pixels, x * 2 + 1.0, y * 2 + 1.0, 2) * |
| 1447 kRGBtoVColorWeights[2] + |
| 1448 kRGBtoVColorWeights[3]); |
1230 } | 1449 } |
1231 } | 1450 } |
1232 | 1451 |
1233 ComparePlane(Y, | 1452 ComparePlane(Y, |
1234 output_frame->data(media::VideoFrame::kYPlane), | 1453 output_frame->data(media::VideoFrame::kYPlane), |
1235 2, | 1454 2, |
1236 output_xsize, | 1455 output_xsize, |
1237 y_stride, | 1456 y_stride, |
1238 output_ysize, | 1457 output_ysize, |
1239 &input_pixels, | 1458 &input_pixels, |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1593 } | 1812 } |
1594 } | 1813 } |
1595 } | 1814 } |
1596 } | 1815 } |
1597 | 1816 |
1598 // Per pixel tests, all sizes are small so that we can print | 1817 // Per pixel tests, all sizes are small so that we can print |
1599 // out the generated bitmaps. | 1818 // out the generated bitmaps. |
1600 TEST_F(GLHelperPixelTest, ScaleTest) { | 1819 TEST_F(GLHelperPixelTest, ScaleTest) { |
1601 int sizes[] = {3, 6, 16}; | 1820 int sizes[] = {3, 6, 16}; |
1602 for (int flip = 0; flip <= 1; flip++) { | 1821 for (int flip = 0; flip <= 1; flip++) { |
1603 for (size_t q = 0; q < arraysize(kQualities); q++) { | 1822 for (size_t q_index = 0; q_index < arraysize(kQualities); q_index++) { |
1604 for (int x = 0; x < 3; x++) { | 1823 for (int x = 0; x < 3; x++) { |
1605 for (int y = 0; y < 3; y++) { | 1824 for (int y = 0; y < 3; y++) { |
1606 for (int dst_x = 0; dst_x < 3; dst_x++) { | 1825 for (int dst_x = 0; dst_x < 3; dst_x++) { |
1607 for (int dst_y = 0; dst_y < 3; dst_y++) { | 1826 for (int dst_y = 0; dst_y < 3; dst_y++) { |
1608 for (int pattern = 0; pattern < 3; pattern++) { | 1827 for (int pattern = 0; pattern < 3; pattern++) { |
1609 TestScale(sizes[x], | 1828 TestScale(sizes[x], |
1610 sizes[y], | 1829 sizes[y], |
1611 sizes[dst_x], | 1830 sizes[dst_x], |
1612 sizes[dst_y], | 1831 sizes[dst_y], |
1613 pattern, | 1832 pattern, |
1614 q, | 1833 q_index, |
1615 flip == 1); | 1834 flip == 1); |
1616 if (HasFailure()) { | 1835 if (HasFailure()) { |
1617 return; | 1836 return; |
1618 } | 1837 } |
1619 } | 1838 } |
1620 } | 1839 } |
1621 } | 1840 } |
1622 } | 1841 } |
1623 } | 1842 } |
1624 } | 1843 } |
1625 } | 1844 } |
1626 } | 1845 } |
1627 | 1846 |
| 1847 // Per pixel tests, all sizes are small so that we can print |
| 1848 // out the generated bitmaps. |
| 1849 TEST_F(GLHelperPixelTest, CropScaleReadbackAndCleanTextureTest) { |
| 1850 const int kSizes[] = {3, 6, 16}; |
| 1851 const SkColorType kColorTypes[] = { |
| 1852 kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType}; |
| 1853 for (size_t color_type = 0; color_type < arraysize(kColorTypes); |
| 1854 color_type++) { |
| 1855 // Test BEST and FAST qualities, skip GOOD |
| 1856 for (size_t q_index = 0; q_index < arraysize(kQualities); q_index += 2) { |
| 1857 for (size_t x = 0; x < arraysize(kSizes); x++) { |
| 1858 for (size_t y = 0; y < arraysize(kSizes); y++) { |
| 1859 for (size_t dst_x = 0; dst_x < arraysize(kSizes); dst_x++) { |
| 1860 for (size_t dst_y = 0; dst_y < arraysize(kSizes); dst_y++) { |
| 1861 for (int pattern = 0; pattern < 3; pattern++) { |
| 1862 TestCropScaleReadbackAndCleanTexture(kSizes[x], |
| 1863 kSizes[y], |
| 1864 kSizes[dst_x], |
| 1865 kSizes[dst_y], |
| 1866 pattern, |
| 1867 kColorTypes[color_type], |
| 1868 false, |
| 1869 q_index); |
| 1870 if (HasFailure()) |
| 1871 return; |
| 1872 } |
| 1873 } |
| 1874 } |
| 1875 } |
| 1876 } |
| 1877 } |
| 1878 } |
| 1879 } |
| 1880 |
1628 // Validate that all scaling generates valid pipelines. | 1881 // Validate that all scaling generates valid pipelines. |
1629 TEST_F(GLHelperTest, ValidateScalerPipelines) { | 1882 TEST_F(GLHelperTest, ValidateScalerPipelines) { |
1630 int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; | 1883 int sizes[] = {7, 99, 128, 256, 512, 719, 720, 721, 1920, 2011, 3217, 4096}; |
1631 for (size_t q = 0; q < arraysize(kQualities); q++) { | 1884 for (size_t q = 0; q < arraysize(kQualities); q++) { |
1632 for (size_t x = 0; x < arraysize(sizes); x++) { | 1885 for (size_t x = 0; x < arraysize(sizes); x++) { |
1633 for (size_t y = 0; y < arraysize(sizes); y++) { | 1886 for (size_t y = 0; y < arraysize(sizes); y++) { |
1634 for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) { | 1887 for (size_t dst_x = 0; dst_x < arraysize(sizes); dst_x++) { |
1635 for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) { | 1888 for (size_t dst_y = 0; dst_y < arraysize(sizes); dst_y++) { |
1636 TestScalerPipeline( | 1889 TestScalerPipeline( |
1637 q, sizes[x], sizes[y], sizes[dst_x], sizes[dst_y]); | 1890 q, sizes[x], sizes[y], sizes[dst_x], sizes[dst_y]); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1701 base::CommandLine::Init(argc, argv); | 1954 base::CommandLine::Init(argc, argv); |
1702 base::TestSuite* suite = new content::ContentTestSuite(argc, argv); | 1955 base::TestSuite* suite = new content::ContentTestSuite(argc, argv); |
1703 #if defined(OS_MACOSX) | 1956 #if defined(OS_MACOSX) |
1704 base::mac::ScopedNSAutoreleasePool pool; | 1957 base::mac::ScopedNSAutoreleasePool pool; |
1705 #endif | 1958 #endif |
1706 | 1959 |
1707 content::UnitTestTestSuite runner(suite); | 1960 content::UnitTestTestSuite runner(suite); |
1708 base::MessageLoop message_loop; | 1961 base::MessageLoop message_loop; |
1709 return runner.Run(); | 1962 return runner.Run(); |
1710 } | 1963 } |
OLD | NEW |