diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
commit | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch) | |
tree | 11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/rendering/RenderPartObject.cpp | |
parent | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff) | |
download | external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/rendering/RenderPartObject.cpp')
-rw-r--r-- | WebCore/rendering/RenderPartObject.cpp | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/WebCore/rendering/RenderPartObject.cpp b/WebCore/rendering/RenderPartObject.cpp new file mode 100644 index 0000000..75ecdec --- /dev/null +++ b/WebCore/rendering/RenderPartObject.cpp @@ -0,0 +1,335 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderPartObject.h" + +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HTMLEmbedElement.h" +#include "HTMLIFrameElement.h" +#include "HTMLNames.h" +#include "HTMLObjectElement.h" +#include "HTMLParamElement.h" +#include "MIMETypeRegistry.h" +#include "Page.h" +#include "Text.h" + +#ifdef FLATTEN_IFRAME +#include "RenderView.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +RenderPartObject::RenderPartObject(HTMLFrameOwnerElement* element) + : RenderPart(element) +{ + // init RenderObject attributes + setInline(true); + m_hasFallbackContent = false; +} + +RenderPartObject::~RenderPartObject() +{ + if (m_view) + m_view->removeWidgetToUpdate(this); +} + +static bool isURLAllowed(Document* doc, const String& url) +{ + if (doc->frame()->page()->frameCount() >= 200) + return false; + + // We allow one level of self-reference because some sites depend on that. + // But we don't allow more than one. + KURL completeURL = doc->completeURL(url); + bool foundSelfReference = false; + for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) { + if (equalIgnoringRef(frame->loader()->url(), completeURL)) { + if (foundSelfReference) + return false; + foundSelfReference = true; + } + } + return true; +} + +static inline void mapClassIdToServiceType(const String& classId, String& serviceType) +{ + // It is ActiveX, but the nsplugin system handling + // should also work, that's why we don't override the + // serviceType with application/x-activex-handler + // but let the KTrader in khtmlpart::createPart() detect + // the user's preference: launch with activex viewer or + // with nspluginviewer (Niko) + if (classId.contains("D27CDB6E-AE6D-11cf-96B8-444553540000")) + serviceType = "application/x-shockwave-flash"; + else if (classId.contains("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) + serviceType = "audio/x-pn-realaudio-plugin"; + else if (classId.contains("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) + serviceType = "video/quicktime"; + else if (classId.contains("166B1BCA-3F9C-11CF-8075-444553540000")) + serviceType = "application/x-director"; + else if (classId.contains("6BF52A52-394A-11d3-B153-00C04F79FAA6")) + serviceType = "application/x-mplayer2"; + else if (!classId.isEmpty()) { + // We have a clsid, means this is Active X (Niko) + serviceType = "application/x-activex-handler"; + } +} + +void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) +{ + String url; + String serviceType; + Vector<String> paramNames; + Vector<String> paramValues; + Frame* frame = m_view->frame(); + + if (element()->hasTagName(objectTag)) { + + HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element()); + + o->setNeedWidgetUpdate(false); + if (!o->isFinishedParsingChildren()) + return; + // Check for a child EMBED tag. + HTMLEmbedElement* embed = 0; + for (Node* child = o->firstChild(); child;) { + if (child->hasTagName(embedTag)) { + embed = static_cast<HTMLEmbedElement*>(child); + break; + } else if (child->hasTagName(objectTag)) + child = child->nextSibling(); // Don't descend into nested OBJECT tags + else + child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags) + } + + // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT. + HTMLElement *embedOrObject; + if (embed) { + embedOrObject = (HTMLElement *)embed; + url = embed->url(); + serviceType = embed->serviceType(); + } else + embedOrObject = (HTMLElement *)o; + + // If there was no URL or type defined in EMBED, try the OBJECT tag. + if (url.isEmpty()) + url = o->url(); + if (serviceType.isEmpty()) + serviceType = o->serviceType(); + + HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; + + // Scan the PARAM children. + // Get the URL and type from the params if we don't already have them. + // Get the attributes from the params if there is no EMBED tag. + Node *child = o->firstChild(); + while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) { + if (child->hasTagName(paramTag)) { + HTMLParamElement* p = static_cast<HTMLParamElement*>(child); + String name = p->name(); + if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) + url = p->value(); + if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { + serviceType = p->value(); + int pos = serviceType.find(";"); + if (pos != -1) + serviceType = serviceType.left(pos); + } + if (!embed && !name.isEmpty()) { + uniqueParamNames.add(name.impl()); + paramNames.append(p->name()); + paramValues.append(p->value()); + } + } + child = child->nextSibling(); + } + + // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag + // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is + // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means + // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM, + // else our Java plugin will misinterpret it. [4004531] + String codebase; + if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) { + codebase = "codebase"; + uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already + } + + // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values. + NamedAttrMap* attributes = embedOrObject->attributes(); + if (attributes) { + for (unsigned i = 0; i < attributes->length(); ++i) { + Attribute* it = attributes->attributeItem(i); + const AtomicString& name = it->name().localName(); + if (embed || !uniqueParamNames.contains(name.impl())) { + paramNames.append(name.string()); + paramValues.append(it->value().string()); + } + } + } + + // If we still don't have a type, try to map from a specific CLASSID to a type. + if (serviceType.isEmpty() && !o->classId().isEmpty()) + mapClassIdToServiceType(o->classId(), serviceType); + + if (!isURLAllowed(document(), url)) + return; + + // Find out if we support fallback content. + m_hasFallbackContent = false; + for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) { + if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param> + (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace())) + m_hasFallbackContent = true; + } + + if (onlyCreateNonNetscapePlugins) { + KURL completedURL; + if (!url.isEmpty()) + completedURL = frame->loader()->completeURL(url); + + if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) + return; + } + + bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues); + if (!success && m_hasFallbackContent) + o->renderFallbackContent(); + } else if (element()->hasTagName(embedTag)) { + HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element()); + o->setNeedWidgetUpdate(false); + url = o->url(); + serviceType = o->serviceType(); + + if (url.isEmpty() && serviceType.isEmpty()) + return; + if (!isURLAllowed(document(), url)) + return; + + // add all attributes set on the embed object + NamedAttrMap* a = o->attributes(); + if (a) { + for (unsigned i = 0; i < a->length(); ++i) { + Attribute* it = a->attributeItem(i); + paramNames.append(it->name().localName().string()); + paramValues.append(it->value().string()); + } + } + + if (onlyCreateNonNetscapePlugins) { + KURL completedURL; + if (!url.isEmpty()) + completedURL = frame->loader()->completeURL(url); + + if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) + return; + + } + + frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues); + } +} + +void RenderPartObject::layout() +{ + ASSERT(needsLayout()); + + calcWidth(); + calcHeight(); + +#ifdef FLATTEN_IFRAME + // Some IFrames have a width and/or height of 1 when they are meant to be + // hidden. If that is the case, don't try to expand. + if (m_widget && m_widget->isFrameView() && + m_width > 1 && m_height > 1) { + FrameView* view = static_cast<FrameView*>(m_widget); + RenderView* root = NULL; + if (view->frame() && view->frame()->document() && + view->frame()->document()->renderer() && view->frame()->document()->renderer()->isRenderView()) + root = static_cast<RenderView*>(view->frame()->document()->renderer()); + if (root) { + // Update the dimensions to get the correct minimum preferred width + updateWidgetPosition(); + + // Use the preferred width if it is larger. + m_width = max(m_width, root->minPrefWidth()); + int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight(); + int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom(); + // Resize the view to recalc the height. + int height = m_height - extraHeight; + int width = m_width - extraWidth; + if (width > view->width()) + height = 0; + if (width != view->width() || height != view->height()) { + view->resize(width, height); + root->setNeedsLayout(true, false); + } + // Layout the view. + if (view->needsLayout()) + view->layout(); + int contentHeight = view->contentsHeight(); + int contentWidth = view->contentsWidth(); + // Do not shrink iframes with specified sizes + if (contentHeight > m_height || style()->height().isAuto()) + m_height = contentHeight; + m_width = std::min(contentWidth, 800); + } + } +#endif + adjustOverflowForBoxShadow(); + + RenderPart::layout(); + + if (!m_widget && m_view) + m_view->addWidgetToUpdate(this); + + setNeedsLayout(false); +} + +void RenderPartObject::viewCleared() +{ + if (element() && m_widget && m_widget->isFrameView()) { + FrameView* view = static_cast<FrameView*>(m_widget); + int marginw = -1; + int marginh = -1; + if (element()->hasTagName(iframeTag)) { + HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(element()); + marginw = frame->getMarginWidth(); + marginh = frame->getMarginHeight(); + } + if (marginw != -1) + view->setMarginWidth(marginw); + if (marginh != -1) + view->setMarginHeight(marginh); + } +} + +} |