1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 2000 Simon Hausmann <hausmann@kde.org>
4 *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
5 * Copyright (C) 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "config.h"
25#include "RenderPartObject.h"
26
27#include "Frame.h"
28#include "FrameLoaderClient.h"
29#include "HTMLEmbedElement.h"
30#include "HTMLIFrameElement.h"
31#include "HTMLNames.h"
32#include "HTMLObjectElement.h"
33#include "HTMLParamElement.h"
34#include "MIMETypeRegistry.h"
35#include "Page.h"
36#include "RenderView.h"
37#include "RenderWidgetProtector.h"
38#include "Text.h"
39
40#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
41#include "HTMLVideoElement.h"
42#endif
43
44namespace WebCore {
45
46using namespace HTMLNames;
47
48RenderPartObject::RenderPartObject(Element* element)
49    : RenderPart(element)
50{
51}
52
53void RenderPartObject::layout()
54{
55    ASSERT(needsLayout());
56
57#ifdef FLATTEN_IFRAME
58    RenderPart::calcWidth();
59    RenderPart::calcHeight();
60    // Calculate the styled dimensions by subtracting the border and padding.
61    int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight();
62    int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom();
63    int styleWidth = width() - extraWidth;
64    int styleHeight = height() - extraHeight;
65    // Some IFrames have a width and/or height of 1 when they are meant to be
66    // hidden. If that is the case, do not try to expand.
67    if (node()->hasTagName(iframeTag) && widget() && widget()->isFrameView() &&
68            styleWidth > 1 && styleHeight > 1) {
69        HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(node());
70        bool scrolling = element->scrollingMode() != ScrollbarAlwaysOff;
71        bool widthIsFixed = style()->width().isFixed();
72        bool heightIsFixed = style()->height().isFixed();
73        // If an iframe has a fixed dimension and suppresses scrollbars, it
74        // will disrupt layout if we force it to expand. Plus on a desktop,
75        // the extra content is not accessible.
76        if (scrolling || !widthIsFixed || !heightIsFixed) {
77            FrameView* view = static_cast<FrameView*>(widget());
78            RenderView* root = view ? view->frame()->contentRenderer() : NULL;
79            if (root && style()->visibility() != HIDDEN) {
80                // Update the dimensions to get the correct minimum preferred
81                // width
82                updateWidgetPosition();
83
84                // Use the preferred width if it is larger and only if
85                // scrollbars are visible or the width style is not fixed.
86                if (scrolling || !widthIsFixed)
87                    setWidth(max(width(), root->minPrefWidth()) + extraWidth);
88
89                // Resize the view to recalc the height.
90                int h = height() - extraHeight;
91                int w = width() - extraWidth;
92                if (w > view->width())
93                    h = 0;
94                if (w != view->width() || h != view->height()) {
95                    view->resize(w, h);
96                }
97
98                // Layout the view.
99                do {
100                    view->layout();
101                } while (view->layoutPending() || root->needsLayout());
102
103                int contentHeight = view->contentsHeight();
104                int contentWidth = view->contentsWidth();
105                // Only change the width or height if scrollbars are visible or
106                // if the style is not a fixed value. Use the maximum value so
107                // that iframes never shrink.
108                if (scrolling || !heightIsFixed)
109                    setHeight(max(height(), contentHeight + extraHeight));
110                if (scrolling || !widthIsFixed)
111                    setWidth(max(width(), contentWidth + extraWidth));
112
113                // Update one last time
114                updateWidgetPosition();
115
116                // Layout one more time to ensure all objects have the correct
117                // height.
118                view->layout();
119
120#if !ASSERT_DISABLED
121                ASSERT(!view->layoutPending());
122                ASSERT(!root->needsLayout());
123                // Sanity check when assertions are enabled.
124                RenderObject* c = root->nextInPreOrder();
125                while (c) {
126                    ASSERT(!c->needsLayout());
127                    c = c->nextInPreOrder();
128                }
129#endif
130            }
131        }
132    }
133#else
134    calcWidth();
135    calcHeight();
136#endif
137
138    RenderPart::layout();
139
140    m_overflow.clear();
141    addShadowOverflow();
142
143    setNeedsLayout(false);
144}
145
146#ifdef FLATTEN_IFRAME
147void RenderPartObject::calcWidth() {
148    RenderPart::calcWidth();
149    if (!node()->hasTagName(iframeTag) || !widget() || !widget()->isFrameView())
150        return;
151    FrameView* view = static_cast<FrameView*>(widget());
152    RenderView* root = static_cast<RenderView*>(view->frame()->contentRenderer());
153    if (!root)
154        return;
155    // Do not expand if the scrollbars are suppressed and the width is fixed.
156    bool scrolling = static_cast<HTMLIFrameElement*>(node())->scrollingMode() != ScrollbarAlwaysOff;
157    if (!scrolling && style()->width().isFixed())
158        return;
159    // Update the dimensions to get the correct minimum preferred
160    // width
161    updateWidgetPosition();
162
163    int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight();
164    // Set the width
165    setWidth(max(width(), root->minPrefWidth()) + extraWidth);
166
167    // Update based on the new width
168    updateWidgetPosition();
169
170    // Layout to get the content width
171    do {
172        view->layout();
173    } while (view->layoutPending() || root->needsLayout());
174
175    setWidth(max(width(), view->contentsWidth() + extraWidth));
176
177    // Update one last time to ensure the dimensions.
178    updateWidgetPosition();
179}
180
181void RenderPartObject::calcHeight() {
182    RenderPart::calcHeight();
183    if (!node()->hasTagName(iframeTag) || !widget() || !widget()->isFrameView())
184        return;
185    FrameView* view = static_cast<FrameView*>(widget());
186    RenderView* root = static_cast<RenderView*>(view->frame()->contentRenderer());
187    if (!root)
188        return;
189    // Do not expand if the scrollbars are suppressed and the height is fixed.
190    bool scrolling = static_cast<HTMLIFrameElement*>(node())->scrollingMode() != ScrollbarAlwaysOff;
191    if (!scrolling && style()->height().isFixed())
192        return;
193    // Update the widget
194    updateWidgetPosition();
195
196    // Layout to get the content height
197    do {
198        view->layout();
199    } while (view->layoutPending() || root->needsLayout());
200
201    int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom();
202    setHeight(max(width(), view->contentsHeight() + extraHeight));
203
204    // Update one last time to ensure the dimensions.
205    updateWidgetPosition();
206}
207#endif
208
209void RenderPartObject::viewCleared()
210{
211    if (node() && widget() && widget()->isFrameView()) {
212        FrameView* view = static_cast<FrameView*>(widget());
213        int marginw = -1;
214        int marginh = -1;
215        if (node()->hasTagName(iframeTag)) {
216            HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node());
217            marginw = frame->getMarginWidth();
218            marginh = frame->getMarginHeight();
219        }
220        if (marginw != -1)
221            view->setMarginWidth(marginw);
222        if (marginh != -1)
223            view->setMarginHeight(marginh);
224    }
225}
226
227}
228