Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / renderer_host / compositing_iosurface_transformer_mac_unittest.cc
blob8e909fd9a5fc291f239718fbfb21b8430a39de58
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 CHECK(bitmap.allocN32Pixels(size.width(), size.height()));
114 bitmap.eraseColor(SK_ColorGRAY);
115 for (int y = 0; y < size.height(); ++y) {
116 uint32_t* p = bitmap.getAddr32(0, y);
117 for (int x = 0; x < size.width(); ++x, ++p) {
118 if ((x < (size.width() / 2)) && (y < (size.height() / 2)))
119 continue; // Leave upper-left quadrant gray.
120 *p = SkColorSetARGB(255,
121 x % 4 < 2 ? 255 : 0,
122 y % 4 < 2 ? 255 : 0,
123 x % 4 < 2 ? 0 : 255);
126 return bitmap;
129 // Creates a new texture consisting of the given |bitmap|.
130 GLuint CreateTextureWithImage(const SkBitmap& bitmap) {
131 GLuint texture;
132 EXPECT_NO_GL_ERROR(glGenTextures(1, &texture));
133 EXPECT_NO_GL_ERROR(glBindTexture(kGLTextureTarget, texture));
135 SkAutoLockPixels lock_bitmap(bitmap);
136 EXPECT_NO_GL_ERROR(glTexImage2D(
137 kGLTextureTarget, 0, GL_RGBA, bitmap.width(), bitmap.height(), 0,
138 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, bitmap.getPixels()));
140 glBindTexture(kGLTextureTarget, 0);
141 return texture;
144 // Read back a texture from the GPU, returning the image data as an SkBitmap.
145 SkBitmap ReadBackTexture(GLuint texture, const gfx::Size& size, GLenum format) {
146 SkBitmap result;
147 CHECK(result.allocN32Pixels(size.width(), size.height()));
149 GLuint frame_buffer;
150 EXPECT_NO_GL_ERROR(glGenFramebuffersEXT(1, &frame_buffer));
151 EXPECT_NO_GL_ERROR(
152 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frame_buffer));
153 EXPECT_NO_GL_ERROR(glFramebufferTexture2DEXT(
154 GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, kGLTextureTarget,
155 texture, 0));
156 DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
157 GL_FRAMEBUFFER_COMPLETE_EXT);
160 SkAutoLockPixels lock_result(result);
161 EXPECT_NO_GL_ERROR(glReadPixels(
162 0, 0, size.width(), size.height(), format, GL_UNSIGNED_INT_8_8_8_8_REV,
163 result.getPixels()));
166 EXPECT_NO_GL_ERROR(glDeleteFramebuffersEXT(1, &frame_buffer));
168 return result;
171 // Returns the |src_rect| region of |src| scaled to |to_size| by drawing on a
172 // Skia canvas, and using bilinear filtering (just like a GPU would).
173 SkBitmap ScaleBitmapWithSkia(const SkBitmap& src,
174 const gfx::Rect& src_rect,
175 const gfx::Size& to_size) {
176 SkBitmap cropped_src;
177 if (src_rect == gfx::Rect(0, 0, src.width(), src.height())) {
178 cropped_src = src;
179 } else {
180 CHECK(src.extractSubset(
181 &cropped_src,
182 SkIRect::MakeXYWH(src_rect.x(), src_rect.y(),
183 src_rect.width(), src_rect.height())));
186 SkBitmap result;
187 CHECK(result.allocPixels(
188 cropped_src.info().makeWH(to_size.width(), to_size.height())));
190 SkCanvas canvas(result);
191 canvas.scale(static_cast<double>(result.width()) / cropped_src.width(),
192 static_cast<double>(result.height()) / cropped_src.height());
193 SkPaint paint;
194 paint.setFilterLevel(SkPaint::kLow_FilterLevel); // Use bilinear filtering.
195 canvas.drawBitmap(cropped_src, 0, 0, &paint);
197 return result;
200 // The maximum value by which a pixel value may deviate from the expected value
201 // before considering it "significantly different." This is meant to account
202 // for the slight differences in filtering techniques used between the various
203 // GPUs and software implementations.
204 const int kDifferenceThreshold = 16;
206 // Returns the number of pixels significantly different between |expected| and
207 // |actual|.
208 int ImageDifference(const SkBitmap& expected, const SkBitmap& actual) {
209 SkAutoLockPixels lock_expected(expected);
210 SkAutoLockPixels lock_actual(actual);
212 // Sanity-check assumed image properties.
213 DCHECK_EQ(expected.width(), actual.width());
214 DCHECK_EQ(expected.height(), actual.height());
215 DCHECK_EQ(kN32_SkColorType, expected.colorType());
216 DCHECK_EQ(kN32_SkColorType, actual.colorType());
218 // Compare both images.
219 int num_pixels_different = 0;
220 for (int y = 0; y < expected.height(); ++y) {
221 const uint32_t* p = expected.getAddr32(0, y);
222 const uint32_t* q = actual.getAddr32(0, y);
223 for (int x = 0; x < expected.width(); ++x, ++p, ++q) {
224 if (abs(static_cast<int>(SkColorGetR(*p)) -
225 static_cast<int>(SkColorGetR(*q))) > kDifferenceThreshold ||
226 abs(static_cast<int>(SkColorGetG(*p)) -
227 static_cast<int>(SkColorGetG(*q))) > kDifferenceThreshold ||
228 abs(static_cast<int>(SkColorGetB(*p)) -
229 static_cast<int>(SkColorGetB(*q))) > kDifferenceThreshold) {
230 ++num_pixels_different;
235 return num_pixels_different;
238 // Returns the number of pixels significantly different between |expected| and
239 // |actual|. It is understood that |actual| contains 4-byte quads, and so we
240 // may need to be ignoring a mod-4 number of pixels at the end of each of its
241 // rows.
242 int ImagePlaneDifference(const uint8* expected, const SkBitmap& actual,
243 const gfx::Size& dst_size) {
244 SkAutoLockPixels actual_lock(actual);
246 int num_pixels_different = 0;
247 for (int y = 0; y < dst_size.height(); ++y) {
248 const uint8* p = expected + y * dst_size.width();
249 const uint8* const p_end = p + dst_size.width();
250 const uint8* q =
251 reinterpret_cast<uint8*>(actual.getPixels()) + y * actual.rowBytes();
252 for (; p < p_end; ++p, ++q) {
253 if (abs(static_cast<int>(*p) - static_cast<int>(*q)) >
254 kDifferenceThreshold) {
255 ++num_pixels_different;
260 return num_pixels_different;
263 } // namespace
265 // Note: All tests fixtures operate within an off-screen OpenGL context.
266 class CompositingIOSurfaceTransformerTest : public testing::Test {
267 public:
268 CompositingIOSurfaceTransformerTest() {
269 // TODO(miu): Try to use RESTRICTION_NONE to speed up the execution time of
270 // unit tests, once it's established that the trybots and buildbots behave
271 // well when using the GPU.
272 CHECK(InitializeGLContext(&context_, RESTRICTION_SOFTWARE_ONLY));
273 CGLSetCurrentContext(context_);
274 shader_program_cache_.reset(new CompositingIOSurfaceShaderPrograms());
275 transformer_.reset(new CompositingIOSurfaceTransformer(
276 kGLTextureTarget, false, shader_program_cache_.get()));
279 virtual ~CompositingIOSurfaceTransformerTest() {
280 transformer_->ReleaseCachedGLObjects();
281 shader_program_cache_->Reset();
282 CGLSetCurrentContext(NULL);
283 CGLDestroyContext(context_);
286 protected:
287 void RunResizeTest(const SkBitmap& src_bitmap, const gfx::Rect& src_rect,
288 const gfx::Size& dst_size) {
289 SCOPED_TRACE(::testing::Message()
290 << "src_rect=(" << src_rect.x() << ',' << src_rect.y()
291 << ")x[" << src_rect.width() << 'x' << src_rect.height()
292 << "]; dst_size=[" << dst_size.width() << 'x'
293 << dst_size.height() << ']');
295 // Do the scale operation on the GPU.
296 const GLuint original_texture = CreateTextureWithImage(src_bitmap);
297 ASSERT_NE(0u, original_texture);
298 GLuint scaled_texture = 0u;
299 ASSERT_TRUE(transformer_->ResizeBilinear(
300 original_texture, src_rect, dst_size, &scaled_texture));
301 EXPECT_NE(0u, scaled_texture);
302 CGLFlushDrawable(context_); // Account for some buggy driver impls.
303 const SkBitmap result_bitmap =
304 ReadBackTexture(scaled_texture, dst_size, GL_BGRA);
305 EXPECT_NO_GL_ERROR(glDeleteTextures(1, &original_texture));
307 // Compare the image read back to the version produced by a known-working
308 // software implementation. Allow up to 2 lines of mismatch due to how
309 // implementations disagree on resolving the processing of edges.
310 const SkBitmap expected_bitmap =
311 ScaleBitmapWithSkia(src_bitmap, src_rect, dst_size);
312 EXPECT_GE(std::max(expected_bitmap.width(), expected_bitmap.height()) * 2,
313 ImageDifference(expected_bitmap, result_bitmap));
316 void RunTransformRGBToYV12Test(
317 const SkBitmap& src_bitmap, const gfx::Rect& src_rect,
318 const gfx::Size& dst_size) {
319 SCOPED_TRACE(::testing::Message()
320 << "src_rect=(" << src_rect.x() << ',' << src_rect.y()
321 << ")x[" << src_rect.width() << 'x' << src_rect.height()
322 << "]; dst_size=[" << dst_size.width() << 'x'
323 << dst_size.height() << ']');
325 // Perform the RGB to YV12 conversion.
326 const GLuint original_texture = CreateTextureWithImage(src_bitmap);
327 ASSERT_NE(0u, original_texture);
328 GLuint texture_y = 0u;
329 GLuint texture_u = 0u;
330 GLuint texture_v = 0u;
331 gfx::Size packed_y_size;
332 gfx::Size packed_uv_size;
333 ASSERT_TRUE(transformer_->TransformRGBToYV12(
334 original_texture, src_rect, dst_size,
335 &texture_y, &texture_u, &texture_v, &packed_y_size, &packed_uv_size));
336 EXPECT_NE(0u, texture_y);
337 EXPECT_NE(0u, texture_u);
338 EXPECT_NE(0u, texture_v);
339 EXPECT_FALSE(packed_y_size.IsEmpty());
340 EXPECT_FALSE(packed_uv_size.IsEmpty());
341 EXPECT_NO_GL_ERROR(glDeleteTextures(1, &original_texture));
343 // Read-back the texture for each plane.
344 CGLFlushDrawable(context_); // Account for some buggy driver impls.
345 const GLenum format = shader_program_cache_->rgb_to_yv12_output_format();
346 const SkBitmap result_y_bitmap =
347 ReadBackTexture(texture_y, packed_y_size, format);
348 const SkBitmap result_u_bitmap =
349 ReadBackTexture(texture_u, packed_uv_size, format);
350 const SkBitmap result_v_bitmap =
351 ReadBackTexture(texture_v, packed_uv_size, format);
353 // Compare the Y, U, and V planes read-back to the version produced by a
354 // known-working software implementation. Allow up to 2 lines of mismatch
355 // due to how implementations disagree on resolving the processing of edges.
356 const SkBitmap expected_bitmap =
357 ScaleBitmapWithSkia(src_bitmap, src_rect, dst_size);
358 const gfx::Size dst_uv_size(
359 (dst_size.width() + 1) / 2, (dst_size.height() + 1) / 2);
360 scoped_ptr<uint8[]> expected_y_plane(
361 new uint8[dst_size.width() * dst_size.height()]);
362 scoped_ptr<uint8[]> expected_u_plane(
363 new uint8[dst_uv_size.width() * dst_uv_size.height()]);
364 scoped_ptr<uint8[]> expected_v_plane(
365 new uint8[dst_uv_size.width() * dst_uv_size.height()]);
367 SkAutoLockPixels src_bitmap_lock(expected_bitmap);
368 media::ConvertRGB32ToYUV(
369 reinterpret_cast<const uint8*>(expected_bitmap.getPixels()),
370 expected_y_plane.get(), expected_u_plane.get(),
371 expected_v_plane.get(),
372 expected_bitmap.width(), expected_bitmap.height(),
373 expected_bitmap.rowBytes(),
374 dst_size.width(), (dst_size.width() + 1) / 2);
376 EXPECT_GE(
377 std::max(expected_bitmap.width(), expected_bitmap.height()) * 2,
378 ImagePlaneDifference(expected_y_plane.get(), result_y_bitmap, dst_size))
379 << " for RGB --> Y Plane";
380 EXPECT_GE(
381 std::max(expected_bitmap.width(), expected_bitmap.height()),
382 ImagePlaneDifference(expected_u_plane.get(), result_u_bitmap,
383 dst_uv_size))
384 << " for RGB --> U Plane";
385 EXPECT_GE(
386 std::max(expected_bitmap.width(), expected_bitmap.height()),
387 ImagePlaneDifference(expected_v_plane.get(), result_v_bitmap,
388 dst_uv_size))
389 << " for RGB --> V Plane";
392 CompositingIOSurfaceShaderPrograms* shader_program_cache() const {
393 return shader_program_cache_.get();
396 private:
397 CGLContextObj context_;
398 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache_;
399 scoped_ptr<CompositingIOSurfaceTransformer> transformer_;
401 private:
402 DISALLOW_COPY_AND_ASSIGN(CompositingIOSurfaceTransformerTest);
405 TEST_F(CompositingIOSurfaceTransformerTest, ShaderProgramsCompileAndLink) {
406 // Attempt to use each program, binding its required uniform variables.
407 EXPECT_NO_GL_ERROR(shader_program_cache()->UseBlitProgram());
408 EXPECT_NO_GL_ERROR(shader_program_cache()->UseSolidWhiteProgram());
409 EXPECT_NO_GL_ERROR(shader_program_cache()->UseRGBToYV12Program(1, 1.0f));
410 EXPECT_NO_GL_ERROR(shader_program_cache()->UseRGBToYV12Program(2, 1.0f));
412 EXPECT_NO_GL_ERROR(glUseProgram(0));
415 namespace {
417 const struct TestParameters {
418 int src_width;
419 int src_height;
420 int scaled_width;
421 int scaled_height;
422 } kTestParameters[] = {
423 // Test 1:1 copies, but exposing varying pixel packing configurations.
424 { 64, 64, 64, 64 },
425 { 63, 63, 63, 63 },
426 { 62, 62, 62, 62 },
427 { 61, 61, 61, 61 },
428 { 60, 60, 60, 60 },
429 { 59, 59, 59, 59 },
430 { 58, 58, 58, 58 },
431 { 57, 57, 57, 57 },
432 { 56, 56, 56, 56 },
434 // Even-size, one or both dimensions upscaled.
435 { 32, 32, 64, 32 }, { 32, 32, 32, 64 }, { 32, 32, 64, 64 },
436 // Even-size, one or both dimensions downscaled by 2X.
437 { 32, 32, 16, 32 }, { 32, 32, 32, 16 }, { 32, 32, 16, 16 },
438 // Even-size, one or both dimensions downscaled by 1 pixel.
439 { 32, 32, 31, 32 }, { 32, 32, 32, 31 }, { 32, 32, 31, 31 },
440 // Even-size, one or both dimensions downscaled by 2 pixels.
441 { 32, 32, 30, 32 }, { 32, 32, 32, 30 }, { 32, 32, 30, 30 },
442 // Even-size, one or both dimensions downscaled by 3 pixels.
443 { 32, 32, 29, 32 }, { 32, 32, 32, 29 }, { 32, 32, 29, 29 },
445 // Odd-size, one or both dimensions upscaled.
446 { 33, 33, 66, 33 }, { 33, 33, 33, 66 }, { 33, 33, 66, 66 },
447 // Odd-size, one or both dimensions downscaled by 2X.
448 { 33, 33, 16, 33 }, { 33, 33, 33, 16 }, { 33, 33, 16, 16 },
449 // Odd-size, one or both dimensions downscaled by 1 pixel.
450 { 33, 33, 32, 33 }, { 33, 33, 33, 32 }, { 33, 33, 32, 32 },
451 // Odd-size, one or both dimensions downscaled by 2 pixels.
452 { 33, 33, 31, 33 }, { 33, 33, 33, 31 }, { 33, 33, 31, 31 },
453 // Odd-size, one or both dimensions downscaled by 3 pixels.
454 { 33, 33, 30, 33 }, { 33, 33, 33, 30 }, { 33, 33, 30, 30 },
457 } // namespace
459 TEST_F(CompositingIOSurfaceTransformerTest, ResizesTexturesCorrectly) {
460 for (size_t i = 0; i < arraysize(kTestParameters); ++i) {
461 SCOPED_TRACE(::testing::Message() << "kTestParameters[" << i << ']');
463 const TestParameters& params = kTestParameters[i];
464 const gfx::Size src_size(params.src_width, params.src_height);
465 const gfx::Size dst_size(params.scaled_width, params.scaled_height);
466 const SkBitmap src_bitmap = GenerateTestPatternBitmap(src_size);
468 // Full texture resize test.
469 RunResizeTest(src_bitmap, gfx::Rect(src_size), dst_size);
470 // Subrect resize test: missing top row in source.
471 RunResizeTest(src_bitmap,
472 gfx::Rect(0, 1, params.src_width, params.src_height - 1),
473 dst_size);
474 // Subrect resize test: missing left column in source.
475 RunResizeTest(src_bitmap,
476 gfx::Rect(1, 0, params.src_width - 1, params.src_height),
477 dst_size);
478 // Subrect resize test: missing top+bottom rows, and left column in source.
479 RunResizeTest(src_bitmap,
480 gfx::Rect(1, 1, params.src_width - 1, params.src_height - 2),
481 dst_size);
482 // Subrect resize test: missing top row, and left+right columns in source.
483 RunResizeTest(src_bitmap,
484 gfx::Rect(1, 1, params.src_width - 2, params.src_height - 1),
485 dst_size);
489 TEST_F(CompositingIOSurfaceTransformerTest, TransformsRGBToYV12) {
490 static const GLenum kOutputFormats[] = { GL_BGRA, GL_RGBA };
492 for (size_t i = 0; i < arraysize(kOutputFormats); ++i) {
493 SCOPED_TRACE(::testing::Message() << "kOutputFormats[" << i << ']');
495 shader_program_cache()->SetOutputFormatForTesting(kOutputFormats[i]);
497 for (size_t j = 0; j < arraysize(kTestParameters); ++j) {
498 SCOPED_TRACE(::testing::Message() << "kTestParameters[" << j << ']');
500 const TestParameters& params = kTestParameters[j];
501 const gfx::Size src_size(params.src_width, params.src_height);
502 const gfx::Size dst_size(params.scaled_width, params.scaled_height);
503 const SkBitmap src_bitmap = GenerateTestPatternBitmap(src_size);
505 // Full texture resize test.
506 RunTransformRGBToYV12Test(src_bitmap, gfx::Rect(src_size), dst_size);
507 // Subrect resize test: missing top row in source.
508 RunTransformRGBToYV12Test(
509 src_bitmap, gfx::Rect(0, 1, params.src_width, params.src_height - 1),
510 dst_size);
511 // Subrect resize test: missing left column in source.
512 RunTransformRGBToYV12Test(
513 src_bitmap, gfx::Rect(1, 0, params.src_width - 1, params.src_height),
514 dst_size);
515 // Subrect resize test: missing top+bottom rows, and left column in
516 // source.
517 RunTransformRGBToYV12Test(
518 src_bitmap,
519 gfx::Rect(1, 1, params.src_width - 1, params.src_height - 2),
520 dst_size);
521 // Subrect resize test: missing top row, and left+right columns in source.
522 RunTransformRGBToYV12Test(
523 src_bitmap,
524 gfx::Rect(1, 1, params.src_width - 2, params.src_height - 1),
525 dst_size);
530 } // namespace content