File indexing completed on 2024-04-28 11:37:29
0001 /** 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) 0005 * (C) 2004-2008 Apple Computer, Inc. 0006 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 0007 * (C) 2009 Germain Garand (germain@ebooksfrance.org) 0008 * 0009 * This library is free software; you can redistribute it and/or 0010 * modify it under the terms of the GNU Library General Public 0011 * License as published by the Free Software Foundation; either 0012 * version 2 of the License, or (at your option) any later version. 0013 * 0014 * This library is distributed in the hope that it will be useful, 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 * Library General Public License for more details. 0018 * 0019 * You should have received a copy of the GNU Library General Public License 0020 * along with this library; see the file COPYING.LIB. If not, write to 0021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 * Boston, MA 02110-1301, USA. 0023 */ 0024 0025 #include "css_valueimpl.h" 0026 #include "css_ruleimpl.h" 0027 #include "css_stylesheetimpl.h" 0028 #include "css/csshelper.h" 0029 #include "cssparser.h" 0030 #include "cssproperties.h" 0031 #include "cssvalues.h" 0032 0033 #include <dom/css_value.h> 0034 #include <dom/dom_exception.h> 0035 #include <dom/dom_string.h> 0036 0037 #include <xml/dom_stringimpl.h> 0038 #include <xml/dom_docimpl.h> 0039 0040 #include <rendering/font.h> 0041 #include <rendering/render_style.h> 0042 0043 #include <wtf/ASCIICType.h> 0044 0045 #include "khtml_debug.h" 0046 #include <QRegExp> 0047 #include <QPaintDevice> 0048 0049 // Hack for debugging purposes 0050 extern DOM::DOMString getPropertyName(unsigned short id); 0051 0052 using khtml::FontDef; 0053 0054 using namespace DOM; 0055 using namespace WTF; 0056 0057 static int propertyID(const DOMString &s) 0058 { 0059 char buffer[maxCSSPropertyNameLength]; 0060 0061 unsigned len = s.length(); 0062 if (len > maxCSSPropertyNameLength) { 0063 return 0; 0064 } 0065 0066 for (unsigned i = 0; i != len; ++i) { 0067 unsigned short c = s[i].unicode(); 0068 if (c == 0 || c >= 0x7F) { 0069 return 0; // illegal character 0070 } 0071 buffer[i] = s[i].toLower().unicode(); 0072 } 0073 0074 return getPropertyID(buffer, len); 0075 } 0076 0077 // "ident" from the CSS tokenizer, minus backslash-escape sequences 0078 static bool isCSSTokenizerIdentifier(const DOMString &string) 0079 { 0080 const QChar *p = string.unicode(); 0081 const QChar *end = p + string.length(); 0082 0083 // -? 0084 if (p != end && p[0] == '-') { 0085 ++p; 0086 } 0087 0088 // {nmstart} 0089 if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p->unicode()))) { 0090 return false; 0091 } 0092 ++p; 0093 0094 // {nmchar}* 0095 for (; p != end; ++p) { 0096 if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p->unicode()))) { 0097 return false; 0098 } 0099 } 0100 0101 return true; 0102 } 0103 0104 static DOMString quoteString(const DOMString &string) 0105 { 0106 // FIXME: Also need to transform control characters into \ sequences. 0107 QString s = string.string(); 0108 s.replace('\\', "\\\\"); 0109 s.replace('\'', "\\'"); 0110 return QString('\'' + s + '\''); 0111 } 0112 0113 // Quotes the string if it needs quoting. 0114 static DOMString quoteStringIfNeeded(const DOMString &string) 0115 { 0116 return isCSSTokenizerIdentifier(string) ? string : quoteString(string); 0117 } 0118 0119 static inline bool isInitialOrInherit(const CSSValueImpl *value) 0120 { 0121 const unsigned short t = value->cssValueType(); 0122 return (t == CSSValue::CSS_INHERIT || t == CSSValue::CSS_INITIAL); 0123 } 0124 0125 CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent) 0126 : StyleBaseImpl(parent) 0127 { 0128 m_lstValues = nullptr; 0129 m_node = nullptr; 0130 } 0131 0132 CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent, QList<CSSProperty *> *lstValues) 0133 : StyleBaseImpl(parent) 0134 { 0135 m_lstValues = lstValues; 0136 m_node = nullptr; 0137 } 0138 0139 CSSStyleDeclarationImpl &CSSStyleDeclarationImpl::operator= (const CSSStyleDeclarationImpl &o) 0140 { 0141 if (this == &o) { 0142 return *this; 0143 } 0144 0145 // don't attach it to the same node, just leave the current m_node value 0146 if (m_lstValues) { 0147 qDeleteAll(*m_lstValues); 0148 } 0149 delete m_lstValues; 0150 m_lstValues = nullptr; 0151 if (o.m_lstValues) { 0152 m_lstValues = new QList<CSSProperty *>; 0153 QListIterator<CSSProperty *> lstValuesIt(*o.m_lstValues); 0154 while (lstValuesIt.hasNext()) { 0155 m_lstValues->append(new CSSProperty(*lstValuesIt.next())); 0156 } 0157 } 0158 0159 return *this; 0160 } 0161 0162 CSSStyleDeclarationImpl::~CSSStyleDeclarationImpl() 0163 { 0164 if (m_lstValues) { 0165 qDeleteAll(*m_lstValues); 0166 } 0167 delete m_lstValues; 0168 // we don't use refcounting for m_node, to avoid cyclic references (see ElementImpl) 0169 } 0170 0171 CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue(const DOMString &propertyName) const 0172 { 0173 int propID = propertyID(propertyName); 0174 if (!propID) { 0175 return nullptr; 0176 } 0177 return getPropertyCSSValue(propID); 0178 } 0179 0180 DOMString CSSStyleDeclarationImpl::getPropertyValue(const DOMString &propertyName) const 0181 { 0182 int propID = propertyID(propertyName); 0183 if (!propID) { 0184 return DOMString(); 0185 } 0186 return getPropertyValue(propID); 0187 } 0188 0189 DOMString CSSStyleDeclarationImpl::getPropertyPriority(const DOMString &propertyName) const 0190 { 0191 int propID = propertyID(propertyName); 0192 if (!propID) { 0193 return DOMString(); 0194 } 0195 return getPropertyPriority(propID) ? "important" : ""; 0196 } 0197 0198 void CSSStyleDeclarationImpl::setProperty(const DOMString &propertyName, const DOMString &value, const DOMString &priority) 0199 { 0200 int propID = propertyID(propertyName); 0201 if (!propID) { // set exception? 0202 return; 0203 } 0204 bool important = priority.string().indexOf("important", 0, Qt::CaseInsensitive) != -1; 0205 setProperty(propID, value, important); 0206 } 0207 0208 DOMString CSSStyleDeclarationImpl::removeProperty(const DOMString &propertyName) 0209 { 0210 int propID = propertyID(propertyName); 0211 if (!propID) { 0212 return DOMString(); 0213 } 0214 DOMString old; 0215 removeProperty(propID, &old); 0216 return old; 0217 } 0218 0219 DOMString CSSStyleDeclarationImpl::getPropertyValue(int propertyID) const 0220 { 0221 if (!m_lstValues || m_lstValues->isEmpty()) { 0222 return DOMString(); 0223 } 0224 CSSValueImpl *value = getPropertyCSSValue(propertyID); 0225 if (value) { 0226 return value->cssText(); 0227 } 0228 0229 // Shorthand and 4-values properties 0230 switch (propertyID) { 0231 case CSS_PROP_BACKGROUND_POSITION: { 0232 // ## Is this correct? The code in cssparser.cpp is confusing 0233 const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X, 0234 CSS_PROP_BACKGROUND_POSITION_Y 0235 }; 0236 return getLayeredShortHandValue(properties, 2); 0237 } 0238 case CSS_PROP_BACKGROUND: { 0239 // 'clip' must come after 'origin' in this array 0240 const int properties[9] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT, CSS_PROP_BACKGROUND_ATTACHMENT, 0241 CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y, CSS_PROP_BACKGROUND_SIZE, 0242 CSS_PROP_BACKGROUND_ORIGIN, CSS_PROP_BACKGROUND_CLIP, CSS_PROP_BACKGROUND_COLOR 0243 }; 0244 return getLayeredShortHandValue(properties, 9); 0245 } 0246 case CSS_PROP_BORDER: { 0247 const int properties[3][4] = {{ 0248 CSS_PROP_BORDER_TOP_WIDTH, 0249 CSS_PROP_BORDER_RIGHT_WIDTH, 0250 CSS_PROP_BORDER_BOTTOM_WIDTH, 0251 CSS_PROP_BORDER_LEFT_WIDTH 0252 }, 0253 { 0254 CSS_PROP_BORDER_TOP_STYLE, 0255 CSS_PROP_BORDER_RIGHT_STYLE, 0256 CSS_PROP_BORDER_BOTTOM_STYLE, 0257 CSS_PROP_BORDER_LEFT_STYLE 0258 }, 0259 { 0260 CSS_PROP_BORDER_TOP_COLOR, 0261 CSS_PROP_BORDER_RIGHT_COLOR, 0262 CSS_PROP_BORDER_LEFT_COLOR, 0263 CSS_PROP_BORDER_BOTTOM_COLOR 0264 } 0265 }; 0266 DOMString res; 0267 const int nrprops = sizeof(properties) / sizeof(properties[0]); 0268 for (int i = 0; i < nrprops; ++i) { 0269 DOMString value = getCommonValue(properties[i], 4); 0270 if (!value.isNull()) { 0271 if (!res.isNull()) { 0272 res += " "; 0273 } 0274 res += value; 0275 } 0276 } 0277 return res; 0278 0279 } 0280 case CSS_PROP_BORDER_TOP: { 0281 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE, 0282 CSS_PROP_BORDER_TOP_COLOR 0283 }; 0284 return getShortHandValue(properties, 3); 0285 } 0286 case CSS_PROP_BORDER_RIGHT: { 0287 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE, 0288 CSS_PROP_BORDER_RIGHT_COLOR 0289 }; 0290 return getShortHandValue(properties, 3); 0291 } 0292 case CSS_PROP_BORDER_BOTTOM: { 0293 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE, 0294 CSS_PROP_BORDER_BOTTOM_COLOR 0295 }; 0296 return getShortHandValue(properties, 3); 0297 } 0298 case CSS_PROP_BORDER_LEFT: { 0299 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE, 0300 CSS_PROP_BORDER_LEFT_COLOR 0301 }; 0302 return getShortHandValue(properties, 3); 0303 } 0304 case CSS_PROP_OUTLINE: { 0305 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE, 0306 CSS_PROP_OUTLINE_COLOR 0307 }; 0308 return getShortHandValue(properties, 3); 0309 } 0310 case CSS_PROP_BORDER_COLOR: { 0311 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR, 0312 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR 0313 }; 0314 return get4Values(properties); 0315 } 0316 case CSS_PROP_BORDER_WIDTH: { 0317 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH, 0318 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH 0319 }; 0320 return get4Values(properties); 0321 } 0322 case CSS_PROP_BORDER_STYLE: { 0323 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE, 0324 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE 0325 }; 0326 return get4Values(properties); 0327 } 0328 case CSS_PROP_MARGIN: { 0329 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT, 0330 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT 0331 }; 0332 return get4Values(properties); 0333 } 0334 case CSS_PROP_PADDING: { 0335 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT, 0336 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT 0337 }; 0338 return get4Values(properties); 0339 } 0340 case CSS_PROP_LIST_STYLE: { 0341 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION, 0342 CSS_PROP_LIST_STYLE_IMAGE 0343 }; 0344 return getShortHandValue(properties, 3); 0345 } 0346 } 0347 //qCDebug(KHTML_LOG) << "property not found:" << propertyID; 0348 return DOMString(); 0349 } 0350 0351 // only returns a non-null value if all properties have the same, non-null value 0352 DOMString CSSStyleDeclarationImpl::getCommonValue(const int *properties, int number) const 0353 { 0354 DOMString res; 0355 for (int i = 0; i < number; ++i) { 0356 CSSValueImpl *value = getPropertyCSSValue(properties[i]); 0357 if (!value) { 0358 return DOMString(); 0359 } 0360 DOMString text = value->cssText(); 0361 if (text.isNull()) { 0362 return DOMString(); 0363 } 0364 if (res.isNull()) { 0365 res = text; 0366 } else if (res != text) { 0367 return DOMString(); 0368 } 0369 } 0370 return res; 0371 } 0372 0373 DOMString CSSStyleDeclarationImpl::get4Values(const int *properties) const 0374 { 0375 // Assume the properties are in the order top, right, bottom, left. 0376 QVector<DOMString> values(4); 0377 for (int i = 0; i < 4; ++i) { 0378 CSSValueImpl *val = getPropertyCSSValue(properties[i]); 0379 // All 4 properties must be specified. 0380 if (!val || isInitialOrInherit(val)) { 0381 return DOMString(); 0382 } else { 0383 values[i] = val->cssText(); 0384 } 0385 } 0386 0387 // Reduce shorthand. 0388 if (values.at(1) == values.at(3)) { // right/left 0389 values.remove(3); 0390 if (values.at(0) == values.at(2)) { // top/bottom 0391 values.remove(2); 0392 if (values.at(0) == values.at(1)) { 0393 values.remove(1); 0394 } 0395 } 0396 } 0397 0398 DOMString res; 0399 const int valuesSize = values.size(); 0400 for (int i = 0; i < valuesSize; ++i) { 0401 if (!res.isNull()) { 0402 res += " "; 0403 } 0404 res += values.at(i); 0405 } 0406 0407 return res; 0408 } 0409 0410 static inline DOMString posXYSize_string_helper(DOMString &bPosX, DOMString &bPosY, DOMString &bSize) 0411 { 0412 DOMString res, position; 0413 0414 if (!bPosX.isEmpty() && !bPosY.isEmpty()) { 0415 position = bPosX + DOMString(" ") + bPosY; 0416 } else if (bPosX.isEmpty() && !bPosY.isEmpty()) { 0417 position = DOMString("0% ") + bPosY; 0418 } else if (!bPosX.isEmpty() && bPosY.isEmpty()) { 0419 position = bPosX + DOMString(" 0%"); 0420 } 0421 0422 if (!bSize.isEmpty()) { 0423 if (position.isEmpty()) { 0424 res = DOMString("0% 0%") + DOMString(" / ") + bSize; 0425 } else { 0426 res = position + DOMString(" / ") + bSize; 0427 } 0428 } else { 0429 res = position; 0430 } 0431 0432 return res; 0433 } 0434 0435 DOMString CSSStyleDeclarationImpl::getLayeredShortHandValue(const int *properties, unsigned number) const 0436 { 0437 DOMString res; 0438 unsigned i; 0439 unsigned j; 0440 0441 // Begin by collecting the properties into an array. 0442 QVector<CSSValueImpl *> values(number); 0443 unsigned numLayers = 0; 0444 0445 for (i = 0; i < number; ++i) { 0446 values[i] = getPropertyCSSValue(properties[i]); 0447 if (values[i]) { 0448 if (values[i]->isValueList()) { 0449 CSSValueListImpl *valueList = static_cast<CSSValueListImpl *>(values[i]); 0450 numLayers = qMax(valueList->length(), (unsigned long)numLayers); 0451 } else { 0452 numLayers = qMax(1U, numLayers); 0453 } 0454 } 0455 } 0456 0457 // Now stitch the properties together. 0458 // Implicit initial values are flagged as such and can safely be omitted. 0459 for (i = 0; i < numLayers; i++) { 0460 DOMString layerRes; 0461 DOMString bPosX, bPosY, bSize; 0462 for (j = 0; j < number; j++) { 0463 CSSValueImpl *value = nullptr; 0464 if (values[j]) { 0465 if (values[j]->isValueList()) { 0466 value = static_cast<CSSValueListImpl *>(values[j])->item(i); 0467 } else { 0468 value = values[j]; 0469 0470 // Color only belongs in the last layer. 0471 if (properties[j] == CSS_PROP_BACKGROUND_COLOR) { 0472 if (i != numLayers - 1) { 0473 value = nullptr; 0474 } 0475 } else if (i != 0) { // Other singletons only belong in the first layer. 0476 value = nullptr; 0477 } 0478 } 0479 } 0480 0481 if (value && !value->isImplicitInitialValue()) { 0482 // positionX,positionY,size should be handled separately in order 0483 // to return a consistent and valid 'background' property string 0484 if (properties[j] == CSS_PROP_BACKGROUND_POSITION_X) { 0485 bPosX = value->cssText(); 0486 } else if (properties[j] == CSS_PROP_BACKGROUND_POSITION_Y) { 0487 bPosY = value->cssText(); 0488 } else if (properties[j] == CSS_PROP_BACKGROUND_SIZE) { 0489 bSize = value->cssText(); 0490 } else { 0491 if (!layerRes.isNull()) { 0492 layerRes += " "; 0493 } 0494 layerRes += value->cssText(); 0495 } 0496 } 0497 } 0498 0499 // now add positionX,positionY,size 0500 DOMString posXYSize = posXYSize_string_helper(bPosX, bPosY, bSize); 0501 if (!posXYSize.isEmpty()) { 0502 if (!layerRes.isNull()) { 0503 layerRes += " "; 0504 } 0505 layerRes += posXYSize; 0506 } 0507 0508 if (!layerRes.isNull()) { 0509 if (!res.isNull()) { 0510 res += ", "; 0511 } 0512 res += layerRes; 0513 } 0514 } 0515 0516 return res; 0517 } 0518 0519 DOMString CSSStyleDeclarationImpl::getShortHandValue(const int *properties, int number) const 0520 { 0521 DOMString res; 0522 for (int i = 0; i < number; ++i) { 0523 CSSValueImpl *value = getPropertyCSSValue(properties[i]); 0524 if (value) { // TODO provide default value if !value 0525 if (!res.isNull()) { 0526 res += " "; 0527 } 0528 res += value->cssText(); 0529 } 0530 } 0531 return res; 0532 } 0533 0534 CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue(int propertyID) const 0535 { 0536 if (!m_lstValues || m_lstValues->isEmpty()) { 0537 return nullptr; 0538 } 0539 0540 QListIterator<CSSProperty *> lstValuesIt(*m_lstValues); 0541 CSSProperty *current; 0542 while (lstValuesIt.hasNext()) { 0543 current = lstValuesIt.next(); 0544 if (current->m_id == propertyID) { 0545 return current->value(); 0546 } 0547 } 0548 return nullptr; 0549 } 0550 0551 bool CSSStyleDeclarationImpl::isPropertyImplicit(int propertyID) const 0552 { 0553 QListIterator<CSSProperty *> lstValuesIt(*m_lstValues); 0554 CSSProperty const *current; 0555 while (lstValuesIt.hasNext()) { 0556 current = lstValuesIt.next(); 0557 if (current->m_id == propertyID) { 0558 return current->isImplicit(); 0559 } 0560 } 0561 return false; 0562 } 0563 0564 // --------------- Shorthands mapping ---------------- 0565 0566 // In order top be able to remove a shorthand property, 0567 // we need a reverse mapping from the shorthands to their composing properties. 0568 0569 // ### Warning: keep in sync when introducing new shorthands. 0570 0571 struct PropertyLonghand { 0572 PropertyLonghand() 0573 : m_properties(nullptr) 0574 , m_length(0) 0575 { 0576 } 0577 0578 PropertyLonghand(const int *firstProperty, unsigned numProperties) 0579 : m_properties(firstProperty) 0580 , m_length(numProperties) 0581 { 0582 } 0583 0584 const int *properties() const 0585 { 0586 return m_properties; 0587 } 0588 unsigned length() const 0589 { 0590 return m_length; 0591 } 0592 0593 private: 0594 const int *m_properties; 0595 unsigned m_length; 0596 }; 0597 0598 static void initShorthandMap(QHash<int, PropertyLonghand> &shorthandMap) 0599 { 0600 #define SET_SHORTHAND_MAP_ENTRY(map, propID, array) \ 0601 map.insert(propID, PropertyLonghand(array, sizeof(array) / sizeof(array[0]))) 0602 0603 // Do not change the order of the following four shorthands, and keep them together. 0604 static const int borderProperties[4][3] = { 0605 { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_TOP_WIDTH }, 0606 { CSS_PROP_BORDER_RIGHT_COLOR, CSS_PROP_BORDER_RIGHT_STYLE, CSS_PROP_BORDER_RIGHT_WIDTH }, 0607 { CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_BOTTOM_WIDTH }, 0608 { CSS_PROP_BORDER_LEFT_COLOR, CSS_PROP_BORDER_LEFT_STYLE, CSS_PROP_BORDER_LEFT_WIDTH } 0609 }; 0610 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_TOP, borderProperties[0]); 0611 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_RIGHT, borderProperties[1]); 0612 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_BOTTOM, borderProperties[2]); 0613 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_LEFT, borderProperties[3]); 0614 0615 shorthandMap.insert(CSS_PROP_BORDER, PropertyLonghand(borderProperties[0], sizeof(borderProperties) / sizeof(borderProperties[0][0]))); 0616 0617 static const int borderColorProperties[] = { 0618 CSS_PROP_BORDER_TOP_COLOR, 0619 CSS_PROP_BORDER_RIGHT_COLOR, 0620 CSS_PROP_BORDER_BOTTOM_COLOR, 0621 CSS_PROP_BORDER_LEFT_COLOR 0622 }; 0623 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_COLOR, borderColorProperties); 0624 0625 static const int borderStyleProperties[] = { 0626 CSS_PROP_BORDER_TOP_STYLE, 0627 CSS_PROP_BORDER_RIGHT_STYLE, 0628 CSS_PROP_BORDER_BOTTOM_STYLE, 0629 CSS_PROP_BORDER_LEFT_STYLE 0630 }; 0631 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_STYLE, borderStyleProperties); 0632 0633 static const int borderWidthProperties[] = { 0634 CSS_PROP_BORDER_TOP_WIDTH, 0635 CSS_PROP_BORDER_RIGHT_WIDTH, 0636 CSS_PROP_BORDER_BOTTOM_WIDTH, 0637 CSS_PROP_BORDER_LEFT_WIDTH 0638 }; 0639 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_WIDTH, borderWidthProperties); 0640 0641 static const int backgroundPositionProperties[] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y }; 0642 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND_POSITION, backgroundPositionProperties); 0643 0644 static const int borderSpacingProperties[] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING, CSS_PROP__KHTML_BORDER_VERTICAL_SPACING }; 0645 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_SPACING, borderSpacingProperties); 0646 0647 static const int listStyleProperties[] = { 0648 CSS_PROP_LIST_STYLE_IMAGE, 0649 CSS_PROP_LIST_STYLE_POSITION, 0650 CSS_PROP_LIST_STYLE_TYPE 0651 }; 0652 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_LIST_STYLE, listStyleProperties); 0653 0654 static const int marginProperties[] = { 0655 CSS_PROP_MARGIN_TOP, 0656 CSS_PROP_MARGIN_RIGHT, 0657 CSS_PROP_MARGIN_BOTTOM, 0658 CSS_PROP_MARGIN_LEFT 0659 }; 0660 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_MARGIN, marginProperties); 0661 0662 #ifdef APPLE_CHANGES 0663 static const int marginCollapseProperties[] = { CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE, CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE }; 0664 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARGIN_COLLAPSE, marginCollapseProperties); 0665 #endif 0666 0667 static const int marqueeProperties[] = { 0668 CSS_PROP__KHTML_MARQUEE_DIRECTION, 0669 CSS_PROP__KHTML_MARQUEE_INCREMENT, 0670 CSS_PROP__KHTML_MARQUEE_REPETITION, 0671 CSS_PROP__KHTML_MARQUEE_STYLE, 0672 CSS_PROP__KHTML_MARQUEE_SPEED 0673 }; 0674 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARQUEE, marqueeProperties); 0675 0676 static const int outlineProperties[] = { 0677 CSS_PROP_OUTLINE_COLOR, 0678 CSS_PROP_OUTLINE_OFFSET, 0679 CSS_PROP_OUTLINE_STYLE, 0680 CSS_PROP_OUTLINE_WIDTH 0681 }; 0682 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OUTLINE, outlineProperties); 0683 0684 static const int paddingProperties[] = { 0685 CSS_PROP_PADDING_TOP, 0686 CSS_PROP_PADDING_RIGHT, 0687 CSS_PROP_PADDING_BOTTOM, 0688 CSS_PROP_PADDING_LEFT 0689 }; 0690 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_PADDING, paddingProperties); 0691 0692 #ifdef APPLE_CHANGES 0693 static const int textStrokeProperties[] = { CSS_PROP__KHTML_TEXT_STROKE_COLOR, CSS_PROP__KHTML_TEXT_STROKE_WIDTH }; 0694 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_TEXT_STROKE, textStrokeProperties); 0695 #endif 0696 0697 static const int backgroundProperties[] = { 0698 CSS_PROP_BACKGROUND_ATTACHMENT, 0699 CSS_PROP_BACKGROUND_COLOR, 0700 CSS_PROP_BACKGROUND_IMAGE, 0701 CSS_PROP_BACKGROUND_POSITION_X, 0702 CSS_PROP_BACKGROUND_POSITION_Y, 0703 CSS_PROP_BACKGROUND_REPEAT, 0704 CSS_PROP_BACKGROUND_SIZE, 0705 CSS_PROP_BACKGROUND_ORIGIN, 0706 CSS_PROP_BACKGROUND_CLIP 0707 }; 0708 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND, backgroundProperties); 0709 0710 #ifdef APPLE_CHANGES 0711 static const int columnsProperties[] = { CSS_PROP__KHTML_COLUMN_WIDTH, CSS_PROP__KHTML_COLUMN_COUNT }; 0712 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMNS, columnsProperties); 0713 0714 static const int columnRuleProperties[] = { 0715 CSS_PROP__KHTML_COLUMN_RULE_COLOR, 0716 CSS_PROP__KHTML_COLUMN_RULE_STYLE, 0717 CSS_PROP__KHTML_COLUMN_RULE_WIDTH 0718 }; 0719 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMN_RULE, columnRuleProperties); 0720 #endif 0721 0722 static const int overflowProperties[] = { CSS_PROP_OVERFLOW_X, CSS_PROP_OVERFLOW_Y }; 0723 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OVERFLOW, overflowProperties); 0724 0725 static const int borderRadiusProperties[] = { 0726 CSS_PROP_BORDER_TOP_RIGHT_RADIUS, 0727 CSS_PROP_BORDER_TOP_LEFT_RADIUS, 0728 CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS, 0729 CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS 0730 }; 0731 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_RADIUS, borderRadiusProperties); 0732 0733 static const int markerProperties[] = { 0734 CSS_PROP_MARKER_START, 0735 CSS_PROP_MARKER_MID, 0736 CSS_PROP_MARKER_END 0737 }; 0738 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_MARKER, markerProperties); 0739 0740 static const int fontProperties[] = { 0741 CSS_PROP_FONT_STYLE, 0742 CSS_PROP_FONT_VARIANT, 0743 CSS_PROP_FONT_WEIGHT, 0744 CSS_PROP_FONT_SIZE, 0745 CSS_PROP_LINE_HEIGHT, 0746 CSS_PROP_FONT_FAMILY 0747 }; 0748 SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_FONT, fontProperties); 0749 0750 #undef SET_SHORTHAND_MAP_ENTRY 0751 } 0752 0753 // ------------------------------------------- 0754 0755 void CSSStyleDeclarationImpl::removeProperty(int propertyID, DOM::DOMString *old) 0756 { 0757 if (!m_lstValues || m_lstValues->isEmpty()) { 0758 return; 0759 } 0760 0761 bool changed = false; 0762 0763 static QHash<int, PropertyLonghand> shorthandMap; 0764 if (shorthandMap.isEmpty()) { 0765 initShorthandMap(shorthandMap); 0766 } 0767 0768 PropertyLonghand longhand = shorthandMap.value(propertyID); 0769 if (longhand.length()) { 0770 changed = removePropertiesInSet(longhand.properties(), longhand.length()); 0771 } 0772 0773 // FIXME: Return an equivalent shorthand when possible. 0774 0775 QMutableListIterator<CSSProperty *> lstValuesIt(*m_lstValues); 0776 CSSProperty *current; 0777 lstValuesIt.toBack(); 0778 while (lstValuesIt.hasPrevious()) { 0779 current = lstValuesIt.previous(); 0780 if (current->m_id == propertyID) { 0781 if (old) { 0782 *old = current->value()->cssText(); 0783 } 0784 delete lstValuesIt.value(); 0785 lstValuesIt.remove(); 0786 changed = true; 0787 break; 0788 } 0789 } 0790 0791 if (changed) { 0792 setChanged(); 0793 } 0794 } 0795 0796 bool CSSStyleDeclarationImpl::removePropertiesInSet(const int *set, unsigned length) 0797 { 0798 bool changed = false; 0799 for (unsigned i = 0; i < length; i++) { 0800 QMutableListIterator<CSSProperty *> lstValuesIt(*m_lstValues); 0801 CSSProperty *current; 0802 lstValuesIt.toBack(); 0803 while (lstValuesIt.hasPrevious()) { 0804 current = lstValuesIt.previous(); 0805 if (current->m_id == set[i]) { 0806 delete lstValuesIt.value(); 0807 lstValuesIt.remove(); 0808 changed = true; 0809 break; 0810 } 0811 } 0812 } 0813 0814 return changed; 0815 } 0816 0817 void CSSStyleDeclarationImpl::setChanged() 0818 { 0819 if (m_node) { 0820 m_node->setChanged(); 0821 return; 0822 } 0823 0824 // ### quick&dirty hack for KDE 3.0... make this MUCH better! (Dirk) 0825 for (StyleBaseImpl *stylesheet = this; stylesheet; stylesheet = stylesheet->parent()) 0826 if (stylesheet->isCSSStyleSheet()) { 0827 static_cast<CSSStyleSheetImpl *>(stylesheet)->doc()->updateStyleSelector(); 0828 break; 0829 } 0830 } 0831 0832 void CSSStyleDeclarationImpl::clear() 0833 { 0834 if (!m_lstValues) { 0835 return; 0836 } 0837 0838 QMutableListIterator<CSSProperty *> it(*m_lstValues); 0839 while (it.hasNext()) { 0840 delete it.next(); 0841 it.remove(); 0842 } 0843 } 0844 0845 bool CSSStyleDeclarationImpl::getPropertyPriority(int propertyID) const 0846 { 0847 if (m_lstValues && !m_lstValues->isEmpty()) { 0848 QListIterator<CSSProperty *> lstValuesIt(*m_lstValues); 0849 CSSProperty *current; 0850 while (lstValuesIt.hasNext()) { 0851 current = lstValuesIt.next(); 0852 if (propertyID == current->m_id) { 0853 return current->m_important; 0854 } 0855 } 0856 } 0857 return false; 0858 } 0859 0860 bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important, int &ec) 0861 { 0862 ec = 0; 0863 0864 // Setting the value to an empty string just removes the property in both IE and Gecko. 0865 // Setting it to null seems to produce less consistent results, but we treat it just the same. 0866 if (value.isEmpty()) { 0867 removeProperty(id); 0868 return true; 0869 } 0870 0871 bool success = setProperty(id, value, important); 0872 #if 0 0873 if (!success) { 0874 // CSS DOM requires raising SYNTAX_ERR here, but this is too dangerous for compatibility, 0875 // see <https://bugs.webkit.org/show_bug.cgi?id=7296>. 0876 } 0877 #endif 0878 return success; 0879 } 0880 0881 bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important) 0882 { 0883 if (!m_lstValues) { 0884 m_lstValues = new QList<CSSProperty *>; 0885 } 0886 0887 CSSParser parser(strictParsing); 0888 bool success = parser.parseValue(this, id, value, important); 0889 if (!success) { 0890 // qCDebug(KHTML_LOG) << "CSSStyleDeclarationImpl::setProperty invalid property: [" << getPropertyName(id).string() 0891 //<< "] value: [" << value.string() << "]"; 0892 } else { 0893 setChanged(); 0894 } 0895 return success; 0896 } 0897 0898 void CSSStyleDeclarationImpl::setProperty(int id, int value, bool important) 0899 { 0900 if (!m_lstValues) { 0901 m_lstValues = new QList<CSSProperty *>; 0902 } 0903 removeProperty(id); 0904 0905 CSSValueImpl *cssValue = new CSSPrimitiveValueImpl(value); 0906 setParsedValue(id, cssValue, important, m_lstValues); 0907 setChanged(); 0908 } 0909 0910 void CSSStyleDeclarationImpl::setLengthProperty(int id, const DOM::DOMString &value, bool important, bool _multiLength) 0911 { 0912 bool parseMode = strictParsing; 0913 strictParsing = false; 0914 multiLength = _multiLength; 0915 setProperty(id, value, important); 0916 strictParsing = parseMode; 0917 multiLength = false; 0918 } 0919 0920 void CSSStyleDeclarationImpl::setProperty(const DOMString &propertyString) 0921 { 0922 if (!m_lstValues) { 0923 m_lstValues = new QList<CSSProperty *>; 0924 } 0925 0926 CSSParser parser(strictParsing); 0927 parser.parseDeclaration(this, propertyString); 0928 setChanged(); 0929 } 0930 0931 unsigned long CSSStyleDeclarationImpl::length() const 0932 { 0933 return m_lstValues ? m_lstValues->count() : 0; 0934 } 0935 0936 DOMString CSSStyleDeclarationImpl::item(unsigned long index) const 0937 { 0938 if (m_lstValues && index < (unsigned)m_lstValues->count() && m_lstValues->at(index)) { 0939 return getPropertyName(m_lstValues->at(index)->m_id); 0940 } 0941 return DOMString(); 0942 } 0943 0944 CSSRuleImpl *CSSStyleDeclarationImpl::parentRule() const 0945 { 0946 return (m_parent && m_parent->isRule()) ? 0947 static_cast<CSSRuleImpl *>(m_parent) : nullptr; 0948 } 0949 0950 DOM::DOMString CSSStyleDeclarationImpl::cssText() const 0951 { 0952 if (!m_lstValues || m_lstValues->isEmpty()) { 0953 return DOMString(); 0954 } 0955 0956 DOMString result; 0957 0958 const CSSProperty *positionXProp = nullptr; 0959 const CSSProperty *positionYProp = nullptr; 0960 0961 QListIterator<CSSProperty *> lstValuesIt(*m_lstValues); 0962 while (lstValuesIt.hasNext()) { 0963 const CSSProperty *cur = lstValuesIt.next(); 0964 if (cur->id() == CSS_PROP_BACKGROUND_POSITION_X) { 0965 positionXProp = cur; 0966 } else if (cur->id() == CSS_PROP_BACKGROUND_POSITION_Y) { 0967 positionYProp = cur; 0968 } else { 0969 result += cur->cssText(); 0970 } 0971 } 0972 0973 // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output. 0974 // It is required because background-position-x/y are non-standard properties and generated output 0975 // would not work in Firefox 0976 // It would be a better solution if background-position was CSS_PAIR. 0977 if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) { 0978 DOMString positionValue; 0979 const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y }; 0980 if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList()) { 0981 positionValue = getLayeredShortHandValue(properties, 2); 0982 } else { 0983 positionValue = positionXProp->value()->cssText() + DOMString(" ") + positionYProp->value()->cssText(); 0984 } 0985 result += DOMString("background-position: ") + positionValue 0986 + DOMString((positionXProp->isImportant() ? " !important" : "")) 0987 + DOMString("; "); 0988 } else { 0989 if (positionXProp) { 0990 result += positionXProp->cssText(); 0991 } 0992 if (positionYProp) { 0993 result += positionYProp->cssText(); 0994 } 0995 } 0996 return result; 0997 } 0998 0999 void CSSStyleDeclarationImpl::setCssText(const DOM::DOMString &text) 1000 { 1001 if (m_lstValues) { 1002 qDeleteAll(*m_lstValues); 1003 m_lstValues->clear(); 1004 } else { 1005 m_lstValues = new QList<CSSProperty *>; 1006 } 1007 1008 CSSParser parser(strictParsing); 1009 parser.parseDeclaration(this, text); 1010 setChanged(); 1011 } 1012 1013 bool CSSStyleDeclarationImpl::parseString(const DOMString &/*string*/, bool) 1014 { 1015 // qCDebug(KHTML_LOG) << "WARNING: CSSStyleDeclarationImpl::parseString, unimplemented, was called"; 1016 return false; 1017 // ### 1018 } 1019 1020 // -------------------------------------------------------------------------------------- 1021 1022 void CSSInlineStyleDeclarationImpl::setChanged() 1023 { 1024 if (m_node) { 1025 m_node->setNeedsStyleAttributeUpdate(); 1026 } 1027 CSSStyleDeclarationImpl::setChanged(); 1028 } 1029 1030 void CSSInlineStyleDeclarationImpl::updateFromAttribute(const DOMString &value) 1031 { 1032 if (!m_lstValues) { 1033 m_lstValues = new QList<CSSProperty *>; 1034 } else { 1035 clear(); 1036 } 1037 CSSParser parser(strictParsing); 1038 parser.parseDeclaration(this, value); 1039 CSSStyleDeclarationImpl::setChanged(); 1040 } 1041 1042 // -------------------------------------------------------------------------------------- 1043 1044 unsigned short CSSInheritedValueImpl::cssValueType() const 1045 { 1046 return CSSValue::CSS_INHERIT; 1047 } 1048 1049 DOM::DOMString CSSInheritedValueImpl::cssText() const 1050 { 1051 return DOMString("inherit"); 1052 } 1053 1054 unsigned short CSSInitialValueImpl::cssValueType() const 1055 { 1056 return CSSValue::CSS_INITIAL; 1057 } 1058 1059 DOM::DOMString CSSInitialValueImpl::cssText() const 1060 { 1061 return DOMString("initial"); 1062 } 1063 1064 // ---------------------------------------------------------------------------------------- 1065 1066 CSSValueListImpl::~CSSValueListImpl() 1067 { 1068 for (QListIterator<CSSValueImpl *> iterator(m_values); iterator.hasNext();) { 1069 iterator.next()->deref(); 1070 } 1071 } 1072 1073 unsigned short CSSValueListImpl::cssValueType() const 1074 { 1075 return CSSValue::CSS_VALUE_LIST; 1076 } 1077 1078 void CSSValueListImpl::append(CSSValueImpl *val) 1079 { 1080 m_values.append(val); 1081 val->ref(); 1082 } 1083 1084 DOM::DOMString CSSValueListImpl::cssText() const 1085 { 1086 DOMString separatorString; 1087 if (m_separator == Comma) { 1088 separatorString = DOMString(", "); 1089 } else { // Space 1090 separatorString = DOMString(" "); 1091 } 1092 1093 DOMString result = ""; 1094 1095 for (QListIterator<CSSValueImpl *> iterator(m_values); iterator.hasNext();) { 1096 if (!result.isEmpty()) { 1097 result += separatorString; 1098 } 1099 result += iterator.next()->cssText(); 1100 } 1101 1102 return result; 1103 } 1104 1105 // ------------------------------------------------------------------------------------- 1106 1107 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl() 1108 : CSSValueImpl() 1109 { 1110 m_type = 0; 1111 } 1112 1113 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(int ident) 1114 : CSSValueImpl() 1115 { 1116 m_value.ident = ident; 1117 m_type = CSSPrimitiveValue::CSS_IDENT; 1118 } 1119 1120 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(double num, CSSPrimitiveValue::UnitTypes type) 1121 { 1122 m_value.num = num; 1123 m_type = type; 1124 } 1125 1126 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(const DOMString &str, CSSPrimitiveValue::UnitTypes type) 1127 { 1128 m_value.string = str.implementation(); 1129 if (m_value.string) { 1130 m_value.string->ref(); 1131 } 1132 m_type = type; 1133 } 1134 1135 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(CounterImpl *c) 1136 { 1137 m_value.counter = c; 1138 if (m_value.counter) { 1139 m_value.counter->ref(); 1140 } 1141 m_type = CSSPrimitiveValue::CSS_COUNTER; 1142 } 1143 1144 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(RectImpl *r) 1145 { 1146 m_value.rect = r; 1147 if (m_value.rect) { 1148 m_value.rect->ref(); 1149 } 1150 m_type = CSSPrimitiveValue::CSS_RECT; 1151 } 1152 1153 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(QRgb color) 1154 { 1155 m_value.rgbcolor = color; 1156 m_type = CSSPrimitiveValue::CSS_RGBCOLOR; 1157 } 1158 1159 CSSPrimitiveValueImpl::CSSPrimitiveValueImpl(PairImpl *p) 1160 { 1161 m_value.pair = p; 1162 if (m_value.pair) { 1163 m_value.pair->ref(); 1164 } 1165 m_type = CSSPrimitiveValue::CSS_PAIR; 1166 } 1167 1168 CSSPrimitiveValueImpl::~CSSPrimitiveValueImpl() 1169 { 1170 cleanup(); 1171 } 1172 1173 void CSSPrimitiveValueImpl::cleanup() 1174 { 1175 switch (m_type) { 1176 case CSSPrimitiveValue::CSS_STRING: 1177 case CSSPrimitiveValue::CSS_URI: 1178 case CSSPrimitiveValue::CSS_ATTR: 1179 if (m_value.string) { 1180 m_value.string->deref(); 1181 } 1182 break; 1183 case CSSPrimitiveValue::CSS_COUNTER: 1184 m_value.counter->deref(); 1185 break; 1186 case CSSPrimitiveValue::CSS_RECT: 1187 m_value.rect->deref(); 1188 break; 1189 case CSSPrimitiveValue::CSS_PAIR: 1190 m_value.pair->deref(); 1191 break; 1192 default: 1193 break; 1194 } 1195 1196 m_type = 0; 1197 } 1198 1199 int CSSPrimitiveValueImpl::computeLength(khtml::RenderStyle *style, khtml::RenderStyle *rootStyle, int logicalDpiY) 1200 { 1201 return snapValue(computeLengthFloat(style, rootStyle, logicalDpiY)); 1202 } 1203 1204 double CSSPrimitiveValueImpl::computeLengthFloat(khtml::RenderStyle *style, khtml::RenderStyle *rootStyle, int logicalDpiY) 1205 { 1206 unsigned short type = primitiveType(); 1207 1208 double dpiY = 72.; // fallback 1209 if (logicalDpiY) { 1210 dpiY = logicalDpiY; 1211 } 1212 if (!khtml::printpainter && dpiY < 96) { 1213 dpiY = 96.; 1214 } 1215 1216 double factor = 1.; 1217 switch (type) { 1218 case CSSPrimitiveValue::CSS_EMS: 1219 factor = style->font().pixelSize(); 1220 break; 1221 case CSSPrimitiveValue::CSS_EXS: 1222 factor = style->htmlFont().xHeight(); 1223 break; 1224 case CSSPrimitiveValue::CSS_CHS: { 1225 const int zw = style->htmlFont().zeroCharWidth(); 1226 if (zw != -1) { 1227 factor = zw; 1228 } else { 1229 // assume 0.5em 1230 return ((double)0.5 * style->font().pixelSize()); 1231 } 1232 break; 1233 } 1234 case CSSPrimitiveValue::CSS_REMS: 1235 factor = rootStyle->font().pixelSize(); 1236 break; 1237 case CSSPrimitiveValue::CSS_PX: 1238 break; 1239 case CSSPrimitiveValue::CSS_CM: 1240 factor = dpiY / 2.54; //72dpi/(2.54 cm/in) 1241 break; 1242 case CSSPrimitiveValue::CSS_MM: 1243 factor = dpiY / 25.4; 1244 break; 1245 case CSSPrimitiveValue::CSS_IN: 1246 factor = dpiY; 1247 break; 1248 case CSSPrimitiveValue::CSS_PT: 1249 factor = dpiY / 72.; 1250 break; 1251 case CSSPrimitiveValue::CSS_PC: 1252 // 1 pc == 12 pt 1253 factor = dpiY * 12. / 72.; 1254 break; 1255 default: 1256 return -1; 1257 } 1258 1259 return floatValue(type) * factor; 1260 } 1261 1262 int CSSPrimitiveValueImpl::getDPIResolution() const 1263 { 1264 unsigned short type = primitiveType(); 1265 double factor = 1.; 1266 switch (type) { 1267 case CSSPrimitiveValue::CSS_DPI: 1268 break; 1269 case CSSPrimitiveValue::CSS_DPCM: 1270 factor = 2.54; 1271 break; 1272 default: 1273 return -1; 1274 } 1275 1276 return (int)(0.01 + floatValue(type) * factor); 1277 } 1278 1279 void CSSPrimitiveValueImpl::setFloatValue(unsigned short unitType, double floatValue, int &exceptioncode) 1280 { 1281 exceptioncode = 0; 1282 cleanup(); 1283 // ### check if property supports this type 1284 if (m_type > CSSPrimitiveValue::CSS_DIMENSION) { 1285 exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET; 1286 return; 1287 } 1288 //if(m_type > CSSPrimitiveValue::CSS_DIMENSION) throw DOMException(DOMException::INVALID_ACCESS_ERR); 1289 m_value.num = floatValue; 1290 m_type = unitType; 1291 } 1292 1293 void CSSPrimitiveValueImpl::setStringValue(unsigned short stringType, const DOMString &stringValue, int &exceptioncode) 1294 { 1295 exceptioncode = 0; 1296 cleanup(); 1297 //if(m_type < CSSPrimitiveValue::CSS_STRING) throw DOMException(DOMException::INVALID_ACCESS_ERR); 1298 //if(m_type > CSSPrimitiveValue::CSS_ATTR) throw DOMException(DOMException::INVALID_ACCESS_ERR); 1299 if (m_type < CSSPrimitiveValue::CSS_STRING || m_type > CSSPrimitiveValue::CSS_ATTR) { 1300 exceptioncode = CSSException::SYNTAX_ERR + CSSException::_EXCEPTION_OFFSET; 1301 return; 1302 } 1303 if (stringType != CSSPrimitiveValue::CSS_IDENT) { 1304 m_value.string = stringValue.implementation(); 1305 m_value.string->ref(); 1306 m_type = stringType; 1307 } 1308 // ### parse ident 1309 } 1310 1311 unsigned short CSSPrimitiveValueImpl::cssValueType() const 1312 { 1313 return CSSValue::CSS_PRIMITIVE_VALUE; 1314 } 1315 1316 bool CSSPrimitiveValueImpl::parseString(const DOMString &/*string*/, bool) 1317 { 1318 // ### 1319 // qCDebug(KHTML_LOG) << "WARNING: CSSPrimitiveValueImpl::parseString, unimplemented, was called"; 1320 return false; 1321 } 1322 1323 int CSSPrimitiveValueImpl::getIdent() 1324 { 1325 if (m_type != CSSPrimitiveValue::CSS_IDENT) { 1326 return 0; 1327 } 1328 return m_value.ident; 1329 } 1330 1331 DOM::DOMString CSSPrimitiveValueImpl::cssText() const 1332 { 1333 // ### return the original value instead of a generated one (e.g. color 1334 // name if it was specified) - check what spec says about this 1335 DOMString text; 1336 switch (m_type) { 1337 case CSSPrimitiveValue::CSS_UNKNOWN: 1338 // ### 1339 break; 1340 case CSSPrimitiveValue::CSS_NUMBER: 1341 // We want to output integral values w/o a period, but others as-is 1342 if (m_value.num == (int)m_value.num) { 1343 text = DOMString(QString::number((int)m_value.num)); 1344 } else { 1345 text = DOMString(QString::number(m_value.num)); 1346 } 1347 break; 1348 case CSSPrimitiveValue::CSS_PERCENTAGE: 1349 text = DOMString(QString::number(m_value.num) + "%"); 1350 break; 1351 case CSSPrimitiveValue::CSS_EMS: 1352 text = DOMString(QString::number(m_value.num) + "em"); 1353 break; 1354 case CSSPrimitiveValue::CSS_EXS: 1355 text = DOMString(QString::number(m_value.num) + "ex"); 1356 break; 1357 case CSSPrimitiveValue::CSS_CHS: 1358 text = DOMString(QString::number( m_value.num ) + "ch"); 1359 break; 1360 case CSSPrimitiveValue::CSS_REMS: 1361 text = DOMString(QString::number( m_value.num ) + "rem"); 1362 break; 1363 case CSSPrimitiveValue::CSS_PX: 1364 text = DOMString(QString::number(m_value.num) + "px"); 1365 break; 1366 case CSSPrimitiveValue::CSS_CM: 1367 text = DOMString(QString::number(m_value.num) + "cm"); 1368 break; 1369 case CSSPrimitiveValue::CSS_MM: 1370 text = DOMString(QString::number(m_value.num) + "mm"); 1371 break; 1372 case CSSPrimitiveValue::CSS_IN: 1373 text = DOMString(QString::number(m_value.num) + "in"); 1374 break; 1375 case CSSPrimitiveValue::CSS_PT: 1376 text = DOMString(QString::number(m_value.num) + "pt"); 1377 break; 1378 case CSSPrimitiveValue::CSS_PC: 1379 text = DOMString(QString::number(m_value.num) + "pc"); 1380 break; 1381 case CSSPrimitiveValue::CSS_DEG: 1382 text = DOMString(QString::number(m_value.num) + "deg"); 1383 break; 1384 case CSSPrimitiveValue::CSS_RAD: 1385 text = DOMString(QString::number(m_value.num) + "rad"); 1386 break; 1387 case CSSPrimitiveValue::CSS_GRAD: 1388 text = DOMString(QString::number(m_value.num) + "grad"); 1389 break; 1390 case CSSPrimitiveValue::CSS_MS: 1391 text = DOMString(QString::number(m_value.num) + "ms"); 1392 break; 1393 case CSSPrimitiveValue::CSS_S: 1394 text = DOMString(QString::number(m_value.num) + "s"); 1395 break; 1396 case CSSPrimitiveValue::CSS_HZ: 1397 text = DOMString(QString::number(m_value.num) + "hz"); 1398 break; 1399 case CSSPrimitiveValue::CSS_KHZ: 1400 text = DOMString(QString::number(m_value.num) + "khz"); 1401 break; 1402 case CSSPrimitiveValue::CSS_DIMENSION: 1403 // ### 1404 break; 1405 case CSSPrimitiveValue::CSS_STRING: 1406 text = quoteStringIfNeeded(m_value.string); 1407 break; 1408 case CSSPrimitiveValue::CSS_URI: 1409 text = "url("; 1410 text += DOMString(m_value.string); 1411 text += ")"; 1412 break; 1413 case CSSPrimitiveValue::CSS_IDENT: 1414 text = getValueName(m_value.ident); 1415 break; 1416 case CSSPrimitiveValue::CSS_ATTR: 1417 text = "attr("; 1418 text += DOMString(m_value.string); 1419 text += ")"; 1420 break; 1421 case CSSPrimitiveValue::CSS_COUNTER: 1422 text = "counter("; 1423 text += m_value.counter->m_identifier; 1424 text += ")"; 1425 // ### add list-style and separator 1426 break; 1427 case CSSPrimitiveValue::CSS_RECT: { 1428 RectImpl *rectVal = getRectValue(); 1429 text = "rect("; 1430 text += rectVal->top()->cssText() + DOMString(" "); 1431 text += rectVal->right()->cssText() + DOMString(" "); 1432 text += rectVal->bottom()->cssText() + DOMString(" "); 1433 text += rectVal->left()->cssText() + DOMString(")"); 1434 break; 1435 } 1436 case CSSPrimitiveValue::CSS_RGBCOLOR: 1437 if (qAlpha(m_value.rgbcolor) != 0xFF) { 1438 if (m_value.rgbcolor == khtml::transparentColor) { 1439 text = "transparent"; 1440 } else 1441 text = QString("rgba(" + QString::number(qRed(m_value.rgbcolor)) + ", " 1442 + QString::number(qGreen(m_value.rgbcolor)) + ", " 1443 + QString::number(qBlue(m_value.rgbcolor)) + ", " 1444 + QString::number(qAlpha(m_value.rgbcolor) / 255.0) + ")"); 1445 } else { 1446 text = QString("rgb(" + QString::number(qRed(m_value.rgbcolor)) + ", " 1447 + QString::number(qGreen(m_value.rgbcolor)) + ", " 1448 + QString::number(qBlue(m_value.rgbcolor)) + ")"); 1449 } 1450 break; 1451 case CSSPrimitiveValue::CSS_PAIR: 1452 text = m_value.pair->first()->cssText(); 1453 text += " "; 1454 text += m_value.pair->second()->cssText(); 1455 break; 1456 default: 1457 break; 1458 } 1459 return text; 1460 } 1461 1462 // ----------------------------------------------------------------- 1463 1464 RectImpl::RectImpl() 1465 { 1466 m_top = nullptr; 1467 m_right = nullptr; 1468 m_bottom = nullptr; 1469 m_left = nullptr; 1470 } 1471 1472 RectImpl::~RectImpl() 1473 { 1474 if (m_top) { 1475 m_top->deref(); 1476 } 1477 if (m_right) { 1478 m_right->deref(); 1479 } 1480 if (m_bottom) { 1481 m_bottom->deref(); 1482 } 1483 if (m_left) { 1484 m_left->deref(); 1485 } 1486 } 1487 1488 void RectImpl::setTop(CSSPrimitiveValueImpl *top) 1489 { 1490 if (top) { 1491 top->ref(); 1492 } 1493 if (m_top) { 1494 m_top->deref(); 1495 } 1496 m_top = top; 1497 } 1498 1499 void RectImpl::setRight(CSSPrimitiveValueImpl *right) 1500 { 1501 if (right) { 1502 right->ref(); 1503 } 1504 if (m_right) { 1505 m_right->deref(); 1506 } 1507 m_right = right; 1508 } 1509 1510 void RectImpl::setBottom(CSSPrimitiveValueImpl *bottom) 1511 { 1512 if (bottom) { 1513 bottom->ref(); 1514 } 1515 if (m_bottom) { 1516 m_bottom->deref(); 1517 } 1518 m_bottom = bottom; 1519 } 1520 1521 void RectImpl::setLeft(CSSPrimitiveValueImpl *left) 1522 { 1523 if (left) { 1524 left->ref(); 1525 } 1526 if (m_left) { 1527 m_left->deref(); 1528 } 1529 m_left = left; 1530 } 1531 1532 // ----------------------------------------------------------------- 1533 1534 PairImpl::~PairImpl() 1535 { 1536 if (m_first) { 1537 m_first->deref(); 1538 } if (m_second) { 1539 m_second->deref(); 1540 } 1541 } 1542 1543 void PairImpl::setFirst(CSSPrimitiveValueImpl *first) 1544 { 1545 if (first == m_first) { 1546 return; 1547 } 1548 if (m_first) { 1549 m_first->deref(); 1550 } 1551 m_first = first; 1552 if (m_first) { 1553 m_first->ref(); 1554 } 1555 } 1556 1557 void PairImpl::setSecond(CSSPrimitiveValueImpl *second) 1558 { 1559 if (second == m_second) { 1560 return; 1561 } 1562 if (m_second) { 1563 m_second->deref(); 1564 } 1565 m_second = second; 1566 if (m_second) { 1567 m_second->ref(); 1568 } 1569 } 1570 1571 // ----------------------------------------------------------------- 1572 1573 CSSImageValueImpl::CSSImageValueImpl(const DOMString &url, StyleBaseImpl *style) 1574 : CSSPrimitiveValueImpl(url, CSSPrimitiveValue::CSS_URI) 1575 { 1576 m_image = nullptr; 1577 const DOMString imgUrl = url.trimSpaces(); 1578 if (!imgUrl.isEmpty()) { 1579 m_fullImageUrl = style->baseURL().resolved(QUrl(imgUrl.string())).toString(); 1580 } else { 1581 m_fullImageUrl.clear(); 1582 } 1583 } 1584 1585 CSSImageValueImpl::CSSImageValueImpl() 1586 : CSSPrimitiveValueImpl(CSS_VAL_NONE) 1587 { 1588 m_image = nullptr; 1589 m_fullImageUrl.clear(); 1590 } 1591 1592 CSSImageValueImpl::~CSSImageValueImpl() 1593 { 1594 if (m_image) { 1595 m_image->deref(this); 1596 } 1597 } 1598 1599 khtml::CachedImage *CSSImageValueImpl::requestCssImage(DocumentImpl *doc) 1600 { 1601 if (!m_image && !m_fullImageUrl.isEmpty()) { 1602 m_image = doc->docLoader()->requestImage(m_fullImageUrl); 1603 if (m_image) { 1604 m_image->ref(this); 1605 } 1606 } 1607 return m_image; 1608 } 1609 1610 // ------------------------------------------------------------------------ 1611 1612 FontFamilyValueImpl::FontFamilyValueImpl(const QString &string) 1613 : CSSPrimitiveValueImpl(DOMString(string), CSSPrimitiveValue::CSS_STRING) 1614 { 1615 static const QRegExp parenReg(" \\(.*\\)$"); 1616 // static const QRegExp braceReg(" \\[.*\\]$"); 1617 1618 parsedFontName = string; 1619 1620 // a language tag is often added in braces at the end. Remove it. 1621 parsedFontName.replace(parenReg, QString()); 1622 1623 #if 0 1624 // cannot use such early checks against the font database anymore, 1625 // as the font subsystem might not contain the requested font yet 1626 // (case of downloadable font faces) 1627 1628 // remove [Xft] qualifiers 1629 parsedFontName.replace(braceReg, QString()); 1630 1631 const QString &available = KHTMLSettings::availableFamilies(); 1632 1633 parsedFontName = parsedFontName.toLower(); 1634 // qCDebug(KHTML_LOG) << "searching for face '" << parsedFontName << "'"; 1635 1636 int pos = available.indexOf(',' + parsedFontName + ',', 0, Qt::CaseInsensitive); 1637 if (pos == -1) { 1638 // many pages add extra MSs to make sure it's windows only ;( 1639 if (parsedFontName.startsWith("ms ")) { 1640 parsedFontName = parsedFontName.mid(3); 1641 } 1642 if (parsedFontName.endsWith(" ms")) { 1643 parsedFontName.truncate(parsedFontName.length() - 3); 1644 } 1645 pos = available.indexOf(",ms " + parsedFontName + ',', 0, Qt::CaseInsensitive); 1646 if (pos == -1) { 1647 pos = available.indexOf(',' + parsedFontName + " ms,", 0, Qt::CaseInsensitive); 1648 } 1649 } 1650 1651 if (pos != -1) { 1652 ++pos; 1653 int p = available.indexOf(',', pos); 1654 assert(p != -1); // available is supposed to start and end with , 1655 parsedFontName = available.mid(pos, p - pos); 1656 // qCDebug(KHTML_LOG) << "going for '" << parsedFontName << "'"; 1657 } 1658 1659 #endif // !APPLE_CHANGES 1660 } 1661 1662 FontValueImpl::FontValueImpl() 1663 : style(nullptr), variant(nullptr), weight(nullptr), size(nullptr), lineHeight(nullptr), family(nullptr) 1664 { 1665 } 1666 1667 FontValueImpl::~FontValueImpl() 1668 { 1669 delete style; 1670 delete variant; 1671 delete weight; 1672 delete size; 1673 delete lineHeight; 1674 delete family; 1675 } 1676 1677 DOMString FontValueImpl::cssText() const 1678 { 1679 // font variant weight size / line-height family 1680 1681 DOMString result(""); 1682 1683 if (style) { 1684 result += style->cssText(); 1685 } 1686 if (variant) { 1687 if (result.length() > 0) { 1688 result += " "; 1689 } 1690 result += variant->cssText(); 1691 } 1692 if (weight) { 1693 if (result.length() > 0) { 1694 result += " "; 1695 } 1696 result += weight->cssText(); 1697 } 1698 if (size) { 1699 if (result.length() > 0) { 1700 result += " "; 1701 } 1702 result += size->cssText(); 1703 } 1704 if (lineHeight) { 1705 if (!size) { 1706 result += " "; 1707 } 1708 result += "/"; 1709 result += lineHeight->cssText(); 1710 } 1711 if (family) { 1712 if (result.length() > 0) { 1713 result += " "; 1714 } 1715 result += family->cssText(); 1716 } 1717 1718 return result; 1719 } 1720 1721 QuotesValueImpl::QuotesValueImpl() 1722 : levels(0) 1723 { 1724 } 1725 1726 DOMString QuotesValueImpl::cssText() const 1727 { 1728 return QString("\"" + data.join("\" \"") + "\""); 1729 } 1730 1731 void QuotesValueImpl::addLevel(const QString &open, const QString &close) 1732 { 1733 data.append(open); 1734 data.append(close); 1735 levels++; 1736 } 1737 1738 QString QuotesValueImpl::openQuote(int level) const 1739 { 1740 if (levels == 0) { 1741 return ""; 1742 } 1743 level--; // increments are calculated before openQuote is called 1744 // qCDebug(KHTML_LOG) << "Open quote level:" << level; 1745 if (level < 0) { 1746 level = 0; 1747 } else if (level >= (int) levels) { 1748 level = (int)(levels - 1); 1749 } 1750 return data[level * 2]; 1751 } 1752 1753 QString QuotesValueImpl::closeQuote(int level) const 1754 { 1755 if (levels == 0) { 1756 return ""; 1757 } 1758 // qCDebug(KHTML_LOG) << "Close quote level:" << level; 1759 if (level < 0) { 1760 level = 0; 1761 } else if (level >= (int) levels) { 1762 level = (int)(levels - 1); 1763 } 1764 return data[level * 2 + 1]; 1765 } 1766 1767 // Used for text-shadow and box-shadow 1768 ShadowValueImpl::ShadowValueImpl(CSSPrimitiveValueImpl *_x, CSSPrimitiveValueImpl *_y, 1769 CSSPrimitiveValueImpl *_blur, CSSPrimitiveValueImpl *_color) 1770 : x(_x), y(_y), blur(_blur), color(_color) 1771 {} 1772 1773 ShadowValueImpl::~ShadowValueImpl() 1774 { 1775 delete x; 1776 delete y; 1777 delete blur; 1778 delete color; 1779 } 1780 1781 DOMString ShadowValueImpl::cssText() const 1782 { 1783 DOMString text(""); 1784 if (color) { 1785 text += color->cssText(); 1786 } 1787 if (x) { 1788 if (text.length() > 0) { 1789 text += " "; 1790 } 1791 text += x->cssText(); 1792 } 1793 if (y) { 1794 if (text.length() > 0) { 1795 text += " "; 1796 } 1797 text += y->cssText(); 1798 } 1799 if (blur) { 1800 if (text.length() > 0) { 1801 text += " "; 1802 } 1803 text += blur->cssText(); 1804 } 1805 1806 return text; 1807 } 1808 1809 DOMString CounterActImpl::cssText() const 1810 { 1811 DOMString text(m_counter); 1812 text += DOMString(QString::number(m_value)); 1813 1814 return text; 1815 } 1816 1817 DOMString CSSProperty::cssText() const 1818 { 1819 return getPropertyName(m_id) + DOMString(": ") + m_value->cssText() + (m_important ? DOMString(" !important") : DOMString()) + DOMString("; "); 1820 } 1821 1822 // ------------------------------------------------------------------------- 1823 1824 #if 0 1825 // ENABLE(SVG_FONTS) 1826 bool CSSFontFaceSrcValueImpl::isSVGFontFaceSrc() const 1827 { 1828 return !strcasecmp(m_format, "svg"); 1829 } 1830 #endif 1831 1832 bool CSSFontFaceSrcValueImpl::isSupportedFormat() const 1833 { 1834 // Normally we would just check the format, but in order to avoid conflicts with the old WinIE style of font-face, 1835 // we will also check to see if the URL ends with .eot. If so, we'll go ahead and assume that we shouldn't load it. 1836 if (m_format.isEmpty()) { 1837 // Check for .eot. 1838 if (m_resource.endsWith(".eot") || m_resource.endsWith(".EOT")) { 1839 return false; 1840 } 1841 return true; 1842 } 1843 1844 return !strcasecmp(m_format, "truetype") || !strcasecmp(m_format, "opentype") || !strcasecmp(m_format, "woff") 1845 #if 0 1846 //ENABLE(SVG_FONTS) 1847 || isSVGFontFaceSrc() 1848 #endif 1849 ; 1850 } 1851 1852 DOMString CSSFontFaceSrcValueImpl::cssText() const 1853 { 1854 DOMString result; 1855 if (isLocal()) { 1856 result += "local("; 1857 } else { 1858 result += "url("; 1859 } 1860 result += m_resource; 1861 result += ")"; 1862 if (!m_format.isEmpty()) { 1863 result += " format("; 1864 result += m_format; 1865 result += ")"; 1866 } 1867 return result; 1868 } 1869