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