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
.config() == SkBitmap::kARGB_8888_Config
);
26 SkAutoLockPixels
lock_image(image
);
29 inverted
.setConfig(SkBitmap::kARGB_8888_Config
, image
.width(), image
.height(),
31 inverted
.allocPixels();
32 inverted
.eraseARGB(0, 0, 0, 0);
34 for (int y
= 0; y
< image
.height(); ++y
) {
35 uint32
* image_row
= image
.getAddr32(0, y
);
36 uint32
* dst_row
= inverted
.getAddr32(0, y
);
38 for (int x
= 0; x
< image
.width(); ++x
) {
39 uint32 image_pixel
= image_row
[x
];
40 dst_row
[x
] = (image_pixel
& 0xFF000000) |
41 (0x00FFFFFF - (image_pixel
& 0x00FFFFFF));
49 SkBitmap
SkBitmapOperations::CreateSuperimposedBitmap(const SkBitmap
& first
,
50 const SkBitmap
& second
) {
51 DCHECK(first
.width() == second
.width());
52 DCHECK(first
.height() == second
.height());
53 DCHECK(first
.bytesPerPixel() == second
.bytesPerPixel());
54 DCHECK(first
.config() == SkBitmap::kARGB_8888_Config
);
56 SkAutoLockPixels
lock_first(first
);
57 SkAutoLockPixels
lock_second(second
);
59 SkBitmap superimposed
;
60 superimposed
.setConfig(SkBitmap::kARGB_8888_Config
,
61 first
.width(), first
.height());
62 superimposed
.allocPixels();
63 superimposed
.eraseARGB(0, 0, 0, 0);
65 SkCanvas
canvas(superimposed
);
70 rect
.fRight
= SkIntToScalar(first
.width());
71 rect
.fBottom
= SkIntToScalar(first
.height());
73 canvas
.drawBitmapRect(first
, NULL
, rect
);
74 canvas
.drawBitmapRect(second
, NULL
, rect
);
80 SkBitmap
SkBitmapOperations::CreateBlendedBitmap(const SkBitmap
& first
,
81 const SkBitmap
& second
,
83 DCHECK((alpha
>= 0) && (alpha
<= 1));
84 DCHECK(first
.width() == second
.width());
85 DCHECK(first
.height() == second
.height());
86 DCHECK(first
.bytesPerPixel() == second
.bytesPerPixel());
87 DCHECK(first
.config() == SkBitmap::kARGB_8888_Config
);
89 // Optimize for case where we won't need to blend anything.
90 static const double alpha_min
= 1.0 / 255;
91 static const double alpha_max
= 254.0 / 255;
92 if (alpha
< alpha_min
)
94 else if (alpha
> alpha_max
)
97 SkAutoLockPixels
lock_first(first
);
98 SkAutoLockPixels
lock_second(second
);
101 blended
.setConfig(SkBitmap::kARGB_8888_Config
, first
.width(), first
.height(),
103 blended
.allocPixels();
104 blended
.eraseARGB(0, 0, 0, 0);
106 double first_alpha
= 1 - alpha
;
108 for (int y
= 0; y
< first
.height(); ++y
) {
109 uint32
* first_row
= first
.getAddr32(0, y
);
110 uint32
* second_row
= second
.getAddr32(0, y
);
111 uint32
* dst_row
= blended
.getAddr32(0, y
);
113 for (int x
= 0; x
< first
.width(); ++x
) {
114 uint32 first_pixel
= first_row
[x
];
115 uint32 second_pixel
= second_row
[x
];
117 int a
= static_cast<int>((SkColorGetA(first_pixel
) * first_alpha
) +
118 (SkColorGetA(second_pixel
) * alpha
));
119 int r
= static_cast<int>((SkColorGetR(first_pixel
) * first_alpha
) +
120 (SkColorGetR(second_pixel
) * alpha
));
121 int g
= static_cast<int>((SkColorGetG(first_pixel
) * first_alpha
) +
122 (SkColorGetG(second_pixel
) * alpha
));
123 int b
= static_cast<int>((SkColorGetB(first_pixel
) * first_alpha
) +
124 (SkColorGetB(second_pixel
) * alpha
));
126 dst_row
[x
] = SkColorSetARGB(a
, r
, g
, b
);
134 SkBitmap
SkBitmapOperations::CreateMaskedBitmap(const SkBitmap
& rgb
,
135 const SkBitmap
& alpha
) {
136 DCHECK(rgb
.width() == alpha
.width());
137 DCHECK(rgb
.height() == alpha
.height());
138 DCHECK(rgb
.bytesPerPixel() == alpha
.bytesPerPixel());
139 DCHECK(rgb
.config() == SkBitmap::kARGB_8888_Config
);
140 DCHECK(alpha
.config() == SkBitmap::kARGB_8888_Config
);
143 masked
.setConfig(SkBitmap::kARGB_8888_Config
, rgb
.width(), rgb
.height(), 0);
144 masked
.allocPixels();
145 masked
.eraseARGB(0, 0, 0, 0);
147 SkAutoLockPixels
lock_rgb(rgb
);
148 SkAutoLockPixels
lock_alpha(alpha
);
149 SkAutoLockPixels
lock_masked(masked
);
151 for (int y
= 0; y
< masked
.height(); ++y
) {
152 uint32
* rgb_row
= rgb
.getAddr32(0, y
);
153 uint32
* alpha_row
= alpha
.getAddr32(0, y
);
154 uint32
* dst_row
= masked
.getAddr32(0, y
);
156 for (int x
= 0; x
< masked
.width(); ++x
) {
157 SkColor rgb_pixel
= SkUnPreMultiply::PMColorToColor(rgb_row
[x
]);
158 SkColor alpha_pixel
= SkUnPreMultiply::PMColorToColor(alpha_row
[x
]);
159 int alpha
= SkAlphaMul(SkColorGetA(rgb_pixel
),
160 SkAlpha255To256(SkColorGetA(alpha_pixel
)));
161 int alpha_256
= SkAlpha255To256(alpha
);
162 dst_row
[x
] = SkColorSetARGB(alpha
,
163 SkAlphaMul(SkColorGetR(rgb_pixel
), alpha_256
),
164 SkAlphaMul(SkColorGetG(rgb_pixel
), alpha_256
),
165 SkAlphaMul(SkColorGetB(rgb_pixel
),
174 SkBitmap
SkBitmapOperations::CreateButtonBackground(SkColor color
,
175 const SkBitmap
& image
,
176 const SkBitmap
& mask
) {
177 DCHECK(image
.config() == SkBitmap::kARGB_8888_Config
);
178 DCHECK(mask
.config() == SkBitmap::kARGB_8888_Config
);
181 background
.setConfig(
182 SkBitmap::kARGB_8888_Config
, mask
.width(), mask
.height(), 0);
183 background
.allocPixels();
185 double bg_a
= SkColorGetA(color
);
186 double bg_r
= SkColorGetR(color
);
187 double bg_g
= SkColorGetG(color
);
188 double bg_b
= SkColorGetB(color
);
190 SkAutoLockPixels
lock_mask(mask
);
191 SkAutoLockPixels
lock_image(image
);
192 SkAutoLockPixels
lock_background(background
);
194 for (int y
= 0; y
< mask
.height(); ++y
) {
195 uint32
* dst_row
= background
.getAddr32(0, y
);
196 uint32
* image_row
= image
.getAddr32(0, y
% image
.height());
197 uint32
* mask_row
= mask
.getAddr32(0, y
);
199 for (int x
= 0; x
< mask
.width(); ++x
) {
200 uint32 image_pixel
= image_row
[x
% image
.width()];
202 double img_a
= SkColorGetA(image_pixel
);
203 double img_r
= SkColorGetR(image_pixel
);
204 double img_g
= SkColorGetG(image_pixel
);
205 double img_b
= SkColorGetB(image_pixel
);
207 double img_alpha
= static_cast<double>(img_a
) / 255.0;
208 double img_inv
= 1 - img_alpha
;
210 double mask_a
= static_cast<double>(SkColorGetA(mask_row
[x
])) / 255.0;
212 dst_row
[x
] = SkColorSetARGB(
213 static_cast<int>(std::min(255.0, bg_a
+ img_a
) * mask_a
),
214 static_cast<int>(((bg_r
* img_inv
) + (img_r
* img_alpha
)) * mask_a
),
215 static_cast<int>(((bg_g
* img_inv
) + (img_g
* img_alpha
)) * mask_a
),
216 static_cast<int>(((bg_b
* img_inv
) + (img_b
* img_alpha
)) * mask_a
));
226 // TODO(viettrungluu): Some things have yet to be optimized at all.
228 // Notes on and conventions used in the following code
231 // - R, G, B, A = obvious; as variables: |r|, |g|, |b|, |a| (see also below)
232 // - H, S, L = obvious; as variables: |h|, |s|, |l| (see also below)
233 // - variables derived from S, L shift parameters: |sdec| and |sinc| for S
234 // increase and decrease factors, |ldec| and |linc| for L (see also below)
236 // To try to optimize HSL shifts, we do several things:
237 // - Avoid unpremultiplying (then processing) then premultiplying. This means
238 // that R, G, B values (and also L, but not H and S) should be treated as
239 // having a range of 0..A (where A is alpha).
240 // - Do things in integer/fixed-point. This avoids costly conversions between
241 // floating-point and integer, though I should study the tradeoff more
242 // carefully (presumably, at some point of processing complexity, converting
243 // and processing using simpler floating-point code will begin to win in
244 // performance). Also to be studied is the speed/type of floating point
245 // conversions; see, e.g., <http://www.stereopsis.com/sree/fpu2006.html>.
247 // Conventions for fixed-point arithmetic
248 // - Each function has a constant denominator (called |den|, which should be a
249 // power of 2), appropriate for the computations done in that function.
250 // - A value |x| is then typically represented by a numerator, named |x_num|,
251 // so that its actual value is |x_num / den| (casting to floating-point
253 // - To obtain |x_num| from |x|, simply multiply by |den|, i.e., |x_num = x *
254 // den| (casting appropriately).
255 // - When necessary, a value |x| may also be represented as a numerator over
256 // the denominator squared (set |den2 = den * den|). In such a case, the
257 // corresponding variable is called |x_num2| (so that its actual value is
259 // - The representation of the product of |x| and |y| is be called |x_y_num| if
260 // |x * y == x_y_num / den|, and |xy_num2| if |x * y == x_y_num2 / den2|. In
261 // the latter case, notice that one can calculate |x_y_num2 = x_num * y_num|.
263 // Routine used to process a line; typically specialized for specific kinds of
264 // HSL shifts (to optimize).
265 typedef void (*LineProcessor
)(const color_utils::HSL
&,
270 enum OperationOnH
{ kOpHNone
= 0, kOpHShift
, kNumHOps
};
271 enum OperationOnS
{ kOpSNone
= 0, kOpSDec
, kOpSInc
, kNumSOps
};
272 enum OperationOnL
{ kOpLNone
= 0, kOpLDec
, kOpLInc
, kNumLOps
};
274 // Epsilon used to judge when shift values are close enough to various critical
275 // values (typically 0.5, which yields a no-op for S and L shifts. 1/256 should
276 // be small enough, but let's play it safe>
277 const double epsilon
= 0.0005;
279 // Line processor: default/universal (i.e., old-school).
280 void LineProcDefault(const color_utils::HSL
& hsl_shift
,
284 for (int x
= 0; x
< width
; x
++) {
285 out
[x
] = SkPreMultiplyColor(color_utils::HSLShift(
286 SkUnPreMultiply::PMColorToColor(in
[x
]), hsl_shift
));
290 // Line processor: no-op (i.e., copy).
291 void LineProcCopy(const color_utils::HSL
& hsl_shift
,
295 DCHECK(hsl_shift
.h
< 0);
296 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
297 DCHECK(hsl_shift
.l
< 0 || fabs(hsl_shift
.l
- 0.5) < HSLShift::epsilon
);
298 memcpy(out
, in
, static_cast<size_t>(width
) * sizeof(out
[0]));
301 // Line processor: H no-op, S no-op, L decrease.
302 void LineProcHnopSnopLdec(const color_utils::HSL
& hsl_shift
,
306 const uint32_t den
= 65536;
308 DCHECK(hsl_shift
.h
< 0);
309 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
310 DCHECK(hsl_shift
.l
<= 0.5 - HSLShift::epsilon
&& hsl_shift
.l
>= 0);
312 uint32_t ldec_num
= static_cast<uint32_t>(hsl_shift
.l
* 2 * den
);
313 for (int x
= 0; x
< width
; x
++) {
314 uint32_t a
= SkGetPackedA32(in
[x
]);
315 uint32_t r
= SkGetPackedR32(in
[x
]);
316 uint32_t g
= SkGetPackedG32(in
[x
]);
317 uint32_t b
= SkGetPackedB32(in
[x
]);
318 r
= r
* ldec_num
/ den
;
319 g
= g
* ldec_num
/ den
;
320 b
= b
* ldec_num
/ den
;
321 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
325 // Line processor: H no-op, S no-op, L increase.
326 void LineProcHnopSnopLinc(const color_utils::HSL
& hsl_shift
,
330 const uint32_t den
= 65536;
332 DCHECK(hsl_shift
.h
< 0);
333 DCHECK(hsl_shift
.s
< 0 || fabs(hsl_shift
.s
- 0.5) < HSLShift::epsilon
);
334 DCHECK(hsl_shift
.l
>= 0.5 + HSLShift::epsilon
&& hsl_shift
.l
<= 1);
336 uint32_t linc_num
= static_cast<uint32_t>((hsl_shift
.l
- 0.5) * 2 * den
);
337 for (int x
= 0; x
< width
; x
++) {
338 uint32_t a
= SkGetPackedA32(in
[x
]);
339 uint32_t r
= SkGetPackedR32(in
[x
]);
340 uint32_t g
= SkGetPackedG32(in
[x
]);
341 uint32_t b
= SkGetPackedB32(in
[x
]);
342 r
+= (a
- r
) * linc_num
/ den
;
343 g
+= (a
- g
) * linc_num
/ den
;
344 b
+= (a
- b
) * linc_num
/ den
;
345 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
349 // Saturation changes modifications in RGB
351 // (Note that as a further complication, the values we deal in are
352 // premultiplied, so R/G/B values must be in the range 0..A. For mathematical
353 // purposes, one may as well use r=R/A, g=G/A, b=B/A. Without loss of
354 // generality, assume that R/G/B values are in the range 0..1.)
356 // Let Max = max(R,G,B), Min = min(R,G,B), and Med be the median value. Then L =
357 // (Max+Min)/2. If L is to remain constant, Max+Min must also remain constant.
359 // For H to remain constant, first, the (numerical) order of R/G/B (from
360 // smallest to largest) must remain the same. Second, all the ratios
361 // (R-G)/(Max-Min), (R-B)/(Max-Min), (G-B)/(Max-Min) must remain constant (of
362 // course, if Max = Min, then S = 0 and no saturation change is well-defined,
363 // since H is not well-defined).
365 // Let C_max be a colour with value Max, C_min be one with value Min, and C_med
366 // the remaining colour. Increasing saturation (to the maximum) is accomplished
367 // by increasing the value of C_max while simultaneously decreasing C_min and
368 // changing C_med so that the ratios are maintained; for the latter, it suffices
369 // to keep (C_med-C_min)/(C_max-C_min) constant (and equal to
370 // (Med-Min)/(Max-Min)).
372 // Line processor: H no-op, S decrease, L no-op.
373 void LineProcHnopSdecLnop(const color_utils::HSL
& hsl_shift
,
377 DCHECK(hsl_shift
.h
< 0);
378 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
379 DCHECK(hsl_shift
.l
< 0 || fabs(hsl_shift
.l
- 0.5) < HSLShift::epsilon
);
381 const int32_t denom
= 65536;
382 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
383 for (int x
= 0; x
< width
; x
++) {
384 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
385 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
386 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
387 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
390 if (r
> g
) { // This uses 3 compares rather than 4.
391 vmax
= std::max(r
, b
);
392 vmin
= std::min(g
, b
);
394 vmax
= std::max(g
, b
);
395 vmin
= std::min(r
, b
);
398 // Use denom * L to avoid rounding.
399 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
400 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
402 r
= (denom_l
+ r
* s_numer
- s_numer_l
) / denom
;
403 g
= (denom_l
+ g
* s_numer
- s_numer_l
) / denom
;
404 b
= (denom_l
+ b
* s_numer
- s_numer_l
) / denom
;
405 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
409 // Line processor: H no-op, S decrease, L decrease.
410 void LineProcHnopSdecLdec(const color_utils::HSL
& hsl_shift
,
414 DCHECK(hsl_shift
.h
< 0);
415 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
416 DCHECK(hsl_shift
.l
>= 0 && hsl_shift
.l
<= 0.5 - HSLShift::epsilon
);
418 // Can't be too big since we need room for denom*denom and a bit for sign.
419 const int32_t denom
= 1024;
420 int32_t l_numer
= static_cast<int32_t>(hsl_shift
.l
* 2 * denom
);
421 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
422 for (int x
= 0; x
< width
; x
++) {
423 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
424 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
425 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
426 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
429 if (r
> g
) { // This uses 3 compares rather than 4.
430 vmax
= std::max(r
, b
);
431 vmin
= std::min(g
, b
);
433 vmax
= std::max(g
, b
);
434 vmin
= std::min(r
, b
);
437 // Use denom * L to avoid rounding.
438 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
439 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
441 r
= (denom_l
+ r
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
442 g
= (denom_l
+ g
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
443 b
= (denom_l
+ b
* s_numer
- s_numer_l
) * l_numer
/ (denom
* denom
);
444 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
448 // Line processor: H no-op, S decrease, L increase.
449 void LineProcHnopSdecLinc(const color_utils::HSL
& hsl_shift
,
453 DCHECK(hsl_shift
.h
< 0);
454 DCHECK(hsl_shift
.s
>= 0 && hsl_shift
.s
<= 0.5 - HSLShift::epsilon
);
455 DCHECK(hsl_shift
.l
>= 0.5 + HSLShift::epsilon
&& hsl_shift
.l
<= 1);
457 // Can't be too big since we need room for denom*denom and a bit for sign.
458 const int32_t denom
= 1024;
459 int32_t l_numer
= static_cast<int32_t>((hsl_shift
.l
- 0.5) * 2 * denom
);
460 int32_t s_numer
= static_cast<int32_t>(hsl_shift
.s
* 2 * denom
);
461 for (int x
= 0; x
< width
; x
++) {
462 int32_t a
= static_cast<int32_t>(SkGetPackedA32(in
[x
]));
463 int32_t r
= static_cast<int32_t>(SkGetPackedR32(in
[x
]));
464 int32_t g
= static_cast<int32_t>(SkGetPackedG32(in
[x
]));
465 int32_t b
= static_cast<int32_t>(SkGetPackedB32(in
[x
]));
468 if (r
> g
) { // This uses 3 compares rather than 4.
469 vmax
= std::max(r
, b
);
470 vmin
= std::min(g
, b
);
472 vmax
= std::max(g
, b
);
473 vmin
= std::min(r
, b
);
476 // Use denom * L to avoid rounding.
477 int32_t denom_l
= (vmax
+ vmin
) * (denom
/ 2);
478 int32_t s_numer_l
= (vmax
+ vmin
) * s_numer
/ 2;
480 r
= denom_l
+ r
* s_numer
- s_numer_l
;
481 g
= denom_l
+ g
* s_numer
- s_numer_l
;
482 b
= denom_l
+ b
* s_numer
- s_numer_l
;
484 r
= (r
* denom
+ (a
* denom
- r
) * l_numer
) / (denom
* denom
);
485 g
= (g
* denom
+ (a
* denom
- g
) * l_numer
) / (denom
* denom
);
486 b
= (b
* denom
+ (a
* denom
- b
) * l_numer
) / (denom
* denom
);
487 out
[x
] = SkPackARGB32(a
, r
, g
, b
);
491 const LineProcessor kLineProcessors
[kNumHOps
][kNumSOps
][kNumLOps
] = {
494 LineProcCopy
, // L: kOpLNone
495 LineProcHnopSnopLdec
, // L: kOpLDec
496 LineProcHnopSnopLinc
// L: kOpLInc
499 LineProcHnopSdecLnop
, // L: kOpLNone
500 LineProcHnopSdecLdec
, // L: kOpLDec
501 LineProcHnopSdecLinc
// L: kOpLInc
504 LineProcDefault
, // L: kOpLNone
505 LineProcDefault
, // L: kOpLDec
506 LineProcDefault
// L: kOpLInc
511 LineProcDefault
, // L: kOpLNone
512 LineProcDefault
, // L: kOpLDec
513 LineProcDefault
// L: kOpLInc
516 LineProcDefault
, // L: kOpLNone
517 LineProcDefault
, // L: kOpLDec
518 LineProcDefault
// L: kOpLInc
521 LineProcDefault
, // L: kOpLNone
522 LineProcDefault
, // L: kOpLDec
523 LineProcDefault
// L: kOpLInc
528 } // namespace HSLShift
532 SkBitmap
SkBitmapOperations::CreateHSLShiftedBitmap(
533 const SkBitmap
& bitmap
,
534 const color_utils::HSL
& hsl_shift
) {
536 HSLShift::OperationOnH H_op
= HSLShift::kOpHNone
;
537 HSLShift::OperationOnS S_op
= HSLShift::kOpSNone
;
538 HSLShift::OperationOnL L_op
= HSLShift::kOpLNone
;
540 if (hsl_shift
.h
>= 0 && hsl_shift
.h
<= 1)
541 H_op
= HSLShift::kOpHShift
;
543 // Saturation shift: 0 -> fully desaturate, 0.5 -> NOP, 1 -> fully saturate.
544 if (hsl_shift
.s
>= 0 && hsl_shift
.s
<= (0.5 - HSLShift::epsilon
))
545 S_op
= HSLShift::kOpSDec
;
546 else if (hsl_shift
.s
>= (0.5 + HSLShift::epsilon
))
547 S_op
= HSLShift::kOpSInc
;
549 // Lightness shift: 0 -> black, 0.5 -> NOP, 1 -> white.
550 if (hsl_shift
.l
>= 0 && hsl_shift
.l
<= (0.5 - HSLShift::epsilon
))
551 L_op
= HSLShift::kOpLDec
;
552 else if (hsl_shift
.l
>= (0.5 + HSLShift::epsilon
))
553 L_op
= HSLShift::kOpLInc
;
555 HSLShift::LineProcessor line_proc
=
556 HSLShift::kLineProcessors
[H_op
][S_op
][L_op
];
558 DCHECK(bitmap
.empty() == false);
559 DCHECK(bitmap
.config() == SkBitmap::kARGB_8888_Config
);
562 shifted
.setConfig(SkBitmap::kARGB_8888_Config
, bitmap
.width(),
564 shifted
.allocPixels();
565 shifted
.eraseARGB(0, 0, 0, 0);
566 shifted
.setIsOpaque(false);
568 SkAutoLockPixels
lock_bitmap(bitmap
);
569 SkAutoLockPixels
lock_shifted(shifted
);
571 // Loop through the pixels of the original bitmap.
572 for (int y
= 0; y
< bitmap
.height(); ++y
) {
573 SkPMColor
* pixels
= bitmap
.getAddr32(0, y
);
574 SkPMColor
* tinted_pixels
= shifted
.getAddr32(0, y
);
576 (*line_proc
)(hsl_shift
, pixels
, tinted_pixels
, bitmap
.width());
583 SkBitmap
SkBitmapOperations::CreateTiledBitmap(const SkBitmap
& source
,
584 int src_x
, int src_y
,
585 int dst_w
, int dst_h
) {
586 DCHECK(source
.config() == SkBitmap::kARGB_8888_Config
);
589 cropped
.setConfig(SkBitmap::kARGB_8888_Config
, dst_w
, dst_h
, 0);
590 cropped
.allocPixels();
591 cropped
.eraseARGB(0, 0, 0, 0);
593 SkAutoLockPixels
lock_source(source
);
594 SkAutoLockPixels
lock_cropped(cropped
);
596 // Loop through the pixels of the original bitmap.
597 for (int y
= 0; y
< dst_h
; ++y
) {
598 int y_pix
= (src_y
+ y
) % source
.height();
600 y_pix
+= source
.height();
602 uint32
* source_row
= source
.getAddr32(0, y_pix
);
603 uint32
* dst_row
= cropped
.getAddr32(0, y
);
605 for (int x
= 0; x
< dst_w
; ++x
) {
606 int x_pix
= (src_x
+ x
) % source
.width();
608 x_pix
+= source
.width();
610 dst_row
[x
] = source_row
[x_pix
];
618 SkBitmap
SkBitmapOperations::DownsampleByTwoUntilSize(const SkBitmap
& bitmap
,
619 int min_w
, int min_h
) {
620 if ((bitmap
.width() <= min_w
) || (bitmap
.height() <= min_h
) ||
621 (min_w
< 0) || (min_h
< 0))
624 // Since bitmaps are refcounted, this copy will be fast.
625 SkBitmap current
= bitmap
;
626 while ((current
.width() >= min_w
* 2) && (current
.height() >= min_h
* 2) &&
627 (current
.width() > 1) && (current
.height() > 1))
628 current
= DownsampleByTwo(current
);
633 SkBitmap
SkBitmapOperations::DownsampleByTwo(const SkBitmap
& bitmap
) {
634 // Handle the nop case.
635 if ((bitmap
.width() <= 1) || (bitmap
.height() <= 1))
639 result
.setConfig(SkBitmap::kARGB_8888_Config
,
640 (bitmap
.width() + 1) / 2, (bitmap
.height() + 1) / 2);
641 result
.allocPixels();
643 SkAutoLockPixels
lock(bitmap
);
645 const int resultLastX
= result
.width() - 1;
646 const int srcLastX
= bitmap
.width() - 1;
648 for (int dest_y
= 0; dest_y
< result
.height(); ++dest_y
) {
649 const int src_y
= dest_y
<< 1;
650 const SkPMColor
* SK_RESTRICT cur_src0
= bitmap
.getAddr32(0, src_y
);
651 const SkPMColor
* SK_RESTRICT cur_src1
= cur_src0
;
652 if (src_y
+ 1 < bitmap
.height())
653 cur_src1
= bitmap
.getAddr32(0, src_y
+ 1);
655 SkPMColor
* SK_RESTRICT cur_dst
= result
.getAddr32(0, dest_y
);
657 for (int dest_x
= 0; dest_x
<= resultLastX
; ++dest_x
) {
658 // This code is based on downsampleby2_proc32 in SkBitmap.cpp. It is very
659 // clever in that it does two channels at once: alpha and green ("ag")
660 // and red and blue ("rb"). Each channel gets averaged across 4 pixels
661 // to get the result.
662 int bump_x
= (dest_x
<< 1) < srcLastX
;
663 SkPMColor tmp
, ag
, rb
;
665 // Top left pixel of the 2x2 block.
667 ag
= (tmp
>> 8) & 0xFF00FF;
670 // Top right pixel of the 2x2 block.
671 tmp
= cur_src0
[bump_x
];
672 ag
+= (tmp
>> 8) & 0xFF00FF;
673 rb
+= tmp
& 0xFF00FF;
675 // Bottom left pixel of the 2x2 block.
677 ag
+= (tmp
>> 8) & 0xFF00FF;
678 rb
+= tmp
& 0xFF00FF;
680 // Bottom right pixel of the 2x2 block.
681 tmp
= cur_src1
[bump_x
];
682 ag
+= (tmp
>> 8) & 0xFF00FF;
683 rb
+= tmp
& 0xFF00FF;
685 // Put the channels back together, dividing each by 4 to get the average.
686 // |ag| has the alpha and green channels shifted right by 8 bits from
687 // there they should end up, so shifting left by 6 gives them in the
688 // correct position divided by 4.
689 *cur_dst
++ = ((rb
>> 2) & 0xFF00FF) | ((ag
<< 6) & 0xFF00FF00);
700 SkBitmap
SkBitmapOperations::UnPreMultiply(const SkBitmap
& bitmap
) {
703 if (bitmap
.isOpaque())
706 SkBitmap opaque_bitmap
;
707 opaque_bitmap
.setConfig(bitmap
.config(), bitmap
.width(), bitmap
.height());
708 opaque_bitmap
.allocPixels();
711 SkAutoLockPixels
bitmap_lock(bitmap
);
712 SkAutoLockPixels
opaque_bitmap_lock(opaque_bitmap
);
713 for (int y
= 0; y
< opaque_bitmap
.height(); y
++) {
714 for (int x
= 0; x
< opaque_bitmap
.width(); x
++) {
715 uint32 src_pixel
= *bitmap
.getAddr32(x
, y
);
716 uint32
* dst_pixel
= opaque_bitmap
.getAddr32(x
, y
);
717 SkColor unmultiplied
= SkUnPreMultiply::PMColorToColor(src_pixel
);
718 *dst_pixel
= unmultiplied
;
723 opaque_bitmap
.setIsOpaque(true);
724 return opaque_bitmap
;
728 SkBitmap
SkBitmapOperations::CreateTransposedBitmap(const SkBitmap
& image
) {
729 DCHECK(image
.config() == SkBitmap::kARGB_8888_Config
);
732 transposed
.setConfig(
733 SkBitmap::kARGB_8888_Config
, image
.height(), image
.width(), 0);
734 transposed
.allocPixels();
736 SkAutoLockPixels
lock_image(image
);
737 SkAutoLockPixels
lock_transposed(transposed
);
739 for (int y
= 0; y
< image
.height(); ++y
) {
740 uint32
* image_row
= image
.getAddr32(0, y
);
741 for (int x
= 0; x
< image
.width(); ++x
) {
742 uint32
* dst
= transposed
.getAddr32(y
, x
);
751 SkBitmap
SkBitmapOperations::CreateColorMask(const SkBitmap
& bitmap
,
753 DCHECK(bitmap
.config() == SkBitmap::kARGB_8888_Config
);
756 color_mask
.setConfig(SkBitmap::kARGB_8888_Config
,
757 bitmap
.width(), bitmap
.height());
758 color_mask
.allocPixels();
759 color_mask
.eraseARGB(0, 0, 0, 0);
761 SkCanvas
canvas(color_mask
);
763 skia::RefPtr
<SkColorFilter
> color_filter
= skia::AdoptRef(
764 SkColorFilter::CreateModeFilter(c
, SkXfermode::kSrcIn_Mode
));
766 paint
.setColorFilter(color_filter
.get());
767 canvas
.drawBitmap(bitmap
, SkIntToScalar(0), SkIntToScalar(0), &paint
);
772 SkBitmap
SkBitmapOperations::CreateDropShadow(
773 const SkBitmap
& bitmap
,
774 const gfx::ShadowValues
& shadows
) {
775 DCHECK(bitmap
.config() == SkBitmap::kARGB_8888_Config
);
777 // Shadow margin insets are negative values because they grow outside.
778 // Negate them here as grow direction is not important and only pixel value
779 // is of interest here.
780 gfx::Insets shadow_margin
= -gfx::ShadowValue::GetMargin(shadows
);
782 SkBitmap image_with_shadow
;
783 image_with_shadow
.setConfig(SkBitmap::kARGB_8888_Config
,
784 bitmap
.width() + shadow_margin
.width(),
785 bitmap
.height() + shadow_margin
.height());
786 image_with_shadow
.allocPixels();
787 image_with_shadow
.eraseARGB(0, 0, 0, 0);
789 SkCanvas
canvas(image_with_shadow
);
790 canvas
.translate(SkIntToScalar(shadow_margin
.left()),
791 SkIntToScalar(shadow_margin
.top()));
794 for (size_t i
= 0; i
< shadows
.size(); ++i
) {
795 const gfx::ShadowValue
& shadow
= shadows
[i
];
796 SkBitmap shadow_image
= SkBitmapOperations::CreateColorMask(bitmap
,
799 skia::RefPtr
<SkBlurImageFilter
> filter
=
800 skia::AdoptRef(new SkBlurImageFilter(SkDoubleToScalar(shadow
.blur()),
801 SkDoubleToScalar(shadow
.blur())));
802 paint
.setImageFilter(filter
.get());
804 canvas
.saveLayer(0, &paint
);
805 canvas
.drawBitmap(shadow_image
,
806 SkIntToScalar(shadow
.x()),
807 SkIntToScalar(shadow
.y()));
811 canvas
.drawBitmap(bitmap
, SkIntToScalar(0), SkIntToScalar(0));
812 return image_with_shadow
;
816 SkBitmap
SkBitmapOperations::Rotate(const SkBitmap
& source
,
817 RotationAmount rotation
) {
819 SkScalar angle
= SkFloatToScalar(0.0f
);
823 angle
= SkFloatToScalar(90.0f
);
825 SkBitmap::kARGB_8888_Config
, source
.height(), source
.width());
827 case ROTATION_180_CW
:
828 angle
= SkFloatToScalar(180.0f
);
830 SkBitmap::kARGB_8888_Config
, source
.width(), source
.height());
832 case ROTATION_270_CW
:
833 angle
= SkFloatToScalar(270.0f
);
835 SkBitmap::kARGB_8888_Config
, source
.height(), source
.width());
838 result
.allocPixels();
839 SkCanvas
canvas(result
);
840 canvas
.clear(SkColorSetARGB(0, 0, 0, 0));
842 canvas
.translate(SkFloatToScalar(result
.width() * 0.5f
),
843 SkFloatToScalar(result
.height() * 0.5f
));
844 canvas
.rotate(angle
);
845 canvas
.translate(-SkFloatToScalar(source
.width() * 0.5f
),
846 -SkFloatToScalar(source
.height() * 0.5f
));
847 canvas
.drawBitmap(source
, 0, 0);