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
freeOwnedGPtr(GtkIconInfo * info)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
getThemeIconFileName(const char * name,int size)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
loadResourceSharedBuffer(CString name)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
initPlatformData()76 void BitmapImage::initPlatformData()
77 {
78 }
79
invalidatePlatformData()80 void BitmapImage::invalidatePlatformData()
81 {
82 }
83
loadImageFromFile(CString fileName)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
loadPlatformResource(const char * name)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
loadPlatformThemeIcon(const char * name,int size)105 PassRefPtr<Image> Image::loadPlatformThemeIcon(const char* name, int size)
106 {
107 return loadImageFromFile(getThemeIconFileName(name, size));
108 }
109
getCairoSurfacePixel(unsigned char * data,uint x,uint y,uint rowStride)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
getGdkPixbufPixel(guchar * data,uint x,uint y,uint rowStride)115 static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride)
116 {
117 return data + (y * rowStride) + x * 4;
118 }
119
getGdkPixbuf()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