1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gfx/skbitmap_operations.h"
10 #include "base/logging.h"
11 #include "skia/ext/refptr.h"
12 #include "third_party/skia/include/core/SkBitmap.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkColorFilter.h"
15 #include "third_party/skia/include/core/SkColorPriv.h"
16 #include "third_party/skia/include/core/SkUnPreMultiply.h"
17 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
18 #include "ui/gfx/insets.h"
19 #include "ui/gfx/point.h"
20 #include "ui/gfx/size.h"
23 SkBitmap
SkBitmapOperations::CreateInvertedBitmap(const SkBitmap
& image
) {
24 DCHECK(image
.colorType() == kN32_SkColorType
);
26 SkAutoLockPixels
lock_image(image
);
29 inverted
.allocN32Pixels(image
.width(), image
.height());
31 for (int y
= 0; y
< image
.height(); ++y
) {
32 uint32
* image_row
= image
.getAddr32(0, y
);
33 uint32
* dst_row
= inverted
.getAddr32(0, y
);
35 for (int x
= 0; x
< image
.width(); ++x
) {
36 uint32 image_pixel
= image_row
[x
];
37 dst_row
[x
] = (image_pixel
& 0xFF000000) |
38 (0x00FFFFFF - (image_pixel
& 0x00FFFFFF));
46 SkBitmap
SkBitmapOperations::CreateBlendedBitmap(const SkBitmap
& first
,
47 const SkBitmap
& second
,
49 DCHECK((alpha
>= 0) && (alpha
<= 1));
50 DCHECK(first
.width() == second
.width());
51 DCHECK(first
.height() == second
.height());
52 DCHECK(first
.bytesPerPixel() == second
.bytesPerPixel());
53 DCHECK(first
.colorType() == kN32_SkColorType
);
55 // Optimize for case where we won't need to blend anything.
56 static const double alpha_min
= 1.0 / 255;
57 static const double alpha_max
= 254.0 / 255;
58 if (alpha
< alpha_min
)
60 else if (alpha
> alpha_max
)
63 SkAutoLockPixels
lock_first(first
);
64 SkAutoLockPixels
lock_second(second
);
67 blended
.allocN32Pixels(first
.width(), first
.height());
69 double first_alpha
= 1 - alpha
;
71 for (int y
= 0; y
< first
.height(); ++y
) {
72 uint32
* first_row
= first
.getAddr32(0, y
);
73 uint32
* second_row
= second
.getAddr32(0, y
);
74 uint32
* dst_row
= blended
.getAddr32(0, y
);
76 for (int x
= 0; x
< first
.width(); ++x
) {
77 uint32 first_pixel
= first_row
[x
];
78 uint32 second_pixel
= second_row
[x
];
80 int a
= static_cast<int>((SkColorGetA(first_pixel
) * first_alpha
) +
81 (SkColorGetA(second_pixel
) * alpha
));
82 int r
= static_cast<int>((SkColorGetR(first_pixel
) * first_alpha
) +
83 (SkColorGetR(second_pixel
) * alpha
));
84 int g
= static_cast<int>((SkColorGetG(first_pixel
) * first_alpha
) +
85 (SkColorGetG(second_pixel
) * alpha
));
86 int b
= static_cast<int>((SkColorGetB(first_pixel
) * first_alpha
) +
87 (SkColorGetB(second_pixel
) * alpha
));
89 dst_row
[x
] = SkColorSetARGB(a
, r
, g
, b
);
97 SkBitmap
SkBitmapOperations::CreateMaskedBitmap(const SkBitmap
& rgb
,
98 const SkBitmap
& alpha
) {
99 DCHECK(rgb
.width() == alpha
.width());
100 DCHECK(rgb
.height() == alpha
.height());
101 DCHECK(rgb
.bytesPerPixel() == alpha
.bytesPerPixel());
102 DCHECK(rgb
.colorType() == kN32_SkColorType
);
103 DCHECK(alpha
.colorType() == kN32_SkColorType
);
106 masked
.allocN32Pixels(rgb
.width(), rgb
.height());
108 SkAutoLockPixels
lock_rgb(rgb
);
109 SkAutoLockPixels
lock_alpha(alpha
);
110 SkAutoLockPixels
lock_masked(masked
);
112 for (int y
= 0; y
< masked
.height(); ++y
) {
113 uint32
* rgb_row
= rgb
.getAddr32(0, y
);
114 uint32
* alpha_row
= alpha
.getAddr32(0, y
);
115 uint32
* dst_row
= masked
.getAddr32(0, y
);
117 for (int x
= 0; x
< masked
.width(); ++x
) {
118 SkColor rgb_pixel
= SkUnPreMultiply::PMColorToColor(rgb_row
[x
]);
119 SkColor alpha_pixel
= SkUnPreMultiply::PMColorToColor(alpha_row
[x
]);
120 int alpha
= SkAlphaMul(SkColorGetA(rgb_pixel
),
121 SkAlpha255To256(SkColorGetA(alpha_pixel
)));
122 int alpha_256
= SkAlpha255To256(alpha
);
123 dst_row
[x
] = SkColorSetARGB(alpha
,
124 SkAlphaMul(SkColorGetR(rgb_pixel
), alpha_256
),
125 SkAlphaMul(SkColorGetG(rgb_pixel
), alpha_256
),
126 SkAlphaMul(SkColorGetB(rgb_pixel
),
135 SkBitmap
SkBitmapOperations::CreateButtonBackground(SkColor color
,
136 const SkBitmap
& image
,
137 const SkBitmap
& mask
) {
138 DCHECK(image
.colorType() == kN32_SkColorType
);
139 DCHECK(mask
.colorType() == kN32_SkColorType
);
142 background
.allocN32Pixels(mask
.width(), mask
.height());
144 double bg_a
= SkColorGetA(color
);
145 double bg_r
= SkColorGetR(color
);
146 double bg_g
= SkColorGetG(color
);
147 double bg_b
= SkColorGetB(color
);
149 SkAutoLockPixels
lock_mask(mask
);
150 SkAutoLockPixels
lock_image(image
);
151 SkAutoLockPixels
lock_background(background
);
153 for (int y
= 0; y
< mask
.height(); ++y
) {
154 uint32
* dst_row
= background
.getAddr32(0, y
);
155 uint32
* image_row
= image
.getAddr32(0, y
% image
.height());
156 uint32
* mask_row
= mask
.getAddr32(0, y
);
158 for (int x
= 0; x
< mask
.width(); ++x
) {
159 uint32 image_pixel
= image_row
[x
% image
.width()];
161 double img_a
= SkColorGetA(image_pixel
);
162 double img_r
= SkColorGetR(image_pixel
);
163 double img_g
= SkColorGetG(image_pixel
);
164 double img_b
= SkColorGetB(image_pixel
);
166 double img_alpha
= static_cast<double>(img_a
) / 255.0;
167 double img_inv
= 1 - img_alpha
;
169 double mask_a
= static_cast<double>(SkColorGetA(mask_row
[x
])) / 255.0;
171 dst_row
[x
] = SkColorSetARGB(
172 static_cast<int>(std::min(255.0, bg_a
+ img_a
) * mask_a
),
173 static_cast<int>(((bg_r
* img_inv
) + (img_r
* img_alpha
)) * mask_a
),
174 static_cast<int>(((bg_g
* img_inv
) + (img_g
* img_alpha
)) * mask_a
),
175 static_cast<int>(((bg_b
* img_inv
) + (img_b
* img_alpha
)) * mask_a
));
185 // TODO(viettrungluu): Some things have yet to be optimized at all.
187 // Notes on and conventions used in the following code
190 // - R, G, B, A = obvious; as variables: |r|, |g|, |b|, |a| (see also below)
191 // - H, S, L = obvious; as variables: |h|, |s|, |l| (see also below)
192 // - variables derived from S, L shift parameters: |sdec| and |sinc| for S
193 // increase and decrease factors, |ldec| and |linc| for L (see also below)
195 // To try to optimize HSL shifts, we do several things:
196 // - Avoid unpremultiplying (then processing) then premultiplying. This means
197 // that R, G, B values (and also L, but not H and S) should be treated as
198 // having a range of 0..A (where A is alpha).
199 // - Do things in integer/fixed-point. This avoids costly conversions between
200 // floating-point and integer, though I should study the tradeoff more
201 // carefully (presumably, at some point of processing complexity, converting
202 // and processing using simpler floating-point code will begin to win in
203 // performance). Also to be studied is the speed/type of floating point
204 // conversions; see, e.g., <http://www.stereopsis.com/sree/fpu2006.html>.
206 // Conventions for fixed-point arithmetic
207 // - Each function has a constant denominator (called |den|, which should be a
208 // power of 2), appropriate for the computations done in that function.
209 // - A value |x| is then typically represented by a numerator, named |x_num|,
210 // so that its actual value is |x_num / den| (casting to floating-point
212 // - To obtain |x_num| from |x|, simply multiply by |den|, i.e., |x_num = x *
213 // den| (casting appropriately).
214 // - When necessary, a value |x| may also be represented as a numerator over
215 // the denominator squared (set |den2 = den * den|). In such a case, the
216 // corresponding variable is called |x_num2| (so that its actual value is
218 // - The representation of the product of |x| and |y| is be called |x_y_num| if
219 // |x * y == x_y_num / den|, and |xy_num2| if |x * y == x_y_num2 / den2|. In
220 // the latter case, notice that one can calculate |x_y_num2 = x_num * y_num|.
222 // Routine used to process a line; typically specialized for specific kinds of
223 // HSL shifts (to optimize).
224 typedef void (*LineProcessor
)(const color_utils::HSL
&,
229 enum OperationOnH
{ kOpHNone
= 0, kOpHShift
, kNumHOps
};
230 enum OperationOnS
{ kOpSNone
= 0, kOpSDec
, kOpSInc
, kNumSOps
};
231 enum OperationOnL
{ kOpLNone
= 0, kOpLDec
, kOpLInc
, kNumLOps
};
233 // Epsilon used to judge when shift values are close enough to various critical
234 // values (typically 0.5, which yields a no-op for S and L shifts. 1/256 should
235 // be small enough, but let's play it safe>
236 const double epsilon
= 0.0005;
238 // Line processor: default/universal (i.e., old-school).
239 void LineProcDefault(const color_utils::HSL
& hsl_shift
,
243 for (int x
= 0; x
< width
; x
++) {
244 out
[x
] = SkPreMultiplyColor(color_utils::HSLShift(
245 SkUnPreMultiply::PMColorToColor(in
[x
]), hsl_shift
));
249 // Line processor: no-op (i.e., copy).
250 void LineProcCopy(const color_utils::HSL
& hsl_shift
,
254 DCHECK(hsl_shift
.h
< 0);
255 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
256 DCHECK(hsl_shift
.l
< 0 || fabs(hsl_shift
.l
- 0.5) < HSLShift::epsilon
);
257 memcpy(out
, in
, static_cast<size_t>(width
) * sizeof(out
[0]));
260 // Line processor: H no-op, S no-op, L decrease.
261 void LineProcHnopSnopLdec(const color_utils::HSL
& hsl_shift
,
265 const uint32_t den
= 65536;
267 DCHECK(hsl_shift
.h
< 0);
268 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
269 DCHECK(hsl_shift
.l
<= 0.5 - HSLShift::epsilon
&& hsl_shift
.l
>= 0);
271 uint32_t ldec_num
= static_cast<uint32_t>(hsl_shift
.l
* 2 * den
);
272 for (int x
= 0; x
< width
; x
++) {
273 uint32_t a
= SkGetPackedA32(in
[x
]);
274 uint32_t r
= SkGetPackedR32(in
[x
]);
275 uint32_t g
= SkGetPackedG32(in
[x
]);
276 uint32_t b
= SkGetPackedB32(in
[x
]);
277 r
= r
* ldec_num
/ den
;
278 g
= g
* ldec_num
/ den
;
279 b
= b
* ldec_num
/ den
;
280 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
284 // Line processor: H no-op, S no-op, L increase.
285 void LineProcHnopSnopLinc(const color_utils::HSL
& hsl_shift
,
289 const uint32_t den
= 65536;
291 DCHECK(hsl_shift
.h
< 0);
292 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
293 DCHECK(hsl_shift
.l
>= 0.5 + HSLShift::epsilon
&& hsl_shift
.l
<= 1);
295 uint32_t linc_num
= static_cast<uint32_t>((hsl_shift
.l
- 0.5) * 2 * den
);
296 for (int x
= 0; x
< width
; x
++) {
297 uint32_t a
= SkGetPackedA32(in
[x
]);
298 uint32_t r
= SkGetPackedR32(in
[x
]);
299 uint32_t g
= SkGetPackedG32(in
[x
]);
300 uint32_t b
= SkGetPackedB32(in
[x
]);
301 r
+= (a
- r
) * linc_num
/ den
;
302 g
+= (a
- g
) * linc_num
/ den
;
303 b
+= (a
- b
) * linc_num
/ den
;
304 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
308 // Saturation changes modifications in RGB
310 // (Note that as a further complication, the values we deal in are
311 // premultiplied, so R/G/B values must be in the range 0..A. For mathematical
312 // purposes, one may as well use r=R/A, g=G/A, b=B/A. Without loss of
313 // generality, assume that R/G/B values are in the range 0..1.)
315 // Let Max = max(R,G,B), Min = min(R,G,B), and Med be the median value. Then L =
316 // (Max+Min)/2. If L is to remain constant, Max+Min must also remain constant.
318 // For H to remain constant, first, the (numerical) order of R/G/B (from
319 // smallest to largest) must remain the same. Second, all the ratios
320 // (R-G)/(Max-Min), (R-B)/(Max-Min), (G-B)/(Max-Min) must remain constant (of
321 // course, if Max = Min, then S = 0 and no saturation change is well-defined,
322 // since H is not well-defined).
324 // Let C_max be a colour with value Max, C_min be one with value Min, and C_med
325 // the remaining colour. Increasing saturation (to the maximum) is accomplished
326 // by increasing the value of C_max while simultaneously decreasing C_min and
327 // changing C_med so that the ratios are maintained; for the latter, it suffices
328 // to keep (C_med-C_min)/(C_max-C_min) constant (and equal to
329 // (Med-Min)/(Max-Min)).
331 // Line processor: H no-op, S decrease, L no-op.
332 void LineProcHnopSdecLnop(const color_utils::HSL
& hsl_shift
,
336 DCHECK(hsl_shift
.h
< 0);
337 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
338 DCHECK(hsl_shift
.l
< 0 || fabs(hsl_shift
.l
- 0.5) < HSLShift::epsilon
);
340 const int32_t denom
= 65536;
341 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
342 for (int x
= 0; x
< width
; x
++) {
343 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
344 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
345 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
346 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
349 if (r
> g
) { // This uses 3 compares rather than 4.
350 vmax
= std::max(r
, b
);
351 vmin
= std::min(g
, b
);
353 vmax
= std::max(g
, b
);
354 vmin
= std::min(r
, b
);
357 // Use denom * L to avoid rounding.
358 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
359 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
361 r
= (denom_l
+ r
* s_numer
- s_numer_l
) / denom
;
362 g
= (denom_l
+ g
* s_numer
- s_numer_l
) / denom
;
363 b
= (denom_l
+ b
* s_numer
- s_numer_l
) / denom
;
364 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
368 // Line processor: H no-op, S decrease, L decrease.
369 void LineProcHnopSdecLdec(const color_utils::HSL
& hsl_shift
,
373 DCHECK(hsl_shift
.h
< 0);
374 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
375 DCHECK(hsl_shift
.l
>= 0 && hsl_shift
.l
<= 0.5 - HSLShift::epsilon
);
377 // Can't be too big since we need room for denom*denom and a bit for sign.
378 const int32_t denom
= 1024;
379 int32_t l_numer
= static_cast<int32_t>(hsl_shift
.l
* 2 * denom
);
380 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
381 for (int x
= 0; x
< width
; x
++) {
382 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
383 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
384 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
385 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
388 if (r
> g
) { // This uses 3 compares rather than 4.
389 vmax
= std::max(r
, b
);
390 vmin
= std::min(g
, b
);
392 vmax
= std::max(g
, b
);
393 vmin
= std::min(r
, b
);
396 // Use denom * L to avoid rounding.
397 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
398 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
400 r
= (denom_l
+ r
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
401 g
= (denom_l
+ g
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
402 b
= (denom_l
+ b
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
403 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
407 // Line processor: H no-op, S decrease, L increase.
408 void LineProcHnopSdecLinc(const color_utils::HSL
& hsl_shift
,
412 DCHECK(hsl_shift
.h
< 0);
413 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
414 DCHECK(hsl_shift
.l
>= 0.5 + HSLShift::epsilon
&& hsl_shift
.l
<= 1);
416 // Can't be too big since we need room for denom*denom and a bit for sign.
417 const int32_t denom
= 1024;
418 int32_t l_numer
= static_cast<int32_t>((hsl_shift
.l
- 0.5) * 2 * denom
);
419 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
420 for (int x
= 0; x
< width
; x
++) {
421 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
422 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
423 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
424 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
427 if (r
> g
) { // This uses 3 compares rather than 4.
428 vmax
= std::max(r
, b
);
429 vmin
= std::min(g
, b
);
431 vmax
= std::max(g
, b
);
432 vmin
= std::min(r
, b
);
435 // Use denom * L to avoid rounding.
436 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
437 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
439 r
= denom_l
+ r
* s_numer
- s_numer_l
;
440 g
= denom_l
+ g
* s_numer
- s_numer_l
;
441 b
= denom_l
+ b
* s_numer
- s_numer_l
;
443 r
= (r
* denom
+ (a
* denom
- r
) * l_numer
) / (denom
* denom
);
444 g
= (g
* denom
+ (a
* denom
- g
) * l_numer
) / (denom
* denom
);
445 b
= (b
* denom
+ (a
* denom
- b
) * l_numer
) / (denom
* denom
);
446 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
450 const LineProcessor kLineProcessors
[kNumHOps
][kNumSOps
][kNumLOps
] = {
453 LineProcCopy
, // L: kOpLNone
454 LineProcHnopSnopLdec
, // L: kOpLDec
455 LineProcHnopSnopLinc
// L: kOpLInc
458 LineProcHnopSdecLnop
, // L: kOpLNone
459 LineProcHnopSdecLdec
, // L: kOpLDec
460 LineProcHnopSdecLinc
// L: kOpLInc
463 LineProcDefault
, // L: kOpLNone
464 LineProcDefault
, // L: kOpLDec
465 LineProcDefault
// L: kOpLInc
470 LineProcDefault
, // L: kOpLNone
471 LineProcDefault
, // L: kOpLDec
472 LineProcDefault
// L: kOpLInc
475 LineProcDefault
, // L: kOpLNone
476 LineProcDefault
, // L: kOpLDec
477 LineProcDefault
// L: kOpLInc
480 LineProcDefault
, // L: kOpLNone
481 LineProcDefault
, // L: kOpLDec
482 LineProcDefault
// L: kOpLInc
487 } // namespace HSLShift
491 SkBitmap
SkBitmapOperations::CreateHSLShiftedBitmap(
492 const SkBitmap
& bitmap
,
493 const color_utils::HSL
& hsl_shift
) {
495 HSLShift::OperationOnH H_op
= HSLShift::kOpHNone
;
496 HSLShift::OperationOnS S_op
= HSLShift::kOpSNone
;
497 HSLShift::OperationOnL L_op
= HSLShift::kOpLNone
;
499 if (hsl_shift
.h
>= 0 && hsl_shift
.h
<= 1)
500 H_op
= HSLShift::kOpHShift
;
502 // Saturation shift: 0 -> fully desaturate, 0.5 -> NOP, 1 -> fully saturate.
503 if (hsl_shift
.s
>= 0 && hsl_shift
.s
<= (0.5 - HSLShift::epsilon
))
504 S_op
= HSLShift::kOpSDec
;
505 else if (hsl_shift
.s
>= (0.5 + HSLShift::epsilon
))
506 S_op
= HSLShift::kOpSInc
;
508 // Lightness shift: 0 -> black, 0.5 -> NOP, 1 -> white.
509 if (hsl_shift
.l
>= 0 && hsl_shift
.l
<= (0.5 - HSLShift::epsilon
))
510 L_op
= HSLShift::kOpLDec
;
511 else if (hsl_shift
.l
>= (0.5 + HSLShift::epsilon
))
512 L_op
= HSLShift::kOpLInc
;
514 HSLShift::LineProcessor line_proc
=
515 HSLShift::kLineProcessors
[H_op
][S_op
][L_op
];
517 DCHECK(bitmap
.empty() == false);
518 DCHECK(bitmap
.colorType() == kN32_SkColorType
);
521 shifted
.allocN32Pixels(bitmap
.width(), bitmap
.height());
523 SkAutoLockPixels
lock_bitmap(bitmap
);
524 SkAutoLockPixels
lock_shifted(shifted
);
526 // Loop through the pixels of the original bitmap.
527 for (int y
= 0; y
< bitmap
.height(); ++y
) {
528 SkPMColor
* pixels
= bitmap
.getAddr32(0, y
);
529 SkPMColor
* tinted_pixels
= shifted
.getAddr32(0, y
);
531 (*line_proc
)(hsl_shift
, pixels
, tinted_pixels
, bitmap
.width());
538 SkBitmap
SkBitmapOperations::CreateTiledBitmap(const SkBitmap
& source
,
539 int src_x
, int src_y
,
540 int dst_w
, int dst_h
) {
541 DCHECK(source
.colorType() == kN32_SkColorType
);
544 cropped
.allocN32Pixels(dst_w
, dst_h
);
546 SkAutoLockPixels
lock_source(source
);
547 SkAutoLockPixels
lock_cropped(cropped
);
549 // Loop through the pixels of the original bitmap.
550 for (int y
= 0; y
< dst_h
; ++y
) {
551 int y_pix
= (src_y
+ y
) % source
.height();
553 y_pix
+= source
.height();
555 uint32
* source_row
= source
.getAddr32(0, y_pix
);
556 uint32
* dst_row
= cropped
.getAddr32(0, y
);
558 for (int x
= 0; x
< dst_w
; ++x
) {
559 int x_pix
= (src_x
+ x
) % source
.width();
561 x_pix
+= source
.width();
563 dst_row
[x
] = source_row
[x_pix
];
571 SkBitmap
SkBitmapOperations::DownsampleByTwoUntilSize(const SkBitmap
& bitmap
,
572 int min_w
, int min_h
) {
573 if ((bitmap
.width() <= min_w
) || (bitmap
.height() <= min_h
) ||
574 (min_w
< 0) || (min_h
< 0))
577 // Since bitmaps are refcounted, this copy will be fast.
578 SkBitmap current
= bitmap
;
579 while ((current
.width() >= min_w
* 2) && (current
.height() >= min_h
* 2) &&
580 (current
.width() > 1) && (current
.height() > 1))
581 current
= DownsampleByTwo(current
);
586 SkBitmap
SkBitmapOperations::DownsampleByTwo(const SkBitmap
& bitmap
) {
587 // Handle the nop case.
588 if ((bitmap
.width() <= 1) || (bitmap
.height() <= 1))
592 result
.allocN32Pixels((bitmap
.width() + 1) / 2, (bitmap
.height() + 1) / 2);
594 SkAutoLockPixels
lock(bitmap
);
596 const int resultLastX
= result
.width() - 1;
597 const int srcLastX
= bitmap
.width() - 1;
599 for (int dest_y
= 0; dest_y
< result
.height(); ++dest_y
) {
600 const int src_y
= dest_y
<< 1;
601 const SkPMColor
* SK_RESTRICT cur_src0
= bitmap
.getAddr32(0, src_y
);
602 const SkPMColor
* SK_RESTRICT cur_src1
= cur_src0
;
603 if (src_y
+ 1 < bitmap
.height())
604 cur_src1
= bitmap
.getAddr32(0, src_y
+ 1);
606 SkPMColor
* SK_RESTRICT cur_dst
= result
.getAddr32(0, dest_y
);
608 for (int dest_x
= 0; dest_x
<= resultLastX
; ++dest_x
) {
609 // This code is based on downsampleby2_proc32 in SkBitmap.cpp. It is very
610 // clever in that it does two channels at once: alpha and green ("ag")
611 // and red and blue ("rb"). Each channel gets averaged across 4 pixels
612 // to get the result.
613 int bump_x
= (dest_x
<< 1) < srcLastX
;
614 SkPMColor tmp
, ag
, rb
;
616 // Top left pixel of the 2x2 block.
618 ag
= (tmp
>> 8) & 0xFF00FF;
621 // Top right pixel of the 2x2 block.
622 tmp
= cur_src0
[bump_x
];
623 ag
+= (tmp
>> 8) & 0xFF00FF;
624 rb
+= tmp
& 0xFF00FF;
626 // Bottom left pixel of the 2x2 block.
628 ag
+= (tmp
>> 8) & 0xFF00FF;
629 rb
+= tmp
& 0xFF00FF;
631 // Bottom right pixel of the 2x2 block.
632 tmp
= cur_src1
[bump_x
];
633 ag
+= (tmp
>> 8) & 0xFF00FF;
634 rb
+= tmp
& 0xFF00FF;
636 // Put the channels back together, dividing each by 4 to get the average.
637 // |ag| has the alpha and green channels shifted right by 8 bits from
638 // there they should end up, so shifting left by 6 gives them in the
639 // correct position divided by 4.
640 *cur_dst
++ = ((rb
>> 2) & 0xFF00FF) | ((ag
<< 6) & 0xFF00FF00);
651 SkBitmap
SkBitmapOperations::UnPreMultiply(const SkBitmap
& bitmap
) {
654 if (bitmap
.isOpaque())
657 SkImageInfo info
= bitmap
.info();
658 info
.fAlphaType
= kOpaque_SkAlphaType
;
659 SkBitmap opaque_bitmap
;
660 opaque_bitmap
.allocPixels(info
);
663 SkAutoLockPixels
bitmap_lock(bitmap
);
664 SkAutoLockPixels
opaque_bitmap_lock(opaque_bitmap
);
665 for (int y
= 0; y
< opaque_bitmap
.height(); y
++) {
666 for (int x
= 0; x
< opaque_bitmap
.width(); x
++) {
667 uint32 src_pixel
= *bitmap
.getAddr32(x
, y
);
668 uint32
* dst_pixel
= opaque_bitmap
.getAddr32(x
, y
);
669 SkColor unmultiplied
= SkUnPreMultiply::PMColorToColor(src_pixel
);
670 *dst_pixel
= unmultiplied
;
675 return opaque_bitmap
;
679 SkBitmap
SkBitmapOperations::CreateTransposedBitmap(const SkBitmap
& image
) {
680 DCHECK(image
.colorType() == kN32_SkColorType
);
683 transposed
.allocN32Pixels(image
.height(), image
.width());
685 SkAutoLockPixels
lock_image(image
);
686 SkAutoLockPixels
lock_transposed(transposed
);
688 for (int y
= 0; y
< image
.height(); ++y
) {
689 uint32
* image_row
= image
.getAddr32(0, y
);
690 for (int x
= 0; x
< image
.width(); ++x
) {
691 uint32
* dst
= transposed
.getAddr32(y
, x
);
700 SkBitmap
SkBitmapOperations::CreateColorMask(const SkBitmap
& bitmap
,
702 DCHECK(bitmap
.colorType() == kN32_SkColorType
);
705 color_mask
.allocN32Pixels(bitmap
.width(), bitmap
.height());
706 color_mask
.eraseARGB(0, 0, 0, 0);
708 SkCanvas
canvas(color_mask
);
710 skia::RefPtr
<SkColorFilter
> color_filter
= skia::AdoptRef(
711 SkColorFilter::CreateModeFilter(c
, SkXfermode::kSrcIn_Mode
));
713 paint
.setColorFilter(color_filter
.get());
714 canvas
.drawBitmap(bitmap
, SkIntToScalar(0), SkIntToScalar(0), &paint
);
719 SkBitmap
SkBitmapOperations::CreateDropShadow(
720 const SkBitmap
& bitmap
,
721 const gfx::ShadowValues
& shadows
) {
722 DCHECK(bitmap
.colorType() == kN32_SkColorType
);
724 // Shadow margin insets are negative values because they grow outside.
725 // Negate them here as grow direction is not important and only pixel value
726 // is of interest here.
727 gfx::Insets shadow_margin
= -gfx::ShadowValue::GetMargin(shadows
);
729 SkBitmap image_with_shadow
;
730 image_with_shadow
.allocN32Pixels(bitmap
.width() + shadow_margin
.width(),
731 bitmap
.height() + shadow_margin
.height());
732 image_with_shadow
.eraseARGB(0, 0, 0, 0);
734 SkCanvas
canvas(image_with_shadow
);
735 canvas
.translate(SkIntToScalar(shadow_margin
.left()),
736 SkIntToScalar(shadow_margin
.top()));
739 for (size_t i
= 0; i
< shadows
.size(); ++i
) {
740 const gfx::ShadowValue
& shadow
= shadows
[i
];
741 SkBitmap shadow_image
= SkBitmapOperations::CreateColorMask(bitmap
,
744 skia::RefPtr
<SkBlurImageFilter
> filter
=
745 skia::AdoptRef(SkBlurImageFilter::Create(
746 SkDoubleToScalar(shadow
.blur()), SkDoubleToScalar(shadow
.blur())));
747 paint
.setImageFilter(filter
.get());
749 canvas
.saveLayer(0, &paint
);
750 canvas
.drawBitmap(shadow_image
,
751 SkIntToScalar(shadow
.x()),
752 SkIntToScalar(shadow
.y()));
756 canvas
.drawBitmap(bitmap
, SkIntToScalar(0), SkIntToScalar(0));
757 return image_with_shadow
;
761 SkBitmap
SkBitmapOperations::Rotate(const SkBitmap
& source
,
762 RotationAmount rotation
) {
764 SkScalar angle
= SkFloatToScalar(0.0f
);
768 angle
= SkFloatToScalar(90.0f
);
769 result
.allocN32Pixels(source
.height(), source
.width());
771 case ROTATION_180_CW
:
772 angle
= SkFloatToScalar(180.0f
);
773 result
.allocN32Pixels(source
.width(), source
.height());
775 case ROTATION_270_CW
:
776 angle
= SkFloatToScalar(270.0f
);
777 result
.allocN32Pixels(source
.height(), source
.width());
781 SkCanvas
canvas(result
);
782 canvas
.clear(SkColorSetARGB(0, 0, 0, 0));
784 canvas
.translate(SkFloatToScalar(result
.width() * 0.5f
),
785 SkFloatToScalar(result
.height() * 0.5f
));
786 canvas
.rotate(angle
);
787 canvas
.translate(-SkFloatToScalar(source
.width() * 0.5f
),
788 -SkFloatToScalar(source
.height() * 0.5f
));
789 canvas
.drawBitmap(source
, 0, 0);