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