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() || kUnknown_SkColorType == this->colorType()) {
     15         return false;
     16     }
     17 
     18     if (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 = this->bytesPerPixel() >> 1;
     27     int width = this->width();
     28     int height = this->height();
     29 
     30     // check if there's nothing to do
     31     if ((dx | dy) == 0 || width <= 0 || height <= 0) {
     32         if (inval) {
     33             inval->setEmpty();
     34         }
     35         return true;
     36     }
     37 
     38     // compute the inval region now, before we see if there are any pixels
     39     if (inval) {
     40         SkIRect r;
     41 
     42         r.set(0, 0, width, height);
     43         // initial the region with the entire bounds
     44         inval->setRect(r);
     45         // do the "scroll"
     46         r.offset(dx, dy);
     47 
     48         // check if we scrolled completely away
     49         if (!SkIRect::Intersects(r, inval->getBounds())) {
     50             // inval has already been updated...
     51             return true;
     52         }
     53 
     54         // compute the dirty area
     55         inval->op(r, SkRegion::kDifference_Op);
     56     }
     57 
     58     SkAutoLockPixels    alp(*this);
     59     // if we have no pixels, just return (inval is already updated)
     60     // don't call readyToDraw(), since we don't require a colortable per se
     61     if (this->getPixels() == NULL) {
     62         return true;
     63     }
     64 
     65     char*       dst = (char*)this->getPixels();
     66     const char* src = dst;
     67     int         rowBytes = (int)this->rowBytes();    // need rowBytes to be signed
     68 
     69     if (dy <= 0) {
     70         src -= dy * rowBytes;
     71         height += dy;
     72     } else {
     73         dst += dy * rowBytes;
     74         height -= dy;
     75         // now jump src/dst to the last scanline
     76         src += (height - 1) * rowBytes;
     77         dst += (height - 1) * rowBytes;
     78         // now invert rowbytes so we copy backwards in the loop
     79         rowBytes = -rowBytes;
     80     }
     81 
     82     if (dx <= 0) {
     83         src -= dx << shift;
     84         width += dx;
     85     } else {
     86         dst += dx << shift;
     87         width -= dx;
     88     }
     89 
     90     // If the X-translation would push it completely beyond the region,
     91     // then there's nothing to draw.
     92     if (width <= 0) {
     93         return true;
     94     }
     95 
     96     width <<= shift;    // now width is the number of bytes to move per line
     97     while (--height >= 0) {
     98         memmove(dst, src, width);
     99         dst += rowBytes;
    100         src += rowBytes;
    101     }
    102 
    103     this->notifyPixelsChanged();
    104     return true;
    105 }
    106