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 (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