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