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 35 namespace WTF { 36 37 template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo* info) 38 { 39 if (info) 40 gtk_icon_info_free(info); 41 } 42 43 } 44 45 namespace WebCore { 46 47 static 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 66 static 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 76 void BitmapImage::initPlatformData() 77 { 78 } 79 80 void BitmapImage::invalidatePlatformData() 81 { 82 } 83 84 PassRefPtr<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 94 PassRefPtr<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 105 PassRefPtr<Image> Image::loadPlatformThemeIcon(const char* name, int size) 106 { 107 return loadImageFromFile(getThemeIconFileName(name, size)); 108 } 109 110 static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride) 111 { 112 return data + (y * rowStride) + x * 4; 113 } 114 115 static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride) 116 { 117 return data + (y * rowStride) + x * 4; 118 } 119 120 GdkPixbuf* 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