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 const int kSkiaToGDKMultiplier
= 257;
18 // GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly
19 // See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html
20 // To get back, we can just right shift by eight
21 // (or, formulated differently, i == (i*257)/256 for all i < 256).
23 SkColor
GdkColorToSkColor(GdkColor color
) {
24 return SkColorSetRGB(color
.red
>> 8, color
.green
>> 8, color
.blue
>> 8);
27 GdkColor
SkColorToGdkColor(SkColor color
) {
28 GdkColor gdk_color
= {
30 static_cast<guint16
>(SkColorGetR(color
) * kSkiaToGDKMultiplier
),
31 static_cast<guint16
>(SkColorGetG(color
) * kSkiaToGDKMultiplier
),
32 static_cast<guint16
>(SkColorGetB(color
) * kSkiaToGDKMultiplier
)
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
42 DCHECK_EQ(GDK_COLORSPACE_RGB
, gdk_pixbuf_get_colorspace(pixbuf
));
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
);
49 ret
.setConfig(SkBitmap::kARGB_8888_Config
, w
, h
);
53 uint32_t* skia_data
= static_cast<uint32_t*>(ret
.getAddr(0, 0));
55 if (n_channels
== 4) {
56 int total_length
= w
* h
;
57 guchar
* gdk_pixels
= gdk_pixbuf_get_pixels(pixbuf
);
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];
67 skia_data
[i
] = SkPreMultiplyARGB(alpha
, red
, green
, blue
);
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
;
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];
83 skia_data
[y
* w
+ x
] = SkPreMultiplyARGB(255, red
, green
, blue
);
93 GdkPixbuf
* GdkPixbufFromSkBitmap(const SkBitmap
& bitmap
) {
97 SkAutoLockPixels
lock_pixels(bitmap
);
99 int width
= bitmap
.width();
100 int height
= bitmap
.height();
103 gdk_pixbuf_new(GDK_COLORSPACE_RGB
, // The only colorspace gtk supports.
104 TRUE
, // There is an alpha channel.
109 // SkBitmaps are premultiplied, we need to unpremultiply them.
110 const int kBytesPerPixel
= 4;
111 uint8
* divided
= gdk_pixbuf_get_pixels(pixbuf
);
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
];
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
;
125 divided
[i
+ 0] = SkColorGetR(pixel
);
126 divided
[i
+ 1] = SkColorGetG(pixel
);
127 divided
[i
+ 2] = SkColorGetB(pixel
);
128 divided
[i
+ 3] = alpha
;
137 } // namespace libgtk2ui