15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/blit.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/platform_canvas.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/vector2d.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(USE_CAIRO)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_OPENBSD)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cairo.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cairo/cairo.h>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_cftyperef.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the given canvas has any part of itself clipped out or
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// any non-identity tranform.
32c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool HasClipOrTransform(SkCanvas& canvas) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!canvas.getTotalMatrix().isIdentity())
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!canvas.isClipRect())
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we know the clip is a regular rectangle, make sure it covers the
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // entire canvas.
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  SkIRect clip_bounds;
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  canvas.getClipDeviceBounds(&clip_bounds);
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  SkImageInfo info;
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  size_t row_bytes;
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void* pixels = canvas.accessTopLayerPixels(&info, &row_bytes);
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(pixels);
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!pixels)
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return true;
50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (clip_bounds.fLeft != 0 || clip_bounds.fTop != 0 ||
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      clip_bounds.fRight != info.width() ||
53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      clip_bounds.fBottom != info.height())
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlitContextToContext(NativeDrawingContext dst_context,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const Rect& dst_rect,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          NativeDrawingContext src_context,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const Point& src_origin) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BitBlt(dst_context, dst_rect.x(), dst_rect.y(),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         dst_rect.width(), dst_rect.height(),
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         src_context, src_origin.x(), src_origin.y(), SRCCOPY);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only translations and/or vertical flips in the source context are
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // supported; more complex source context transforms will be ignored.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is a translation on the source context, we need to account for
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it ourselves since CGBitmapContextCreateImage will bypass it.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Rect src_rect(src_origin, dst_rect.size());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CGAffineTransform transform = CGContextGetCTM(src_context);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool flipped = fabs(transform.d + 1) < 0.0001;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CGFloat delta_y = flipped ? CGBitmapContextGetHeight(src_context) -
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              transform.ty
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            : transform.ty;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  src_rect.Offset(transform.tx, delta_y);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ScopedCFTypeRef<CGImageRef> src_image(
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      CGBitmapContextCreateImage(src_context));
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ScopedCFTypeRef<CGImageRef> src_sub_image(
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CGImageCreateWithImageInRect(src_image, src_rect.ToCGRect()));
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CGContextDrawImage(dst_context, dst_rect.ToCGRect(), src_sub_image);
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#elif defined(USE_CAIRO)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only translations in the source context are supported; more complex
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // source context transforms will be ignored.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cairo_save(dst_context);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double surface_x = src_origin.x();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double surface_y = src_origin.y();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cairo_user_to_device(src_context, &surface_x, &surface_y);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cairo_set_source_surface(dst_context, cairo_get_target(src_context),
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           dst_rect.x()-surface_x, dst_rect.y()-surface_y);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cairo_rectangle(dst_context, dst_rect.x(), dst_rect.y(),
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  dst_rect.width(), dst_rect.height());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cairo_clip(dst_context);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cairo_paint(dst_context);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cairo_restore(dst_context);
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#else
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  NOTIMPLEMENTED();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlitContextToCanvas(SkCanvas *dst_canvas,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const Rect& dst_rect,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         NativeDrawingContext src_context,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const Point& src_origin) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(skia::SupportsPlatformPaint(dst_canvas));
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BlitContextToContext(skia::BeginPlatformPaint(dst_canvas), dst_rect,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       src_context, src_origin);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  skia::EndPlatformPaint(dst_canvas);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlitCanvasToContext(NativeDrawingContext dst_context,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const Rect& dst_rect,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         SkCanvas *src_canvas,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const Point& src_origin) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(skia::SupportsPlatformPaint(src_canvas));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BlitContextToContext(dst_context, dst_rect,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       skia::BeginPlatformPaint(src_canvas), src_origin);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  skia::EndPlatformPaint(src_canvas);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlitCanvasToCanvas(SkCanvas *dst_canvas,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const Rect& dst_rect,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        SkCanvas *src_canvas,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const Point& src_origin) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(skia::SupportsPlatformPaint(dst_canvas));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(skia::SupportsPlatformPaint(src_canvas));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BlitContextToContext(skia::BeginPlatformPaint(dst_canvas), dst_rect,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       skia::BeginPlatformPaint(src_canvas), src_origin);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  skia::EndPlatformPaint(src_canvas);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  skia::EndPlatformPaint(dst_canvas);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ScrollCanvas(SkCanvas* canvas,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const gfx::Rect& in_clip,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const gfx::Vector2d& offset) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!HasClipOrTransform(*canvas));  // Don't support special stuff.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have a PlatformCanvas, we should use ScrollDC. Otherwise, fall
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // through to the software implementation.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (skia::SupportsPlatformPaint(canvas)) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    skia::ScopedPlatformPaint scoped_platform_paint(canvas);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HDC hdc = scoped_platform_paint.GetPlatformSurface();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RECT damaged_rect;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RECT r = in_clip.ToRECT();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScrollDC(hdc, offset.x(), offset.y(), NULL, &r, NULL, &damaged_rect);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_WIN)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For non-windows, always do scrolling in software.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cairo has no nice scroll function so we do our own. On Mac it's possible to
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use platform scroll code, but it's complex so we just use the same path
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // here. Either way it will be software-only, so it shouldn't matter much.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap& bitmap = const_cast<SkBitmap&>(
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      skia::GetTopDevice(*canvas)->accessBitmap(true));
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkAutoLockPixels lock(bitmap);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We expect all coords to be inside the canvas, so clip here.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect clip = gfx::IntersectRects(
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      in_clip, gfx::Rect(0, 0, bitmap.width(), bitmap.height()));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the set of pixels we'll actually end up painting.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect dest_rect = gfx::IntersectRects(clip + offset, clip);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dest_rect.size().IsEmpty())
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Nothing to do.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the source pixels that will map to the dest_rect
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect src_rect = dest_rect - offset;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t row_bytes = dest_rect.width() * 4;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (offset.y() > 0) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Data is moving down, copy from the bottom up.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = dest_rect.height() - 1; y >= 0; y--) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(bitmap.getAddr32(dest_rect.x(), dest_rect.y() + y),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             bitmap.getAddr32(src_rect.x(), src_rect.y() + y),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             row_bytes);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (offset.y() < 0) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Data is moving up, copy from the top down.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = 0; y < dest_rect.height(); y++) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(bitmap.getAddr32(dest_rect.x(), dest_rect.y() + y),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             bitmap.getAddr32(src_rect.x(), src_rect.y() + y),
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             row_bytes);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (offset.x() != 0) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Horizontal-only scroll. We can do it in either top-to-bottom or bottom-
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to-top, but have to be careful about the order for copying each row.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Fortunately, memmove already handles this for us.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = 0; y < dest_rect.height(); y++) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memmove(bitmap.getAddr32(dest_rect.x(), dest_rect.y() + y),
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              bitmap.getAddr32(src_rect.x(), src_rect.y() + y),
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              row_bytes);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gfx
204