11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2011 Google Inc.
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkBitmap.h"
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkRegion.h"
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy,
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          SkRegion* inval) const
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL != subset) {
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkBitmap tmp;
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return  this->extractSubset(&tmp, *subset) &&
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // now call again with no rectangle
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                tmp.scrollRect(NULL, dx, dy, inval);
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int shift;
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (this->config()) {
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    case kIndex8_Config:
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    case kA8_Config:
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        shift = 0;
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        break;
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    case kARGB_4444_Config:
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    case kRGB_565_Config:
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        shift = 1;
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        break;
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    case kARGB_8888_Config:
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        shift = 2;
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        break;
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    default:
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // can't scroll this config
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int width = this->width();
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int height = this->height();
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // check if there's nothing to do
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if ((dx | dy) == 0 || width <= 0 || height <= 0) {
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (NULL != inval) {
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            inval->setEmpty();
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return true;
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // compute the inval region now, before we see if there are any pixels
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL != inval) {
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkIRect r;
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        r.set(0, 0, width, height);
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // initial the region with the entire bounds
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        inval->setRect(r);
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // do the "scroll"
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        r.offset(dx, dy);
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // check if we scrolled completely away
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!SkIRect::Intersects(r, inval->getBounds())) {
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // inval has already been updated...
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return true;
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // compute the dirty area
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        inval->op(r, SkRegion::kDifference_Op);
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoLockPixels    alp(*this);
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // if we have no pixels, just return (inval is already updated)
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // don't call readyToDraw(), since we don't require a colortable per se
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (this->getPixels() == NULL) {
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return true;
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    char*       dst = (char*)this->getPixels();
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const char* src = dst;
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int         rowBytes = this->rowBytes();    // need rowBytes to be signed
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dy <= 0) {
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src -= dy * rowBytes;
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        height += dy;
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += dy * rowBytes;
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        height -= dy;
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // now jump src/dst to the last scanline
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src += (height - 1) * rowBytes;
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += (height - 1) * rowBytes;
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // now invert rowbytes so we copy backwards in the loop
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        rowBytes = -rowBytes;
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dx <= 0) {
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src -= dx << shift;
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        width += dx;
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += dx << shift;
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        width -= dx;
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // If the X-translation would push it completely beyond the region,
1051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // then there's nothing to draw.
1061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (width <= 0) {
1071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return true;
1081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
1091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    width <<= shift;    // now width is the number of bytes to move per line
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (--height >= 0) {
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        memmove(dst, src, width);
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += rowBytes;
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src += rowBytes;
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
118