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) 2003 Apple Computer, Inc.
7  *           (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25 // -------------------------------------------------------------------------
26 //#define DEBUG
27 #include "html_blockimpl.h"
28 #include "html_documentimpl.h"
29 #include "css/cssstyleselector.h"
30 
31 #include "css/cssproperties.h"
32 #include "css/cssvalues.h"
33 
34 using namespace khtml;
35 using namespace DOM;
36 
parseAttribute(AttributeImpl * attr)37 void HTMLDivElementImpl::parseAttribute(AttributeImpl *attr)
38 {
39     switch (attr->id()) {
40     case ATTR_ALIGN: {
41         DOMString v = attr->value().lower();
42         if (strcmp(v, "middle") == 0 || strcmp(v, "center") == 0) {
43             addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_CENTER);
44         } else if (strcmp(v, "left") == 0) {
45             addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_LEFT);
46         } else if (strcmp(v, "right") == 0) {
47             addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_RIGHT);
48         } else {
49             addCSSProperty(CSS_PROP_TEXT_ALIGN, v);
50         }
51         break;
52     }
53     default:
54         HTMLElementImpl::parseAttribute(attr);
55     }
56 }
57 
58 // -------------------------------------------------------------------------
59 
id() const60 NodeImpl::Id HTMLHRElementImpl::id() const
61 {
62     return ID_HR;
63 }
64 
parseAttribute(AttributeImpl * attr)65 void HTMLHRElementImpl::parseAttribute(AttributeImpl *attr)
66 {
67     switch (attr->id()) {
68     case ATTR_ALIGN: {
69         if (strcasecmp(attr->value(), "left") == 0) {
70             addCSSProperty(CSS_PROP_MARGIN_LEFT, "0");
71             addCSSProperty(CSS_PROP_MARGIN_RIGHT, CSS_VAL_AUTO);
72         } else if (strcasecmp(attr->value(), "right") == 0) {
73             addCSSProperty(CSS_PROP_MARGIN_LEFT, CSS_VAL_AUTO);
74             addCSSProperty(CSS_PROP_MARGIN_RIGHT, "0");
75         } else {
76             addCSSProperty(CSS_PROP_MARGIN_LEFT, CSS_VAL_AUTO);
77             addCSSProperty(CSS_PROP_MARGIN_RIGHT, CSS_VAL_AUTO);
78         }
79         break;
80     }
81     case ATTR_WIDTH: {
82         if (!attr->val()) {
83             break;
84         }
85         // cheap hack to cause linebreaks
86         // khtmltests/html/strange_hr.html
87         bool ok;
88         int v = attr->val()->toInt(&ok);
89         if (ok && !v) {
90             addCSSLength(CSS_PROP_WIDTH, "1");
91         } else {
92             addCSSLength(CSS_PROP_WIDTH, attr->value());
93         }
94     }
95     break;
96     default:
97         HTMLElementImpl::parseAttribute(attr);
98     }
99 }
100 
101 // ### make sure we undo what we did during detach
attach()102 void HTMLHRElementImpl::attach()
103 {
104     if (attributes(true /* readonly */)) {
105         // there are some attributes, lets check
106         DOMString color = getAttribute(ATTR_COLOR);
107         DOMStringImpl *si = getAttribute(ATTR_SIZE).implementation();
108         int _s =  si ? si->toInt() : -1;
109         DOMString n("1");
110         if (!color.isNull()) {
111             addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
112             addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
113             addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
114             addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
115             addCSSProperty(CSS_PROP_BORDER_TOP_WIDTH, DOMString("0"));
116             addCSSLength(CSS_PROP_BORDER_BOTTOM_WIDTH, DOMString(si));
117             addHTMLColor(CSS_PROP_BORDER_COLOR, color);
118         } else {
119             if (_s > 1 && getAttribute(ATTR_NOSHADE).isNull()) {
120                 addCSSProperty(CSS_PROP_BORDER_BOTTOM_WIDTH, n);
121                 addCSSProperty(CSS_PROP_BORDER_TOP_WIDTH, n);
122                 addCSSProperty(CSS_PROP_BORDER_LEFT_WIDTH, n);
123                 addCSSProperty(CSS_PROP_BORDER_RIGHT_WIDTH, n);
124                 addCSSLength(CSS_PROP_HEIGHT, DOMString(QString::number(_s - 2)));
125             } else if (_s >= 0) {
126                 addCSSProperty(CSS_PROP_BORDER_TOP_WIDTH, DOMString(QString::number(_s)));
127                 addCSSProperty(CSS_PROP_BORDER_BOTTOM_WIDTH, DOMString("0"));
128             }
129         }
130         if (_s == 0) {
131             addCSSProperty(CSS_PROP_MARGIN_BOTTOM, n);
132         }
133     }
134 
135     HTMLElementImpl::attach();
136 }
137 
138 // -------------------------------------------------------------------------
139 
width() const140 long HTMLPreElementImpl::width() const
141 {
142     // ###
143     return 0;
144 }
145 
setWidth(long)146 void HTMLPreElementImpl::setWidth(long /*w*/)
147 {
148     // ###
149 }
150 
151 // -------------------------------------------------------------------------
152 
153 // WinIE uses 60ms as the minimum delay by default.
154 const int defaultMinimumDelay = 60;
155 
HTMLMarqueeElementImpl(DocumentImpl * doc)156 HTMLMarqueeElementImpl::HTMLMarqueeElementImpl(DocumentImpl *doc)
157     : HTMLElementImpl(doc),
158       m_minimumDelay(defaultMinimumDelay)
159 {
160 }
161 
id() const162 NodeImpl::Id HTMLMarqueeElementImpl::id() const
163 {
164     return ID_MARQUEE;
165 }
166 
parseAttribute(AttributeImpl * attr)167 void HTMLMarqueeElementImpl::parseAttribute(AttributeImpl *attr)
168 {
169     switch (attr->id()) {
170     case ATTR_WIDTH:
171         if (!attr->value().isEmpty()) {
172             addCSSLength(CSS_PROP_WIDTH, attr->value());
173         } else {
174             removeCSSProperty(CSS_PROP_WIDTH);
175         }
176         break;
177     case ATTR_HEIGHT:
178         if (!attr->value().isEmpty()) {
179             addCSSLength(CSS_PROP_HEIGHT, attr->value());
180         } else {
181             removeCSSProperty(CSS_PROP_HEIGHT);
182         }
183         break;
184     case ATTR_BGCOLOR:
185         if (!attr->value().isEmpty()) {
186             addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
187         } else {
188             removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
189         }
190         break;
191     case ATTR_VSPACE:
192         if (!attr->value().isEmpty()) {
193             addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
194             addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
195         } else {
196             removeCSSProperty(CSS_PROP_MARGIN_TOP);
197             removeCSSProperty(CSS_PROP_MARGIN_BOTTOM);
198         }
199         break;
200     case ATTR_HSPACE:
201         if (!attr->value().isEmpty()) {
202             addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
203             addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
204         } else {
205             removeCSSProperty(CSS_PROP_MARGIN_LEFT);
206             removeCSSProperty(CSS_PROP_MARGIN_RIGHT);
207         }
208         break;
209     case ATTR_SCROLLAMOUNT:
210         if (!attr->value().isEmpty()) {
211             addCSSLength(CSS_PROP__KHTML_MARQUEE_INCREMENT, attr->value());
212         } else {
213             removeCSSProperty(CSS_PROP__KHTML_MARQUEE_INCREMENT);
214         }
215         break;
216     case ATTR_SCROLLDELAY:
217         if (!attr->value().isEmpty()) {
218             addCSSLength(CSS_PROP__KHTML_MARQUEE_SPEED, attr->value(), true);
219         } else {
220             removeCSSProperty(CSS_PROP__KHTML_MARQUEE_SPEED);
221         }
222         break;
223     case ATTR_LOOP:
224         if (!attr->value().isEmpty()) {
225             if (attr->value() == "-1" || strcasecmp(attr->value(), "infinite") == 0) {
226                 addCSSProperty(CSS_PROP__KHTML_MARQUEE_REPETITION, CSS_VAL_INFINITE);
227             } else {
228                 addCSSLength(CSS_PROP__KHTML_MARQUEE_REPETITION, attr->value().lower(), true);
229             }
230         } else {
231             removeCSSProperty(CSS_PROP__KHTML_MARQUEE_REPETITION);
232         }
233         break;
234     case ATTR_BEHAVIOR:
235         if (!attr->value().isEmpty()) {
236             addCSSProperty(CSS_PROP__KHTML_MARQUEE_STYLE, attr->value().lower());
237         } else {
238             removeCSSProperty(CSS_PROP__KHTML_MARQUEE_STYLE);
239         }
240         break;
241     case ATTR_DIRECTION:
242         if (!attr->value().isEmpty()) {
243             addCSSProperty(CSS_PROP__KHTML_MARQUEE_DIRECTION, attr->value().lower());
244         } else {
245             removeCSSProperty(CSS_PROP__KHTML_MARQUEE_DIRECTION);
246         }
247         break;
248     case ATTR_TRUESPEED:
249         m_minimumDelay = attr->val() ? 0 : defaultMinimumDelay;
250         break;
251     default:
252         HTMLElementImpl::parseAttribute(attr);
253     }
254 }
255 
256 // ------------------------------------------------------------------------
257 
HTMLLayerElementImpl(DocumentImpl * doc,ushort _tagid)258 HTMLLayerElementImpl::HTMLLayerElementImpl(DocumentImpl *doc, ushort _tagid)
259     : HTMLDivElementImpl(doc, _tagid)
260 {
261     transparent = fixed = false;
262 }
263 
parseAttribute(AttributeImpl * attr)264 void HTMLLayerElementImpl::parseAttribute(AttributeImpl *attr)
265 {
266     // Layers are evil
267     // They are mainly implemented here to correctly parse the hidden attribute
268     switch (attr->id()) {
269     case ATTR_LEFT:
270         addCSSProperty(CSS_PROP_LEFT, attr->value());
271         break;
272     case ATTR_TOP:
273         addCSSProperty(CSS_PROP_TOP, attr->value());
274         break;
275     case ATTR_PAGEX:
276         if (!transparent && !fixed) {
277             addCSSProperty(CSS_PROP_POSITION, CSS_VAL_FIXED);
278             fixed = true;
279         }
280         addCSSProperty(CSS_PROP_LEFT, attr->value());
281         break;
282     case ATTR_PAGEY:
283         if (!transparent && !fixed) {
284             addCSSProperty(CSS_PROP_POSITION, CSS_VAL_FIXED);
285             fixed = true;
286         }
287         addCSSProperty(CSS_PROP_TOP, attr->value());
288         break;
289     case ATTR_WIDTH:
290         if (!attr->value().isEmpty()) {
291             addCSSLength(CSS_PROP_WIDTH, attr->value());
292         } else {
293             removeCSSProperty(CSS_PROP_WIDTH);
294         }
295         break;
296     case ATTR_HEIGHT:
297         if (!attr->value().isEmpty()) {
298             addCSSLength(CSS_PROP_HEIGHT, attr->value());
299         } else {
300             removeCSSProperty(CSS_PROP_HEIGHT);
301         }
302         break;
303     case ATTR_BGCOLOR:
304         if (!attr->value().isEmpty()) {
305             addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
306         } else {
307             removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
308         }
309         break;
310     case ATTR_Z_INDEX:
311         if (!attr->value().isEmpty()) {
312             addCSSProperty(CSS_PROP_Z_INDEX, attr->value());
313         } else {
314             removeCSSProperty(CSS_PROP_Z_INDEX);
315         }
316         break;
317     case ATTR_VISIBILITY:
318         if (attr->value().lower() == "show") {
319             addCSSProperty(CSS_PROP_VISIBILITY, CSS_VAL_VISIBLE);
320         } else if (attr->value().lower() == "hide") {
321             addCSSProperty(CSS_PROP_VISIBILITY, CSS_VAL_HIDDEN);
322         } else if (attr->value().lower() == "inherit") {
323             addCSSProperty(CSS_PROP_VISIBILITY, CSS_VAL_INHERIT);
324         }
325         break;
326     case ATTR_NAME:
327         if (id() == ID_LAYER && inDocument() && m_name != attr->value()) {
328             document()->underDocNamedCache().remove(m_name,        this);
329             document()->underDocNamedCache().add(attr->value(), this);
330         }
331     //fallthrough
332     default:
333         HTMLElementImpl::parseAttribute(attr);
334     }
335 }
336 
removedFromDocument()337 void HTMLLayerElementImpl::removedFromDocument()
338 {
339     if (id() == ID_LAYER) {
340         document()->underDocNamedCache().remove(m_name, this);
341     }
342     HTMLDivElementImpl::removedFromDocument();
343 }
344 
insertedIntoDocument()345 void HTMLLayerElementImpl::insertedIntoDocument()
346 {
347     if (id() == ID_LAYER) {
348         document()->underDocNamedCache().add(m_name, this);
349     }
350     HTMLDivElementImpl::insertedIntoDocument();
351 }
352 
removeId(const DOMString & id)353 void HTMLLayerElementImpl::removeId(const DOMString &id)
354 {
355     document()->underDocNamedCache().remove(id, this);
356     HTMLDivElementImpl::removeId(id);
357 }
358 
addId(const DOMString & id)359 void HTMLLayerElementImpl::addId(const DOMString &id)
360 {
361     document()->underDocNamedCache().add(id, this);
362     HTMLDivElementImpl::addId(id);
363 }
364 
addChild(NodeImpl * child)365 NodeImpl *HTMLLayerElementImpl::addChild(NodeImpl *child)
366 {
367     NodeImpl *retval = HTMLDivElementImpl::addChild(child);
368     // When someone adds standard layers, we make sure not to interfere
369     if (retval && retval->id() == ID_DIV) {
370         if (!transparent) {
371             addCSSProperty(CSS_PROP_POSITION, CSS_VAL_STATIC);
372         }
373         transparent = true;
374     }
375     return retval;
376 }
377