OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/gtk/tabs/dragged_tab_gtk.h" | 5 #include "chrome/browser/gtk/tabs/dragged_tab_gtk.h" |
6 | 6 |
7 #include <gdk/gdk.h> | 7 #include <gdk/gdk.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
11 #include "app/gfx/canvas_paint.h" | 11 #include "app/gfx/canvas_paint.h" |
12 #include "base/gfx/gtk_util.h" | 12 #include "base/gfx/gtk_util.h" |
13 #include "chrome/browser/tab_contents/tab_contents.h" | 13 #include "chrome/browser/tab_contents/tab_contents.h" |
14 #include "chrome/browser/tabs/tab_strip_model.h" | 14 #include "chrome/browser/tabs/tab_strip_model.h" |
15 #include "chrome/browser/gtk/tabs/tab_renderer_gtk.h" | 15 #include "chrome/browser/gtk/tabs/tab_renderer_gtk.h" |
16 #include "chrome/common/gtk_util.h" | 16 #include "chrome/common/gtk_util.h" |
| 17 #include "chrome/common/x11_util.h" |
17 #include "third_party/skia/include/core/SkShader.h" | 18 #include "third_party/skia/include/core/SkShader.h" |
18 | 19 |
19 namespace { | 20 namespace { |
20 | 21 |
21 // The size of the dragged window frame. | 22 // The size of the dragged window frame. |
22 const int kDragFrameBorderSize = 2; | 23 const int kDragFrameBorderSize = 1; |
23 const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize; | 24 const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize; |
24 | 25 |
25 // Used to scale the dragged window sizes. | 26 // Used to scale the dragged window sizes. |
26 const float kScalingFactor = 0.5; | 27 const float kScalingFactor = 0.5; |
27 | 28 |
28 const int kAnimateToBoundsDurationMs = 150; | 29 const int kAnimateToBoundsDurationMs = 150; |
29 | 30 |
30 const gdouble kTransparentAlpha = (200.0f / 255.0f); | 31 const gdouble kTransparentAlpha = (200.0f / 255.0f); |
31 const gdouble kOpaqueAlpha = 1.0f; | 32 const gdouble kOpaqueAlpha = 1.0f; |
32 const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162); | 33 const double kDraggedTabBorderColor[] = { 103.0 / 0xff, |
| 34 129.0 / 0xff, |
| 35 162.0 / 0xff }; |
33 | 36 |
34 } // namespace | 37 } // namespace |
35 | 38 |
36 //////////////////////////////////////////////////////////////////////////////// | 39 //////////////////////////////////////////////////////////////////////////////// |
37 // DraggedTabGtk, public: | 40 // DraggedTabGtk, public: |
38 | 41 |
39 DraggedTabGtk::DraggedTabGtk(TabContents* datasource, | 42 DraggedTabGtk::DraggedTabGtk(TabContents* datasource, |
40 const gfx::Point& mouse_tab_offset, | 43 const gfx::Point& mouse_tab_offset, |
41 const gfx::Size& contents_size) | 44 const gfx::Size& contents_size) |
42 : backing_store_(NULL), | 45 : backing_store_(NULL), |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 // If rgba is not available, use rgb instead. | 192 // If rgba is not available, use rgb instead. |
190 if (!colormap) | 193 if (!colormap) |
191 colormap = gdk_screen_get_rgb_colormap(screen); | 194 colormap = gdk_screen_get_rgb_colormap(screen); |
192 | 195 |
193 gtk_widget_set_colormap(container_, colormap); | 196 gtk_widget_set_colormap(container_, colormap); |
194 } | 197 } |
195 | 198 |
196 void DraggedTabGtk::SetContainerTransparency() { | 199 void DraggedTabGtk::SetContainerTransparency() { |
197 cairo_t* cairo_context = gdk_cairo_create(container_->window); | 200 cairo_t* cairo_context = gdk_cairo_create(container_->window); |
198 if (!cairo_context) | 201 if (!cairo_context) |
199 return; | 202 return; |
200 | 203 |
201 // Make the background of the dragged tab window fully transparent. All of | 204 // Make the background of the dragged tab window fully transparent. All of |
202 // the content of the window (child widgets) will be completely opaque. | 205 // the content of the window (child widgets) will be completely opaque. |
203 gfx::Size size = bounds().size(); | 206 gfx::Size size = bounds().size(); |
204 cairo_scale(cairo_context, static_cast<double>(size.width()), | 207 cairo_scale(cairo_context, static_cast<double>(size.width()), |
205 static_cast<double>(size.height())); | 208 static_cast<double>(size.height())); |
206 cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f); | 209 cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f); |
207 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); | 210 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); |
208 cairo_paint(cairo_context); | 211 cairo_paint(cairo_context); |
209 cairo_destroy(cairo_context); | 212 cairo_destroy(cairo_context); |
210 } | 213 } |
211 | 214 |
212 void DraggedTabGtk::SetContainerShapeMask(const SkBitmap& dragged_contents) { | 215 void DraggedTabGtk::SetContainerShapeMask(GdkPixbuf* pixbuf) { |
213 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&dragged_contents); | |
214 | |
215 // Create a 1bpp bitmap the size of |container_|. | 216 // Create a 1bpp bitmap the size of |container_|. |
216 gfx::Size size = bounds().size(); | 217 gfx::Size size = bounds().size(); |
217 GdkPixmap* pixmap = gdk_pixmap_new(NULL, size.width(), size.height(), 1); | 218 GdkPixmap* pixmap = gdk_pixmap_new(NULL, size.width(), size.height(), 1); |
218 cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(pixmap)); | 219 cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(pixmap)); |
219 | 220 |
220 // Set the transparency. | 221 // Set the transparency. |
221 cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f); | 222 cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f); |
222 | 223 |
223 // Blit the rendered bitmap into a pixmap. Any pixel set in the pixmap will | 224 // Blit the rendered bitmap into a pixmap. Any pixel set in the pixmap will |
224 // be opaque in the container window. | 225 // be opaque in the container window. |
225 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); | 226 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); |
| 227 if (!attached_) |
| 228 cairo_scale(cairo_context, kScalingFactor, kScalingFactor); |
226 gdk_cairo_set_source_pixbuf(cairo_context, pixbuf, 0, 0); | 229 gdk_cairo_set_source_pixbuf(cairo_context, pixbuf, 0, 0); |
227 cairo_paint(cairo_context); | 230 cairo_paint(cairo_context); |
| 231 |
| 232 if (!attached_) { |
| 233 // Make the render area depiction opaque (leaving enough room for the |
| 234 // border). |
| 235 cairo_identity_matrix(cairo_context); |
| 236 cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 1.0f); |
| 237 int tab_height = kScalingFactor * gdk_pixbuf_get_height(pixbuf) - |
| 238 kDragFrameBorderSize; |
| 239 cairo_rectangle(cairo_context, |
| 240 0, tab_height, |
| 241 size.width(), size.height() - tab_height); |
| 242 cairo_fill(cairo_context); |
| 243 } |
| 244 |
228 cairo_destroy(cairo_context); | 245 cairo_destroy(cairo_context); |
229 | 246 |
230 // Set the shape mask. | 247 // Set the shape mask. |
231 gdk_window_shape_combine_mask(container_->window, pixmap, 0, 0); | 248 gdk_window_shape_combine_mask(container_->window, pixmap, 0, 0); |
232 g_object_unref(pixbuf); | |
233 g_object_unref(pixmap); | 249 g_object_unref(pixmap); |
234 } | 250 } |
235 | 251 |
236 SkBitmap DraggedTabGtk::PaintAttachedTab() { | 252 GdkPixbuf* DraggedTabGtk::PaintTab() { |
237 return renderer_->PaintBitmap(); | 253 SkBitmap bitmap = renderer_->PaintBitmap(); |
238 } | 254 return gfx::GdkPixbufFromSkBitmap(&bitmap); |
239 | |
240 SkBitmap DraggedTabGtk::PaintDetachedView() { | |
241 gfx::Size ps = GetPreferredSize(); | |
242 gfx::Canvas scale_canvas(ps.width(), ps.height(), false); | |
243 SkBitmap& bitmap_device = const_cast<SkBitmap&>( | |
244 scale_canvas.getTopPlatformDevice().accessBitmap(true)); | |
245 bitmap_device.eraseARGB(0, 0, 0, 0); | |
246 | |
247 scale_canvas.FillRectInt(kDraggedTabBorderColor, 0, | |
248 attached_tab_size_.height() - kDragFrameBorderSize, | |
249 ps.width(), ps.height() - attached_tab_size_.height()); | |
250 int image_x = kDragFrameBorderSize; | |
251 int image_y = attached_tab_size_.height(); | |
252 int image_w = ps.width() - kTwiceDragFrameBorderSize; | |
253 int image_h = | |
254 ps.height() - kTwiceDragFrameBorderSize - attached_tab_size_.height(); | |
255 scale_canvas.FillRectInt(SK_ColorBLACK, image_x, image_y, image_w, image_h); | |
256 PaintScreenshotIntoCanvas(&scale_canvas, | |
257 gfx::Rect(image_x, image_y, image_w, image_h)); | |
258 renderer_->Paint(&scale_canvas); | |
259 | |
260 SkIRect subset; | |
261 subset.set(0, 0, ps.width(), ps.height()); | |
262 SkBitmap mipmap = scale_canvas.ExtractBitmap(); | |
263 mipmap.buildMipMap(true); | |
264 | |
265 SkShader* bitmap_shader = | |
266 SkShader::CreateBitmapShader(mipmap, SkShader::kClamp_TileMode, | |
267 SkShader::kClamp_TileMode); | |
268 | |
269 SkMatrix shader_scale; | |
270 shader_scale.setScale(kScalingFactor, kScalingFactor); | |
271 bitmap_shader->setLocalMatrix(shader_scale); | |
272 | |
273 SkPaint paint; | |
274 paint.setShader(bitmap_shader); | |
275 paint.setAntiAlias(true); | |
276 bitmap_shader->unref(); | |
277 | |
278 SkRect rc; | |
279 rc.fLeft = 0; | |
280 rc.fTop = 0; | |
281 rc.fRight = SkIntToScalar(ps.width()); | |
282 rc.fBottom = SkIntToScalar(ps.height()); | |
283 gfx::Canvas canvas(ps.width(), ps.height(), false); | |
284 canvas.drawRect(rc, paint); | |
285 | |
286 return canvas.ExtractBitmap(); | |
287 } | |
288 | |
289 void DraggedTabGtk::PaintScreenshotIntoCanvas(gfx::Canvas* canvas, | |
290 const gfx::Rect& target_bounds) { | |
291 // A drag could be initiated before the backing store is created. | |
292 if (!backing_store_) | |
293 return; | |
294 | |
295 gfx::Rect rect(0, 0, target_bounds.width(), target_bounds.height()); | |
296 SkBitmap bitmap = backing_store_->PaintRectToBitmap(rect); | |
297 if (!bitmap.isNull()) | |
298 canvas->DrawBitmapInt(bitmap, target_bounds.x(), target_bounds.y()); | |
299 } | 255 } |
300 | 256 |
301 // static | 257 // static |
302 gboolean DraggedTabGtk::OnExposeEvent(GtkWidget* widget, | 258 gboolean DraggedTabGtk::OnExposeEvent(GtkWidget* widget, |
303 GdkEventExpose* event, | 259 GdkEventExpose* event, |
304 DraggedTabGtk* dragged_tab) { | 260 DraggedTabGtk* dragged_tab) { |
305 SkBitmap bmp; | 261 GdkPixbuf* pixbuf = dragged_tab->PaintTab(); |
306 if (dragged_tab->attached_) { | |
307 bmp = dragged_tab->PaintAttachedTab(); | |
308 } else { | |
309 bmp = dragged_tab->PaintDetachedView(); | |
310 } | |
311 | |
312 if (gtk_util::IsScreenComposited()) { | 262 if (gtk_util::IsScreenComposited()) { |
313 dragged_tab->SetContainerTransparency(); | 263 dragged_tab->SetContainerTransparency(); |
314 } else { | 264 } else { |
315 dragged_tab->SetContainerShapeMask(bmp); | 265 dragged_tab->SetContainerShapeMask(pixbuf); |
316 } | 266 } |
317 | 267 |
318 gfx::CanvasPaint canvas(event, false); | 268 // Only used when not attached. |
319 canvas.DrawBitmapInt(bmp, 0, 0); | 269 int tab_height = kScalingFactor * gdk_pixbuf_get_height(pixbuf); |
| 270 int tab_width = kScalingFactor * gdk_pixbuf_get_width(pixbuf); |
| 271 |
| 272 // Draw the render area. |
| 273 if (dragged_tab->backing_store_ && !dragged_tab->attached_) { |
| 274 // This leaves room for the border. |
| 275 dragged_tab->backing_store_->PaintToRect( |
| 276 gfx::Rect(kDragFrameBorderSize, tab_height, |
| 277 widget->allocation.width - kTwiceDragFrameBorderSize, |
| 278 widget->allocation.height - tab_height - |
| 279 kDragFrameBorderSize), |
| 280 GDK_DRAWABLE(widget->window)); |
| 281 } |
| 282 |
| 283 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window)); |
| 284 // Draw the border. |
| 285 if (!dragged_tab->attached_) { |
| 286 cairo_set_line_width(cr, kDragFrameBorderSize); |
| 287 cairo_set_source_rgb(cr, kDraggedTabBorderColor[0], |
| 288 kDraggedTabBorderColor[1], |
| 289 kDraggedTabBorderColor[2]); |
| 290 // |offset| is the distance from the edge of the image to the middle of |
| 291 // the border line. |
| 292 double offset = kDragFrameBorderSize / 2.0 - 0.5; |
| 293 double left_x = offset; |
| 294 double top_y = tab_height - kDragFrameBorderSize + offset; |
| 295 double right_x = widget->allocation.width - offset; |
| 296 double bottom_y = widget->allocation.height - offset; |
| 297 double middle_x = tab_width + offset; |
| 298 |
| 299 // We don't use cairo_rectangle() because we don't want to draw the border |
| 300 // under the tab itself. |
| 301 cairo_move_to(cr, left_x, top_y); |
| 302 cairo_line_to(cr, left_x, bottom_y); |
| 303 cairo_line_to(cr, right_x, bottom_y); |
| 304 cairo_line_to(cr, right_x, top_y); |
| 305 cairo_line_to(cr, middle_x, top_y); |
| 306 cairo_stroke(cr); |
| 307 } |
| 308 |
| 309 // Draw the tab. |
| 310 if (!dragged_tab->attached_) |
| 311 cairo_scale(cr, kScalingFactor, kScalingFactor); |
| 312 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); |
| 313 cairo_paint(cr); |
| 314 |
| 315 cairo_destroy(cr); |
| 316 |
| 317 g_object_unref(pixbuf); |
320 | 318 |
321 // We've already drawn the tab, so don't propagate the expose-event signal. | 319 // We've already drawn the tab, so don't propagate the expose-event signal. |
322 return TRUE; | 320 return TRUE; |
323 } | 321 } |
OLD | NEW |