Home | History | Annotate | Download | only in gtk
      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