Fix for http://bugzilla.opendarwin.org/show_bug.cgi?id=3942 and marquee problems...
[WebKit-https.git] / WebCore / khtml / html / html_blockimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  * Copyright (C) 2003 Apple Computer, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  */
24 // -------------------------------------------------------------------------
25 //#define DEBUG
26 #include "html_blockimpl.h"
27 #include "html_documentimpl.h"
28 #include "css/cssstyleselector.h"
29
30 #include "css/cssproperties.h"
31 #include "css/cssvalues.h"
32 #include "misc/htmlhashes.h"
33
34 #include <kdebug.h>
35
36 using namespace khtml;
37 using namespace DOM;
38
39 HTMLBlockquoteElementImpl::HTMLBlockquoteElementImpl(DocumentPtr *doc)
40     : HTMLElementImpl(HTMLNames::blockquote(), doc)
41 {
42 }
43
44 HTMLBlockquoteElementImpl::~HTMLBlockquoteElementImpl()
45 {
46 }
47
48 DOMString HTMLBlockquoteElementImpl::cite() const
49 {
50     return getAttribute(ATTR_CITE);
51 }
52
53 void HTMLBlockquoteElementImpl::setCite(const DOMString &value)
54 {
55     setAttribute(ATTR_CITE, value);
56 }
57
58 // -------------------------------------------------------------------------
59
60 HTMLDivElementImpl::HTMLDivElementImpl(DocumentPtr *doc)
61     : HTMLElementImpl(HTMLNames::div(), doc)
62 {
63 }
64
65 HTMLDivElementImpl::~HTMLDivElementImpl()
66 {
67 }
68
69 bool HTMLDivElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
70 {
71     if (attr == ATTR_ALIGN) {
72         result = eBlock;
73         return false;
74     }
75     return HTMLElementImpl::mapToEntry(attr, result);
76 }
77         
78 void HTMLDivElementImpl::parseMappedAttribute(MappedAttributeImpl *attr)
79 {
80     switch(attr->id())
81     {
82     case ATTR_ALIGN:
83     {
84         DOMString v = attr->value();
85         if ( strcasecmp( attr->value(), "middle" ) == 0 || strcasecmp( attr->value(), "center" ) == 0 )
86            addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_CENTER);
87         else if (strcasecmp(attr->value(), "left") == 0)
88             addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_LEFT);
89         else if (strcasecmp(attr->value(), "right") == 0)
90             addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_RIGHT);
91         else
92             addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, v);
93         break;
94     }
95     default:
96         HTMLElementImpl::parseMappedAttribute(attr);
97     }
98 }
99
100 DOMString HTMLDivElementImpl::align() const
101 {
102     return getAttribute(ATTR_ALIGN);
103 }
104
105 void HTMLDivElementImpl::setAlign(const DOMString &value)
106 {
107     setAttribute(ATTR_ALIGN, value);
108 }
109
110 // -------------------------------------------------------------------------
111
112 HTMLHRElementImpl::HTMLHRElementImpl(DocumentPtr *doc)
113     : HTMLElementImpl(HTMLNames::hr(), doc)
114 {
115 }
116
117 HTMLHRElementImpl::~HTMLHRElementImpl()
118 {
119 }
120
121 bool HTMLHRElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
122 {
123     switch (attr) {
124         case ATTR_ALIGN:
125         case ATTR_WIDTH:
126         case ATTR_COLOR:
127         case ATTR_SIZE:
128         case ATTR_NOSHADE:
129             result = eHR;
130             return false;
131         default:
132             break;
133     }
134     return HTMLElementImpl::mapToEntry(attr, result);
135 }
136
137 void HTMLHRElementImpl::parseMappedAttribute(MappedAttributeImpl *attr)
138 {
139     switch( attr->id() )
140     {
141     case ATTR_ALIGN: {
142         if (strcasecmp(attr->value(), "left") == 0) {
143             addCSSProperty(attr, CSS_PROP_MARGIN_LEFT, "0");
144             addCSSProperty(attr, CSS_PROP_MARGIN_RIGHT, CSS_VAL_AUTO);
145         }
146         else if (strcasecmp(attr->value(), "right") == 0) {
147             addCSSProperty(attr, CSS_PROP_MARGIN_LEFT, CSS_VAL_AUTO);
148             addCSSProperty(attr, CSS_PROP_MARGIN_RIGHT, "0");
149         }
150         else {
151             addCSSProperty(attr, CSS_PROP_MARGIN_LEFT, CSS_VAL_AUTO);
152             addCSSProperty(attr, CSS_PROP_MARGIN_RIGHT, CSS_VAL_AUTO);
153         }
154         break;
155     }
156     case ATTR_WIDTH:
157     {
158         // cheap hack to cause linebreaks
159         // khtmltests/html/strange_hr.html
160         bool ok;
161         int v = attr->value().implementation()->toInt(&ok);
162         if(ok && !v)
163             addCSSLength(attr, CSS_PROP_WIDTH, "1");
164         else
165             addCSSLength(attr, CSS_PROP_WIDTH, attr->value());
166         break;
167     }
168     case ATTR_COLOR:
169         addCSSProperty(attr, CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
170         addCSSProperty(attr, CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
171         addCSSProperty(attr, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
172         addCSSProperty(attr, CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
173         addCSSColor(attr, CSS_PROP_BORDER_COLOR, attr->value());
174         addCSSColor(attr, CSS_PROP_BACKGROUND_COLOR, attr->value());
175         break;
176     case ATTR_NOSHADE:
177         addCSSProperty(attr, CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
178         addCSSProperty(attr, CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
179         addCSSProperty(attr, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
180         addCSSProperty(attr, CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
181         addCSSColor(attr, CSS_PROP_BORDER_COLOR, DOMString("grey"));
182         addCSSColor(attr, CSS_PROP_BACKGROUND_COLOR, DOMString("grey"));
183         break;
184     case ATTR_SIZE: {
185         DOMStringImpl* si = attr->value().implementation();
186         int size = si->toInt();
187         if (size <= 1)
188             addCSSProperty(attr, CSS_PROP_BORDER_BOTTOM_WIDTH, DOMString("0"));
189         else
190             addCSSLength(attr, CSS_PROP_HEIGHT, DOMString(QString::number(size-2)));
191         break;
192     }
193     default:
194         HTMLElementImpl::parseMappedAttribute(attr);
195     }
196 }
197
198 DOMString HTMLHRElementImpl::align() const
199 {
200     return getAttribute(ATTR_ALIGN);
201 }
202
203 void HTMLHRElementImpl::setAlign(const DOMString &value)
204 {
205     setAttribute(ATTR_ALIGN, value);
206 }
207
208 bool HTMLHRElementImpl::noShade() const
209 {
210     return !getAttribute(ATTR_NOSHADE).isNull();
211 }
212
213 void HTMLHRElementImpl::setNoShade(bool noShade)
214 {
215     setAttribute(ATTR_NOSHADE, noShade ? "" : 0);
216 }
217
218 DOMString HTMLHRElementImpl::size() const
219 {
220     return getAttribute(ATTR_SIZE);
221 }
222
223 void HTMLHRElementImpl::setSize(const DOMString &value)
224 {
225     setAttribute(ATTR_SIZE, value);
226 }
227
228 DOMString HTMLHRElementImpl::width() const
229 {
230     return getAttribute(ATTR_WIDTH);
231 }
232
233 void HTMLHRElementImpl::setWidth(const DOMString &value)
234 {
235     setAttribute(ATTR_WIDTH, value);
236 }
237
238 // -------------------------------------------------------------------------
239
240 HTMLHeadingElementImpl::HTMLHeadingElementImpl(const QualifiedName& tagName, DocumentPtr *doc)
241     : HTMLElementImpl(tagName, doc)
242 {
243 }
244
245 bool HTMLHeadingElementImpl::checkDTD(const NodeImpl* newChild)
246 {
247     if (newChild->hasTagName(HTMLNames::h1()) || newChild->hasTagName(HTMLNames::h2()) ||
248         newChild->hasTagName(HTMLNames::h3()) || newChild->hasTagName(HTMLNames::h4()) ||
249         newChild->hasTagName(HTMLNames::h5()) || newChild->hasTagName(HTMLNames::h6()))
250         return false;
251
252     return inEitherTagList(newChild);
253 }
254
255 DOMString HTMLHeadingElementImpl::align() const
256 {
257     return getAttribute(ATTR_ALIGN);
258 }
259
260 void HTMLHeadingElementImpl::setAlign(const DOMString &value)
261 {
262     setAttribute(ATTR_ALIGN, value);
263 }
264
265 // -------------------------------------------------------------------------
266
267 HTMLParagraphElementImpl::HTMLParagraphElementImpl(DocumentPtr *doc)
268     : HTMLElementImpl(HTMLNames::p(), doc)
269 {
270 }
271
272 bool HTMLParagraphElementImpl::checkDTD(const NodeImpl* newChild)
273 {
274     return inInlineTagList(newChild) || (getDocument()->inCompatMode() && newChild->hasTagName(HTMLNames::table()));
275 }
276
277 bool HTMLParagraphElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
278 {
279     if (attr == ATTR_ALIGN) {
280         result = eBlock; // We can share with DIV here.
281         return false;
282     }
283     return HTMLElementImpl::mapToEntry(attr, result);
284 }
285
286 void HTMLParagraphElementImpl::parseMappedAttribute(MappedAttributeImpl *attr)
287 {
288     switch(attr->id())
289     {
290         case ATTR_ALIGN:
291         {
292             DOMString v = attr->value();
293             if ( strcasecmp( attr->value(), "middle" ) == 0 || strcasecmp( attr->value(), "center" ) == 0 )
294                 addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_CENTER);
295             else if (strcasecmp(attr->value(), "left") == 0)
296                 addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_LEFT);
297             else if (strcasecmp(attr->value(), "right") == 0)
298                 addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_RIGHT);
299             else
300                 addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, v);
301             break;
302         }
303         default:
304             HTMLElementImpl::parseMappedAttribute(attr);
305     }
306 }
307
308 DOMString HTMLParagraphElementImpl::align() const
309 {
310     return getAttribute(ATTR_ALIGN);
311 }
312
313 void HTMLParagraphElementImpl::setAlign(const DOMString &value)
314 {
315     setAttribute(ATTR_ALIGN, value);
316 }
317
318 // -------------------------------------------------------------------------
319
320 HTMLPreElementImpl::HTMLPreElementImpl(const QualifiedName& tagName, DocumentPtr *doc)
321     : HTMLElementImpl(tagName, doc)
322 {
323 }
324
325 long HTMLPreElementImpl::width() const
326 {
327     return getAttribute(ATTR_WIDTH).toInt();
328 }
329
330 void HTMLPreElementImpl::setWidth(long width)
331 {
332     setAttribute(ATTR_WIDTH, QString::number(width));
333 }
334
335 // -------------------------------------------------------------------------
336
337  // WinIE uses 60ms as the minimum delay by default.
338 const int defaultMinimumDelay = 60;
339
340 HTMLMarqueeElementImpl::HTMLMarqueeElementImpl(DocumentPtr *doc)
341 : HTMLElementImpl(HTMLNames::marquee(), doc),
342   m_minimumDelay(defaultMinimumDelay)
343 {
344 }
345
346 bool HTMLMarqueeElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
347 {
348     switch (attr) {
349         case ATTR_HEIGHT:   
350         case ATTR_WIDTH:
351         case ATTR_BGCOLOR:
352         case ATTR_VSPACE:
353         case ATTR_HSPACE:
354         case ATTR_SCROLLAMOUNT:
355         case ATTR_SCROLLDELAY:
356         case ATTR_LOOP:
357         case ATTR_BEHAVIOR:
358         case ATTR_DIRECTION:
359             result = eUniversal;
360             return false;
361         default:
362             break;
363     }
364     
365     return HTMLElementImpl::mapToEntry(attr, result);
366 }
367             
368 void HTMLMarqueeElementImpl::parseMappedAttribute(MappedAttributeImpl *attr)
369 {
370     switch(attr->id())
371     {
372         case ATTR_WIDTH:
373             if (!attr->value().isEmpty())
374                 addCSSLength(attr, CSS_PROP_WIDTH, attr->value());
375             break;
376         case ATTR_HEIGHT:
377             if (!attr->value().isEmpty())
378                 addCSSLength(attr, CSS_PROP_HEIGHT, attr->value());
379             break;
380         case ATTR_BGCOLOR:
381             if (!attr->value().isEmpty())
382                 addCSSColor(attr, CSS_PROP_BACKGROUND_COLOR, attr->value());
383             break;
384         case ATTR_VSPACE:
385             if (!attr->value().isEmpty()) {
386                 addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
387                 addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
388             }
389             break;
390         case ATTR_HSPACE:
391             if (!attr->value().isEmpty()) {
392                 addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
393                 addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
394             }
395             break;
396         case ATTR_SCROLLAMOUNT:
397             if (!attr->value().isEmpty())
398                 addCSSLength(attr, CSS_PROP__KHTML_MARQUEE_INCREMENT, attr->value());
399             break;
400         case ATTR_SCROLLDELAY:
401             if (!attr->value().isEmpty())
402                 addCSSLength(attr, CSS_PROP__KHTML_MARQUEE_SPEED, attr->value());
403             break;
404         case ATTR_LOOP:
405             if (!attr->value().isEmpty()) {
406                 if (attr->value() == "-1" || strcasecmp(attr->value(), "infinite") == 0)
407                     addCSSProperty(attr, CSS_PROP__KHTML_MARQUEE_REPETITION, CSS_VAL_INFINITE);
408                 else
409                     addCSSLength(attr, CSS_PROP__KHTML_MARQUEE_REPETITION, attr->value());
410             }
411             break;
412         case ATTR_BEHAVIOR:
413             if (!attr->value().isEmpty())
414                 addCSSProperty(attr, CSS_PROP__KHTML_MARQUEE_STYLE, attr->value());
415             break;
416         case ATTR_DIRECTION:
417             if (!attr->value().isEmpty())
418                 addCSSProperty(attr, CSS_PROP__KHTML_MARQUEE_DIRECTION, attr->value());
419             break;
420         case ATTR_TRUESPEED:
421             m_minimumDelay = !attr->isNull() ? 0 : defaultMinimumDelay;
422             break;
423         default:
424             HTMLElementImpl::parseMappedAttribute(attr);
425     }
426 }