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