blob: 986e889bbd3685a6f02a3097583b83ad7857c120 [file] [log] [blame]
/**
* This file is part of the DOM implementation for KDE.
*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Simon Hausmann (hausmann@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
// -------------------------------------------------------------------------
#include "html/html_baseimpl.h"
#include "html/html_documentimpl.h"
#include "khtmlview.h"
#include "khtml_part.h"
#include "rendering/render_frames.h"
#include "rendering/render_html.h"
#include "rendering/render_body.h"
#include "css/cssstyleselector.h"
#include "css/css_stylesheetimpl.h"
#include "css/cssproperties.h"
#include "css/cssvalues.h"
#include "css/csshelper.h"
#include "misc/loader.h"
#include "misc/htmlhashes.h"
#include "dom/dom_string.h"
#include "dom/dom_doc.h"
#include "xml/dom2_eventsimpl.h"
#include <kurl.h>
#include <kdebug.h>
using namespace DOM;
using namespace khtml;
HTMLBodyElementImpl::HTMLBodyElementImpl(DocumentPtr *doc)
: HTMLElementImpl(doc),
m_bgSet( false ), m_fgSet( false )
{
m_styleSheet = 0;
}
HTMLBodyElementImpl::~HTMLBodyElementImpl()
{
if(m_styleSheet) m_styleSheet->deref();
}
NodeImpl::Id HTMLBodyElementImpl::id() const
{
return ID_BODY;
}
void HTMLBodyElementImpl::parseAttribute(AttributeImpl *attr)
{
switch(attr->id())
{
case ATTR_BACKGROUND:
{
QString url = khtml::parseURL( attr->value() ).string();
if (!url.isEmpty()) {
url = getDocument()->completeURL( url );
addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, "url('"+url+"')" );
m_bgSet = true;
}
else
m_bgSet = false;
break;
}
case ATTR_MARGINWIDTH:
addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value() );
/* nobreak; */
case ATTR_LEFTMARGIN:
addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value() );
break;
case ATTR_MARGINHEIGHT:
addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
/* nobreak */
case ATTR_TOPMARGIN:
addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
break;
case ATTR_BGCOLOR:
addCSSProperty(CSS_PROP_BACKGROUND_COLOR, attr->value());
m_bgSet = !attr->value().isNull();
break;
case ATTR_TEXT:
addCSSProperty(CSS_PROP_COLOR, attr->value());
m_fgSet = !attr->value().isNull();
break;
case ATTR_BGPROPERTIES:
if ( strcasecmp( attr->value(), "fixed" ) == 0)
addCSSProperty(CSS_PROP_BACKGROUND_ATTACHMENT, CSS_VAL_FIXED);
break;
case ATTR_VLINK:
case ATTR_ALINK:
case ATTR_LINK:
{
if(!m_styleSheet) {
m_styleSheet = new CSSStyleSheetImpl(this,DOMString(),true);
m_styleSheet->ref();
}
QString aStr;
if ( attr->id() == ATTR_LINK )
aStr = "a:link";
else if ( attr->id() == ATTR_VLINK )
aStr = "a:visited";
else if ( attr->id() == ATTR_ALINK )
aStr = "a:active";
aStr += " { color: " + attr->value().string() + "; }";
m_styleSheet->parseString(aStr);
m_styleSheet->setNonCSSHints();
if (attached())
getDocument()->updateStyleSelector();
break;
}
case ATTR_ONLOAD:
getDocument()->setWindowEventListener(EventImpl::LOAD_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONUNLOAD:
getDocument()->setWindowEventListener(EventImpl::UNLOAD_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONBLUR:
getDocument()->setWindowEventListener(EventImpl::BLUR_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONFOCUS:
getDocument()->setWindowEventListener(EventImpl::FOCUS_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONRESIZE:
getDocument()->setWindowEventListener(EventImpl::RESIZE_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_NOSAVE:
break;
default:
HTMLElementImpl::parseAttribute(attr);
}
}
void HTMLBodyElementImpl::init()
{
HTMLElementImpl::init();
KHTMLView* w = getDocument()->view();
if(w->marginWidth() != -1) {
QString s;
s.sprintf( "%d", w->marginWidth() );
addCSSLength(CSS_PROP_MARGIN_LEFT, s);
addCSSLength(CSS_PROP_MARGIN_RIGHT, s);
}
if(w->marginHeight() != -1) {
QString s;
s.sprintf( "%d", w->marginHeight() );
addCSSLength(CSS_PROP_MARGIN_TOP, s);
addCSSLength(CSS_PROP_MARGIN_BOTTOM, s);
}
if ( m_bgSet && !m_fgSet )
addCSSProperty(CSS_PROP_COLOR, "#000000");
getDocument()->updateStyleSelector();
}
void HTMLBodyElementImpl::attach()
{
assert(!m_render);
assert(parentNode());
assert(parentNode()->renderer());
RenderStyle* style = getDocument()->styleSelector()->styleForElement(this);
style->ref();
if (style->display() != NONE) {
m_render = new RenderBody(this);
m_render->setStyle(style);
parentNode()->renderer()->addChild(m_render, nextRenderer());
}
style->deref();
NodeBaseImpl::attach();
}
// -------------------------------------------------------------------------
HTMLFrameElementImpl::HTMLFrameElementImpl(DocumentPtr *doc)
: HTMLElementImpl(doc)
{
parentWidget = 0;
frameBorder = true;
frameBorderSet = false;
marginWidth = -1;
marginHeight = -1;
scrolling = QScrollView::Auto;
noresize = false;
url = "about:blank";
}
HTMLFrameElementImpl::~HTMLFrameElementImpl()
{
}
NodeImpl::Id HTMLFrameElementImpl::id() const
{
return ID_FRAME;
}
void HTMLFrameElementImpl::parseAttribute(AttributeImpl *attr)
{
switch(attr->id())
{
case ATTR_SRC:
url = khtml::parseURL(attr->val());
break;
case ATTR_ID:
case ATTR_NAME:
name = attr->value();
break;
case ATTR_FRAMEBORDER:
{
frameBorder = attr->value().toInt();
frameBorderSet = ( attr->val() != 0 );
}
break;
case ATTR_MARGINWIDTH:
marginWidth = attr->val()->toInt();
break;
case ATTR_MARGINHEIGHT:
marginHeight = attr->val()->toInt();
break;
case ATTR_NORESIZE:
noresize = true;
break;
case ATTR_SCROLLING:
kdDebug( 6031 ) << "set scroll mode" << endl;
if( strcasecmp( attr->value(), "auto" ) == 0 )
scrolling = QScrollView::Auto;
else if( strcasecmp( attr->value(), "yes" ) == 0 )
scrolling = QScrollView::AlwaysOn;
else if( strcasecmp( attr->value(), "no" ) == 0 )
scrolling = QScrollView::AlwaysOff;
default:
HTMLElementImpl::parseAttribute(attr);
}
}
void HTMLFrameElementImpl::init()
{
HTMLElementImpl::init();
// we should first look up via id, then via name.
// this shortterm hack fixes the ugly case. ### rewrite needed for next release
name = getAttribute(ATTR_NAME);
if (name.isNull())
name = getAttribute(ATTR_ID);
// inherit default settings from parent frameset
HTMLElementImpl* node = static_cast<HTMLElementImpl*>(parentNode());
while(node)
{
if(node->id() == ID_FRAMESET)
{
HTMLFrameSetElementImpl* frameset = static_cast<HTMLFrameSetElementImpl*>(node);
if(!frameBorderSet) frameBorder = frameset->frameBorder();
if(!noresize) noresize = frameset->noResize();
break;
}
node = static_cast<HTMLElementImpl*>(node->parentNode());
}
}
void HTMLFrameElementImpl::attach()
{
assert(!attached());
assert(parentNode());
assert(parentNode()->renderer());
// ignore display: none for this element!
KHTMLView* w = getDocument()->view();
// limit to how deep we can nest frames
KHTMLPart *part = w->part();
int depth = 0;
while ((part = part->parentPart()))
depth++;
if (depth < 5) {
m_render = new RenderFrame(this);
m_render->setStyle(getDocument()->styleSelector()->styleForElement(this));
parentNode()->renderer()->addChild(m_render, nextRenderer());
}
NodeBaseImpl::attach();
if (!m_render)
return;
// we need a unique name for every frame in the frameset. Hope that's unique enough.
if(name.isEmpty() || w->part()->frameExists( name.string() ) )
name = DOMString(w->part()->requestFrameName());
// load the frame contents
if (!url.isEmpty())
w->part()->requestFrame( static_cast<RenderFrame*>(m_render), url.string(), name.string() );
}
void HTMLFrameElementImpl::detach()
{
HTMLElementImpl::detach();
parentWidget = 0;
}
void HTMLFrameElementImpl::setLocation( const DOMString& str )
{
url = str;
KHTMLView* w = getDocument()->view();
if ( m_render && w && w->part() )
// don't call this for an iframe
w->part()->requestFrame( static_cast<khtml::RenderFrame *>(m_render), url.string(), name.string() );
}
bool HTMLFrameElementImpl::isSelectable() const
{
return m_render!=0;
}
void HTMLFrameElementImpl::setFocus(bool received)
{
HTMLElementImpl::setFocus(received);
khtml::RenderFrame *renderFrame = static_cast<khtml::RenderFrame *>(m_render);
if (!renderFrame || !renderFrame->widget())
return;
if (received)
renderFrame->widget()->setFocus();
else
renderFrame->widget()->clearFocus();
}
DocumentImpl* HTMLFrameElementImpl::contentDocument() const
{
if ( !m_render ) return 0;
RenderPart* render = static_cast<RenderPart*>( m_render );
if(render->widget() && render->widget()->inherits("KHTMLView"))
return static_cast<KHTMLView*>( render->widget() )->part()->xmlDocImpl();
return 0;
}
// -------------------------------------------------------------------------
HTMLFrameSetElementImpl::HTMLFrameSetElementImpl(DocumentPtr *doc)
: HTMLElementImpl(doc)
{
// default value for rows and cols...
m_totalRows = 1;
m_totalCols = 1;
m_rows = m_cols = 0;
frameborder = true;
frameBorderSet = false;
m_border = 4;
noresize = false;
m_resizing = false;
}
HTMLFrameSetElementImpl::~HTMLFrameSetElementImpl()
{
if (m_rows)
delete [] m_rows;
if (m_cols)
delete [] m_cols;
}
NodeImpl::Id HTMLFrameSetElementImpl::id() const
{
return ID_FRAMESET;
}
void HTMLFrameSetElementImpl::parseAttribute(AttributeImpl *attr)
{
switch(attr->id())
{
case ATTR_ROWS:
if (!attr->val()) break;
if (m_rows) delete [] m_rows;
m_rows = attr->val()->toLengthArray(m_totalRows);
setChanged();
break;
case ATTR_COLS:
if (!attr->val()) break;
delete [] m_cols;
m_cols = attr->val()->toLengthArray(m_totalCols);
setChanged();
break;
case ATTR_FRAMEBORDER:
// false or "no" or "0"..
if ( attr->value().toInt() == 0 ) {
frameborder = false;
m_border = 0;
}
frameBorderSet = true;
break;
case ATTR_NORESIZE:
noresize = true;
break;
case ATTR_BORDER:
m_border = attr->val()->toInt();
if(!m_border)
frameborder = false;
break;
case ATTR_ONLOAD:
setHTMLEventListener(EventImpl::LOAD_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
case ATTR_ONUNLOAD:
setHTMLEventListener(EventImpl::UNLOAD_EVENT,
getDocument()->createHTMLEventListener(attr->value().string()));
break;
default:
HTMLElementImpl::parseAttribute(attr);
}
}
void HTMLFrameSetElementImpl::init()
{
HTMLElementImpl::init();
// inherit default settings from parent frameset
HTMLElementImpl* node = static_cast<HTMLElementImpl*>(parentNode());
while(node)
{
if(node->id() == ID_FRAMESET)
{
HTMLFrameSetElementImpl* frameset = static_cast<HTMLFrameSetElementImpl*>(node);
if(!frameBorderSet) frameborder = frameset->frameBorder();
if(!noresize) noresize = frameset->noResize();
break;
}
node = static_cast<HTMLElementImpl*>(node->parentNode());
}
}
void HTMLFrameSetElementImpl::attach()
{
assert(!m_render);
assert(parentNode());
assert(parentNode()->renderer());
// ignore display: none
m_render = new RenderFrameSet(this);
m_render->setStyle(getDocument()->styleSelector()->styleForElement(this));
parentNode()->renderer()->addChild(m_render, nextRenderer());
NodeBaseImpl::attach();
}
void HTMLFrameSetElementImpl::defaultEventHandler(EventImpl *evt)
{
if (evt->isMouseEvent() && !noresize && m_render)
static_cast<khtml::RenderFrameSet *>(m_render)->userResize(static_cast<MouseEventImpl*>(evt));
evt->setDefaultHandled();
HTMLElementImpl::defaultEventHandler(evt);
}
void HTMLFrameSetElementImpl::detach()
{
if(attached())
// ### send the event when we actually get removed from the doc instead of here
dispatchHTMLEvent(EventImpl::UNLOAD_EVENT,false,false);
HTMLElementImpl::detach();
}
void HTMLFrameSetElementImpl::recalcStyle( StyleChange ch )
{
if (changed() && m_render) {
m_render->setLayouted(false);
// m_render->layout();
setChanged(false);
}
HTMLElementImpl::recalcStyle( ch );
}
// -------------------------------------------------------------------------
HTMLHeadElementImpl::HTMLHeadElementImpl(DocumentPtr *doc)
: HTMLElementImpl(doc)
{
}
HTMLHeadElementImpl::~HTMLHeadElementImpl()
{
}
NodeImpl::Id HTMLHeadElementImpl::id() const
{
return ID_HEAD;
}
void HTMLHtmlElementImpl::attach()
{
assert(!m_render);
assert(parentNode());
assert(parentNode()->renderer());
m_render = new RenderHtml(this);
m_render->setStyle(getDocument()->styleSelector()->styleForElement(this));
parentNode()->renderer()->addChild(m_render, nextRenderer());
NodeBaseImpl::attach();
}
// -------------------------------------------------------------------------
HTMLHtmlElementImpl::HTMLHtmlElementImpl(DocumentPtr *doc)
: HTMLElementImpl(doc)
{
}
HTMLHtmlElementImpl::~HTMLHtmlElementImpl()
{
}
NodeImpl::Id HTMLHtmlElementImpl::id() const
{
return ID_HTML;
}
// -------------------------------------------------------------------------
HTMLIFrameElementImpl::HTMLIFrameElementImpl(DocumentPtr *doc) : HTMLFrameElementImpl(doc)
{
frameBorder = false;
marginWidth = 0;
marginHeight = 0;
needWidgetUpdate = false;
}
HTMLIFrameElementImpl::~HTMLIFrameElementImpl()
{
}
NodeImpl::Id HTMLIFrameElementImpl::id() const
{
return ID_IFRAME;
}
void HTMLIFrameElementImpl::parseAttribute(AttributeImpl *attr )
{
switch ( attr->id() )
{
case ATTR_WIDTH:
addCSSLength( CSS_PROP_WIDTH, attr->value());
break;
case ATTR_HEIGHT:
addCSSLength( CSS_PROP_HEIGHT, attr->value() );
break;
case ATTR_SRC:
needWidgetUpdate = true; // ### do this for scrolling, margins etc?
HTMLFrameElementImpl::parseAttribute( attr );
break;
default:
HTMLFrameElementImpl::parseAttribute( attr );
}
}
void HTMLIFrameElementImpl::attach()
{
assert(!attached());
assert(!m_render);
assert(parentNode());
KHTMLView* w = getDocument()->view();
// limit to how deep we can nest frames
KHTMLPart *part = w->part();
int depth = 0;
while ((part = part->parentPart()))
depth++;
RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
_style->ref();
if (depth < 7 && parentNode()->renderer() && _style->display() != NONE) {
m_render = new RenderPartObject(this);
m_render->setStyle(_style);
parentNode()->renderer()->addChild(m_render, nextRenderer());
}
_style->deref();
NodeBaseImpl::attach();
if (m_render) {
// we need a unique name for every frame in the frameset. Hope that's unique enough.
KHTMLView* w = getDocument()->view();
if(name.isEmpty() || w->part()->frameExists( name.string() ))
name = DOMString(w->part()->requestFrameName());
static_cast<RenderPartObject*>(m_render)->updateWidget();
needWidgetUpdate = false;
}
}
void HTMLIFrameElementImpl::recalcStyle( StyleChange ch )
{
if (needWidgetUpdate) {
if(m_render) static_cast<RenderPartObject*>(m_render)->updateWidget();
needWidgetUpdate = false;
}
HTMLElementImpl::recalcStyle( ch );
}