• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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