1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000 Simon Hausmann <hausmann@kde.org>
7  *           (C) 2001-2003 Dirk Mueller (mueller@kde.org)
8  *           (C) 2002 Apple Computer, Inc.
9  *
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.
14  *
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.
19  *
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., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25 // -------------------------------------------------------------------------
26 
27 #include "html/html_inlineimpl.h"
28 #include "html/html_imageimpl.h"
29 #include "html/html_documentimpl.h"
30 
31 #include "khtmlview.h"
32 #include "khtml_part.h"
33 #include "css/cssproperties.h"
34 #include "css/cssvalues.h"
35 #include "css/cssstyleselector.h"
36 #include "xml/dom2_eventsimpl.h"
37 #include "rendering/render_br.h"
38 #include "rendering/render_image.h"
39 #include "rendering/render_inline.h"
40 
41 #include <QKeyEvent>
42 
43 using namespace khtml;
44 using namespace DOM;
45 
id() const46 NodeImpl::Id HTMLAnchorElementImpl::id() const
47 {
48     return ID_A;
49 }
50 
defaultEventHandler(EventImpl * evt)51 void HTMLAnchorElementImpl::defaultEventHandler(EventImpl *evt)
52 {
53     bool keydown = evt->id() == EventImpl::KEYDOWN_EVENT && evt->isKeyRelatedEvent();
54 
55     // React on clicks and on keypresses.
56     // Don't make this KEYUP_EVENT again, it makes khtml follow links
57     // it shouldn't, when pressing Enter in the combo.
58     if (((evt->id() == EventImpl::CLICK_EVENT && !static_cast<MouseEventImpl *>(evt)->isDoubleClick()) ||
59             (keydown && m_focused)) && m_hasAnchor) {
60 
61         MouseEventImpl *e = nullptr;
62         if (evt->id() == EventImpl::CLICK_EVENT) {
63             e = static_cast<MouseEventImpl *>(evt);
64         }
65 
66         KeyEventBaseImpl *k = nullptr;
67         if (keydown) {
68             k = static_cast<KeyEventBaseImpl *>(evt);
69         }
70 
71         if (e && e->button() == 2) {
72             HTMLElementImpl::defaultEventHandler(evt);
73             return;
74         }
75 
76         if (k) {
77             if (k->virtKeyVal() != KeyEventBaseImpl::DOM_VK_ENTER) {
78                 if (k->qKeyEvent()) {
79                     k->qKeyEvent()->ignore();
80                 }
81                 HTMLElementImpl::defaultEventHandler(evt);
82                 return;
83             }
84             if (k->qKeyEvent()) {
85                 k->qKeyEvent()->accept();
86             }
87         }
88 
89         QString url = getAttribute(ATTR_HREF).trimSpaces().string();
90         QString utarget = getAttribute(ATTR_TARGET).string();
91 
92         if (e && e->button() == 1) {
93             utarget = "_blank";
94         }
95 
96         if (static_cast<NodeImpl *>(evt->target())->id() == ID_IMG) {
97             HTMLImageElementImpl *img = static_cast<HTMLImageElementImpl *>(evt->target());
98             if (img && img->isServerMap()) {
99                 khtml::RenderImage *r = static_cast<khtml::RenderImage *>(img->renderer());
100                 if (r && e) {
101                     KHTMLView *v = document()->view();
102                     int x = e->clientX();
103                     int y = e->clientY();
104                     int absx = 0;
105                     int absy = 0;
106                     if (v) {
107                         x += v->contentsX();
108                         y += v->contentsY();
109                     }
110                     r->absolutePosition(absx, absy);
111                     url += QString("?%1,%2").arg(x - absx).arg(y - absy);
112                 } else {
113                     evt->setDefaultHandled();
114                     HTMLElementImpl::defaultEventHandler(evt);
115                     return;
116                 }
117             }
118         }
119         if (!evt->defaultPrevented()) {
120             int state = 0;
121             int button = 0;
122 
123             if (e) {
124                 if (e->ctrlKey()) {
125                     state |= Qt::ControlModifier;
126                 }
127                 if (e->shiftKey()) {
128                     state |= Qt::ShiftModifier;
129                 }
130                 if (e->altKey()) {
131                     state |= Qt::AltModifier;
132                 }
133                 if (e->metaKey()) {
134                     state |= Qt::MetaModifier;
135                 }
136 
137                 if (e->button() == 0) {
138                     button = Qt::LeftButton;
139                 } else if (e->button() == 1) {
140                     button = Qt::MidButton;
141                 } else if (e->button() == 2) {
142                     button = Qt::RightButton;
143                 }
144             } else if (k) {
145                 if (k->checkModifier(Qt::ShiftModifier)) {
146                     state |= Qt::ShiftModifier;
147                 }
148                 if (k->checkModifier(Qt::AltModifier)) {
149                     state |= Qt::AltModifier;
150                 }
151                 if (k->checkModifier(Qt::ControlModifier)) {
152                     state |= Qt::ControlModifier;
153                 }
154             }
155 
156             if (document()->part() && !isContentEditable()) {
157                 if (k) {
158                     click();
159                 } else {
160                     KParts::OpenUrlArguments args;
161                     args.setActionRequestedByUser(true);
162                     document()->part()->urlSelected(url, button, state, utarget, args);
163                 }
164             }
165         }
166         evt->setDefaultHandled();
167     }
168     HTMLElementImpl::defaultEventHandler(evt);
169 }
170 
click()171 void HTMLAnchorElementImpl::click()
172 {
173     QMouseEvent me(QEvent::MouseButtonRelease, QPoint(0, 0), Qt::LeftButton, Qt::LeftButton, nullptr);
174     dispatchMouseEvent(&me, EventImpl::CLICK_EVENT, 1);
175 }
176 
parseAttribute(AttributeImpl * attr)177 void HTMLAnchorElementImpl::parseAttribute(AttributeImpl *attr)
178 {
179     switch (attr->id()) {
180     case ATTR_HREF: {
181         bool hadAnchor = m_hasAnchor;
182         m_hasAnchor = attr->val() != nullptr;
183         document()->incDOMTreeVersion(DocumentImpl::TV_IDNameHref);
184         if (hadAnchor != m_hasAnchor) {
185             setChanged();
186         }
187         if (m_hasAnchor && document()->part() && document()->part()->dnsPrefetch()) {
188             QUrl url(attr->value().string());
189             if (!url.host().isEmpty()) {
190                 document()->part()->mayPrefetchHostname(url.host());
191             }
192         }
193     }
194     break;
195     case ATTR_TARGET:
196         m_hasTarget = attr->val() != nullptr;
197         break;
198     case ATTR_TITLE:
199     case ATTR_REL:
200         break;
201     case ATTR_ACCESSKEY:
202         break;
203     default:
204         HTMLElementImpl::parseAttribute(attr);
205     }
206 }
207 
isFocusableImpl(FocusType ft) const208 bool HTMLAnchorElementImpl::isFocusableImpl(FocusType ft) const
209 {
210     if (m_hasAnchor) {
211         return true;
212     }
213     return HTMLElementImpl::isFocusableImpl(ft);
214 }
215 
216 // -------------------------------------------------------------------------
217 
id() const218 NodeImpl::Id HTMLBRElementImpl::id() const
219 {
220     return ID_BR;
221 }
222 
parseAttribute(AttributeImpl * attr)223 void HTMLBRElementImpl::parseAttribute(AttributeImpl *attr)
224 {
225     switch (attr->id()) {
226     case ATTR_CLEAR: {
227         DOMString str = attr->value().lower();
228         if (str.isEmpty()) {
229             str = "none";
230         } else if (strcmp(str, "all") == 0) {
231             str = "both";
232         }
233         addCSSProperty(CSS_PROP_CLEAR, str);
234         break;
235     }
236     default:
237         HTMLElementImpl::parseAttribute(attr);
238     }
239 }
240 
attach()241 void HTMLBRElementImpl::attach()
242 {
243     assert(!attached());
244     assert(!m_render);
245     assert(parentNode());
246 
247     if (parentNode()->renderer() && parentNode()->renderer()->childAllowed()) {
248         RenderStyle *style = document()->styleSelector()->styleForElement(this);
249         style->ref();
250         if (style->display() != NONE) {
251             m_render = new(document()->renderArena()) RenderBR(this);
252             m_render->setStyle(style);
253             parentNode()->renderer()->addChild(m_render, nextRenderer());
254         }
255         style->deref();
256     }
257     NodeImpl::attach();
258 }
259 
260 // -------------------------------------------------------------------------
261 
id() const262 NodeImpl::Id HTMLWBRElementImpl::id() const
263 {
264     return ID_WBR;
265 }
266 
attach()267 void HTMLWBRElementImpl::attach()
268 {
269     assert(!attached());
270     assert(!m_render);
271     assert(parentNode());
272 
273     if (parentNode()->renderer() && parentNode()->renderer()->childAllowed()) {
274         RenderStyle *style = document()->styleSelector()->styleForElement(this);
275         style->ref();
276         if (style->display() != NONE) {
277             m_render = new(document()->renderArena()) RenderInline(this);
278             m_render->setStyle(style);
279             parentNode()->renderer()->addChild(m_render, nextRenderer());
280         }
281         style->deref();
282     }
283     NodeImpl::attach();
284 }
285 
286 // -------------------------------------------------------------------------
287 
id() const288 NodeImpl::Id HTMLFontElementImpl::id() const
289 {
290     return ID_FONT;
291 }
292 
parseAttribute(AttributeImpl * attr)293 void HTMLFontElementImpl::parseAttribute(AttributeImpl *attr)
294 {
295     switch (attr->id()) {
296     case ATTR_SIZE: {
297         DOMStringImpl *v = attr->val();
298         if (v) {
299             const QChar *s = v->s;
300             int num = v->toInt();
301             int len = v->l;
302             while (len && s->isSpace()) {
303                 len--, s++;
304             }
305             if (len && *s == '+') {
306                 num += 3;
307             }
308             int size;
309             switch (num) {
310             case -2:
311             case  1: size = CSS_VAL_XX_SMALL;  break;
312             case -1:
313             case  2: size = CSS_VAL_SMALL;    break;
314             case  0: // treat 0 the same as 3, because people
315             // expect it to be between -1 and +1
316             case  3: size = CSS_VAL_MEDIUM;   break;
317             case  4: size = CSS_VAL_LARGE;    break;
318             case  5: size = CSS_VAL_X_LARGE;  break;
319             case  6: size = CSS_VAL_XX_LARGE; break;
320             default:
321                 if (num > 6) {
322                     size = CSS_VAL__KHTML_XXX_LARGE;
323                 } else {
324                     size = CSS_VAL_XX_SMALL;
325                 }
326             }
327             addCSSProperty(CSS_PROP_FONT_SIZE, size);
328         }
329         break;
330     }
331     case ATTR_COLOR:
332         addHTMLColor(CSS_PROP_COLOR, attr->value());
333         break;
334     case ATTR_FACE:
335         addCSSProperty(CSS_PROP_FONT_FAMILY, attr->value());
336         break;
337     default:
338         HTMLElementImpl::parseAttribute(attr);
339     }
340 }
341 
342