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