1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "web/PopupContainer.h" 28 29 #include <gtest/gtest.h> 30 31 using namespace WebCore; 32 using namespace blink; 33 34 class MockPopupContent : public PopupContent { 35 public: 36 virtual void setMaxHeight(int max) OVERRIDE { maxHeight = max; } 37 virtual int popupContentHeight() const OVERRIDE { return height; } 38 virtual ~MockPopupContent() { } 39 40 virtual void layout() OVERRIDE 41 { 42 layoutCount++; 43 width = std::min(maxWidth, width); 44 height = std::min(maxHeight, height); 45 height -= height % 16; 46 } 47 48 virtual void setMaxWidthAndLayout(int max) OVERRIDE 49 { 50 maxWidth = max; 51 layout(); 52 } 53 54 MockPopupContent(const IntSize& widgetSize) 55 : width(widgetSize.width() - borderSize * 2) 56 , height(widgetSize.height() - borderSize * 2) 57 , maxWidth(width) 58 , maxHeight(height) 59 , layoutCount(0) 60 { 61 } 62 63 int width; 64 int height; 65 int maxWidth; 66 int maxHeight; 67 unsigned layoutCount; 68 69 static const int borderSize = 1; // Should match to kBorderSize in PopupContainer.cpp. 70 }; 71 72 const int screenMaxX = 1024; 73 const int screenMaxY = 768; 74 const int targetControlWidth = 130; 75 76 static IntRect calculatePositionWithTransformAndRTL(const IntRect& initialRect, const IntSize& transformOffset, int verticalOffset, PopupContent* content) 77 { 78 const bool isRTL = true; 79 const int targetControlHeight = 20; 80 const FloatRect screenRect(0, 0, screenMaxX, screenMaxY); 81 const FloatRect windowRect(0, 0, 512, 512); 82 int rtlOffset = targetControlWidth - initialRect.width(); 83 bool needToResizeView = false; 84 return PopupContainer::layoutAndCalculateWidgetRectInternal(initialRect, targetControlHeight, windowRect, screenRect, !isRTL, rtlOffset, verticalOffset, transformOffset, content, needToResizeView); 85 } 86 87 static IntRect calculatePosition(const IntRect& initialRect, PopupContent* content, FloatRect windowRect = FloatRect(0, 0, 512, 512), bool isRTL = true) 88 { 89 const int targetControlHeight = 20; 90 const FloatRect screenRect(0, 0, screenMaxX, screenMaxY); 91 int rtlOffset = (targetControlWidth - initialRect.width()) * (isRTL ? 1 : -1); 92 bool needToResizeView = false; 93 return PopupContainer::layoutAndCalculateWidgetRectInternal(initialRect, targetControlHeight, windowRect, screenRect, !isRTL, rtlOffset, 0, IntSize(), content, needToResizeView); 94 } 95 96 TEST(PopupContainerTest, PopupPosition) 97 { 98 // Suppose that initialRect.location is the bottom-left corner of the target 99 // control such as <select>. 100 101 { 102 // If initialRect is in the screen, nothing should happen. 103 IntRect initialRect(100, 100, 256, 258); 104 MockPopupContent content(initialRect.size()); 105 IntRect resultRect = calculatePosition(initialRect, &content); 106 EXPECT_EQ(initialRect, resultRect); 107 EXPECT_EQ(0u, content.layoutCount); 108 } 109 110 { 111 // If the left edge of the control is projecting from the screen, making 112 // the widget aligned to the right edge of the control. 113 IntRect initialRect(-10, 100, 100, 258); 114 MockPopupContent content(initialRect.size()); 115 IntRect resultRect = calculatePosition(initialRect, &content); 116 EXPECT_EQ(IntRect(20, 100, 100, 258), resultRect); 117 } 118 119 { 120 // Made the widget aligned to the right edge. But it's still projecting 121 // from the screen. 122 IntRect initialRect(-10, 100, targetControlWidth, 258); 123 MockPopupContent content(initialRect.size()); 124 IntRect resultRect = calculatePosition(initialRect, &content); 125 EXPECT_EQ(IntRect(0, 100, 120, 258), resultRect); 126 EXPECT_EQ(118, content.width); 127 EXPECT_TRUE(content.layoutCount); 128 } 129 130 { 131 // If the right edge of the control is projecting from the screen, 132 // shrink the width of the widget. 133 IntRect initialRect(screenMaxX - 100, 100, targetControlWidth, 258); 134 MockPopupContent content(initialRect.size()); 135 IntRect resultRect = calculatePosition(initialRect, &content); 136 EXPECT_EQ(IntRect(screenMaxX - 100, 100, 100, 258), resultRect); 137 EXPECT_EQ(98, content.width); 138 EXPECT_TRUE(content.layoutCount); 139 } 140 141 { 142 // If there is no enough room below, move the widget upwards. 143 IntRect initialRect(100, 700, targetControlWidth, 258); 144 MockPopupContent content(initialRect.size()); 145 IntRect resultRect = calculatePosition(initialRect, &content); 146 EXPECT_EQ(IntRect(100, 422, targetControlWidth, 258), resultRect); 147 EXPECT_EQ(0u, content.layoutCount); 148 } 149 150 { 151 // There is no enough room below and above, and the below space is larger. 152 IntRect initialRect(100, 300, targetControlWidth, 514); 153 MockPopupContent content(initialRect.size()); 154 IntRect resultRect = calculatePosition(initialRect, &content); 155 EXPECT_EQ(IntRect(100, 300, targetControlWidth, 466), resultRect); 156 EXPECT_TRUE(content.layoutCount); 157 EXPECT_EQ(464, content.height); 158 } 159 160 { 161 // There is no enough room below and above, and the above space is larger. 162 IntRect initialRect(100, 400, targetControlWidth, 514); 163 MockPopupContent content(initialRect.size()); 164 IntRect resultRect = calculatePosition(initialRect, &content); 165 EXPECT_EQ(IntRect(100, 10, targetControlWidth, 370), resultRect); 166 EXPECT_TRUE(content.layoutCount); 167 EXPECT_EQ(368, content.height); 168 } 169 170 { 171 // There is not enough room to the right, so open the popup menu to the left. 172 IntRect initialRect(screenMaxX - targetControlWidth - 6, 100, targetControlWidth * 2, 100); 173 MockPopupContent content(initialRect.size()); 174 IntRect resultRect = calculatePosition(initialRect, &content, FloatRect(0, 0, screenMaxX, screenMaxY), false); 175 EXPECT_EQ(IntRect(758, 100, 260, 100), resultRect); 176 } 177 178 { 179 // Test for --webkit-transform:rotate(53deg). 180 IntRect initialRect(100, 700, targetControlWidth, 258); 181 MockPopupContent content(initialRect.size()); 182 IntSize transformOffset(-4, -8); 183 IntRect resultRect = calculatePositionWithTransformAndRTL(initialRect, transformOffset, -104, &content); 184 EXPECT_EQ(IntRect(104, 430, targetControlWidth, 258), resultRect); 185 EXPECT_EQ(0u, content.layoutCount); 186 } 187 188 { 189 // Test for --webkit-transform:rotate(-53deg). 190 IntRect initialRect(100, 700, targetControlWidth, 258); 191 MockPopupContent content(initialRect.size()); 192 IntSize transformOffset(4, -8); 193 IntRect resultRect = calculatePositionWithTransformAndRTL(initialRect, transformOffset, 104, &content); 194 EXPECT_EQ(IntRect(96, 430, targetControlWidth, 258), resultRect); 195 EXPECT_EQ(0u, content.layoutCount); 196 } 197 } 198