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