00001
00023 #include "html/html_imageimpl.h"
00024 #include "html/html_formimpl.h"
00025 #include "html/html_documentimpl.h"
00026
00027 #include "misc/htmlhashes.h"
00028 #include "khtmlview.h"
00029 #include "khtml_part.h"
00030
00031 #include <kstringhandler.h>
00032 #include <kglobal.h>
00033 #include <kdebug.h>
00034
00035 #include "rendering/render_image.h"
00036 #include "rendering/render_flow.h"
00037 #include "css/cssstyleselector.h"
00038 #include "css/cssproperties.h"
00039 #include "css/cssvalues.h"
00040 #include "css/csshelper.h"
00041 #include "xml/dom2_eventsimpl.h"
00042
00043 #include <qstring.h>
00044 #include <qpoint.h>
00045 #include <qregion.h>
00046 #include <qptrstack.h>
00047 #include <qimage.h>
00048 #include <qpointarray.h>
00049
00050 using namespace DOM;
00051 using namespace khtml;
00052
00053
00054
00055 HTMLImageElementImpl::HTMLImageElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
00056 : HTMLElementImpl(doc), ismap(false), m_form(f)
00057 {
00058 if (m_form)
00059 m_form->registerImgElement(this);
00060 }
00061
00062 HTMLImageElementImpl::~HTMLImageElementImpl()
00063 {
00064 if (m_form)
00065 m_form->removeImgElement(this);
00066 }
00067
00068 NodeImpl::Id HTMLImageElementImpl::id() const
00069 {
00070 return ID_IMG;
00071 }
00072
00073 void HTMLImageElementImpl::parseAttribute(AttributeImpl *attr)
00074 {
00075 switch (attr->id())
00076 {
00077 case ATTR_ALT:
00078 case ATTR_SRC:
00079 setChanged();
00080 break;
00081 case ATTR_WIDTH:
00082 addCSSLength(CSS_PROP_WIDTH, attr->value());
00083 break;
00084 case ATTR_HEIGHT:
00085 addCSSLength(CSS_PROP_HEIGHT, attr->value());
00086 break;
00087 case ATTR_BORDER:
00088
00089 if(attr->value().toInt()) {
00090 addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value());
00091 addCSSProperty( CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID );
00092 addCSSProperty( CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID );
00093 addCSSProperty( CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID );
00094 addCSSProperty( CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID );
00095 }
00096 break;
00097 case ATTR_VSPACE:
00098 addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
00099 addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
00100 break;
00101 case ATTR_HSPACE:
00102 addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
00103 addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
00104 break;
00105 case ATTR_ALIGN:
00106 addHTMLAlignment( attr->value() );
00107 break;
00108 case ATTR_VALIGN:
00109 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value());
00110 break;
00111 case ATTR_USEMAP:
00112 if ( attr->value()[0] == '#' )
00113 usemap = attr->value();
00114 else {
00115 QString url = getDocument()->completeURL( khtml::parseURL( attr->value() ).string() );
00116
00117
00118 usemap = url;
00119 }
00120 m_hasAnchor = attr->val() != 0;
00121 case ATTR_ISMAP:
00122 ismap = true;
00123 break;
00124 case ATTR_ONABORT:
00125 setHTMLEventListener(EventImpl::ABORT_EVENT,
00126 getDocument()->createHTMLEventListener(attr->value().string()));
00127 break;
00128 case ATTR_ONERROR:
00129 setHTMLEventListener(EventImpl::ERROR_EVENT,
00130 getDocument()->createHTMLEventListener(attr->value().string()));
00131 break;
00132 case ATTR_ONLOAD:
00133 setHTMLEventListener(EventImpl::LOAD_EVENT,
00134 getDocument()->createHTMLEventListener(attr->value().string()));
00135 break;
00136 case ATTR_NAME:
00137 case ATTR_NOSAVE:
00138 break;
00139 default:
00140 HTMLElementImpl::parseAttribute(attr);
00141 }
00142 }
00143
00144 DOMString HTMLImageElementImpl::altText() const
00145 {
00146
00147
00148
00149 DOMString alt( getAttribute( ATTR_ALT ) );
00150
00151 if ( alt.isNull() )
00152 alt = getAttribute( ATTR_TITLE );
00153 #if 0
00154 if ( alt.isNull() ) {
00155 QString p = KURL( getDocument()->completeURL( getAttribute(ATTR_SRC).string() ) ).prettyURL();
00156 int pos;
00157 if ( ( pos = p.findRev( '.' ) ) > 0 )
00158 p.truncate( pos );
00159 alt = DOMString( KStringHandler::csqueeze( p ) );
00160 }
00161 #endif
00162
00163 return alt;
00164 }
00165
00166 void HTMLImageElementImpl::attach()
00167 {
00168 assert(!attached());
00169 assert(!m_render);
00170 assert(parentNode());
00171
00172 RenderStyle* _style = getDocument()->styleSelector()->styleForElement(this);
00173 _style->ref();
00174 if (parentNode()->renderer() && _style->display() != NONE) {
00175 m_render = new RenderImage(this);
00176 m_render->setStyle(getDocument()->styleSelector()->styleForElement(this));
00177 parentNode()->renderer()->addChild(m_render, nextRenderer());
00178 m_render->updateFromElement();
00179 }
00180 _style->deref();
00181
00182 NodeBaseImpl::attach();
00183 }
00184
00185 long HTMLImageElementImpl::width() const
00186 {
00187 if (!m_render) return getAttribute(ATTR_WIDTH).toInt();
00188
00189
00190 if (changed()) {
00191 getDocument()->updateRendering();
00192 if (getDocument()->view())
00193 getDocument()->view()->layout();
00194 }
00195
00196 return m_render->contentWidth();
00197 }
00198
00199 long HTMLImageElementImpl::height() const
00200 {
00201 if (!m_render) return getAttribute(ATTR_HEIGHT).toInt();
00202
00203
00204 if (changed()) {
00205 getDocument()->updateRendering();
00206 if (getDocument()->view())
00207 getDocument()->view()->layout();
00208 }
00209
00210 return m_render->contentHeight();
00211 }
00212
00213 QImage HTMLImageElementImpl::currentImage() const
00214 {
00215 RenderImage *r = static_cast<RenderImage*>(renderer());
00216
00217 if(r)
00218 return r->pixmap().convertToImage();
00219
00220 return QImage();
00221 }
00222
00223
00224 bool HTMLImageElementImpl::complete() const
00225 {
00226 RenderImage *r = static_cast<RenderImage*>(renderer());
00227 if(r)
00228 return r->complete();
00229 return false;
00230 }
00231
00232
00233
00234 HTMLMapElementImpl::HTMLMapElementImpl(DocumentPtr *doc)
00235 : HTMLElementImpl(doc)
00236 {
00237 }
00238
00239 HTMLMapElementImpl::~HTMLMapElementImpl()
00240 {
00241 if(getDocument() && getDocument()->isHTMLDocument())
00242 static_cast<HTMLDocumentImpl*>(getDocument())->mapMap.remove(name);
00243 }
00244
00245 NodeImpl::Id HTMLMapElementImpl::id() const
00246 {
00247 return ID_MAP;
00248 }
00249
00250 bool
00251 HTMLMapElementImpl::mapMouseEvent(int x_, int y_, int width_, int height_,
00252 RenderObject::NodeInfo& info)
00253 {
00254
00255
00256 QPtrStack<NodeImpl> nodeStack;
00257
00258 NodeImpl *current = firstChild();
00259 while(1)
00260 {
00261 if(!current)
00262 {
00263 if(nodeStack.isEmpty()) break;
00264 current = nodeStack.pop();
00265 current = current->nextSibling();
00266 continue;
00267 }
00268 if(current->id()==ID_AREA)
00269 {
00270
00271 HTMLAreaElementImpl* area=static_cast<HTMLAreaElementImpl*>(current);
00272 if (area->mapMouseEvent(x_,y_,width_,height_, info))
00273 return true;
00274 }
00275 NodeImpl *child = current->firstChild();
00276 if(child)
00277 {
00278 nodeStack.push(current);
00279 current = child;
00280 }
00281 else
00282 {
00283 current = current->nextSibling();
00284 }
00285 }
00286
00287 return false;
00288 }
00289
00290 void HTMLMapElementImpl::parseAttribute(AttributeImpl *attr)
00291 {
00292 switch (attr->id())
00293 {
00294 case ATTR_ID:
00295 if (getDocument()->htmlMode() != DocumentImpl::XHtml) break;
00296
00297 case ATTR_NAME:
00298 {
00299 DOMString s = attr->value();
00300 if(*s.unicode() == '#')
00301 name = QString(s.unicode()+1, s.length()-1);
00302 else
00303 name = s.string();
00304
00305 if(getDocument()->isHTMLDocument())
00306 static_cast<HTMLDocumentImpl*>(getDocument())->mapMap[name] = this;
00307 break;
00308 }
00309 default:
00310 HTMLElementImpl::parseAttribute(attr);
00311 }
00312 }
00313
00314
00315
00316 HTMLAreaElementImpl::HTMLAreaElementImpl(DocumentPtr *doc)
00317 : HTMLAnchorElementImpl(doc)
00318 {
00319 m_coords=0;
00320 m_coordsLen = 0;
00321 nohref = false;
00322 shape = Unknown;
00323 lasth = lastw = -1;
00324 }
00325
00326 HTMLAreaElementImpl::~HTMLAreaElementImpl()
00327 {
00328 if (m_coords) delete [] m_coords;
00329 }
00330
00331 NodeImpl::Id HTMLAreaElementImpl::id() const
00332 {
00333 return ID_AREA;
00334 }
00335
00336 void HTMLAreaElementImpl::parseAttribute(AttributeImpl *attr)
00337 {
00338 switch (attr->id())
00339 {
00340 case ATTR_SHAPE:
00341 if ( strcasecmp( attr->value(), "default" ) == 0 )
00342 shape = Default;
00343 else if ( strcasecmp( attr->value(), "circle" ) == 0 )
00344 shape = Circle;
00345 else if ( strcasecmp( attr->value(), "poly" ) == 0 )
00346 shape = Poly;
00347 else if ( strcasecmp( attr->value(), "rect" ) == 0 )
00348 shape = Rect;
00349 break;
00350 case ATTR_COORDS:
00351 if (m_coords) delete [] m_coords;
00352 m_coords = attr->val()->toLengthArray(m_coordsLen);
00353 break;
00354 case ATTR_NOHREF:
00355 nohref = attr->val() != 0;
00356 break;
00357 case ATTR_TARGET:
00358 m_hasTarget = attr->val() != 0;
00359 break;
00360 case ATTR_ALT:
00361 break;
00362 case ATTR_ACCESSKEY:
00363 break;
00364 default:
00365 HTMLAnchorElementImpl::parseAttribute(attr);
00366 }
00367 }
00368
00369 bool HTMLAreaElementImpl::mapMouseEvent(int x_, int y_, int width_, int height_,
00370 RenderObject::NodeInfo& info)
00371 {
00372 bool inside = false;
00373 if (width_ != lastw || height_ != lasth)
00374 {
00375 region=getRegion(width_, height_);
00376 lastw=width_; lasth=height_;
00377 }
00378 if (region.contains(QPoint(x_,y_)))
00379 {
00380 inside = true;
00381 info.setInnerNode(this);
00382 info.setURLElement(this);
00383 }
00384
00385 return inside;
00386 }
00387
00388 QRect HTMLAreaElementImpl::getRect() const
00389 {
00390 if (parentNode()->renderer()==0)
00391 return QRect();
00392 int dx, dy;
00393 if (!parentNode()->renderer()->absolutePosition(dx, dy))
00394 return QRect();
00395 QRegion region = getRegion(lastw,lasth);
00396 region.translate(dx, dy);
00397 return region.boundingRect();
00398 }
00399
00400 QRegion HTMLAreaElementImpl::getRegion(int width_, int height_) const
00401 {
00402 QRegion region;
00403 if (!m_coords)
00404 return region;
00405
00406
00407
00408
00409
00410
00411 if ((shape==Poly || shape==Unknown) && m_coordsLen > 5) {
00412
00413 int len = m_coordsLen >> 1;
00414 QPointArray points(len);
00415 for (int i = 0; i < len; ++i)
00416 points.setPoint(i, m_coords[(i<<1)].minWidth(width_),
00417 m_coords[(i<<1)+1].minWidth(height_));
00418 region = QRegion(points);
00419 }
00420 else if (shape==Circle && m_coordsLen>=3 || shape==Unknown && m_coordsLen == 3) {
00421 int r = kMin(m_coords[2].minWidth(width_), m_coords[2].minWidth(height_));
00422 region = QRegion(m_coords[0].minWidth(width_)-r,
00423 m_coords[1].minWidth(height_)-r, 2*r, 2*r,QRegion::Ellipse);
00424 }
00425 else if (shape==Rect && m_coordsLen>=4 || shape==Unknown && m_coordsLen == 4) {
00426 int x0 = m_coords[0].minWidth(width_);
00427 int y0 = m_coords[1].minWidth(height_);
00428 int x1 = m_coords[2].minWidth(width_);
00429 int y1 = m_coords[3].minWidth(height_);
00430 region = QRegion(x0,y0,x1-x0,y1-y0);
00431 }
00432 else if (shape==Default)
00433 region = QRegion(0,0,width_,height_);
00434
00435
00436
00437 return region;
00438 }