Home | History | Annotate | Download | only in web
      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 blink;
     32 
     33 class MockPopupContent : public PopupContent {
     34 public:
     35     virtual void setMaxHeight(int max) OVERRIDE { maxHeight = max; }
     36     virtual int popupContentHeight() const OVERRIDE { return height; }
     37     virtual ~MockPopupContent() { }
     38 
     39     virtual void layout() OVERRIDE
     40     {
     41         layoutCount++;
     42         width = std::min(maxWidth, width);
     43         height = std::min(maxHeight, height);
     44         height -= height % 16;
     45     }
     46 
     47     virtual void setMaxWidthAndLayout(int max) OVERRIDE
     48     {
     49         maxWidth = max;
     50         layout();
     51     }
     52 
     53     MockPopupContent(const IntSize& widgetSize)
     54         : width(widgetSize.width() - borderSize * 2)
     55         , height(widgetSize.height() - borderSize * 2)
     56         , maxWidth(width)
     57         , maxHeight(height)
     58         , layoutCount(0)
     59     {
     60     }
     61 
     62     int width;
     63     int height;
     64     int maxWidth;
     65     int maxHeight;
     66     unsigned layoutCount;
     67 
     68     static const int borderSize = 1; // Should match to kBorderSize in PopupContainer.cpp.
     69 };
     70 
     71 const int screenMaxX = 1024;
     72 const int screenMaxY = 768;
     73 const int targetControlWidth = 130;
     74 
     75 static IntRect calculatePositionWithTransformAndRTL(const IntRect& initialRect, const IntSize& transformOffset, int verticalOffset, PopupContent* content)
     76 {
     77     const bool isRTL = true;
     78     const int targetControlHeight = 20;
     79     const FloatRect screenRect(0, 0, screenMaxX, screenMaxY);
     80     const FloatRect windowRect(0, 0, 512, 512);
     81     int rtlOffset = targetControlWidth - initialRect.width();
     82     bool needToResizeView = false;
     83     return PopupContainer::layoutAndCalculateWidgetRectInternal(initialRect, targetControlHeight, windowRect, screenRect, !isRTL, rtlOffset, verticalOffset, transformOffset, content, needToResizeView);
     84 }
     85 
     86 static IntRect calculatePosition(const IntRect& initialRect, PopupContent* content, FloatRect windowRect = FloatRect(0, 0, 512, 512), bool isRTL = true)
     87 {
     88     const int targetControlHeight = 20;
     89     const FloatRect screenRect(0, 0, screenMaxX, screenMaxY);
     90     int rtlOffset = (targetControlWidth - initialRect.width()) * (isRTL ? 1 : -1);
     91     bool needToResizeView = false;
     92     return PopupContainer::layoutAndCalculateWidgetRectInternal(initialRect, targetControlHeight, windowRect, screenRect, !isRTL, rtlOffset, 0, IntSize(), content, needToResizeView);
     93 }
     94 
     95 TEST(PopupContainerTest, PopupPosition)
     96 {
     97     // Suppose that initialRect.location is the bottom-left corner of the target
     98     // control such as <select>.
     99 
    100     {
    101         // If initialRect is in the screen, nothing should happen.
    102         IntRect initialRect(100, 100, 256, 258);
    103         MockPopupContent content(initialRect.size());
    104         IntRect resultRect = calculatePosition(initialRect, &content);
    105         EXPECT_EQ(initialRect, resultRect);
    106         EXPECT_EQ(0u, content.layoutCount);
    107     }
    108 
    109     {
    110         // If the left edge of the control is projecting from the screen, making
    111         // the widget aligned to the right edge of the control.
    112         IntRect initialRect(-10, 100, 100, 258);
    113         MockPopupContent content(initialRect.size());
    114         IntRect resultRect = calculatePosition(initialRect, &content);
    115         EXPECT_EQ(IntRect(20, 100, 100, 258), resultRect);
    116     }
    117 
    118     {
    119         // Made the widget aligned to the right edge. But it's still projecting
    120         // from the screen.
    121         IntRect initialRect(-10, 100, targetControlWidth, 258);
    122         MockPopupContent content(initialRect.size());
    123         IntRect resultRect = calculatePosition(initialRect, &content);
    124         EXPECT_EQ(IntRect(0, 100, 120, 258), resultRect);
    125         EXPECT_EQ(118, content.width);
    126         EXPECT_TRUE(content.layoutCount);
    127     }
    128 
    129     {
    130         // If the right edge of the control is projecting from the screen,
    131         // shrink the width of the widget.
    132         IntRect initialRect(screenMaxX - 100, 100, targetControlWidth, 258);
    133         MockPopupContent content(initialRect.size());
    134         IntRect resultRect = calculatePosition(initialRect, &content);
    135         EXPECT_EQ(IntRect(screenMaxX - 100, 100, 100, 258), resultRect);
    136         EXPECT_EQ(98, content.width);
    137         EXPECT_TRUE(content.layoutCount);
    138     }
    139 
    140     {
    141         // If there is no enough room below, move the widget upwards.
    142         IntRect initialRect(100, 700, targetControlWidth, 258);
    143         MockPopupContent content(initialRect.size());
    144         IntRect resultRect = calculatePosition(initialRect, &content);
    145         EXPECT_EQ(IntRect(100, 422, targetControlWidth, 258), resultRect);
    146         EXPECT_EQ(0u, content.layoutCount);
    147     }
    148 
    149     {
    150         // There is no enough room below and above, and the below space is larger.
    151         IntRect initialRect(100, 300, targetControlWidth, 514);
    152         MockPopupContent content(initialRect.size());
    153         IntRect resultRect = calculatePosition(initialRect, &content);
    154         EXPECT_EQ(IntRect(100, 300, targetControlWidth, 466), resultRect);
    155         EXPECT_TRUE(content.layoutCount);
    156         EXPECT_EQ(464, content.height);
    157     }
    158 
    159     {
    160         // There is no enough room below and above, and the above space is larger.
    161         IntRect initialRect(100, 400, targetControlWidth, 514);
    162         MockPopupContent content(initialRect.size());
    163         IntRect resultRect = calculatePosition(initialRect, &content);
    164         EXPECT_EQ(IntRect(100, 10, targetControlWidth, 370), resultRect);
    165         EXPECT_TRUE(content.layoutCount);
    166         EXPECT_EQ(368, content.height);
    167     }
    168 
    169     {
    170         // There is not enough room to the right, so open the popup menu to the left.
    171         IntRect initialRect(screenMaxX - targetControlWidth - 6, 100, targetControlWidth * 2, 100);
    172         MockPopupContent content(initialRect.size());
    173         IntRect resultRect = calculatePosition(initialRect, &content, FloatRect(0, 0, screenMaxX, screenMaxY), false);
    174         EXPECT_EQ(IntRect(758, 100, 260, 100), resultRect);
    175     }
    176 
    177     {
    178         // Test for --webkit-transform:rotate(53deg).
    179         IntRect initialRect(100, 700, targetControlWidth, 258);
    180         MockPopupContent content(initialRect.size());
    181         IntSize transformOffset(-4, -8);
    182         IntRect resultRect = calculatePositionWithTransformAndRTL(initialRect, transformOffset, -104, &content);
    183         EXPECT_EQ(IntRect(104, 430, targetControlWidth, 258), resultRect);
    184         EXPECT_EQ(0u, content.layoutCount);
    185     }
    186 
    187     {
    188         // Test for --webkit-transform:rotate(-53deg).
    189         IntRect initialRect(100, 700, targetControlWidth, 258);
    190         MockPopupContent content(initialRect.size());
    191         IntSize transformOffset(4, -8);
    192         IntRect resultRect = calculatePositionWithTransformAndRTL(initialRect, transformOffset, 104, &content);
    193         EXPECT_EQ(IntRect(96, 430, targetControlWidth, 258), resultRect);
    194         EXPECT_EQ(0u, content.layoutCount);
    195     }
    196 }
    197