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