• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "webkit/glue/webcursor.h"
6 
7 #include <gdk/gdk.h>
8 #include <gtk/gtk.h>
9 
10 #include "base/logging.h"
11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
12 #include "ui/gfx/gtk_util.h"
13 
14 using WebKit::WebCursorInfo;
15 
16 namespace {
17 
18 // webcursor_gtk_data.h is taken directly from WebKit's CursorGtk.h.
19 #include "webkit/glue/webcursor_gtk_data.h"
20 
21 // This helper function is taken directly from WebKit's CursorGtk.cpp.
22 // It attempts to create a custom cursor from the data inlined in
23 // webcursor_gtk_data.h.
GetInlineCustomCursor(CustomCursorType type)24 GdkCursor* GetInlineCustomCursor(CustomCursorType type) {
25   static GdkCursor* CustomCursorsGdk[G_N_ELEMENTS(CustomCursors)];
26   GdkCursor* cursor = CustomCursorsGdk[type];
27   if (cursor)
28     return cursor;
29   const CustomCursor& custom = CustomCursors[type];
30   cursor = gdk_cursor_new_from_name(gdk_display_get_default(), custom.name);
31   if (!cursor) {
32     const GdkColor fg = { 0, 0, 0, 0 };
33     const GdkColor bg = { 65535, 65535, 65535, 65535 };
34     GdkPixmap* source = gdk_bitmap_create_from_data(NULL, custom.bits,
35                                                     32, 32);
36     GdkPixmap* mask = gdk_bitmap_create_from_data(NULL, custom.mask_bits,
37                                                   32, 32);
38     cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg,
39                                         custom.hot_x, custom.hot_y);
40     g_object_unref(source);
41     g_object_unref(mask);
42   }
43   CustomCursorsGdk[type] = cursor;
44   return cursor;
45 }
46 
47 // For GTK 2.16 and beyond, GDK_BLANK_CURSOR is available. Before, we have to
48 // use a custom cursor.
49 #if !GTK_CHECK_VERSION(2, 16, 0)
50 // Get/create a custom cursor which is invisible.
GetInvisibleCustomCursor()51 GdkCursor* GetInvisibleCustomCursor() {
52   static GdkCursor* cursor = NULL;
53   if (cursor)
54     return cursor;
55   const char bits[] = { 0 };
56   const GdkColor color = { 0, 0, 0, 0 };
57   GdkPixmap* bitmap = gdk_bitmap_create_from_data(NULL, bits, 1, 1);
58   cursor = gdk_cursor_new_from_pixmap(bitmap, bitmap, &color, &color, 0, 0);
59   g_object_unref(bitmap);
60   return cursor;
61 }
62 #endif
63 
64 }  // end anonymous namespace
65 
GetCursorType() const66 int WebCursor::GetCursorType() const {
67   // http://library.gnome.org/devel/gdk/2.12/gdk-Cursors.html has images
68   // of the default X theme, but beware that the user's cursor theme can
69   // change everything.
70   switch (type_) {
71     case WebCursorInfo::TypePointer:
72       return GDK_LAST_CURSOR;
73     case WebCursorInfo::TypeCross:
74       return GDK_CROSS;
75     case WebCursorInfo::TypeHand:
76       return GDK_HAND2;
77     case WebCursorInfo::TypeIBeam:
78       return GDK_XTERM;
79     case WebCursorInfo::TypeWait:
80       return GDK_WATCH;
81     case WebCursorInfo::TypeHelp:
82       return GDK_QUESTION_ARROW;
83     case WebCursorInfo::TypeEastResize:
84       return GDK_RIGHT_SIDE;
85     case WebCursorInfo::TypeNorthResize:
86       return GDK_TOP_SIDE;
87     case WebCursorInfo::TypeNorthEastResize:
88       return GDK_TOP_RIGHT_CORNER;
89     case WebCursorInfo::TypeNorthWestResize:
90       return GDK_TOP_LEFT_CORNER;
91     case WebCursorInfo::TypeSouthResize:
92       return GDK_BOTTOM_SIDE;
93     case WebCursorInfo::TypeSouthEastResize:
94       return GDK_BOTTOM_RIGHT_CORNER;
95     case WebCursorInfo::TypeSouthWestResize:
96       return GDK_BOTTOM_LEFT_CORNER;
97     case WebCursorInfo::TypeWestResize:
98       return GDK_LEFT_SIDE;
99     case WebCursorInfo::TypeNorthSouthResize:
100       return GDK_SB_V_DOUBLE_ARROW;
101     case WebCursorInfo::TypeEastWestResize:
102       return GDK_SB_H_DOUBLE_ARROW;
103     case WebCursorInfo::TypeNorthEastSouthWestResize:
104     case WebCursorInfo::TypeNorthWestSouthEastResize:
105       // There isn't really a useful cursor available for these.
106       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
107     case WebCursorInfo::TypeColumnResize:
108       return GDK_SB_H_DOUBLE_ARROW;  // TODO(evanm): is this correct?
109     case WebCursorInfo::TypeRowResize:
110       return GDK_SB_V_DOUBLE_ARROW;  // TODO(evanm): is this correct?
111     case WebCursorInfo::TypeMiddlePanning:
112       return GDK_FLEUR;
113     case WebCursorInfo::TypeEastPanning:
114       return GDK_SB_RIGHT_ARROW;
115     case WebCursorInfo::TypeNorthPanning:
116       return GDK_SB_UP_ARROW;
117     case WebCursorInfo::TypeNorthEastPanning:
118       return GDK_TOP_RIGHT_CORNER;
119     case WebCursorInfo::TypeNorthWestPanning:
120       return GDK_TOP_LEFT_CORNER;
121     case WebCursorInfo::TypeSouthPanning:
122       return GDK_SB_DOWN_ARROW;
123     case WebCursorInfo::TypeSouthEastPanning:
124       return GDK_BOTTOM_RIGHT_CORNER;
125     case WebCursorInfo::TypeSouthWestPanning:
126       return GDK_BOTTOM_LEFT_CORNER;
127     case WebCursorInfo::TypeWestPanning:
128       return GDK_SB_LEFT_ARROW;
129     case WebCursorInfo::TypeMove:
130       return GDK_FLEUR;
131     case WebCursorInfo::TypeVerticalText:
132       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
133     case WebCursorInfo::TypeCell:
134       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
135     case WebCursorInfo::TypeContextMenu:
136       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
137     case WebCursorInfo::TypeAlias:
138       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
139     case WebCursorInfo::TypeProgress:
140       return GDK_WATCH;
141     case WebCursorInfo::TypeNoDrop:
142       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
143     case WebCursorInfo::TypeCopy:
144       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
145     case WebCursorInfo::TypeNone:
146 // See comment above |GetInvisibleCustomCursor()|.
147 #if !GTK_CHECK_VERSION(2, 16, 0)
148       return GDK_CURSOR_IS_PIXMAP;
149 #else
150       return GDK_BLANK_CURSOR;
151 #endif
152     case WebCursorInfo::TypeNotAllowed:
153       NOTIMPLEMENTED(); return GDK_LAST_CURSOR;
154     case WebCursorInfo::TypeZoomIn:
155     case WebCursorInfo::TypeZoomOut:
156     case WebCursorInfo::TypeGrab:
157     case WebCursorInfo::TypeGrabbing:
158     case WebCursorInfo::TypeCustom:
159       return GDK_CURSOR_IS_PIXMAP;
160   }
161   NOTREACHED();
162   return GDK_LAST_CURSOR;
163 }
164 
GetNativeCursor()165 gfx::NativeCursor WebCursor::GetNativeCursor() {
166   int type = GetCursorType();
167   if (type == GDK_CURSOR_IS_PIXMAP)
168     return GetCustomCursor();
169   return gfx::GetCursor(type);
170 }
171 
GetCustomCursor()172 GdkCursor* WebCursor::GetCustomCursor() {
173   switch (type_) {
174 // See comment above |GetInvisibleCustomCursor()|.
175 #if !GTK_CHECK_VERSION(2, 16, 0)
176     case WebCursorInfo::TypeNone:
177       return GetInvisibleCustomCursor();
178 #endif
179     case WebCursorInfo::TypeZoomIn:
180       return GetInlineCustomCursor(CustomCursorZoomIn);
181     case WebCursorInfo::TypeZoomOut:
182       return GetInlineCustomCursor(CustomCursorZoomOut);
183     case WebCursorInfo::TypeGrab:
184       return GetInlineCustomCursor(CustomCursorGrab);
185     case WebCursorInfo::TypeGrabbing:
186       return GetInlineCustomCursor(CustomCursorGrabbing);
187   }
188 
189   if (type_ != WebCursorInfo::TypeCustom) {
190     NOTREACHED();
191     return NULL;
192   }
193 
194   SkBitmap bitmap;
195   bitmap.setConfig(SkBitmap::kARGB_8888_Config,
196                    custom_size_.width(), custom_size_.height());
197   bitmap.allocPixels();
198   memcpy(bitmap.getAddr32(0, 0), custom_data_.data(), custom_data_.size());
199 
200   GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
201   GdkCursor* cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
202                                                  pixbuf,
203                                                  hotspot_.x(),
204                                                  hotspot_.y());
205 
206   gdk_pixbuf_unref(pixbuf);
207 
208   if (unref_)
209     gdk_cursor_unref(unref_);
210   unref_ = cursor;
211   return cursor;
212 }
213 
InitPlatformData()214 void WebCursor::InitPlatformData() {
215   unref_ = NULL;
216   return;
217 }
218 
SerializePlatformData(Pickle * pickle) const219 bool WebCursor::SerializePlatformData(Pickle* pickle) const {
220   return true;
221 }
222 
DeserializePlatformData(const Pickle * pickle,void ** iter)223 bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) {
224   return true;
225 }
226 
IsPlatformDataEqual(const WebCursor & other) const227 bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const {
228   return true;
229 }
230 
CleanupPlatformData()231 void WebCursor::CleanupPlatformData() {
232   if (unref_) {
233     gdk_cursor_unref(unref_);
234     unref_ = NULL;
235   }
236   return;
237 }
238 
CopyPlatformData(const WebCursor & other)239 void WebCursor::CopyPlatformData(const WebCursor& other) {
240   if (other.unref_)
241     unref_ = gdk_cursor_ref(other.unref_);
242   return;
243 }
244