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 "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
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"
16 // GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly
17 // See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html
18 // To get back, we can just right shift by eight
19 // (or, formulated differently, i == (i*257)/256 for all i < 256).
21 SkColor
GdkColorToSkColor(GdkColor color
) {
22 return SkColorSetRGB(color
.red
>> 8, color
.green
>> 8, color
.blue
>> 8);
25 GdkColor
SkColorToGdkColor(SkColor color
) {
26 GdkColor gdk_color
= {
28 static_cast<guint16
>(SkColorGetR(color
) * kSkiaToGDKMultiplier
),
29 static_cast<guint16
>(SkColorGetG(color
) * kSkiaToGDKMultiplier
),
30 static_cast<guint16
>(SkColorGetB(color
) * kSkiaToGDKMultiplier
)
35 const SkBitmap
GdkPixbufToImageSkia(GdkPixbuf
* pixbuf
) {
36 // TODO(erg): What do we do in the case where the pixbuf fails these dchecks?
37 // I would prefer to use our gtk based canvas, but that would require
38 // recompiling half of our skia extensions with gtk support, which we can't
40 DCHECK_EQ(GDK_COLORSPACE_RGB
, gdk_pixbuf_get_colorspace(pixbuf
));
42 int n_channels
= gdk_pixbuf_get_n_channels(pixbuf
);
43 int w
= gdk_pixbuf_get_width(pixbuf
);
44 int h
= gdk_pixbuf_get_height(pixbuf
);
47 ret
.allocN32Pixels(w
, h
);
50 uint32_t* skia_data
= static_cast<uint32_t*>(ret
.getAddr(0, 0));
52 if (n_channels
== 4) {
53 int total_length
= w
* h
;
54 guchar
* gdk_pixels
= gdk_pixbuf_get_pixels(pixbuf
);
56 // Now here's the trick: we need to convert the gdk data (which is RGBA and
57 // isn't premultiplied) to skia (which can be anything and premultiplied).
58 for (int i
= 0; i
< total_length
; ++i
, gdk_pixels
+= 4) {
59 const unsigned char& red
= gdk_pixels
[0];
60 const unsigned char& green
= gdk_pixels
[1];
61 const unsigned char& blue
= gdk_pixels
[2];
62 const unsigned char& alpha
= gdk_pixels
[3];
64 skia_data
[i
] = SkPreMultiplyARGB(alpha
, red
, green
, blue
);
66 } else if (n_channels
== 3) {
67 // Because GDK makes rowstrides word aligned, we need to do something a bit
68 // more complex when a pixel isn't perfectly a word of memory.
69 int rowstride
= gdk_pixbuf_get_rowstride(pixbuf
);
70 guchar
* gdk_pixels
= gdk_pixbuf_get_pixels(pixbuf
);
71 for (int y
= 0; y
< h
; ++y
) {
72 int row
= y
* rowstride
;
74 for (int x
= 0; x
< w
; ++x
) {
75 guchar
* pixel
= gdk_pixels
+ row
+ (x
* 3);
76 const unsigned char& red
= pixel
[0];
77 const unsigned char& green
= pixel
[1];
78 const unsigned char& blue
= pixel
[2];
80 skia_data
[y
* w
+ x
] = SkPreMultiplyARGB(255, red
, green
, blue
);
90 GdkPixbuf
* GdkPixbufFromSkBitmap(const SkBitmap
& bitmap
) {
94 SkAutoLockPixels
lock_pixels(bitmap
);
96 int width
= bitmap
.width();
97 int height
= bitmap
.height();
100 gdk_pixbuf_new(GDK_COLORSPACE_RGB
, // The only colorspace gtk supports.
101 TRUE
, // There is an alpha channel.
106 // SkBitmaps are premultiplied, we need to unpremultiply them.
107 const int kBytesPerPixel
= 4;
108 uint8
* divided
= gdk_pixbuf_get_pixels(pixbuf
);
110 for (int y
= 0, i
= 0; y
< height
; y
++) {
111 for (int x
= 0; x
< width
; x
++) {
112 uint32 pixel
= bitmap
.getAddr32(0, y
)[x
];
114 int alpha
= SkColorGetA(pixel
);
115 if (alpha
!= 0 && alpha
!= 255) {
116 SkColor unmultiplied
= SkUnPreMultiply::PMColorToColor(pixel
);
117 divided
[i
+ 0] = SkColorGetR(unmultiplied
);
118 divided
[i
+ 1] = SkColorGetG(unmultiplied
);
119 divided
[i
+ 2] = SkColorGetB(unmultiplied
);
120 divided
[i
+ 3] = alpha
;
122 divided
[i
+ 0] = SkColorGetR(pixel
);
123 divided
[i
+ 1] = SkColorGetG(pixel
);
124 divided
[i
+ 2] = SkColorGetB(pixel
);
125 divided
[i
+ 3] = alpha
;
134 } // namespace libgtk2ui