Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / frame / FrameViewAutoSizeInfo.cpp
1 // Copyright 2014 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 "config.h"
6 #include "core/frame/FrameViewAutoSizeInfo.h"
7
8 #include "core/frame/FrameView.h"
9 #include "core/frame/LocalFrame.h"
10 #include "core/rendering/RenderBox.h"
11 #include "core/rendering/RenderView.h"
12
13 namespace blink {
14
15 FrameViewAutoSizeInfo::FrameViewAutoSizeInfo(FrameView* view)
16     : m_frameView(view)
17     , m_inAutoSize(false)
18     , m_didRunAutosize(false)
19 {
20     ASSERT(m_frameView);
21 }
22
23 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(FrameViewAutoSizeInfo);
24
25 void FrameViewAutoSizeInfo::trace(Visitor* visitor)
26 {
27     visitor->trace(m_frameView);
28 }
29
30 void FrameViewAutoSizeInfo::configureAutoSizeMode(const IntSize& minSize, const IntSize& maxSize)
31 {
32     ASSERT(!minSize.isEmpty());
33     ASSERT(minSize.width() <= maxSize.width());
34     ASSERT(minSize.height() <= maxSize.height());
35
36     if (m_minAutoSize == minSize && m_maxAutoSize == maxSize)
37         return;
38
39     m_minAutoSize = minSize;
40     m_maxAutoSize = maxSize;
41     m_didRunAutosize = false;
42 }
43
44 void FrameViewAutoSizeInfo::autoSizeIfNeeded()
45 {
46     if (m_inAutoSize)
47         return;
48
49     TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true);
50
51     Document* document = m_frameView->frame().document();
52     if (!document || !document->isActive())
53         return;
54
55     Element* documentElement = document->documentElement();
56     if (!documentElement)
57         return;
58
59     // If this is the first time we run autosize, start from small height and
60     // allow it to grow.
61     if (!m_didRunAutosize)
62         m_frameView->resize(m_frameView->frameRect().width(), m_minAutoSize.height());
63
64     IntSize size = m_frameView->frameRect().size();
65
66     // Do the resizing twice. The first time is basically a rough calculation using the preferred width
67     // which may result in a height change during the second iteration.
68     for (int i = 0; i < 2; i++) {
69         // Update various sizes including contentsSize, scrollHeight, etc.
70         document->updateLayoutIgnorePendingStylesheets();
71
72         RenderView* renderView = document->renderView();
73         if (!renderView)
74             return;
75
76         int width = renderView->minPreferredLogicalWidth();
77
78         RenderBox* documentRenderBox = documentElement->renderBox();
79         if (!documentRenderBox)
80             return;
81
82         int height = documentRenderBox->scrollHeight();
83         IntSize newSize(width, height);
84
85         // Check to see if a scrollbar is needed for a given dimension and
86         // if so, increase the other dimension to account for the scrollbar.
87         // Since the dimensions are only for the view rectangle, once a
88         // dimension exceeds the maximum, there is no need to increase it further.
89         if (newSize.width() > m_maxAutoSize.width()) {
90             RefPtrWillBeRawPtr<Scrollbar> localHorizontalScrollbar = m_frameView->horizontalScrollbar();
91             if (!localHorizontalScrollbar)
92                 localHorizontalScrollbar = m_frameView->createScrollbar(HorizontalScrollbar);
93             if (!localHorizontalScrollbar->isOverlayScrollbar())
94                 newSize.setHeight(newSize.height() + localHorizontalScrollbar->height());
95
96             // Don't bother checking for a vertical scrollbar because the width is at
97             // already greater the maximum.
98         } else if (newSize.height() > m_maxAutoSize.height()) {
99             RefPtrWillBeRawPtr<Scrollbar> localVerticalScrollbar = m_frameView->verticalScrollbar();
100             if (!localVerticalScrollbar)
101                 localVerticalScrollbar = m_frameView->createScrollbar(VerticalScrollbar);
102             if (!localVerticalScrollbar->isOverlayScrollbar())
103                 newSize.setWidth(newSize.width() + localVerticalScrollbar->width());
104
105             // Don't bother checking for a horizontal scrollbar because the height is
106             // already greater the maximum.
107         }
108
109         // Ensure the size is at least the min bounds.
110         newSize = newSize.expandedTo(m_minAutoSize);
111
112         // Bound the dimensions by the max bounds and determine what scrollbars to show.
113         ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff;
114         if (newSize.width() > m_maxAutoSize.width()) {
115             newSize.setWidth(m_maxAutoSize.width());
116             horizonalScrollbarMode = ScrollbarAlwaysOn;
117         }
118         ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff;
119         if (newSize.height() > m_maxAutoSize.height()) {
120             newSize.setHeight(m_maxAutoSize.height());
121             verticalScrollbarMode = ScrollbarAlwaysOn;
122         }
123
124         if (newSize == size)
125             continue;
126
127         // While loading only allow the size to increase (to avoid twitching during intermediate smaller states)
128         // unless autoresize has just been turned on or the maximum size is smaller than the current size.
129         if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width()
130             && !m_frameView->frame().document()->loadEventFinished() && (newSize.height() < size.height() || newSize.width() < size.width()))
131             break;
132
133         m_frameView->resize(newSize.width(), newSize.height());
134         // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example,
135         // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed).
136         m_frameView->setVerticalScrollbarLock(false);
137         m_frameView->setHorizontalScrollbarLock(false);
138         m_frameView->setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true);
139     }
140     m_didRunAutosize = true;
141 }
142
143 } // namespace blink