OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/ui/gtk/nine_box.h" | 5 #include "chrome/browser/ui/gtk/nine_box.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/i18n/rtl.h" | 8 #include "base/i18n/rtl.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "ui/base/resource/resource_bundle.h" | 10 #include "ui/base/resource/resource_bundle.h" |
11 #include "ui/gfx/gtk_util.h" | 11 #include "ui/gfx/gtk_util.h" |
12 #include "ui/gfx/image/image.h" | 12 #include "ui/gfx/image/image.h" |
| 13 #include "ui/gfx/image/cairo_cached_surface.h" |
13 #include "ui/gfx/point.h" | 14 #include "ui/gfx/point.h" |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 // Draw pixbuf |src| into |dst| at position (x, y). | 18 // Draw pixbuf |src| into |dst| at position (x, y). |
18 void DrawPixbuf(cairo_t* cr, GdkPixbuf* src, int x, int y, double alpha) { | 19 void DrawImage(cairo_t* cr, GtkWidget* widget, gfx::Image* src, |
19 gdk_cairo_set_source_pixbuf(cr, src, x, y); | 20 int x, int y, double alpha) { |
| 21 if (!src) |
| 22 return; |
| 23 |
| 24 src->ToCairo()->SetSource(cr, widget, x, y); |
20 cairo_paint_with_alpha(cr, alpha); | 25 cairo_paint_with_alpha(cr, alpha); |
21 } | 26 } |
22 | 27 |
23 // Tile pixbuf |src| across |cr| at |x|, |y| for |width| and |height|. | 28 // Tile pixbuf |src| across |cr| at |x|, |y| for |width| and |height|. |
24 void TileImage(cairo_t* cr, GdkPixbuf* src, | 29 void TileImage(cairo_t* cr, GtkWidget* widget, gfx::Image* src, |
25 int x, int y, int width, int height, double alpha) { | 30 int x, int y, int width, int height, double alpha) { |
| 31 if (!src) |
| 32 return; |
| 33 |
26 if (alpha == 1.0) { | 34 if (alpha == 1.0) { |
27 gdk_cairo_set_source_pixbuf(cr, src, x, y); | 35 src->ToCairo()->SetSource(cr, widget, x, y); |
28 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); | 36 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); |
29 cairo_rectangle(cr, x, y, width, height); | 37 cairo_rectangle(cr, x, y, width, height); |
30 cairo_fill(cr); | 38 cairo_fill(cr); |
31 } else { | 39 } else { |
32 // Since there is no easy way to apply a mask to a fill operation, we create | 40 // Since there is no easy way to apply a mask to a fill operation, we create |
33 // a secondary surface and tile into that, then paint it with |alpha|. | 41 // a secondary surface and tile into that, then paint it with |alpha|. |
34 cairo_surface_t* surface = cairo_image_surface_create( | 42 cairo_surface_t* target = cairo_get_target(cr); |
35 CAIRO_FORMAT_ARGB32, width, height); | 43 cairo_surface_t* surface = cairo_surface_create_similar( |
| 44 target, CAIRO_CONTENT_COLOR_ALPHA, width, height); |
36 cairo_t* tiled = cairo_create(surface); | 45 cairo_t* tiled = cairo_create(surface); |
37 gdk_cairo_set_source_pixbuf(tiled, src, 0, 0); | 46 src->ToCairo()->SetSource(tiled, widget, 0, 0); |
38 cairo_pattern_set_extend(cairo_get_source(tiled), CAIRO_EXTEND_REPEAT); | 47 cairo_pattern_set_extend(cairo_get_source(tiled), CAIRO_EXTEND_REPEAT); |
39 cairo_rectangle(tiled, 0, 0, width, height); | 48 cairo_rectangle(tiled, 0, 0, width, height); |
40 cairo_fill(tiled); | 49 cairo_fill(tiled); |
41 | 50 |
42 cairo_set_source_surface(cr, surface, x, y); | 51 cairo_set_source_surface(cr, surface, x, y); |
43 cairo_paint_with_alpha(cr, alpha); | 52 cairo_paint_with_alpha(cr, alpha); |
44 | 53 |
45 cairo_destroy(tiled); | 54 cairo_destroy(tiled); |
46 cairo_surface_destroy(surface); | 55 cairo_surface_destroy(surface); |
47 } | 56 } |
48 } | 57 } |
49 | 58 |
50 GdkPixbuf* GetPixbufImage(int resource_id) { | |
51 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
52 return static_cast<GdkPixbuf*>(rb.GetNativeImageNamed(resource_id)); | |
53 } | |
54 | |
55 } // namespace | 59 } // namespace |
56 | 60 |
57 NineBox::NineBox(int top_left, int top, int top_right, int left, int center, | 61 NineBox::NineBox(int top_left, int top, int top_right, int left, int center, |
58 int right, int bottom_left, int bottom, int bottom_right) | 62 int right, int bottom_left, int bottom, int bottom_right) |
59 : unref_pixbufs_on_destroy_(false) { | 63 : unref_images_on_destroy_(false) { |
60 images_[0] = top_left ? GetPixbufImage(top_left) : NULL; | 64 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
61 images_[1] = top ? GetPixbufImage(top) : NULL; | 65 |
62 images_[2] = top_right ? GetPixbufImage(top_right) : NULL; | 66 images_[0] = top_left ? &rb.GetNativeImageNamed(top_left) : NULL; |
63 images_[3] = left ? GetPixbufImage(left) : NULL; | 67 images_[1] = top ? &rb.GetNativeImageNamed(top) : NULL; |
64 images_[4] = center ? GetPixbufImage(center) : NULL; | 68 images_[2] = top_right ? &rb.GetNativeImageNamed(top_right) : NULL; |
65 images_[5] = right ? GetPixbufImage(right) : NULL; | 69 images_[3] = left ? &rb.GetNativeImageNamed(left) : NULL; |
66 images_[6] = bottom_left ? GetPixbufImage(bottom_left) : NULL; | 70 images_[4] = center ? &rb.GetNativeImageNamed(center) : NULL; |
67 images_[7] = bottom ? GetPixbufImage(bottom) : NULL; | 71 images_[5] = right ? &rb.GetNativeImageNamed(right) : NULL; |
68 images_[8] = bottom_right ? GetPixbufImage(bottom_right) : NULL; | 72 images_[6] = bottom_left ? &rb.GetNativeImageNamed(bottom_left) : NULL; |
| 73 images_[7] = bottom ? &rb.GetNativeImageNamed(bottom) : NULL; |
| 74 images_[8] = bottom_right ? &rb.GetNativeImageNamed(bottom_right) : NULL; |
69 } | 75 } |
70 | 76 |
71 NineBox::NineBox(int image, int top_margin, int bottom_margin, int left_margin, | 77 NineBox::NineBox(int image, int top_margin, int bottom_margin, int left_margin, |
72 int right_margin) | 78 int right_margin) |
73 : unref_pixbufs_on_destroy_(true) { | 79 : unref_images_on_destroy_(true) { |
74 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 80 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
75 GdkPixbuf* pixbuf = rb.GetNativeImageNamed(image); | 81 GdkPixbuf* pixbuf = rb.GetNativeImageNamed(image); |
76 int width = gdk_pixbuf_get_width(pixbuf); | 82 int width = gdk_pixbuf_get_width(pixbuf); |
77 int height = gdk_pixbuf_get_height(pixbuf); | 83 int height = gdk_pixbuf_get_height(pixbuf); |
78 int inset_width = left_margin + right_margin; | 84 int inset_width = left_margin + right_margin; |
79 int inset_height = top_margin + bottom_margin; | 85 int inset_height = top_margin + bottom_margin; |
80 | 86 |
81 images_[0] = gdk_pixbuf_new_subpixbuf(pixbuf, 0, 0, left_margin, top_margin); | 87 images_[0] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
82 images_[1] = gdk_pixbuf_new_subpixbuf(pixbuf, left_margin, 0, | 88 pixbuf, 0, 0, left_margin, top_margin)); |
83 width - inset_width, top_margin); | 89 images_[1] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
84 images_[2] = gdk_pixbuf_new_subpixbuf(pixbuf, width - right_margin, 0, | 90 pixbuf, left_margin, 0, width - inset_width, top_margin)); |
85 right_margin, top_margin); | 91 images_[2] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
86 images_[3] = gdk_pixbuf_new_subpixbuf(pixbuf, 0, top_margin, | 92 pixbuf, width - right_margin, 0, right_margin, top_margin)); |
87 left_margin, height - inset_height); | 93 images_[3] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
88 images_[4] = gdk_pixbuf_new_subpixbuf(pixbuf, left_margin, top_margin, | 94 pixbuf, 0, top_margin, left_margin, height - inset_height)); |
89 width - inset_width, | 95 images_[4] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
90 height - inset_height); | 96 pixbuf, left_margin, top_margin, width - inset_width, |
91 images_[5] = gdk_pixbuf_new_subpixbuf(pixbuf, width - right_margin, | 97 height - inset_height)); |
92 top_margin, right_margin, | 98 images_[5] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
93 height - inset_height); | 99 pixbuf, width - right_margin, top_margin, right_margin, |
94 images_[6] = gdk_pixbuf_new_subpixbuf(pixbuf, 0, height - bottom_margin, | 100 height - inset_height)); |
95 left_margin, bottom_margin); | 101 images_[6] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
96 images_[7] = gdk_pixbuf_new_subpixbuf(pixbuf, left_margin, | 102 pixbuf, 0, height - bottom_margin, left_margin, bottom_margin)); |
97 height - bottom_margin, | 103 images_[7] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
98 width - inset_width, bottom_margin); | 104 pixbuf, left_margin, height - bottom_margin, |
99 images_[8] = gdk_pixbuf_new_subpixbuf(pixbuf, width - right_margin, | 105 width - inset_width, bottom_margin)); |
100 height - bottom_margin, | 106 images_[8] = new gfx::Image(gdk_pixbuf_new_subpixbuf( |
101 right_margin, bottom_margin); | 107 pixbuf, width - right_margin, height - bottom_margin, |
| 108 right_margin, bottom_margin)); |
102 } | 109 } |
103 | 110 |
104 NineBox::~NineBox() { | 111 NineBox::~NineBox() { |
105 if (unref_pixbufs_on_destroy_) { | 112 if (unref_images_on_destroy_) { |
106 for (int i = 0; i < 9; i++) { | 113 for (int i = 0; i < 9; i++) { |
107 g_object_unref(images_[i]); | 114 delete images_[i]; |
108 } | 115 } |
109 } | 116 } |
110 } | 117 } |
111 | 118 |
112 void NineBox::RenderToWidget(GtkWidget* dst) const { | 119 void NineBox::RenderToWidget(GtkWidget* dst) const { |
113 RenderToWidgetWithOpacity(dst, 1.0); | 120 RenderToWidgetWithOpacity(dst, 1.0); |
114 } | 121 } |
115 | 122 |
116 void NineBox::RenderToWidgetWithOpacity(GtkWidget* dst, double opacity) const { | 123 void NineBox::RenderToWidgetWithOpacity(GtkWidget* dst, double opacity) const { |
117 int dst_width = dst->allocation.width; | 124 int dst_width = dst->allocation.width; |
118 int dst_height = dst->allocation.height; | 125 int dst_height = dst->allocation.height; |
119 | 126 |
120 // The upper-left and lower-right corners of the center square in the | 127 // The upper-left and lower-right corners of the center square in the |
121 // rendering of the ninebox. | 128 // rendering of the ninebox. |
122 int x1 = gdk_pixbuf_get_width(images_[0]); | 129 int x1 = gdk_pixbuf_get_width(images_[0]->ToGdkPixbuf()); |
123 int y1 = gdk_pixbuf_get_height(images_[0]); | 130 int y1 = gdk_pixbuf_get_height(images_[0]->ToGdkPixbuf()); |
124 int x2 = images_[2] ? dst_width - gdk_pixbuf_get_width(images_[2]) : x1; | 131 int x2 = images_[2] ? dst_width - gdk_pixbuf_get_width( |
125 int y2 = images_[6] ? dst_height - gdk_pixbuf_get_height(images_[6]) : y1; | 132 images_[2]->ToGdkPixbuf()) : x1; |
| 133 int y2 = images_[6] ? dst_height - gdk_pixbuf_get_height( |
| 134 images_[6]->ToGdkPixbuf()) : y1; |
126 // Paint nothing if there's not enough room. | 135 // Paint nothing if there's not enough room. |
127 if (x2 < x1 || y2 < y1) | 136 if (x2 < x1 || y2 < y1) |
128 return; | 137 return; |
129 | 138 |
130 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(dst->window)); | 139 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(dst->window)); |
131 // For widgets that have their own window, the allocation (x,y) coordinates | 140 // For widgets that have their own window, the allocation (x,y) coordinates |
132 // are GdkWindow relative. For other widgets, the coordinates are relative | 141 // are GdkWindow relative. For other widgets, the coordinates are relative |
133 // to their container. | 142 // to their container. |
134 if (GTK_WIDGET_NO_WINDOW(dst)) { | 143 if (GTK_WIDGET_NO_WINDOW(dst)) { |
135 // Transform our cairo from window to widget coordinates. | 144 // Transform our cairo from window to widget coordinates. |
136 cairo_translate(cr, dst->allocation.x, dst->allocation.y); | 145 cairo_translate(cr, dst->allocation.x, dst->allocation.y); |
137 } | 146 } |
138 | 147 |
139 if (base::i18n::IsRTL()) { | 148 if (base::i18n::IsRTL()) { |
140 cairo_translate(cr, dst_width, 0.0f); | 149 cairo_translate(cr, dst_width, 0.0f); |
141 cairo_scale(cr, -1.0f, 1.0f); | 150 cairo_scale(cr, -1.0f, 1.0f); |
142 } | 151 } |
143 | 152 |
144 // Top row, center image is horizontally tiled. | 153 // Top row, center image is horizontally tiled. |
145 if (images_[0]) | 154 DrawImage(cr, dst, images_[0], 0, 0, opacity); |
146 DrawPixbuf(cr, images_[0], 0, 0, opacity); | 155 TileImage(cr, dst, images_[1], x1, 0, x2 - x1, y1, opacity); |
147 if (images_[1]) | 156 DrawImage(cr, dst, images_[2], x2, 0, opacity); |
148 TileImage(cr, images_[1], x1, 0, x2 - x1, y1, opacity); | |
149 if (images_[2]) | |
150 DrawPixbuf(cr, images_[2], x2, 0, opacity); | |
151 | 157 |
152 // Center row, all images are vertically tiled, center is horizontally tiled. | 158 // Center row, all images are vertically tiled, center is horizontally tiled. |
153 if (images_[3]) | 159 TileImage(cr, dst, images_[3], 0, y1, x1, y2 - y1, opacity); |
154 TileImage(cr, images_[3], 0, y1, x1, y2 - y1, opacity); | 160 TileImage(cr, dst, images_[4], x1, y1, x2 - x1, y2 - y1, opacity); |
155 if (images_[4]) | 161 TileImage(cr, dst, images_[5], x2, y1, dst_width - x2, y2 - y1, opacity); |
156 TileImage(cr, images_[4], x1, y1, x2 - x1, y2 - y1, opacity); | |
157 if (images_[5]) | |
158 TileImage(cr, images_[5], x2, y1, dst_width - x2, y2 - y1, opacity); | |
159 | 162 |
160 // Bottom row, center image is horizontally tiled. | 163 // Bottom row, center image is horizontally tiled. |
161 if (images_[6]) | 164 DrawImage(cr, dst, images_[6], 0, y2, opacity); |
162 DrawPixbuf(cr, images_[6], 0, y2, opacity); | 165 TileImage(cr, dst, images_[7], x1, y2, x2 - x1, dst_height - y2, opacity); |
163 if (images_[7]) | 166 DrawImage(cr, dst, images_[8], x2, y2, opacity); |
164 TileImage(cr, images_[7], x1, y2, x2 - x1, dst_height - y2, opacity); | |
165 if (images_[8]) | |
166 DrawPixbuf(cr, images_[8], x2, y2, opacity); | |
167 | 167 |
168 cairo_destroy(cr); | 168 cairo_destroy(cr); |
169 } | 169 } |
170 | 170 |
171 void NineBox::RenderTopCenterStrip(cairo_t* cr, int x, int y, | |
172 int width) const { | |
173 const int height = gdk_pixbuf_get_height(images_[1]); | |
174 TileImage(cr, images_[1], x, y, width, height, 1.0); | |
175 } | |
176 | |
177 void NineBox::ContourWidget(GtkWidget* widget) const { | 171 void NineBox::ContourWidget(GtkWidget* widget) const { |
178 GtkAllocation allocation; | 172 GtkAllocation allocation; |
179 gtk_widget_get_allocation(widget, &allocation); | 173 gtk_widget_get_allocation(widget, &allocation); |
180 int width = allocation.width; | 174 int width = allocation.width; |
181 int height = allocation.height; | 175 int height = allocation.height; |
182 int x1 = gdk_pixbuf_get_width(images_[0]); | 176 int x1 = gdk_pixbuf_get_width(images_[0]->ToGdkPixbuf()); |
183 int x2 = width - gdk_pixbuf_get_width(images_[2]); | 177 int x2 = width - gdk_pixbuf_get_width(images_[2]->ToGdkPixbuf()); |
| 178 |
| 179 // TODO(erg): Far in the future, when we're doing the real gtk3 porting, this |
| 180 // all needs to be switchted to pure cairo operations. |
184 | 181 |
185 // Paint the left and right sides. | 182 // Paint the left and right sides. |
186 GdkBitmap* mask = gdk_pixmap_new(NULL, width, height, 1); | 183 GdkBitmap* mask = gdk_pixmap_new(NULL, width, height, 1); |
187 gdk_pixbuf_render_threshold_alpha(images_[0], mask, | 184 gdk_pixbuf_render_threshold_alpha(images_[0]->ToGdkPixbuf(), mask, |
188 0, 0, | 185 0, 0, |
189 0, 0, -1, -1, | 186 0, 0, -1, -1, |
190 1); | 187 1); |
191 gdk_pixbuf_render_threshold_alpha(images_[2], mask, | 188 gdk_pixbuf_render_threshold_alpha(images_[2]->ToGdkPixbuf(), mask, |
192 0, 0, | 189 0, 0, |
193 x2, 0, -1, -1, | 190 x2, 0, -1, -1, |
194 1); | 191 1); |
195 | 192 |
196 // Assume no transparency in the middle rectangle. | 193 // Assume no transparency in the middle rectangle. |
197 cairo_t* cr = gdk_cairo_create(mask); | 194 cairo_t* cr = gdk_cairo_create(mask); |
198 cairo_rectangle(cr, x1, 0, x2 - x1, height); | 195 cairo_rectangle(cr, x1, 0, x2 - x1, height); |
199 cairo_fill(cr); | 196 cairo_fill(cr); |
200 cairo_destroy(cr); | 197 cairo_destroy(cr); |
201 | 198 |
(...skipping 18 matching lines...) Expand all Loading... |
220 cairo_paint(flipped_cr); | 217 cairo_paint(flipped_cr); |
221 cairo_destroy(flipped_cr); | 218 cairo_destroy(flipped_cr); |
222 | 219 |
223 // Mask the widget. | 220 // Mask the widget. |
224 gtk_widget_shape_combine_mask(widget, flipped_mask, 0, 0); | 221 gtk_widget_shape_combine_mask(widget, flipped_mask, 0, 0); |
225 g_object_unref(flipped_mask); | 222 g_object_unref(flipped_mask); |
226 } | 223 } |
227 | 224 |
228 g_object_unref(mask); | 225 g_object_unref(mask); |
229 } | 226 } |
OLD | NEW |