• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ui/gfx/skbitmap_operations.h"
6 
7 #include <algorithm>
8 #include <string.h>
9 
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"
21 
22 // static
CreateInvertedBitmap(const SkBitmap & image)23 SkBitmap SkBitmapOperations::CreateInvertedBitmap(const SkBitmap& image) {
24   DCHECK(image.colorType() == kPMColor_SkColorType);
25 
26   SkAutoLockPixels lock_image(image);
27 
28   SkBitmap inverted;
29   inverted.allocN32Pixels(image.width(), image.height());
30   inverted.eraseARGB(0, 0, 0, 0);
31 
32   for (int y = 0; y < image.height(); ++y) {
33     uint32* image_row = image.getAddr32(0, y);
34     uint32* dst_row = inverted.getAddr32(0, y);
35 
36     for (int x = 0; x < image.width(); ++x) {
37       uint32 image_pixel = image_row[x];
38       dst_row[x] = (image_pixel & 0xFF000000) |
39                    (0x00FFFFFF - (image_pixel & 0x00FFFFFF));
40     }
41   }
42 
43   return inverted;
44 }
45 
46 // static
CreateSuperimposedBitmap(const SkBitmap & first,const SkBitmap & second)47 SkBitmap SkBitmapOperations::CreateSuperimposedBitmap(const SkBitmap& first,
48                                                       const SkBitmap& second) {
49   DCHECK(first.width() == second.width());
50   DCHECK(first.height() == second.height());
51   DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
52   DCHECK(first.colorType() == kPMColor_SkColorType);
53 
54   SkAutoLockPixels lock_first(first);
55   SkAutoLockPixels lock_second(second);
56 
57   SkBitmap superimposed;
58   superimposed.allocN32Pixels(first.width(), first.height());
59   superimposed.eraseARGB(0, 0, 0, 0);
60 
61   SkCanvas canvas(superimposed);
62 
63   SkRect rect;
64   rect.fLeft = 0;
65   rect.fTop = 0;
66   rect.fRight = SkIntToScalar(first.width());
67   rect.fBottom = SkIntToScalar(first.height());
68 
69   canvas.drawBitmapRect(first, NULL, rect);
70   canvas.drawBitmapRect(second, NULL, rect);
71 
72   return superimposed;
73 }
74 
75 // static
CreateBlendedBitmap(const SkBitmap & first,const SkBitmap & second,double alpha)76 SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
77                                                  const SkBitmap& second,
78                                                  double alpha) {
79   DCHECK((alpha >= 0) && (alpha <= 1));
80   DCHECK(first.width() == second.width());
81   DCHECK(first.height() == second.height());
82   DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
83   DCHECK(first.colorType() == kPMColor_SkColorType);
84 
85   // Optimize for case where we won't need to blend anything.
86   static const double alpha_min = 1.0 / 255;
87   static const double alpha_max = 254.0 / 255;
88   if (alpha < alpha_min)
89     return first;
90   else if (alpha > alpha_max)
91     return second;
92 
93   SkAutoLockPixels lock_first(first);
94   SkAutoLockPixels lock_second(second);
95 
96   SkBitmap blended;
97   blended.allocN32Pixels(first.width(), first.height());
98   blended.eraseARGB(0, 0, 0, 0);
99 
100   double first_alpha = 1 - alpha;
101 
102   for (int y = 0; y < first.height(); ++y) {
103     uint32* first_row = first.getAddr32(0, y);
104     uint32* second_row = second.getAddr32(0, y);
105     uint32* dst_row = blended.getAddr32(0, y);
106 
107     for (int x = 0; x < first.width(); ++x) {
108       uint32 first_pixel = first_row[x];
109       uint32 second_pixel = second_row[x];
110 
111       int a = static_cast<int>((SkColorGetA(first_pixel) * first_alpha) +
112                                (SkColorGetA(second_pixel) * alpha));
113       int r = static_cast<int>((SkColorGetR(first_pixel) * first_alpha) +
114                                (SkColorGetR(second_pixel) * alpha));
115       int g = static_cast<int>((SkColorGetG(first_pixel) * first_alpha) +
116                                (SkColorGetG(second_pixel) * alpha));
117       int b = static_cast<int>((SkColorGetB(first_pixel) * first_alpha) +
118                                (SkColorGetB(second_pixel) * alpha));
119 
120       dst_row[x] = SkColorSetARGB(a, r, g, b);
121     }
122   }
123 
124   return blended;
125 }
126 
127 // static
CreateMaskedBitmap(const SkBitmap & rgb,const SkBitmap & alpha)128 SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
129                                                 const SkBitmap& alpha) {
130   DCHECK(rgb.width() == alpha.width());
131   DCHECK(rgb.height() == alpha.height());
132   DCHECK(rgb.bytesPerPixel() == alpha.bytesPerPixel());
133   DCHECK(rgb.colorType() == kPMColor_SkColorType);
134   DCHECK(alpha.colorType() == kPMColor_SkColorType);
135 
136   SkBitmap masked;
137   masked.allocN32Pixels(rgb.width(), rgb.height());
138   masked.eraseARGB(0, 0, 0, 0);
139 
140   SkAutoLockPixels lock_rgb(rgb);
141   SkAutoLockPixels lock_alpha(alpha);
142   SkAutoLockPixels lock_masked(masked);
143 
144   for (int y = 0; y < masked.height(); ++y) {
145     uint32* rgb_row = rgb.getAddr32(0, y);
146     uint32* alpha_row = alpha.getAddr32(0, y);
147     uint32* dst_row = masked.getAddr32(0, y);
148 
149     for (int x = 0; x < masked.width(); ++x) {
150       SkColor rgb_pixel = SkUnPreMultiply::PMColorToColor(rgb_row[x]);
151       SkColor alpha_pixel = SkUnPreMultiply::PMColorToColor(alpha_row[x]);
152       int alpha = SkAlphaMul(SkColorGetA(rgb_pixel),
153                              SkAlpha255To256(SkColorGetA(alpha_pixel)));
154       int alpha_256 = SkAlpha255To256(alpha);
155       dst_row[x] = SkColorSetARGB(alpha,
156                                   SkAlphaMul(SkColorGetR(rgb_pixel), alpha_256),
157                                   SkAlphaMul(SkColorGetG(rgb_pixel), alpha_256),
158                                   SkAlphaMul(SkColorGetB(rgb_pixel),
159                                              alpha_256));
160     }
161   }
162 
163   return masked;
164 }
165 
166 // static
CreateButtonBackground(SkColor color,const SkBitmap & image,const SkBitmap & mask)167 SkBitmap SkBitmapOperations::CreateButtonBackground(SkColor color,
168                                                     const SkBitmap& image,
169                                                     const SkBitmap& mask) {
170   DCHECK(image.colorType() == kPMColor_SkColorType);
171   DCHECK(mask.colorType() == kPMColor_SkColorType);
172 
173   SkBitmap background;
174   background.allocN32Pixels(mask.width(), mask.height());
175 
176   double bg_a = SkColorGetA(color);
177   double bg_r = SkColorGetR(color);
178   double bg_g = SkColorGetG(color);
179   double bg_b = SkColorGetB(color);
180 
181   SkAutoLockPixels lock_mask(mask);
182   SkAutoLockPixels lock_image(image);
183   SkAutoLockPixels lock_background(background);
184 
185   for (int y = 0; y < mask.height(); ++y) {
186     uint32* dst_row = background.getAddr32(0, y);
187     uint32* image_row = image.getAddr32(0, y % image.height());
188     uint32* mask_row = mask.getAddr32(0, y);
189 
190     for (int x = 0; x < mask.width(); ++x) {
191       uint32 image_pixel = image_row[x % image.width()];
192 
193       double img_a = SkColorGetA(image_pixel);
194       double img_r = SkColorGetR(image_pixel);
195       double img_g = SkColorGetG(image_pixel);
196       double img_b = SkColorGetB(image_pixel);
197 
198       double img_alpha = static_cast<double>(img_a) / 255.0;
199       double img_inv = 1 - img_alpha;
200 
201       double mask_a = static_cast<double>(SkColorGetA(mask_row[x])) / 255.0;
202 
203       dst_row[x] = SkColorSetARGB(
204           static_cast<int>(std::min(255.0, bg_a + img_a) * mask_a),
205           static_cast<int>(((bg_r * img_inv) + (img_r * img_alpha)) * mask_a),
206           static_cast<int>(((bg_g * img_inv) + (img_g * img_alpha)) * mask_a),
207           static_cast<int>(((bg_b * img_inv) + (img_b * img_alpha)) * mask_a));
208     }
209   }
210 
211   return background;
212 }
213 
214 namespace {
215 namespace HSLShift {
216 
217 // TODO(viettrungluu): Some things have yet to be optimized at all.
218 
219 // Notes on and conventions used in the following code
220 //
221 // Conventions:
222 //  - R, G, B, A = obvious; as variables: |r|, |g|, |b|, |a| (see also below)
223 //  - H, S, L = obvious; as variables: |h|, |s|, |l| (see also below)
224 //  - variables derived from S, L shift parameters: |sdec| and |sinc| for S
225 //    increase and decrease factors, |ldec| and |linc| for L (see also below)
226 //
227 // To try to optimize HSL shifts, we do several things:
228 //  - Avoid unpremultiplying (then processing) then premultiplying. This means
229 //    that R, G, B values (and also L, but not H and S) should be treated as
230 //    having a range of 0..A (where A is alpha).
231 //  - Do things in integer/fixed-point. This avoids costly conversions between
232 //    floating-point and integer, though I should study the tradeoff more
233 //    carefully (presumably, at some point of processing complexity, converting
234 //    and processing using simpler floating-point code will begin to win in
235 //    performance). Also to be studied is the speed/type of floating point
236 //    conversions; see, e.g., <http://www.stereopsis.com/sree/fpu2006.html>.
237 //
238 // Conventions for fixed-point arithmetic
239 //  - Each function has a constant denominator (called |den|, which should be a
240 //    power of 2), appropriate for the computations done in that function.
241 //  - A value |x| is then typically represented by a numerator, named |x_num|,
242 //    so that its actual value is |x_num / den| (casting to floating-point
243 //    before division).
244 //  - To obtain |x_num| from |x|, simply multiply by |den|, i.e., |x_num = x *
245 //    den| (casting appropriately).
246 //  - When necessary, a value |x| may also be represented as a numerator over
247 //    the denominator squared (set |den2 = den * den|). In such a case, the
248 //    corresponding variable is called |x_num2| (so that its actual value is
249 //    |x_num^2 / den2|.
250 //  - The representation of the product of |x| and |y| is be called |x_y_num| if
251 //    |x * y == x_y_num / den|, and |xy_num2| if |x * y == x_y_num2 / den2|. In
252 //    the latter case, notice that one can calculate |x_y_num2 = x_num * y_num|.
253 
254 // Routine used to process a line; typically specialized for specific kinds of
255 // HSL shifts (to optimize).
256 typedef void (*LineProcessor)(const color_utils::HSL&,
257                               const SkPMColor*,
258                               SkPMColor*,
259                               int width);
260 
261 enum OperationOnH { kOpHNone = 0, kOpHShift, kNumHOps };
262 enum OperationOnS { kOpSNone = 0, kOpSDec, kOpSInc, kNumSOps };
263 enum OperationOnL { kOpLNone = 0, kOpLDec, kOpLInc, kNumLOps };
264 
265 // Epsilon used to judge when shift values are close enough to various critical
266 // values (typically 0.5, which yields a no-op for S and L shifts. 1/256 should
267 // be small enough, but let's play it safe>
268 const double epsilon = 0.0005;
269 
270 // Line processor: default/universal (i.e., old-school).
LineProcDefault(const color_utils::HSL & hsl_shift,const SkPMColor * in,SkPMColor * out,int width)271 void LineProcDefault(const color_utils::HSL& hsl_shift,
272                      const SkPMColor* in,
273                      SkPMColor* out,
274                      int width) {
275   for (int x = 0; x < width; x++) {
276     out[x] = SkPreMultiplyColor(color_utils::HSLShift(
277         SkUnPreMultiply::PMColorToColor(in[x]), hsl_shift));
278   }
279 }
280 
281 // Line processor: no-op (i.e., copy).
LineProcCopy(const color_utils::HSL & hsl_shift,const SkPMColor * in,SkPMColor * out,int width)282 void LineProcCopy(const color_utils::HSL& hsl_shift,
283                   const SkPMColor* in,
284                   SkPMColor* out,
285                   int width) {
286   DCHECK(hsl_shift.h < 0);
287   DCHECK(hsl_shift.s < 0 || fabs(hsl_shift.s - 0.5) < HSLShift::epsilon);
288   DCHECK(hsl_shift.l < 0 || fabs(hsl_shift.l - 0.5) < HSLShift::epsilon);
289   memcpy(out, in, static_cast<size_t>(width) * sizeof(out[0]));
290 }
291 
292 // Line processor: H no-op, S no-op, L decrease.
LineProcHnopSnopLdec(const color_utils::HSL & hsl_shift,const SkPMColor * in,SkPMColor * out,int width)293 void LineProcHnopSnopLdec(const color_utils::HSL& hsl_shift,
294                           const SkPMColor* in,
295                           SkPMColor* out,
296                           int width) {
297   const uint32_t den = 65536;
298 
299   DCHECK(hsl_shift.h < 0);
300   DCHECK(hsl_shift.s < 0 || fabs(hsl_shift.s - 0.5) < HSLShift::epsilon);
301   DCHECK(hsl_shift.l <= 0.5 - HSLShift::epsilon && hsl_shift.l >= 0);
302 
303   uint32_t ldec_num = static_cast<uint32_t>(hsl_shift.l * 2 * den);
304   for (int x = 0; x < width; x++) {
305     uint32_t a = SkGetPackedA32(in[x]);
306     uint32_t r = SkGetPackedR32(in[x]);
307     uint32_t g = SkGetPackedG32(in[x]);
308     uint32_t b = SkGetPackedB32(in[x]);
309     r = r * ldec_num / den;
310     g = g * ldec_num / den;
311     b = b * ldec_num / den;
312     out[x] = SkPackARGB32(a, r, g, b);
313   }
314 }
315 
316 // Line processor: H no-op, S no-op, L increase.
LineProcHnopSnopLinc(const color_utils::HSL & hsl_shift,const SkPMColor * in,SkPMColor * out,int width)317 void LineProcHnopSnopLinc(const color_utils::HSL& hsl_shift,
318                           const SkPMColor* in,
319                           SkPMColor* out,
320                           int width) {
321   const uint32_t den = 65536;
322 
323   DCHECK(hsl_shift.h < 0);
324   DCHECK(hsl_shift.s < 0 || fabs(hsl_shift.s - 0.5) < HSLShift::epsilon);
325   DCHECK(hsl_shift.l >= 0.5 + HSLShift::epsilon && hsl_shift.l <= 1);
326 
327   uint32_t linc_num = static_cast<uint32_t>((hsl_shift.l - 0.5) * 2 * den);
328   for (int x = 0; x < width; x++) {
329     uint32_t a = SkGetPackedA32(in[x]);
330     uint32_t r = SkGetPackedR32(in[x]);
331     uint32_t g = SkGetPackedG32(in[x]);
332     uint32_t b = SkGetPackedB32(in[x]);
333     r += (a - r) * linc_num / den;
334     g += (a - g) * linc_num / den;
335     b += (a - b) * linc_num / den;
336     out[x] = SkPackARGB32(a, r, g, b);
337   }
338 }
339 
340 // Saturation changes modifications in RGB
341 //
342 // (Note that as a further complication, the values we deal in are
343 // premultiplied, so R/G/B values must be in the range 0..A. For mathematical
344 // purposes, one may as well use r=R/A, g=G/A, b=B/A. Without loss of
345 // generality, assume that R/G/B values are in the range 0..1.)
346 //
347 // Let Max = max(R,G,B), Min = min(R,G,B), and Med be the median value. Then L =
348 // (Max+Min)/2. If L is to remain constant, Max+Min must also remain constant.
349 //
350 // For H to remain constant, first, the (numerical) order of R/G/B (from
351 // smallest to largest) must remain the same. Second, all the ratios
352 // (R-G)/(Max-Min), (R-B)/(Max-Min), (G-B)/(Max-Min) must remain constant (of
353 // course, if Max = Min, then S = 0 and no saturation change is well-defined,
354 // since H is not well-defined).
355 //
356 // Let C_max be a colour with value Max, C_min be one with value Min, and C_med
357 // the remaining colour. Increasing saturation (to the maximum) is accomplished
358 // by increasing the value of C_max while simultaneously decreasing C_min and
359 // changing C_med so that the ratios are maintained; for the latter, it suffices
360 // to keep (C_med-C_min)/(C_max-C_min) constant (and equal to
361 // (Med-Min)/(Max-Min)).
362 
363 // Line processor: H no-op, S decrease, L no-op.
LineProcHnopSdecLnop(const color_utils::HSL & hsl_shift,const SkPMColor * in,SkPMColor * out,int width)364 void LineProcHnopSdecLnop(const color_utils::HSL& hsl_shift,
365                           const SkPMColor* in,
366                           SkPMColor* out,
367                           int width) {
368   DCHECK(hsl_shift.h < 0);
369   DCHECK(hsl_shift.s >= 0 && hsl_shift.s <= 0.5 - HSLShift::epsilon);
370   DCHECK(hsl_shift.l < 0 || fabs(hsl_shift.l - 0.5) < HSLShift::epsilon);
371 
372   const int32_t denom = 65536;
373   int32_t s_numer = static_cast<int32_t>(hsl_shift.s * 2 * denom);
374   for (int x = 0; x < width; x++) {
375     int32_t a = static_cast<int32_t>(SkGetPackedA32(in[x]));
376     int32_t r = static_cast<int32_t>(SkGetPackedR32(in[x]));
377     int32_t g = static_cast<int32_t>(SkGetPackedG32(in[x]));
378     int32_t b = static_cast<int32_t>(SkGetPackedB32(in[x]));
379 
380     int32_t vmax, vmin;
381     if (r > g) {  // This uses 3 compares rather than 4.
382       vmax = std::max(r, b);
383       vmin = std::min(g, b);
384     } else {
385       vmax = std::max(g, b);
386       vmin = std::min(r, b);
387     }
388 
389     // Use denom * L to avoid rounding.
390     int32_t denom_l = (vmax + vmin) * (denom / 2);
391     int32_t s_numer_l = (vmax + vmin) * s_numer / 2;
392 
393     r = (denom_l + r * s_numer - s_numer_l) / denom;
394     g = (denom_l + g * s_numer - s_numer_l) / denom;
395     b = (denom_l + b * s_numer - s_numer_l) / denom;
396     out[x] = SkPackARGB32(a, r, g, b);
397   }
398 }
399 
400 // Line processor: H no-op, S decrease, L decrease.
LineProcHnopSdecLdec(const color_utils::HSL & hsl_shift,const SkPMColor * in,SkPMColor * out,int width)401 void LineProcHnopSdecLdec(const color_utils::HSL& hsl_shift,
402                           const SkPMColor* in,
403                           SkPMColor* out,
404                           int width) {
405   DCHECK(hsl_shift.h < 0);
406   DCHECK(hsl_shift.s >= 0 && hsl_shift.s <= 0.5 - HSLShift::epsilon);
407   DCHECK(hsl_shift.l >= 0 && hsl_shift.l <= 0.5 - HSLShift::epsilon);
408 
409   // Can't be too big since we need room for denom*denom and a bit for sign.
410   const int32_t denom = 1024;
411   int32_t l_numer = static_cast<int32_t>(hsl_shift.l * 2 * denom);
412   int32_t s_numer = static_cast<int32_t>(hsl_shift.s * 2 * denom);
413   for (int x = 0; x < width; x++) {
414     int32_t a = static_cast<int32_t>(SkGetPackedA32(in[x]));
415     int32_t r = static_cast<int32_t>(SkGetPackedR32(in[x]));
416     int32_t g = static_cast<int32_t>(SkGetPackedG32(in[x]));
417     int32_t b = static_cast<int32_t>(SkGetPackedB32(in[x]));
418 
419     int32_t vmax, vmin;
420     if (r > g) {  // This uses 3 compares rather than 4.
421       vmax = std::max(r, b);
422       vmin = std::min(g, b);
423     } else {
424       vmax = std::max(g, b);
425       vmin = std::min(r, b);
426     }
427 
428     // Use denom * L to avoid rounding.
429     int32_t denom_l = (vmax + vmin) * (denom / 2);
430     int32_t s_numer_l = (vmax + vmin) * s_numer / 2;
431 
432     r = (denom_l + r * s_numer - s_numer_l) * l_numer / (denom * denom);
433     g = (denom_l + g * s_numer - s_numer_l) * l_numer / (denom * denom);
434     b = (denom_l + b * s_numer - s_numer_l) * l_numer / (denom * denom);
435     out[x] = SkPackARGB32(a, r, g, b);
436   }
437 }
438 
439 // Line processor: H no-op, S decrease, L increase.
LineProcHnopSdecLinc(const color_utils::HSL & hsl_shift,const SkPMColor * in,SkPMColor * out,int width)440 void LineProcHnopSdecLinc(const color_utils::HSL& hsl_shift,
441                           const SkPMColor* in,
442                           SkPMColor* out,
443                           int width) {
444   DCHECK(hsl_shift.h < 0);
445   DCHECK(hsl_shift.s >= 0 && hsl_shift.s <= 0.5 - HSLShift::epsilon);
446   DCHECK(hsl_shift.l >= 0.5 + HSLShift::epsilon && hsl_shift.l <= 1);
447 
448   // Can't be too big since we need room for denom*denom and a bit for sign.
449   const int32_t denom = 1024;
450   int32_t l_numer = static_cast<int32_t>((hsl_shift.l - 0.5) * 2 * denom);
451   int32_t s_numer = static_cast<int32_t>(hsl_shift.s * 2 * denom);
452   for (int x = 0; x < width; x++) {
453     int32_t a = static_cast<int32_t>(SkGetPackedA32(in[x]));
454     int32_t r = static_cast<int32_t>(SkGetPackedR32(in[x]));
455     int32_t g = static_cast<int32_t>(SkGetPackedG32(in[x]));
456     int32_t b = static_cast<int32_t>(SkGetPackedB32(in[x]));
457 
458     int32_t vmax, vmin;
459     if (r > g) {  // This uses 3 compares rather than 4.
460       vmax = std::max(r, b);
461       vmin = std::min(g, b);
462     } else {
463       vmax = std::max(g, b);
464       vmin = std::min(r, b);
465     }
466 
467     // Use denom * L to avoid rounding.
468     int32_t denom_l = (vmax + vmin) * (denom / 2);
469     int32_t s_numer_l = (vmax + vmin) * s_numer / 2;
470 
471     r = denom_l + r * s_numer - s_numer_l;
472     g = denom_l + g * s_numer - s_numer_l;
473     b = denom_l + b * s_numer - s_numer_l;
474 
475     r = (r * denom + (a * denom - r) * l_numer) / (denom * denom);
476     g = (g * denom + (a * denom - g) * l_numer) / (denom * denom);
477     b = (b * denom + (a * denom - b) * l_numer) / (denom * denom);
478     out[x] = SkPackARGB32(a, r, g, b);
479   }
480 }
481 
482 const LineProcessor kLineProcessors[kNumHOps][kNumSOps][kNumLOps] = {
483   { // H: kOpHNone
484     { // S: kOpSNone
485       LineProcCopy,         // L: kOpLNone
486       LineProcHnopSnopLdec, // L: kOpLDec
487       LineProcHnopSnopLinc  // L: kOpLInc
488     },
489     { // S: kOpSDec
490       LineProcHnopSdecLnop, // L: kOpLNone
491       LineProcHnopSdecLdec, // L: kOpLDec
492       LineProcHnopSdecLinc  // L: kOpLInc
493     },
494     { // S: kOpSInc
495       LineProcDefault, // L: kOpLNone
496       LineProcDefault, // L: kOpLDec
497       LineProcDefault  // L: kOpLInc
498     }
499   },
500   { // H: kOpHShift
501     { // S: kOpSNone
502       LineProcDefault, // L: kOpLNone
503       LineProcDefault, // L: kOpLDec
504       LineProcDefault  // L: kOpLInc
505     },
506     { // S: kOpSDec
507       LineProcDefault, // L: kOpLNone
508       LineProcDefault, // L: kOpLDec
509       LineProcDefault  // L: kOpLInc
510     },
511     { // S: kOpSInc
512       LineProcDefault, // L: kOpLNone
513       LineProcDefault, // L: kOpLDec
514       LineProcDefault  // L: kOpLInc
515     }
516   }
517 };
518 
519 }  // namespace HSLShift
520 }  // namespace
521 
522 // static
CreateHSLShiftedBitmap(const SkBitmap & bitmap,const color_utils::HSL & hsl_shift)523 SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
524     const SkBitmap& bitmap,
525     const color_utils::HSL& hsl_shift) {
526   // Default to NOPs.
527   HSLShift::OperationOnH H_op = HSLShift::kOpHNone;
528   HSLShift::OperationOnS S_op = HSLShift::kOpSNone;
529   HSLShift::OperationOnL L_op = HSLShift::kOpLNone;
530 
531   if (hsl_shift.h >= 0 && hsl_shift.h <= 1)
532     H_op = HSLShift::kOpHShift;
533 
534   // Saturation shift: 0 -> fully desaturate, 0.5 -> NOP, 1 -> fully saturate.
535   if (hsl_shift.s >= 0 && hsl_shift.s <= (0.5 - HSLShift::epsilon))
536     S_op = HSLShift::kOpSDec;
537   else if (hsl_shift.s >= (0.5 + HSLShift::epsilon))
538     S_op = HSLShift::kOpSInc;
539 
540   // Lightness shift: 0 -> black, 0.5 -> NOP, 1 -> white.
541   if (hsl_shift.l >= 0 && hsl_shift.l <= (0.5 - HSLShift::epsilon))
542     L_op = HSLShift::kOpLDec;
543   else if (hsl_shift.l >= (0.5 + HSLShift::epsilon))
544     L_op = HSLShift::kOpLInc;
545 
546   HSLShift::LineProcessor line_proc =
547       HSLShift::kLineProcessors[H_op][S_op][L_op];
548 
549   DCHECK(bitmap.empty() == false);
550   DCHECK(bitmap.colorType() == kPMColor_SkColorType);
551 
552   SkBitmap shifted;
553   shifted.allocN32Pixels(bitmap.width(), bitmap.height());
554   shifted.eraseARGB(0, 0, 0, 0);
555 
556   SkAutoLockPixels lock_bitmap(bitmap);
557   SkAutoLockPixels lock_shifted(shifted);
558 
559   // Loop through the pixels of the original bitmap.
560   for (int y = 0; y < bitmap.height(); ++y) {
561     SkPMColor* pixels = bitmap.getAddr32(0, y);
562     SkPMColor* tinted_pixels = shifted.getAddr32(0, y);
563 
564     (*line_proc)(hsl_shift, pixels, tinted_pixels, bitmap.width());
565   }
566 
567   return shifted;
568 }
569 
570 // static
CreateTiledBitmap(const SkBitmap & source,int src_x,int src_y,int dst_w,int dst_h)571 SkBitmap SkBitmapOperations::CreateTiledBitmap(const SkBitmap& source,
572                                                int src_x, int src_y,
573                                                int dst_w, int dst_h) {
574   DCHECK(source.colorType() == kPMColor_SkColorType);
575 
576   SkBitmap cropped;
577   cropped.allocN32Pixels(dst_w, dst_h);
578   cropped.eraseARGB(0, 0, 0, 0);
579 
580   SkAutoLockPixels lock_source(source);
581   SkAutoLockPixels lock_cropped(cropped);
582 
583   // Loop through the pixels of the original bitmap.
584   for (int y = 0; y < dst_h; ++y) {
585     int y_pix = (src_y + y) % source.height();
586     while (y_pix < 0)
587       y_pix += source.height();
588 
589     uint32* source_row = source.getAddr32(0, y_pix);
590     uint32* dst_row = cropped.getAddr32(0, y);
591 
592     for (int x = 0; x < dst_w; ++x) {
593       int x_pix = (src_x + x) % source.width();
594       while (x_pix < 0)
595         x_pix += source.width();
596 
597       dst_row[x] = source_row[x_pix];
598     }
599   }
600 
601   return cropped;
602 }
603 
604 // static
DownsampleByTwoUntilSize(const SkBitmap & bitmap,int min_w,int min_h)605 SkBitmap SkBitmapOperations::DownsampleByTwoUntilSize(const SkBitmap& bitmap,
606                                                       int min_w, int min_h) {
607   if ((bitmap.width() <= min_w) || (bitmap.height() <= min_h) ||
608       (min_w < 0) || (min_h < 0))
609     return bitmap;
610 
611   // Since bitmaps are refcounted, this copy will be fast.
612   SkBitmap current = bitmap;
613   while ((current.width() >= min_w * 2) && (current.height() >= min_h * 2) &&
614          (current.width() > 1) && (current.height() > 1))
615     current = DownsampleByTwo(current);
616   return current;
617 }
618 
619 // static
DownsampleByTwo(const SkBitmap & bitmap)620 SkBitmap SkBitmapOperations::DownsampleByTwo(const SkBitmap& bitmap) {
621   // Handle the nop case.
622   if ((bitmap.width() <= 1) || (bitmap.height() <= 1))
623     return bitmap;
624 
625   SkBitmap result;
626   result.allocN32Pixels((bitmap.width() + 1) / 2, (bitmap.height() + 1) / 2);
627 
628   SkAutoLockPixels lock(bitmap);
629 
630   const int resultLastX = result.width() - 1;
631   const int srcLastX = bitmap.width() - 1;
632 
633   for (int dest_y = 0; dest_y < result.height(); ++dest_y) {
634     const int src_y = dest_y << 1;
635     const SkPMColor* SK_RESTRICT cur_src0 = bitmap.getAddr32(0, src_y);
636     const SkPMColor* SK_RESTRICT cur_src1 = cur_src0;
637     if (src_y + 1 < bitmap.height())
638       cur_src1 = bitmap.getAddr32(0, src_y + 1);
639 
640     SkPMColor* SK_RESTRICT cur_dst = result.getAddr32(0, dest_y);
641 
642     for (int dest_x = 0; dest_x <= resultLastX; ++dest_x) {
643       // This code is based on downsampleby2_proc32 in SkBitmap.cpp. It is very
644       // clever in that it does two channels at once: alpha and green ("ag")
645       // and red and blue ("rb"). Each channel gets averaged across 4 pixels
646       // to get the result.
647       int bump_x = (dest_x << 1) < srcLastX;
648       SkPMColor tmp, ag, rb;
649 
650       // Top left pixel of the 2x2 block.
651       tmp = cur_src0[0];
652       ag = (tmp >> 8) & 0xFF00FF;
653       rb = tmp & 0xFF00FF;
654 
655       // Top right pixel of the 2x2 block.
656       tmp = cur_src0[bump_x];
657       ag += (tmp >> 8) & 0xFF00FF;
658       rb += tmp & 0xFF00FF;
659 
660       // Bottom left pixel of the 2x2 block.
661       tmp = cur_src1[0];
662       ag += (tmp >> 8) & 0xFF00FF;
663       rb += tmp & 0xFF00FF;
664 
665       // Bottom right pixel of the 2x2 block.
666       tmp = cur_src1[bump_x];
667       ag += (tmp >> 8) & 0xFF00FF;
668       rb += tmp & 0xFF00FF;
669 
670       // Put the channels back together, dividing each by 4 to get the average.
671       // |ag| has the alpha and green channels shifted right by 8 bits from
672       // there they should end up, so shifting left by 6 gives them in the
673       // correct position divided by 4.
674       *cur_dst++ = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00);
675 
676       cur_src0 += 2;
677       cur_src1 += 2;
678     }
679   }
680 
681   return result;
682 }
683 
684 // static
UnPreMultiply(const SkBitmap & bitmap)685 SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
686   if (bitmap.isNull())
687     return bitmap;
688   if (bitmap.isOpaque())
689     return bitmap;
690 
691   SkImageInfo info = bitmap.info();
692   info.fAlphaType = kOpaque_SkAlphaType;
693   SkBitmap opaque_bitmap;
694   opaque_bitmap.allocPixels(info);
695 
696   {
697     SkAutoLockPixels bitmap_lock(bitmap);
698     SkAutoLockPixels opaque_bitmap_lock(opaque_bitmap);
699     for (int y = 0; y < opaque_bitmap.height(); y++) {
700       for (int x = 0; x < opaque_bitmap.width(); x++) {
701         uint32 src_pixel = *bitmap.getAddr32(x, y);
702         uint32* dst_pixel = opaque_bitmap.getAddr32(x, y);
703         SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(src_pixel);
704         *dst_pixel = unmultiplied;
705       }
706     }
707   }
708 
709   return opaque_bitmap;
710 }
711 
712 // static
CreateTransposedBitmap(const SkBitmap & image)713 SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
714   DCHECK(image.colorType() == kPMColor_SkColorType);
715 
716   SkBitmap transposed;
717   transposed.allocN32Pixels(image.height(), image.width());
718 
719   SkAutoLockPixels lock_image(image);
720   SkAutoLockPixels lock_transposed(transposed);
721 
722   for (int y = 0; y < image.height(); ++y) {
723     uint32* image_row = image.getAddr32(0, y);
724     for (int x = 0; x < image.width(); ++x) {
725       uint32* dst = transposed.getAddr32(y, x);
726       *dst = image_row[x];
727     }
728   }
729 
730   return transposed;
731 }
732 
733 // static
CreateColorMask(const SkBitmap & bitmap,SkColor c)734 SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
735                                              SkColor c) {
736   DCHECK(bitmap.colorType() == kPMColor_SkColorType);
737 
738   SkBitmap color_mask;
739   color_mask.allocN32Pixels(bitmap.width(), bitmap.height());
740   color_mask.eraseARGB(0, 0, 0, 0);
741 
742   SkCanvas canvas(color_mask);
743 
744   skia::RefPtr<SkColorFilter> color_filter = skia::AdoptRef(
745       SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode));
746   SkPaint paint;
747   paint.setColorFilter(color_filter.get());
748   canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
749   return color_mask;
750 }
751 
752 // static
CreateDropShadow(const SkBitmap & bitmap,const gfx::ShadowValues & shadows)753 SkBitmap SkBitmapOperations::CreateDropShadow(
754     const SkBitmap& bitmap,
755     const gfx::ShadowValues& shadows) {
756   DCHECK(bitmap.colorType() == kPMColor_SkColorType);
757 
758   // Shadow margin insets are negative values because they grow outside.
759   // Negate them here as grow direction is not important and only pixel value
760   // is of interest here.
761   gfx::Insets shadow_margin = -gfx::ShadowValue::GetMargin(shadows);
762 
763   SkBitmap image_with_shadow;
764   image_with_shadow.allocN32Pixels(bitmap.width() + shadow_margin.width(),
765                                    bitmap.height() + shadow_margin.height());
766   image_with_shadow.eraseARGB(0, 0, 0, 0);
767 
768   SkCanvas canvas(image_with_shadow);
769   canvas.translate(SkIntToScalar(shadow_margin.left()),
770                    SkIntToScalar(shadow_margin.top()));
771 
772   SkPaint paint;
773   for (size_t i = 0; i < shadows.size(); ++i) {
774     const gfx::ShadowValue& shadow = shadows[i];
775     SkBitmap shadow_image = SkBitmapOperations::CreateColorMask(bitmap,
776                                                                 shadow.color());
777 
778     skia::RefPtr<SkBlurImageFilter> filter =
779         skia::AdoptRef(SkBlurImageFilter::Create(
780             SkDoubleToScalar(shadow.blur()), SkDoubleToScalar(shadow.blur())));
781     paint.setImageFilter(filter.get());
782 
783     canvas.saveLayer(0, &paint);
784     canvas.drawBitmap(shadow_image,
785                       SkIntToScalar(shadow.x()),
786                       SkIntToScalar(shadow.y()));
787     canvas.restore();
788   }
789 
790   canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0));
791   return image_with_shadow;
792 }
793 
794 // static
Rotate(const SkBitmap & source,RotationAmount rotation)795 SkBitmap SkBitmapOperations::Rotate(const SkBitmap& source,
796                                     RotationAmount rotation) {
797   SkBitmap result;
798   SkScalar angle = SkFloatToScalar(0.0f);
799 
800   switch (rotation) {
801    case ROTATION_90_CW:
802      angle = SkFloatToScalar(90.0f);
803      result.setConfig(
804          SkBitmap::kARGB_8888_Config, source.height(), source.width());
805      break;
806    case ROTATION_180_CW:
807      angle = SkFloatToScalar(180.0f);
808      result.setConfig(
809          SkBitmap::kARGB_8888_Config, source.width(), source.height());
810      break;
811    case ROTATION_270_CW:
812      angle = SkFloatToScalar(270.0f);
813      result.setConfig(
814          SkBitmap::kARGB_8888_Config, source.height(), source.width());
815      break;
816   }
817   result.allocPixels();
818   SkCanvas canvas(result);
819   canvas.clear(SkColorSetARGB(0, 0, 0, 0));
820 
821   canvas.translate(SkFloatToScalar(result.width() * 0.5f),
822                    SkFloatToScalar(result.height() * 0.5f));
823   canvas.rotate(angle);
824   canvas.translate(-SkFloatToScalar(source.width() * 0.5f),
825                    -SkFloatToScalar(source.height() * 0.5f));
826   canvas.drawBitmap(source, 0, 0);
827   canvas.flush();
828 
829   return result;
830 }
831