summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/libgtk2ui/gtk2_util.cc
blob: a28c74656415be30586f2b17f0c04813c77bcc25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"

#include <gtk/gtk.h>

#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/size.h"

namespace {

void CommonInitFromCommandLine(const CommandLine& command_line,
                               void (*init_func)(gint*, gchar***)) {
  const std::vector<std::string>& args = command_line.argv();
  int argc = args.size();
  scoped_array<char *> argv(new char *[argc + 1]);
  for (size_t i = 0; i < args.size(); ++i) {
    // TODO(piman@google.com): can gtk_init modify argv? Just being safe
    // here.
    argv[i] = strdup(args[i].c_str());
  }
  argv[argc] = NULL;
  char **argv_pointer = argv.get();

  init_func(&argc, &argv_pointer);
  for (size_t i = 0; i < args.size(); ++i) {
    free(argv[i]);
  }
}

}  // namespace

namespace libgtk2ui {

void GtkInitFromCommandLine(const CommandLine& command_line) {
  CommonInitFromCommandLine(command_line, gtk_init);
}

const SkBitmap GdkPixbufToImageSkia(GdkPixbuf* pixbuf) {
  // TODO(erg): What do we do in the case where the pixbuf fails these dchecks?
  // I would prefer to use our gtk based canvas, but that would require
  // recompiling half of our skia extensions with gtk support, which we can't
  // do in this build.
  DCHECK_EQ(GDK_COLORSPACE_RGB, gdk_pixbuf_get_colorspace(pixbuf));

  int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
  int w = gdk_pixbuf_get_width(pixbuf);
  int h = gdk_pixbuf_get_height(pixbuf);

  SkBitmap ret;
  ret.setConfig(SkBitmap::kARGB_8888_Config, w, h);
  ret.allocPixels();
  ret.eraseColor(0);

  uint32_t* skia_data = static_cast<uint32_t*>(ret.getAddr(0, 0));

  if (n_channels == 4) {
    int total_length = w * h;
    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);

    // Now here's the trick: we need to convert the gdk data (which is RGBA and
    // isn't premultiplied) to skia (which can be anything and premultiplied).
    for (int i = 0; i < total_length; ++i, gdk_pixels += 4) {
      const unsigned char& red = gdk_pixels[0];
      const unsigned char& green = gdk_pixels[1];
      const unsigned char& blue = gdk_pixels[2];
      const unsigned char& alpha = gdk_pixels[3];

      skia_data[i] = SkPreMultiplyARGB(alpha, red, green, blue);
    }
  } else if (n_channels == 3) {
    // Because GDK makes rowstrides word aligned, we need to do something a bit
    // more complex when a pixel isn't perfectly a word of memory.
    int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
    guchar* gdk_pixels = gdk_pixbuf_get_pixels(pixbuf);
    for (int y = 0; y < h; ++y) {
      int row = y * rowstride;

      for (int x = 0; x < w; ++x) {
        guchar* pixel = gdk_pixels + row + (x * 3);
        const unsigned char& red = pixel[0];
        const unsigned char& green = pixel[1];
        const unsigned char& blue = pixel[2];

        skia_data[y * w + x] = SkPreMultiplyARGB(255, red, green, blue);
      }
    }
  } else {
    NOTREACHED();
  }

  return ret;
}

}  // namespace libgtk2ui