WebCore:
[WebKit-https.git] / WebCore / css / cssstyleselector.cpp
1 /**
2  * This file is part of the CSS implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
6  *           (C) 2006 Nicholas Shanks (webkit@nickshanks.com)
7  * Copyright (C) 2005, 2006 Apple Computer, Inc.
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., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "config.h"
26 #include "cssstyleselector.h"
27
28 #include "CSSBorderImageValue.h"
29 #include "CSSImageValue.h"
30 #include "CSSImportRule.h"
31 #include "CSSMediaRule.h"
32 #include "CSSProperty.h"
33 #include "CSSPropertyNames.h"
34 #include "CSSRuleList.h"
35 #include "CSSSelector.h"
36 #include "CSSStyleRule.h"
37 #include "CSSStyleSheet.h"
38 #include "CSSValueKeywords.h"
39 #include "CSSValueList.h"
40 #include "CachedImage.h"
41 #include "DashboardRegion.h"
42 #include "FontFamilyValue.h"
43 #include "FontValue.h"
44 #include "Frame.h"
45 #include "HTMLDocument.h"
46 #include "HTMLElement.h"
47 #include "HTMLInputElement.h"
48 #include "HTMLNames.h"
49 #include "History.h"
50 #include "KWQKHTMLSettings.h"
51 #include "MediaList.h"
52 #include "MediaQueryEvaluator.h"
53 #include "Pair.h"
54 #include "RectImpl.h"
55 #include "RenderTheme.h"
56 #include "StyleSheetList.h"
57 #include "UserAgentStyleSheets.h"
58 #include "loader.h"
59 #include "ShadowValue.h"
60
61 using namespace std;
62
63 namespace WebCore {
64
65 using namespace HTMLNames;
66
67 // #define STYLE_SHARING_STATS 1
68
69 #define HANDLE_INHERIT(prop, Prop) \
70 if (isInherit) { \
71     style->set##Prop(parentStyle->prop()); \
72     return; \
73 }
74
75 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
76 HANDLE_INHERIT(prop, Prop) \
77 if (isInitial) { \
78     style->set##Prop(RenderStyle::initial##Prop()); \
79     return; \
80 }
81
82 #define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \
83 HANDLE_INHERIT(prop, Prop) \
84 if (isInitial) { \
85     style->set##Prop(RenderStyle::initial##Value());\
86     return;\
87 }
88
89 #define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
90 if (isInherit) { \
91     BackgroundLayer* currChild = style->accessBackgroundLayers(); \
92     BackgroundLayer* prevChild = 0; \
93     const BackgroundLayer* currParent = parentStyle->backgroundLayers(); \
94     while (currParent && currParent->is##Prop##Set()) { \
95         if (!currChild) { \
96             /* Need to make a new layer.*/ \
97             currChild = new BackgroundLayer(); \
98             prevChild->setNext(currChild); \
99         } \
100         currChild->set##Prop(currParent->prop()); \
101         prevChild = currChild; \
102         currChild = prevChild->next(); \
103         currParent = currParent->next(); \
104     } \
105     \
106     while (currChild) { \
107         /* Reset any remaining layers to not have the property set. */ \
108         currChild->clear##Prop(); \
109         currChild = currChild->next(); \
110     } \
111     return; \
112 } \
113 if (isInitial) { \
114     BackgroundLayer* currChild = style->accessBackgroundLayers(); \
115     currChild->set##Prop(RenderStyle::initial##Prop()); \
116     for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
117         currChild->clear##Prop(); \
118     return; \
119 }
120
121 #define HANDLE_BACKGROUND_VALUE(prop, Prop, value) { \
122 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
123 if (!value->isPrimitiveValue() && !value->isValueList()) \
124     return; \
125 BackgroundLayer* currChild = style->accessBackgroundLayers(); \
126 BackgroundLayer* prevChild = 0; \
127 if (value->isPrimitiveValue()) { \
128     map##Prop(currChild, value); \
129     currChild = currChild->next(); \
130 } \
131 else { \
132     /* Walk each value and put it into a layer, creating new layers as needed. */ \
133     CSSValueList* valueList = static_cast<CSSValueList*>(value); \
134     for (unsigned int i = 0; i < valueList->length(); i++) { \
135         if (!currChild) { \
136             /* Need to make a new layer to hold this value */ \
137             currChild = new BackgroundLayer(); \
138             prevChild->setNext(currChild); \
139         } \
140         map##Prop(currChild, valueList->item(i)); \
141         prevChild = currChild; \
142         currChild = currChild->next(); \
143     } \
144 } \
145 while (currChild) { \
146     /* Reset all remaining layers to not have the property set. */ \
147     currChild->clear##Prop(); \
148     currChild = currChild->next(); \
149 } }
150
151 #define HANDLE_INHERIT_COND(propID, prop, Prop) \
152 if (id == propID) { \
153     style->set##Prop(parentStyle->prop()); \
154     return; \
155 }
156
157 #define HANDLE_INITIAL_COND(propID, Prop) \
158 if (id == propID) { \
159     style->set##Prop(RenderStyle::initial##Prop()); \
160     return; \
161 }
162
163 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \
164 if (id == propID) { \
165     style->set##Prop(RenderStyle::initial##Value()); \
166     return; \
167 }
168
169 class CSSRuleSet
170 {
171 public:
172     CSSRuleSet();
173     ~CSSRuleSet();
174     
175     typedef HashMap<AtomicStringImpl*, CSSRuleDataList*> AtomRuleMap;
176     
177     void addRulesFromSheet(CSSStyleSheet* sheet, MediaQueryEvaluator* medium);
178     
179     void addRule(CSSStyleRule* rule, CSSSelector* sel);
180     void addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
181                       CSSStyleRule* rule, CSSSelector* sel);
182     
183     CSSRuleDataList* getIDRules(AtomicStringImpl* key) { return m_idRules.get(key); }
184     CSSRuleDataList* getClassRules(AtomicStringImpl* key) { return m_classRules.get(key); }
185     CSSRuleDataList* getTagRules(AtomicStringImpl* key) { return m_tagRules.get(key); }
186     CSSRuleDataList* getUniversalRules() { return m_universalRules; }
187     
188 public:
189     AtomRuleMap m_idRules;
190     AtomRuleMap m_classRules;
191     AtomRuleMap m_tagRules;
192     CSSRuleDataList* m_universalRules;
193     
194     unsigned m_ruleCount;
195 };
196
197 CSSRuleSet* CSSStyleSelector::defaultStyle = 0;
198 CSSRuleSet* CSSStyleSelector::defaultQuirksStyle = 0;
199 CSSRuleSet* CSSStyleSelector::defaultPrintStyle = 0;
200 CSSRuleSet* CSSStyleSelector::defaultViewSourceStyle = 0;
201
202 CSSStyleSheet* CSSStyleSelector::defaultSheet = 0;
203 RenderStyle* CSSStyleSelector::styleNotYetAvailable = 0;
204 CSSStyleSheet* CSSStyleSelector::quirksSheet = 0;
205 CSSStyleSheet* CSSStyleSelector::viewSourceSheet = 0;
206
207 #if SVG_SUPPORT
208 CSSStyleSheet *CSSStyleSelector::svgSheet = 0;
209 #endif
210
211 static CSSStyleSelector::Encodedurl *currentEncodedURL = 0;
212 static PseudoState pseudoState;
213
214 CSSStyleSelector::CSSStyleSelector(Document* doc, const String& userStyleSheet, StyleSheetList *styleSheets, bool _strictParsing)
215 {
216     init();
217
218     view = doc->view();
219     strictParsing = _strictParsing;
220     settings = view ? view->frame()->settings() : 0;
221     if (!defaultStyle)
222         loadDefaultStyle();
223
224     m_userStyle = 0;
225     m_userSheet = 0;
226
227     // construct document root element default style. this is needed
228     // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
229     // This is here instead of constructor, because when constructor is run,
230     // document doesn't have documentElement
231     // NOTE: this assumes that element that gets passed to styleForElement -call
232     // is always from the document that owns the style selector
233     if (view)
234         m_medium = new MediaQueryEvaluator(view->mediaType());
235     else
236         m_medium = new MediaQueryEvaluator("all");
237
238     Element* root = doc->documentElement();
239
240     if (root)
241         m_rootDefaultStyle = styleForElement(root, 0, false, true); // dont ref, because the RenderStyle is allocated from global heap
242
243     if (m_rootDefaultStyle && view) {
244         delete m_medium;
245         m_medium = new MediaQueryEvaluator(view->mediaType(), view, m_rootDefaultStyle);
246     }
247
248
249     // FIXME: This sucks! The user sheet is reparsed every time!
250     if (!userStyleSheet.isEmpty()) {
251         m_userSheet = new CSSStyleSheet(doc);
252         m_userSheet->parseString(userStyleSheet, strictParsing);
253
254         m_userStyle = new CSSRuleSet();
255         m_userStyle->addRulesFromSheet(m_userSheet, m_medium);
256     }
257
258     // add stylesheets from document
259     m_authorStyle = new CSSRuleSet();
260
261     DeprecatedPtrListIterator<StyleSheet> it(styleSheets->styleSheets);
262     for (; it.current(); ++it)
263         if (it.current()->isCSSStyleSheet() && !it.current()->disabled())
264             m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(it.current()), m_medium);
265
266 }
267
268 CSSStyleSelector::CSSStyleSelector(CSSStyleSheet *sheet)
269 {
270     init();
271
272     if (!defaultStyle)
273         loadDefaultStyle();
274     FrameView *view = sheet->doc()->view();
275
276     if (view)
277         m_medium = new MediaQueryEvaluator(view->mediaType());
278     else
279         m_medium = new MediaQueryEvaluator("all");
280
281     Element* root = sheet->doc()->documentElement();
282     if (root)
283         m_rootDefaultStyle = styleForElement(root, 0, false, true);
284
285     if (m_rootDefaultStyle && view) {
286         delete m_medium;
287         m_medium = new MediaQueryEvaluator(view->mediaType(), view, m_rootDefaultStyle);
288     }
289
290     m_authorStyle = new CSSRuleSet();
291     m_authorStyle->addRulesFromSheet(sheet, m_medium);
292 }
293
294 void CSSStyleSelector::init()
295 {
296     element = 0;
297     settings = 0;
298     m_matchedRules.clear();
299     m_matchedDecls.clear();
300     m_ruleList = 0;
301     m_collectRulesOnly = false;
302     m_rootDefaultStyle = 0;
303     m_medium = 0;
304 }
305
306 void CSSStyleSelector::setEncodedURL(const KURL& url)
307 {
308     KURL u = url;
309
310     u.setQuery(DeprecatedString::null);
311     u.setRef(DeprecatedString::null);
312     encodedurl.file = u.url();
313     int pos = encodedurl.file.findRev('/');
314     encodedurl.path = encodedurl.file;
315     if (pos > 0) {
316         encodedurl.path.truncate(pos);
317         encodedurl.path += '/';
318     }
319     u.setPath(DeprecatedString::null);
320     encodedurl.host = u.url();
321 }
322
323 CSSStyleSelector::~CSSStyleSelector()
324 {
325     delete m_medium;
326     ::delete m_rootDefaultStyle;
327
328     delete m_authorStyle;
329     delete m_userStyle;
330     delete m_userSheet;
331 }
332
333 static CSSStyleSheet* parseUASheet(const char* characters, unsigned size)
334 {
335     CSSStyleSheet* const parent = 0;
336     CSSStyleSheet* sheet = new CSSStyleSheet(parent);
337     sheet->ref(); // leak the sheet on purpose since it will be stored in a global variable
338     sheet->parseString(String(characters, size));
339     return sheet;
340 }
341
342 template<typename T> CSSStyleSheet* parseUASheet(const T& array)
343 {
344     return parseUASheet(array, sizeof(array));
345 }
346
347 void CSSStyleSelector::loadDefaultStyle()
348 {
349     if (defaultStyle)
350         return;
351
352     defaultStyle = new CSSRuleSet;
353     defaultPrintStyle = new CSSRuleSet;
354     defaultQuirksStyle = new CSSRuleSet;
355     defaultViewSourceStyle = new CSSRuleSet;
356
357     MediaQueryEvaluator screenEval("screen");
358     MediaQueryEvaluator printEval("print");
359
360     // Strict-mode rules.
361     defaultSheet = parseUASheet(html4UserAgentStyleSheet);
362     defaultStyle->addRulesFromSheet(defaultSheet, &screenEval);
363     defaultPrintStyle->addRulesFromSheet(defaultSheet, &printEval);
364
365 #if SVG_SUPPORT
366     // SVG rules.
367     svgSheet = parseUASheet(svgUserAgentStyleSheet);
368     defaultStyle->addRulesFromSheet(svgSheet, &screenEval);
369     defaultPrintStyle->addRulesFromSheet(svgSheet, &printEval);
370 #endif
371
372     // Quirks-mode rules.
373     quirksSheet = parseUASheet(quirksUserAgentStyleSheet);
374     defaultQuirksStyle->addRulesFromSheet(quirksSheet, &screenEval);
375     
376     // View source rules.
377     viewSourceSheet = parseUASheet(sourceUserAgentStyleSheet);
378     defaultViewSourceStyle->addRulesFromSheet(viewSourceSheet, &screenEval);
379 }
380
381 void CSSStyleSelector::matchRules(CSSRuleSet* rules, int& firstRuleIndex, int& lastRuleIndex)
382 {
383     m_matchedRules.clear();
384
385     if (!rules || !element)
386         return;
387     
388     // We need to collect the rules for id, class, tag, and everything else into a buffer and
389     // then sort the buffer.
390     if (element->hasID())
391         matchRulesForList(rules->getIDRules(element->getIDAttribute().impl()), firstRuleIndex, lastRuleIndex);
392     if (element->hasClass()) {
393         for (const AtomicStringList* singleClass = element->getClassList(); singleClass; singleClass = singleClass->next())
394             matchRulesForList(rules->getClassRules(singleClass->string().impl()), firstRuleIndex, lastRuleIndex);
395     }
396     matchRulesForList(rules->getTagRules(element->localName().impl()), firstRuleIndex, lastRuleIndex);
397     matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex);
398     
399     // If we didn't match any rules, we're done.
400     if (m_matchedRules.isEmpty())
401         return;
402     
403     // Sort the set of matched rules.
404     sortMatchedRules(0, m_matchedRules.size());
405     
406     // Now transfer the set of matched rules over to our list of decls.
407     if (!m_collectRulesOnly) {
408         for (unsigned i = 0; i < m_matchedRules.size(); i++)
409             addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
410     } else {
411         for (unsigned i = 0; i < m_matchedRules.size(); i++) {
412             if (!m_ruleList)
413                 m_ruleList = new CSSRuleList();
414             m_ruleList->append(m_matchedRules[i]->rule());
415         }
416     }
417 }
418
419 void CSSStyleSelector::matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex)
420 {
421     if (!rules)
422         return;
423
424     for (CSSRuleData* d = rules->first(); d; d = d->next()) {
425         CSSStyleRule* rule = d->rule();
426         const AtomicString& localName = element->localName();
427         const AtomicString& selectorLocalName = d->selector()->tag.localName();
428         if ((localName == selectorLocalName || selectorLocalName == starAtom) && checkSelector(d->selector(), element)) {
429             // If the rule has no properties to apply, then ignore it.
430             CSSMutableStyleDeclaration* decl = rule->declaration();
431             if (!decl || !decl->length())
432                 continue;
433             
434             // If we're matching normal rules, set a pseudo bit if 
435             // we really just matched a pseudo-element.
436             if (dynamicPseudo != RenderStyle::NOPSEUDO && pseudoStyle == RenderStyle::NOPSEUDO) {
437                 if (m_collectRulesOnly)
438                     return;
439                 style->setHasPseudoStyle(dynamicPseudo);
440             } else {
441                 // Update our first/last rule indices in the matched rules array.
442                 lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size();
443                 if (firstRuleIndex == -1)
444                     firstRuleIndex = lastRuleIndex;
445
446                 // Add this rule to our list of matched rules.
447                 addMatchedRule(d);
448             }
449         }
450     }
451 }
452
453 bool operator >(CSSRuleData& r1, CSSRuleData& r2)
454 {
455     int spec1 = r1.selector()->specificity();
456     int spec2 = r2.selector()->specificity();
457     return (spec1 == spec2) ? r1.position() > r2.position() : spec1 > spec2; 
458 }
459 bool operator <=(CSSRuleData& r1, CSSRuleData& r2)
460 {
461     return !(r1 > r2);
462 }
463
464 void CSSStyleSelector::sortMatchedRules(unsigned start, unsigned end)
465 {
466     if (start >= end || (end - start == 1))
467         return; // Sanity check.
468
469     if (end - start <= 6) {
470         // Apply a bubble sort for smaller lists.
471         for (unsigned i = end - 1; i > start; i--) {
472             bool sorted = true;
473             for (unsigned j = start; j < i; j++) {
474                 CSSRuleData* elt = m_matchedRules[j];
475                 CSSRuleData* elt2 = m_matchedRules[j + 1];
476                 if (*elt > *elt2) {
477                     sorted = false;
478                     m_matchedRules[j] = elt2;
479                     m_matchedRules[j + 1] = elt;
480                 }
481             }
482             if (sorted)
483                 return;
484         }
485         return;
486     }
487
488     // Peform a merge sort for larger lists.
489     unsigned mid = (start + end) / 2;
490     sortMatchedRules(start, mid);
491     sortMatchedRules(mid, end);
492     
493     CSSRuleData* elt = m_matchedRules[mid - 1];
494     CSSRuleData* elt2 = m_matchedRules[mid];
495     
496     // Handle the fast common case (of equal specificity).  The list may already
497     // be completely sorted.
498     if (*elt <= *elt2)
499         return;
500     
501     // We have to merge sort.  Ensure our merge buffer is big enough to hold
502     // all the items.
503     Vector<CSSRuleData*> rulesMergeBuffer;
504     rulesMergeBuffer.reserveCapacity(end - start); 
505
506     unsigned i1 = start;
507     unsigned i2 = mid;
508     
509     elt = m_matchedRules[i1];
510     elt2 = m_matchedRules[i2];
511     
512     while (i1 < mid || i2 < end) {
513         if (i1 < mid && (i2 == end || *elt <= *elt2)) {
514             rulesMergeBuffer.append(elt);
515             if (++i1 < mid)
516                 elt = m_matchedRules[i1];
517         } else {
518             rulesMergeBuffer.append(elt2);
519             if (++i2 < end)
520                 elt2 = m_matchedRules[i2];
521         }
522     }
523     
524     for (unsigned i = start; i < end; i++)
525         m_matchedRules[i] = rulesMergeBuffer[i - start];
526 }
527
528 void CSSStyleSelector::initElementAndPseudoState(Element* e)
529 {
530     element = e;
531     if (element && element->isStyledElement())
532         styledElement = static_cast<StyledElement*>(element);
533     else
534         styledElement = 0;
535     currentEncodedURL = &encodedurl;
536     pseudoState = PseudoUnknown;
537 }
538
539 void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* defaultParent)
540 {
541     // set some variables we will need
542     pseudoStyle = RenderStyle::NOPSEUDO;
543
544     parentNode = e->parentNode();
545     if (defaultParent)
546         parentStyle = defaultParent;
547     else
548         parentStyle = parentNode ? parentNode->renderStyle() : 0;
549     view = element->document()->view();
550     isXMLDoc = !element->document()->isHTMLDocument();
551     frame = element->document()->frame();
552     settings = frame ? frame->settings() : 0;
553
554     style = 0;
555     
556     m_matchedRules.clear();
557     m_matchedDecls.clear();
558
559     m_ruleList = 0;
560
561     fontDirty = false;
562 }
563
564 // modified version of the one in kurl.cpp
565 static void cleanpath(DeprecatedString &path)
566 {
567     int pos;
568     while ((pos = path.find("/../")) != -1) {
569         int prev = 0;
570         if (pos > 0)
571             prev = path.findRev("/", pos -1);
572         // don't remove the host, i.e. http://foo.org/../foo.html
573         if (prev < 0 || (prev > 3 && path.findRev("://", prev-1) == prev-2))
574             path.remove(pos, 3);
575         else
576             // matching directory found ?
577             path.remove(prev, pos- prev + 3);
578     }
579     pos = 0;
580     
581     // Don't remove "//" from an anchor identifier. -rjw
582     // Set refPos to -2 to mean "I haven't looked for the anchor yet".
583     // We don't want to waste a function call on the search for the the anchor
584     // in the vast majority of cases where there is no "//" in the path.
585     int refPos = -2;
586     while ((pos = path.find("//", pos)) != -1) {
587         if (refPos == -2)
588             refPos = path.find("#");
589         if (refPos > 0 && pos >= refPos)
590             break;
591         
592         if (pos == 0 || path[pos-1] != ':')
593             path.remove(pos, 1);
594         else
595             pos += 2;
596     }
597     while ((pos = path.find("/./")) != -1)
598         path.remove(pos, 2);
599 }
600
601 static void checkPseudoState(Element *e, bool checkVisited = true)
602 {
603     if (!e->isLink()) {
604         pseudoState = PseudoNone;
605         return;
606     }
607     
608     const AtomicString& attr = e->getAttribute(hrefAttr);
609     if (attr.isNull()) {
610         pseudoState = PseudoNone;
611         return;
612     }
613     
614     if (!checkVisited) {
615         pseudoState = PseudoAnyLink;
616         return;
617     }
618     
619     QConstString cu(reinterpret_cast<const QChar*>(attr.characters()), attr.length());
620     DeprecatedString u = cu.string();
621     if (!u.contains("://")) {
622         if (u[0] == '/')
623             u.prepend(currentEncodedURL->host);
624         else if (u[0] == '#')
625             u.prepend(currentEncodedURL->file);
626         else
627             u.prepend(currentEncodedURL->path);
628         cleanpath(u);
629     }
630     pseudoState = historyContains(u) ? PseudoVisited : PseudoLink;
631 }
632
633 #ifdef STYLE_SHARING_STATS
634 static int fraction = 0;
635 static int total = 0;
636 #endif
637
638 const int siblingThreshold = 10;
639
640 Node* CSSStyleSelector::locateCousinList(Element* parent)
641 {
642     if (parent && parent->isStyledElement()) {
643         StyledElement* p = static_cast<StyledElement*>(parent);
644         if (!p->inlineStyleDecl() && !p->hasID()) {
645             Node* r = p->previousSibling();
646             int subcount = 0;
647             RenderStyle* st = p->renderStyle();
648             while (r) {
649                 if (r->renderStyle() == st)
650                     return r->lastChild();
651                 if (subcount++ == siblingThreshold)
652                     return 0;
653                 r = r->previousSibling();
654             }
655             if (!r)
656                 r = locateCousinList(static_cast<Element*>(parent->parentNode()));
657             while (r) {
658                 if (r->renderStyle() == st)
659                     return r->lastChild();
660                 if (subcount++ == siblingThreshold)
661                     return 0;
662                 r = r->previousSibling();
663             }
664         }
665     }
666     return 0;
667 }
668
669 bool CSSStyleSelector::canShareStyleWithElement(Node* n)
670 {
671     if (n->isStyledElement()) {
672         StyledElement* s = static_cast<StyledElement*>(n);
673         RenderStyle* style = s->renderStyle();
674         if (style && !style->unique() &&
675             (s->tagQName() == element->tagQName()) && !s->hasID() &&
676             (s->hasClass() == element->hasClass()) && !s->inlineStyleDecl() &&
677             (s->hasMappedAttributes() == styledElement->hasMappedAttributes()) &&
678             (s->isLink() == element->isLink()) && 
679             !style->affectedByAttributeSelectors() &&
680             (s->hovered() == element->hovered()) &&
681             (s->active() == element->active()) &&
682             (s->focused() == element->focused()) &&
683             (s->isEnabled() == element->isEnabled()) &&
684             (s->isIndeterminate() == element->isIndeterminate()) &&
685             (s->isChecked() == element->isChecked()) &&
686             (s != s->document()->getCSSTarget() && element != element->document()->getCSSTarget()) &&
687             (s->getAttribute(typeAttr) == element->getAttribute(typeAttr))) {
688             bool classesMatch = true;
689             if (s->hasClass()) {
690                 const AtomicString& class1 = element->getAttribute(classAttr);
691                 const AtomicString& class2 = s->getAttribute(classAttr);
692                 classesMatch = (class1 == class2);
693             }
694             
695             if (classesMatch) {
696                 bool mappedAttrsMatch = true;
697                 if (s->hasMappedAttributes())
698                     mappedAttrsMatch = s->mappedAttributes()->mapsEquivalent(styledElement->mappedAttributes());
699                 if (mappedAttrsMatch) {
700                     bool linksMatch = true;
701                     if (s->isLink()) {
702                         // We need to check to see if the visited state matches.
703                         Color linkColor = element->document()->linkColor();
704                         Color visitedColor = element->document()->visitedLinkColor();
705                         if (pseudoState == PseudoUnknown)
706                             checkPseudoState(element, style->pseudoState() != PseudoAnyLink ||
707                                              linkColor != visitedColor);
708                         linksMatch = (pseudoState == style->pseudoState());
709                     }
710                     
711                     if (linksMatch)
712                         return true;
713                 }
714             }
715         }
716     }
717     return false;
718 }
719
720 RenderStyle* CSSStyleSelector::locateSharedStyle()
721 {
722     if (styledElement && !styledElement->inlineStyleDecl() && !styledElement->hasID() &&
723         !styledElement->document()->usesSiblingRules()) {
724         // Check previous siblings.
725         int count = 0;
726         Node* n;
727         for (n = element->previousSibling(); n && !n->isElementNode(); n = n->previousSibling());
728         while (n) {
729             if (canShareStyleWithElement(n))
730                 return n->renderStyle();
731             if (count++ == siblingThreshold)
732                 return 0;
733             for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling());
734         }
735         if (!n) 
736             n = locateCousinList(static_cast<Element*>(element->parentNode()));
737         while (n) {
738             if (canShareStyleWithElement(n))
739                 return n->renderStyle();
740             if (count++ == siblingThreshold)
741                 return 0;
742             for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling());
743         }        
744     }
745     return 0;
746 }
747
748 void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule)
749 {
750     // 1. First we match rules from the user agent sheet.
751     matchRules(defaultStyle, firstUARule, lastUARule);
752
753     // 2. In quirks mode, we match rules from the quirks user agent sheet.
754     if (!strictParsing)
755         matchRules(defaultQuirksStyle, firstUARule, lastUARule);
756
757     // 3. If our medium is print, then we match rules from the print sheet.
758     if (m_medium->mediaTypeMatch("print"))
759         matchRules(defaultPrintStyle, firstUARule, lastUARule);
760         
761     // 4. If we're in view source mode, then we match rules from the view source style sheet.
762     if (view && view->frame() && view->frame()->inViewSourceMode())
763         matchRules(defaultViewSourceStyle, firstUARule, lastUARule);
764 }
765
766 // If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where
767 // relative units are interpreted according to document root element style, styled only with UA stylesheet
768
769 RenderStyle* CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault)
770 {
771     if (allowSharing && !e->document()->haveStylesheetsLoaded()) {
772         if (!styleNotYetAvailable) {
773             styleNotYetAvailable = ::new RenderStyle();
774             styleNotYetAvailable->setDisplay(NONE);
775             styleNotYetAvailable->ref();
776         }
777         styleNotYetAvailable->ref();
778         return styleNotYetAvailable;
779     }
780     
781     initElementAndPseudoState(e);
782     if (allowSharing) {
783         style = locateSharedStyle();
784 #ifdef STYLE_SHARING_STATS
785         fraction += style != 0;
786         total++;
787         printf("Sharing %d out of %d\n", fraction, total);
788 #endif
789         if (style) {
790             style->ref();
791             return style;
792         }
793     }
794     initForStyleResolve(e, defaultParent);
795
796     if (resolveForRootDefault) {
797         style = ::new RenderStyle();
798         // don't ref, because we want to delete this, but we cannot unref it
799     } else {
800         style = new (e->document()->renderArena()) RenderStyle();
801         style->ref();
802     }
803     if (parentStyle)
804         style->inheritFrom(parentStyle);
805     else
806         parentStyle = style;
807
808     int firstUARule = -1, lastUARule = -1;
809     int firstUserRule = -1, lastUserRule = -1;
810     int firstAuthorRule = -1, lastAuthorRule = -1;
811     matchUARules(firstUARule, lastUARule);
812
813     if (!resolveForRootDefault) {
814         // 4. Now we check user sheet rules.
815         matchRules(m_userStyle, firstUserRule, lastUserRule);
816
817         // 5. Now check author rules, beginning first with presentational attributes
818         // mapped from HTML.
819         if (styledElement) {
820             // Ask if the HTML element has mapped attributes.
821             if (styledElement->hasMappedAttributes()) {
822                 // Walk our attribute list and add in each decl.
823                 const NamedMappedAttrMap* map = styledElement->mappedAttributes();
824                 for (unsigned i = 0; i < map->length(); i++) {
825                     MappedAttribute* attr = map->attributeItem(i);
826                     if (attr->decl()) {
827                         lastAuthorRule = m_matchedDecls.size();
828                         if (firstAuthorRule == -1)
829                             firstAuthorRule = lastAuthorRule;
830                         addMatchedDeclaration(attr->decl());
831                     }
832                 }
833             }
834
835             // Now we check additional mapped declarations.
836             // Tables and table cells share an additional mapped rule that must be applied
837             // after all attributes, since their mapped style depends on the values of multiple attributes.
838             CSSMutableStyleDeclaration* attributeDecl = styledElement->additionalAttributeStyleDecl();
839             if (attributeDecl) {
840                 lastAuthorRule = m_matchedDecls.size();
841                 if (firstAuthorRule == -1)
842                     firstAuthorRule = lastAuthorRule;
843                 addMatchedDeclaration(attributeDecl);
844             }
845         }
846     
847         // 6. Check the rules in author sheets next.
848         matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
849     
850         // 7. Now check our inline style attribute.
851         if (styledElement) {
852             CSSMutableStyleDeclaration* inlineDecl = styledElement->inlineStyleDecl();
853             if (inlineDecl) {
854                 lastAuthorRule = m_matchedDecls.size();
855                 if (firstAuthorRule == -1)
856                     firstAuthorRule = lastAuthorRule;
857                 addMatchedDeclaration(inlineDecl);
858             }
859         }
860     }
861
862     // Now we have all of the matched rules in the appropriate order.  Walk the rules and apply
863     // high-priority properties first, i.e., those properties that other properties depend on.
864     // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
865     // and (4) normal important.
866     applyDeclarations(true, false, 0, m_matchedDecls.size() - 1);
867     if (!resolveForRootDefault) {
868         applyDeclarations(true, true, firstAuthorRule, lastAuthorRule);
869         applyDeclarations(true, true, firstUserRule, lastUserRule);
870     }
871     applyDeclarations(true, true, firstUARule, lastUARule);
872     
873     // If our font got dirtied, go ahead and update it now.
874     if (fontDirty)
875         updateFont();
876     
877     // Now do the normal priority UA properties.
878     applyDeclarations(false, false, firstUARule, lastUARule);
879     
880     // Cache our border and background so that we can examine them later.
881     cacheBorderAndBackground();
882     
883     // Now do the author and user normal priority properties and all the !important properties.
884     if (!resolveForRootDefault) {
885         applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1);
886         applyDeclarations(false, true, firstAuthorRule, lastAuthorRule);
887         applyDeclarations(false, true, firstUserRule, lastUserRule);
888     }
889     applyDeclarations(false, true, firstUARule, lastUARule);
890     
891     // If our font got dirtied by one of the non-essential font props, 
892     // go ahead and update it a second time.
893     if (fontDirty)
894         updateFont();
895     
896     // Clean up our style object's display and text decorations (among other fixups).
897     adjustRenderStyle(style, e);
898
899     // If we are a link, cache the determined pseudo-state.
900     if (e->isLink())
901         style->setPseudoState(pseudoState);
902
903     // Now return the style.
904     return style;
905 }
906
907 RenderStyle* CSSStyleSelector::pseudoStyleForElement(RenderStyle::PseudoId pseudo, Element* e, RenderStyle* parentStyle)
908 {
909     if (!e)
910         return 0;
911
912     initElementAndPseudoState(e);
913     initForStyleResolve(e, parentStyle);
914     pseudoStyle = pseudo;
915     
916     // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
917     // those rules.
918     
919     // Check UA, user and author rules.
920     int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1;
921     matchRules(defaultStyle, firstUARule, lastUARule);
922     matchRules(m_userStyle, firstUserRule, lastUserRule);
923     matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
924     
925     if (m_matchedDecls.isEmpty())
926         return 0;
927     
928     style = new (e->document()->renderArena()) RenderStyle();
929     style->ref();
930     if (parentStyle)
931         style->inheritFrom(parentStyle);
932     else
933         parentStyle = style;
934     style->noninherited_flags._styleType = pseudoStyle;
935     
936     // High-priority properties.
937     applyDeclarations(true, false, 0, m_matchedDecls.size() - 1);
938     applyDeclarations(true, true, firstAuthorRule, lastAuthorRule);
939     applyDeclarations(true, true, firstUserRule, lastUserRule);
940     applyDeclarations(true, true, firstUARule, lastUARule);
941     
942     // If our font got dirtied, go ahead and update it now.
943     if (fontDirty)
944         updateFont();
945     
946     // Now do the normal priority properties.
947     applyDeclarations(false, false, firstUARule, lastUARule);
948     
949     // Cache our border and background so that we can examine them later.
950     cacheBorderAndBackground();
951     
952     applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1);
953     applyDeclarations(false, true, firstAuthorRule, lastAuthorRule);
954     applyDeclarations(false, true, firstUserRule, lastUserRule);
955     applyDeclarations(false, true, firstUARule, lastUARule);
956     
957     // If our font got dirtied by one of the non-essential font props, 
958     // go ahead and update it a second time.
959     if (fontDirty)
960         updateFont();
961     // Clean up our style object's display and text decorations (among other fixups).
962     adjustRenderStyle(style, 0);
963
964     // Now return the style.
965     return style;
966 }
967
968 void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, Element *e)
969 {
970     // Cache our original display.
971     style->setOriginalDisplay(style->display());
972
973     if (style->display() != NONE) {
974         // If we have a <td> that specifies a float property, in quirks mode we just drop the float
975         // property.
976         // Sites also commonly use display:inline/block on <td>s and <table>s.  In quirks mode we force
977         // these tags to retain their display types.
978         if (!strictParsing && e) {
979             if (e->hasTagName(tdTag)) {
980                 style->setDisplay(TABLE_CELL);
981                 style->setFloating(FNONE);
982             }
983             else if (e->hasTagName(tableTag))
984                 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
985         }
986
987         // Frames and framesets never honor position:relative or position:absolute.  This is necessary to
988         // fix a crash where a site tries to position these objects.  They also never honor display.
989         if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
990             style->setPosition(StaticPosition);
991             style->setDisplay(BLOCK);
992         }
993
994         // Table headers with a text-align of auto will change the text-align to center.
995         if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO)
996             style->setTextAlign(CENTER);
997         
998         // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to
999         // position or float an inline, compact, or run-in.  Cache the original display, since it
1000         // may be needed for positioned elements that have to compute their static normal flow
1001         // positions.  We also force inline-level roots to be block-level.
1002         if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX &&
1003             (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE ||
1004              (e && e->document()->documentElement() == e))) {
1005             if (style->display() == INLINE_TABLE)
1006                 style->setDisplay(TABLE);
1007             else if (style->display() == INLINE_BOX)
1008                 style->setDisplay(BOX);
1009             else if (style->display() == LIST_ITEM) {
1010                 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk,
1011                 // but only in quirks mode.
1012                 if (!strictParsing && style->floating() != FNONE)
1013                     style->setDisplay(BLOCK);
1014             }
1015             else
1016                 style->setDisplay(BLOCK);
1017         }
1018         
1019         // After performing the display mutation, check table rows.  We do not honor position:relative on
1020         // table rows or cells.  This has been established in CSS2.1 (and caused a crash in containingBlock()
1021         // on some sites).
1022         if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP ||
1023              style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_CELL) &&
1024              style->position() == RelativePosition)
1025             style->setPosition(StaticPosition);
1026     }
1027
1028     // Make sure our z-index value is only applied if the object is positioned,
1029     // relatively positioned, or transparent.
1030     if (style->position() == StaticPosition && style->opacity() == 1.0f)
1031         style->setHasAutoZIndex();
1032
1033     // Auto z-index becomes 0 for the root element and transparent objects.  This prevents
1034     // cases where objects that should be blended as a single unit end up with a non-transparent
1035     // object wedged in between them.
1036     if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f))
1037         style->setZIndex(0);
1038     
1039     // Button, legend, input, select and textarea all consider width values of 'auto' to be 'intrinsic'.
1040     // This will be important when we use block flows for all form controls.
1041     if (e && (e->hasTagName(legendTag) || e->hasTagName(buttonTag) || e->hasTagName(inputTag) ||
1042               e->hasTagName(selectTag) || e->hasTagName(textareaTag))) {
1043         if (style->width().isAuto())
1044             style->setWidth(Length(Intrinsic));
1045     }
1046
1047     // Finally update our text decorations in effect, but don't allow text-decoration to percolate through
1048     // tables, inline blocks, inline tables, or run-ins.
1049     if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
1050         || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX)
1051         style->setTextDecorationsInEffect(style->textDecoration());
1052     else
1053         style->addToTextDecorationsInEffect(style->textDecoration());
1054     
1055     // If either overflow value is not visible, change to auto.
1056     if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE)
1057         style->setOverflowY(OMARQUEE);
1058     else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE)
1059         style->setOverflowX(OMARQUEE);
1060     else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE)
1061         style->setOverflowX(OAUTO);
1062     else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE)
1063         style->setOverflowY(OAUTO);
1064
1065     // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1066     // FIXME: Eventually table sections will support auto and scroll.
1067     if (style->display() == TABLE || style->display() == INLINE_TABLE ||
1068         style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1069         if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN) 
1070             style->setOverflowX(OVISIBLE);
1071         if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN) 
1072             style->setOverflowY(OVISIBLE);
1073     }
1074
1075     // Links should be user selectable when content editable
1076     if (e && e->isLink() && (style->userModify() == READ_WRITE || style->userModify() == READ_WRITE_PLAINTEXT_ONLY))
1077         style->setUserSelect(SELECT_AUTO);
1078
1079     // Cull out any useless layers and also repeat patterns into additional layers.
1080     style->adjustBackgroundLayers();
1081
1082     // Let the theme also have a crack at adjusting the style.
1083     if (style->hasAppearance()) {
1084         if (m_hasUAAppearance && theme()->isControlStyled(style, m_borderData, m_backgroundData, m_backgroundColor))
1085             style->setAppearance(NoAppearance);
1086         else
1087             theme()->adjustStyle(this, style, e);
1088     }
1089
1090     // Only use slow repaints if we actually have a background image.
1091     // FIXME: We only need to invalidate the fixed regions when scrolling.  It's total overkill to
1092     // prevent the entire view from blitting on a scroll.
1093     if (style->hasFixedBackgroundImage() && view)
1094         view->useSlowRepaints();
1095 }
1096
1097 void CSSStyleSelector::updateFont()
1098 {
1099     checkForTextSizeAdjust();
1100     checkForGenericFamilyChange(style, parentStyle);
1101     style->font().update();
1102     fontDirty = false;
1103 }
1104
1105 void CSSStyleSelector::cacheBorderAndBackground()
1106 {
1107     m_hasUAAppearance = style->hasAppearance();
1108     if (m_hasUAAppearance) {
1109         m_borderData = style->border();
1110         m_backgroundData = *style->backgroundLayers();
1111         m_backgroundColor = style->backgroundColor();
1112     }
1113 }
1114
1115 RefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly)
1116 {
1117     if (!e->document()->haveStylesheetsLoaded())
1118         return 0;
1119
1120     m_collectRulesOnly = true;
1121     
1122     initElementAndPseudoState(e);
1123     initForStyleResolve(e, 0);
1124     
1125     if (!authorOnly) {
1126         int firstUARule = -1, lastUARule = -1;
1127         // First we match rules from the user agent sheet.
1128         matchUARules(firstUARule, lastUARule);
1129
1130         // Now we check user sheet rules.
1131         int firstUserRule = -1, lastUserRule = -1;
1132         matchRules(m_userStyle, firstUserRule, lastUserRule);
1133     }
1134
1135     // Check the rules in author sheets.
1136     int firstAuthorRule = -1, lastAuthorRule = -1;
1137     matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
1138     
1139     m_collectRulesOnly = false;
1140     
1141     return m_ruleList;
1142 }
1143
1144 RefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, StringImpl* pseudoStyle, bool authorOnly)
1145 {
1146     // FIXME: Implement this.
1147     return 0;
1148 }
1149
1150 static bool subject;
1151
1152 bool CSSStyleSelector::checkSelector(CSSSelector* sel, Element *e)
1153 {
1154     dynamicPseudo = RenderStyle::NOPSEUDO;
1155     
1156     Node *n = e;
1157
1158     // we have the subject part of the selector
1159     subject = true;
1160
1161     // We track whether or not the rule contains only :hover and :active in a simple selector. If
1162     // so, we can't allow that to apply to every element on the page.  We assume the author intended
1163     // to apply the rules only to links.
1164     bool onlyHoverActive = (!sel->hasTag() &&
1165                             (sel->match == CSSSelector::PseudoClass &&
1166                               (sel->pseudoType() == CSSSelector::PseudoHover ||
1167                                sel->pseudoType() == CSSSelector::PseudoActive)));
1168     bool affectedByHover = style ? style->affectedByHoverRules() : false;
1169     bool affectedByActive = style ? style->affectedByActiveRules() : false;
1170     bool havePseudo = pseudoStyle != RenderStyle::NOPSEUDO;
1171     
1172     // first selector has to match
1173     if (!checkOneSelector(sel, e))
1174         return false;
1175
1176     // check the subselectors
1177     CSSSelector::Relation relation = sel->relation();
1178     while((sel = sel->tagHistory)) {
1179         if (!n->isElementNode())
1180             return false;
1181         if (relation != CSSSelector::SubSelector) {
1182             subject = false;
1183             if (havePseudo && dynamicPseudo != pseudoStyle)
1184                 return false;
1185         }
1186         
1187         switch(relation)
1188         {
1189         case CSSSelector::Descendant:
1190             // FIXME: This match needs to know how to backtrack and be non-deterministic.
1191             do {
1192                 n = n->parentNode();
1193                 if (!n || !n->isElementNode())
1194                     return false;
1195             } while (!checkOneSelector(sel, static_cast<Element*>(n)));
1196             break;
1197         case CSSSelector::Child:
1198         {
1199             n = n->parentNode();
1200             if (!strictParsing)
1201                 while (n && n->implicitNode())
1202                     n = n->parentNode();
1203             if (!n || !n->isElementNode())
1204                 return false;
1205             if (!checkOneSelector(sel, static_cast<Element*>(n)))
1206                 return false;
1207             break;
1208         }
1209         case CSSSelector::DirectAdjacent:
1210         {
1211             n = n->previousSibling();
1212             while (n && !n->isElementNode())
1213                 n = n->previousSibling();
1214             if (!n)
1215                 return false;
1216             if (!checkOneSelector(sel, static_cast<Element*>(n)))
1217                 return false;
1218             break;
1219         }
1220         case CSSSelector::IndirectAdjacent:
1221             // FIXME: This match needs to know how to backtrack and be non-deterministic.
1222             do {
1223                 n = n->previousSibling();
1224                 while (n && !n->isElementNode())
1225                     n = n->previousSibling();
1226                 if (!n)
1227                     return false;
1228             } while (!checkOneSelector(sel, static_cast<Element*>(n)));
1229             break;
1230        case CSSSelector::SubSelector:
1231        {
1232             if (onlyHoverActive)
1233                 onlyHoverActive = (sel->match == CSSSelector::PseudoClass &&
1234                                    (sel->pseudoType() == CSSSelector::PseudoHover ||
1235                                     sel->pseudoType() == CSSSelector::PseudoActive));
1236             
1237             Element *elem = static_cast<Element*>(n);
1238             // a selector is invalid if something follows :first-xxx
1239             if (elem == element && dynamicPseudo != RenderStyle::NOPSEUDO)
1240                 return false;
1241             if (!checkOneSelector(sel, elem, true))
1242                 return false;
1243             break;
1244         }
1245         }
1246         relation = sel->relation();
1247     }
1248
1249     if (subject && havePseudo && dynamicPseudo != pseudoStyle)
1250         return false;
1251     
1252     // disallow *:hover, *:active, and *:hover:active except for links
1253     if (onlyHoverActive && subject) {
1254         if (pseudoState == PseudoUnknown)
1255             checkPseudoState(e);
1256
1257         if (pseudoState == PseudoNone) {
1258             if (!affectedByHover && style->affectedByHoverRules())
1259                 style->setAffectedByHoverRules(false);
1260             if (!affectedByActive && style->affectedByActiveRules())
1261                 style->setAffectedByActiveRules(false);
1262             return false;
1263         }
1264     }
1265
1266     return true;
1267 }
1268
1269 bool CSSStyleSelector::checkOneSelector(CSSSelector* sel, Element* e, bool isSubSelector)
1270 {
1271     if(!e)
1272         return false;
1273
1274     if (sel->hasTag()) {
1275         const AtomicString& localName = e->localName();
1276         const AtomicString& ns = e->namespaceURI();
1277         const AtomicString& selLocalName = sel->tag.localName();
1278         const AtomicString& selNS = sel->tag.namespaceURI();
1279     
1280         if ((selLocalName != starAtom && localName != selLocalName) ||
1281             (selNS != starAtom && ns != selNS))
1282             return false;
1283     }
1284
1285     if (sel->hasAttribute()) {
1286         if (sel->match == CSSSelector::Class) {
1287             if (!e->hasClass())
1288                 return false;
1289             for (const AtomicStringList* c = e->getClassList(); c; c = c->next())
1290                 if (c->string() == sel->value)
1291                     return true;
1292             return false;
1293         }
1294         else if (sel->match == CSSSelector::Id)
1295             return e->hasID() && e->getIDAttribute() == sel->value;
1296         else if (style && (e != element || !styledElement || (!styledElement->isMappedAttribute(sel->attr) && sel->attr != typeAttr))) {
1297             style->setAffectedByAttributeSelectors(); // Special-case the "type" attribute so input form controls can share style.
1298             m_selectorAttrs.add(sel->attr.localName().impl());
1299         }
1300
1301         const AtomicString& value = e->getAttribute(sel->attr);
1302         if (value.isNull())
1303             return false; // attribute is not set
1304
1305         switch(sel->match) {
1306         case CSSSelector::Exact:
1307             if ((isXMLDoc && sel->value != value) || (!isXMLDoc && !equalIgnoringCase(sel->value, value)))
1308                 return false;
1309             break;
1310         case CSSSelector::List:
1311         {
1312             // The selector's value can't contain a space, or it's totally bogus.
1313             if (sel->value.contains(' '))
1314                 return false;
1315
1316             int startSearchAt = 0;
1317             while (true) {
1318                 int foundPos = value.find(sel->value, startSearchAt, isXMLDoc);
1319                 if (foundPos == -1)
1320                     return false;
1321                 if (foundPos == 0 || value[foundPos-1] == ' ') {
1322                     unsigned endStr = foundPos + sel->value.length();
1323                     if (endStr == value.length() || value[endStr] == ' ')
1324                         break; // We found a match.
1325                 }
1326                 
1327                 // No match.  Keep looking.
1328                 startSearchAt = foundPos + 1;
1329             }
1330             break;
1331         }
1332         case CSSSelector::Contain:
1333             if (!value.contains(sel->value, isXMLDoc))
1334                 return false;
1335             break;
1336         case CSSSelector::Begin:
1337             if (!value.startsWith(sel->value, isXMLDoc))
1338                 return false;
1339             break;
1340         case CSSSelector::End:
1341             if (!value.endsWith(sel->value, isXMLDoc))
1342                 return false;
1343             break;
1344         case CSSSelector::Hyphen:
1345             if (value.length() < sel->value.length())
1346                 return false;
1347             if (!value.startsWith(sel->value, isXMLDoc))
1348                 return false;
1349             // It they start the same, check for exact match or following '-':
1350             if (value.length() != sel->value.length() && value[sel->value.length()] != '-')
1351                 return false;
1352             break;
1353         case CSSSelector::PseudoClass:
1354         case CSSSelector::PseudoElement:
1355         default:
1356             break;
1357         }
1358     }
1359     if(sel->match == CSSSelector::PseudoClass || sel->match == CSSSelector::PseudoElement)
1360     {
1361         // Pseudo elements. We need to check first child here. No dynamic pseudo
1362         // elements for the moment
1363             switch (sel->pseudoType()) {
1364                 // Pseudo classes:
1365             case CSSSelector::PseudoEmpty:
1366                 if (!e->firstChild())
1367                     return true;
1368                 break;
1369             case CSSSelector::PseudoFirstChild: {
1370                 // first-child matches the first child that is an element!
1371                 if (e->parentNode() && e->parentNode()->isElementNode()) {
1372                     Node *n = e->previousSibling();
1373                     while (n && !n->isElementNode())
1374                         n = n->previousSibling();
1375                     if (!n)
1376                         return true;
1377                 }
1378                 break;
1379             }
1380             case CSSSelector::PseudoFirstOfType: {
1381                 // first-of-type matches the first element of its type!
1382                 if (e->parentNode() && e->parentNode()->isElementNode()) {
1383                     const QualifiedName& type = e->tagQName();
1384                     Node *n = e->previousSibling();
1385                     while (n) {
1386                         if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
1387                             break;
1388                         n = n->previousSibling();
1389                     }
1390                     if (!n)
1391                         return true;
1392                 }
1393                 break;
1394             }
1395             case CSSSelector::PseudoLastChild: {
1396                 // last-child matches the last child that is an element!
1397                 if (e->parentNode() && e->parentNode()->isElementNode()) {
1398                     Node *n = e->nextSibling();
1399                     while (n && !n->isElementNode())
1400                         n = n->nextSibling();
1401                     if (!n)
1402                         return true;
1403                 }
1404                 break;
1405             }
1406             case CSSSelector::PseudoLastOfType: {
1407                 // last-of-type matches the last element of its type!
1408                 if (e->parentNode() && e->parentNode()->isElementNode()) {
1409                     const QualifiedName& type = e->tagQName();
1410                     Node *n = e->nextSibling();
1411                     while (n) {
1412                         if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
1413                             break;
1414                         n = n->nextSibling();
1415                     }
1416                     if (!n)
1417                         return true;
1418                 }
1419                 break;
1420             }
1421             case CSSSelector::PseudoOnlyChild: {
1422                 // If both first-child and last-child apply, then only-child applies.
1423                 if (e->parentNode() && e->parentNode()->isElementNode()) {
1424                     Node *n = e->previousSibling();
1425                     while (n && !n->isElementNode())
1426                         n = n->previousSibling();
1427                     if (!n) {
1428                         n = e->nextSibling();
1429                         while (n && !n->isElementNode())
1430                             n = n->nextSibling();
1431                         if (!n)
1432                             return true;
1433                     }
1434                 }
1435                 break;
1436             }
1437             case CSSSelector::PseudoOnlyOfType: {
1438                 // If both first-of-type and last-of-type apply, then only-of-type applies.
1439                 if (e->parentNode() && e->parentNode()->isElementNode()) {
1440                     const QualifiedName& type = e->tagQName();
1441                     Node *n = e->previousSibling();
1442                     while (n && !static_cast<Element*>(n)->hasTagName(type))
1443                         n = n->previousSibling();
1444                     if (!n) {
1445                         n = e->nextSibling();
1446                         while (n && !static_cast<Element*>(n)->hasTagName(type))
1447                             n = n->nextSibling();
1448                         if (!n)
1449                             return true;
1450                     }
1451                 }
1452                 break;
1453             }
1454             case CSSSelector::PseudoTarget:
1455                 if (e == e->document()->getCSSTarget())
1456                     return true;
1457                 break;
1458             case CSSSelector::PseudoAnyLink:
1459                 if (pseudoState == PseudoUnknown)
1460                     checkPseudoState(e, false);
1461                 if (pseudoState == PseudoAnyLink || pseudoState == PseudoLink || pseudoState == PseudoVisited)
1462                     return true;
1463                 break;
1464             case CSSSelector::PseudoAutofill:
1465                 if (e && e->hasTagName(inputTag))
1466                     return static_cast<HTMLInputElement*>(e)->autofilled();
1467                 break;
1468             case CSSSelector::PseudoLink:
1469                 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1470                     checkPseudoState(e);
1471                 if (pseudoState == PseudoLink)
1472                     return true;
1473                 break;
1474             case CSSSelector::PseudoVisited:
1475                 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1476                     checkPseudoState(e);
1477                 if (pseudoState == PseudoVisited)
1478                     return true;
1479                 break;
1480             case CSSSelector::PseudoHover: {
1481                 // If we're in quirks mode, then hover should never match anchors with no
1482                 // href and *:hover should not match anything.  This is important for sites like wsj.com.
1483                 if (strictParsing || isSubSelector || sel->relation() == CSSSelector::SubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1484                     if (element == e && style)
1485                         style->setAffectedByHoverRules(true);
1486                         if (element != e && e->renderStyle())
1487                             e->renderStyle()->setAffectedByHoverRules(true);
1488                         if (e->hovered())
1489                             return true;
1490                 }
1491                 break;
1492             }
1493             case CSSSelector::PseudoDrag: {
1494                 if (element == e && style)
1495                     style->setAffectedByDragRules(true);
1496                     if (element != e && e->renderStyle())
1497                         e->renderStyle()->setAffectedByDragRules(true);
1498                     if (e->renderer() && e->renderer()->isDragging())
1499                         return true;
1500                 break;
1501             }
1502             case CSSSelector::PseudoFocus:
1503                 if (e && e->focused() && e->document()->frame()->isActive())
1504                     return true;
1505                 break;
1506             case CSSSelector::PseudoActive:
1507                 // If we're in quirks mode, then :active should never match anchors with no
1508                 // href and *:active should not match anything. 
1509                 if (strictParsing || isSubSelector || sel->relation() == CSSSelector::SubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1510                     if (element == e && style)
1511                         style->setAffectedByActiveRules(true);
1512                     else if (e->renderStyle())
1513                         e->renderStyle()->setAffectedByActiveRules(true);
1514                     if (e->active())
1515                         return true;
1516                 }
1517                 break;
1518             case CSSSelector::PseudoEnabled:
1519                 if (e && e->isControl())
1520                     // The UI spec states that you can't match :enabled unless you are an object that can
1521                     // "receive focus and be activated."  We will limit matching of this pseudo-class to elements
1522                     // that are controls.
1523                     return e->isEnabled();                    
1524                 break;
1525             case CSSSelector::PseudoDisabled:
1526                 if (e && e->isControl())
1527                     // The UI spec states that you can't match :enabled unless you are an object that can
1528                     // "receive focus and be activated."  We will limit matching of this pseudo-class to elements
1529                     // that are controls.
1530                     return !e->isEnabled();                    
1531                 break;
1532             case CSSSelector::PseudoChecked:
1533                 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
1534                 // you can't be both checked and indeterminate.  We will behave like WinIE behind the scenes and just
1535                 // obey the CSS spec here in the test for matching the pseudo.
1536                 if (e && e->isChecked() && !e->isIndeterminate())
1537                     return true;
1538                 break;
1539             case CSSSelector::PseudoIndeterminate:
1540                 if (e && e->isIndeterminate())
1541                     return true;
1542                 break;
1543             case CSSSelector::PseudoRoot:
1544                 if (e == e->document()->documentElement())
1545                     return true;
1546                 break;
1547             case CSSSelector::PseudoLang: {
1548                 const AtomicString& value = e->getAttribute(langAttr);
1549                 if (value.isEmpty() || !value.startsWith(sel->argument, false))
1550                     break;
1551                 if (value.length() != sel->argument.length() && value[sel->argument.length()] != '-')
1552                     break;
1553                 return true;
1554             }
1555             case CSSSelector::PseudoNot: {
1556                 // check the simple selector
1557                 for (CSSSelector* subSel = sel->simpleSelector; subSel; subSel = subSel->tagHistory) {
1558                     // :not cannot nest. I don't really know why this is a
1559                     // restriction in CSS3, but it is, so let's honour it.
1560                     if (subSel->simpleSelector)
1561                         break;
1562                     if (!checkOneSelector(subSel, e))
1563                         return true;
1564                 }
1565                 break;
1566             }
1567             case CSSSelector::PseudoOther:
1568                 break;
1569             
1570             // Pseudo-elements:
1571             case CSSSelector::PseudoFirstLine:
1572                 if (subject) {
1573                     dynamicPseudo=RenderStyle::FIRST_LINE;
1574                     return true;
1575                 }
1576                 break;
1577             case CSSSelector::PseudoFirstLetter:
1578                 if (subject) {
1579                     dynamicPseudo=RenderStyle::FIRST_LETTER;
1580                     return true;
1581                 }
1582                 break;
1583             case CSSSelector::PseudoSelection:
1584                 dynamicPseudo = RenderStyle::SELECTION;
1585                 return true;
1586             case CSSSelector::PseudoBefore:
1587                 dynamicPseudo = RenderStyle::BEFORE;
1588                 return true;
1589             case CSSSelector::PseudoAfter:
1590                 dynamicPseudo = RenderStyle::AFTER;
1591                 return true;
1592                 
1593             case CSSSelector::PseudoNotParsed:
1594                 assert(false);
1595                 break;
1596         }
1597         return false;
1598     }
1599     // ### add the rest of the checks...
1600     return true;
1601 }
1602
1603 // -----------------------------------------------------------------
1604
1605 CSSRuleSet::CSSRuleSet()
1606 {
1607     m_universalRules = 0;
1608     m_ruleCount = 0;
1609 }
1610
1611 CSSRuleSet::~CSSRuleSet()
1612
1613     deleteAllValues(m_idRules);
1614     deleteAllValues(m_classRules);
1615     deleteAllValues(m_tagRules);
1616
1617     delete m_universalRules; 
1618 }
1619
1620
1621 void CSSRuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
1622                               CSSStyleRule* rule, CSSSelector* sel)
1623 {
1624     if (!key) return;
1625     CSSRuleDataList* rules = map.get(key);
1626     if (!rules) {
1627         rules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1628         map.set(key, rules);
1629     } else
1630         rules->append(m_ruleCount++, rule, sel);
1631 }
1632
1633 void CSSRuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel)
1634 {
1635     if (sel->match == CSSSelector::Id) {
1636         addToRuleSet(sel->value.impl(), m_idRules, rule, sel);
1637         return;
1638     }
1639     if (sel->match == CSSSelector::Class) {
1640         addToRuleSet(sel->value.impl(), m_classRules, rule, sel);
1641         return;
1642     }
1643      
1644     const AtomicString& localName = sel->tag.localName();
1645     if (localName != starAtom) {
1646         addToRuleSet(localName.impl(), m_tagRules, rule, sel);
1647         return;
1648     }
1649     
1650     // Just put it in the universal rule set.
1651     if (!m_universalRules)
1652         m_universalRules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1653     else
1654         m_universalRules->append(m_ruleCount++, rule, sel);
1655 }
1656
1657 void CSSRuleSet::addRulesFromSheet(CSSStyleSheet* sheet,  MediaQueryEvaluator* medium)
1658 {
1659     if (!sheet || !sheet->isCSSStyleSheet())
1660         return;
1661
1662     // No media implies "all", but if a media list exists it must
1663     // contain our current medium
1664     if (sheet->media() && !medium->eval(sheet->media()))
1665         return; // the style sheet doesn't apply
1666
1667     int len = sheet->length();
1668
1669     for (int i = 0; i < len; i++) {
1670         StyleBase* item = sheet->item(i);
1671         if (item->isStyleRule()) {
1672             CSSStyleRule* rule = static_cast<CSSStyleRule*>(item);
1673             for (CSSSelector* s = rule->selector(); s; s = s->next())
1674                 addRule(rule, s);
1675         }
1676         else if(item->isImportRule()) {
1677             CSSImportRule* import = static_cast<CSSImportRule*>(item);
1678             if (!import->media() || medium->eval(import->media()))
1679                 addRulesFromSheet(import->styleSheet(), medium);
1680         }
1681         else if(item->isMediaRule()) {
1682             CSSMediaRule* r = static_cast<CSSMediaRule*>(item);
1683             CSSRuleList* rules = r->cssRules();
1684
1685             if ((!r->media() || medium->eval(r->media())) && rules) {
1686                 // Traverse child elements of the @media rule.
1687                 for (unsigned j = 0; j < rules->length(); j++) {
1688                     CSSRule *childItem = rules->item(j);
1689                     if (childItem->isStyleRule()) {
1690                         // It is a StyleRule, so append it to our list
1691                         CSSStyleRule* rule = static_cast<CSSStyleRule*>(childItem);
1692                         for (CSSSelector* s = rule->selector(); s; s = s->next())
1693                             addRule(rule, s);
1694                         
1695                     }
1696                 }   // for rules
1697             }   // if rules
1698         }
1699     }
1700 }
1701
1702 // -------------------------------------------------------------------------------------
1703 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1704
1705 static Length convertToLength(CSSPrimitiveValue *primitiveValue, RenderStyle *style, bool *ok = 0)
1706 {
1707     Length l;
1708     if (!primitiveValue) {
1709         if (ok)
1710             *ok = false;
1711     } else {
1712         int type = primitiveValue->primitiveType();
1713         if(type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
1714             l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
1715         else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
1716             l = Length(int(primitiveValue->getFloatValue()), Percent);
1717         else if(type == CSSPrimitiveValue::CSS_NUMBER)
1718             l = Length(int(primitiveValue->getFloatValue() * 100), Percent);
1719         else if (ok)
1720             *ok = false;
1721     }
1722     return l;
1723 }
1724
1725 void CSSStyleSelector::applyDeclarations(bool applyFirst, bool isImportant,
1726                                          int startIndex, int endIndex)
1727 {
1728     if (startIndex == -1) return;
1729     for (int i = startIndex; i <= endIndex; i++) {
1730         CSSMutableStyleDeclaration* decl = m_matchedDecls[i];
1731         DeprecatedValueListConstIterator<CSSProperty> end;
1732         for (DeprecatedValueListConstIterator<CSSProperty> it = decl->valuesIterator(); it != end; ++it) {
1733             const CSSProperty& current = *it;
1734             // give special priority to font-xxx, color properties
1735             if (isImportant == current.isImportant()) {
1736                 bool first;
1737                 switch(current.id()) {
1738                     case CSS_PROP_COLOR:
1739                     case CSS_PROP_DIRECTION:
1740                     case CSS_PROP_DISPLAY:
1741                     case CSS_PROP_FONT:
1742                     case CSS_PROP_FONT_SIZE:
1743                     case CSS_PROP_FONT_STYLE:
1744                     case CSS_PROP_FONT_FAMILY:
1745                     case CSS_PROP_FONT_WEIGHT:
1746                     case CSS_PROP__WEBKIT_TEXT_SIZE_ADJUST:
1747                     case CSS_PROP_FONT_VARIANT:
1748                         // these have to be applied first, because other properties use the computed
1749                         // values of these porperties.
1750                         first = true;
1751                         break;
1752                     default:
1753                         first = false;
1754                         break;
1755                 }
1756                 
1757                 if (first == applyFirst)
1758                     applyProperty(current.id(), current.value());
1759             }
1760         }
1761     }
1762 }
1763
1764 void CSSStyleSelector::applyProperty(int id, CSSValue *value)
1765 {
1766     CSSPrimitiveValue *primitiveValue = 0;
1767     if(value->isPrimitiveValue()) primitiveValue = static_cast<CSSPrimitiveValue*>(value);
1768
1769     Length l;
1770     bool apply = false;
1771
1772     unsigned short valueType = value->cssValueType();
1773
1774     bool isInherit = parentNode && valueType == CSSValue::CSS_INHERIT;
1775     bool isInitial = valueType == CSSValue::CSS_INITIAL || (!parentNode && valueType == CSSValue::CSS_INHERIT);
1776
1777     // These properties are used to set the correct margins/padding on RTL lists.
1778     if (id == CSS_PROP__WEBKIT_MARGIN_START)
1779         id = style->direction() == LTR ? CSS_PROP_MARGIN_LEFT : CSS_PROP_MARGIN_RIGHT;
1780     else if (id == CSS_PROP__WEBKIT_PADDING_START)
1781         id = style->direction() == LTR ? CSS_PROP_PADDING_LEFT : CSS_PROP_PADDING_RIGHT;
1782
1783     // What follows is a list that maps the CSS properties into their corresponding front-end
1784     // RenderStyle values.  Shorthands (e.g. border, background) occur in this list as well and
1785     // are only hit when mapping "inherit" or "initial" into front-end values.
1786     switch(id)
1787     {
1788 // ident only properties
1789     case CSS_PROP_BACKGROUND_ATTACHMENT:
1790         HANDLE_BACKGROUND_VALUE(backgroundAttachment, BackgroundAttachment, value)
1791         break;
1792     case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
1793         HANDLE_BACKGROUND_VALUE(backgroundClip, BackgroundClip, value)
1794         break;
1795     case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
1796         HANDLE_BACKGROUND_VALUE(backgroundComposite, BackgroundComposite, value)
1797         break;
1798     case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
1799         HANDLE_BACKGROUND_VALUE(backgroundOrigin, BackgroundOrigin, value)
1800         break;
1801     case CSS_PROP_BACKGROUND_REPEAT:
1802         HANDLE_BACKGROUND_VALUE(backgroundRepeat, BackgroundRepeat, value)
1803         break;
1804     case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
1805         HANDLE_BACKGROUND_VALUE(backgroundSize, BackgroundSize, value)
1806         break;
1807     case CSS_PROP_BORDER_COLLAPSE:
1808         HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse)
1809         if(!primitiveValue) break;
1810         switch(primitiveValue->getIdent())
1811         {
1812         case CSS_VAL_COLLAPSE:
1813             style->setBorderCollapse(true);
1814             break;
1815         case CSS_VAL_SEPARATE:
1816             style->setBorderCollapse(false);
1817             break;
1818         default:
1819             return;
1820         }
1821         break;
1822         
1823     case CSS_PROP_BORDER_TOP_STYLE:
1824         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle)
1825         if (!primitiveValue) return;
1826         style->setBorderTopStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL_NONE));
1827         break;
1828     case CSS_PROP_BORDER_RIGHT_STYLE:
1829         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle)
1830         if (!primitiveValue) return;
1831         style->setBorderRightStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL_NONE));
1832         break;
1833     case CSS_PROP_BORDER_BOTTOM_STYLE:
1834         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle)
1835         if (!primitiveValue) return;
1836         style->setBorderBottomStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL_NONE));
1837         break;
1838     case CSS_PROP_BORDER_LEFT_STYLE:
1839         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle)
1840         if (!primitiveValue) return;
1841         style->setBorderLeftStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL_NONE));
1842         break;
1843     case CSS_PROP_OUTLINE_STYLE:
1844         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle)
1845         if (!primitiveValue) return;
1846         if (primitiveValue->getIdent() == CSS_VAL_AUTO)
1847             style->setOutlineStyle(DOTTED, true);
1848         else
1849             style->setOutlineStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL_NONE));
1850         break;
1851     case CSS_PROP_CAPTION_SIDE:
1852     {
1853         HANDLE_INHERIT_AND_INITIAL(captionSide, CaptionSide)
1854         if(!primitiveValue) break;
1855         ECaptionSide c = RenderStyle::initialCaptionSide();
1856         switch(primitiveValue->getIdent())
1857         {
1858         case CSS_VAL_LEFT:
1859             c = CAPLEFT; break;
1860         case CSS_VAL_RIGHT:
1861             c = CAPRIGHT; break;
1862         case CSS_VAL_TOP:
1863             c = CAPTOP; break;
1864         case CSS_VAL_BOTTOM:
1865             c = CAPBOTTOM; break;
1866         default:
1867             return;
1868         }
1869         style->setCaptionSide(c);
1870         return;
1871     }
1872     case CSS_PROP_CLEAR:
1873     {
1874         HANDLE_INHERIT_AND_INITIAL(clear, Clear)
1875         if(!primitiveValue) break;
1876         EClear c;
1877         switch(primitiveValue->getIdent())
1878         {
1879         case CSS_VAL_NONE:
1880             c = CNONE; break;
1881         case CSS_VAL_LEFT:
1882             c = CLEFT; break;
1883         case CSS_VAL_RIGHT:
1884             c = CRIGHT; break;
1885         case CSS_VAL_BOTH:
1886             c = CBOTH; break;
1887         default:
1888             return;
1889         }
1890         style->setClear(c);
1891         return;
1892     }
1893     case CSS_PROP_DIRECTION:
1894     {
1895         HANDLE_INHERIT_AND_INITIAL(direction, Direction)
1896         if(!primitiveValue) break;
1897         style->setDirection(primitiveValue->getIdent() == CSS_VAL_LTR ? LTR : RTL);
1898         return;
1899     }
1900     case CSS_PROP_DISPLAY:
1901     {
1902         HANDLE_INHERIT_AND_INITIAL(display, Display)
1903         if(!primitiveValue) break;
1904         int id = primitiveValue->getIdent();
1905         EDisplay d;
1906         if (id == CSS_VAL_NONE)
1907             d = NONE;
1908         else
1909             d = EDisplay(primitiveValue->getIdent() - CSS_VAL_INLINE);
1910
1911         style->setDisplay(d);
1912         break;
1913     }
1914
1915     case CSS_PROP_EMPTY_CELLS:
1916     {
1917         HANDLE_INHERIT_AND_INITIAL(emptyCells, EmptyCells)
1918         if (!primitiveValue) break;
1919         int id = primitiveValue->getIdent();
1920         if (id == CSS_VAL_SHOW)
1921             style->setEmptyCells(SHOW);
1922         else if (id == CSS_VAL_HIDE)
1923             style->setEmptyCells(HIDE);
1924         break;
1925     }
1926     case CSS_PROP_FLOAT:
1927     {
1928         HANDLE_INHERIT_AND_INITIAL(floating, Floating)
1929         if(!primitiveValue) return;
1930         EFloat f;
1931         switch(primitiveValue->getIdent())
1932         {
1933         case CSS_VAL_LEFT:
1934             f = FLEFT; break;
1935         case CSS_VAL_RIGHT:
1936             f = FRIGHT; break;
1937         case CSS_VAL_NONE:
1938         case CSS_VAL_CENTER:  //Non standart CSS-Value
1939             f = FNONE; break;
1940         default:
1941             return;
1942         }
1943         
1944         style->setFloating(f);
1945         break;
1946     }
1947
1948         break;
1949     case CSS_PROP_FONT_STRETCH:
1950         break; /* Not supported. */
1951
1952     case CSS_PROP_FONT_STYLE:
1953     {
1954         FontDescription fontDescription = style->fontDescription();
1955         if (isInherit)
1956             fontDescription.setItalic(parentStyle->fontDescription().italic());
1957         else if (isInitial)
1958             fontDescription.setItalic(false);
1959         else {
1960             if (!primitiveValue) return;
1961             switch (primitiveValue->getIdent()) {
1962                 case CSS_VAL_OBLIQUE:
1963                 // FIXME: oblique is the same as italic for the moment...
1964                 case CSS_VAL_ITALIC:
1965                     fontDescription.setItalic(true);
1966                     break;
1967                 case CSS_VAL_NORMAL:
1968                     fontDescription.setItalic(false);
1969                     break;
1970                 default:
1971                     return;
1972             }
1973         }
1974         if (style->setFontDescription(fontDescription))
1975             fontDirty = true;
1976         break;
1977     }
1978
1979     case CSS_PROP_FONT_VARIANT:
1980     {
1981         FontDescription fontDescription = style->fontDescription();
1982         if (isInherit) 
1983             fontDescription.setSmallCaps(parentStyle->fontDescription().smallCaps());
1984         else if (isInitial)
1985             fontDescription.setSmallCaps(false);
1986         else {
1987             if (!primitiveValue) return;
1988             int id = primitiveValue->getIdent();
1989             if (id == CSS_VAL_NORMAL)
1990                 fontDescription.setSmallCaps(false);
1991             else if (id == CSS_VAL_SMALL_CAPS)
1992                 fontDescription.setSmallCaps(true);
1993             else
1994                 return;
1995         }
1996         if (style->setFontDescription(fontDescription))
1997             fontDirty = true;
1998         break;        
1999     }
2000
2001     case CSS_PROP_FONT_WEIGHT:
2002     {
2003         FontDescription fontDescription = style->fontDescription();
2004         if (isInherit)
2005             fontDescription.setWeight(parentStyle->fontDescription().weight());
2006         else if (isInitial)
2007             fontDescription.setWeight(cNormalWeight);
2008         else {
2009             if (!primitiveValue) return;
2010             if (primitiveValue->getIdent()) {
2011                 switch (primitiveValue->getIdent()) {
2012                     // FIXME: We aren't genuinely supporting specific weight values.
2013                     case CSS_VAL_BOLD:
2014                     case CSS_VAL_BOLDER:
2015                     case CSS_VAL_600:
2016                     case CSS_VAL_700:
2017                     case CSS_VAL_800:
2018                     case CSS_VAL_900:
2019                         fontDescription.setWeight(cBoldWeight);
2020                         break;
2021                     case CSS_VAL_NORMAL:
2022                     case CSS_VAL_LIGHTER:
2023                     case CSS_VAL_100:
2024                     case CSS_VAL_200:
2025                     case CSS_VAL_300:
2026                     case CSS_VAL_400:
2027                     case CSS_VAL_500:
2028                         fontDescription.setWeight(cNormalWeight);
2029                         break;
2030                     default:
2031                         return;
2032                 }
2033             }
2034             else
2035             {
2036                 // ### fix parsing of 100-900 values in parser, apply them here
2037             }
2038         }
2039         if (style->setFontDescription(fontDescription))
2040             fontDirty = true;
2041         break;
2042     }
2043         
2044     case CSS_PROP_LIST_STYLE_POSITION:
2045     {
2046         HANDLE_INHERIT_AND_INITIAL(listStylePosition, ListStylePosition)
2047         if (!primitiveValue) return;
2048         if (primitiveValue->getIdent())
2049             style->setListStylePosition((EListStylePosition) (primitiveValue->getIdent() - CSS_VAL_OUTSIDE));
2050         return;
2051     }
2052
2053     case CSS_PROP_LIST_STYLE_TYPE:
2054     {
2055         HANDLE_INHERIT_AND_INITIAL(listStyleType, ListStyleType)
2056         if (!primitiveValue) return;
2057         if (primitiveValue->getIdent())
2058         {
2059             EListStyleType t;
2060             int id = primitiveValue->getIdent();
2061             if (id == CSS_VAL_NONE) { // important!!
2062               t = LNONE;
2063             } else {
2064               t = EListStyleType(id - CSS_VAL_DISC);
2065             }
2066             style->setListStyleType(t);
2067         }
2068         return;
2069     }
2070
2071     case CSS_PROP_OVERFLOW:
2072     {
2073         if (isInherit) {
2074             style->setOverflowX(parentStyle->overflowX());
2075             style->setOverflowY(parentStyle->overflowY());
2076             return;
2077         }
2078         
2079         if (isInitial) {
2080             style->setOverflowX(RenderStyle::initialOverflowX());
2081             style->setOverflowY(RenderStyle::initialOverflowY());
2082             return;
2083         }
2084             
2085         EOverflow o;
2086         switch(primitiveValue->getIdent()) {
2087             case CSS_VAL_VISIBLE:
2088                 o = OVISIBLE; break;
2089             case CSS_VAL_HIDDEN:
2090                 o = OHIDDEN; break;
2091             case CSS_VAL_SCROLL:
2092                 o = OSCROLL; break;
2093             case CSS_VAL_AUTO:
2094                 o = OAUTO; break;
2095             case CSS_VAL__WEBKIT_MARQUEE:
2096                 o = OMARQUEE; break;
2097             case CSS_VAL_OVERLAY:
2098                 o = OOVERLAY; break;
2099             default:
2100                 return;
2101         }
2102         style->setOverflowX(o);
2103         style->setOverflowY(o);
2104         return;
2105     }
2106
2107     case CSS_PROP_OVERFLOW_X:
2108     {
2109         HANDLE_INHERIT_AND_INITIAL(overflowX, OverflowX)
2110         EOverflow o;
2111         switch(primitiveValue->getIdent())
2112         {
2113         case CSS_VAL_VISIBLE:
2114             o = OVISIBLE; break;
2115         case CSS_VAL_HIDDEN:
2116             o = OHIDDEN; break;
2117         case CSS_VAL_SCROLL:
2118             o = OSCROLL; break;
2119         case CSS_VAL_AUTO:
2120             o = OAUTO; break;
2121         case CSS_VAL_OVERLAY:
2122             o = OOVERLAY; break;
2123         default:
2124             return;
2125         }
2126         style->setOverflowX(o);
2127         return;
2128     }
2129
2130     case CSS_PROP_OVERFLOW_Y:
2131     {
2132         HANDLE_INHERIT_AND_INITIAL(overflowY, OverflowY)
2133         EOverflow o;
2134         switch(primitiveValue->getIdent())
2135         {
2136         case CSS_VAL_VISIBLE:
2137             o = OVISIBLE; break;
2138         case CSS_VAL_HIDDEN:
2139             o = OHIDDEN; break;
2140         case CSS_VAL_SCROLL:
2141             o = OSCROLL; break;
2142         case CSS_VAL_AUTO:
2143             o = OAUTO; break;
2144         case CSS_VAL_OVERLAY:
2145             o = OOVERLAY; break;
2146         default:
2147             return;
2148         }
2149         style->setOverflowY(o);
2150         return;
2151     }
2152
2153     case CSS_PROP_PAGE_BREAK_BEFORE:
2154     {
2155         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak)
2156         if (!primitiveValue) return;
2157         switch (primitiveValue->getIdent()) {
2158             case CSS_VAL_AUTO:
2159                 style->setPageBreakBefore(PBAUTO);
2160                 break;
2161             case CSS_VAL_LEFT:
2162             case CSS_VAL_RIGHT:
2163             case CSS_VAL_ALWAYS:
2164                 style->setPageBreakBefore(PBALWAYS); // CSS2.1: "Conforming user agents may map left/right to always."
2165                 break;
2166             case CSS_VAL_AVOID:
2167                 style->setPageBreakBefore(PBAVOID);
2168                 break;
2169         }
2170         break;
2171     }
2172
2173     case CSS_PROP_PAGE_BREAK_AFTER:
2174     {
2175         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak)
2176         if (!primitiveValue) return;
2177         switch (primitiveValue->getIdent()) {
2178             case CSS_VAL_AUTO:
2179                 style->setPageBreakAfter(PBAUTO);
2180                 break;
2181             case CSS_VAL_LEFT:
2182             case CSS_VAL_RIGHT:
2183             case CSS_VAL_ALWAYS:
2184                 style->setPageBreakAfter(PBALWAYS); // CSS2.1: "Conforming user agents may map left/right to always."
2185                 break;
2186             case CSS_VAL_AVOID:
2187                 style->setPageBreakAfter(PBAVOID);
2188                 break;
2189         }
2190         break;
2191     }
2192
2193     case CSS_PROP_PAGE_BREAK_INSIDE: {
2194         HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak)
2195         if (!primitiveValue) return;
2196         if (primitiveValue->getIdent() == CSS_VAL_AUTO)
2197             style->setPageBreakInside(PBAUTO);
2198         else if (primitiveValue->getIdent() == CSS_VAL_AVOID)
2199             style->setPageBreakInside(PBAVOID);
2200         return;
2201     }
2202         
2203     case CSS_PROP_PAGE:
2204         break; /* FIXME: Not even sure what this is...  -dwh */
2205
2206     case CSS_PROP_POSITION:
2207     {
2208         HANDLE_INHERIT_AND_INITIAL(position, Position)
2209         if(!primitiveValue) return;
2210         EPosition p;
2211         switch(primitiveValue->getIdent())
2212         {
2213         case CSS_VAL_STATIC:
2214             p = StaticPosition; break;
2215         case CSS_VAL_RELATIVE:
2216             p = RelativePosition; break;
2217         case CSS_VAL_ABSOLUTE:
2218             p = AbsolutePosition; break;
2219         case CSS_VAL_FIXED:
2220             {
2221                 if (view)
2222                     view->useSlowRepaints();
2223                 p = FixedPosition;
2224                 break;
2225             }
2226         default:
2227             return;
2228         }
2229         style->setPosition(p);
2230         return;
2231     }
2232
2233     case CSS_PROP_TABLE_LAYOUT: {
2234         HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout)
2235
2236         if (!primitiveValue->getIdent())
2237             return;
2238
2239         ETableLayout l = RenderStyle::initialTableLayout();
2240         switch(primitiveValue->getIdent()) {
2241             case CSS_VAL_FIXED:
2242                 l = TFIXED;
2243                 // fall through
2244             case CSS_VAL_AUTO:
2245                 style->setTableLayout(l);
2246             default:
2247                 break;
2248         }
2249         break;
2250     }
2251         
2252     case CSS_PROP_UNICODE_BIDI: {
2253         HANDLE_INHERIT_AND_INITIAL(unicodeBidi, UnicodeBidi)
2254         switch (primitiveValue->getIdent()) {
2255             case CSS_VAL_NORMAL:
2256                 style->setUnicodeBidi(UBNormal); 
2257                 break;
2258             case CSS_VAL_EMBED:
2259                 style->setUnicodeBidi(Embed); 
2260                 break;
2261             case CSS_VAL_BIDI_OVERRIDE:
2262                 style->setUnicodeBidi(Override);
2263                 break;
2264             default:
2265                 return;
2266         }
2267         break;
2268     }
2269     case CSS_PROP_TEXT_TRANSFORM: {
2270         HANDLE_INHERIT_AND_INITIAL(textTransform, TextTransform)
2271         
2272         if(!primitiveValue->getIdent()) return;
2273
2274         ETextTransform tt;
2275         switch(primitiveValue->getIdent()) {
2276         case CSS_VAL_CAPITALIZE:  tt = CAPITALIZE;  break;
2277         case CSS_VAL_UPPERCASE:   tt = UPPERCASE;   break;
2278         case CSS_VAL_LOWERCASE:   tt = LOWERCASE;   break;
2279         case CSS_VAL_NONE:
2280         default:                  tt = TTNONE;      break;
2281         }
2282         style->setTextTransform(tt);
2283         break;
2284         }
2285
2286     case CSS_PROP_VISIBILITY:
2287     {
2288         HANDLE_INHERIT_AND_INITIAL(visibility, Visibility)
2289
2290         switch(primitiveValue->getIdent()) {
2291         case CSS_VAL_HIDDEN:
2292             style->setVisibility(HIDDEN);
2293             break;
2294         case CSS_VAL_VISIBLE:
2295             style->setVisibility(VISIBLE);
2296             break;
2297         case CSS_VAL_COLLAPSE:
2298             style->setVisibility(COLLAPSE);
2299         default:
2300             break;
2301         }
2302         break;
2303     }
2304     case CSS_PROP_WHITE_SPACE:
2305         HANDLE_INHERIT_AND_INITIAL(whiteSpace, WhiteSpace)
2306
2307         if(!primitiveValue->getIdent()) return;
2308
2309         EWhiteSpace s;
2310         switch(primitiveValue->getIdent()) {
2311         case CSS_VAL__WEBKIT_NOWRAP:
2312             s = KHTML_NOWRAP;
2313             break;
2314         case CSS_VAL_NOWRAP:
2315             s = NOWRAP;
2316             break;
2317         case CSS_VAL_PRE:
2318             s = PRE;
2319             break;
2320         case CSS_VAL_PRE_WRAP:
2321             s = PRE_WRAP;
2322             break;
2323         case CSS_VAL_PRE_LINE:
2324             s = PRE_LINE;
2325             break;
2326         case CSS_VAL_NORMAL:
2327         default:
2328             s = NORMAL;
2329             break;
2330         }
2331         style->setWhiteSpace(s);
2332         break;
2333
2334     case CSS_PROP_BACKGROUND_POSITION:
2335         HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundXPosition, BackgroundXPosition);
2336         HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundYPosition, BackgroundYPosition);
2337         break;
2338     case CSS_PROP_BACKGROUND_POSITION_X: {
2339         HANDLE_BACKGROUND_VALUE(backgroundXPosition, BackgroundXPosition, value)
2340         break;
2341     }
2342     case CSS_PROP_BACKGROUND_POSITION_Y: {
2343         HANDLE_BACKGROUND_VALUE(backgroundYPosition, BackgroundYPosition, value)
2344         break;
2345     }
2346     case CSS_PROP_BORDER_SPACING: {
2347         if (isInherit) {
2348             style->setHorizontalBorderSpacing(parentStyle->horizontalBorderSpacing());
2349             style->setVerticalBorderSpacing(parentStyle->verticalBorderSpacing());
2350         }
2351         else if (isInitial) {
2352             style->setHorizontalBorderSpacing(0);
2353             style->setVerticalBorderSpacing(0);
2354         }
2355         break;
2356     }
2357     case CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING: {
2358         HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing)
2359         if (!primitiveValue) break;
2360         short spacing =  primitiveValue->computeLengthShort(style);
2361         style->setHorizontalBorderSpacing(spacing);
2362         break;
2363     }
2364     case CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING: {
2365         HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing)
2366         if (!primitiveValue) break;
2367         short spacing =  primitiveValue->computeLengthShort(style);
2368         style->setVerticalBorderSpacing(spacing);
2369         break;
2370     }
2371     case CSS_PROP_CURSOR:
2372         if (isInherit) {
2373             style->setCursor(parentStyle->cursor());
2374             style->setCursorImage(parentStyle->cursorImage());
2375             return;
2376         }
2377         if (isInitial) {
2378             style->setCursor(RenderStyle::initialCursor());
2379             style->setCursorImage(0);
2380             return;
2381         }
2382         if (primitiveValue) {
2383             int type = primitiveValue->primitiveType();
2384             if (type == CSSPrimitiveValue::CSS_IDENT) {
2385                 style->setCursor((ECursor)(primitiveValue->getIdent() - CSS_VAL_AUTO));
2386                 style->setCursorImage(0);
2387             } else if (type == CSSPrimitiveValue::CSS_URI) {
2388                 CSSImageValue* image = static_cast<CSSImageValue*>(primitiveValue);
2389                 style->setCursor(CURSOR_AUTO);
2390                 style->setCursorImage(image->image(element->document()->docLoader()));
2391             }
2392         }
2393         break;
2394 // colors || inherit
2395     case CSS_PROP_BACKGROUND_COLOR:
2396     case CSS_PROP_BORDER_TOP_COLOR:
2397     case CSS_PROP_BORDER_RIGHT_COLOR:
2398     case CSS_PROP_BORDER_BOTTOM_COLOR:
2399     case CSS_PROP_BORDER_LEFT_COLOR:
2400     case CSS_PROP_COLOR:
2401     case CSS_PROP_OUTLINE_COLOR:
2402         // this property is an extension used to get HTML4 <font> right.
2403     {
2404         Color col;
2405         if (isInherit) {
2406             HANDLE_INHERIT_COND(CSS_PROP_BACKGROUND_COLOR, backgroundColor, BackgroundColor)
2407             HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_COLOR, borderTopColor, BorderTopColor)
2408             HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_COLOR, borderBottomColor, BorderBottomColor)
2409             HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_COLOR, borderRightColor, BorderRightColor)
2410             HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_COLOR, borderLeftColor, BorderLeftColor)
2411             HANDLE_INHERIT_COND(CSS_PROP_COLOR, color, Color)
2412             HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_COLOR, outlineColor, OutlineColor)
2413             return;
2414         }
2415         if (isInitial) {
2416             // The border/outline colors will just map to the invalid color |col| above.  This will have the
2417             // effect of forcing the use of the currentColor when it comes time to draw the borders (and of
2418             // not painting the background since the color won't be valid).
2419             if (id == CSS_PROP_COLOR)
2420                 col = RenderStyle::initialColor();
2421         } else {
2422             if (!primitiveValue)
2423                 return;
2424             col = getColorFromPrimitiveValue(primitiveValue);
2425         }
2426
2427         switch(id) {
2428         case CSS_PROP_BACKGROUND_COLOR:
2429             style->setBackgroundColor(col); break;
2430         case CSS_PROP_BORDER_TOP_COLOR:
2431             style->setBorderTopColor(col); break;
2432         case CSS_PROP_BORDER_RIGHT_COLOR:
2433             style->setBorderRightColor(col); break;
2434         case CSS_PROP_BORDER_BOTTOM_COLOR:
2435             style->setBorderBottomColor(col); break;
2436         case CSS_PROP_BORDER_LEFT_COLOR:
2437             style->setBorderLeftColor(col); break;
2438         case CSS_PROP_COLOR:
2439             style->setColor(col); break;
2440         case CSS_PROP_OUTLINE_COLOR:
2441             style->setOutlineColor(col); break;
2442         }
2443         return;
2444     }
2445     break;
2446     
2447 // uri || inherit
2448     case CSS_PROP_BACKGROUND_IMAGE:
2449         HANDLE_BACKGROUND_VALUE(backgroundImage, BackgroundImage, value)
2450         break;
2451     case CSS_PROP_LIST_STYLE_IMAGE:
2452     {
2453         HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage)
2454         if (!primitiveValue)
2455             return;
2456         style->setListStyleImage(static_cast<CSSImageValue*>(primitiveValue)->image(element->document()->docLoader()));
2457         break;
2458     }
2459
2460 // length
2461     case CSS_PROP_BORDER_TOP_WIDTH:
2462     case CSS_PROP_BORDER_RIGHT_WIDTH:
2463     case CSS_PROP_BORDER_BOTTOM_WIDTH:
2464     case CSS_PROP_BORDER_LEFT_WIDTH:
2465     case CSS_PROP_OUTLINE_WIDTH:
2466     {
2467         if (isInherit) {
2468             HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_WIDTH, borderTopWidth, BorderTopWidth)
2469             HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_WIDTH, borderRightWidth, BorderRightWidth)
2470             HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_WIDTH, borderBottomWidth, BorderBottomWidth)
2471             HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_WIDTH, borderLeftWidth, BorderLeftWidth)
2472             HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_WIDTH, outlineWidth, OutlineWidth)
2473             return;
2474         }
2475         else if (isInitial) {
2476             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_TOP_WIDTH, BorderTopWidth, BorderWidth)
2477             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_RIGHT_WIDTH, BorderRightWidth, BorderWidth)
2478             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_BOTTOM_WIDTH, BorderBottomWidth, BorderWidth)
2479             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_LEFT_WIDTH, BorderLeftWidth, BorderWidth)
2480             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_OUTLINE_WIDTH, OutlineWidth, BorderWidth)
2481             return;
2482         }
2483
2484         if(!primitiveValue) break;
2485         short width = 3;
2486         switch(primitiveValue->getIdent())
2487         {
2488         case CSS_VAL_THIN:
2489             width = 1;
2490             break;
2491         case CSS_VAL_MEDIUM:
2492             width = 3;
2493             break;
2494         case CSS_VAL_THICK:
2495             width = 5;
2496             break;
2497         case CSS_VAL_INVALID:
2498             width = primitiveValue->computeLengthShort(style);
2499             break;
2500         default:
2501             return;
2502         }
2503
2504         if(width < 0) return;
2505         switch(id)
2506         {
2507         case CSS_PROP_BORDER_TOP_WIDTH:
2508             style->setBorderTopWidth(width);
2509             break;
2510         case CSS_PROP_BORDER_RIGHT_WIDTH:
2511             style->setBorderRightWidth(width);
2512             break;
2513         case CSS_PROP_BORDER_BOTTOM_WIDTH:
2514             style->setBorderBottomWidth(width);
2515             break;
2516         case CSS_PROP_BORDER_LEFT_WIDTH:
2517             style->setBorderLeftWidth(width);
2518             break;
2519         case CSS_PROP_OUTLINE_WIDTH:
2520             style->setOutlineWidth(width);
2521             break;
2522         default:
2523             return;
2524         }
2525         return;
2526     }
2527
2528     case CSS_PROP_LETTER_SPACING:
2529     case CSS_PROP_WORD_SPACING:
2530     {
2531         
2532         if (isInherit) {
2533             HANDLE_INHERIT_COND(CSS_PROP_LETTER_SPACING, letterSpacing, LetterSpacing)
2534             HANDLE_INHERIT_COND(CSS_PROP_WORD_SPACING, wordSpacing, WordSpacing)
2535             return;
2536         }
2537         else if (isInitial) {
2538             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LETTER_SPACING, LetterSpacing, LetterWordSpacing)
2539             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WORD_SPACING, WordSpacing, LetterWordSpacing)
2540             return;
2541         }
2542         
2543         int width = 0;
2544         if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NORMAL){
2545             width = 0;
2546         } else {
2547             if(!primitiveValue) return;
2548             width = primitiveValue->computeLengthInt(style);
2549         }
2550         switch(id)
2551         {
2552         case CSS_PROP_LETTER_SPACING:
2553             style->setLetterSpacing(width);
2554             break;
2555         case CSS_PROP_WORD_SPACING:
2556             style->setWordSpacing(width);
2557             break;
2558             // ### needs the definitions in renderstyle
2559         default: break;
2560         }
2561         return;
2562     }
2563
2564     case CSS_PROP_WORD_WRAP:
2565     {
2566         HANDLE_INHERIT_AND_INITIAL(wordWrap, WordWrap)
2567
2568         if(!primitiveValue->getIdent()) return;
2569
2570         EWordWrap s;
2571         switch(primitiveValue->getIdent()) {
2572         case CSS_VAL_BREAK_WORD:
2573             s = BREAK_WORD;
2574             break;
2575         case CSS_VAL_NORMAL:
2576         default:
2577             s = WBNORMAL;
2578             break;
2579         }
2580         style->setWordWrap(s);
2581         break;
2582     }
2583
2584     case CSS_PROP__WEBKIT_NBSP_MODE:
2585     {
2586         HANDLE_INHERIT_AND_INITIAL(nbspMode, NBSPMode)
2587
2588         if (!primitiveValue->getIdent()) return;
2589
2590         ENBSPMode m;
2591         switch(primitiveValue->getIdent()) {
2592         case CSS_VAL_SPACE:
2593             m = SPACE;
2594             break;
2595         case CSS_VAL_NORMAL:
2596         default:
2597             m = NBNORMAL;
2598             break;
2599         }
2600         style->setNBSPMode(m);
2601         break;
2602     }
2603
2604     case CSS_PROP__WEBKIT_LINE_BREAK:
2605     {
2606         HANDLE_INHERIT_AND_INITIAL(khtmlLineBreak, KHTMLLineBreak)
2607
2608         if (!primitiveValue->getIdent()) return;
2609
2610         EKHTMLLineBreak b;
2611         switch(primitiveValue->getIdent()) {
2612         case CSS_VAL_AFTER_WHITE_SPACE:
2613             b = AFTER_WHITE_SPACE;
2614             break;
2615         case CSS_VAL_NORMAL:
2616         default:
2617             b = LBNORMAL;
2618             break;
2619         }
2620         style->setKHTMLLineBreak(b);
2621         break;
2622     }
2623
2624     case CSS_PROP__WEBKIT_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR:
2625     {
2626         HANDLE_INHERIT_AND_INITIAL(matchNearestMailBlockquoteColor, MatchNearestMailBlockquoteColor)
2627
2628         if (!primitiveValue->getIdent()) return;
2629
2630         EMatchNearestMailBlockquoteColor c;
2631         switch(primitiveValue->getIdent()) {
2632         case CSS_VAL_NORMAL:
2633             c = BCNORMAL;
2634             break;
2635         case CSS_VAL_MATCH:
2636         default:
2637             c = MATCH;
2638             break;
2639         }
2640         style->setMatchNearestMailBlockquoteColor(c);
2641         break;
2642     }
2643
2644     case CSS_PROP_RESIZE:
2645     {
2646         HANDLE_INHERIT_AND_INITIAL(resize, Resize)
2647
2648         if (!primitiveValue->getIdent()) return;
2649
2650         EResize r;
2651         switch(primitiveValue->getIdent()) {
2652         case CSS_VAL_BOTH:
2653             r = RESIZE_BOTH;
2654             break;
2655         case CSS_VAL_HORIZONTAL:
2656             r = RESIZE_HORIZONTAL;
2657             break;
2658         case CSS_VAL_VERTICAL:
2659             r = RESIZE_VERTICAL;
2660             break;
2661         case CSS_VAL_NONE:
2662         default:
2663             r = RESIZE_NONE;
2664             break;
2665         }
2666         style->setResize(r);
2667         break;
2668     }
2669     
2670     // length, percent
2671     case CSS_PROP_MAX_WIDTH:
2672         // +none +inherit
2673         if(primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE)
2674             apply = true;
2675     case CSS_PROP_TOP:
2676     case CSS_PROP_LEFT:
2677     case CSS_PROP_RIGHT:
2678     case CSS_PROP_BOTTOM:
2679     case CSS_PROP_WIDTH:
2680     case CSS_PROP_MIN_WIDTH:
2681     case CSS_PROP_MARGIN_TOP:
2682     case CSS_PROP_MARGIN_RIGHT:
2683     case CSS_PROP_MARGIN_BOTTOM:
2684     case CSS_PROP_MARGIN_LEFT:
2685         // +inherit +auto
2686         if (id == CSS_PROP_WIDTH || id == CSS_PROP_MIN_WIDTH || id == CSS_PROP_MAX_WIDTH) {
2687             if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2688                 l = Length(Intrinsic);
2689                 apply = true;
2690             }
2691             else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2692                 l = Length(MinIntrinsic);
2693                 apply = true;
2694             }
2695         }
2696         if (id != CSS_PROP_MAX_WIDTH && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2697             apply = true;
2698     case CSS_PROP_PADDING_TOP:
2699     case CSS_PROP_PADDING_RIGHT:
2700     case CSS_PROP_PADDING_BOTTOM:
2701     case CSS_PROP_PADDING_LEFT:
2702     case CSS_PROP_TEXT_INDENT:
2703         // +inherit
2704     {
2705         if (isInherit) {
2706             HANDLE_INHERIT_COND(CSS_PROP_MAX_WIDTH, maxWidth, MaxWidth)
2707             HANDLE_INHERIT_COND(CSS_PROP_BOTTOM, bottom, Bottom)
2708             HANDLE_INHERIT_COND(CSS_PROP_TOP, top, Top)
2709             HANDLE_INHERIT_COND(CSS_PROP_LEFT, left, Left)
2710             HANDLE_INHERIT_COND(CSS_PROP_RIGHT, right, Right)
2711             HANDLE_INHERIT_COND(CSS_PROP_WIDTH, width, Width)
2712             HANDLE_INHERIT_COND(CSS_PROP_MIN_WIDTH, minWidth, MinWidth)
2713             HANDLE_INHERIT_COND(CSS_PROP_PADDING_TOP, paddingTop, PaddingTop)
2714             HANDLE_INHERIT_COND(CSS_PROP_PADDING_RIGHT, paddingRight, PaddingRight)
2715             HANDLE_INHERIT_COND(CSS_PROP_PADDING_BOTTOM, paddingBottom, PaddingBottom)
2716             HANDLE_INHERIT_COND(CSS_PROP_PADDING_LEFT, paddingLeft, PaddingLeft)
2717             HANDLE_INHERIT_COND(CSS_PROP_MARGIN_TOP, marginTop, MarginTop)
2718             HANDLE_INHERIT_COND(CSS_PROP_MARGIN_RIGHT, marginRight, MarginRight)
2719             HANDLE_INHERIT_COND(CSS_PROP_MARGIN_BOTTOM, marginBottom, MarginBottom)
2720             HANDLE_INHERIT_COND(CSS_PROP_MARGIN_LEFT, marginLeft, MarginLeft)
2721             HANDLE_INHERIT_COND(CSS_PROP_TEXT_INDENT, textIndent, TextIndent)
2722             return;
2723         }
2724         else if (isInitial) {
2725             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_WIDTH, MaxWidth, MaxSize)
2726             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BOTTOM, Bottom, Offset)
2727             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_TOP, Top, Offset)
2728             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LEFT, Left, Offset)
2729             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_RIGHT, Right, Offset)
2730             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WIDTH, Width, Size)
2731             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_WIDTH, MinWidth, MinSize)
2732             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_TOP, PaddingTop, Padding)
2733             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_RIGHT, PaddingRight, Padding)
2734             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_BOTTOM, PaddingBottom, Padding)
2735             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_LEFT, PaddingLeft, Padding)
2736             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_TOP, MarginTop, Margin)
2737             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_RIGHT, MarginRight, Margin)
2738             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_BOTTOM, MarginBottom, Margin)
2739             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_LEFT, MarginLeft, Margin)
2740             HANDLE_INITIAL_COND(CSS_PROP_TEXT_INDENT, TextIndent)
2741             return;
2742         } 
2743
2744         if (primitiveValue && !apply) {
2745             int type = primitiveValue->primitiveType();
2746             if(type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2747                 // Handle our quirky margin units if we have them.
2748                 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed, 
2749                            primitiveValue->isQuirkValue());
2750             else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
2751                 l = Length((int)primitiveValue->getFloatValue(), Percent);
2752             else
2753                 return;
2754             if (id == CSS_PROP_PADDING_LEFT || id == CSS_PROP_PADDING_RIGHT ||
2755                 id == CSS_PROP_PADDING_TOP || id == CSS_PROP_PADDING_BOTTOM)
2756                 // Padding can't be negative
2757                 apply = !((l.isFixed() || l.isPercent()) && l.calcValue(100) < 0);
2758             else
2759                 apply = true;
2760         }
2761         if(!apply) return;
2762         switch(id)
2763             {
2764             case CSS_PROP_MAX_WIDTH:
2765                 style->setMaxWidth(l); break;
2766             case CSS_PROP_BOTTOM:
2767                 style->setBottom(l); break;
2768             case CSS_PROP_TOP:
2769                 style->setTop(l); break;
2770             case CSS_PROP_LEFT:
2771                 style->setLeft(l); break;
2772             case CSS_PROP_RIGHT:
2773                 style->setRight(l); break;
2774             case CSS_PROP_WIDTH:
2775                 style->setWidth(l); break;
2776             case CSS_PROP_MIN_WIDTH:
2777                 style->setMinWidth(l); break;
2778             case CSS_PROP_PADDING_TOP:
2779                 style->setPaddingTop(l); break;
2780             case CSS_PROP_PADDING_RIGHT:
2781                 style->setPaddingRight(l); break;
2782             case CSS_PROP_PADDING_BOTTOM:
2783                 style->setPaddingBottom(l); break;
2784             case CSS_PROP_PADDING_LEFT:
2785                 style->setPaddingLeft(l); break;
2786             case CSS_PROP_MARGIN_TOP:
2787                 style->setMarginTop(l); break;
2788             case CSS_PROP_MARGIN_RIGHT:
2789                 style->setMarginRight(l); break;
2790             case CSS_PROP_MARGIN_BOTTOM:
2791                 style->setMarginBottom(l); break;
2792             case CSS_PROP_MARGIN_LEFT:
2793                 style->setMarginLeft(l); break;
2794             case CSS_PROP_TEXT_INDENT:
2795                 style->setTextIndent(l); break;
2796             default: break;
2797             }
2798         return;
2799     }
2800
2801     case CSS_PROP_MAX_HEIGHT:
2802         if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
2803             l = Length(undefinedLength, Fixed);
2804             apply = true;
2805         }
2806     case CSS_PROP_HEIGHT:
2807     case CSS_PROP_MIN_HEIGHT:
2808         if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2809             l = Length(Intrinsic);
2810             apply = true;
2811         } else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2812             l = Length(MinIntrinsic);
2813             apply = true;
2814         } else if (id != CSS_PROP_MAX_HEIGHT && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2815             apply = true;
2816         if (isInherit) {
2817             HANDLE_INHERIT_COND(CSS_PROP_MAX_HEIGHT, maxHeight, MaxHeight)
2818             HANDLE_INHERIT_COND(CSS_PROP_HEIGHT, height, Height)
2819             HANDLE_INHERIT_COND(CSS_PROP_MIN_HEIGHT, minHeight, MinHeight)
2820             return;
2821         }
2822         if (isInitial) {
2823             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_HEIGHT, MaxHeight, MaxSize)
2824             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_HEIGHT, Height, Size)
2825             HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_HEIGHT, MinHeight, MinSize)
2826             return;
2827         }
2828
2829         if (primitiveValue && !apply) {
2830             unsigned short type = primitiveValue->primitiveType();
2831             if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2832                 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2833             else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2834                 l = Length((int)primitiveValue->getFloatValue(), Percent);
2835             else
2836                 return;
2837             apply = true;
2838         }
2839         if (apply)
2840             switch (id) {
2841                 case CSS_PROP_MAX_HEIGHT:
2842                     style->setMaxHeight(l);
2843                     break;
2844                 case CSS_PROP_HEIGHT:
2845                     style->setHeight(l);
2846                     break;
2847                 case CSS_PROP_MIN_HEIGHT:
2848                     style->setMinHeight(l);
2849                     break;
2850             }
2851         break;
2852
2853     case CSS_PROP_VERTICAL_ALIGN:
2854         HANDLE_INHERIT_AND_INITIAL(verticalAlign, VerticalAlign)
2855         if (!primitiveValue) return;
2856         if (primitiveValue->getIdent()) {
2857           EVerticalAlign align;
2858
2859           switch(primitiveValue->getIdent())
2860             {
2861                 case CSS_VAL_TOP:
2862                     align = TOP; break;
2863                 case CSS_VAL_BOTTOM:
2864                     align = BOTTOM; break;
2865                 case CSS_VAL_MIDDLE:
2866                     align = MIDDLE; break;
2867                 case CSS_VAL_BASELINE:
2868                     align = BASELINE; break;
2869                 case CSS_VAL_TEXT_BOTTOM:
2870                     align = TEXT_BOTTOM; break;
2871                 case CSS_VAL_TEXT_TOP:
2872                     align = TEXT_TOP; break;
2873                 case CSS_VAL_SUB:
2874                     align = SUB; break;
2875                 case CSS_VAL_SUPER:
2876                     align = SUPER; break;
2877                 case CSS_VAL__WEBKIT_BASELINE_MIDDLE:
2878                     align = BASELINE_MIDDLE; break;
2879                 default:
2880                     return;
2881             }
2882           style->setVerticalAlign(align);
2883           return;
2884         } else {
2885           int type = primitiveValue->primitiveType();
2886           Length l;
2887           if(type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2888             l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2889           else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
2890             l = Length(int(primitiveValue->getFloatValue()), Percent);
2891
2892           style->setVerticalAlign(LENGTH);
2893           style->setVerticalAlignLength(l);
2894         }
2895         break;
2896
2897     case CSS_PROP_FONT_SIZE:
2898     {
2899         FontDescription fontDescription = style->fontDescription();
2900         float oldSize = 0;
2901         float size = 0;
2902         
2903         bool parentIsAbsoluteSize = false;
2904         if (parentNode) {
2905             oldSize = parentStyle->fontDescription().specifiedSize();
2906             parentIsAbsoluteSize = parentStyle->fontDescription().isAbsoluteSize();
2907         }
2908
2909         if (isInherit)
2910             size = oldSize;
2911         else if (isInitial)
2912             size = fontSizeForKeyword(CSS_VAL_MEDIUM, style->htmlHacks());
2913         else if (primitiveValue->getIdent()) {
2914             // Keywords are being used.
2915             switch (primitiveValue->getIdent()) {
2916             case CSS_VAL_XX_SMALL:
2917             case CSS_VAL_X_SMALL:
2918             case CSS_VAL_SMALL:
2919             case CSS_VAL_MEDIUM:
2920             case CSS_VAL_LARGE:
2921             case CSS_VAL_X_LARGE:
2922             case CSS_VAL_XX_LARGE:
2923             case CSS_VAL__WEBKIT_XXX_LARGE:
2924                 size = fontSizeForKeyword(primitiveValue->getIdent(), style->htmlHacks());
2925                 break;
2926             case CSS_VAL_LARGER:
2927                 size = largerFontSize(oldSize, style->htmlHacks());
2928                 break;
2929             case CSS_VAL_SMALLER:
2930                 size = smallerFontSize(oldSize, style->htmlHacks());
2931                 break;
2932             default:
2933                 return;
2934             }
2935
2936             fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize && 
2937                                               (primitiveValue->getIdent() == CSS_VAL_LARGER ||
2938                                                primitiveValue->getIdent() == CSS_VAL_SMALLER));
2939         } else {
2940             int type = primitiveValue->primitiveType();
2941             fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize ||
2942                                               (type != CSSPrimitiveValue::CSS_PERCENTAGE &&
2943                                                type != CSSPrimitiveValue::CSS_EMS && 
2944                                                type != CSSPrimitiveValue::CSS_EXS));
2945             if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2946                 size = primitiveValue->computeLengthFloat(parentStyle, false);
2947             else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
2948                 size = (primitiveValue->getFloatValue() * oldSize) / 100;
2949             else
2950                 return;
2951         }
2952
2953         if (size <= 0)
2954             return;
2955
2956         setFontSize(fontDescription, size);
2957         if (style->setFontDescription(fontDescription))
2958             fontDirty = true;
2959         return;
2960     }
2961         break;
2962     case CSS_PROP_Z_INDEX:
2963     {
2964         HANDLE_INHERIT(zIndex, ZIndex)
2965         else if (isInitial) {
2966             style->setHasAutoZIndex();
2967             return;
2968         }
2969         
2970         if (!primitiveValue)
2971             return;
2972
2973         if (primitiveValue->getIdent() == CSS_VAL_AUTO) {
2974             style->setHasAutoZIndex();
2975             return;
2976         }
2977         
2978         if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2979             return; // Error case.
2980         
2981         style->setZIndex((int)primitiveValue->getFloatValue());
2982         
2983         return;
2984     }
2985         
2986     case CSS_PROP_WIDOWS:
2987     {
2988         HANDLE_INHERIT_AND_INITIAL(widows, Widows)
2989         if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2990             return;
2991         style->setWidows((int)primitiveValue->getFloatValue());
2992         break;
2993     }
2994         
2995     case CSS_PROP_ORPHANS:
2996     {
2997         HANDLE_INHERIT_AND_INITIAL(orphans, Orphans)
2998         if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2999             return;
3000         style->setOrphans((int)primitiveValue->getFloatValue());
3001         break;
3002     }        
3003
3004 // length, percent, number
3005     case CSS_PROP_LINE_HEIGHT:
3006     {
3007         HANDLE_INHERIT_AND_INITIAL(lineHeight, LineHeight)
3008         if(!primitiveValue) return;
3009         Length lineHeight;
3010         int type = primitiveValue->primitiveType();
3011         if (primitiveValue->getIdent() == CSS_VAL_NORMAL)
3012             lineHeight = Length(-100, Percent);
3013         else if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
3014             double multiplier = 1.0;
3015             // Scale for the font zoom factor only for types other than "em" and "ex", since those are
3016             // already based on the font size.
3017             if (type != CSSPrimitiveValue::CSS_EMS && type != CSSPrimitiveValue::CSS_EXS && view && view->frame()) {
3018                 multiplier = view->frame()->zoomFactor() / 100.0;
3019             }
3020             lineHeight = Length(primitiveValue->computeLengthIntForLength(style, multiplier), Fixed);
3021         } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
3022             lineHeight = Length((style->fontSize() * int(primitiveValue->getFloatValue())) / 100, Fixed);
3023         else if (type == CSSPrimitiveValue::CSS_NUMBER)
3024             lineHeight = Length(int(primitiveValue->getFloatValue() * 100), Percent);
3025         else
3026             return;
3027         style->setLineHeight(lineHeight);
3028         return;
3029     }
3030
3031 // string
3032     case CSS_PROP_TEXT_ALIGN:
3033     {
3034         HANDLE_INHERIT_AND_INITIAL(textAlign, TextAlign)
3035         if (!primitiveValue) return;
3036         if (primitiveValue->getIdent())
3037             style->setTextAlign((ETextAlign) (primitiveValue->getIdent() - CSS_VAL__WEBKIT_AUTO));
3038         return;
3039     }
3040
3041 // rect
3042     case CSS_PROP_CLIP:
3043     {
3044         Length top;
3045         Length right;
3046         Length bottom;
3047         Length left;
3048         bool hasClip = true;
3049         if (isInherit) {
3050             if (parentStyle->hasClip()) {
3051                 top = parentStyle->clipTop();
3052                 right = parentStyle->clipRight();
3053                 bottom = parentStyle->clipBottom();
3054                 left = parentStyle->clipLeft();
3055             }
3056             else {
3057                 hasClip = false;
3058                 top = right = bottom = left = Length();
3059             }
3060         } else if (isInitial) {
3061             hasClip = false;
3062             top = right = bottom = left = Length();
3063         } else if (!primitiveValue) {
3064             break;
3065         } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) {
3066             RectImpl* rect = primitiveValue->getRectValue();
3067             if (!rect)
3068                 break;
3069             top = convertToLength(rect->top(), style);
3070             right = convertToLength(rect->right(), style);
3071             bottom = convertToLength(rect->bottom(), style);
3072             left = convertToLength(rect->left(), style);
3073
3074         } else if (primitiveValue->getIdent() != CSS_VAL_AUTO) {
3075             break;
3076         }
3077         style->setClip(top, right, bottom, left);
3078         style->setHasClip(hasClip);
3079     
3080         // rect, ident
3081         break;
3082     }
3083
3084 // lists
3085     case CSS_PROP_CONTENT:
3086         // list of string, uri, counter, attr, i
3087     {
3088         // FIXME: In CSS3, it will be possible to inherit content.  In CSS2 it is not.  This
3089         // note is a reminder that eventually "inherit" needs to be supported.
3090         if (!(style->styleType()==RenderStyle::BEFORE ||
3091                 style->styleType()==RenderStyle::AFTER))
3092             break;
3093
3094         if (isInitial) {
3095             if (style->contentData())
3096                 style->contentData()->clearContent();
3097             return;
3098         }
3099         
3100         if (!value->isValueList()) return;
3101         CSSValueList *list = static_cast<CSSValueList*>(value);
3102         int len = list->length();
3103
3104         for (int i = 0; i < len; i++) {
3105             CSSValue *item = list->item(i);
3106             if (!item->isPrimitiveValue()) continue;
3107             CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item);
3108             if (val->primitiveType()==CSSPrimitiveValue::CSS_STRING)
3109                 style->setContent(val->getStringValue().impl(), i != 0);
3110             else if (val->primitiveType()==CSSPrimitiveValue::CSS_ATTR) {
3111                 // FIXME: Can a namespace be specified for an attr(foo)?
3112                 if (style->styleType() == RenderStyle::NOPSEUDO)
3113                     style->setUnique();
3114                 else
3115                     parentStyle->setUnique();
3116                 QualifiedName attr(nullAtom, val->getStringValue().impl(), nullAtom);
3117                 style->setContent(element->getAttribute(attr).impl(), i != 0);
3118                 // register the fact that the attribute value affects the style
3119                 m_selectorAttrs.add(attr.localName().impl());
3120             }
3121             else if (val->primitiveType()==CSSPrimitiveValue::CSS_URI) {
3122                 CSSImageValue *image = static_cast<CSSImageValue*>(val);
3123                 style->setContent(image->image(element->document()->docLoader()), i != 0);
3124             }
3125         }
3126         break;
3127     }
3128
3129     case CSS_PROP_COUNTER_INCREMENT:
3130         // list of CSS2CounterIncrement
3131     case CSS_PROP_COUNTER_RESET:
3132         // list of CSS2CounterReset
3133         break;
3134     case CSS_PROP_FONT_FAMILY: {
3135         // list of strings and ids
3136         if (isInherit) {
3137             FontDescription parentFontDescription = parentStyle->fontDescription();
3138             FontDescription fontDescription = style->fontDescription();
3139             fontDescription.setGenericFamily(parentFontDescription.genericFamily());
3140             fontDescription.setFamily(parentFontDescription.firstFamily());
3141             if (style->setFontDescription(fontDescription))
3142                 fontDirty = true;
3143             return;
3144         }
3145         else if (isInitial) {
3146             FontDescription initialDesc = FontDescription();
3147             FontDescription fontDescription = style->fontDescription();
3148             fontDescription.setGenericFamily(initialDesc.genericFamily());
3149             fontDescription.setFamily(initialDesc.firstFamily());
3150             if (style->setFontDescription(fontDescription))
3151                 fontDirty = true;
3152             return;
3153         }
3154         
3155         if (!value->isValueList()) return;
3156         FontDescription fontDescription = style->fontDescription();
3157         CSSValueList *list = static_cast<CSSValueList*>(value);
3158         int len = list->length();
3159         FontFamily& firstFamily = fontDescription.firstFamily();
3160         FontFamily *currFamily = 0;
3161         
3162         for(int i = 0; i < len; i++) {
3163             CSSValue *item = list->item(i);
3164             if(!item->isPrimitiveValue()) continue;
3165             CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item);
3166             AtomicString face;
3167             if(val->primitiveType() == CSSPrimitiveValue::CSS_STRING)
3168                 face = static_cast<FontFamilyValue*>(val)->fontName();
3169             else if (val->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
3170                 switch (val->getIdent()) {
3171                     case CSS_VAL__WEBKIT_BODY:
3172                         face = settings->stdFontName();
3173                         break;
3174                     case CSS_VAL_SERIF:
3175                         face = settings->serifFontName();
3176                         fontDescription.setGenericFamily(FontDescription::SerifFamily);
3177                         break;
3178                     case CSS_VAL_SANS_SERIF:
3179                         face = settings->sansSerifFontName();
3180                         fontDescription.setGenericFamily(FontDescription::SansSerifFamily);
3181                         break;
3182                     case CSS_VAL_CURSIVE:
3183                         face = settings->cursiveFontName();
3184                         fontDescription.setGenericFamily(FontDescription::CursiveFamily);
3185                         break;
3186                     case CSS_VAL_FANTASY:
3187                         face = settings->fantasyFontName();
3188                         fontDescription.setGenericFamily(FontDescription::FantasyFamily);
3189                         break;
3190                     case CSS_VAL_MONOSPACE:
3191                         face = settings->fixedFontName();
3192                         fontDescription.setGenericFamily(FontDescription::MonospaceFamily);
3193                         break;
3194                 }
3195             }
3196     
3197             if (!face.isEmpty()) {
3198                 if (!currFamily) {
3199                     // Filling in the first family.
3200                     firstFamily.setFamily(face);
3201                     currFamily = &firstFamily;
3202                 }
3203                 else {
3204                     FontFamily *newFamily = new FontFamily;
3205                     newFamily->setFamily(face);
3206                     currFamily->appendFamily(newFamily);
3207                     currFamily = newFamily;
3208                 }
3209                 
3210                 if (style->setFontDescription(fontDescription))
3211                     fontDirty = true;
3212             }
3213         }
3214       break;
3215     }
3216     case CSS_PROP_QUOTES:
3217         // list of strings or i
3218     case CSS_PROP_SIZE:
3219         // ### look up
3220       break;
3221     case CSS_PROP_TEXT_DECORATION: {
3222         // list of ident
3223         HANDLE_INHERIT_AND_INITIAL(textDecoration, TextDecoration)
3224         int t = RenderStyle::initialTextDecoration();
3225         if(primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
3226             // do nothing
3227         } else {
3228             if(!value->isValueList()) return;
3229             CSSValueList *list = static_cast<CSSValueList*>(value);
3230             int len = list->length();
3231             for(int i = 0; i < len; i++)
3232             {
3233                 CSSValue *item = list->item(i);
3234                 if(!item->isPrimitiveValue()) continue;
3235                 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
3236                 switch(primitiveValue->getIdent())
3237                 {
3238                     case CSS_VAL_NONE:
3239                         t = TDNONE; break;
3240                     case CSS_VAL_UNDERLINE:
3241                         t |= UNDERLINE; break;
3242                     case CSS_VAL_OVERLINE:
3243                         t |= OVERLINE; break;
3244                     case CSS_VAL_LINE_THROUGH:
3245                         t |= LINE_THROUGH; break;
3246                     case CSS_VAL_BLINK:
3247                         t |= BLINK; break;
3248                     default:
3249                         return;
3250                 }
3251             }
3252         }
3253
3254         style->setTextDecoration(t);
3255         break;
3256     }
3257
3258 // shorthand properties
3259     case CSS_PROP_BACKGROUND:
3260         if (isInitial) {
3261             style->clearBackgroundLayers();
3262             return;
3263         }
3264         else if (isInherit) {
3265             if (parentStyle)
3266                 style->inheritBackgroundLayers(*parentStyle->backgroundLayers());
3267             else
3268                 style->clearBackgroundLayers();
3269             return;
3270         }
3271         break;
3272     case CSS_PROP_BORDER:
3273     case CSS_PROP_BORDER_STYLE:
3274     case CSS_PROP_BORDER_WIDTH:
3275     case CSS_PROP_BORDER_COLOR:
3276         if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_COLOR)
3277         {
3278             if (isInherit) {
3279                 style->setBorderTopColor(parentStyle->borderTopColor());
3280                 style->setBorderBottomColor(parentStyle->borderBottomColor());
3281                 style->setBorderLeftColor(parentStyle->borderLeftColor());
3282                 style->setBorderRightColor(parentStyle->borderRightColor());
3283             }
3284             else if (isInitial) {
3285                 style->setBorderTopColor(Color()); // Reset to invalid color so currentColor is used instead.
3286                 style->setBorderBottomColor(Color());
3287                 style->setBorderLeftColor(Color());
3288                 style->setBorderRightColor(Color());
3289             }
3290         }
3291         if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_STYLE)
3292         {
3293             if (isInherit) {
3294                 style->setBorderTopStyle(parentStyle->borderTopStyle());
3295                 style->setBorderBottomStyle(parentStyle->borderBottomStyle());
3296                 style->setBorderLeftStyle(parentStyle->borderLeftStyle());
3297                 style->setBorderRightStyle(parentStyle->borderRightStyle());
3298             }
3299             else if (isInitial) {
3300 &n