KHtml

css_valueimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999-2003 Lars Knoll ([email protected])
5  * (C) 2004-2008 Apple Computer, Inc.
6  * (C) 2005 Allan Sandfeld Jensen ([email protected])
7  * (C) 2009 Germain Garand ([email protected])
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB. If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 #include "css_valueimpl.h"
26 #include "css_ruleimpl.h"
27 #include "css_stylesheetimpl.h"
28 #include "css/csshelper.h"
29 #include "cssparser.h"
30 #include "cssproperties.h"
31 #include "cssvalues.h"
32 
33 #include <dom/css_value.h>
34 #include <dom/dom_exception.h>
35 #include <dom/dom_string.h>
36 
37 #include <xml/dom_stringimpl.h>
38 #include <xml/dom_docimpl.h>
39 
40 #include <rendering/font.h>
41 #include <rendering/render_style.h>
42 
43 #include <wtf/ASCIICType.h>
44 
45 #include "khtml_debug.h"
46 #include <QRegExp>
47 #include <QPaintDevice>
48 
49 // Hack for debugging purposes
50 extern DOM::DOMString getPropertyName(unsigned short id);
51 
52 using khtml::FontDef;
53 
54 using namespace DOM;
55 using namespace WTF;
56 
57 static int propertyID(const DOMString &s)
58 {
59  char buffer[maxCSSPropertyNameLength];
60 
61  unsigned len = s.length();
62  if (len > maxCSSPropertyNameLength) {
63  return 0;
64  }
65 
66  for (unsigned i = 0; i != len; ++i) {
67  unsigned short c = s[i].unicode();
68  if (c == 0 || c >= 0x7F) {
69  return 0; // illegal character
70  }
71  buffer[i] = s[i].toLower().unicode();
72  }
73 
74  return getPropertyID(buffer, len);
75 }
76 
77 // "ident" from the CSS tokenizer, minus backslash-escape sequences
78 static bool isCSSTokenizerIdentifier(const DOMString &string)
79 {
80  const QChar *p = string.unicode();
81  const QChar *end = p + string.length();
82 
83  // -?
84  if (p != end && p[0] == '-') {
85  ++p;
86  }
87 
88  // {nmstart}
89  if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p->unicode()))) {
90  return false;
91  }
92  ++p;
93 
94  // {nmchar}*
95  for (; p != end; ++p) {
96  if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p->unicode()))) {
97  return false;
98  }
99  }
100 
101  return true;
102 }
103 
104 static DOMString quoteString(const DOMString &string)
105 {
106  // FIXME: Also need to transform control characters into \ sequences.
107  QString s = string.string();
108  s.replace('\\', "\\\\");
109  s.replace('\'', "\\'");
110  return QString('\'' + s + '\'');
111 }
112 
113 // Quotes the string if it needs quoting.
114 static DOMString quoteStringIfNeeded(const DOMString &string)
115 {
116  return isCSSTokenizerIdentifier(string) ? string : quoteString(string);
117 }
118 
119 static inline bool isInitialOrInherit(const CSSValueImpl *value)
120 {
121  const unsigned short t = value->cssValueType();
122  return (t == CSSValue::CSS_INHERIT || t == CSSValue::CSS_INITIAL);
123 }
124 
125 CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent)
126  : StyleBaseImpl(parent)
127 {
128  m_lstValues = nullptr;
129  m_node = nullptr;
130 }
131 
132 CSSStyleDeclarationImpl::CSSStyleDeclarationImpl(CSSRuleImpl *parent, QList<CSSProperty *> *lstValues)
133  : StyleBaseImpl(parent)
134 {
135  m_lstValues = lstValues;
136  m_node = nullptr;
137 }
138 
139 CSSStyleDeclarationImpl &CSSStyleDeclarationImpl::operator= (const CSSStyleDeclarationImpl &o)
140 {
141  if (this == &o) {
142  return *this;
143  }
144 
145  // don't attach it to the same node, just leave the current m_node value
146  if (m_lstValues) {
147  qDeleteAll(*m_lstValues);
148  }
149  delete m_lstValues;
150  m_lstValues = nullptr;
151  if (o.m_lstValues) {
152  m_lstValues = new QList<CSSProperty *>;
153  QListIterator<CSSProperty *> lstValuesIt(*o.m_lstValues);
154  while (lstValuesIt.hasNext()) {
155  m_lstValues->append(new CSSProperty(*lstValuesIt.next()));
156  }
157  }
158 
159  return *this;
160 }
161 
162 CSSStyleDeclarationImpl::~CSSStyleDeclarationImpl()
163 {
164  if (m_lstValues) {
165  qDeleteAll(*m_lstValues);
166  }
167  delete m_lstValues;
168  // we don't use refcounting for m_node, to avoid cyclic references (see ElementImpl)
169 }
170 
171 CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue(const DOMString &propertyName) const
172 {
173  int propID = propertyID(propertyName);
174  if (!propID) {
175  return nullptr;
176  }
177  return getPropertyCSSValue(propID);
178 }
179 
180 DOMString CSSStyleDeclarationImpl::getPropertyValue(const DOMString &propertyName) const
181 {
182  int propID = propertyID(propertyName);
183  if (!propID) {
184  return DOMString();
185  }
186  return getPropertyValue(propID);
187 }
188 
189 DOMString CSSStyleDeclarationImpl::getPropertyPriority(const DOMString &propertyName) const
190 {
191  int propID = propertyID(propertyName);
192  if (!propID) {
193  return DOMString();
194  }
195  return getPropertyPriority(propID) ? "important" : "";
196 }
197 
198 void CSSStyleDeclarationImpl::setProperty(const DOMString &propertyName, const DOMString &value, const DOMString &priority)
199 {
200  int propID = propertyID(propertyName);
201  if (!propID) { // set exception?
202  return;
203  }
204  bool important = priority.string().indexOf("important", 0, Qt::CaseInsensitive) != -1;
205  setProperty(propID, value, important);
206 }
207 
208 DOMString CSSStyleDeclarationImpl::removeProperty(const DOMString &propertyName)
209 {
210  int propID = propertyID(propertyName);
211  if (!propID) {
212  return DOMString();
213  }
214  DOMString old;
215  removeProperty(propID, &old);
216  return old;
217 }
218 
219 DOMString CSSStyleDeclarationImpl::getPropertyValue(int propertyID) const
220 {
221  if (!m_lstValues || m_lstValues->isEmpty()) {
222  return DOMString();
223  }
224  CSSValueImpl *value = getPropertyCSSValue(propertyID);
225  if (value) {
226  return value->cssText();
227  }
228 
229  // Shorthand and 4-values properties
230  switch (propertyID) {
231  case CSS_PROP_BACKGROUND_POSITION: {
232  // ## Is this correct? The code in cssparser.cpp is confusing
233  const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X,
234  CSS_PROP_BACKGROUND_POSITION_Y
235  };
236  return getLayeredShortHandValue(properties, 2);
237  }
238  case CSS_PROP_BACKGROUND: {
239  // 'clip' must come after 'origin' in this array
240  const int properties[9] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT, CSS_PROP_BACKGROUND_ATTACHMENT,
241  CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y, CSS_PROP_BACKGROUND_SIZE,
242  CSS_PROP_BACKGROUND_ORIGIN, CSS_PROP_BACKGROUND_CLIP, CSS_PROP_BACKGROUND_COLOR
243  };
244  return getLayeredShortHandValue(properties, 9);
245  }
246  case CSS_PROP_BORDER: {
247  const int properties[3][4] = {{
248  CSS_PROP_BORDER_TOP_WIDTH,
249  CSS_PROP_BORDER_RIGHT_WIDTH,
250  CSS_PROP_BORDER_BOTTOM_WIDTH,
251  CSS_PROP_BORDER_LEFT_WIDTH
252  },
253  {
254  CSS_PROP_BORDER_TOP_STYLE,
255  CSS_PROP_BORDER_RIGHT_STYLE,
256  CSS_PROP_BORDER_BOTTOM_STYLE,
257  CSS_PROP_BORDER_LEFT_STYLE
258  },
259  {
260  CSS_PROP_BORDER_TOP_COLOR,
261  CSS_PROP_BORDER_RIGHT_COLOR,
262  CSS_PROP_BORDER_LEFT_COLOR,
263  CSS_PROP_BORDER_BOTTOM_COLOR
264  }
265  };
266  DOMString res;
267  const int nrprops = sizeof(properties) / sizeof(properties[0]);
268  for (int i = 0; i < nrprops; ++i) {
269  DOMString value = getCommonValue(properties[i], 4);
270  if (!value.isNull()) {
271  if (!res.isNull()) {
272  res += " ";
273  }
274  res += value;
275  }
276  }
277  return res;
278 
279  }
280  case CSS_PROP_BORDER_TOP: {
281  const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
282  CSS_PROP_BORDER_TOP_COLOR
283  };
284  return getShortHandValue(properties, 3);
285  }
286  case CSS_PROP_BORDER_RIGHT: {
287  const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
288  CSS_PROP_BORDER_RIGHT_COLOR
289  };
290  return getShortHandValue(properties, 3);
291  }
292  case CSS_PROP_BORDER_BOTTOM: {
293  const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
294  CSS_PROP_BORDER_BOTTOM_COLOR
295  };
296  return getShortHandValue(properties, 3);
297  }
298  case CSS_PROP_BORDER_LEFT: {
299  const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
300  CSS_PROP_BORDER_LEFT_COLOR
301  };
302  return getShortHandValue(properties, 3);
303  }
304  case CSS_PROP_OUTLINE: {
305  const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
306  CSS_PROP_OUTLINE_COLOR
307  };
308  return getShortHandValue(properties, 3);
309  }
310  case CSS_PROP_BORDER_COLOR: {
311  const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
312  CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR
313  };
314  return get4Values(properties);
315  }
316  case CSS_PROP_BORDER_WIDTH: {
317  const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
318  CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH
319  };
320  return get4Values(properties);
321  }
322  case CSS_PROP_BORDER_STYLE: {
323  const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
324  CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE
325  };
326  return get4Values(properties);
327  }
328  case CSS_PROP_MARGIN: {
329  const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
330  CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT
331  };
332  return get4Values(properties);
333  }
334  case CSS_PROP_PADDING: {
335  const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
336  CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT
337  };
338  return get4Values(properties);
339  }
340  case CSS_PROP_LIST_STYLE: {
341  const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
342  CSS_PROP_LIST_STYLE_IMAGE
343  };
344  return getShortHandValue(properties, 3);
345  }
346  }
347  //qCDebug(KHTML_LOG) << "property not found:" << propertyID;
348  return DOMString();
349 }
350 
351 // only returns a non-null value if all properties have the same, non-null value
352 DOMString CSSStyleDeclarationImpl::getCommonValue(const int *properties, int number) const
353 {
354  DOMString res;
355  for (int i = 0; i < number; ++i) {
356  CSSValueImpl *value = getPropertyCSSValue(properties[i]);
357  if (!value) {
358  return DOMString();
359  }
360  DOMString text = value->cssText();
361  if (text.isNull()) {
362  return DOMString();
363  }
364  if (res.isNull()) {
365  res = text;
366  } else if (res != text) {
367  return DOMString();
368  }
369  }
370  return res;
371 }
372 
373 DOMString CSSStyleDeclarationImpl::get4Values(const int *properties) const
374 {
375  // Assume the properties are in the order top, right, bottom, left.
377  for (int i = 0; i < 4; ++i) {
378  CSSValueImpl *val = getPropertyCSSValue(properties[i]);
379  // All 4 properties must be specified.
380  if (!val || isInitialOrInherit(val)) {
381  return DOMString();
382  } else {
383  values[i] = val->cssText();
384  }
385  }
386 
387  // Reduce shorthand.
388  if (values.at(1) == values.at(3)) { // right/left
389  values.remove(3);
390  if (values.at(0) == values.at(2)) { // top/bottom
391  values.remove(2);
392  if (values.at(0) == values.at(1)) {
393  values.remove(1);
394  }
395  }
396  }
397 
398  DOMString res;
399  const int valuesSize = values.size();
400  for (int i = 0; i < valuesSize; ++i) {
401  if (!res.isNull()) {
402  res += " ";
403  }
404  res += values.at(i);
405  }
406 
407  return res;
408 }
409 
410 static inline DOMString posXYSize_string_helper(DOMString &bPosX, DOMString &bPosY, DOMString &bSize)
411 {
412  DOMString res, position;
413 
414  if (!bPosX.isEmpty() && !bPosY.isEmpty()) {
415  position = bPosX + DOMString(" ") + bPosY;
416  } else if (bPosX.isEmpty() && !bPosY.isEmpty()) {
417  position = DOMString("0% ") + bPosY;
418  } else if (!bPosX.isEmpty() && bPosY.isEmpty()) {
419  position = bPosX + DOMString(" 0%");
420  }
421 
422  if (!bSize.isEmpty()) {
423  if (position.isEmpty()) {
424  res = DOMString("0% 0%") + DOMString(" / ") + bSize;
425  } else {
426  res = position + DOMString(" / ") + bSize;
427  }
428  } else {
429  res = position;
430  }
431 
432  return res;
433 }
434 
435 DOMString CSSStyleDeclarationImpl::getLayeredShortHandValue(const int *properties, unsigned number) const
436 {
437  DOMString res;
438  unsigned i;
439  unsigned j;
440 
441  // Begin by collecting the properties into an array.
443  unsigned numLayers = 0;
444 
445  for (i = 0; i < number; ++i) {
446  values[i] = getPropertyCSSValue(properties[i]);
447  if (values[i]) {
448  if (values[i]->isValueList()) {
449  CSSValueListImpl *valueList = static_cast<CSSValueListImpl *>(values[i]);
450  numLayers = qMax(valueList->length(), (unsigned long)numLayers);
451  } else {
452  numLayers = qMax(1U, numLayers);
453  }
454  }
455  }
456 
457  // Now stitch the properties together.
458  // Implicit initial values are flagged as such and can safely be omitted.
459  for (i = 0; i < numLayers; i++) {
460  DOMString layerRes;
461  DOMString bPosX, bPosY, bSize;
462  for (j = 0; j < number; j++) {
463  CSSValueImpl *value = nullptr;
464  if (values[j]) {
465  if (values[j]->isValueList()) {
466  value = static_cast<CSSValueListImpl *>(values[j])->item(i);
467  } else {
468  value = values[j];
469 
470  // Color only belongs in the last layer.
471  if (properties[j] == CSS_PROP_BACKGROUND_COLOR) {
472  if (i != numLayers - 1) {
473  value = nullptr;
474  }
475  } else if (i != 0) { // Other singletons only belong in the first layer.
476  value = nullptr;
477  }
478  }
479  }
480 
481  if (value && !value->isImplicitInitialValue()) {
482  // positionX,positionY,size should be handled separately in order
483  // to return a consistent and valid 'background' property string
484  if (properties[j] == CSS_PROP_BACKGROUND_POSITION_X) {
485  bPosX = value->cssText();
486  } else if (properties[j] == CSS_PROP_BACKGROUND_POSITION_Y) {
487  bPosY = value->cssText();
488  } else if (properties[j] == CSS_PROP_BACKGROUND_SIZE) {
489  bSize = value->cssText();
490  } else {
491  if (!layerRes.isNull()) {
492  layerRes += " ";
493  }
494  layerRes += value->cssText();
495  }
496  }
497  }
498 
499  // now add positionX,positionY,size
500  DOMString posXYSize = posXYSize_string_helper(bPosX, bPosY, bSize);
501  if (!posXYSize.isEmpty()) {
502  if (!layerRes.isNull()) {
503  layerRes += " ";
504  }
505  layerRes += posXYSize;
506  }
507 
508  if (!layerRes.isNull()) {
509  if (!res.isNull()) {
510  res += ", ";
511  }
512  res += layerRes;
513  }
514  }
515 
516  return res;
517 }
518 
519 DOMString CSSStyleDeclarationImpl::getShortHandValue(const int *properties, int number) const
520 {
521  DOMString res;
522  for (int i = 0; i < number; ++i) {
523  CSSValueImpl *value = getPropertyCSSValue(properties[i]);
524  if (value) { // TODO provide default value if !value
525  if (!res.isNull()) {
526  res += " ";
527  }
528  res += value->cssText();
529  }
530  }
531  return res;
532 }
533 
534 CSSValueImpl *CSSStyleDeclarationImpl::getPropertyCSSValue(int propertyID) const
535 {
536  if (!m_lstValues || m_lstValues->isEmpty()) {
537  return nullptr;
538  }
539 
540  QListIterator<CSSProperty *> lstValuesIt(*m_lstValues);
541  CSSProperty *current;
542  while (lstValuesIt.hasNext()) {
543  current = lstValuesIt.next();
544  if (current->m_id == propertyID) {
545  return current->value();
546  }
547  }
548  return nullptr;
549 }
550 
551 bool CSSStyleDeclarationImpl::isPropertyImplicit(int propertyID) const
552 {
553  QListIterator<CSSProperty *> lstValuesIt(*m_lstValues);
554  CSSProperty const *current;
555  while (lstValuesIt.hasNext()) {
556  current = lstValuesIt.next();
557  if (current->m_id == propertyID) {
558  return current->isImplicit();
559  }
560  }
561  return false;
562 }
563 
564 // --------------- Shorthands mapping ----------------
565 
566 // In order top be able to remove a shorthand property,
567 // we need a reverse mapping from the shorthands to their composing properties.
568 
569 // ### Warning: keep in sync when introducing new shorthands.
570 
571 struct PropertyLonghand {
572  PropertyLonghand()
573  : m_properties(nullptr)
574  , m_length(0)
575  {
576  }
577 
578  PropertyLonghand(const int *firstProperty, unsigned numProperties)
579  : m_properties(firstProperty)
580  , m_length(numProperties)
581  {
582  }
583 
584  const int *properties() const
585  {
586  return m_properties;
587  }
588  unsigned length() const
589  {
590  return m_length;
591  }
592 
593 private:
594  const int *m_properties;
595  unsigned m_length;
596 };
597 
598 static void initShorthandMap(QHash<int, PropertyLonghand> &shorthandMap)
599 {
600 #define SET_SHORTHAND_MAP_ENTRY(map, propID, array) \
601  map.insert(propID, PropertyLonghand(array, sizeof(array) / sizeof(array[0])))
602 
603  // Do not change the order of the following four shorthands, and keep them together.
604  static const int borderProperties[4][3] = {
605  { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_TOP_WIDTH },
606  { CSS_PROP_BORDER_RIGHT_COLOR, CSS_PROP_BORDER_RIGHT_STYLE, CSS_PROP_BORDER_RIGHT_WIDTH },
607  { CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_BOTTOM_WIDTH },
608  { CSS_PROP_BORDER_LEFT_COLOR, CSS_PROP_BORDER_LEFT_STYLE, CSS_PROP_BORDER_LEFT_WIDTH }
609  };
610  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_TOP, borderProperties[0]);
611  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_RIGHT, borderProperties[1]);
612  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_BOTTOM, borderProperties[2]);
613  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_LEFT, borderProperties[3]);
614 
615  shorthandMap.insert(CSS_PROP_BORDER, PropertyLonghand(borderProperties[0], sizeof(borderProperties) / sizeof(borderProperties[0][0])));
616 
617  static const int borderColorProperties[] = {
618  CSS_PROP_BORDER_TOP_COLOR,
619  CSS_PROP_BORDER_RIGHT_COLOR,
620  CSS_PROP_BORDER_BOTTOM_COLOR,
621  CSS_PROP_BORDER_LEFT_COLOR
622  };
623  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_COLOR, borderColorProperties);
624 
625  static const int borderStyleProperties[] = {
626  CSS_PROP_BORDER_TOP_STYLE,
627  CSS_PROP_BORDER_RIGHT_STYLE,
628  CSS_PROP_BORDER_BOTTOM_STYLE,
629  CSS_PROP_BORDER_LEFT_STYLE
630  };
631  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_STYLE, borderStyleProperties);
632 
633  static const int borderWidthProperties[] = {
634  CSS_PROP_BORDER_TOP_WIDTH,
635  CSS_PROP_BORDER_RIGHT_WIDTH,
636  CSS_PROP_BORDER_BOTTOM_WIDTH,
637  CSS_PROP_BORDER_LEFT_WIDTH
638  };
639  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_WIDTH, borderWidthProperties);
640 
641  static const int backgroundPositionProperties[] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y };
642  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND_POSITION, backgroundPositionProperties);
643 
644  static const int borderSpacingProperties[] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING, CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
645  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_SPACING, borderSpacingProperties);
646 
647  static const int listStyleProperties[] = {
648  CSS_PROP_LIST_STYLE_IMAGE,
649  CSS_PROP_LIST_STYLE_POSITION,
650  CSS_PROP_LIST_STYLE_TYPE
651  };
652  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_LIST_STYLE, listStyleProperties);
653 
654  static const int marginProperties[] = {
655  CSS_PROP_MARGIN_TOP,
656  CSS_PROP_MARGIN_RIGHT,
657  CSS_PROP_MARGIN_BOTTOM,
658  CSS_PROP_MARGIN_LEFT
659  };
660  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_MARGIN, marginProperties);
661 
662 #ifdef APPLE_CHANGES
663  static const int marginCollapseProperties[] = { CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE, CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE };
664  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARGIN_COLLAPSE, marginCollapseProperties);
665 #endif
666 
667  static const int marqueeProperties[] = {
668  CSS_PROP__KHTML_MARQUEE_DIRECTION,
669  CSS_PROP__KHTML_MARQUEE_INCREMENT,
670  CSS_PROP__KHTML_MARQUEE_REPETITION,
671  CSS_PROP__KHTML_MARQUEE_STYLE,
672  CSS_PROP__KHTML_MARQUEE_SPEED
673  };
674  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_MARQUEE, marqueeProperties);
675 
676  static const int outlineProperties[] = {
677  CSS_PROP_OUTLINE_COLOR,
678  CSS_PROP_OUTLINE_OFFSET,
679  CSS_PROP_OUTLINE_STYLE,
680  CSS_PROP_OUTLINE_WIDTH
681  };
682  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OUTLINE, outlineProperties);
683 
684  static const int paddingProperties[] = {
685  CSS_PROP_PADDING_TOP,
686  CSS_PROP_PADDING_RIGHT,
687  CSS_PROP_PADDING_BOTTOM,
688  CSS_PROP_PADDING_LEFT
689  };
690  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_PADDING, paddingProperties);
691 
692 #ifdef APPLE_CHANGES
693  static const int textStrokeProperties[] = { CSS_PROP__KHTML_TEXT_STROKE_COLOR, CSS_PROP__KHTML_TEXT_STROKE_WIDTH };
694  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_TEXT_STROKE, textStrokeProperties);
695 #endif
696 
697  static const int backgroundProperties[] = {
698  CSS_PROP_BACKGROUND_ATTACHMENT,
699  CSS_PROP_BACKGROUND_COLOR,
700  CSS_PROP_BACKGROUND_IMAGE,
701  CSS_PROP_BACKGROUND_POSITION_X,
702  CSS_PROP_BACKGROUND_POSITION_Y,
703  CSS_PROP_BACKGROUND_REPEAT,
704  CSS_PROP_BACKGROUND_SIZE,
705  CSS_PROP_BACKGROUND_ORIGIN,
706  CSS_PROP_BACKGROUND_CLIP
707  };
708  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BACKGROUND, backgroundProperties);
709 
710 #ifdef APPLE_CHANGES
711  static const int columnsProperties[] = { CSS_PROP__KHTML_COLUMN_WIDTH, CSS_PROP__KHTML_COLUMN_COUNT };
712  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMNS, columnsProperties);
713 
714  static const int columnRuleProperties[] = {
715  CSS_PROP__KHTML_COLUMN_RULE_COLOR,
716  CSS_PROP__KHTML_COLUMN_RULE_STYLE,
717  CSS_PROP__KHTML_COLUMN_RULE_WIDTH
718  };
719  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP__KHTML_COLUMN_RULE, columnRuleProperties);
720 #endif
721 
722  static const int overflowProperties[] = { CSS_PROP_OVERFLOW_X, CSS_PROP_OVERFLOW_Y };
723  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_OVERFLOW, overflowProperties);
724 
725  static const int borderRadiusProperties[] = {
726  CSS_PROP_BORDER_TOP_RIGHT_RADIUS,
727  CSS_PROP_BORDER_TOP_LEFT_RADIUS,
728  CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS,
729  CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS
730  };
731  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_BORDER_RADIUS, borderRadiusProperties);
732 
733  static const int markerProperties[] = {
734  CSS_PROP_MARKER_START,
735  CSS_PROP_MARKER_MID,
736  CSS_PROP_MARKER_END
737  };
738  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_MARKER, markerProperties);
739 
740  static const int fontProperties[] = {
741  CSS_PROP_FONT_STYLE,
742  CSS_PROP_FONT_VARIANT,
743  CSS_PROP_FONT_WEIGHT,
744  CSS_PROP_FONT_SIZE,
745  CSS_PROP_LINE_HEIGHT,
746  CSS_PROP_FONT_FAMILY
747  };
748  SET_SHORTHAND_MAP_ENTRY(shorthandMap, CSS_PROP_FONT, fontProperties);
749 
750 #undef SET_SHORTHAND_MAP_ENTRY
751 }
752 
753 // -------------------------------------------
754 
755 void CSSStyleDeclarationImpl::removeProperty(int propertyID, DOM::DOMString *old)
756 {
757  if (!m_lstValues || m_lstValues->isEmpty()) {
758  return;
759  }
760 
761  bool changed = false;
762 
763  static QHash<int, PropertyLonghand> shorthandMap;
764  if (shorthandMap.isEmpty()) {
765  initShorthandMap(shorthandMap);
766  }
767 
768  PropertyLonghand longhand = shorthandMap.value(propertyID);
769  if (longhand.length()) {
770  changed = removePropertiesInSet(longhand.properties(), longhand.length());
771  }
772 
773  // FIXME: Return an equivalent shorthand when possible.
774 
775  QMutableListIterator<CSSProperty *> lstValuesIt(*m_lstValues);
776  CSSProperty *current;
777  lstValuesIt.toBack();
778  while (lstValuesIt.hasPrevious()) {
779  current = lstValuesIt.previous();
780  if (current->m_id == propertyID) {
781  if (old) {
782  *old = current->value()->cssText();
783  }
784  delete lstValuesIt.value();
785  lstValuesIt.remove();
786  changed = true;
787  break;
788  }
789  }
790 
791  if (changed) {
792  setChanged();
793  }
794 }
795 
796 bool CSSStyleDeclarationImpl::removePropertiesInSet(const int *set, unsigned length)
797 {
798  bool changed = false;
799  for (unsigned i = 0; i < length; i++) {
800  QMutableListIterator<CSSProperty *> lstValuesIt(*m_lstValues);
801  CSSProperty *current;
802  lstValuesIt.toBack();
803  while (lstValuesIt.hasPrevious()) {
804  current = lstValuesIt.previous();
805  if (current->m_id == set[i]) {
806  delete lstValuesIt.value();
807  lstValuesIt.remove();
808  changed = true;
809  break;
810  }
811  }
812  }
813 
814  return changed;
815 }
816 
817 void CSSStyleDeclarationImpl::setChanged()
818 {
819  if (m_node) {
820  m_node->setChanged();
821  return;
822  }
823 
824  // ### quick&dirty hack for KDE 3.0... make this MUCH better! (Dirk)
825  for (StyleBaseImpl *stylesheet = this; stylesheet; stylesheet = stylesheet->parent())
826  if (stylesheet->isCSSStyleSheet()) {
827  static_cast<CSSStyleSheetImpl *>(stylesheet)->doc()->updateStyleSelector();
828  break;
829  }
830 }
831 
832 void CSSStyleDeclarationImpl::clear()
833 {
834  if (!m_lstValues) {
835  return;
836  }
837 
838  QMutableListIterator<CSSProperty *> it(*m_lstValues);
839  while (it.hasNext()) {
840  delete it.next();
841  it.remove();
842  }
843 }
844 
845 bool CSSStyleDeclarationImpl::getPropertyPriority(int propertyID) const
846 {
847  if (m_lstValues && !m_lstValues->isEmpty()) {
848  QListIterator<CSSProperty *> lstValuesIt(*m_lstValues);
849  CSSProperty *current;
850  while (lstValuesIt.hasNext()) {
851  current = lstValuesIt.next();
852  if (propertyID == current->m_id) {
853  return current->m_important;
854  }
855  }
856  }
857  return false;
858 }
859 
860 bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important, int &ec)
861 {
862  ec = 0;
863 
864  // Setting the value to an empty string just removes the property in both IE and Gecko.
865  // Setting it to null seems to produce less consistent results, but we treat it just the same.
866  if (value.isEmpty()) {
867  removeProperty(id);
868  return true;
869  }
870 
871  bool success = setProperty(id, value, important);
872 #if 0
873  if (!success) {
874  // CSS DOM requires raising SYNTAX_ERR here, but this is too dangerous for compatibility,
875  // see <https://bugs.webkit.org/show_bug.cgi?id=7296>.
876  }
877 #endif
878  return success;
879 }
880 
881 bool CSSStyleDeclarationImpl::setProperty(int id, const DOMString &value, bool important)
882 {
883  if (!m_lstValues) {
884  m_lstValues = new QList<CSSProperty *>;
885  }
886 
887  CSSParser parser(strictParsing);
888  bool success = parser.parseValue(this, id, value, important);
889  if (!success) {
890  // qCDebug(KHTML_LOG) << "CSSStyleDeclarationImpl::setProperty invalid property: [" << getPropertyName(id).string()
891  //<< "] value: [" << value.string() << "]";
892  } else {
893  setChanged();
894  }
895  return success;
896 }
897 
898 void CSSStyleDeclarationImpl::setProperty(int id, int value, bool important)
899 {
900  if (!m_lstValues) {
901  m_lstValues = new QList<CSSProperty *>;
902  }
903  removeProperty(id);
904 
905  CSSValueImpl *cssValue = new CSSPrimitiveValueImpl(value);
906  setParsedValue(id, cssValue, important, m_lstValues);
907  setChanged();
908 }
909 
910 void CSSStyleDeclarationImpl::setLengthProperty(int id, const DOM::DOMString &value, bool important, bool _multiLength)
911 {
912  bool parseMode = strictParsing;
913  strictParsing = false;
914  multiLength = _multiLength;
915  setProperty(id, value, important);
916  strictParsing = parseMode;
917  multiLength = false;
918 }
919 
920 void CSSStyleDeclarationImpl::setProperty(const DOMString &propertyString)
921 {
922  if (!m_lstValues) {
923  m_lstValues = new QList<CSSProperty *>;
924  }
925 
926  CSSParser parser(strictParsing);
927  parser.parseDeclaration(this, propertyString);
928  setChanged();
929 }
930 
931 unsigned long CSSStyleDeclarationImpl::length() const
932 {
933  return m_lstValues ? m_lstValues->count() : 0;
934 }
935 
936 DOMString CSSStyleDeclarationImpl::item(unsigned long index) const
937 {
938  if (m_lstValues && index < (unsigned)m_lstValues->count() && m_lstValues->at(index)) {
939  return getPropertyName(m_lstValues->at(index)->m_id);
940  }
941  return DOMString();
942 }
943 
944 CSSRuleImpl *CSSStyleDeclarationImpl::parentRule() const
945 {
946  return (m_parent && m_parent->isRule()) ?
947  static_cast<CSSRuleImpl *>(m_parent) : nullptr;
948 }
949 
950 DOM::DOMString CSSStyleDeclarationImpl::cssText() const
951 {
952  if (!m_lstValues || m_lstValues->isEmpty()) {
953  return DOMString();
954  }
955 
956  DOMString result;
957 
958  const CSSProperty *positionXProp = nullptr;
959  const CSSProperty *positionYProp = nullptr;
960 
961  QListIterator<CSSProperty *> lstValuesIt(*m_lstValues);
962  while (lstValuesIt.hasNext()) {
963  const CSSProperty *cur = lstValuesIt.next();
964  if (cur->id() == CSS_PROP_BACKGROUND_POSITION_X) {
965  positionXProp = cur;
966  } else if (cur->id() == CSS_PROP_BACKGROUND_POSITION_Y) {
967  positionYProp = cur;
968  } else {
969  result += cur->cssText();
970  }
971  }
972 
973  // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output.
974  // It is required because background-position-x/y are non-standard properties and generated output
975  // would not work in Firefox
976  // It would be a better solution if background-position was CSS_PAIR.
977  if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) {
978  DOMString positionValue;
979  const int properties[2] = { CSS_PROP_BACKGROUND_POSITION_X, CSS_PROP_BACKGROUND_POSITION_Y };
980  if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList()) {
981  positionValue = getLayeredShortHandValue(properties, 2);
982  } else {
983  positionValue = positionXProp->value()->cssText() + DOMString(" ") + positionYProp->value()->cssText();
984  }
985  result += DOMString("background-position: ") + positionValue
986  + DOMString((positionXProp->isImportant() ? " !important" : ""))
987  + DOMString("; ");
988  } else {
989  if (positionXProp) {
990  result += positionXProp->cssText();
991  }
992  if (positionYProp) {
993  result += positionYProp->cssText();
994  }
995  }
996  return result;
997 }
998 
999 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 
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString & append(QChar ch)
QHash::iterator insert(const Key &key, const T &value)
a cached image
Definition: loader.h:359
QVector< V > values(const QMultiHash< K, V > &c)
QString number(int n, int base)
KGuiItem properties()
CaseInsensitive
The CSSPrimitiveValue interface represents a single CSS value .
Definition: css_value.h:367
UnitTypes
An integer indicating which type of unit applies to the value.
Definition: css_value.h:384
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
ushort unicode() const const
const T value(const Key &key) const const
QString & replace(int position, int n, QChar after)
This library provides a full-featured HTML parser and widget.
const QList< QKeySequence > & end()
QString mid(int position, int n) const const
bool isEmpty() const const
DOMStringImpl * implementation() const
Definition: dom_string.h:145
Definition: css_base.h:371
QCA_EXPORT void setProperty(const QString &name, const QVariant &value)
DOMString trimSpaces() const
Returns a string with Space Characters removed from the start and the end.
Definition: dom_string.cpp:345
bool hasNext() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Oct 25 2021 22:48:12 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.