1/* 2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#include "BitmapImage.h" 29#include "CString.h" 30#include "GOwnPtr.h" 31 32#include <cairo.h> 33#include <gtk/gtk.h> 34 35namespace WTF { 36 37template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo* info) 38{ 39 if (info) 40 gtk_icon_info_free(info); 41} 42 43} 44 45namespace WebCore { 46 47static CString getThemeIconFileName(const char* name, int size) 48{ 49 GtkIconInfo* iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(), 50 name, size, GTK_ICON_LOOKUP_NO_SVG); 51 // Try to fallback on MISSING_IMAGE. 52 if (!iconInfo) 53 iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(), 54 GTK_STOCK_MISSING_IMAGE, size, 55 GTK_ICON_LOOKUP_NO_SVG); 56 if (iconInfo) { 57 GOwnPtr<GtkIconInfo> info(iconInfo); 58 return CString(gtk_icon_info_get_filename(info.get())); 59 } 60 61 // No icon was found, this can happen if not GTK theme is set. In 62 // that case an empty Image will be created. 63 return CString(); 64} 65 66static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(CString name) 67{ 68 GOwnPtr<gchar> content; 69 gsize length; 70 if (!g_file_get_contents(name.data(), &content.outPtr(), &length, 0)) 71 return SharedBuffer::create(); 72 73 return SharedBuffer::create(content.get(), length); 74} 75 76void BitmapImage::initPlatformData() 77{ 78} 79 80void BitmapImage::invalidatePlatformData() 81{ 82} 83 84PassRefPtr<Image> loadImageFromFile(CString fileName) 85{ 86 RefPtr<BitmapImage> img = BitmapImage::create(); 87 if (!fileName.isNull()) { 88 RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(fileName); 89 img->setData(buffer.release(), true); 90 } 91 return img.release(); 92} 93 94PassRefPtr<Image> Image::loadPlatformResource(const char* name) 95{ 96 CString fileName; 97 if (!strcmp("missingImage", name)) 98 fileName = getThemeIconFileName(GTK_STOCK_MISSING_IMAGE, 16); 99 if (fileName.isNull()) 100 fileName = String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, name).utf8(); 101 102 return loadImageFromFile(fileName); 103} 104 105PassRefPtr<Image> Image::loadPlatformThemeIcon(const char* name, int size) 106{ 107 return loadImageFromFile(getThemeIconFileName(name, size)); 108} 109 110static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride) 111{ 112 return data + (y * rowStride) + x * 4; 113} 114 115static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride) 116{ 117 return data + (y * rowStride) + x * 4; 118} 119 120GdkPixbuf* BitmapImage::getGdkPixbuf() 121{ 122 int width = cairo_image_surface_get_width(frameAtIndex(currentFrame())); 123 int height = cairo_image_surface_get_height(frameAtIndex(currentFrame())); 124 unsigned char* surfaceData = cairo_image_surface_get_data(frameAtIndex(currentFrame())); 125 int surfaceRowStride = cairo_image_surface_get_stride(frameAtIndex(currentFrame())); 126 127 GdkPixbuf* dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); 128 if (!dest) 129 return 0; 130 131 guchar* pixbufData = gdk_pixbuf_get_pixels(dest); 132 int pixbufRowStride = gdk_pixbuf_get_rowstride(dest); 133 134 /* From: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t 135 * "CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with alpha in 136 * the upper 8 bits, then red, then green, then blue. The 32-bit 137 * quantities are stored native-endian. Pre-multiplied alpha is used. 138 * (That is, 50% transparent red is 0x80800000, not 0x80ff0000.)" 139 * 140 * See http://developer.gimp.org/api/2.0/gdk-pixbuf/gdk-pixbuf-gdk-pixbuf.html#GdkPixbuf 141 * for information on the structure of GdkPixbufs stored with GDK_COLORSPACE_RGB. 142 * 143 * RGB color channels in CAIRO_FORMAT_ARGB32 are stored based on the 144 * endianness of the machine and are also multiplied by the alpha channel. 145 * To properly transfer the data from the Cairo surface we must divide each 146 * of the RGB channels by the alpha channel and then reorder all channels 147 * if this machine is little-endian. 148 */ 149 for (int y = 0; y < height; y++) { 150 for (int x = 0; x < width; x++) { 151 unsigned char* source = getCairoSurfacePixel(surfaceData, x, y, surfaceRowStride); 152 guchar* dest = getGdkPixbufPixel(pixbufData, x, y, pixbufRowStride); 153 154#if G_BYTE_ORDER == G_LITTLE_ENDIAN 155 guchar alpha = source[3]; 156 dest[0] = alpha ? ((source[2] * 255) / alpha) : 0; 157 dest[1] = alpha ? ((source[1] * 255) / alpha) : 0; 158 dest[2] = alpha ? ((source[0] * 255) / alpha) : 0; 159 dest[3] = alpha; 160#else 161 guchar alpha = source[0]; 162 dest[0] = alpha ? ((source[1] * 255) / alpha) : 0; 163 dest[1] = alpha ? ((source[2] * 255) / alpha) : 0; 164 dest[2] = alpha ? ((source[3] * 255) / alpha) : 0; 165 dest[3] = alpha; 166#endif 167 } 168 } 169 170 return dest; 171} 172 173} 174