IntRect PopupContainer::layoutAndCalculateWidgetRect(int targetControlHeight, const IntPoint& popupInitialCoordinate) { // Reset the max width and height to their default values, they will be recomputed below // if necessary. m_listBox->setMaxHeight(kMaxHeight); m_listBox->setMaxWidth(std::numeric_limits<int>::max()); // Lay everything out to figure out our preferred size, then tell the view's // WidgetClient about it. It should assign us a client. int rtlOffset = layoutAndGetRTLOffset(); bool isRTL = this->isRTL(); int rightOffset = isRTL ? rtlOffset : 0; // Assume m_listBox size is already calculated. IntSize targetSize(m_listBox->width() + kBorderSize * 2, m_listBox->height() + kBorderSize * 2); IntRect widgetRectInScreen; ChromeClientChromium* chromeClient = chromeClientChromium(); if (chromeClient) { // If the popup would extend past the bottom of the screen, open upwards // instead. FloatRect screen = screenAvailableRect(m_frameView.get()); // Use popupInitialCoordinate.x() + rightOffset because RTL position // needs to be considered. widgetRectInScreen = chromeClient->rootViewToScreen(IntRect(popupInitialCoordinate.x() + rightOffset, popupInitialCoordinate.y(), targetSize.width(), targetSize.height())); // If we have multiple screens and the browser rect is in one screen, we have // to clip the window width to the screen width. // When clipping, we also need to set a maximum width for the list box. FloatRect windowRect = chromeClient->windowRect(); bool needToResizeView = false; widgetRectInScreen = layoutAndCalculateWidgetRectInternal(widgetRectInScreen, targetControlHeight, windowRect, screen, isRTL, rtlOffset, m_listBox.get(), needToResizeView); if (needToResizeView) fitToListBox(); } return widgetRectInScreen; }
IntRect PopupContainer::layoutAndCalculateWidgetRect(int targetControlHeight, const IntPoint& popupInitialCoordinate) { // Reset the max width and height to their default values, they will be recomputed below // if necessary. m_listBox->setMaxHeight(kMaxHeight); m_listBox->setMaxWidth(std::numeric_limits<int>::max()); // Lay everything out to figure out our preferred size, then tell the view's // WidgetClient about it. It should assign us a client. int rtlOffset = layoutAndGetRTLOffset(); bool isRTL = this->isRTL(); int rightOffset = isRTL ? rtlOffset : 0; // Assume m_listBox size is already calculated. IntSize targetSize(m_listBox->width() + kBorderSize * 2, m_listBox->height() + kBorderSize * 2); IntRect widgetRect; ChromeClientChromium* chromeClient = chromeClientChromium(); if (chromeClient) { // If the popup would extend past the bottom of the screen, open upwards // instead. FloatRect screen = screenAvailableRect(m_frameView.get()); // Use popupInitialCoordinate.x() + rightOffset because RTL position // needs to be considered. widgetRect = chromeClient->rootViewToScreen(IntRect(popupInitialCoordinate.x() + rightOffset, popupInitialCoordinate.y(), targetSize.width(), targetSize.height())); // If we have multiple screens and the browser rect is in one screen, we have // to clip the window width to the screen width. // When clipping, we also need to set a maximum width for the list box. FloatRect windowRect = chromeClient->windowRect(); if (windowRect.x() >= screen.x() && windowRect.maxX() <= screen.maxX() && (widgetRect.x() < screen.x() || widgetRect.maxX() > screen.maxX())) { // First, inverse the popup alignment if it does not fit the screen - this might fix things (or make them better). IntRect inverseWidgetRect = chromeClient->rootViewToScreen(IntRect(popupInitialCoordinate.x() + (isRTL ? 0 : rtlOffset), popupInitialCoordinate.y(), targetSize.width(), targetSize.height())); IntRect enclosingScreen = enclosingIntRect(screen); unsigned originalCutoff = max(enclosingScreen.x() - widgetRect.x(), 0) + max(widgetRect.maxX() - enclosingScreen.maxX(), 0); unsigned inverseCutoff = max(enclosingScreen.x() - inverseWidgetRect.x(), 0) + max(inverseWidgetRect.maxX() - enclosingScreen.maxX(), 0); // Accept the inverse popup alignment if the trimmed content gets shorter than that in the original alignment case. if (inverseCutoff < originalCutoff) widgetRect = inverseWidgetRect; if (widgetRect.x() < screen.x()) { unsigned widgetRight = widgetRect.maxX(); widgetRect.setWidth(widgetRect.maxX() - screen.x()); widgetRect.setX(widgetRight - widgetRect.width()); listBox()->setMaxWidthAndLayout(max(widgetRect.width() - kBorderSize * 2, 0)); } else if (widgetRect.maxX() > screen.maxX()) { widgetRect.setWidth(screen.maxX() - widgetRect.x()); listBox()->setMaxWidthAndLayout(max(widgetRect.width() - kBorderSize * 2, 0)); } } // Calculate Y axis size. if (widgetRect.maxY() > static_cast<int>(screen.maxY())) { if (widgetRect.y() - widgetRect.height() - targetControlHeight > 0) { // There is enough room to open upwards. widgetRect.move(0, -(widgetRect.height() + targetControlHeight)); } else { // Figure whether upwards or downwards has more room and set the // maximum number of items. int spaceAbove = widgetRect.y() - targetControlHeight; int spaceBelow = screen.maxY() - widgetRect.y(); if (spaceAbove > spaceBelow) m_listBox->setMaxHeight(spaceAbove); else m_listBox->setMaxHeight(spaceBelow); layoutAndGetRTLOffset(); // Our height has changed, so recompute only Y axis of widgetRect. // We don't have to recompute X axis, so we only replace Y axis // in widgetRect. IntRect frameInScreen = chromeClient->rootViewToScreen(frameRect()); widgetRect.setY(frameInScreen.y()); widgetRect.setHeight(frameInScreen.height()); // And move upwards if necessary. if (spaceAbove > spaceBelow) widgetRect.move(0, -(widgetRect.height() + targetControlHeight)); } } } return widgetRect; }