2 * This file is part of the DOM implementation for KDE.
4 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
5 * Copyright (C) 2004 Apple Computer, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include "dom/css_value.h"
24 #include "dom/dom_exception.h"
25 #include "dom/dom_string.h"
27 #include "css/css_valueimpl.h"
28 #include "css/css_ruleimpl.h"
29 #include "css/css_stylesheetimpl.h"
30 #include "css/cssparser.h"
31 #include "css/cssproperties.h"
32 #include "css/cssvalues.h"
33 #include "css/cssstyleselector.h"
35 #include "xml/dom_stringimpl.h"
36 #include "xml/dom_docimpl.h"
37 #include "html/html_elementimpl.h"
39 #include "misc/loader.h"
41 #include "rendering/font.h"
42 #include "rendering/render_style.h"
46 #include <qpaintdevice.h>
47 #include <qpaintdevicemetrics.h>
49 // Hack for debugging purposes
50 extern DOM::DOMString getPropertyName(unsigned short id);
53 using khtml::CSSStyleSelector;
59 // Too risky to quote all legal identifiers right now.
60 // Post-Tiger we should use this function or something like it.
62 // Return true if this string qualifies as an identifier (from the point of view of CSS syntax).
63 static bool isLegalIdentifier(const DOMString &string)
65 int len = string.length();
69 QChar *p = string.unicode();
77 ushort code = p[i].unicode();
78 if (!(code >= 0x80 || code == '_' || isalpha(code))) {
83 code = p[i].unicode();
84 if (!(code >= 0x80 || code == '-' || code == '_' || isalnum(code))) {
94 // Quotes the string if it needs quoting.
95 // We use single quotes for now beause markup.cpp uses double quotes.
96 static DOMString quoteStringIfNeeded(const DOMString &string)
98 // For now, just do this for strings that start with "#" to fix Korean font names that start with "#".
99 // Post-Tiger, we should isLegalIdentifier instead after working out all the ancillary issues.
100 if (string[0] != '#') {
104 // FIXME: Also need to transform control characters into \ sequences.
105 QString s = string.string();
106 s.replace('\\', "\\\\");
107 s.replace('\'', "\\'");
108 return '\'' + s + '\'';
111 CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent)
112 : StyleBaseImpl(parent)
116 bool CSSStyleDeclarationImpl::isStyleDeclaration()
121 CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl()
126 CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl(CSSRuleImpl *parent)
127 : CSSStyleDeclarationImpl(parent), m_node(0)
131 CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl(CSSRuleImpl *parent, const QValueList<CSSProperty> &values)
132 : CSSStyleDeclarationImpl(parent), m_values(values), m_node(0)
134 // FIXME: This allows duplicate properties.
137 CSSMutableStyleDeclarationImpl::CSSMutableStyleDeclarationImpl(CSSRuleImpl *parent, const CSSProperty * const *properties, int numProperties)
138 : CSSStyleDeclarationImpl(parent), m_node(0)
140 for (int i = 0; i < numProperties; ++i)
141 m_values.append(*properties[i]);
142 // FIXME: This allows duplicate properties.
145 CSSMutableStyleDeclarationImpl& CSSMutableStyleDeclarationImpl::operator=(const CSSMutableStyleDeclarationImpl& o)
147 // don't attach it to the same node, just leave the current m_node value
148 m_values = o.m_values;
152 CSSMutableStyleDeclarationImpl::~CSSMutableStyleDeclarationImpl()
154 // we don't use refcounting for m_node, to avoid cyclic references (see ElementImpl)
157 DOMString CSSMutableStyleDeclarationImpl::getPropertyValue( int propertyID ) const
159 CSSValueImpl* value = getPropertyCSSValue( propertyID );
161 return CSSValue(value).cssText();
163 // Shorthand and 4-values properties
164 switch ( propertyID ) {
165 case CSS_PROP_BACKGROUND_POSITION:
167 // ## Is this correct? The code in cssparser.cpp is confusing
168 const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X,
169 CSS_PROP_BACKGROUND_POSITION_Y };
170 return getShortHandValue( properties, 2 );
172 case CSS_PROP_BACKGROUND:
174 const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
175 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
176 CSS_PROP_BACKGROUND_COLOR };
177 return getShortHandValue( properties, 5 );
179 case CSS_PROP_BORDER:
181 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
182 CSS_PROP_BORDER_COLOR };
183 return getShortHandValue( properties, 3 );
185 case CSS_PROP_BORDER_TOP:
187 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
188 CSS_PROP_BORDER_TOP_COLOR};
189 return getShortHandValue( properties, 3 );
191 case CSS_PROP_BORDER_RIGHT:
193 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
194 CSS_PROP_BORDER_RIGHT_COLOR};
195 return getShortHandValue( properties, 3 );
197 case CSS_PROP_BORDER_BOTTOM:
199 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
200 CSS_PROP_BORDER_BOTTOM_COLOR};
201 return getShortHandValue( properties, 3 );
203 case CSS_PROP_BORDER_LEFT:
205 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
206 CSS_PROP_BORDER_LEFT_COLOR};
207 return getShortHandValue( properties, 3 );
209 case CSS_PROP_OUTLINE:
211 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
212 CSS_PROP_OUTLINE_COLOR };
213 return getShortHandValue( properties, 3 );
215 case CSS_PROP_BORDER_COLOR:
217 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
218 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
219 return get4Values( properties );
221 case CSS_PROP_BORDER_WIDTH:
223 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
224 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
225 return get4Values( properties );
227 case CSS_PROP_BORDER_STYLE:
229 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
230 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
231 return get4Values( properties );
233 case CSS_PROP_MARGIN:
235 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
236 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
237 return get4Values( properties );
239 case CSS_PROP_PADDING:
241 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
242 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
243 return get4Values( properties );
245 case CSS_PROP_LIST_STYLE:
247 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
248 CSS_PROP_LIST_STYLE_IMAGE };
249 return getShortHandValue( properties, 3 );
252 //kdDebug() << k_funcinfo << "property not found:" << propertyID << endl;
256 DOMString CSSMutableStyleDeclarationImpl::get4Values( const int* properties ) const
259 for ( int i = 0 ; i < 4 ; ++i ) {
260 CSSValueImpl* value = getPropertyCSSValue( properties[i] );
261 if ( !value ) { // apparently all 4 properties must be specified.
267 res += value->cssText();
273 DOMString CSSMutableStyleDeclarationImpl::getShortHandValue( const int* properties, int number ) const
276 for ( int i = 0 ; i < number ; ++i ) {
277 CSSValueImpl* value = getPropertyCSSValue( properties[i] );
278 if ( value ) { // TODO provide default value if !value
282 res += value->cssText();
289 CSSValueImpl *CSSMutableStyleDeclarationImpl::getPropertyCSSValue( int propertyID ) const
291 QValueListConstIterator<CSSProperty> end;
292 for (QValueListConstIterator<CSSProperty> it = m_values.fromLast(); it != end; --it)
293 if (propertyID == (*it).m_id)
294 return (*it).value();
298 DOMString CSSMutableStyleDeclarationImpl::removeProperty(int propertyID, bool notifyChanged, int &exceptionCode)
300 if (m_node && !m_node->getDocument())
301 return ""; // FIXME: This (not well-understood) situation happens on albertsons.com. We don't really know how they managed to run a script on a node
302 // with no document pointer, but this sidesteps the crash.
308 QValueListIterator<CSSProperty> end;
309 for (QValueListIterator<CSSProperty> it = m_values.fromLast(); it != end; --it)
310 if (propertyID == (*it).m_id) {
311 value = (*it).value()->cssText();
321 void CSSMutableStyleDeclarationImpl::clear()
327 void CSSMutableStyleDeclarationImpl::setChanged()
330 m_node->setChanged();
331 // FIXME: Ideally, this should be factored better and there
332 // should be a subclass of CSSMutableStyleDeclarationImpl just
333 // for inline style declarations that handles this
334 if (m_node->isHTMLElement() && this == static_cast<HTMLElementImpl *>(m_node)->inlineStyleDecl())
335 static_cast<HTMLElementImpl *>(m_node)->invalidateStyleAttribute();
339 // ### quick&dirty hack for KDE 3.0... make this MUCH better! (Dirk)
340 for (StyleBaseImpl* stylesheet = this; stylesheet; stylesheet = stylesheet->parent())
341 if (stylesheet->isCSSStyleSheet()) {
342 static_cast<CSSStyleSheetImpl*>(stylesheet)->doc()->updateStyleSelector();
347 bool CSSMutableStyleDeclarationImpl::getPropertyPriority(int propertyID) const
349 QValueListConstIterator<CSSProperty> end;
350 for (QValueListConstIterator<CSSProperty> it = m_values.begin(); it != end; ++it)
351 if (propertyID == (*it).m_id)
352 return (*it).m_bImportant;
356 void CSSMutableStyleDeclarationImpl::setProperty(int propertyID, const DOMString &value, bool important, int &exceptionCode)
358 setProperty(propertyID, value, important, true, exceptionCode);
361 DOMString CSSMutableStyleDeclarationImpl::removeProperty(int propertyID, int &exceptionCode)
363 return removeProperty(propertyID, true, exceptionCode);
366 bool CSSMutableStyleDeclarationImpl::setProperty(int propertyID, const DOMString &value, bool important, bool notifyChanged, int &exceptionCode)
368 if (m_node && !m_node->getDocument())
369 return false; // FIXME: This (not well-understood) situation happens on albertsons.com. We don't really know how they managed to run a script on a node
370 // with no document pointer, but this sidesteps the crash.
373 removeProperty(propertyID);
375 CSSParser parser(strictParsing);
376 bool success = parser.parseValue(this, propertyID, value, important);
379 kdDebug( 6080 ) << "CSSMutableStyleDeclarationImpl::setProperty invalid property: [" << getPropertyName(id).string()
380 << "] value: [" << value.string() << "]"<< endl;
382 exceptionCode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
383 } else if (notifyChanged)
388 bool CSSMutableStyleDeclarationImpl::setProperty(int propertyID, int value, bool important, bool notifyChanged)
390 removeProperty(propertyID);
391 m_values.append(CSSProperty(propertyID, new CSSPrimitiveValueImpl(value), important));
397 void CSSMutableStyleDeclarationImpl::setStringProperty(int propertyId, const DOMString &value, CSSPrimitiveValue::UnitTypes type, bool important)
399 removeProperty(propertyId);
400 m_values.append(CSSProperty(propertyId, new CSSPrimitiveValueImpl(value, type), important));
404 void CSSMutableStyleDeclarationImpl::setImageProperty(int propertyId, const DOMString &URL, bool important)
406 removeProperty(propertyId);
407 m_values.append(CSSProperty(propertyId, new CSSImageValueImpl(URL, this), important));
411 void CSSMutableStyleDeclarationImpl::parseDeclaration(const DOMString &styleDeclaration)
414 CSSParser parser(strictParsing);
415 parser.parseDeclaration(this, styleDeclaration);
419 void CSSMutableStyleDeclarationImpl::addParsedProperties(const CSSProperty * const *properties, int numProperties)
421 for (int i = 0; i < numProperties; ++i) {
422 removeProperty(properties[i]->id(), false);
423 m_values.append(*properties[i]);
425 // FIXME: This probably should have a call to setChanged() if something changed. We may also wish to add
426 // a notifyChanged argument to this function to follow the model of other functions in this class.
429 void CSSMutableStyleDeclarationImpl::setLengthProperty(int id, const DOM::DOMString &value, bool important, bool _multiLength )
431 bool parseMode = strictParsing;
432 strictParsing = false;
433 multiLength = _multiLength;
434 setProperty( id, value, important);
435 strictParsing = parseMode;
439 unsigned long CSSMutableStyleDeclarationImpl::length() const
441 return m_values.count();
444 DOMString CSSMutableStyleDeclarationImpl::item( unsigned long /*index*/ ) const
447 //return m_lstValues->at(index);
451 CSSRuleImpl *CSSStyleDeclarationImpl::parentRule() const
453 return (m_parent && m_parent->isRule() ) ?
454 static_cast<CSSRuleImpl *>(m_parent) : 0;
457 DOM::DOMString CSSMutableStyleDeclarationImpl::cssText() const
459 DOMString result = "";
461 QValueListConstIterator<CSSProperty> end;
462 for (QValueListConstIterator<CSSProperty> it = m_values.begin(); it != end; ++it)
463 result += (*it).cssText();
468 void CSSMutableStyleDeclarationImpl::setCssText(const DOM::DOMString& text, int &exceptionCode)
472 CSSParser parser(strictParsing);
473 parser.parseDeclaration(this, text);
474 // FIXME: Detect syntax errors and set exceptionCode.
478 void CSSMutableStyleDeclarationImpl::merge(CSSMutableStyleDeclarationImpl *other, bool argOverridesOnConflict)
480 QValueListConstIterator<CSSProperty> end;
481 for (QValueListConstIterator<CSSProperty> it = other->valuesIterator(); it != end; ++it) {
482 const CSSProperty &property = *it;
483 CSSValueImpl *value = getPropertyCSSValue(property.id());
487 if (!argOverridesOnConflict)
489 removeProperty(property.id());
491 m_values.append(property);
493 // FIXME: This probably should have a call to setChanged() if something changed. We may also wish to add
494 // a notifyChanged argument to this function to follow the model of other functions in this class.
497 void CSSStyleDeclarationImpl::diff(CSSMutableStyleDeclarationImpl *style) const
502 QValueList<int> properties;
503 QValueListConstIterator<CSSProperty> end;
504 for (QValueListConstIterator<CSSProperty> it(style->valuesIterator()); it != end; ++it) {
505 const CSSProperty &property = *it;
506 CSSValueImpl *value = getPropertyCSSValue(property.id());
509 if (value->cssText() == property.value()->cssText()) {
510 properties.append(property.id());
516 for (QValueListIterator<int> it(properties.begin()); it != properties.end(); ++it)
517 style->removeProperty(*it);
520 // This is the list of properties we want to copy in the copyInheritableProperties() function.
521 // It is the intersection of the list of inherited CSS properties and the
522 // properties for which we have a computed implementation in this file.
523 const int inheritableProperties[] = {
524 CSS_PROP_BORDER_COLLAPSE,
525 CSS_PROP_BORDER_SPACING,
527 CSS_PROP_FONT_FAMILY,
530 CSS_PROP_FONT_VARIANT,
531 CSS_PROP_FONT_WEIGHT,
532 CSS_PROP_LETTER_SPACING,
533 CSS_PROP_LINE_HEIGHT,
535 CSS_PROP__KHTML_TEXT_DECORATIONS_IN_EFFECT,
536 CSS_PROP_TEXT_INDENT,
537 CSS_PROP__KHTML_TEXT_SIZE_ADJUST,
538 CSS_PROP_TEXT_TRANSFORM,
540 CSS_PROP_WHITE_SPACE,
542 CSS_PROP_WORD_SPACING,
545 const unsigned numInheritableProperties = sizeof(inheritableProperties) / sizeof(inheritableProperties[0]);
547 // This is the list of properties we want to copy in the copyBlockProperties() function.
548 // It is the list of CSS properties that apply to specially to block-level elements.
549 static const int blockProperties[] = {
551 CSS_PROP_OVERFLOW, // This can be also be applied to replaced elements
552 CSS_PROP_PAGE_BREAK_AFTER,
553 CSS_PROP_PAGE_BREAK_BEFORE,
554 CSS_PROP_PAGE_BREAK_INSIDE,
556 CSS_PROP_TEXT_INDENT,
560 const unsigned numBlockProperties = sizeof(blockProperties) / sizeof(blockProperties[0]);
562 CSSMutableStyleDeclarationImpl *CSSMutableStyleDeclarationImpl::copyBlockProperties() const
564 return copyPropertiesInSet(blockProperties, numBlockProperties);
567 void CSSMutableStyleDeclarationImpl::removeBlockProperties()
569 removePropertiesInSet(blockProperties, numBlockProperties);
572 void CSSMutableStyleDeclarationImpl::removeInheritableProperties()
574 removePropertiesInSet(inheritableProperties, numInheritableProperties);
577 CSSMutableStyleDeclarationImpl *CSSStyleDeclarationImpl::copyPropertiesInSet(const int *set, unsigned length) const
579 QValueList<CSSProperty> list;
580 for (unsigned i = 0; i < length; i++) {
581 CSSValueImpl *value = getPropertyCSSValue(set[i]);
583 list.append(CSSProperty(set[i], value, false));
585 return new CSSMutableStyleDeclarationImpl(0, list);
588 void CSSMutableStyleDeclarationImpl::removePropertiesInSet(const int *set, unsigned length)
590 bool changed = false;
591 for (unsigned i = 0; i < length; i++) {
592 CSSValueImpl *value = getPropertyCSSValue(set[i]);
594 m_values.remove(CSSProperty(set[i], value, false));
602 CSSMutableStyleDeclarationImpl *CSSMutableStyleDeclarationImpl::makeMutable()
607 CSSMutableStyleDeclarationImpl *CSSMutableStyleDeclarationImpl::copy() const
609 return new CSSMutableStyleDeclarationImpl(0, m_values);
612 // --------------------------------------------------------------------------------------
614 unsigned short CSSInheritedValueImpl::cssValueType() const
616 return CSSValue::CSS_INHERIT;
619 DOM::DOMString CSSInheritedValueImpl::cssText() const
621 return DOMString("inherit");
624 unsigned short CSSInitialValueImpl::cssValueType() const
626 return CSSValue::CSS_INITIAL;
629 DOM::DOMString CSSInitialValueImpl::cssText() const
631 return DOMString("initial");
634 // ----------------------------------------------------------------------------------------
636 CSSValueListImpl::CSSValueListImpl()
640 CSSValueListImpl::~CSSValueListImpl()
642 CSSValueImpl *val = m_values.first();
645 val = m_values.next();
649 unsigned short CSSValueListImpl::cssValueType() const
651 return CSSValue::CSS_VALUE_LIST;
654 void CSSValueListImpl::append(CSSValueImpl *val)
656 m_values.append(val);
660 DOM::DOMString CSSValueListImpl::cssText() const
662 DOMString result = "";
664 for (QPtrListIterator<CSSValueImpl> iterator(m_values); iterator.current(); ++iterator) {
665 if (result.length() != 0) {
668 result += iterator.current()->cssText();
674 // -------------------------------------------------------------------------------------
676 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl()
682 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(int ident)
685 m_value.ident = ident;
686 m_type = CSSPrimitiveValue::CSS_IDENT;
689 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(double num, CSSPrimitiveValue::UnitTypes type)
695 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(const DOMString &str, CSSPrimitiveValue::UnitTypes type)
697 m_value.string = str.implementation();
698 if(m_value.string) m_value.string->ref();
702 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(const Counter &c)
704 m_value.counter = c.handle();
706 m_value.counter->ref();
707 m_type = CSSPrimitiveValue::CSS_COUNTER;
710 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl( RectImpl *r)
715 m_type = CSSPrimitiveValue::CSS_RECT;
718 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl( DashboardRegionImpl *r)
722 m_value.region->ref();
723 m_type = CSSPrimitiveValue::CSS_DASHBOARD_REGION;
726 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(QRgb color)
728 m_value.rgbcolor = color;
729 m_type = CSSPrimitiveValue::CSS_RGBCOLOR;
732 CSSPrimitiveValueImpl::~CSSPrimitiveValueImpl()
737 void CSSPrimitiveValueImpl::cleanup()
740 case CSSPrimitiveValue::CSS_STRING:
741 case CSSPrimitiveValue::CSS_URI:
742 case CSSPrimitiveValue::CSS_ATTR:
743 if(m_value.string) m_value.string->deref();
745 case CSSPrimitiveValue::CSS_COUNTER:
746 m_value.counter->deref();
748 case CSSPrimitiveValue::CSS_RECT:
749 m_value.rect->deref();
751 case CSSPrimitiveValue::CSS_DASHBOARD_REGION:
753 m_value.region->deref();
762 int CSSPrimitiveValueImpl::computeLength( khtml::RenderStyle *style, QPaintDeviceMetrics *devMetrics )
764 double result = computeLengthFloat( style, devMetrics );
766 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We
767 // need to go ahead and round if we're really close to the next integer value.
768 int intResult = (int)(result + (result < 0 ? -0.01 : +0.01));
770 int intResult = (int)result;
775 int CSSPrimitiveValueImpl::computeLength( khtml::RenderStyle *style, QPaintDeviceMetrics *devMetrics,
778 double result = multiplier * computeLengthFloat( style, devMetrics );
780 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We
781 // need to go ahead and round if we're really close to the next integer value.
782 int intResult = (int)(result + (result < 0 ? -0.01 : +0.01));
784 int intResult = (int)result;
789 double CSSPrimitiveValueImpl::computeLengthFloat( khtml::RenderStyle *style, QPaintDeviceMetrics *devMetrics,
790 bool applyZoomFactor )
792 unsigned short type = primitiveType();
794 double dpiY = 72.; // fallback
796 dpiY = devMetrics->logicalDpiY();
797 if ( !khtml::printpainter && dpiY < 96 )
803 case CSSPrimitiveValue::CSS_EMS:
804 factor = applyZoomFactor ?
805 style->htmlFont().getFontDef().computedSize :
806 style->htmlFont().getFontDef().specifiedSize;
808 case CSSPrimitiveValue::CSS_EXS:
809 // FIXME: We have a bug right now where the zoom will be applied multiple times to EX units.
810 // We really need to compute EX using fontMetrics for the original specifiedSize and not use
811 // our actual constructed rendering font.
813 QFontMetrics fm = style->fontMetrics();
815 factor = fm.xHeight();
817 QRect b = fm.boundingRect('x');
822 case CSSPrimitiveValue::CSS_PX:
824 case CSSPrimitiveValue::CSS_CM:
825 factor = dpiY/2.54; //72dpi/(2.54 cm/in)
827 case CSSPrimitiveValue::CSS_MM:
830 case CSSPrimitiveValue::CSS_IN:
833 case CSSPrimitiveValue::CSS_PT:
836 case CSSPrimitiveValue::CSS_PC:
838 factor = dpiY*12./72.;
844 return getFloatValue(type)*factor;
847 void CSSPrimitiveValueImpl::setFloatValue( unsigned short unitType, double floatValue, int &exceptioncode )
851 // ### check if property supports this type
852 if(m_type > CSSPrimitiveValue::CSS_DIMENSION) {
853 exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
856 //if(m_type > CSSPrimitiveValue::CSS_DIMENSION) throw DOMException(DOMException::INVALID_ACCESS_ERR);
857 m_value.num = floatValue;
861 void CSSPrimitiveValueImpl::setStringValue( unsigned short stringType, const DOMString &stringValue, int &exceptioncode )
865 //if(m_type < CSSPrimitiveValue::CSS_STRING) throw DOMException(DOMException::INVALID_ACCESS_ERR);
866 //if(m_type > CSSPrimitiveValue::CSS_ATTR) throw DOMException(DOMException::INVALID_ACCESS_ERR);
867 if(m_type < CSSPrimitiveValue::CSS_STRING || m_type >> CSSPrimitiveValue::CSS_ATTR) {
868 exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET;
871 if(stringType != CSSPrimitiveValue::CSS_IDENT)
873 m_value.string = stringValue.implementation();
874 m_value.string->ref();
880 DOMString CSSPrimitiveValueImpl::getStringValue() const
883 case CSSPrimitiveValue::CSS_STRING:
884 case CSSPrimitiveValue::CSS_ATTR:
885 case CSSPrimitiveValue::CSS_URI:
886 return m_value.string;
887 case CSSPrimitiveValue::CSS_IDENT:
888 return getValueName(m_value.ident);
890 // FIXME: The CSS 2.1 spec says you should throw an exception here.
897 unsigned short CSSPrimitiveValueImpl::cssValueType() const
899 return CSSValue::CSS_PRIMITIVE_VALUE;
902 bool CSSPrimitiveValueImpl::parseString( const DOMString &/*string*/, bool )
908 int CSSPrimitiveValueImpl::getIdent()
910 if(m_type != CSSPrimitiveValue::CSS_IDENT) return 0;
911 return m_value.ident;
914 DOM::DOMString CSSPrimitiveValueImpl::cssText() const
916 // ### return the original value instead of a generated one (e.g. color
917 // name if it was specified) - check what spec says about this
920 case CSSPrimitiveValue::CSS_UNKNOWN:
923 case CSSPrimitiveValue::CSS_NUMBER:
924 text = DOMString(QString::number( m_value.num ));
926 case CSSPrimitiveValue::CSS_PERCENTAGE:
927 text = DOMString(QString::number( m_value.num ) + "%");
929 case CSSPrimitiveValue::CSS_EMS:
930 text = DOMString(QString::number( m_value.num ) + "em");
932 case CSSPrimitiveValue::CSS_EXS:
933 text = DOMString(QString::number( m_value.num ) + "ex");
935 case CSSPrimitiveValue::CSS_PX:
936 text = DOMString(QString::number( m_value.num ) + "px");
938 case CSSPrimitiveValue::CSS_CM:
939 text = DOMString(QString::number( m_value.num ) + "cm");
941 case CSSPrimitiveValue::CSS_MM:
942 text = DOMString(QString::number( m_value.num ) + "mm");
944 case CSSPrimitiveValue::CSS_IN:
945 text = DOMString(QString::number( m_value.num ) + "in");
947 case CSSPrimitiveValue::CSS_PT:
948 text = DOMString(QString::number( m_value.num ) + "pt");
950 case CSSPrimitiveValue::CSS_PC:
951 text = DOMString(QString::number( m_value.num ) + "pc");
953 case CSSPrimitiveValue::CSS_DEG:
954 text = DOMString(QString::number( m_value.num ) + "deg");
956 case CSSPrimitiveValue::CSS_RAD:
957 text = DOMString(QString::number( m_value.num ) + "rad");
959 case CSSPrimitiveValue::CSS_GRAD:
960 text = DOMString(QString::number( m_value.num ) + "grad");
962 case CSSPrimitiveValue::CSS_MS:
963 text = DOMString(QString::number( m_value.num ) + "ms");
965 case CSSPrimitiveValue::CSS_S:
966 text = DOMString(QString::number( m_value.num ) + "s");
968 case CSSPrimitiveValue::CSS_HZ:
969 text = DOMString(QString::number( m_value.num ) + "hz");
971 case CSSPrimitiveValue::CSS_KHZ:
972 text = DOMString(QString::number( m_value.num ) + "khz");
974 case CSSPrimitiveValue::CSS_DIMENSION:
977 case CSSPrimitiveValue::CSS_STRING:
978 text = quoteStringIfNeeded(m_value.string);
980 case CSSPrimitiveValue::CSS_URI:
982 text += DOMString( m_value.string );
985 case CSSPrimitiveValue::CSS_IDENT:
986 text = getValueName(m_value.ident);
988 case CSSPrimitiveValue::CSS_ATTR:
991 case CSSPrimitiveValue::CSS_COUNTER:
994 case CSSPrimitiveValue::CSS_RECT: {
995 RectImpl* rectVal = getRectValue();
997 text += rectVal->top()->cssText() + " ";
998 text += rectVal->right()->cssText() + " ";
999 text += rectVal->bottom()->cssText() + " ";
1000 text += rectVal->left()->cssText() + ")";
1003 case CSSPrimitiveValue::CSS_RGBCOLOR: {
1004 QColor color(m_value.rgbcolor);
1005 if (qAlpha(m_value.rgbcolor) < 0xFF)
1009 text += QString::number(color.red()) + ", ";
1010 text += QString::number(color.green()) + ", ";
1011 text += QString::number(color.blue());
1012 if (qAlpha(m_value.rgbcolor) < 0xFF)
1013 text += ", " + QString::number((float)qAlpha(m_value.rgbcolor) / 0xFF);
1018 case CSSPrimitiveValue::CSS_DASHBOARD_REGION: {
1019 DashboardRegionImpl *region = getDashboardRegionValue();
1021 text = "dashboard-region(";
1022 text += region->m_label;
1023 if (region->m_isCircle){
1026 else if (region->m_isRectangle){
1027 text += " rectangle ";
1031 text += region->top()->cssText() + " ";
1032 text += region->right()->cssText() + " ";
1033 text += region->bottom()->cssText() + " ";
1034 text += region->left()->cssText();
1036 region = region->m_next;
1045 // -----------------------------------------------------------------
1047 RectImpl::RectImpl()
1055 RectImpl::~RectImpl()
1057 if (m_top) m_top->deref();
1058 if (m_right) m_right->deref();
1059 if (m_bottom) m_bottom->deref();
1060 if (m_left) m_left->deref();
1063 void RectImpl::setTop( CSSPrimitiveValueImpl *top )
1065 if( top ) top->ref();
1066 if ( m_top ) m_top->deref();
1070 void RectImpl::setRight( CSSPrimitiveValueImpl *right )
1072 if( right ) right->ref();
1073 if ( m_right ) m_right->deref();
1077 void RectImpl::setBottom( CSSPrimitiveValueImpl *bottom )
1079 if( bottom ) bottom->ref();
1080 if ( m_bottom ) m_bottom->deref();
1084 void RectImpl::setLeft( CSSPrimitiveValueImpl *left )
1086 if( left ) left->ref();
1087 if ( m_left ) m_left->deref();
1091 // -----------------------------------------------------------------
1093 CSSImageValueImpl::CSSImageValueImpl(const DOMString &url, StyleBaseImpl *style)
1094 : CSSPrimitiveValueImpl(url, CSSPrimitiveValue::CSS_URI), m_image(0), m_accessedImage(false)
1098 CSSImageValueImpl::CSSImageValueImpl()
1099 : CSSPrimitiveValueImpl(CSS_VAL_NONE), m_image(0), m_accessedImage(true)
1103 CSSImageValueImpl::~CSSImageValueImpl()
1105 if(m_image) m_image->deref(this);
1108 khtml::CachedImage* CSSImageValueImpl::image(khtml::DocLoader* loader)
1110 if (!m_accessedImage) {
1111 m_accessedImage = true;
1114 m_image = loader->requestImage(getStringValue());
1116 m_image = khtml::Cache::requestImage(0, getStringValue());
1118 if(m_image) m_image->ref(this);
1124 // ------------------------------------------------------------------------
1126 FontFamilyValueImpl::FontFamilyValueImpl( const QString &string)
1127 : CSSPrimitiveValueImpl( DOMString(), CSSPrimitiveValue::CSS_STRING)
1129 static const QRegExp parenReg(" \\(.*\\)$");
1130 static const QRegExp braceReg(" \\[.*\\]$");
1133 parsedFontName = string;
1134 // a language tag is often added in braces at the end. Remove it.
1135 parsedFontName.replace(parenReg, "");
1136 // remove [Xft] qualifiers
1137 parsedFontName.replace(braceReg, "");
1139 const QString &available = KHTMLSettings::availableFamilies();
1141 QString face = string.lower();
1142 // a languge tag is often added in braces at the end. Remove it.
1143 face = face.replace(parenReg, "");
1144 // remove [Xft] qualifiers
1145 face = face.replace(braceReg, "");
1146 //kdDebug(0) << "searching for face '" << face << "'" << endl;
1148 int pos = available.find( face, 0, false );
1151 int p = face.find(' ');
1152 // Arial Blk --> Arial
1153 // MS Sans Serif --> Sans Serif
1155 if(p > 0 && (int)str.length() - p > p + 1)
1156 str = str.mid( p+1 );
1159 pos = available.find( str, 0, false);
1164 int pos1 = available.findRev( ',', pos ) + 1;
1165 pos = available.find( ',', pos );
1167 pos = available.length();
1168 parsedFontName = available.mid( pos1, pos - pos1 );
1170 #endif // !APPLE_CHANGES
1173 DOM::DOMString FontFamilyValueImpl::cssText() const
1175 return quoteStringIfNeeded(parsedFontName);
1178 FontValueImpl::FontValueImpl()
1179 : style(0), variant(0), weight(0), size(0), lineHeight(0), family(0)
1183 FontValueImpl::~FontValueImpl()
1193 DOMString FontValueImpl::cssText() const
1195 // font variant weight size / line-height family
1197 DOMString result("");
1200 result += style->cssText();
1203 if (result.length() > 0) {
1206 result += variant->cssText();
1209 if (result.length() > 0) {
1212 result += weight->cssText();
1215 if (result.length() > 0) {
1218 result += size->cssText();
1225 result += lineHeight->cssText();
1228 if (result.length() > 0) {
1231 result += family->cssText();
1238 // Used for text-shadow and box-shadow
1239 ShadowValueImpl::ShadowValueImpl(CSSPrimitiveValueImpl* _x, CSSPrimitiveValueImpl* _y,
1240 CSSPrimitiveValueImpl* _blur, CSSPrimitiveValueImpl* _color)
1241 :x(_x), y(_y), blur(_blur), color(_color)
1244 ShadowValueImpl::~ShadowValueImpl()
1252 DOMString ShadowValueImpl::cssText() const
1256 text += color->cssText();
1259 if (text.length() > 0) {
1262 text += x->cssText();
1265 if (text.length() > 0) {
1268 text += y->cssText();
1271 if (text.length() > 0) {
1274 text += blur->cssText();
1280 DOMString CSSProperty::cssText() const
1282 return getPropertyName(m_id) + DOMString(": ") + m_value->cssText() + (m_bImportant ? DOMString(" !important") : DOMString()) + DOMString("; ");
1285 bool operator==(const CSSProperty &a, const CSSProperty &b)
1287 return a.m_id == b.m_id && a.m_bImportant == b.m_bImportant && a.m_value == b.m_value;