| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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 "chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "testing/gtest/include/gtest/gtest.h" | |
| 10 | |
| 11 namespace { | |
| 12 | |
| 13 const int kSpacing = 3; | |
| 14 const int kBorderWidth = 5; | |
| 15 | |
| 16 } // namespace | |
| 17 | |
| 18 class GtkChromeShrinkableHBoxTest : public testing::Test { | |
| 19 protected: | |
| 20 GtkChromeShrinkableHBoxTest() | |
| 21 : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)), | |
| 22 box_(gtk_chrome_shrinkable_hbox_new(FALSE, FALSE, kSpacing)) { | |
| 23 gtk_widget_set_direction(box_, GTK_TEXT_DIR_LTR); | |
| 24 gtk_window_set_default_size(GTK_WINDOW(window_), 200, 200); | |
| 25 gtk_container_add(GTK_CONTAINER(window_), box_); | |
| 26 gtk_container_set_border_width(GTK_CONTAINER(box_), kBorderWidth); | |
| 27 } | |
| 28 | |
| 29 ~GtkChromeShrinkableHBoxTest() { | |
| 30 gtk_widget_destroy(window_); | |
| 31 } | |
| 32 | |
| 33 // Add some children widgets with arbitrary width and padding. | |
| 34 void AddChildren(bool pack_start) { | |
| 35 static struct { | |
| 36 int width; | |
| 37 int padding; | |
| 38 } kChildrenData[] = { | |
| 39 { 60, 2 }, | |
| 40 { 70, 3 }, | |
| 41 { 80, 5 }, | |
| 42 { 50, 7 }, | |
| 43 { 40, 11 }, | |
| 44 { 60, 0 }, | |
| 45 { 0, 0 } | |
| 46 }; | |
| 47 | |
| 48 for (size_t i = 0; kChildrenData[i].width; ++i) { | |
| 49 GtkWidget* child = gtk_fixed_new(); | |
| 50 gtk_widget_set_size_request(child, kChildrenData[i].width, -1); | |
| 51 if (pack_start) { | |
| 52 gtk_chrome_shrinkable_hbox_pack_start( | |
| 53 GTK_CHROME_SHRINKABLE_HBOX(box_), child, kChildrenData[i].padding); | |
| 54 } else { | |
| 55 gtk_chrome_shrinkable_hbox_pack_end( | |
| 56 GTK_CHROME_SHRINKABLE_HBOX(box_), child, kChildrenData[i].padding); | |
| 57 } | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 // Check if all children's size allocation are inside the |box_|'s boundary. | |
| 62 void Validate(bool pack_start) { | |
| 63 std::vector<ChildData> children_data; | |
| 64 gtk_container_foreach(GTK_CONTAINER(box_), CollectChildData, | |
| 65 &children_data); | |
| 66 | |
| 67 size_t children_count = children_data.size(); | |
| 68 size_t visible_children_count = 0; | |
| 69 for (size_t i = 0; i < children_count; ++i) { | |
| 70 if (children_data[i].visible) | |
| 71 ++visible_children_count; | |
| 72 } | |
| 73 | |
| 74 if (visible_children_count == 0) | |
| 75 return; | |
| 76 | |
| 77 int border_width = gtk_container_get_border_width(GTK_CONTAINER(box_)); | |
| 78 int x = box_->allocation.x + border_width; | |
| 79 int width = box_->allocation.width - border_width * 2; | |
| 80 int spacing = gtk_box_get_spacing(GTK_BOX(box_)); | |
| 81 bool homogeneous = gtk_box_get_homogeneous(GTK_BOX(box_)); | |
| 82 | |
| 83 if (homogeneous) { | |
| 84 // If the |box_| is in homogeneous mode, then check if the visible | |
| 85 // children are not overlapped with each other. | |
| 86 int homogeneous_child_width = | |
| 87 (width - (visible_children_count - 1) * spacing) / | |
| 88 visible_children_count; | |
| 89 | |
| 90 for (size_t i = 0; i < children_count; ++i) { | |
| 91 SCOPED_TRACE(testing::Message() << "Validate homogeneous child " << i | |
| 92 << " visible: " << children_data[i].visible | |
| 93 << " padding: " << children_data[i].padding | |
| 94 << " x: " << children_data[i].x | |
| 95 << " width: " << children_data[i].width); | |
| 96 | |
| 97 if (children_data[i].visible) | |
| 98 ASSERT_LE(children_data[i].width, homogeneous_child_width); | |
| 99 } | |
| 100 } else { | |
| 101 // If the |box_| is not in homogeneous mode, then just check if all | |
| 102 // visible children are inside the |box_|'s boundary. And for those | |
| 103 // hidden children which are out of the boundary, they should only | |
| 104 // be hidden one by one from the end of the |box_|. | |
| 105 bool last_visible = pack_start; | |
| 106 bool visibility_changed = false; | |
| 107 for (size_t i = 0; i < children_count; ++i) { | |
| 108 SCOPED_TRACE(testing::Message() << "Validate child " << i | |
| 109 << " visible: " << children_data[i].visible | |
| 110 << " padding: " << children_data[i].padding | |
| 111 << " x: " << children_data[i].x | |
| 112 << " width: " << children_data[i].width); | |
| 113 | |
| 114 if (last_visible != children_data[i].visible) { | |
| 115 ASSERT_FALSE(visibility_changed); | |
| 116 visibility_changed = true; | |
| 117 last_visible = children_data[i].visible; | |
| 118 } | |
| 119 if (children_data[i].visible) { | |
| 120 ASSERT_GE(children_data[i].x, | |
| 121 x + children_data[i].padding); | |
| 122 ASSERT_LE(children_data[i].x + children_data[i].width, | |
| 123 x + width - children_data[i].padding); | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 void Test(bool pack_start) { | |
| 130 gtk_widget_show_all(window_); | |
| 131 GtkAllocation allocation = { 0, 0, 0, 200 }; | |
| 132 gtk_chrome_shrinkable_hbox_set_hide_child_directly( | |
| 133 GTK_CHROME_SHRINKABLE_HBOX(box_), FALSE); | |
| 134 for (int width = 500; width > kBorderWidth * 2; --width) { | |
| 135 SCOPED_TRACE(testing::Message() << "Shrink hide_child_directly = FALSE," | |
| 136 << " width = " << width); | |
| 137 | |
| 138 allocation.width = width; | |
| 139 // Reducing the width may cause some children to be hidden, which will | |
| 140 // cause queue resize, so it's necessary to do another size allocation to | |
| 141 // emulate the queue resize. | |
| 142 gtk_widget_size_allocate(box_, &allocation); | |
| 143 gtk_widget_size_allocate(box_, &allocation); | |
| 144 ASSERT_NO_FATAL_FAILURE(Validate(pack_start)) << "width = " << width; | |
| 145 } | |
| 146 | |
| 147 for (int width = kBorderWidth * 2; width <= 500; ++width) { | |
| 148 SCOPED_TRACE(testing::Message() << "Expand hide_child_directly = FALSE," | |
| 149 << " width = " << width); | |
| 150 | |
| 151 allocation.width = width; | |
| 152 // Expanding the width may cause some invisible children to be shown, | |
| 153 // which will cause queue resize, so it's necessary to do another size | |
| 154 // allocation to emulate the queue resize. | |
| 155 gtk_widget_size_allocate(box_, &allocation); | |
| 156 gtk_widget_size_allocate(box_, &allocation); | |
| 157 ASSERT_NO_FATAL_FAILURE(Validate(pack_start)); | |
| 158 } | |
| 159 | |
| 160 gtk_chrome_shrinkable_hbox_set_hide_child_directly( | |
| 161 GTK_CHROME_SHRINKABLE_HBOX(box_), TRUE); | |
| 162 for (int width = 500; width > kBorderWidth * 2; --width) { | |
| 163 SCOPED_TRACE(testing::Message() << "Shrink hide_child_directly = TRUE," | |
| 164 << " width = " << width); | |
| 165 | |
| 166 allocation.width = width; | |
| 167 gtk_widget_size_allocate(box_, &allocation); | |
| 168 gtk_widget_size_allocate(box_, &allocation); | |
| 169 ASSERT_NO_FATAL_FAILURE(Validate(pack_start)); | |
| 170 } | |
| 171 | |
| 172 for (int width = kBorderWidth * 2; width <= 500; ++width) { | |
| 173 SCOPED_TRACE(testing::Message() << "Expand hide_child_directly = TRUE," | |
| 174 << " width = " << width); | |
| 175 | |
| 176 allocation.width = width; | |
| 177 gtk_widget_size_allocate(box_, &allocation); | |
| 178 gtk_widget_size_allocate(box_, &allocation); | |
| 179 ASSERT_NO_FATAL_FAILURE(Validate(pack_start)); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 protected: | |
| 184 GtkWidget* window_; | |
| 185 GtkWidget* box_; | |
| 186 | |
| 187 private: | |
| 188 struct ChildData { | |
| 189 bool visible; | |
| 190 int padding; | |
| 191 int x; | |
| 192 int width; | |
| 193 }; | |
| 194 | |
| 195 static void CollectChildData(GtkWidget* child, gpointer userdata) { | |
| 196 guint padding; | |
| 197 gtk_box_query_child_packing(GTK_BOX(gtk_widget_get_parent(child)), child, | |
| 198 NULL, NULL, &padding, NULL); | |
| 199 | |
| 200 ChildData data; | |
| 201 data.visible = GTK_WIDGET_VISIBLE(child); | |
| 202 data.padding = padding; | |
| 203 data.x = child->allocation.x; | |
| 204 data.width = child->allocation.width; | |
| 205 | |
| 206 reinterpret_cast<std::vector<ChildData>*>(userdata)->push_back(data); | |
| 207 } | |
| 208 }; | |
| 209 | |
| 210 TEST_F(GtkChromeShrinkableHBoxTest, PackStart) { | |
| 211 AddChildren(true); | |
| 212 | |
| 213 { | |
| 214 SCOPED_TRACE("Test LTR"); | |
| 215 gtk_widget_set_direction(box_, GTK_TEXT_DIR_LTR); | |
| 216 EXPECT_NO_FATAL_FAILURE(Test(true)); | |
| 217 } | |
| 218 { | |
| 219 SCOPED_TRACE("Test RTL"); | |
| 220 gtk_widget_set_direction(box_, GTK_TEXT_DIR_RTL); | |
| 221 EXPECT_NO_FATAL_FAILURE(Test(true)); | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 TEST_F(GtkChromeShrinkableHBoxTest, PackEnd) { | |
| 226 AddChildren(false); | |
| 227 | |
| 228 { | |
| 229 SCOPED_TRACE("Test LTR"); | |
| 230 gtk_widget_set_direction(box_, GTK_TEXT_DIR_LTR); | |
| 231 EXPECT_NO_FATAL_FAILURE(Test(false)); | |
| 232 } | |
| 233 { | |
| 234 SCOPED_TRACE("Test RTL"); | |
| 235 gtk_widget_set_direction(box_, GTK_TEXT_DIR_RTL); | |
| 236 EXPECT_NO_FATAL_FAILURE(Test(false)); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 TEST_F(GtkChromeShrinkableHBoxTest, Homogeneous) { | |
| 241 AddChildren(true); | |
| 242 gtk_box_set_homogeneous(GTK_BOX(box_), true); | |
| 243 | |
| 244 { | |
| 245 SCOPED_TRACE("Test LTR"); | |
| 246 gtk_widget_set_direction(box_, GTK_TEXT_DIR_LTR); | |
| 247 EXPECT_NO_FATAL_FAILURE(Test(true)); | |
| 248 } | |
| 249 { | |
| 250 SCOPED_TRACE("Test RTL"); | |
| 251 gtk_widget_set_direction(box_, GTK_TEXT_DIR_RTL); | |
| 252 EXPECT_NO_FATAL_FAILURE(Test(true)); | |
| 253 } | |
| 254 } | |
| OLD | NEW |