1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/* 3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 Google Inc. 4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * 5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file. 7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */ 8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBitmap.h" 9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkRegion.h" 10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy, 12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkRegion* inval) const 13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{ 14afd90e40718aaa332d3a1d86d173d21e5039f5c6scroggo@google.com if (this->isImmutable()) { 15afd90e40718aaa332d3a1d86d173d21e5039f5c6scroggo@google.com return false; 16afd90e40718aaa332d3a1d86d173d21e5039f5c6scroggo@google.com } 17afd90e40718aaa332d3a1d86d173d21e5039f5c6scroggo@google.com 18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (NULL != subset) { 19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkBitmap tmp; 20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return this->extractSubset(&tmp, *subset) && 22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now call again with no rectangle 23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com tmp.scrollRect(NULL, dx, dy, inval); 24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int shift; 27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com switch (this->config()) { 29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case kIndex8_Config: 30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case kA8_Config: 31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com shift = 0; 32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case kARGB_4444_Config: 34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case kRGB_565_Config: 35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com shift = 1; 36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com case kARGB_8888_Config: 38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com shift = 2; 39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com break; 40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com default: 41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // can't scroll this config 42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return false; 43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int width = this->width(); 46935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com int height = this->height(); 47935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // check if there's nothing to do 49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if ((dx | dy) == 0 || width <= 0 || height <= 0) { 50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (NULL != inval) { 51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com inval->setEmpty(); 52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // compute the inval region now, before we see if there are any pixels 57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (NULL != inval) { 58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkIRect r; 59935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com r.set(0, 0, width, height); 61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // initial the region with the entire bounds 62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com inval->setRect(r); 63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // do the "scroll" 64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com r.offset(dx, dy); 65935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // check if we scrolled completely away 67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (!SkIRect::Intersects(r, inval->getBounds())) { 68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // inval has already been updated... 69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 71935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // compute the dirty area 73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com inval->op(r, SkRegion::kDifference_Op); 74bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 75935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkAutoLockPixels alp(*this); 77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // if we have no pixels, just return (inval is already updated) 78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // don't call readyToDraw(), since we don't require a colortable per se 79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (this->getPixels() == NULL) { 80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com char* dst = (char*)this->getPixels(); 84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com const char* src = dst; 852dcc8513452824388c1f2bb47cb4095cfd7abbfescroggo@google.com int rowBytes = (int)this->rowBytes(); // need rowBytes to be signed 86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (dy <= 0) { 88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com src -= dy * rowBytes; 89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com height += dy; 90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst += dy * rowBytes; 92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com height -= dy; 93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now jump src/dst to the last scanline 94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com src += (height - 1) * rowBytes; 95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst += (height - 1) * rowBytes; 96bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now invert rowbytes so we copy backwards in the loop 97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com rowBytes = -rowBytes; 98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 994ad4a787d3a6d6a5c434ead057cc065b2324acaaepoger@google.com 100bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (dx <= 0) { 101bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com src -= dx << shift; 102bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com width += dx; 103bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 104bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst += dx << shift; 105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com width -= dx; 106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 1084ad4a787d3a6d6a5c434ead057cc065b2324acaaepoger@google.com // If the X-translation would push it completely beyond the region, 1094ad4a787d3a6d6a5c434ead057cc065b2324acaaepoger@google.com // then there's nothing to draw. 1104ad4a787d3a6d6a5c434ead057cc065b2324acaaepoger@google.com if (width <= 0) { 1114ad4a787d3a6d6a5c434ead057cc065b2324acaaepoger@google.com return true; 1124ad4a787d3a6d6a5c434ead057cc065b2324acaaepoger@google.com } 1134ad4a787d3a6d6a5c434ead057cc065b2324acaaepoger@google.com 114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com width <<= shift; // now width is the number of bytes to move per line 115bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com while (--height >= 0) { 116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com memmove(dst, src, width); 117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com dst += rowBytes; 118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com src += rowBytes; 119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 120afd90e40718aaa332d3a1d86d173d21e5039f5c6scroggo@google.com 121afd90e40718aaa332d3a1d86d173d21e5039f5c6scroggo@google.com this->notifyPixelsChanged(); 122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return true; 123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 124