1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc. 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBitmap.h" 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegion.h" 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy, 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRegion* inval) const 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 14900ecf2f1579d42c9d2959831787af0346320f86reed@google.com if (this->isImmutable() || kUnknown_SkColorType == this->colorType()) { 156a9368d41154890b6c316fdae704bf56ca4c70ccscroggo@google.com return false; 166a9368d41154890b6c316fdae704bf56ca4c70ccscroggo@google.com } 176a9368d41154890b6c316fdae704bf56ca4c70ccscroggo@google.com 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (NULL != subset) { 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBitmap tmp; 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this->extractSubset(&tmp, *subset) && 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now call again with no rectangle 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tmp.scrollRect(NULL, dx, dy, inval); 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 26900ecf2f1579d42c9d2959831787af0346320f86reed@google.com int shift = this->bytesPerPixel() >> 1; 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int width = this->width(); 28fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com int height = this->height(); 29fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // check if there's nothing to do 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if ((dx | dy) == 0 || width <= 0 || height <= 0) { 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (NULL != inval) { 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com inval->setEmpty(); 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // compute the inval region now, before we see if there are any pixels 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (NULL != inval) { 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect r; 41fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.set(0, 0, width, height); 438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // initial the region with the entire bounds 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com inval->setRect(r); 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // do the "scroll" 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.offset(dx, dy); 47fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // check if we scrolled completely away 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!SkIRect::Intersects(r, inval->getBounds())) { 508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // inval has already been updated... 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 53fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // compute the dirty area 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com inval->op(r, SkRegion::kDifference_Op); 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 57fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkAutoLockPixels alp(*this); 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // if we have no pixels, just return (inval is already updated) 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // don't call readyToDraw(), since we don't require a colortable per se 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (this->getPixels() == NULL) { 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com char* dst = (char*)this->getPixels(); 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const char* src = dst; 67e5f48243bdbed2662be7a31be0888abc273b09e8scroggo@google.com int rowBytes = (int)this->rowBytes(); // need rowBytes to be signed 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (dy <= 0) { 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com src -= dy * rowBytes; 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com height += dy; 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst += dy * rowBytes; 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com height -= dy; 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now jump src/dst to the last scanline 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com src += (height - 1) * rowBytes; 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst += (height - 1) * rowBytes; 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now invert rowbytes so we copy backwards in the loop 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com rowBytes = -rowBytes; 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 81d4af56c5f24a7bf0200e20a591d55f8c82fb9627epoger@google.com 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (dx <= 0) { 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com src -= dx << shift; 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com width += dx; 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst += dx << shift; 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com width -= dx; 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 90d4af56c5f24a7bf0200e20a591d55f8c82fb9627epoger@google.com // If the X-translation would push it completely beyond the region, 91d4af56c5f24a7bf0200e20a591d55f8c82fb9627epoger@google.com // then there's nothing to draw. 92d4af56c5f24a7bf0200e20a591d55f8c82fb9627epoger@google.com if (width <= 0) { 93d4af56c5f24a7bf0200e20a591d55f8c82fb9627epoger@google.com return true; 94d4af56c5f24a7bf0200e20a591d55f8c82fb9627epoger@google.com } 95d4af56c5f24a7bf0200e20a591d55f8c82fb9627epoger@google.com 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com width <<= shift; // now width is the number of bytes to move per line 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while (--height >= 0) { 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memmove(dst, src, width); 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst += rowBytes; 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com src += rowBytes; 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1026a9368d41154890b6c316fdae704bf56ca4c70ccscroggo@google.com 1036a9368d41154890b6c316fdae704bf56ca4c70ccscroggo@google.com this->notifyPixelsChanged(); 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 106