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