fix logic
[personal-kdelibs.git] / khtml / css / css_valueimpl.cpp
blob6e8949a8636149b3876ec1d4599abfad217883b5
1 /**
2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
5 * (C) 2004-2007 Apple Computer, Inc.
6 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
24 #include "css_valueimpl.h"
25 #include "css_ruleimpl.h"
26 #include "css_stylesheetimpl.h"
27 #include "cssparser.h"
28 #include "cssproperties.h"
29 #include "cssvalues.h"
31 #include <dom/css_value.h>
32 #include <dom/dom_exception.h>
33 #include <dom/dom_string.h>
35 #include <xml/dom_stringimpl.h>
36 #include <xml/dom_docimpl.h>
38 #include <misc/loader.h>
40 #include <rendering/font.h>
41 #include <rendering/render_style.h>
43 #include <wtf/ASCIICType.h>
45 #include <kdebug.h>
46 #include <QtCore/QRegExp>
47 #include <QtGui/QPaintDevice>
49 // Hack for debugging purposes
50 extern DOM::DOMString getPropertyName(unsigned short id);
52 using khtml::FontDef;
54 using namespace DOM;
55 using namespace WTF;
57 static int propertyID(const DOMString &s)
59 char buffer[maxCSSPropertyNameLength];
61 unsigned len = s.length();
62 if (len > maxCSSPropertyNameLength)
63 return 0;
65 for (unsigned i = 0; i != len; ++i) {
66 unsigned short c = s[i].unicode();
67 if (c == 0 || c >= 0x7F)
68 return 0; // illegal character
69 buffer[i] = s[i].toLower().unicode();
72 return getPropertyID(buffer, len);
75 // "ident" from the CSS tokenizer, minus backslash-escape sequences
76 static bool isCSSTokenizerIdentifier(const DOMString& string)
78 const QChar* p = string.unicode();
79 const QChar* end = p + string.length();
81 // -?
82 if (p != end && p[0] == '-')
83 ++p;
85 // {nmstart}
86 if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p->unicode())))
87 return false;
88 ++p;
90 // {nmchar}*
91 for (; p != end; ++p) {
92 if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p->unicode())))
93 return false;
96 return true;
99 static DOMString quoteString(const DOMString &string)
101 // FIXME: Also need to transform control characters into \ sequences.
102 QString s = string.string();
103 s.replace('\\', "\\\\");
104 s.replace('\'', "\\'");
105 return '\'' + s + '\'';
108 // Quotes the string if it needs quoting.
109 static DOMString quoteStringIfNeeded(const DOMString &string)
111 return isCSSTokenizerIdentifier(string) ? string : quoteString(string);
114 CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent)
115 : StyleBaseImpl(parent)
117 m_lstValues = 0;
118 m_node = 0;
121 CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent, QList<CSSProperty*> *lstValues)
122 : StyleBaseImpl(parent)
124 m_lstValues = lstValues;
125 m_node = 0;
128 CSSStyleDeclarationImpl& CSSStyleDeclarationImpl::operator= (const CSSStyleDeclarationImpl& o)
130 if (this == &o) return *this;
132 // don't attach it to the same node, just leave the current m_node value
133 if (m_lstValues)
134 qDeleteAll(*m_lstValues);
135 delete m_lstValues;
136 m_lstValues = 0;
137 if (o.m_lstValues) {
138 m_lstValues = new QList<CSSProperty*>;
139 QListIterator<CSSProperty*> lstValuesIt(*o.m_lstValues);
140 while ( lstValuesIt.hasNext() )
141 m_lstValues->append(new CSSProperty(*lstValuesIt.next()));
144 return *this;
147 CSSStyleDeclarationImpl::~CSSStyleDeclarationImpl()
149 if (m_lstValues)
150 qDeleteAll( *m_lstValues );
151 delete m_lstValues;
152 // we don't use refcounting for m_node, to avoid cyclic references (see ElementImpl)
155 CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue(const DOMString &propertyName) const
157 int propID = propertyID(propertyName);
158 if (!propID)
159 return 0;
160 return getPropertyCSSValue(propID);
163 DOMString CSSStyleDeclarationImpl::getPropertyValue(const DOMString &propertyName) const
165 int propID = propertyID(propertyName);
166 if (!propID)
167 return DOMString();
168 return getPropertyValue(propID);
171 DOMString CSSStyleDeclarationImpl::getPropertyPriority(const DOMString &propertyName) const
173 int propID = propertyID(propertyName);
174 if (!propID)
175 return DOMString();
176 return getPropertyPriority(propID) ? "important" : "";
179 void CSSStyleDeclarationImpl::setProperty(const DOMString &propertyName, const DOMString &value, const DOMString &priority)
181 int propID = propertyID(propertyName);
182 if (!propID) // set exception?
183 return;
184 bool important = priority.string().indexOf("important", 0, Qt::CaseInsensitive) != -1;
185 setProperty(propID, value, important);
188 DOMString CSSStyleDeclarationImpl::removeProperty(const DOMString &propertyName)
190 int propID = propertyID(propertyName);
191 if (!propID)
192 return DOMString();
193 DOMString old;
194 removeProperty(propID, &old);
195 return old;
198 DOMString CSSStyleDeclarationImpl::getPropertyValue( int propertyID ) const
200 if(!m_lstValues) return DOMString();
201 CSSValueImpl* value = getPropertyCSSValue( propertyID );
202 if ( value )
203 return value->cssText();
205 // Shorthand and 4-values properties
206 switch ( propertyID ) {
207 case CSS_PROP_BACKGROUND_POSITION:
209 // ## Is this correct? The code in cssparser.cpp is confusing
210 const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X,
211 CSS_PROP_BACKGROUND_POSITION_Y };
212 return getLayeredShortHandValue( properties, 2 );
214 case CSS_PROP_BACKGROUND:
216 const int properties[6] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
217 CSS_PROP_BACKGROUND_ATTACHMENT,CSS_PROP_BACKGROUND_POSITION_X,
218 CSS_PROP_BACKGROUND_POSITION_Y, CSS_PROP_BACKGROUND_COLOR };
219 return getLayeredShortHandValue( properties, 6 );
221 case CSS_PROP_BORDER:
223 const int properties[3][4] = {{ CSS_PROP_BORDER_TOP_WIDTH,
224 CSS_PROP_BORDER_RIGHT_WIDTH,
225 CSS_PROP_BORDER_BOTTOM_WIDTH,
226 CSS_PROP_BORDER_LEFT_WIDTH },
227 { CSS_PROP_BORDER_TOP_STYLE,
228 CSS_PROP_BORDER_RIGHT_STYLE,
229 CSS_PROP_BORDER_BOTTOM_STYLE,
230 CSS_PROP_BORDER_LEFT_STYLE },
231 { CSS_PROP_BORDER_TOP_COLOR,
232 CSS_PROP_BORDER_RIGHT_COLOR,
233 CSS_PROP_BORDER_LEFT_COLOR,
234 CSS_PROP_BORDER_BOTTOM_COLOR }};
235 DOMString res;
236 const int nrprops = sizeof(properties) / sizeof(properties[0]);
237 for (int i = 0; i < nrprops; ++i) {
238 DOMString value = getCommonValue(properties[i], 4);
239 if (!value.isNull()) {
240 if (!res.isNull())
241 res += " ";
242 res += value;
245 return res;
248 case CSS_PROP_BORDER_TOP:
250 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
251 CSS_PROP_BORDER_TOP_COLOR};
252 return getShortHandValue( properties, 3 );
254 case CSS_PROP_BORDER_RIGHT:
256 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
257 CSS_PROP_BORDER_RIGHT_COLOR};
258 return getShortHandValue( properties, 3 );
260 case CSS_PROP_BORDER_BOTTOM:
262 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
263 CSS_PROP_BORDER_BOTTOM_COLOR};
264 return getShortHandValue( properties, 3 );
266 case CSS_PROP_BORDER_LEFT:
268 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
269 CSS_PROP_BORDER_LEFT_COLOR};
270 return getShortHandValue( properties, 3 );
272 case CSS_PROP_OUTLINE:
274 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
275 CSS_PROP_OUTLINE_COLOR };
276 return getShortHandValue( properties, 3 );
278 case CSS_PROP_BORDER_COLOR:
280 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
281 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
282 return get4Values( properties );
284 case CSS_PROP_BORDER_WIDTH:
286 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
287 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
288 return get4Values( properties );
290 case CSS_PROP_BORDER_STYLE:
292 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
293 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
294 return get4Values( properties );
296 case CSS_PROP_MARGIN:
298 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
299 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
300 return get4Values( properties );
302 case CSS_PROP_PADDING:
304 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
305 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
306 return get4Values( properties );
308 case CSS_PROP_LIST_STYLE:
310 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
311 CSS_PROP_LIST_STYLE_IMAGE };
312 return getShortHandValue( properties, 3 );
315 //kDebug() << "property not found:" << propertyID;
316 return DOMString();
319 // only returns a non-null value if all properties have the same, non-null value
320 DOMString CSSStyleDeclarationImpl::getCommonValue(const int* properties, int number) const
322 DOMString res;
323 for (int i = 0; i < number; ++i) {
324 CSSValueImpl* value = getPropertyCSSValue(properties[i]);
325 if (!value)
326 return DOMString();
327 DOMString text = value->cssText();
328 if (text.isNull())
329 return DOMString();
330 if (res.isNull())
331 res = text;
332 else if (res != text)
333 return DOMString();
335 return res;
338 DOMString CSSStyleDeclarationImpl::get4Values( const int* properties ) const
340 DOMString res;
341 for ( int i = 0 ; i < 4 ; ++i ) {
342 if (!isPropertyImplicit(properties[i])) {
343 CSSValueImpl* value = getPropertyCSSValue( properties[i] );
344 if ( !value ) { // apparently all 4 properties must be specified.
345 return DOMString();
347 if ( i > 0 )
348 res += " ";
349 res += value->cssText();
352 return res;
355 DOMString CSSStyleDeclarationImpl::getLayeredShortHandValue(const int* properties, unsigned number) const
357 DOMString res;
358 unsigned i;
359 unsigned j;
361 // Begin by collecting the properties into an array.
362 QVector<CSSValueImpl*> values(number);
363 unsigned numLayers = 0;
365 for (i = 0; i < number; ++i) {
366 values[i] = getPropertyCSSValue(properties[i]);
367 if (values[i]) {
368 if (values[i]->isValueList()) {
369 CSSValueListImpl* valueList = static_cast<CSSValueListImpl*>(values[i]);
370 numLayers = qMax(valueList->length(), (unsigned long)numLayers);
371 } else
372 numLayers = qMax(1U, numLayers);
376 // Now stitch the properties together. Implicit initial values are flagged as such and
377 // can safely be omitted.
378 for (i = 0; i < numLayers; i++) {
379 DOMString layerRes;
380 for (j = 0; j < number; j++) {
381 CSSValueImpl* value = 0;
382 if (values[j]) {
383 if (values[j]->isValueList())
384 value = static_cast<CSSValueListImpl*>(values[j])->item(i);
385 else {
386 value = values[j];
388 // Color only belongs in the last layer.
389 if (properties[j] == CSS_PROP_BACKGROUND_COLOR) {
390 if (i != numLayers - 1)
391 value = 0;
392 } else if (i != 0) // Other singletons only belong in the first layer.
393 value = 0;
397 if (value && !value->isImplicitInitialValue()) {
398 if (!layerRes.isNull())
399 layerRes += " ";
400 layerRes += value->cssText();
404 if (!layerRes.isNull()) {
405 if (!res.isNull())
406 res += ", ";
407 res += layerRes;
411 return res;
414 DOMString CSSStyleDeclarationImpl::getShortHandValue( const int* properties, int number ) const
416 DOMString res;
417 for ( int i = 0 ; i < number ; ++i ) {
418 CSSValueImpl* value = getPropertyCSSValue( properties[i] );
419 if ( value ) { // TODO provide default value if !value
420 if ( !res.isNull() )
421 res += " ";
422 res += value->cssText();
425 return res;
428 CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue( int propertyID ) const
430 if(!m_lstValues) return 0;
432 QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
433 CSSProperty *current;
434 while ( lstValuesIt.hasNext() ) {
435 current = lstValuesIt.next();
436 if (current->m_id == propertyID)
437 return current->value();
439 return 0;
442 bool CSSStyleDeclarationImpl::isPropertyImplicit(int propertyID) const
444 QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
445 CSSProperty const *current;
446 while ( lstValuesIt.hasNext() ) {
447 current = lstValuesIt.next();
448 if (current->m_id == propertyID)
449 return current->isImplicit();;
451 return false;
454 // --------------- Shorthands mapping ----------------
456 // In order top be able to remove a shorthand property,
457 // we need a reverse mapping from the shorthands to their composing properties.
459 // ### Warning: keep in sync when introducing new shorthands.
461 struct PropertyLonghand {
462 PropertyLonghand()
463 : m_properties(0)
464 , m_length(0)
468 PropertyLonghand(const int* firstProperty, unsigned numProperties)
469 : m_properties(firstProperty)
470 , m_length(numProperties)
474 const int* properties() const { return m_properties; }
475 unsigned length() const { return m_length; }
477 private:
478 const int* m_properties;
479 unsigned m_length;
482 static void initShorthandMap(QHash<int, PropertyLonghand>& shorthandMap)
484 #define SET_SHORTHAND_MAP_ENTRY(map, propID, array) \
485 map.insert(propID, PropertyLonghand(array, sizeof(array) / sizeof(array[0])))
487 // FIXME: The 'font' property has "shorthand nature" but is not parsed as a shorthand.
489 // Do not change the order of the following four shorthands, and keep them together.
490 static const int borderProperties[4][3] = {
491 { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_TOP_WIDTH },
492 { CSS_PROP_BORDER_RIGHT_COLOR, CSS_PROP_BORDER_RIGHT_STYLE, CSS_PROP_BORDER_RIGHT_WIDTH },
493 { CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_BOTTOM_WIDTH },
494 { CSS_PROP_BORDER_LEFT_COLOR, CSS_PROP_BORDER_LEFT_STYLE, CSS_PROP_BORDER_LEFT_WIDTH }
496 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_TOP, borderProperties[0]);
497 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_RIGHT, borderProperties[1]);
498 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_BOTTOM, borderProperties[2]);
499 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_LEFT, borderProperties[3]);
501 shorthandMap.insert(CSS_PROP_BORDER, PropertyLonghand(borderProperties[0], sizeof(borderProperties) / sizeof(borderProperties[0][0])));
503 static const int borderColorProperties[] = {
504 CSS_PROP_BORDER_TOP_COLOR,
505 CSS_PROP_BORDER_RIGHT_COLOR,
506 CSS_PROP_BORDER_BOTTOM_COLOR,
507 CSS_PROP_BORDER_LEFT_COLOR
509 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_COLOR, borderColorProperties);
511 static const int borderStyleProperties[] = {
512 CSS_PROP_BORDER_TOP_STYLE,
513 CSS_PROP_BORDER_RIGHT_STYLE,
514 CSS_PROP_BORDER_BOTTOM_STYLE,
515 CSS_PROP_BORDER_LEFT_STYLE
517 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_STYLE, borderStyleProperties);
519 static const int borderWidthProperties[] = {
520 CSS_PROP_BORDER_TOP_WIDTH,
521 CSS_PROP_BORDER_RIGHT_WIDTH,
522 CSS_PROP_BORDER_BOTTOM_WIDTH,
523 CSS_PROP_BORDER_LEFT_WIDTH
525 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_WIDTH, borderWidthProperties);
527 static const int backgroundPositionProperties[] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y };
528 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND_POSITION, backgroundPositionProperties);
530 static const int borderSpacingProperties[] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING, CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
531 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_SPACING, borderSpacingProperties);
533 static const int listStyleProperties[] = {
534 CSS_PROP_LIST_STYLE_IMAGE,
535 CSS_PROP_LIST_STYLE_POSITION,
536 CSS_PROP_LIST_STYLE_TYPE
538 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_LIST_STYLE, listStyleProperties);
540 static const int marginProperties[] = {
541 CSS_PROP_MARGIN_TOP,
542 CSS_PROP_MARGIN_RIGHT,
543 CSS_PROP_MARGIN_BOTTOM,
544 CSS_PROP_MARGIN_LEFT
546 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_MARGIN, marginProperties);
548 #ifdef APPLE_CHANGES
549 static const int marginCollapseProperties[] = { CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE, CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE };
550 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARGIN_COLLAPSE, marginCollapseProperties);
551 #endif
553 static const int marqueeProperties[] = {
554 CSS_PROP__KHTML_MARQUEE_DIRECTION,
555 CSS_PROP__KHTML_MARQUEE_INCREMENT,
556 CSS_PROP__KHTML_MARQUEE_REPETITION,
557 CSS_PROP__KHTML_MARQUEE_STYLE,
558 CSS_PROP__KHTML_MARQUEE_SPEED
560 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARQUEE, marqueeProperties);
562 static const int outlineProperties[] = {
563 CSS_PROP_OUTLINE_COLOR,
564 CSS_PROP_OUTLINE_OFFSET,
565 CSS_PROP_OUTLINE_STYLE,
566 CSS_PROP_OUTLINE_WIDTH
568 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OUTLINE, outlineProperties);
570 static const int paddingProperties[] = {
571 CSS_PROP_PADDING_TOP,
572 CSS_PROP_PADDING_RIGHT,
573 CSS_PROP_PADDING_BOTTOM,
574 CSS_PROP_PADDING_LEFT
576 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_PADDING, paddingProperties);
578 #ifdef APPLE_CHANGES
579 static const int textStrokeProperties[] = { CSS_PROP__KHTML_TEXT_STROKE_COLOR, CSS_PROP__KHTML_TEXT_STROKE_WIDTH };
580 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_TEXT_STROKE, textStrokeProperties);
581 #endif
583 static const int backgroundProperties[] = {
584 CSS_PROP_BACKGROUND_ATTACHMENT,
585 CSS_PROP_BACKGROUND_COLOR,
586 CSS_PROP_BACKGROUND_IMAGE,
587 CSS_PROP_BACKGROUND_POSITION_X,
588 CSS_PROP_BACKGROUND_POSITION_Y,
589 CSS_PROP_BACKGROUND_REPEAT,
590 CSS_PROP__KHTML_BACKGROUND_SIZE
592 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND, backgroundProperties);
594 #ifdef APPLE_CHANGES
595 static const int columnsProperties[] = { CSS_PROP__KHTML_COLUMN_WIDTH, CSS_PROP__KHTML_COLUMN_COUNT };
596 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMNS, columnsProperties);
598 static const int columnRuleProperties[] = {
599 CSS_PROP__KHTML_COLUMN_RULE_COLOR,
600 CSS_PROP__KHTML_COLUMN_RULE_STYLE,
601 CSS_PROP__KHTML_COLUMN_RULE_WIDTH
603 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMN_RULE, columnRuleProperties);
604 #endif
606 static const int overflowProperties[] = { CSS_PROP_OVERFLOW_X, CSS_PROP_OVERFLOW_Y };
607 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OVERFLOW, overflowProperties);
609 static const int borderRadiusProperties[] = {
610 CSS_PROP__KHTML_BORDER_TOP_RIGHT_RADIUS,
611 CSS_PROP__KHTML_BORDER_TOP_LEFT_RADIUS,
612 CSS_PROP__KHTML_BORDER_BOTTOM_LEFT_RADIUS,
613 CSS_PROP__KHTML_BORDER_BOTTOM_RIGHT_RADIUS
615 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_BORDER_RADIUS, borderRadiusProperties);
617 #undef SET_SHORTHAND_MAP_ENTRY
620 // -------------------------------------------
622 void CSSStyleDeclarationImpl::removeProperty(int propertyID,
623 DOM::DOMString* old)
625 if(!m_lstValues)
626 return;
628 static QHash<int, PropertyLonghand> shorthandMap;
629 if (shorthandMap.isEmpty())
630 initShorthandMap(shorthandMap);
632 PropertyLonghand longhand = shorthandMap.value(propertyID);
633 if (longhand.length()) {
634 removePropertiesInSet(longhand.properties(), longhand.length());
635 // FIXME: Return an equivalent shorthand when possible.
636 return;
639 QMutableListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
640 CSSProperty *current;
641 lstValuesIt.toBack();
642 while ( lstValuesIt.hasPrevious() ) {
643 current = lstValuesIt.previous();
644 if (current->m_id == propertyID) {
645 if (old)
646 *old = current->value()->cssText();
647 delete lstValuesIt.value();
648 lstValuesIt.remove();
649 setChanged();
650 break;
655 void CSSStyleDeclarationImpl::removePropertiesInSet(const int* set, unsigned length)
657 bool changed = false;
658 for (unsigned i = 0; i < length; i++) {
659 QMutableListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
660 CSSProperty *current;
661 lstValuesIt.toBack();
662 while ( lstValuesIt.hasPrevious() ) {
663 current = lstValuesIt.previous();
664 if (current->m_id == set[i]) {
665 delete lstValuesIt.value();
666 lstValuesIt.remove();
667 changed = true;
668 break;
672 if (changed)
673 setChanged();
676 void CSSStyleDeclarationImpl::setChanged()
678 if (m_node) {
679 m_node->setChanged();
680 return;
683 // ### quick&dirty hack for KDE 3.0... make this MUCH better! (Dirk)
684 for (StyleBaseImpl* stylesheet = this; stylesheet; stylesheet = stylesheet->parent())
685 if (stylesheet->isCSSStyleSheet()) {
686 static_cast<CSSStyleSheetImpl*>(stylesheet)->doc()->updateStyleSelector();
687 break;
691 void CSSStyleDeclarationImpl::clear()
693 if (!m_lstValues)
694 return;
696 QMutableListIterator<CSSProperty*> it(*m_lstValues);
697 while (it.hasNext()) {
698 delete it.next();
699 it.remove();
703 bool CSSStyleDeclarationImpl::getPropertyPriority( int propertyID ) const
705 if ( m_lstValues) {
706 QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
707 CSSProperty *current;
708 while (lstValuesIt.hasNext()) {
709 current = lstValuesIt.next();
710 if( propertyID == current->m_id )
711 return current->m_important;
714 return false;
717 bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important, int &ec)
719 ec = 0;
721 // Setting the value to an empty string just removes the property in both IE and Gecko.
722 // Setting it to null seems to produce less consistent results, but we treat it just the same.
723 if (value.isEmpty()) {
724 removeProperty(id);
725 return true;
728 bool success = setProperty(id, value, important);
729 #if 0
730 if (!success) {
731 // CSS DOM requires raising SYNTAX_ERR here, but this is too dangerous for compatibility,
732 // see <http://bugs.webkit.org/show_bug.cgi?id=7296>.
734 #endif
735 return success;
738 bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important)
740 if(!m_lstValues) {
741 m_lstValues = new QList<CSSProperty*>;
744 CSSParser parser( strictParsing );
745 bool success = parser.parseValue( this, id, value, important );
746 if(!success)
747 kDebug( 6080 ) << "CSSStyleDeclarationImpl::setProperty invalid property: [" << getPropertyName(id).string()
748 << "] value: [" << value.string() << "]"<< endl;
749 else
750 setChanged();
751 return success;
754 void CSSStyleDeclarationImpl::setProperty(int id, int value, bool important )
756 if(!m_lstValues) {
757 m_lstValues = new QList<CSSProperty*>;
759 removeProperty(id);
761 CSSValueImpl * cssValue = new CSSPrimitiveValueImpl(value);
762 setParsedValue(id, cssValue, important, m_lstValues);
763 setChanged();
766 void CSSStyleDeclarationImpl::setLengthProperty(int id, const DOM::DOMString &value, bool important, bool _multiLength )
768 bool parseMode = strictParsing;
769 strictParsing = false;
770 multiLength = _multiLength;
771 setProperty( id, value, important );
772 strictParsing = parseMode;
773 multiLength = false;
776 void CSSStyleDeclarationImpl::setProperty ( const DOMString &propertyString)
778 if(!m_lstValues) {
779 m_lstValues = new QList<CSSProperty*>;
782 CSSParser parser( strictParsing );
783 parser.parseDeclaration( this, propertyString );
784 setChanged();
787 unsigned long CSSStyleDeclarationImpl::length() const
789 return m_lstValues ? m_lstValues->count() : 0;
792 DOMString CSSStyleDeclarationImpl::item( unsigned long index ) const
794 if(m_lstValues && index < (unsigned)m_lstValues->count() && m_lstValues->at(index))
795 return getPropertyName(m_lstValues->at(index)->m_id);
796 return DOMString();
799 CSSRuleImpl *CSSStyleDeclarationImpl::parentRule() const
801 return (m_parent && m_parent->isRule() ) ?
802 static_cast<CSSRuleImpl *>(m_parent) : 0;
805 DOM::DOMString CSSStyleDeclarationImpl::cssText() const
807 DOMString result;
809 const CSSProperty* positionXProp = 0;
810 const CSSProperty* positionYProp = 0;
812 if ( m_lstValues) {
813 QListIterator<CSSProperty*> lstValuesIt(*m_lstValues);
814 while (lstValuesIt.hasNext()) {
815 const CSSProperty* cur = lstValuesIt.next();
816 if (cur->id() == CSS_PROP_BACKGROUND_POSITION_X)
817 positionXProp = cur;
818 else if (cur->id() == CSS_PROP_BACKGROUND_POSITION_Y)
819 positionYProp = cur;
820 else
821 result += cur->cssText();
825 // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output.
826 // It is required because background-position-x/y are non-standard properties and generated output
827 // would not work in Firefox
828 // It would be a better solution if background-position was CSS_PAIR.
829 if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) {
830 DOMString positionValue;
831 const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y };
832 if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList())
833 positionValue = getLayeredShortHandValue(properties, 2);
834 else
835 positionValue = positionXProp->value()->cssText() + " " + positionYProp->value()->cssText();
836 result += DOMString("background-position: ") + positionValue
837 + DOMString((positionXProp->isImportant() ? " !important" : ""))
838 + "; ";
839 } else {
840 if (positionXProp)
841 result += positionXProp->cssText();
842 if (positionYProp)
843 result += positionYProp->cssText();
845 return result;
848 void CSSStyleDeclarationImpl::setCssText(const DOM::DOMString& text)
850 if (m_lstValues) {
851 qDeleteAll(*m_lstValues);
852 m_lstValues->clear();
853 } else {
854 m_lstValues = new QList<CSSProperty*>;
857 CSSParser parser( strictParsing );
858 parser.parseDeclaration( this, text );
859 setChanged();
862 bool CSSStyleDeclarationImpl::parseString( const DOMString &/*string*/, bool )
864 kDebug() << "WARNING: CSSStyleDeclarationImpl::parseString, unimplemented, was called";
865 return false;
866 // ###
870 // --------------------------------------------------------------------------------------
872 unsigned short CSSInheritedValueImpl::cssValueType() const
874 return CSSValue::CSS_INHERIT;
877 DOM::DOMString CSSInheritedValueImpl::cssText() const
879 return DOMString("inherit");
882 unsigned short CSSInitialValueImpl::cssValueType() const
884 return CSSValue::CSS_INITIAL;
887 DOM::DOMString CSSInitialValueImpl::cssText() const
889 return DOMString("initial");
892 // ----------------------------------------------------------------------------------------
894 CSSValueListImpl::~CSSValueListImpl()
896 for (QListIterator<CSSValueImpl*> iterator(m_values); iterator.hasNext();)
897 iterator.next()->deref();
900 unsigned short CSSValueListImpl::cssValueType() const
902 return CSSValue::CSS_VALUE_LIST;
905 void CSSValueListImpl::append(CSSValueImpl *val)
907 m_values.append(val);
908 val->ref();
911 DOM::DOMString CSSValueListImpl::cssText() const
913 DOMString result = "";
915 for (QListIterator<CSSValueImpl*> iterator(m_values); iterator.hasNext();) {
916 result += iterator.next()->cssText();
919 return result;
922 // -------------------------------------------------------------------------------------
924 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl()
925 : CSSValueImpl()
927 m_type = 0;
930 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(int ident)
931 : CSSValueImpl()
933 m_value.ident = ident;
934 m_type = CSSPrimitiveValue::CSS_IDENT;
937 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(double num, CSSPrimitiveValue::UnitTypes type)
939 m_value.num = num;
940 m_type = type;
943 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(const DOMString &str, CSSPrimitiveValue::UnitTypes type)
945 m_value.string = str.implementation();
946 if(m_value.string) m_value.string->ref();
947 m_type = type;
950 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(CounterImpl *c)
952 m_value.counter = c;
953 if (m_value.counter)
954 m_value.counter->ref();
955 m_type = CSSPrimitiveValue::CSS_COUNTER;
958 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl( RectImpl *r)
960 m_value.rect = r;
961 if (m_value.rect)
962 m_value.rect->ref();
963 m_type = CSSPrimitiveValue::CSS_RECT;
966 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(QRgb color)
968 m_value.rgbcolor = color;
969 m_type = CSSPrimitiveValue::CSS_RGBCOLOR;
972 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(PairImpl *p)
974 m_value.pair = p;
975 if (m_value.pair)
976 m_value.pair->ref();
977 m_type = CSSPrimitiveValue::CSS_PAIR;
981 CSSPrimitiveValueImpl::~CSSPrimitiveValueImpl()
983 cleanup();
986 void CSSPrimitiveValueImpl::cleanup()
988 switch(m_type) {
989 case CSSPrimitiveValue::CSS_STRING:
990 case CSSPrimitiveValue::CSS_URI:
991 case CSSPrimitiveValue::CSS_ATTR:
992 if(m_value.string) m_value.string->deref();
993 break;
994 case CSSPrimitiveValue::CSS_COUNTER:
995 m_value.counter->deref();
996 break;
997 case CSSPrimitiveValue::CSS_RECT:
998 m_value.rect->deref();
999 break;
1000 case CSSPrimitiveValue::CSS_PAIR:
1001 m_value.pair->deref();
1002 break;
1003 default:
1004 break;
1007 m_type = 0;
1010 int CSSPrimitiveValueImpl::computeLength( khtml::RenderStyle *style, int logicalDpiY)
1012 double result = computeLengthFloat( style, logicalDpiY );
1013 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We
1014 // need to go ahead and round if we're really close to the next integer value.
1015 int intResult = (int)(result + (result < 0 ? -0.01 : +0.01));
1016 return intResult;
1019 double CSSPrimitiveValueImpl::computeLengthFloat( khtml::RenderStyle *style, int logicalDpiY)
1021 unsigned short type = primitiveType();
1023 double dpiY = 72.; // fallback
1024 if ( logicalDpiY )
1025 dpiY = logicalDpiY;
1026 if ( !khtml::printpainter && dpiY < 96 )
1027 dpiY = 96.;
1029 double factor = 1.;
1030 switch(type)
1032 case CSSPrimitiveValue::CSS_EMS:
1033 factor = style->font().pixelSize();
1034 break;
1035 case CSSPrimitiveValue::CSS_EXS:
1037 QFontMetrics fm = style->fontMetrics();
1038 factor = fm.xHeight();
1039 break;
1041 case CSSPrimitiveValue::CSS_PX:
1042 break;
1043 case CSSPrimitiveValue::CSS_CM:
1044 factor = dpiY/2.54; //72dpi/(2.54 cm/in)
1045 break;
1046 case CSSPrimitiveValue::CSS_MM:
1047 factor = dpiY/25.4;
1048 break;
1049 case CSSPrimitiveValue::CSS_IN:
1050 factor = dpiY;
1051 break;
1052 case CSSPrimitiveValue::CSS_PT:
1053 factor = dpiY/72.;
1054 break;
1055 case CSSPrimitiveValue::CSS_PC:
1056 // 1 pc == 12 pt
1057 factor = dpiY*12./72.;
1058 break;
1059 default:
1060 return -1;
1063 return floatValue(type)*factor;
1066 int CSSPrimitiveValueImpl::getDPIResolution() const
1068 unsigned short type = primitiveType();
1069 double factor = 1.;
1070 switch(type)
1072 case CSSPrimitiveValue::CSS_DPI:
1073 break;
1074 case CSSPrimitiveValue::CSS_DPCM:
1075 factor = 2.54;
1076 break;
1077 default:
1078 return -1;
1081 return (int)(0.01+floatValue(type)*factor);
1084 void CSSPrimitiveValueImpl::setFloatValue( unsigned short unitType, double floatValue, int &exceptioncode )
1086 exceptioncode = 0;
1087 cleanup();
1088 // ### check if property supports this type
1089 if(m_type > CSSPrimitiveValue::CSS_DIMENSION) {
1090 exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
1091 return;
1093 //if(m_type > CSSPrimitiveValue::CSS_DIMENSION) throw DOMException(DOMException::INVALID_ACCESS_ERR);
1094 m_value.num = floatValue;
1095 m_type = unitType;
1098 void CSSPrimitiveValueImpl::setStringValue( unsigned short stringType, const DOMString &stringValue, int &exceptioncode )
1100 exceptioncode = 0;
1101 cleanup();
1102 //if(m_type < CSSPrimitiveValue::CSS_STRING) throw DOMException(DOMException::INVALID_ACCESS_ERR);
1103 //if(m_type > CSSPrimitiveValue::CSS_ATTR) throw DOMException(DOMException::INVALID_ACCESS_ERR);
1104 if(m_type < CSSPrimitiveValue::CSS_STRING || m_type > CSSPrimitiveValue::CSS_ATTR) {
1105 exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
1106 return;
1108 if(stringType != CSSPrimitiveValue::CSS_IDENT)
1110 m_value.string = stringValue.implementation();
1111 m_value.string->ref();
1112 m_type = stringType;
1114 // ### parse ident
1117 unsigned short CSSPrimitiveValueImpl::cssValueType() const
1119 return CSSValue::CSS_PRIMITIVE_VALUE;
1122 bool CSSPrimitiveValueImpl::parseString( const DOMString &/*string*/, bool )
1124 // ###
1125 kDebug() << "WARNING: CSSPrimitiveValueImpl::parseString, unimplemented, was called";
1126 return false;
1129 int CSSPrimitiveValueImpl::getIdent()
1131 if(m_type != CSSPrimitiveValue::CSS_IDENT) return 0;
1132 return m_value.ident;
1135 DOM::DOMString CSSPrimitiveValueImpl::cssText() const
1137 // ### return the original value instead of a generated one (e.g. color
1138 // name if it was specified) - check what spec says about this
1139 DOMString text;
1140 switch ( m_type ) {
1141 case CSSPrimitiveValue::CSS_UNKNOWN:
1142 // ###
1143 break;
1144 case CSSPrimitiveValue::CSS_NUMBER:
1145 // We want to output integral values w/o a period, but others as-is
1146 if ( m_value.num == (int)m_value.num )
1147 text = DOMString(QString::number( (int)m_value.num ));
1148 else
1149 text = DOMString(QString::number( m_value.num ));
1150 break;
1151 case CSSPrimitiveValue::CSS_PERCENTAGE:
1152 text = DOMString(QString::number( m_value.num ) + "%");
1153 break;
1154 case CSSPrimitiveValue::CSS_EMS:
1155 text = DOMString(QString::number( m_value.num ) + "em");
1156 break;
1157 case CSSPrimitiveValue::CSS_EXS:
1158 text = DOMString(QString::number( m_value.num ) + "ex");
1159 break;
1160 case CSSPrimitiveValue::CSS_PX:
1161 text = DOMString(QString::number( m_value.num ) + "px");
1162 break;
1163 case CSSPrimitiveValue::CSS_CM:
1164 text = DOMString(QString::number( m_value.num ) + "cm");
1165 break;
1166 case CSSPrimitiveValue::CSS_MM:
1167 text = DOMString(QString::number( m_value.num ) + "mm");
1168 break;
1169 case CSSPrimitiveValue::CSS_IN:
1170 text = DOMString(QString::number( m_value.num ) + "in");
1171 break;
1172 case CSSPrimitiveValue::CSS_PT:
1173 text = DOMString(QString::number( m_value.num ) + "pt");
1174 break;
1175 case CSSPrimitiveValue::CSS_PC:
1176 text = DOMString(QString::number( m_value.num ) + "pc");
1177 break;
1178 case CSSPrimitiveValue::CSS_DEG:
1179 text = DOMString(QString::number( m_value.num ) + "deg");
1180 break;
1181 case CSSPrimitiveValue::CSS_RAD:
1182 text = DOMString(QString::number( m_value.num ) + "rad");
1183 break;
1184 case CSSPrimitiveValue::CSS_GRAD:
1185 text = DOMString(QString::number( m_value.num ) + "grad");
1186 break;
1187 case CSSPrimitiveValue::CSS_MS:
1188 text = DOMString(QString::number( m_value.num ) + "ms");
1189 break;
1190 case CSSPrimitiveValue::CSS_S:
1191 text = DOMString(QString::number( m_value.num ) + "s");
1192 break;
1193 case CSSPrimitiveValue::CSS_HZ:
1194 text = DOMString(QString::number( m_value.num ) + "hz");
1195 break;
1196 case CSSPrimitiveValue::CSS_KHZ:
1197 text = DOMString(QString::number( m_value.num ) + "khz");
1198 break;
1199 case CSSPrimitiveValue::CSS_DIMENSION:
1200 // ###
1201 break;
1202 case CSSPrimitiveValue::CSS_STRING:
1203 text = quoteStringIfNeeded(m_value.string);
1204 break;
1205 case CSSPrimitiveValue::CSS_URI:
1206 text = "url(";
1207 text += DOMString( m_value.string );
1208 text += ")";
1209 break;
1210 case CSSPrimitiveValue::CSS_IDENT:
1211 text = getValueName(m_value.ident);
1212 break;
1213 case CSSPrimitiveValue::CSS_ATTR:
1214 // ###
1215 break;
1216 case CSSPrimitiveValue::CSS_COUNTER:
1217 text = "counter(";
1218 text += m_value.counter->m_identifier;
1219 text += ")";
1220 // ### add list-style and separator
1221 break;
1222 case CSSPrimitiveValue::CSS_RECT:
1224 RectImpl* rectVal = getRectValue();
1225 text = "rect(";
1226 text += rectVal->top()->cssText() + " ";
1227 text += rectVal->right()->cssText() + " ";
1228 text += rectVal->bottom()->cssText() + " ";
1229 text += rectVal->left()->cssText() + ")";
1230 break;
1232 case CSSPrimitiveValue::CSS_RGBCOLOR:
1233 if (qAlpha(m_value.rgbcolor) != 0xFF) {
1234 if (m_value.rgbcolor == khtml::transparentColor)
1235 text = "transparent";
1236 else
1237 text = "rgba(" + QString::number(qRed (m_value.rgbcolor)) + ", "
1238 + QString::number(qGreen(m_value.rgbcolor)) + ", "
1239 + QString::number(qBlue (m_value.rgbcolor)) + ", "
1240 + QString::number(qAlpha(m_value.rgbcolor)/255.0) + ")";
1241 } else {
1242 text = "rgb(" + QString::number(qRed (m_value.rgbcolor)) + ", "
1243 + QString::number(qGreen(m_value.rgbcolor)) + ", "
1244 + QString::number(qBlue (m_value.rgbcolor)) + ")";
1246 break;
1247 case CSSPrimitiveValue::CSS_PAIR:
1248 text = m_value.pair->first()->cssText();
1249 text += " ";
1250 text += m_value.pair->second()->cssText();
1251 break;
1252 default:
1253 break;
1255 return text;
1258 // -----------------------------------------------------------------
1260 RectImpl::RectImpl()
1262 m_top = 0;
1263 m_right = 0;
1264 m_bottom = 0;
1265 m_left = 0;
1268 RectImpl::~RectImpl()
1270 if (m_top) m_top->deref();
1271 if (m_right) m_right->deref();
1272 if (m_bottom) m_bottom->deref();
1273 if (m_left) m_left->deref();
1276 void RectImpl::setTop( CSSPrimitiveValueImpl *top )
1278 if( top ) top->ref();
1279 if ( m_top ) m_top->deref();
1280 m_top = top;
1283 void RectImpl::setRight( CSSPrimitiveValueImpl *right )
1285 if( right ) right->ref();
1286 if ( m_right ) m_right->deref();
1287 m_right = right;
1290 void RectImpl::setBottom( CSSPrimitiveValueImpl *bottom )
1292 if( bottom ) bottom->ref();
1293 if ( m_bottom ) m_bottom->deref();
1294 m_bottom = bottom;
1297 void RectImpl::setLeft( CSSPrimitiveValueImpl *left )
1299 if( left ) left->ref();
1300 if ( m_left ) m_left->deref();
1301 m_left = left;
1304 // -----------------------------------------------------------------
1306 PairImpl::~PairImpl()
1308 if (m_first) m_first->deref(); if (m_second) m_second->deref();
1311 void PairImpl::setFirst(CSSPrimitiveValueImpl* first)
1313 if (first == m_first) return;
1314 if (m_first) m_first->deref();
1315 m_first = first;
1316 if (m_first) m_first->ref();
1319 void PairImpl::setSecond(CSSPrimitiveValueImpl* second)
1321 if (second == m_second) return;
1322 if (m_second) m_second->deref();
1323 m_second = second;
1324 if (m_second) m_second->ref();
1327 // -----------------------------------------------------------------
1329 CSSImageValueImpl::CSSImageValueImpl(const DOMString &url, const StyleBaseImpl* style)
1330 : CSSPrimitiveValueImpl(url, CSSPrimitiveValue::CSS_URI)
1332 khtml::DocLoader *docLoader = 0;
1333 const StyleBaseImpl *root = style;
1334 while (root->parent())
1335 root = root->parent();
1336 if (root->isCSSStyleSheet())
1337 docLoader = static_cast<const CSSStyleSheetImpl*>(root)->docLoader();
1339 m_image = docLoader->requestImage(url);
1340 if(m_image) m_image->ref(this);
1343 CSSImageValueImpl::CSSImageValueImpl()
1344 : CSSPrimitiveValueImpl(CSS_VAL_NONE)
1346 m_image = 0;
1349 CSSImageValueImpl::~CSSImageValueImpl()
1351 if(m_image) m_image->deref(this);
1354 // ------------------------------------------------------------------------
1356 FontFamilyValueImpl::FontFamilyValueImpl( const QString &string)
1357 : CSSPrimitiveValueImpl( DOMString(string), CSSPrimitiveValue::CSS_STRING)
1359 static const QRegExp parenReg(" \\(.*\\)$");
1360 static const QRegExp braceReg(" \\[.*\\]$");
1362 parsedFontName = string;
1363 // a language tag is often added in braces at the end. Remove it.
1364 parsedFontName.replace(parenReg, QString());
1365 // remove [Xft] qualifiers
1366 parsedFontName.replace(braceReg, QString());
1368 #ifndef APPLE_CHANGES
1369 const QString &available = KHTMLSettings::availableFamilies();
1371 parsedFontName = parsedFontName.toLower();
1372 // kDebug(0) << "searching for face '" << parsedFontName << "'";
1374 int pos = available.indexOf( ',' + parsedFontName + ',', 0, Qt::CaseInsensitive );
1375 if ( pos == -1 ) {
1376 // many pages add extra MSs to make sure it's windows only ;(
1377 if ( parsedFontName.startsWith( "ms " ) )
1378 parsedFontName = parsedFontName.mid( 3 );
1379 if ( parsedFontName.endsWith( " ms" ) )
1380 parsedFontName.truncate( parsedFontName.length() - 3 );
1381 pos = available.indexOf( ",ms " + parsedFontName + ',', 0, Qt::CaseInsensitive );
1382 if ( pos == -1 )
1383 pos = available.indexOf( ',' + parsedFontName + " ms,", 0, Qt::CaseInsensitive );
1386 if ( pos != -1 ) {
1387 ++pos;
1388 int p = available.indexOf(',', pos);
1389 assert( p != -1 ); // available is supposed to start and end with ,
1390 parsedFontName = available.mid( pos, p - pos);
1391 // kDebug(0) << "going for '" << parsedFontName << "'";
1392 } else
1393 parsedFontName.clear();
1395 #endif // !APPLE_CHANGES
1398 FontValueImpl::FontValueImpl()
1399 : style(0), variant(0), weight(0), size(0), lineHeight(0), family(0)
1403 FontValueImpl::~FontValueImpl()
1405 delete style;
1406 delete variant;
1407 delete weight;
1408 delete size;
1409 delete lineHeight;
1410 delete family;
1413 DOMString FontValueImpl::cssText() const
1415 // font variant weight size / line-height family
1417 DOMString result("");
1419 if (style) {
1420 result += style->cssText();
1422 if (variant) {
1423 if (result.length() > 0) {
1424 result += " ";
1426 result += variant->cssText();
1428 if (weight) {
1429 if (result.length() > 0) {
1430 result += " ";
1432 result += weight->cssText();
1434 if (size) {
1435 if (result.length() > 0) {
1436 result += " ";
1438 result += size->cssText();
1440 if (lineHeight) {
1441 if (!size) {
1442 result += " ";
1444 result += "/";
1445 result += lineHeight->cssText();
1447 if (family) {
1448 if (result.length() > 0) {
1449 result += " ";
1451 result += family->cssText();
1454 return result;
1457 QuotesValueImpl::QuotesValueImpl()
1458 : levels(0)
1462 DOMString QuotesValueImpl::cssText() const
1464 return "\"" + data.join("\" \"") + "\"";
1467 void QuotesValueImpl::addLevel(const QString& open, const QString& close)
1469 data.append(open);
1470 data.append(close);
1471 levels++;
1474 QString QuotesValueImpl::openQuote(int level) const
1476 if (levels == 0) return "";
1477 level--; // increments are calculated before openQuote is called
1478 // kDebug( 6080 ) << "Open quote level:" << level;
1479 if (level < 0) level = 0;
1480 else
1481 if (level >= (int) levels) level = (int) (levels-1);
1482 return data[level*2];
1485 QString QuotesValueImpl::closeQuote(int level) const
1487 if (levels == 0) return "";
1488 // kDebug( 6080 ) << "Close quote level:" << level;
1489 if (level < 0) level = 0;
1490 else
1491 if (level >= (int) levels) level = (int) (levels-1);
1492 return data[level*2+1];
1495 // Used for text-shadow and box-shadow
1496 ShadowValueImpl::ShadowValueImpl(CSSPrimitiveValueImpl* _x, CSSPrimitiveValueImpl* _y,
1497 CSSPrimitiveValueImpl* _blur, CSSPrimitiveValueImpl* _color)
1498 :x(_x), y(_y), blur(_blur), color(_color)
1501 ShadowValueImpl::~ShadowValueImpl()
1503 delete x;
1504 delete y;
1505 delete blur;
1506 delete color;
1509 DOMString ShadowValueImpl::cssText() const
1511 DOMString text("");
1512 if (color) {
1513 text += color->cssText();
1515 if (x) {
1516 if (text.length() > 0) {
1517 text += " ";
1519 text += x->cssText();
1521 if (y) {
1522 if (text.length() > 0) {
1523 text += " ";
1525 text += y->cssText();
1527 if (blur) {
1528 if (text.length() > 0) {
1529 text += " ";
1531 text += blur->cssText();
1534 return text;
1537 DOMString CounterActImpl::cssText() const
1539 DOMString text(m_counter);
1540 text += DOMString(QString::number(m_value));
1542 return text;
1545 DOMString CSSProperty::cssText() const
1547 return getPropertyName(m_id) + DOMString(": ") + m_value->cssText() + (m_important ? DOMString(" !important") : DOMString()) + DOMString("; ");