| 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 |