Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / renderer_host / compositing_iosurface_transformer_mac_unittest.cc
blob7d9452fd01e0a6c2cd8863e0c20664135905d1e8
1 // Copyright (c) 2013 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.
5 #include "content/browser/renderer_host/compositing_iosurface_transformer_mac.h"
7 #include <OpenGL/CGLCurrent.h>
8 #include <OpenGL/CGLRenderers.h>
9 #include <OpenGL/CGLTypes.h>
10 #include <OpenGL/OpenGL.h>
11 #include <OpenGL/gl.h>
12 #include <OpenGL/glu.h>
14 #include <algorithm>
15 #include <cstdlib>
16 #include <sstream>
17 #include <vector>
19 #include "base/logging.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
22 #include "media/base/yuv_convert.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/skia/include/core/SkBitmap.h"
25 #include "third_party/skia/include/core/SkCanvas.h"
26 #include "third_party/skia/include/core/SkColor.h"
27 #include "third_party/skia/include/core/SkRect.h"
28 #include "ui/gfx/rect.h"
30 namespace content {
32 #define EXPECT_NO_GL_ERROR(stmt) \
33 do { \
34 stmt; \
35 const GLenum error_code = glGetError(); \
36 EXPECT_TRUE(GL_NO_ERROR == error_code) \
37 << "for error code " << error_code \
38 << ": " << gluErrorString(error_code); \
39 } while(0)
41 namespace {
43 const GLenum kGLTextureTarget = GL_TEXTURE_RECTANGLE_ARB;
45 enum RendererRestriction {
46 RESTRICTION_NONE,
47 RESTRICTION_SOFTWARE_ONLY,
48 RESTRICTION_HARDWARE_ONLY
51 bool InitializeGLContext(CGLContextObj* context,
52 RendererRestriction restriction) {
53 std::vector<CGLPixelFormatAttribute> attribs;
54 // Select off-screen renderers only.
55 attribs.push_back(kCGLPFAOffScreen);
56 // By default, the library will prefer hardware-accelerated renderers, but
57 // falls back on the software ones if necessary. However, there are use cases
58 // where we want to force a restriction (e.g., benchmarking performance).
59 if (restriction == RESTRICTION_SOFTWARE_ONLY) {
60 attribs.push_back(kCGLPFARendererID);
61 attribs.push_back(static_cast<CGLPixelFormatAttribute>(
62 kCGLRendererGenericFloatID));
63 } else if (restriction == RESTRICTION_HARDWARE_ONLY) {
64 attribs.push_back(kCGLPFAAccelerated);
66 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
68 CGLPixelFormatObj format;
69 GLint num_pixel_formats = 0;
70 bool success = true;
71 if (CGLChoosePixelFormat(&attribs.front(), &format, &num_pixel_formats) !=
72 kCGLNoError) {
73 LOG(ERROR) << "Error choosing pixel format.";
74 success = false;
76 if (success && num_pixel_formats <= 0) {
77 LOG(ERROR) << "num_pixel_formats <= 0; actual value is "
78 << num_pixel_formats;
79 success = false;
81 if (success && CGLCreateContext(format, NULL, context) != kCGLNoError) {
82 LOG(ERROR) << "Error creating context.";
83 success = false;
85 CGLDestroyPixelFormat(format);
86 return success;
89 // Returns a decent test pattern for testing all of: 1) orientation, 2) scaling,
90 // 3) color space conversion (e.g., 4 pixels --> one U or V pixel), and 4)
91 // texture alignment/processing. Example 32x32 bitmap:
93 // GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
94 // GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
95 // GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
96 // GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
97 // GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
98 // GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
99 // GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
100 // GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
101 // RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
102 // RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
103 // YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
104 // YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
105 // RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
106 // RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
107 // YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
108 // YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
110 // Key: G = Gray, R = Red, B = Blue, Y = Yellow, C = Cyan
111 SkBitmap GenerateTestPatternBitmap(const gfx::Size& size) {
112 SkBitmap bitmap;
113 bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
114 CHECK(bitmap.allocPixels());
115 SkAutoLockPixels lock_bitmap(bitmap);
116 bitmap.eraseColor(SK_ColorGRAY);
117 for (int y = 0; y < size.height(); ++y) {
118 uint32_t* p = bitmap.getAddr32(0, y);
119 for (int x = 0; x < size.width(); ++x, ++p) {
120 if ((x < (size.width() / 2)) && (y < (size.height() / 2)))
121 continue; // Leave upper-left quadrant gray.
122 *p = SkColorSetARGB(255,
123 x % 4 < 2 ? 255 : 0,
124 y % 4 < 2 ? 255 : 0,
125 x % 4 < 2 ? 0 : 255);
128 return bitmap;
131 // Creates a new texture consisting of the given |bitmap|.
132 GLuint CreateTextureWithImage(const SkBitmap& bitmap) {
133 GLuint texture;
134 EXPECT_NO_GL_ERROR(glGenTextures(1, &texture));
135 EXPECT_NO_GL_ERROR(glBindTexture(kGLTextureTarget, texture));
137 SkAutoLockPixels lock_bitmap(bitmap);
138 EXPECT_NO_GL_ERROR(glTexImage2D(
139 kGLTextureTarget, 0, GL_RGBA, bitmap.width(), bitmap.height(), 0,
140 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, bitmap.getPixels()));
142 glBindTexture(kGLTextureTarget, 0);
143 return texture;
146 // Read back a texture from the GPU, returning the image data as an SkBitmap.
147 SkBitmap ReadBackTexture(GLuint texture, const gfx::Size& size, GLenum format) {
148 SkBitmap result;
149 result.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
150 CHECK(result.allocPixels());
152 GLuint frame_buffer;
153 EXPECT_NO_GL_ERROR(glGenFramebuffersEXT(1, &frame_buffer));
154 EXPECT_NO_GL_ERROR(
155 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frame_buffer));
156 EXPECT_NO_GL_ERROR(glFramebufferTexture2DEXT(
157 GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, kGLTextureTarget,
158 texture, 0));
159 DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
160 GL_FRAMEBUFFER_COMPLETE_EXT);
163 SkAutoLockPixels lock_result(result);
164 EXPECT_NO_GL_ERROR(glReadPixels(
165 0, 0, size.width(), size.height(), format, GL_UNSIGNED_INT_8_8_8_8_REV,
166 result.getPixels()));
169 EXPECT_NO_GL_ERROR(glDeleteFramebuffersEXT(1, &frame_buffer));
171 return result;
174 // Returns the |src_rect| region of |src| scaled to |to_size| by drawing on a
175 // Skia canvas, and using bilinear filtering (just like a GPU would).
176 SkBitmap ScaleBitmapWithSkia(const SkBitmap& src,
177 const gfx::Rect& src_rect,
178 const gfx::Size& to_size) {
179 SkBitmap cropped_src;
180 if (src_rect == gfx::Rect(0, 0, src.width(), src.height())) {
181 cropped_src = src;
182 } else {
183 CHECK(src.extractSubset(
184 &cropped_src,
185 SkIRect::MakeXYWH(src_rect.x(), src_rect.y(),
186 src_rect.width(), src_rect.height())));
189 SkBitmap result;
190 result.setConfig(cropped_src.config(), to_size.width(), to_size.height());
191 CHECK(result.allocPixels());
193 SkCanvas canvas(result);
194 canvas.scale(static_cast<double>(result.width()) / cropped_src.width(),
195 static_cast<double>(result.height()) / cropped_src.height());
196 SkPaint paint;
197 paint.setFilterBitmap(true); // Use bilinear filtering.
198 canvas.drawBitmap(cropped_src, 0, 0, &paint);
200 return result;
203 // The maximum value by which a pixel value may deviate from the expected value
204 // before considering it "significantly different." This is meant to account
205 // for the slight differences in filtering techniques used between the various
206 // GPUs and software implementations.
207 const int kDifferenceThreshold = 16;
209 // Returns the number of pixels significantly different between |expected| and
210 // |actual|.
211 int ImageDifference(const SkBitmap& expected, const SkBitmap& actual) {
212 SkAutoLockPixels lock_expected(expected);
213 SkAutoLockPixels lock_actual(actual);
215 // Sanity-check assumed image properties.
216 DCHECK_EQ(expected.width(), actual.width());
217 DCHECK_EQ(expected.height(), actual.height());
218 DCHECK_EQ(SkBitmap::kARGB_8888_Config, expected.config());
219 DCHECK_EQ(SkBitmap::kARGB_8888_Config, actual.config());
221 // Compare both images.
222 int num_pixels_different = 0;
223 for (int y = 0; y < expected.height(); ++y) {
224 const uint32_t* p = expected.getAddr32(0, y);
225 const uint32_t* q = actual.getAddr32(0, y);
226 for (int x = 0; x < expected.width(); ++x, ++p, ++q) {
227 if (abs(static_cast<int>(SkColorGetR(*p)) -
228 static_cast<int>(SkColorGetR(*q))) > kDifferenceThreshold ||
229 abs(static_cast<int>(SkColorGetG(*p)) -
230 static_cast<int>(SkColorGetG(*q))) > kDifferenceThreshold ||
231 abs(static_cast<int>(SkColorGetB(*p)) -
232 static_cast<int>(SkColorGetB(*q))) > kDifferenceThreshold) {
233 ++num_pixels_different;
238 return num_pixels_different;
241 // Returns the number of pixels significantly different between |expected| and
242 // |actual|. It is understood that |actual| contains 4-byte quads, and so we
243 // may need to be ignoring a mod-4 number of pixels at the end of each of its
244 // rows.
245 int ImagePlaneDifference(const uint8* expected, const SkBitmap& actual,
246 const gfx::Size& dst_size) {
247 SkAutoLockPixels actual_lock(actual);
249 int num_pixels_different = 0;
250 for (int y = 0; y < dst_size.height(); ++y) {
251 const uint8* p = expected + y * dst_size.width();
252 const uint8* const p_end = p + dst_size.width();
253 const uint8* q =
254 reinterpret_cast<uint8*>(actual.getPixels()) + y * actual.rowBytes();
255 for (; p < p_end; ++p, ++q) {
256 if (abs(static_cast<int>(*p) - static_cast<int>(*q)) >
257 kDifferenceThreshold) {
258 ++num_pixels_different;
263 return num_pixels_different;
266 } // namespace
268 // Note: All tests fixtures operate within an off-screen OpenGL context.
269 class CompositingIOSurfaceTransformerTest : public testing::Test {
270 public:
271 CompositingIOSurfaceTransformerTest() {
272 // TODO(miu): Try to use RESTRICTION_NONE to speed up the execution time of
273 // unit tests, once it's established that the trybots and buildbots behave
274 // well when using the GPU.
275 CHECK(InitializeGLContext(&context_, RESTRICTION_SOFTWARE_ONLY));
276 CGLSetCurrentContext(context_);
277 shader_program_cache_.reset(new CompositingIOSurfaceShaderPrograms());
278 transformer_.reset(new CompositingIOSurfaceTransformer(
279 kGLTextureTarget, false, shader_program_cache_.get()));
282 virtual ~CompositingIOSurfaceTransformerTest() {
283 transformer_->ReleaseCachedGLObjects();
284 shader_program_cache_->Reset();
285 CGLSetCurrentContext(NULL);
286 CGLDestroyContext(context_);
289 protected:
290 void RunResizeTest(const SkBitmap& src_bitmap, const gfx::Rect& src_rect,
291 const gfx::Size& dst_size) {
292 SCOPED_TRACE(::testing::Message()
293 << "src_rect=(" << src_rect.x() << ',' << src_rect.y()
294 << ")x[" << src_rect.width() << 'x' << src_rect.height()
295 << "]; dst_size=[" << dst_size.width() << 'x'
296 << dst_size.height() << ']');
298 // Do the scale operation on the GPU.
299 const GLuint original_texture = CreateTextureWithImage(src_bitmap);
300 ASSERT_NE(0u, original_texture);
301 GLuint scaled_texture = 0u;
302 ASSERT_TRUE(transformer_->ResizeBilinear(
303 original_texture, src_rect, dst_size, &scaled_texture));
304 EXPECT_NE(0u, scaled_texture);
305 CGLFlushDrawable(context_); // Account for some buggy driver impls.
306 const SkBitmap result_bitmap =
307 ReadBackTexture(scaled_texture, dst_size, GL_BGRA);
308 EXPECT_NO_GL_ERROR(glDeleteTextures(1, &original_texture));
310 // Compare the image read back to the version produced by a known-working
311 // software implementation. Allow up to 2 lines of mismatch due to how
312 // implementations disagree on resolving the processing of edges.
313 const SkBitmap expected_bitmap =
314 ScaleBitmapWithSkia(src_bitmap, src_rect, dst_size);
315 EXPECT_GE(std::max(expected_bitmap.width(), expected_bitmap.height()) * 2,
316 ImageDifference(expected_bitmap, result_bitmap));
319 void RunTransformRGBToYV12Test(
320 const SkBitmap& src_bitmap, const gfx::Rect& src_rect,
321 const gfx::Size& dst_size) {
322 SCOPED_TRACE(::testing::Message()
323 << "src_rect=(" << src_rect.x() << ',' << src_rect.y()
324 << ")x[" << src_rect.width() << 'x' << src_rect.height()
325 << "]; dst_size=[" << dst_size.width() << 'x'
326 << dst_size.height() << ']');
328 // Perform the RGB to YV12 conversion.
329 const GLuint original_texture = CreateTextureWithImage(src_bitmap);
330 ASSERT_NE(0u, original_texture);
331 GLuint texture_y = 0u;
332 GLuint texture_u = 0u;
333 GLuint texture_v = 0u;
334 gfx::Size packed_y_size;
335 gfx::Size packed_uv_size;
336 ASSERT_TRUE(transformer_->TransformRGBToYV12(
337 original_texture, src_rect, dst_size,
338 &texture_y, &texture_u, &texture_v, &packed_y_size, &packed_uv_size));
339 EXPECT_NE(0u, texture_y);
340 EXPECT_NE(0u, texture_u);
341 EXPECT_NE(0u, texture_v);
342 EXPECT_FALSE(packed_y_size.IsEmpty());
343 EXPECT_FALSE(packed_uv_size.IsEmpty());
344 EXPECT_NO_GL_ERROR(glDeleteTextures(1, &original_texture));
346 // Read-back the texture for each plane.
347 CGLFlushDrawable(context_); // Account for some buggy driver impls.
348 const GLenum format = shader_program_cache_->rgb_to_yv12_output_format();
349 const SkBitmap result_y_bitmap =
350 ReadBackTexture(texture_y, packed_y_size, format);
351 const SkBitmap result_u_bitmap =
352 ReadBackTexture(texture_u, packed_uv_size, format);
353 const SkBitmap result_v_bitmap =
354 ReadBackTexture(texture_v, packed_uv_size, format);
356 // Compare the Y, U, and V planes read-back to the version produced by a
357 // known-working software implementation. Allow up to 2 lines of mismatch
358 // due to how implementations disagree on resolving the processing of edges.
359 const SkBitmap expected_bitmap =
360 ScaleBitmapWithSkia(src_bitmap, src_rect, dst_size);
361 const gfx::Size dst_uv_size(
362 (dst_size.width() + 1) / 2, (dst_size.height() + 1) / 2);
363 scoped_ptr<uint8[]> expected_y_plane(
364 new uint8[dst_size.width() * dst_size.height()]);
365 scoped_ptr<uint8[]> expected_u_plane(
366 new uint8[dst_uv_size.width() * dst_uv_size.height()]);
367 scoped_ptr<uint8[]> expected_v_plane(
368 new uint8[dst_uv_size.width() * dst_uv_size.height()]);
370 SkAutoLockPixels src_bitmap_lock(expected_bitmap);
371 media::ConvertRGB32ToYUV(
372 reinterpret_cast<const uint8*>(expected_bitmap.getPixels()),
373 expected_y_plane.get(), expected_u_plane.get(),
374 expected_v_plane.get(),
375 expected_bitmap.width(), expected_bitmap.height(),
376 expected_bitmap.rowBytes(),
377 dst_size.width(), (dst_size.width() + 1) / 2);
379 EXPECT_GE(
380 std::max(expected_bitmap.width(), expected_bitmap.height()) * 2,
381 ImagePlaneDifference(expected_y_plane.get(), result_y_bitmap, dst_size))
382 << " for RGB --> Y Plane";
383 EXPECT_GE(
384 std::max(expected_bitmap.width(), expected_bitmap.height()),
385 ImagePlaneDifference(expected_u_plane.get(), result_u_bitmap,
386 dst_uv_size))
387 << " for RGB --> U Plane";
388 EXPECT_GE(
389 std::max(expected_bitmap.width(), expected_bitmap.height()),
390 ImagePlaneDifference(expected_v_plane.get(), result_v_bitmap,
391 dst_uv_size))
392 << " for RGB --> V Plane";
395 CompositingIOSurfaceShaderPrograms* shader_program_cache() const {
396 return shader_program_cache_.get();
399 private:
400 CGLContextObj context_;
401 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache_;
402 scoped_ptr<CompositingIOSurfaceTransformer> transformer_;
404 private:
405 DISALLOW_COPY_AND_ASSIGN(CompositingIOSurfaceTransformerTest);
408 TEST_F(CompositingIOSurfaceTransformerTest, ShaderProgramsCompileAndLink) {
409 // Attempt to use each program, binding its required uniform variables.
410 EXPECT_NO_GL_ERROR(shader_program_cache()->UseBlitProgram());
411 EXPECT_NO_GL_ERROR(shader_program_cache()->UseSolidWhiteProgram());
412 EXPECT_NO_GL_ERROR(shader_program_cache()->UseRGBToYV12Program(1, 1.0f));
413 EXPECT_NO_GL_ERROR(shader_program_cache()->UseRGBToYV12Program(2, 1.0f));
415 EXPECT_NO_GL_ERROR(glUseProgram(0));
418 namespace {
420 const struct TestParameters {
421 int src_width;
422 int src_height;
423 int scaled_width;
424 int scaled_height;
425 } kTestParameters[] = {
426 // Test 1:1 copies, but exposing varying pixel packing configurations.
427 { 64, 64, 64, 64 },
428 { 63, 63, 63, 63 },
429 { 62, 62, 62, 62 },
430 { 61, 61, 61, 61 },
431 { 60, 60, 60, 60 },
432 { 59, 59, 59, 59 },
433 { 58, 58, 58, 58 },
434 { 57, 57, 57, 57 },
435 { 56, 56, 56, 56 },
437 // Even-size, one or both dimensions upscaled.
438 { 32, 32, 64, 32 }, { 32, 32, 32, 64 }, { 32, 32, 64, 64 },
439 // Even-size, one or both dimensions downscaled by 2X.
440 { 32, 32, 16, 32 }, { 32, 32, 32, 16 }, { 32, 32, 16, 16 },
441 // Even-size, one or both dimensions downscaled by 1 pixel.
442 { 32, 32, 31, 32 }, { 32, 32, 32, 31 }, { 32, 32, 31, 31 },
443 // Even-size, one or both dimensions downscaled by 2 pixels.
444 { 32, 32, 30, 32 }, { 32, 32, 32, 30 }, { 32, 32, 30, 30 },
445 // Even-size, one or both dimensions downscaled by 3 pixels.
446 { 32, 32, 29, 32 }, { 32, 32, 32, 29 }, { 32, 32, 29, 29 },
448 // Odd-size, one or both dimensions upscaled.
449 { 33, 33, 66, 33 }, { 33, 33, 33, 66 }, { 33, 33, 66, 66 },
450 // Odd-size, one or both dimensions downscaled by 2X.
451 { 33, 33, 16, 33 }, { 33, 33, 33, 16 }, { 33, 33, 16, 16 },
452 // Odd-size, one or both dimensions downscaled by 1 pixel.
453 { 33, 33, 32, 33 }, { 33, 33, 33, 32 }, { 33, 33, 32, 32 },
454 // Odd-size, one or both dimensions downscaled by 2 pixels.
455 { 33, 33, 31, 33 }, { 33, 33, 33, 31 }, { 33, 33, 31, 31 },
456 // Odd-size, one or both dimensions downscaled by 3 pixels.
457 { 33, 33, 30, 33 }, { 33, 33, 33, 30 }, { 33, 33, 30, 30 },
460 } // namespace
462 TEST_F(CompositingIOSurfaceTransformerTest, ResizesTexturesCorrectly) {
463 for (size_t i = 0; i < arraysize(kTestParameters); ++i) {
464 SCOPED_TRACE(::testing::Message() << "kTestParameters[" << i << ']');
466 const TestParameters& params = kTestParameters[i];
467 const gfx::Size src_size(params.src_width, params.src_height);
468 const gfx::Size dst_size(params.scaled_width, params.scaled_height);
469 const SkBitmap src_bitmap = GenerateTestPatternBitmap(src_size);
471 // Full texture resize test.
472 RunResizeTest(src_bitmap, gfx::Rect(src_size), dst_size);
473 // Subrect resize test: missing top row in source.
474 RunResizeTest(src_bitmap,
475 gfx::Rect(0, 1, params.src_width, params.src_height - 1),
476 dst_size);
477 // Subrect resize test: missing left column in source.
478 RunResizeTest(src_bitmap,
479 gfx::Rect(1, 0, params.src_width - 1, params.src_height),
480 dst_size);
481 // Subrect resize test: missing top+bottom rows, and left column in source.
482 RunResizeTest(src_bitmap,
483 gfx::Rect(1, 1, params.src_width - 1, params.src_height - 2),
484 dst_size);
485 // Subrect resize test: missing top row, and left+right columns in source.
486 RunResizeTest(src_bitmap,
487 gfx::Rect(1, 1, params.src_width - 2, params.src_height - 1),
488 dst_size);
492 TEST_F(CompositingIOSurfaceTransformerTest, TransformsRGBToYV12) {
493 static const GLenum kOutputFormats[] = { GL_BGRA, GL_RGBA };
495 for (size_t i = 0; i < arraysize(kOutputFormats); ++i) {
496 SCOPED_TRACE(::testing::Message() << "kOutputFormats[" << i << ']');
498 shader_program_cache()->SetOutputFormatForTesting(kOutputFormats[i]);
500 for (size_t j = 0; j < arraysize(kTestParameters); ++j) {
501 SCOPED_TRACE(::testing::Message() << "kTestParameters[" << j << ']');
503 const TestParameters& params = kTestParameters[j];
504 const gfx::Size src_size(params.src_width, params.src_height);
505 const gfx::Size dst_size(params.scaled_width, params.scaled_height);
506 const SkBitmap src_bitmap = GenerateTestPatternBitmap(src_size);
508 // Full texture resize test.
509 RunTransformRGBToYV12Test(src_bitmap, gfx::Rect(src_size), dst_size);
510 // Subrect resize test: missing top row in source.
511 RunTransformRGBToYV12Test(
512 src_bitmap, gfx::Rect(0, 1, params.src_width, params.src_height - 1),
513 dst_size);
514 // Subrect resize test: missing left column in source.
515 RunTransformRGBToYV12Test(
516 src_bitmap, gfx::Rect(1, 0, params.src_width - 1, params.src_height),
517 dst_size);
518 // Subrect resize test: missing top+bottom rows, and left column in
519 // source.
520 RunTransformRGBToYV12Test(
521 src_bitmap,
522 gfx::Rect(1, 1, params.src_width - 1, params.src_height - 2),
523 dst_size);
524 // Subrect resize test: missing top row, and left+right columns in source.
525 RunTransformRGBToYV12Test(
526 src_bitmap,
527 gfx::Rect(1, 1, params.src_width - 2, params.src_height - 1),
528 dst_size);
533 } // namespace content