2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2000 Simon Hausmann (hausmann@kde.org)
7 * (C) 2001 Dirk Mueller (mueller@kde.org)
8 * Copyright (C) 2004 Apple Computer, Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
25 // -------------------------------------------------------------------------
27 #include "html/html_baseimpl.h"
28 #include "html/html_documentimpl.h"
30 #include "khtmlview.h"
31 #include "khtml_part.h"
33 #include "rendering/render_frames.h"
34 #include "css/cssstyleselector.h"
35 #include "css/css_stylesheetimpl.h"
36 #include "css/cssproperties.h"
37 #include "css/cssvalues.h"
38 #include "css/csshelper.h"
39 #include "misc/loader.h"
40 #include "misc/htmlhashes.h"
41 #include "dom/dom_string.h"
42 #include "dom/dom_doc.h"
43 #include "xml/dom2_eventsimpl.h"
49 using namespace khtml;
51 HTMLBodyElementImpl::HTMLBodyElementImpl(DocumentPtr *doc)
52 : HTMLElementImpl(doc), m_linkDecl(0)
56 HTMLBodyElementImpl::~HTMLBodyElementImpl()
59 m_linkDecl->setNode(0);
60 m_linkDecl->setParent(0);
65 NodeImpl::Id HTMLBodyElementImpl::id() const
70 void HTMLBodyElementImpl::createLinkDecl()
72 m_linkDecl = new CSSMutableStyleDeclarationImpl;
74 m_linkDecl->setParent(getDocument()->elementSheet());
75 m_linkDecl->setNode(this);
76 m_linkDecl->setStrictParsing(!getDocument()->inCompatMode());
79 bool HTMLBodyElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
86 case ATTR_MARGINWIDTH:
88 case ATTR_MARGINHEIGHT:
90 case ATTR_BGPROPERTIES:
97 return HTMLElementImpl::mapToEntry(attr, result);
100 void HTMLBodyElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
104 case ATTR_BACKGROUND:
106 QString url = khtml::parseURL( attr->value() ).string();
108 addCSSImageProperty(attr, CSS_PROP_BACKGROUND_IMAGE, getDocument()->completeURL(url));
111 case ATTR_MARGINWIDTH:
112 addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value() );
114 case ATTR_LEFTMARGIN:
115 addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value() );
117 case ATTR_MARGINHEIGHT:
118 addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
121 addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
124 addHTMLColor(attr, CSS_PROP_BACKGROUND_COLOR, attr->value());
127 addHTMLColor(attr, CSS_PROP_COLOR, attr->value());
129 case ATTR_BGPROPERTIES:
130 if ( strcasecmp( attr->value(), "fixed" ) == 0)
131 addCSSProperty(attr, CSS_PROP_BACKGROUND_ATTACHMENT, CSS_VAL_FIXED);
137 if (attr->isNull()) {
138 if (attr->id() == ATTR_LINK)
139 getDocument()->resetLinkColor();
140 else if (attr->id() == ATTR_VLINK)
141 getDocument()->resetVisitedLinkColor();
143 getDocument()->resetActiveLinkColor();
148 m_linkDecl->setProperty(CSS_PROP_COLOR, attr->value(), false, false);
149 CSSValueImpl* val = m_linkDecl->getPropertyCSSValue(CSS_PROP_COLOR);
152 if (val->isPrimitiveValue()) {
153 QColor col = getDocument()->styleSelector()->getColorFromPrimitiveValue(static_cast<CSSPrimitiveValueImpl*>(val));
154 if (attr->id() == ATTR_LINK)
155 getDocument()->setLinkColor(col);
156 else if (attr->id() == ATTR_VLINK)
157 getDocument()->setVisitedLinkColor(col);
159 getDocument()->setActiveLinkColor(col);
166 getDocument()->recalcStyle(Force);
170 getDocument()->setHTMLWindowEventListener(EventImpl::LOAD_EVENT,
171 getDocument()->createHTMLEventListener(attr->value().string(), this));
174 getDocument()->setHTMLWindowEventListener(EventImpl::UNLOAD_EVENT,
175 getDocument()->createHTMLEventListener(attr->value().string(), this));
178 getDocument()->setHTMLWindowEventListener(EventImpl::BLUR_EVENT,
179 getDocument()->createHTMLEventListener(attr->value().string(), this));
182 getDocument()->setHTMLWindowEventListener(EventImpl::FOCUS_EVENT,
183 getDocument()->createHTMLEventListener(attr->value().string(), this));
186 getDocument()->setHTMLWindowEventListener(EventImpl::RESIZE_EVENT,
187 getDocument()->createHTMLEventListener(attr->value().string(), this));
190 getDocument()->setHTMLWindowEventListener(EventImpl::SCROLL_EVENT,
191 getDocument()->createHTMLEventListener(attr->value().string(), this));
196 HTMLElementImpl::parseHTMLAttribute(attr);
200 void HTMLBodyElementImpl::insertedIntoDocument()
202 HTMLElementImpl::insertedIntoDocument();
204 // FIXME: perhaps this code should be in attach() instead of here
206 DocumentImpl *d = getDocument();
207 KHTMLView *w = d ? d->view() : 0;
208 if (w && w->marginWidth() != -1) {
210 s.sprintf( "%d", w->marginWidth() );
211 setAttribute(ATTR_MARGINWIDTH, s);
213 if (w && w->marginHeight() != -1) {
215 s.sprintf( "%d", w->marginHeight() );
216 setAttribute(ATTR_MARGINHEIGHT, s);
220 w->scheduleRelayout();
223 bool HTMLBodyElementImpl::isURLAttribute(AttributeImpl *attr) const
225 return attr->id() == ATTR_BACKGROUND;
228 // -------------------------------------------------------------------------
230 HTMLFrameElementImpl::HTMLFrameElementImpl(DocumentPtr *doc)
231 : HTMLElementImpl(doc)
234 frameBorderSet = false;
237 scrolling = QScrollView::Auto;
241 HTMLFrameElementImpl::~HTMLFrameElementImpl()
245 NodeImpl::Id HTMLFrameElementImpl::id() const
250 bool HTMLFrameElementImpl::isURLAllowed(const AtomicString &URLString) const
252 if (URLString.isEmpty()) {
256 DocumentImpl *d = getDocument();
257 KHTMLView *w = d ? d->view() : 0;
263 KURL newURL(getDocument()->completeURL(URLString.string()));
264 newURL.setRef(QString::null);
266 // Don't allow more than 1000 total frames in a set. This seems
267 // like a reasonable upper bound, and otherwise mutually recursive
268 // frameset pages can quickly bring the program to its knees with
269 // exponential growth in the number of frames.
271 // FIXME: This limit could be higher, but WebKit has some
272 // algorithms that happen while loading which appear to be N^2 or
273 // worse in the number of frames
274 if (w->part()->topLevelFrameCount() >= 200) {
278 // Prohibit non-file URLs if we are asked to.
279 if (w->part()->onlyLocalReferences() && newURL.protocol().lower() != "file") {
283 // We allow one level of self-reference because some sites depend on that.
284 // But we don't allow more than one.
285 bool foundSelfReference = false;
286 for (KHTMLPart *part = w->part(); part; part = part->parentPart()) {
287 KURL partURL = part->url();
288 partURL.setRef(QString::null);
289 if (partURL == newURL) {
290 if (foundSelfReference) {
293 foundSelfReference = true;
300 void HTMLFrameElementImpl::updateForNewURL()
306 // Handle the common case where we decided not to make a frame the first time.
307 // Detach and the let attach() decide again whether to make the frame for this URL.
314 if (!isURLAllowed(url)) {
321 void HTMLFrameElementImpl::openURL()
323 DocumentImpl *d = getDocument();
324 KHTMLView *w = d ? d->view() : 0;
329 AtomicString relativeURL = url;
330 if (relativeURL.isEmpty()) {
331 relativeURL = "about:blank";
334 // Load the frame contents.
335 KHTMLPart *part = w->part();
336 KHTMLPart *framePart = part->findFrame(name.string());
338 framePart->openURL(getDocument()->completeURL(relativeURL.string()));
340 part->requestFrame(static_cast<RenderFrame *>(m_render), relativeURL.string(), name.string());
345 void HTMLFrameElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
350 setLocation(khtml::parseURL(attr->value()));
353 // Important to call through to base for ATTR_ID so the hasID bit gets set.
354 HTMLElementImpl::parseHTMLAttribute(attr);
357 name = attr->value();
358 // FIXME: If we are already attached, this doesn't actually change the frame's name.
359 // FIXME: If we are already attached, this doesn't check for frame name
360 // conflicts and generate a unique frame name.
362 case ATTR_FRAMEBORDER:
363 frameBorder = attr->value().toInt();
364 frameBorderSet = !attr->isNull();
365 // FIXME: If we are already attached, this has no effect.
367 case ATTR_MARGINWIDTH:
368 marginWidth = attr->value().toInt();
369 // FIXME: If we are already attached, this has no effect.
371 case ATTR_MARGINHEIGHT:
372 marginHeight = attr->value().toInt();
373 // FIXME: If we are already attached, this has no effect.
377 // FIXME: If we are already attached, this has no effect.
380 kdDebug( 6031 ) << "set scroll mode" << endl;
381 // Auto and yes both simply mean "allow scrolling." No means
382 // "don't allow scrolling."
383 if( strcasecmp( attr->value(), "auto" ) == 0 ||
384 strcasecmp( attr->value(), "yes" ) == 0 )
385 scrolling = QScrollView::Auto;
386 else if( strcasecmp( attr->value(), "no" ) == 0 )
387 scrolling = QScrollView::AlwaysOff;
388 // FIXME: If we are already attached, this has no effect.
391 setHTMLEventListener(EventImpl::LOAD_EVENT,
392 getDocument()->createHTMLEventListener(attr->value().string(), this));
395 setHTMLEventListener(EventImpl::UNLOAD_EVENT,
396 getDocument()->createHTMLEventListener(attr->value().string(), this));
399 HTMLElementImpl::parseHTMLAttribute(attr);
403 bool HTMLFrameElementImpl::rendererIsNeeded(RenderStyle *style)
405 // Ignore display: none.
406 return isURLAllowed(url);
409 RenderObject *HTMLFrameElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
411 return new (arena) RenderFrame(this);
414 void HTMLFrameElementImpl::attach()
416 // we should first look up via id, then via name.
417 // this shortterm hack fixes the ugly case. ### rewrite needed for next release
418 name = getAttribute(ATTR_NAME);
420 name = getAttribute(ATTR_ID);
422 // inherit default settings from parent frameset
423 HTMLElementImpl* node = static_cast<HTMLElementImpl*>(parentNode());
426 if(node->id() == ID_FRAMESET)
428 HTMLFrameSetElementImpl* frameset = static_cast<HTMLFrameSetElementImpl*>(node);
429 if(!frameBorderSet) frameBorder = frameset->frameBorder();
430 if(!noresize) noresize = frameset->noResize();
433 node = static_cast<HTMLElementImpl*>(node->parentNode());
436 HTMLElementImpl::attach();
441 KHTMLPart *part = getDocument()->part();
446 part->incrementFrameCount();
448 AtomicString relativeURL = url;
449 if (relativeURL.isEmpty()) {
450 relativeURL = "about:blank";
453 // we need a unique name for every frame in the frameset. Hope that's unique enough.
454 if (name.isEmpty() || part->frameExists( name.string() ) )
455 name = AtomicString(part->requestFrameName());
457 // load the frame contents
458 part->requestFrame( static_cast<RenderFrame*>(m_render), relativeURL.string(), name.string() );
461 void HTMLFrameElementImpl::detach()
463 KHTMLPart *part = getDocument()->part();
465 if (m_render && part) {
466 part->decrementFrameCount();
467 KHTMLPart *framePart = part->findFrame( name.string() );
469 framePart->frameDetached();
472 HTMLElementImpl::detach();
475 void HTMLFrameElementImpl::setLocation( const DOMString& str )
477 if (url == str) return;
478 url = AtomicString(str);
482 bool HTMLFrameElementImpl::isFocusable() const
487 void HTMLFrameElementImpl::setFocus(bool received)
489 HTMLElementImpl::setFocus(received);
490 khtml::RenderFrame *renderFrame = static_cast<khtml::RenderFrame *>(m_render);
491 if (!renderFrame || !renderFrame->widget())
494 renderFrame->widget()->setFocus();
496 renderFrame->widget()->clearFocus();
499 KHTMLPart* HTMLFrameElementImpl::contentPart() const
501 // Start with the part that contains this element, our ownerDocument.
502 KHTMLPart* ownerDocumentPart = getDocument()->part();
503 if (!ownerDocumentPart) {
507 // Find the part for the subframe that this element represents.
508 return ownerDocumentPart->findFrame(name.string());
511 DocumentImpl* HTMLFrameElementImpl::contentDocument() const
513 KHTMLPart* part = contentPart();
518 // Return the document for that part, which is our contentDocument.
519 return part->xmlDocImpl();
522 bool HTMLFrameElementImpl::isURLAttribute(AttributeImpl *attr) const
524 return attr->id() == ATTR_SRC;
527 // -------------------------------------------------------------------------
529 HTMLFrameSetElementImpl::HTMLFrameSetElementImpl(DocumentPtr *doc)
530 : HTMLElementImpl(doc)
532 // default value for rows and cols...
539 frameBorderSet = false;
546 HTMLFrameSetElementImpl::~HTMLFrameSetElementImpl()
554 NodeImpl::Id HTMLFrameSetElementImpl::id() const
559 void HTMLFrameSetElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
564 if (attr->isNull()) break;
565 if (m_rows) delete [] m_rows;
566 m_rows = attr->value().toLengthArray(m_totalRows);
570 if (attr->isNull()) break;
572 m_cols = attr->value().toLengthArray(m_totalCols);
575 case ATTR_FRAMEBORDER:
576 // false or "no" or "0"..
577 if ( attr->value().toInt() == 0 ) {
581 frameBorderSet = true;
587 m_border = attr->value().toInt();
592 setHTMLEventListener(EventImpl::LOAD_EVENT,
593 getDocument()->createHTMLEventListener(attr->value().string(), this));
596 setHTMLEventListener(EventImpl::UNLOAD_EVENT,
597 getDocument()->createHTMLEventListener(attr->value().string(), this));
600 HTMLElementImpl::parseHTMLAttribute(attr);
604 bool HTMLFrameSetElementImpl::rendererIsNeeded(RenderStyle *style)
606 // Ignore display: none but do pay attention if a stylesheet has caused us to delay our loading.
607 return style->isStyleAvailable();
610 RenderObject *HTMLFrameSetElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
612 return new (arena) RenderFrameSet(this);
615 void HTMLFrameSetElementImpl::attach()
617 // inherit default settings from parent frameset
618 HTMLElementImpl* node = static_cast<HTMLElementImpl*>(parentNode());
621 if(node->id() == ID_FRAMESET)
623 HTMLFrameSetElementImpl* frameset = static_cast<HTMLFrameSetElementImpl*>(node);
624 if(!frameBorderSet) frameborder = frameset->frameBorder();
625 if(!noresize) noresize = frameset->noResize();
628 node = static_cast<HTMLElementImpl*>(node->parentNode());
631 HTMLElementImpl::attach();
634 void HTMLFrameSetElementImpl::defaultEventHandler(EventImpl *evt)
636 if (evt->isMouseEvent() && !noresize && m_render) {
637 static_cast<khtml::RenderFrameSet *>(m_render)->userResize(static_cast<MouseEventImpl*>(evt));
638 evt->setDefaultHandled();
641 HTMLElementImpl::defaultEventHandler(evt);
644 void HTMLFrameSetElementImpl::detach()
647 // ### send the event when we actually get removed from the doc instead of here
648 dispatchHTMLEvent(EventImpl::UNLOAD_EVENT,false,false);
650 HTMLElementImpl::detach();
653 void HTMLFrameSetElementImpl::recalcStyle( StyleChange ch )
655 if (changed() && m_render) {
656 m_render->setNeedsLayout(true);
657 // m_render->layout();
660 HTMLElementImpl::recalcStyle( ch );
663 // -------------------------------------------------------------------------
665 HTMLHeadElementImpl::HTMLHeadElementImpl(DocumentPtr *doc)
666 : HTMLElementImpl(doc)
670 HTMLHeadElementImpl::~HTMLHeadElementImpl()
674 NodeImpl::Id HTMLHeadElementImpl::id() const
679 // -------------------------------------------------------------------------
681 HTMLHtmlElementImpl::HTMLHtmlElementImpl(DocumentPtr *doc)
682 : HTMLElementImpl(doc)
686 HTMLHtmlElementImpl::~HTMLHtmlElementImpl()
690 NodeImpl::Id HTMLHtmlElementImpl::id() const
695 // -------------------------------------------------------------------------
697 HTMLIFrameElementImpl::HTMLIFrameElementImpl(DocumentPtr *doc) : HTMLFrameElementImpl(doc)
702 needWidgetUpdate = false;
705 HTMLIFrameElementImpl::~HTMLIFrameElementImpl()
709 NodeImpl::Id HTMLIFrameElementImpl::id() const
714 bool HTMLIFrameElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
722 result = eReplaced; // Share with <img> since the alignment behavior is the same.
728 return HTMLElementImpl::mapToEntry(attr, result);
731 void HTMLIFrameElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr )
733 switch ( attr->id() )
736 addCSSLength( attr, CSS_PROP_WIDTH, attr->value());
739 addCSSLength( attr, CSS_PROP_HEIGHT, attr->value() );
742 addHTMLAlignment( attr );
745 HTMLFrameElementImpl::parseHTMLAttribute( attr );
749 bool HTMLIFrameElementImpl::rendererIsNeeded(RenderStyle *style)
751 // Don't ignore display: none the way frame does.
752 return isURLAllowed(url) && style->display() != NONE;
755 RenderObject *HTMLIFrameElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
757 return new (arena) RenderPartObject(this);
760 void HTMLIFrameElementImpl::attach()
762 HTMLElementImpl::attach();
764 KHTMLPart *part = getDocument()->part();
765 if (m_render && part) {
766 // we need a unique name for every frame in the frameset. Hope that's unique enough.
767 part->incrementFrameCount();
768 if(name.isEmpty() || part->frameExists( name.string() ))
769 name = AtomicString(part->requestFrameName());
771 static_cast<RenderPartObject*>(m_render)->updateWidget();
772 needWidgetUpdate = false;
776 void HTMLIFrameElementImpl::recalcStyle( StyleChange ch )
778 if (needWidgetUpdate) {
779 if(m_render) static_cast<RenderPartObject*>(m_render)->updateWidget();
780 needWidgetUpdate = false;
782 HTMLElementImpl::recalcStyle( ch );
785 void HTMLIFrameElementImpl::openURL()
787 needWidgetUpdate = true;
791 bool HTMLIFrameElementImpl::isURLAttribute(AttributeImpl *attr) const
793 return attr->id() == ATTR_SRC;