📄 render_frames.cpp
字号:
if (!root->minMaxKnown())
root->calcMinMaxWidth();
// if no scrolling for this frame, minwidth is set to zero
if (element()->scrollingMode() != QScrollView::AlwaysOff
|| (body && body->id()==ID_FRAMESET) )
m_minWidth = QMAX(root->minWidth(),root->docWidth());
m_maxWidth = QMAX(root->maxWidth(),m_minWidth);
}
}
setMinMaxKnown();
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << "RenderFrame::calcMinMaxWidth(" << this << "): min = " << m_minWidth << " max = " << m_maxWidth << endl;
#endif
}
void RenderFrame::layout()
{
// expand the frame by setting frame height = content height
#ifdef DEBUG_LAYOUT
kdDebug( 6040 ) << renderName() << "(RenderFrame)::layout() this=" << this << endl;
#endif
m_width = QMAX(m_width,m_minWidth);
QScrollView* sview = static_cast<QScrollView *>(m_widget);
if (sview && sview->inherits("KHTMLView")) {
KHTMLView* view = static_cast<KHTMLView *>(sview);
RenderCanvas* root = static_cast<RenderCanvas*>(view->part()?(view->part()->xmlDocImpl()?view->part()->xmlDocImpl()->renderer():0):0);
if (root) {
NodeImpl *body = 0;
if (view->part()->xmlDocImpl()->isHTMLDocument())
body = static_cast<HTMLDocumentImpl *>(view->part()->xmlDocImpl())->body();
if (root->needsLayout())
root->layout();
if (element()->scrollingMode() != QScrollView::AlwaysOff
|| (body && body->id()==ID_FRAMESET) )
m_height = QMAX(m_height,root->docHeight());
}
}
// kdDebug( 0 ) << "m_height =" << m_height << endl;
setNeedsLayout(false);
}
#endif
/****************************************************************************************/
RenderPartObject::RenderPartObject( DOM::HTMLElementImpl* element )
: RenderPart( element )
{
// init RenderObject attributes
setInline(true);
}
void RenderPartObject::updateWidget()
{
QString url;
QString serviceType;
QStringList paramNames;
QStringList paramValues;
KHTMLPart *part = m_view->part();
setNeedsLayoutAndMinMaxRecalc();
if (element()->id() == ID_OBJECT) {
HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element());
// Check for a child EMBED tag.
HTMLEmbedElementImpl *embed = 0;
for (NodeImpl *child = o->firstChild(); child; ) {
if (child->id() == ID_EMBED) {
embed = static_cast<HTMLEmbedElementImpl *>( child );
break;
} else if (child->id() == ID_OBJECT) {
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.
HTMLElementImpl *embedOrObject;
if (embed) {
embedOrObject = (HTMLElementImpl *)embed;
DOMString attribute = embedOrObject->getAttribute(ATTR_WIDTH);
if (!attribute.isEmpty()) {
o->setAttribute(ATTR_WIDTH, attribute);
}
attribute = embedOrObject->getAttribute(ATTR_HEIGHT);
if (!attribute.isEmpty()) {
o->setAttribute(ATTR_HEIGHT, attribute);
}
url = embed->url;
serviceType = embed->serviceType;
} else {
embedOrObject = (HTMLElementImpl *)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;
}
QDict<bool> uniqueParamNames(5, false);
// 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.
NodeImpl *child = o->firstChild();
while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
if (child->id() == ID_PARAM) {
HTMLParamElementImpl *p = static_cast<HTMLParamElementImpl *>( child );
QString name = p->name().lower();
if (url.isEmpty() && (name == "src" || name == "movie" || name == "code" || name == "url")) {
url = p->value();
}
if (serviceType.isEmpty() && name == "type") {
serviceType = p->value();
int pos = serviceType.find( ";" );
if (pos != -1) {
serviceType = serviceType.left(pos);
}
}
if (!embed) {
bool dummyValue = true;
uniqueParamNames.insert(p->name(), &dummyValue);
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]
if (!embed && serviceType.lower() == "application/x-java-applet") {
bool dummyValue = true;
uniqueParamNames.insert("codebase", &dummyValue); // 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.
NamedAttrMapImpl* attributes = embedOrObject->attributes();
if (attributes) {
for (unsigned long i = 0; i < attributes->length(); ++i) {
AttributeImpl* it = attributes->attributeItem(i);
QString name = o->getDocument()->attrName(it->id()).string();
if (embed || uniqueParamNames.find(name) == 0) {
paramNames.append(name);
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()) {
// 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 (o->classId.contains("D27CDB6E-AE6D-11cf-96B8-444553540000")) {
serviceType = "application/x-shockwave-flash";
} else if (o->classId.contains("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA")) {
serviceType = "audio/x-pn-realaudio-plugin";
} else if (o->classId.contains("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B")) {
serviceType = "video/quicktime";
} else if (o->classId.contains("166B1BCA-3F9C-11CF-8075-444553540000")) {
serviceType = "application/x-director";
} else if (o->classId.contains("6BF52A52-394A-11d3-B153-00C04F79FAA6")) {
serviceType = "application/x-mplayer2";
} else {
// We have a clsid, means this is activex (Niko)
serviceType = "application/x-activex-handler";
}
// TODO: add more plugins here
}
// If no URL and type, abort.
if (url.isEmpty() && serviceType.isEmpty()) {
#ifdef DEBUG_LAYOUT
kdDebug() << "RenderPartObject::close - empty url and serverType" << endl;
#endif
return;
}
// Avoid infinite recursion. If the plug-in's URL is the same as the part's URL, infinite frames may be created.
if (!url.isEmpty() && part->completeURL(url) == part->baseURL()) {
return;
}
#if !APPLE_CHANGES
params.append( QString::fromLatin1("__KHTML__CLASSID=\"%1\"").arg( o->classId ) );
params.append( QString::fromLatin1("__KHTML__CODEBASE=\"%1\"").arg( o->getAttribute(ATTR_CODEBASE).string() ) );
#endif
part->requestObject( this, url, serviceType, paramNames, paramValues );
} else if ( element()->id() == ID_EMBED ) {
HTMLEmbedElementImpl *o = static_cast<HTMLEmbedElementImpl *>(element());
url = o->url;
serviceType = o->serviceType;
if ( url.isEmpty() && serviceType.isEmpty() ) {
#ifdef DEBUG_LAYOUT
kdDebug() << "RenderPartObject::close - empty url and serverType" << endl;
#endif
return;
}
// Avoid infinite recursion. If the plug-in's URL is the same as the part's URL, infinite frames may be created.
if (!url.isEmpty() && part->completeURL(url) == part->baseURL()) {
return;
}
// add all attributes set on the embed object
NamedAttrMapImpl* a = o->attributes();
if (a) {
for (unsigned long i = 0; i < a->length(); ++i) {
AttributeImpl* it = a->attributeItem(i);
paramNames.append(o->getDocument()->attrName(it->id()).string());
paramValues.append(it->value().string());
}
}
part->requestObject( this, url, serviceType, paramNames, paramValues );
} else {
assert(element()->id() == ID_IFRAME);
HTMLIFrameElementImpl *o = static_cast<HTMLIFrameElementImpl *>(element());
url = o->url.string();
if (url.isEmpty()) {
url = "about:blank";
}
KHTMLView *v = static_cast<KHTMLView *>(m_view);
bool requestSucceeded = v->part()->requestFrame( this, url, o->name.string(), QStringList(), QStringList(), true );
if (requestSucceeded && url == "about:blank") {
KHTMLPart *newPart = v->part()->findFrame( o->name.string() );
if (newPart && newPart->xmlDocImpl()) {
newPart->xmlDocImpl()->setBaseURL( v->part()->baseURL().url() );
}
}
}
}
bool RenderPartObject::partLoadingErrorNotify( khtml::ChildFrame *childFrame, const KURL& url, const QString& serviceType )
{
KHTMLPart *part = static_cast<KHTMLView *>(m_view)->part();
//kdDebug() << "RenderPartObject::partLoadingErrorNotify serviceType=" << serviceType << endl;
// Check if we just tried with e.g. nsplugin
// and fallback to the activexhandler if there is a classid
// and a codebase, where we may download the ocx if it's missing
if( serviceType != "application/x-activex-handler" && element()->id()==ID_OBJECT ) {
// check for embed child object
HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element());
HTMLEmbedElementImpl *embed = 0;
NodeImpl *child = o->firstChild();
while ( child ) {
if ( child->id() == ID_EMBED )
embed = static_cast<HTMLEmbedElementImpl *>( child );
child = child->nextSibling();
}
if( embed && !o->classId.isEmpty() &&
!( static_cast<ElementImpl *>(o)->getAttribute(ATTR_CODEBASE).string() ).isEmpty() )
{
KParts::URLArgs args;
args.serviceType = "application/x-activex-handler";
if (part->requestObject( childFrame, url, args ))
return true; // success
}
}
// Dissociate ourselves from the current event loop (to prevent crashes
// due to the message box staying up)
QTimer::singleShot( 0, this, SLOT( slotPartLoadingErrorNotify() ) );
Tokenizer *tokenizer = static_cast<DOM::DocumentImpl *>(part->document().handle())->tokenizer();
if (tokenizer) tokenizer->setOnHold( true );
slotPartLoadingErrorNotify();
if (tokenizer) tokenizer->setOnHold( false );
return false;
}
void RenderPartObject::slotPartLoadingErrorNotify()
{
#if APPLE_CHANGES
// FIXME: What are we going to do for this case?
#else
// First we need to find out the servicetype - again - this code is too duplicated !
HTMLEmbedElementImpl *embed = 0;
QString serviceType;
if( element()->id()==ID_OBJECT ) {
// check for embed child object
HTMLObjectElementImpl *o = static_cast<HTMLObjectElementImpl *>(element());
serviceType = o->serviceType;
NodeImpl *child = o->firstChild();
while ( child ) {
if ( child->id() == ID_EMBED )
embed = static_cast<HTMLEmbedElementImpl *>( child );
child = child->nextSibling();
}
} else if( element()->id()==ID_EMBED ) {
embed = static_cast<HTMLEmbedElementImpl *>(element());
}
if ( embed )
serviceType = embed->serviceType;
KHTMLPart *part = static_cast<KHTMLView *>(m_view)->part();
KParts::BrowserExtension *ext = part->browserExtension();
if( embed && !embed->pluginPage.isEmpty() && ext ) {
// Prepare the mimetype to show in the question (comment if available, name as fallback)
QString mimeName = serviceType;
KMimeType::Ptr mime = KMimeType::mimeType(serviceType);
if ( mime->name() != KMimeType::defaultMimeType() )
mimeName = mime->comment();
// Prepare the URL to show in the question (host only if http, to make it short)
KURL pluginPageURL( embed->pluginPage );
QString shortURL = pluginPageURL.protocol() == "http" ? pluginPageURL.host() : pluginPageURL.prettyURL();
int res = KMessageBox::questionYesNo( m_view,
i18n("No plugin found for '%1'.\nDo you want to download one from %2?").arg(mimeName).arg(shortURL),
i18n("Missing plugin"), QString::null, QString::null, QString("plugin-")+serviceType);
if ( res == KMessageBox::Yes )
{
// Display vendor download page
ext->createNewWindow( pluginPageURL );
}
}
#endif // APPLE_CHANGES
}
void RenderPartObject::layout( )
{
KHTMLAssert( needsLayout() );
KHTMLAssert( minMaxKnown() );
#if !APPLE_CHANGES
int m_oldwidth = m_width;
int m_oldheight = m_height;
#endif
calcWidth();
calcHeight();
RenderPart::layout();
setNeedsLayout(false);
}
void RenderPartObject::slotViewCleared()
{
if(element() && m_widget && m_widget->inherits("QScrollView") ) {
#ifdef DEBUG_LAYOUT
kdDebug(6031) << "iframe is a scrollview!" << endl;
#endif
QScrollView *view = static_cast<QScrollView *>(m_widget);
int frameStyle = QFrame::NoFrame;
QScrollView::ScrollBarMode scroll = QScrollView::Auto;
int marginw = -1;
int marginh = -1;
if ( element()->id() == ID_IFRAME) {
HTMLIFrameElementImpl *frame = static_cast<HTMLIFrameElementImpl *>(element());
if(frame->frameBorder)
frameStyle = QFrame::Box;
scroll = frame->scrolling;
marginw = frame->marginWidth;
marginh = frame->marginHeight;
}
view->setFrameStyle(frameStyle);
#if !APPLE_CHANGES
view->setVScrollBarMode(scroll);
view->setHScrollBarMode(scroll);
#endif
if(view->inherits("KHTMLView")) {
#ifdef DEBUG_LAYOUT
kdDebug(6031) << "frame is a KHTMLview!" << endl;
#endif
KHTMLView *htmlView = static_cast<KHTMLView *>(view);
htmlView->setIgnoreWheelEvents( element()->id() == ID_IFRAME );
if(marginw != -1) htmlView->setMarginWidth(marginw);
if(marginh != -1) htmlView->setMarginHeight(marginh);
}
}
}
#if APPLE_CHANGES
// FIXME: This should not be necessary. Remove this once WebKit knows to properly schedule
// layouts using WebCore when objects resize.
void RenderPart::updateWidgetPositions()
{
if (!m_widget)
return;
int x, y, width, height;
absolutePosition(x,y);
x += borderLeft() + paddingLeft();
y += borderTop() + paddingTop();
width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight();
height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom();
QRect newBounds(x,y,width,height);
if (newBounds != m_widget->frameGeometry()) {
// The widget changed positions. Update the frame geometry.
RenderArena *arena = ref();
element()->ref();
m_widget->setFrameGeometry(newBounds);
element()->deref();
deref(arena);
QScrollView *view = static_cast<QScrollView *>(m_widget);
#if !NOKIA_CHANGES
if (view && view->inherits("KHTMLView"))
static_cast<KHTMLView*>(view)->layout();
#endif
}
}
#endif
#include "render_frames.moc"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -