180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2011 Google Inc.
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkBitmap.h"
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkRegion.h"
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy,
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                          SkRegion* inval) const
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (this->isImmutable()) {
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL != subset) {
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkBitmap tmp;
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return  this->extractSubset(&tmp, *subset) &&
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                // now call again with no rectangle
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                tmp.scrollRect(NULL, dx, dy, inval);
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int shift;
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    switch (this->config()) {
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case kIndex8_Config:
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case kA8_Config:
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        shift = 0;
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        break;
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case kARGB_4444_Config:
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case kRGB_565_Config:
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        shift = 1;
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        break;
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    case kARGB_8888_Config:
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        shift = 2;
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        break;
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    default:
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // can't scroll this config
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int width = this->width();
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int height = this->height();
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // check if there's nothing to do
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((dx | dy) == 0 || width <= 0 || height <= 0) {
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (NULL != inval) {
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            inval->setEmpty();
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return true;
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // compute the inval region now, before we see if there are any pixels
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL != inval) {
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkIRect r;
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        r.set(0, 0, width, height);
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // initial the region with the entire bounds
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        inval->setRect(r);
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // do the "scroll"
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        r.offset(dx, dy);
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // check if we scrolled completely away
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (!SkIRect::Intersects(r, inval->getBounds())) {
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // inval has already been updated...
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return true;
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // compute the dirty area
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        inval->op(r, SkRegion::kDifference_Op);
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoLockPixels    alp(*this);
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // if we have no pixels, just return (inval is already updated)
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // don't call readyToDraw(), since we don't require a colortable per se
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (this->getPixels() == NULL) {
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return true;
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    char*       dst = (char*)this->getPixels();
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const char* src = dst;
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int         rowBytes = this->rowBytes();    // need rowBytes to be signed
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (dy <= 0) {
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src -= dy * rowBytes;
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        height += dy;
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += dy * rowBytes;
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        height -= dy;
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // now jump src/dst to the last scanline
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src += (height - 1) * rowBytes;
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += (height - 1) * rowBytes;
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // now invert rowbytes so we copy backwards in the loop
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        rowBytes = -rowBytes;
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (dx <= 0) {
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src -= dx << shift;
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        width += dx;
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += dx << shift;
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        width -= dx;
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // If the X-translation would push it completely beyond the region,
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // then there's nothing to draw.
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (width <= 0) {
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return true;
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    width <<= shift;    // now width is the number of bytes to move per line
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (--height >= 0) {
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        memmove(dst, src, width);
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += rowBytes;
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src += rowBytes;
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->notifyPixelsChanged();
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
124