1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "SkBitmap.h" 9#include "SkRegion.h" 10 11bool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy, 12 SkRegion* inval) const 13{ 14 if (NULL != subset) { 15 SkBitmap tmp; 16 17 return this->extractSubset(&tmp, *subset) && 18 // now call again with no rectangle 19 tmp.scrollRect(NULL, dx, dy, inval); 20 } 21 22 int shift; 23 24 switch (this->config()) { 25 case kIndex8_Config: 26 case kA8_Config: 27 shift = 0; 28 break; 29 case kARGB_4444_Config: 30 case kRGB_565_Config: 31 shift = 1; 32 break; 33 case kARGB_8888_Config: 34 shift = 2; 35 break; 36 default: 37 // can't scroll this config 38 return false; 39 } 40 41 int width = this->width(); 42 int height = this->height(); 43 44 // check if there's nothing to do 45 if ((dx | dy) == 0 || width <= 0 || height <= 0) { 46 if (NULL != inval) { 47 inval->setEmpty(); 48 } 49 return true; 50 } 51 52 // compute the inval region now, before we see if there are any pixels 53 if (NULL != inval) { 54 SkIRect r; 55 56 r.set(0, 0, width, height); 57 // initial the region with the entire bounds 58 inval->setRect(r); 59 // do the "scroll" 60 r.offset(dx, dy); 61 62 // check if we scrolled completely away 63 if (!SkIRect::Intersects(r, inval->getBounds())) { 64 // inval has already been updated... 65 return true; 66 } 67 68 // compute the dirty area 69 inval->op(r, SkRegion::kDifference_Op); 70 } 71 72 SkAutoLockPixels alp(*this); 73 // if we have no pixels, just return (inval is already updated) 74 // don't call readyToDraw(), since we don't require a colortable per se 75 if (this->getPixels() == NULL) { 76 return true; 77 } 78 79 char* dst = (char*)this->getPixels(); 80 const char* src = dst; 81 int rowBytes = this->rowBytes(); // need rowBytes to be signed 82 83 if (dy <= 0) { 84 src -= dy * rowBytes; 85 height += dy; 86 } else { 87 dst += dy * rowBytes; 88 height -= dy; 89 // now jump src/dst to the last scanline 90 src += (height - 1) * rowBytes; 91 dst += (height - 1) * rowBytes; 92 // now invert rowbytes so we copy backwards in the loop 93 rowBytes = -rowBytes; 94 } 95 96 if (dx <= 0) { 97 src -= dx << shift; 98 width += dx; 99 } else { 100 dst += dx << shift; 101 width -= dx; 102 } 103 104 // If the X-translation would push it completely beyond the region, 105 // then there's nothing to draw. 106 if (width <= 0) { 107 return true; 108 } 109 110 width <<= shift; // now width is the number of bytes to move per line 111 while (--height >= 0) { 112 memmove(dst, src, width); 113 dst += rowBytes; 114 src += rowBytes; 115 } 116 return true; 117} 118