OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" | 5 #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" |
6 | 6 |
7 #include <gdk/gdk.h> | 7 #include <gdk/gdk.h> |
8 | 8 |
| 9 #include "base/basictypes.h" |
| 10 #include "base/logging.h" |
| 11 #include "third_party/skia/include/core/SkBitmap.h" |
| 12 #include "third_party/skia/include/core/SkUnPreMultiply.h" |
| 13 |
9 namespace libgtk2ui { | 14 namespace libgtk2ui { |
10 | 15 |
11 const int kSkiaToGDKMultiplier = 257; | 16 const int kSkiaToGDKMultiplier = 257; |
12 | 17 |
13 // GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly | 18 // GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly |
14 // See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html | 19 // See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html |
15 // To get back, we can just right shift by eight | 20 // To get back, we can just right shift by eight |
16 // (or, formulated differently, i == (i*257)/256 for all i < 256). | 21 // (or, formulated differently, i == (i*257)/256 for all i < 256). |
17 | 22 |
18 SkColor GdkColorToSkColor(GdkColor color) { | 23 SkColor GdkColorToSkColor(GdkColor color) { |
19 return SkColorSetRGB(color.red >> 8, color.green >> 8, color.blue >> 8); | 24 return SkColorSetRGB(color.red >> 8, color.green >> 8, color.blue >> 8); |
20 } | 25 } |
21 | 26 |
22 GdkColor SkColorToGdkColor(SkColor color) { | 27 GdkColor SkColorToGdkColor(SkColor color) { |
23 GdkColor gdk_color = { | 28 GdkColor gdk_color = { |
24 0, | 29 0, |
25 static_cast<guint16>(SkColorGetR(color) * kSkiaToGDKMultiplier), | 30 static_cast<guint16>(SkColorGetR(color) * kSkiaToGDKMultiplier), |
26 static_cast<guint16>(SkColorGetG(color) * kSkiaToGDKMultiplier), | 31 static_cast<guint16>(SkColorGetG(color) * kSkiaToGDKMultiplier), |
27 static_cast<guint16>(SkColorGetB(color) * kSkiaToGDKMultiplier) | 32 static_cast<guint16>(SkColorGetB(color) * kSkiaToGDKMultiplier) |
28 }; | 33 }; |
29 return gdk_color; | 34 return gdk_color; |
30 } | 35 } |
31 | 36 |
| 37 const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf) { |
| 38 // TODO(erg): What do we do in the case where the pixbuf fails these dchecks? |
| 39 // I would prefer to use our gtk based canvas, but that would require |
| 40 // recompiling half of our skia extensions with gtk support, which we can't |
| 41 // do in this build. |
| 42 DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf)); |
| 43 |
| 44 int n_channels = gdk_pixbuf_get_n_channels(pixbuf); |
| 45 int w = gdk_pixbuf_get_width(pixbuf); |
| 46 int h = gdk_pixbuf_get_height(pixbuf); |
| 47 |
| 48 SkBitmap ret; |
| 49 ret.setConfig(SkBitmap::kARGB_8888_Config, w, h); |
| 50 ret.allocPixels(); |
| 51 ret.eraseColor(0); |
| 52 |
| 53 uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0)); |
| 54 |
| 55 if (n_channels == 4) { |
| 56 int total_length = w * h; |
| 57 guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf); |
| 58 |
| 59 // Now here's the trick: we need to convert the gdk data (which is RGBA and |
| 60 // isn't premultiplied) to skia (which can be anything and premultiplied). |
| 61 for (int i = 0; i < total_length; ++i, gdk_pixels += 4) { |
| 62 const unsigned char& red = gdk_pixels[0]; |
| 63 const unsigned char& green = gdk_pixels[1]; |
| 64 const unsigned char& blue = gdk_pixels[2]; |
| 65 const unsigned char& alpha = gdk_pixels[3]; |
| 66 |
| 67 skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue); |
| 68 } |
| 69 } else if (n_channels == 3) { |
| 70 // Because GDK makes rowstrides word aligned, we need to do something a bit |
| 71 // more complex when a pixel isn't perfectly a word of memory. |
| 72 int rowstride = gdk_pixbuf_get_rowstride(pixbuf); |
| 73 guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf); |
| 74 for (int y = 0; y < h; ++y) { |
| 75 int row = y * rowstride; |
| 76 |
| 77 for (int x = 0; x < w; ++x) { |
| 78 guchar* pixel = gdk_pixels + row + (x * 3); |
| 79 const unsigned char& red = pixel[0]; |
| 80 const unsigned char& green = pixel[1]; |
| 81 const unsigned char& blue = pixel[2]; |
| 82 |
| 83 skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue); |
| 84 } |
| 85 } |
| 86 } else { |
| 87 NOTREACHED(); |
| 88 } |
| 89 |
| 90 return ret; |
| 91 } |
| 92 |
| 93 GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) { |
| 94 if (bitmap.isNull()) |
| 95 return NULL; |
| 96 |
| 97 SkAutoLockPixels lock_pixels(bitmap); |
| 98 |
| 99 int width = bitmap.width(); |
| 100 int height = bitmap.height(); |
| 101 |
| 102 GdkPixbuf* pixbuf = |
| 103 gdk_pixbuf_new(GDK_COLORSPACE_RGB, // The only colorspace gtk supports. |
| 104 TRUE, // There is an alpha channel. |
| 105 8, |
| 106 width, |
| 107 height); |
| 108 |
| 109 // SkBitmaps are premultiplied, we need to unpremultiply them. |
| 110 const int kBytesPerPixel = 4; |
| 111 uint8* divided = gdk_pixbuf_get_pixels(pixbuf); |
| 112 |
| 113 for (int y = 0, i = 0; y < height; y++) { |
| 114 for (int x = 0; x < width; x++) { |
| 115 uint32 pixel = bitmap.getAddr32(0, y)[x]; |
| 116 |
| 117 int alpha = SkColorGetA(pixel); |
| 118 if (alpha != 0 && alpha != 255) { |
| 119 SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel); |
| 120 divided[i + 0] = SkColorGetR(unmultiplied); |
| 121 divided[i + 1] = SkColorGetG(unmultiplied); |
| 122 divided[i + 2] = SkColorGetB(unmultiplied); |
| 123 divided[i + 3] = alpha; |
| 124 } else { |
| 125 divided[i + 0] = SkColorGetR(pixel); |
| 126 divided[i + 1] = SkColorGetG(pixel); |
| 127 divided[i + 2] = SkColorGetB(pixel); |
| 128 divided[i + 3] = alpha; |
| 129 } |
| 130 i += kBytesPerPixel; |
| 131 } |
| 132 } |
| 133 |
| 134 return pixbuf; |
| 135 } |
| 136 |
32 } // namespace libgtk2ui | 137 } // namespace libgtk2ui |
OLD | NEW |