Home | History | Annotate | Download | only in core
      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