Index: Source/core/frame/FrameViewAutoSizeInfo.cpp |
diff --git a/Source/core/frame/FrameViewAutoSizeInfo.cpp b/Source/core/frame/FrameViewAutoSizeInfo.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1dbd577e1a6c961335b0e7671e7c9bf1f295c75e |
--- /dev/null |
+++ b/Source/core/frame/FrameViewAutoSizeInfo.cpp |
@@ -0,0 +1,157 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/frame/FrameViewAutoSizeInfo.h" |
+ |
+#include "core/frame/FrameView.h" |
+#include "core/frame/LocalFrame.h" |
+#include "core/rendering/RenderBox.h" |
+#include "core/rendering/RenderView.h" |
+ |
+namespace blink { |
+ |
+FrameViewAutoSizeInfo::FrameViewAutoSizeInfo(FrameView* view) |
+ : m_frameView(view) |
+ , m_inAutoSize(false) |
+ , m_didRunAutosize(false) |
+{ |
+ ASSERT(m_frameView); |
+} |
+ |
+FrameViewAutoSizeInfo::~FrameViewAutoSizeInfo() |
+{ |
+ removeAutoSizeMode(); |
+} |
+ |
+void FrameViewAutoSizeInfo::configureAutoSizeMode(const IntSize& minSize, const IntSize& maxSize) |
+{ |
+ ASSERT(!minSize.isEmpty()); |
+ ASSERT(minSize.width() <= maxSize.width()); |
+ ASSERT(minSize.height() <= maxSize.height()); |
+ |
+ if (m_minAutoSize == minSize && m_maxAutoSize == maxSize) |
+ return; |
+ |
+ m_minAutoSize = minSize; |
+ m_maxAutoSize = maxSize; |
+ m_didRunAutosize = false; |
+ |
+ m_frameView->setLayoutSizeFixedToFrameSize(true); |
+ m_frameView->setNeedsLayout(); |
+ m_frameView->scheduleRelayout(); |
+} |
+ |
+void FrameViewAutoSizeInfo::removeAutoSizeMode() |
+{ |
+ m_frameView->setLayoutSizeFixedToFrameSize(false); |
+ m_frameView->setNeedsLayout(); |
+ m_frameView->scheduleRelayout(); |
+ |
+ // Since autosize mode forces the scrollbar mode, change them to being auto. |
+ m_frameView->setVerticalScrollbarLock(false); |
+ m_frameView->setHorizontalScrollbarLock(false); |
+ m_frameView->setScrollbarModes(ScrollbarAuto, ScrollbarAuto); |
+} |
+ |
+void FrameViewAutoSizeInfo::autoSizeIfNeeded() |
+{ |
+ if (m_inAutoSize) |
+ return; |
+ |
+ TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true); |
+ |
+ Document* document = m_frameView->frame().document(); |
+ if (!document || !document->isActive()) |
+ return; |
+ |
+ Element* documentElement = document->documentElement(); |
+ if (!documentElement) |
+ return; |
+ |
+ // If this is the first time we run autosize, start from small height and |
+ // allow it to grow. |
+ if (!m_didRunAutosize) |
+ m_frameView->resize(m_frameView->frameRect().width(), m_minAutoSize.height()); |
+ |
+ IntSize size = m_frameView->frameRect().size(); |
+ |
+ // Do the resizing twice. The first time is basically a rough calculation using the preferred width |
+ // which may result in a height change during the second iteration. |
+ for (int i = 0; i < 2; i++) { |
+ // Update various sizes including contentsSize, scrollHeight, etc. |
+ document->updateLayoutIgnorePendingStylesheets(); |
+ |
+ RenderView* renderView = document->renderView(); |
+ if (!renderView) |
+ return; |
+ |
+ int width = renderView->minPreferredLogicalWidth(); |
+ |
+ RenderBox* documentRenderBox = documentElement->renderBox(); |
+ if (!documentRenderBox) |
+ return; |
+ |
+ int height = documentRenderBox->scrollHeight(); |
+ IntSize newSize(width, height); |
+ |
+ // Check to see if a scrollbar is needed for a given dimension and |
+ // if so, increase the other dimension to account for the scrollbar. |
+ // Since the dimensions are only for the view rectangle, once a |
+ // dimension exceeds the maximum, there is no need to increase it further. |
+ if (newSize.width() > m_maxAutoSize.width()) { |
+ RefPtr<Scrollbar> localHorizontalScrollbar = m_frameView->horizontalScrollbar(); |
+ if (!localHorizontalScrollbar) |
+ localHorizontalScrollbar = m_frameView->createScrollbar(HorizontalScrollbar); |
+ if (!localHorizontalScrollbar->isOverlayScrollbar()) |
+ newSize.setHeight(newSize.height() + localHorizontalScrollbar->height()); |
+ |
+ // Don't bother checking for a vertical scrollbar because the width is at |
+ // already greater the maximum. |
+ } else if (newSize.height() > m_maxAutoSize.height()) { |
+ RefPtr<Scrollbar> localVerticalScrollbar = m_frameView->verticalScrollbar(); |
+ if (!localVerticalScrollbar) |
+ localVerticalScrollbar = m_frameView->createScrollbar(VerticalScrollbar); |
+ if (!localVerticalScrollbar->isOverlayScrollbar()) |
+ newSize.setWidth(newSize.width() + localVerticalScrollbar->width()); |
+ |
+ // Don't bother checking for a horizontal scrollbar because the height is |
+ // already greater the maximum. |
+ } |
+ |
+ // Ensure the size is at least the min bounds. |
+ newSize = newSize.expandedTo(m_minAutoSize); |
+ |
+ // Bound the dimensions by the max bounds and determine what scrollbars to show. |
+ ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff; |
+ if (newSize.width() > m_maxAutoSize.width()) { |
+ newSize.setWidth(m_maxAutoSize.width()); |
+ horizonalScrollbarMode = ScrollbarAlwaysOn; |
+ } |
+ ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff; |
+ if (newSize.height() > m_maxAutoSize.height()) { |
+ newSize.setHeight(m_maxAutoSize.height()); |
+ verticalScrollbarMode = ScrollbarAlwaysOn; |
+ } |
+ |
+ if (newSize == size) |
+ continue; |
+ |
+ // While loading only allow the size to increase (to avoid twitching during intermediate smaller states) |
+ // unless autoresize has just been turned on or the maximum size is smaller than the current size. |
+ if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width() |
+ && !m_frameView->frame().document()->loadEventFinished() && (newSize.height() < size.height() || newSize.width() < size.width())) |
+ break; |
+ |
+ m_frameView->resize(newSize.width(), newSize.height()); |
+ // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example, |
+ // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed). |
+ m_frameView->setVerticalScrollbarLock(false); |
+ m_frameView->setHorizontalScrollbarLock(false); |
+ m_frameView->setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true); |
+ } |
+ m_didRunAutosize = true; |
+} |
+ |
+} // namespace blink |