38da70d1c672f2b59514604e7fe04492dd96fbbb
[WebKit-https.git] / WebCore / platform / graphics / gtk / ImageGtk.cpp
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 getIconFileNameOrFallback(const char* name, const char* fallback)
48 {
49     GOwnPtr<GtkIconInfo> info(gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
50                                                          name, 16, GTK_ICON_LOOKUP_NO_SVG));
51     if (!info)
52         return String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, fallback).utf8();
53
54     return CString(gtk_icon_info_get_filename(info.get()));
55 }
56
57 static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name)
58 {
59     CString fileName;
60
61     // Find the path for the image
62     if (strcmp("missingImage", name) == 0)
63         fileName = getIconFileNameOrFallback(GTK_STOCK_MISSING_IMAGE, "missingImage");
64     else
65         fileName = String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, name).utf8();
66
67     GOwnPtr<gchar> content;
68     gsize length;
69     if (!g_file_get_contents(fileName.data(), &content.outPtr(), &length, 0))
70         return SharedBuffer::create();
71
72     return SharedBuffer::create(content.get(), length);
73 }
74
75 void BitmapImage::initPlatformData()
76 {
77 }
78
79 void BitmapImage::invalidatePlatformData()
80 {
81 }
82
83 PassRefPtr<Image> Image::loadPlatformResource(const char* name)
84 {
85     RefPtr<BitmapImage> img = BitmapImage::create();
86     RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(name);
87     img->setData(buffer.release(), true);
88     return img.release();
89 }
90
91 static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride)
92 {
93     return data + (y * rowStride) + x * 4;
94 }
95
96 static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride)
97 {
98     return data + (y * rowStride) + x * 4;
99 }
100
101 GdkPixbuf* BitmapImage::getGdkPixbuf()
102 {
103     int width = cairo_image_surface_get_width(frameAtIndex(currentFrame()));
104     int height = cairo_image_surface_get_height(frameAtIndex(currentFrame()));
105     unsigned char* surfaceData = cairo_image_surface_get_data(frameAtIndex(currentFrame()));
106     int surfaceRowStride = cairo_image_surface_get_stride(frameAtIndex(currentFrame()));
107
108     GdkPixbuf* dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
109     if (!dest)
110         return 0;
111
112     guchar* pixbufData = gdk_pixbuf_get_pixels(dest);
113     int pixbufRowStride = gdk_pixbuf_get_rowstride(dest);
114
115     /* From: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t
116      * "CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with alpha in
117      * the upper 8 bits, then red, then green, then blue. The 32-bit
118      * quantities are stored native-endian. Pre-multiplied alpha is used.
119      * (That is, 50% transparent red is 0x80800000, not 0x80ff0000.)"
120      *
121      * See http://developer.gimp.org/api/2.0/gdk-pixbuf/gdk-pixbuf-gdk-pixbuf.html#GdkPixbuf
122      * for information on the structure of GdkPixbufs stored with GDK_COLORSPACE_RGB.
123      *
124      * RGB color channels in CAIRO_FORMAT_ARGB32 are stored based on the
125      * endianness of the machine and are also multiplied by the alpha channel.
126      * To properly transfer the data from the Cairo surface we must divide each
127      * of the RGB channels by the alpha channel and then reorder all channels
128      * if this machine is little-endian.
129      */
130     for (int y = 0; y < height; y++) {
131         for (int x = 0; x < width; x++) {
132             unsigned char* source = getCairoSurfacePixel(surfaceData, x, y, surfaceRowStride);
133             guchar* dest = getGdkPixbufPixel(pixbufData, x, y, pixbufRowStride);
134
135 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
136             guchar alpha = source[3];
137             dest[0] = alpha ? ((source[2] * 255) / alpha) : 0;
138             dest[1] = alpha ? ((source[1] * 255) / alpha) : 0;
139             dest[2] = alpha ? ((source[0] * 255) / alpha) : 0;
140             dest[3] = alpha;
141 #else
142             guchar alpha = source[0];
143             dest[0] = alpha ? ((source[1] * 255) / alpha) : 0;
144             dest[1] = alpha ? ((source[2] * 255) / alpha) : 0;
145             dest[2] = alpha ? ((source[3] * 255) / alpha) : 0;
146             dest[3] = alpha;
147 #endif
148         }
149     }
150
151     return dest;
152 }
153
154 }