KHtml

render_style.cpp
1 /*
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Antti Koivisto ([email protected])
5  * Copyright (C) 1999-2003 Lars Knoll ([email protected])
6  * Copyright (C) 2002-2003 Dirk Mueller ([email protected])
7  * Copyright (C) 2002-2005 Apple Computer, Inc.
8  * Copyright (C) 2005 Allan Sandfeld Jensen ([email protected])
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB. If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  */
26 
27 #include "render_style.h"
28 
29 #include <xml/dom_stringimpl.h>
30 #include <css/cssstyleselector.h>
31 #include <css/css_valueimpl.h>
32 
33 using namespace khtml;
34 using namespace DOM;
35 
36 /* CSS says Fixed for the default padding value, but we treat variable as 0 padding anyways, and like
37  * this is works fine for table paddings aswell
38  */
39 StyleSurroundData::StyleSurroundData()
40  : margin(Fixed), padding(Auto)
41 {
42 }
43 
44 StyleSurroundData::StyleSurroundData(const StyleSurroundData &o)
45  : Shared<StyleSurroundData>(),
46  offset(o.offset), margin(o.margin), padding(o.padding),
47  border(o.border)
48 {
49 }
50 
51 bool StyleSurroundData::operator==(const StyleSurroundData &o) const
52 {
53  return offset == o.offset && margin == o.margin &&
54  padding == o.padding && border == o.border;
55 }
56 
57 StyleBoxData::StyleBoxData()
58  : z_index(0), z_auto(true)
59 {
60  min_width = min_height = RenderStyle::initialMinSize();
61  max_width = max_height = RenderStyle::initialMaxSize();
62  box_sizing = RenderStyle::initialBoxSizing();
63 }
64 
65 StyleBoxData::StyleBoxData(const StyleBoxData &o)
66  : Shared<StyleBoxData>(),
67  width(o.width), height(o.height),
68  min_width(o.min_width), max_width(o.max_width),
69  min_height(o.min_height), max_height(o.max_height),
70  box_sizing(o.box_sizing),
71  z_index(o.z_index), z_auto(o.z_auto)
72 {
73 }
74 
75 bool StyleBoxData::operator==(const StyleBoxData &o) const
76 {
77  return
78  width == o.width &&
79  height == o.height &&
80  min_width == o.min_width &&
81  max_width == o.max_width &&
82  min_height == o.min_height &&
83  max_height == o.max_height &&
84  box_sizing == o.box_sizing &&
85  vertical_align == o.vertical_align &&
86  z_index == o.z_index &&
87  z_auto == o.z_auto;
88 }
89 
90 StyleVisualData::StyleVisualData()
91  : textDecoration(RenderStyle::initialTextDecoration()),
92  palette(QApplication::palette())
93 {
94 }
95 
96 StyleVisualData::~StyleVisualData()
97 {
98 }
99 
100 StyleVisualData::StyleVisualData(const StyleVisualData &o)
101  : Shared<StyleVisualData>(),
102  clip(o.clip), textDecoration(o.textDecoration),
103  palette(o.palette)
104 {
105 }
106 
107 BackgroundLayer::BackgroundLayer()
108  : m_image(RenderStyle::initialBackgroundImage()),
109  m_xPosition(RenderStyle::initialBackgroundXPosition()),
110  m_yPosition(RenderStyle::initialBackgroundYPosition()),
111  m_bgAttachment(RenderStyle::initialBackgroundAttachment()),
112  m_bgClip(RenderStyle::initialBackgroundClip()),
113  m_bgOrigin(RenderStyle::initialBackgroundOrigin()),
114  m_bgRepeat(RenderStyle::initialBackgroundRepeat()),
115  m_backgroundSize(RenderStyle::initialBackgroundSize()),
116  m_next(nullptr)
117 {
118  m_imageSet = m_attachmentSet = m_clipSet = m_originSet =
119  m_repeatSet = m_xPosSet = m_yPosSet = m_backgroundSizeSet = false;
120 }
121 
122 BackgroundLayer::BackgroundLayer(const BackgroundLayer &o)
123 {
124  m_next = o.m_next ? new BackgroundLayer(*o.m_next) : nullptr;
125  m_image = o.m_image;
126  m_xPosition = o.m_xPosition;
127  m_yPosition = o.m_yPosition;
128  m_bgAttachment = o.m_bgAttachment;
129  m_bgClip = o.m_bgClip;
130  m_bgOrigin = o.m_bgOrigin;
131  m_bgRepeat = o.m_bgRepeat;
132  m_backgroundSize = o.m_backgroundSize;
133  m_imageSet = o.m_imageSet;
134  m_attachmentSet = o.m_attachmentSet;
135  m_clipSet = o.m_clipSet;
136  m_originSet = o.m_originSet;
137  m_repeatSet = o.m_repeatSet;
138  m_xPosSet = o.m_xPosSet;
139  m_yPosSet = o.m_yPosSet;
140  m_backgroundSizeSet = o.m_backgroundSizeSet;
141 }
142 
143 BackgroundLayer::~BackgroundLayer()
144 {
145  delete m_next;
146 }
147 
148 BackgroundLayer &BackgroundLayer::operator=(const BackgroundLayer &o)
149 {
150  if (m_next != o.m_next) {
151  delete m_next;
152  m_next = o.m_next ? new BackgroundLayer(*o.m_next) : nullptr;
153  }
154 
155  m_image = o.m_image;
156  m_xPosition = o.m_xPosition;
157  m_yPosition = o.m_yPosition;
158  m_bgAttachment = o.m_bgAttachment;
159  m_bgClip = o.m_bgClip;
160  m_bgOrigin = o.m_bgOrigin;
161  m_bgRepeat = o.m_bgRepeat;
162  m_backgroundSize = o.m_backgroundSize;
163 
164  m_imageSet = o.m_imageSet;
165  m_attachmentSet = o.m_attachmentSet;
166  m_originSet = o.m_originSet;
167  m_repeatSet = o.m_repeatSet;
168  m_xPosSet = o.m_xPosSet;
169  m_yPosSet = o.m_yPosSet;
170  m_backgroundSizeSet = o.m_backgroundSizeSet;
171 
172  return *this;
173 }
174 
175 bool BackgroundLayer::operator==(const BackgroundLayer &o) const
176 {
177  return m_image == o.m_image && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition &&
178  m_bgAttachment == o.m_bgAttachment && m_bgClip == o.m_bgClip && m_bgOrigin == o.m_bgOrigin &&
179  m_bgRepeat == o.m_bgRepeat && m_backgroundSize == o.m_backgroundSize &&
180  m_imageSet == o.m_imageSet && m_attachmentSet == o.m_attachmentSet && m_repeatSet == o.m_repeatSet &&
181  m_xPosSet == o.m_xPosSet && m_yPosSet == o.m_yPosSet && m_backgroundSizeSet == o.m_backgroundSizeSet &&
182  ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
183 }
184 
185 void BackgroundLayer::fillUnsetProperties()
186 {
187  BackgroundLayer *curr;
188 
189  for (curr = this; curr && curr->isBackgroundXPositionSet(); curr = curr->next()) {};
190  if (curr && curr != this) {
191  // We need to fill in the remaining values with the pattern specified.
192  for (BackgroundLayer *pattern = this; curr; curr = curr->next()) {
193  curr->setBackgroundXPosition(pattern->backgroundXPosition());
194  pattern = pattern->next();
195  if (pattern == curr || !pattern) {
196  pattern = this;
197  }
198  }
199  }
200 
201  for (curr = this; curr && curr->isBackgroundYPositionSet(); curr = curr->next()) {};
202  if (curr && curr != this) {
203  // We need to fill in the remaining values with the pattern specified.
204  for (BackgroundLayer *pattern = this; curr; curr = curr->next()) {
205  curr->setBackgroundYPosition(pattern->backgroundYPosition());
206  pattern = pattern->next();
207  if (pattern == curr || !pattern) {
208  pattern = this;
209  }
210  }
211  }
212 
213  for (curr = this; curr && curr->isBackgroundAttachmentSet(); curr = curr->next()) {};
214  if (curr && curr != this) {
215  // We need to fill in the remaining values with the pattern specified.
216  for (BackgroundLayer *pattern = this; curr; curr = curr->next()) {
217  curr->setBackgroundAttachment(pattern->backgroundAttachment());
218  pattern = pattern->next();
219  if (pattern == curr || !pattern) {
220  pattern = this;
221  }
222  }
223  }
224 
225  for (curr = this; curr && curr->isBackgroundClipSet(); curr = curr->next()) {};
226  if (curr && curr != this) {
227  // We need to fill in the remaining values with the pattern specified.
228  for (BackgroundLayer *pattern = this; curr; curr = curr->next()) {
229  curr->setBackgroundClip(pattern->backgroundClip());
230  pattern = pattern->next();
231  if (pattern == curr || !pattern) {
232  pattern = this;
233  }
234  }
235  }
236 
237  for (curr = this; curr && curr->isBackgroundOriginSet(); curr = curr->next()) {};
238  if (curr && curr != this) {
239  // We need to fill in the remaining values with the pattern specified.
240  for (BackgroundLayer *pattern = this; curr; curr = curr->next()) {
241  curr->setBackgroundOrigin(pattern->backgroundOrigin());
242  pattern = pattern->next();
243  if (pattern == curr || !pattern) {
244  pattern = this;
245  }
246  }
247  }
248 
249  for (curr = this; curr && curr->isBackgroundRepeatSet(); curr = curr->next()) {};
250  if (curr && curr != this) {
251  // We need to fill in the remaining values with the pattern specified.
252  for (BackgroundLayer *pattern = this; curr; curr = curr->next()) {
253  curr->setBackgroundRepeat(pattern->backgroundRepeat());
254  pattern = pattern->next();
255  if (pattern == curr || !pattern) {
256  pattern = this;
257  }
258  }
259  }
260 
261  for (curr = this; curr && curr->isBackgroundSizeSet(); curr = curr->next()) {};
262  if (curr && curr != this) {
263  // We need to fill in the remaining values with the pattern specified.
264  for (BackgroundLayer *pattern = this; curr; curr = curr->next()) {
265  curr->setBackgroundSize(pattern->backgroundSize());
266  pattern = pattern->next();
267  if (pattern == curr || !pattern) {
268  pattern = this;
269  }
270  }
271  }
272 }
273 
274 void BackgroundLayer::cullEmptyLayers()
275 {
276  BackgroundLayer *next;
277  for (BackgroundLayer *p = this; p; p = next) {
278  next = p->m_next;
279  if (next && !next->isBackgroundImageSet()) {
280  delete next;
281  p->m_next = nullptr;
282  break;
283  }
284  }
285 }
286 
287 StyleBackgroundData::StyleBackgroundData()
288 {}
289 
290 StyleBackgroundData::StyleBackgroundData(const StyleBackgroundData &o)
291  : Shared<StyleBackgroundData>(), m_background(o.m_background), m_outline(o.m_outline)
292 {}
293 
294 bool StyleBackgroundData::operator==(const StyleBackgroundData &o) const
295 {
296  return m_background == o.m_background && m_color == o.m_color && m_outline == o.m_outline;
297 }
298 
299 StyleGeneratedData::StyleGeneratedData() : Shared<StyleGeneratedData>(), content(nullptr), counter_reset(nullptr), counter_increment(nullptr) {}
300 
301 StyleGeneratedData::~StyleGeneratedData()
302 {
303  if (counter_reset) {
304  counter_reset->deref();
305  }
306  if (counter_increment) {
307  counter_increment->deref();
308  }
309  delete content;
310 }
311 
312 StyleGeneratedData::StyleGeneratedData(const StyleGeneratedData &o)
313  : Shared<StyleGeneratedData>(), content(nullptr),
314  counter_reset(o.counter_reset), counter_increment(o.counter_increment)
315 {
316  if (o.content) {
317  content = new ContentData(*o.content);
318  }
319  if (counter_reset) {
320  counter_reset->ref();
321  }
322  if (counter_increment) {
323  counter_increment->ref();
324  }
325 }
326 
327 bool StyleGeneratedData::contentDataEquivalent(const StyleGeneratedData *otherStyle) const
328 {
329  ContentData *c1 = content;
330  ContentData *c2 = otherStyle->content;
331 
332  while (c1 && c2) {
333  if (c1->_contentType != c2->_contentType) {
334  return false;
335  }
336  if (c1->_contentType == CONTENT_TEXT) {
337  DOM::DOMString c1Str(c1->_content.text);
338  DOM::DOMString c2Str(c2->_content.text);
339  if (c1Str != c2Str) {
340  return false;
341  }
342  } else if (c1->_contentType == CONTENT_OBJECT) {
343  if (c1->_content.object != c2->_content.object) {
344  return false;
345  }
346  } else if (c1->_contentType == CONTENT_COUNTER) {
347  if (c1->_content.counter != c2->_content.counter) {
348  return false;
349  }
350  } else if (c1->_contentType == CONTENT_QUOTE) {
351  if (c1->_content.quote != c2->_content.quote) {
352  return false;
353  }
354  }
355 
356  c1 = c1->_nextContent;
357  c2 = c2->_nextContent;
358  }
359 
360  return !c1 && !c2;
361 }
362 
363 static bool compareCounterActList(const CSSValueListImpl *ca, const CSSValueListImpl *cb)
364 {
365  // weeee....
366  CSSValueListImpl *a = const_cast<CSSValueListImpl *>(ca);
367  CSSValueListImpl *b = const_cast<CSSValueListImpl *>(cb);
368 
369  if (!a && !b) {
370  return true;
371  }
372  if (!a || !b) {
373  return false;
374  }
375  if (a->length() != b->length()) {
376  return false;
377  }
378  for (uint i = 0; i < a->length(); i++) {
379  CSSValueImpl *ai = a->item(i);
380  CSSValueImpl *bi = b->item(i);
381  assert(ai && ai->cssValueType() == CSSValue::CSS_CUSTOM);
382  assert(bi && bi->cssValueType() == CSSValue::CSS_CUSTOM);
383  CounterActImpl *caa = static_cast<CounterActImpl *>(ai);
384  CounterActImpl *cab = static_cast<CounterActImpl *>(bi);
385  if (caa->value() != cab->value()) {
386  return false;
387  }
388  if (caa->counter() != cab->counter()) {
389  return false;
390  }
391  }
392  return true;
393 }
394 
395 bool StyleGeneratedData::counterDataEquivalent(const StyleGeneratedData *otherStyle) const
396 {
397  return compareCounterActList(counter_reset, otherStyle->counter_reset) &&
398  compareCounterActList(counter_increment, otherStyle->counter_increment);
399 }
400 
401 bool StyleGeneratedData::operator==(const StyleGeneratedData &o) const
402 {
403  return contentDataEquivalent(&o) && counterDataEquivalent(&o);
404 }
405 
406 StyleMarqueeData::StyleMarqueeData()
407 {
408  increment = RenderStyle::initialMarqueeIncrement();
409  speed = RenderStyle::initialMarqueeSpeed();
410  direction = RenderStyle::initialMarqueeDirection();
411  behavior = RenderStyle::initialMarqueeBehavior();
412  loops = RenderStyle::initialMarqueeLoopCount();
413 }
414 
415 StyleMarqueeData::StyleMarqueeData(const StyleMarqueeData &o)
416  : Shared<StyleMarqueeData>(), increment(o.increment), speed(o.speed), loops(o.loops),
417  behavior(o.behavior), direction(o.direction)
418 {}
419 
420 bool StyleMarqueeData::operator==(const StyleMarqueeData &o) const
421 {
422  return (increment == o.increment && speed == o.speed && direction == o.direction &&
423  behavior == o.behavior && loops == o.loops);
424 }
425 
426 bool BorderRadii::operator==(const BorderRadii &o) const
427 {
428  return horizontal == o.horizontal &&
429  vertical == o.vertical;
430 }
431 
432 BorderRadiusData::BorderRadiusData()
433  :Shared<BorderRadiusData>()
434 {
435  topRight = RenderStyle::initialBorderRadius();
436  bottomRight = RenderStyle::initialBorderRadius();
437  bottomLeft = RenderStyle::initialBorderRadius();
438  topLeft = RenderStyle::initialBorderRadius();
439 }
440 
441 bool BorderRadiusData::operator==(const BorderRadiusData &o) const
442 {
443  return topRight == o.topRight && bottomRight == o.bottomRight
444  && bottomLeft == o.bottomLeft && topLeft == o.topLeft;
445 }
446 
447 bool BorderRadiusData::hasBorderRadius() const
448 {
449  return topRight.hasBorderRadius() || bottomRight.hasBorderRadius() ||
450  bottomLeft.hasBorderRadius() || topLeft.hasBorderRadius();
451 }
452 
453 StyleCSS3NonInheritedData::StyleCSS3NonInheritedData()
454  : Shared<StyleCSS3NonInheritedData>()
455  , opacity(RenderStyle::initialOpacity())
456 {
457 }
458 
459 StyleCSS3NonInheritedData::StyleCSS3NonInheritedData(const StyleCSS3NonInheritedData &o)
460  : Shared<StyleCSS3NonInheritedData>(),
461  opacity(o.opacity),
462 #ifdef APPLE_CHANGES
463  flexibleBox(o.flexibleBox),
464 #endif
465  marquee(o.marquee),
466  borderRadius(o.borderRadius)
467 {
468 }
469 
470 bool StyleCSS3NonInheritedData::operator==(const StyleCSS3NonInheritedData &o) const
471 {
472  return
473  opacity == o.opacity &&
474 #ifdef APPLE_CHANGES
475  flexibleBox == o.flexibleBox &&
476 #endif
477  marquee == o.marquee &&
478  borderRadius == o.borderRadius;
479 }
480 
481 StyleCSS3InheritedData::StyleCSS3InheritedData()
482  : Shared<StyleCSS3InheritedData>(), textShadow(nullptr), wordWrap(RenderStyle::initialWordWrap())
483 #ifdef APPLE_CHANGES
484  , userModify(READ_ONLY), textSizeAdjust(RenderStyle::initialTextSizeAdjust())
485 #endif
486 {
487 
488 }
489 
490 StyleCSS3InheritedData::StyleCSS3InheritedData(const StyleCSS3InheritedData &o)
491  : Shared<StyleCSS3InheritedData>()
492 {
493  textShadow = o.textShadow ? new ShadowData(*o.textShadow) : nullptr;
494  wordWrap = o.wordWrap;
495 #ifdef APPLE_CHANGES
496  userModify = o.userModify;
497  textSizeAdjust = o.textSizeAdjust;
498 #endif
499 }
500 
501 StyleCSS3InheritedData::~StyleCSS3InheritedData()
502 {
503  delete textShadow;
504 }
505 
506 bool StyleCSS3InheritedData::operator==(const StyleCSS3InheritedData &o) const
507 {
508  return shadowDataEquivalent(o) && (wordWrap == o.wordWrap)
509 #ifdef APPLE_CHANGES
510  && (userModify == o.userModify) && (textSizeAdjust == o.textSizeAdjust)
511 #endif
512  ;
513 }
514 
515 bool StyleCSS3InheritedData::shadowDataEquivalent(const StyleCSS3InheritedData &o) const
516 {
517  if ((!textShadow && o.textShadow) || (textShadow && !o.textShadow)) {
518  return false;
519  }
520  if ((textShadow && o.textShadow) && (*textShadow != *o.textShadow)) {
521  return false;
522  }
523  return true;
524 }
525 
526 StyleInheritedData::StyleInheritedData()
527  : indent(RenderStyle::initialTextIndent()), line_height(RenderStyle::initialLineHeight()),
528  style_image(RenderStyle::initialListStyleImage()),
529  font(), color(RenderStyle::initialColor()),
530  border_hspacing(RenderStyle::initialBorderHorizontalSpacing()),
531  border_vspacing(RenderStyle::initialBorderVerticalSpacing()),
532  widows(RenderStyle::initialWidows()), orphans(RenderStyle::initialOrphans()),
533  quotes(nullptr)
534 {
535 }
536 
537 StyleInheritedData::~StyleInheritedData()
538 {
539  if (quotes) {
540  quotes->deref();
541  }
542 }
543 
544 StyleInheritedData::StyleInheritedData(const StyleInheritedData &o)
545  : Shared<StyleInheritedData>(),
546  indent(o.indent), line_height(o.line_height), style_image(o.style_image),
547  font(o.font), color(o.color),
548  border_hspacing(o.border_hspacing),
549  border_vspacing(o.border_vspacing),
550  widows(o.widows), orphans(o.orphans)
551 {
552  quotes = o.quotes;
553  if (quotes) {
554  quotes->ref();
555  }
556 }
557 
558 bool StyleInheritedData::operator==(const StyleInheritedData &o) const
559 {
560  return
561  indent == o.indent &&
562  line_height == o.line_height &&
563  border_hspacing == o.border_hspacing &&
564  border_vspacing == o.border_vspacing &&
565  style_image == o.style_image &&
566  font == o.font &&
567  color == o.color &&
568  border_hspacing == o.border_hspacing &&
569  border_vspacing == o.border_vspacing &&
570  quotes == o.quotes &&
571  widows == o.widows &&
572  orphans == o.orphans;
573 
574  // doesn't work because structs are not packed
575  //return memcmp(this, &o, sizeof(*this))==0;
576 }
577 
578 RenderStyle::RenderStyle()
579 {
580 // counter++;
581  if (!_default) {
582  _default = new RenderStyle(true);
583  }
584 
585  box = _default->box;
586  visual = _default->visual;
587  background = _default->background;
588  surround = _default->surround;
589  generated = _default->generated;
590  css3NonInheritedData = _default->css3NonInheritedData;
591  css3InheritedData = _default->css3InheritedData;
592 
593  inherited = _default->inherited;
594 
595  m_svgStyle = _default->m_svgStyle;
596 
597  setBitDefaults();
598 
599  pseudoStyle = nullptr;
600 }
601 
602 RenderStyle::RenderStyle(bool)
603 {
604  // Let the font cache create its initial value.
605  // We need this because attach can call styleForElement
606  // for things with display:none parents, and then we need to be
607  // able to provide some sort of fallback font data to operate on.
608  Font::initDefault();
609 
610  setBitDefaults();
611 
612  box.init();
613  visual.init();
614  background.init();
615  surround.init();
616  generated.init();
617  css3NonInheritedData.init();
618 #ifdef APPLE_CHANGES // ### yet to be merged
619  css3NonInheritedData.access()->flexibleBox.init();
620 #endif
621  css3NonInheritedData.access()->marquee.init();
622  css3NonInheritedData.access()->borderRadius.init();
623  css3InheritedData.init();
624  inherited.init();
625 
626  m_svgStyle.init();
627 
628  pseudoStyle = nullptr;
629 }
630 
631 RenderStyle::RenderStyle(const RenderStyle &o)
632  : Shared<RenderStyle>(),
633  inherited_flags(o.inherited_flags), noninherited_flags(o.noninherited_flags),
634  box(o.box), visual(o.visual), background(o.background), surround(o.surround), generated(o.generated),
635  css3NonInheritedData(o.css3NonInheritedData), css3InheritedData(o.css3InheritedData),
636  inherited(o.inherited), pseudoStyle(nullptr), m_svgStyle(o.m_svgStyle)
637 {}
638 
639 void RenderStyle::inheritFrom(const RenderStyle *inheritParent)
640 {
641  css3InheritedData = inheritParent->css3InheritedData;
642  inherited = inheritParent->inherited;
643  inherited_flags = inheritParent->inherited_flags;
644 
645  // SVG
646  if (m_svgStyle != inheritParent->m_svgStyle) {
647  m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get());
648  }
649 
650  // Simulate ":after,:before { white-space: pre-line }"
651  if (styleType() == AFTER || styleType() == BEFORE) {
652  setWhiteSpace(PRE_LINE);
653  }
654 }
655 
656 void RenderStyle::compactWith(const RenderStyle *similarStyle)
657 {
658  if (this == similarStyle) {
659  return;
660  }
661 
662  if (box.get() != similarStyle->box.get() && box == similarStyle->box) {
663  box = similarStyle->box;
664  }
665  if (visual.get() != similarStyle->visual.get() && visual == similarStyle->visual) {
666  visual = similarStyle->visual;
667  }
668  if (background.get() != similarStyle->background.get() && background == similarStyle->background) {
669  background = similarStyle->background;
670  }
671  if (surround.get() != similarStyle->surround.get() && surround == similarStyle->surround) {
672  surround = similarStyle->surround;
673  }
674  if (generated.get() != similarStyle->generated.get() && generated == similarStyle->generated) {
675  generated = similarStyle->generated;
676  }
677  if (css3NonInheritedData.get() != similarStyle->css3NonInheritedData.get() && css3NonInheritedData == similarStyle->css3NonInheritedData) {
678  css3NonInheritedData = similarStyle->css3NonInheritedData;
679  }
680  if (css3InheritedData.get() != similarStyle->css3InheritedData.get() && css3InheritedData == similarStyle->css3InheritedData) {
681  css3InheritedData = similarStyle->css3InheritedData;
682  }
683  if (inherited.get() != similarStyle->inherited.get() && inherited == similarStyle->inherited) {
684  inherited = similarStyle->inherited;
685  }
686 }
687 
688 RenderStyle::~RenderStyle()
689 {
690  RenderStyle *ps = pseudoStyle;
691  RenderStyle *prev = nullptr;
692 
693  while (ps) {
694  prev = ps;
695  ps = ps->pseudoStyle;
696  // to prevent a double deletion.
697  // this works only because the styles below aren't really shared
698  // Dirk said we need another construct as soon as these are shared
699  prev->pseudoStyle = nullptr;
700  prev->deref();
701  }
702 }
703 
704 bool RenderStyle::operator==(const RenderStyle &o) const
705 {
706 // compare everything except the pseudoStyle pointer
707  return (inherited_flags == o.inherited_flags &&
708  noninherited_flags == o.noninherited_flags &&
709  box == o.box &&
710  visual == o.visual &&
711  background == o.background &&
712  surround == o.surround &&
713  generated == o.generated &&
714  css3NonInheritedData == o.css3NonInheritedData &&
715  css3InheritedData == o.css3InheritedData &&
716  inherited == o.inherited &&
717  m_svgStyle == o.m_svgStyle); // SVG
718 }
719 
720 enum EPseudoBit { NO_BIT = 0x0,
721  FIRST_LINE_BIT = 0x1, FIRST_LETTER_BIT = 0x2, SELECTION_BIT = 0x4,
722  BEFORE_BIT = 0x8, AFTER_BIT = 0x10, MARKER_BIT = 0x20,
723  REPLACED_BIT = 0x40
724  };
725 
726 static int pseudoBit(RenderStyle::PseudoId pseudo)
727 {
728  switch (pseudo) {
729  case RenderStyle::BEFORE:
730  return BEFORE_BIT;
731  case RenderStyle::AFTER:
732  return AFTER_BIT;
733  case RenderStyle::MARKER:
734  return MARKER_BIT;
735  case RenderStyle::REPLACED:
736  return REPLACED_BIT;
737  case RenderStyle::FIRST_LINE:
738  return FIRST_LINE_BIT;
739  case RenderStyle::FIRST_LETTER:
740  return FIRST_LETTER_BIT;
741  case RenderStyle::SELECTION:
742  return SELECTION_BIT;
743  default:
744  return NO_BIT;
745  }
746 }
747 
748 bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const
749 {
750  return (pseudoBit(pseudo) & noninherited_flags.f._pseudoBits) != 0;
751 }
752 
753 void RenderStyle::setHasPseudoStyle(PseudoId pseudo, bool b)
754 {
755  if (b) {
756  noninherited_flags.f._pseudoBits |= pseudoBit(pseudo);
757  } else {
758  noninherited_flags.f._pseudoBits &= ~(pseudoBit(pseudo));
759  }
760 }
761 
762 RenderStyle *RenderStyle::getPseudoStyle(PseudoId pid) const
763 {
764  if (!hasPseudoStyle(pid)) {
765  return nullptr;
766  }
767 
768  RenderStyle *ps = nullptr;
769  if (noninherited_flags.f._styleType == NOPSEUDO)
770  for (ps = pseudoStyle; ps; ps = ps->pseudoStyle)
771  if (ps->noninherited_flags.f._styleType == pid) {
772  break;
773  }
774  return ps;
775 }
776 
777 RenderStyle *RenderStyle::addPseudoStyle(PseudoId pid)
778 {
779  if (hasPseudoStyle(pid)) {
780  return getPseudoStyle(pid);
781  }
782 
783  RenderStyle *ps = nullptr;
784 
785  switch (pid) {
786  case FIRST_LETTER: // pseudo-elements (FIRST_LINE has a special handling)
787  case SELECTION:
788  case BEFORE:
789  case AFTER:
790  ps = new RenderStyle();
791  break;
792  default:
793  ps = new RenderStyle(*this); // use the real copy constructor to get an identical copy
794  }
795  ps->ref();
796  ps->noninherited_flags.f._styleType = pid;
797  ps->pseudoStyle = pseudoStyle;
798 
799  pseudoStyle = ps;
800 
801  setHasPseudoStyle(pid, true);
802 
803  return ps;
804 }
805 
806 void RenderStyle::removePseudoStyle(PseudoId pid)
807 {
808  RenderStyle *ps = pseudoStyle;
809  RenderStyle *prev = this;
810 
811  while (ps) {
812  if (ps->noninherited_flags.f._styleType == pid) {
813  prev->pseudoStyle = ps->pseudoStyle;
814  ps->deref();
815  return;
816  }
817  prev = ps;
818  ps = ps->pseudoStyle;
819  }
820 
821  setHasPseudoStyle(pid, false);
822 }
823 
824 bool RenderStyle::inheritedNotEqual(RenderStyle *other) const
825 {
826  return
827  (
828  inherited_flags != other->inherited_flags ||
829  inherited != other->inherited ||
830  css3InheritedData != other->css3InheritedData ||
831  m_svgStyle->inheritedNotEqual(other->m_svgStyle.get())
832  );
833 }
834 
835 /*
836  compares two styles. The result gives an idea of the action that
837  needs to be taken when replacing the old style with a new one.
838 
839  CbLayout: The containing block of the object needs a relayout.
840  Layout: the RenderObject needs a relayout after the style change
841  Visible: The change is visible, but no relayout is needed
842  NonVisible: The object does need neither repaint nor relayout after
843  the change.
844 
845  ### TODO:
846  A lot can be optimised here based on the display type, lots of
847  optimizations are unimplemented, and currently result in the
848  worst case result causing a relayout of the containing block.
849 */
850 RenderStyle::Diff RenderStyle::diff(const RenderStyle *other) const
851 {
852  if (m_svgStyle != other->m_svgStyle) {
853  return Layout;
854  }
855  // we anyway assume they are the same
856 // EDisplay _display : 5;
857 
858  // NonVisible:
859 // ECursor _cursor_style : 4;
860 // EUserInput _user_input : 2; as long as :enabled is not impl'd
861 
862 // ### this needs work to know more exactly if we need a relayout
863 // or just a repaint
864 
865 // non-inherited attributes
866 // DataRef<StyleBoxData> box;
867 // DataRef<StyleVisualData> visual;
868 // DataRef<StyleSurroundData> surround;
869 
870 // inherited attributes
871 // DataRef<StyleInheritedData> inherited;
872 
873  if (*box.get() != *other->box.get() ||
874  *visual.get() != *other->visual.get() ||
875  (*surround.get() != *other->surround.get()
876  && (other->position() == PSTATIC || other->position() != position())) ||
877  !(inherited->indent == other->inherited->indent) ||
878  !(inherited->line_height == other->inherited->line_height) ||
879  !(inherited->style_image == other->inherited->style_image) ||
880  !(inherited->font == other->inherited->font) ||
881  !(inherited->border_hspacing == other->inherited->border_hspacing) ||
882  !(inherited->border_vspacing == other->inherited->border_vspacing) ||
883  !(inherited_flags.f._visuallyOrdered == other->inherited_flags.f._visuallyOrdered) ||
884  !(inherited_flags.f._htmlHacks == other->inherited_flags.f._htmlHacks) ||
885  !(noninherited_flags.f._textOverflow == other->noninherited_flags.f._textOverflow)) {
886  return CbLayout;
887  }
888 
889  // changes causing Layout changes:
890 
891 // only for tables:
892 // _border_collapse
893 // EEmptyCell _empty_cells : 2 ;
894 // ECaptionSide _caption_side : 2;
895 // ETableLayout _table_layout : 1;
896 // EPosition _position : 2;
897 // EFloat _floating : 2;
898  if (((int)noninherited_flags.f._display) >= TABLE) {
899  if (!(inherited_flags.f._empty_cells == other->inherited_flags.f._empty_cells) ||
900  !(inherited_flags.f._caption_side == other->inherited_flags.f._caption_side) ||
901  !(inherited_flags.f._border_collapse == other->inherited_flags.f._border_collapse) ||
902  !(noninherited_flags.f._table_layout == other->noninherited_flags.f._table_layout) ||
903  !(noninherited_flags.f._position == other->noninherited_flags.f._position) ||
904  !(noninherited_flags.f._floating == other->noninherited_flags.f._floating) ||
905  !(noninherited_flags.f._flowAroundFloats == other->noninherited_flags.f._flowAroundFloats) ||
906  !(noninherited_flags.f._unicodeBidi == other->noninherited_flags.f._unicodeBidi)) {
907  return CbLayout;
908  }
909  }
910 
911 // only for lists:
912 // EListStyleType _list_style_type : 5 ;
913 // EListStylePosition _list_style_position :1;
914  if (noninherited_flags.f._display == LIST_ITEM) {
915  if (!(inherited_flags.f._list_style_type == other->inherited_flags.f._list_style_type) ||
916  !(inherited_flags.f._list_style_position == other->inherited_flags.f._list_style_position)) {
917  return Layout;
918  }
919  }
920 
921 // ### These could be better optimised
922 // ETextAlign _text_align : 3;
923 // ETextTransform _text_transform : 4;
924 // EDirection _direction : 1;
925 // EWhiteSpace _white_space : 2;
926 // EClear _clear : 2;
927  if (!(inherited_flags.f._text_align == other->inherited_flags.f._text_align) ||
928  !(inherited_flags.f._text_transform == other->inherited_flags.f._text_transform) ||
929  !(inherited_flags.f._direction == other->inherited_flags.f._direction) ||
930  !(inherited_flags.f._white_space == other->inherited_flags.f._white_space) ||
931  !(noninherited_flags.f._clear == other->noninherited_flags.f._clear)
932  ) {
933  return Layout;
934  }
935 
936  // Overflow returns a layout hint.
937  if (noninherited_flags.f._overflowX != other->noninherited_flags.f._overflowX ||
938  noninherited_flags.f._overflowY != other->noninherited_flags.f._overflowY) {
939  return Layout;
940  }
941 
942 // only for inline:
943 // EVerticalAlign _vertical_align : 4;
944 
945  if (!(noninherited_flags.f._display == INLINE) &&
946  !(noninherited_flags.f._vertical_align == other->noninherited_flags.f._vertical_align)) {
947  return Layout;
948  }
949 
950  if (*surround.get() != *other->surround.get()) {
951  assert(other->position() != PSTATIC); // this style is positioned or relatively positioned
952  if (surround->hasSamePBMData(*other->surround.get()) && // padding/border/margin are identical
953  (other->position() == PRELATIVE ||
954  (!(other->left().isAuto() && other->right().isAuto()) && // X isn't static
955  !(other->top().isAuto() && other->bottom().isAuto())))) // neither is Y
956  // therefore only the offset is different
957  {
958  return Position;
959  }
960  return Layout;
961  }
962 
963  // Visible:
964 // EVisibility _visibility : 2;
965 // int _text_decorations : 4;
966 // DataRef<StyleBackgroundData> background;
967  if (inherited->color != other->inherited->color ||
968  !(inherited_flags.f._visibility == other->inherited_flags.f._visibility) ||
969  !(inherited_flags.f._text_decorations == other->inherited_flags.f._text_decorations) ||
970  !(noninherited_flags.f._hasClip == other->noninherited_flags.f._hasClip) ||
971  visual->textDecoration != other->visual->textDecoration ||
972  *background.get() != *other->background.get() ||
973  css3NonInheritedData->opacity != other->css3NonInheritedData->opacity ||
974  !css3InheritedData->shadowDataEquivalent(*other->css3InheritedData.get())
975  ) {
976  return Visible;
977  }
978 
979  RenderStyle::Diff ch = Equal;
980  // Check for visible pseudo-changes:
981  if (hasPseudoStyle(FIRST_LINE) != other->hasPseudoStyle(FIRST_LINE)) {
982  ch = Visible;
983  } else if (hasPseudoStyle(FIRST_LINE) && other->hasPseudoStyle(FIRST_LINE)) {
984  ch = getPseudoStyle(FIRST_LINE)->diff(other->getPseudoStyle(FIRST_LINE));
985  }
986 
987  if (ch != Equal) {
988  return ch;
989  }
990 
991  // Check for visible pseudo-changes:
992  if (hasPseudoStyle(SELECTION) != other->hasPseudoStyle(SELECTION)) {
993  ch = Visible;
994  } else if (hasPseudoStyle(SELECTION) && other->hasPseudoStyle(SELECTION)) {
995  ch = getPseudoStyle(SELECTION)->diff(other->getPseudoStyle(SELECTION));
996  }
997 
998  return ch;
999 }
1000 
1001 RenderStyle *RenderStyle::_default = nullptr;
1002 
1003 void RenderStyle::cleanup()
1004 {
1005  delete _default;
1006  _default = nullptr;
1007 }
1008 
1009 void RenderStyle::setPaletteColor(QPalette::ColorGroup g, QPalette::ColorRole r, const QColor &c)
1010 {
1011  visual.access()->palette.setColor(g, r, c);
1012 }
1013 
1014 void RenderStyle::adjustBackgroundLayers()
1015 {
1016  // https://www.w3.org/TR/css3-background/#layering
1017  if (backgroundLayers()->next()) {
1018  // First we cull out backgroundLayers that have no image property set.
1019  accessBackgroundLayers()->cullEmptyLayers();
1020 
1021  // Next we repeat patterns into layers that don't have some properties set.
1022  accessBackgroundLayers()->fillUnsetProperties();
1023  }
1024 }
1025 
1026 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
1027 {
1028  StyleVisualData *data = visual.access();
1029  data->clip.top = top;
1030  data->clip.right = right;
1031  data->clip.bottom = bottom;
1032  data->clip.left = left;
1033 }
1034 
1035 void RenderStyle::setQuotes(DOM::QuotesValueImpl *q)
1036 {
1037  DOM::QuotesValueImpl *t = inherited->quotes;
1038  inherited.access()->quotes = q;
1039  if (q) {
1040  q->ref();
1041  }
1042  if (t) {
1043  t->deref();
1044  }
1045 }
1046 
1047 QString RenderStyle::openQuote(int level) const
1048 {
1049  if (inherited->quotes) {
1050  return inherited->quotes->openQuote(level);
1051  } else if (level > 1) {
1052  return "'";
1053  } else {
1054  return "\""; // 0 is default quotes
1055  }
1056 }
1057 
1058 QString RenderStyle::closeQuote(int level) const
1059 {
1060  if (inherited->quotes) {
1061  return inherited->quotes->closeQuote(level);
1062  } else if (level) {
1063  return "'";
1064  } else {
1065  return "\""; // 0 is default quotes
1066  }
1067 }
1068 
1069 void RenderStyle::addContent(CachedObject *o)
1070 {
1071  if (!o) {
1072  return; // The object is null. Nothing to do. Just bail.
1073  }
1074 
1075  StyleGeneratedData *t_generated = generated.access();
1076 
1077  ContentData *lastContent = t_generated->content;
1078  while (lastContent && lastContent->_nextContent) {
1079  lastContent = lastContent->_nextContent;
1080  }
1081 
1082  ContentData *newContentData = new ContentData;
1083 
1084  if (lastContent) {
1085  lastContent->_nextContent = newContentData;
1086  } else {
1087  t_generated->content = newContentData;
1088  }
1089 
1090  // o->ref();
1091  newContentData->_content.object = o;
1092  newContentData->_contentType = CONTENT_OBJECT;
1093 }
1094 
1095 void RenderStyle::addContent(DOM::DOMStringImpl *s)
1096 {
1097  if (!s) {
1098  return; // The string is null. Nothing to do. Just bail.
1099  }
1100 
1101  StyleGeneratedData *t_generated = generated.access();
1102 
1103  ContentData *lastContent = t_generated->content;
1104  while (lastContent && lastContent->_nextContent) {
1105  lastContent = lastContent->_nextContent;
1106  }
1107 
1108  if (lastContent) {
1109  if (lastContent->_contentType == CONTENT_TEXT) {
1110  // We can augment the existing string and share this ContentData node.
1111  DOMStringImpl *oldStr = lastContent->_content.text;
1112  DOMStringImpl *newStr = oldStr->copy();
1113  newStr->ref();
1114  oldStr->deref();
1115  newStr->append(s);
1116  lastContent->_content.text = newStr;
1117  return;
1118  }
1119  }
1120 
1121  ContentData *newContentData = new ContentData;
1122 
1123  if (lastContent) {
1124  lastContent->_nextContent = newContentData;
1125  } else {
1126  t_generated->content = newContentData;
1127  }
1128 
1129  newContentData->_content.text = s;
1130  newContentData->_content.text->ref();
1131  newContentData->_contentType = CONTENT_TEXT;
1132 
1133 }
1134 
1135 void RenderStyle::addContent(DOM::CounterImpl *c)
1136 {
1137  if (!c) {
1138  return;
1139  }
1140 
1141  StyleGeneratedData *t_generated = generated.access();
1142 
1143  ContentData *lastContent = t_generated->content;
1144  while (lastContent && lastContent->_nextContent) {
1145  lastContent = lastContent->_nextContent;
1146  }
1147 
1148  ContentData *newContentData = new ContentData;
1149 
1150  if (lastContent) {
1151  lastContent->_nextContent = newContentData;
1152  } else {
1153  t_generated->content = newContentData;
1154  }
1155 
1156  c->ref();
1157  newContentData->_content.counter = c;
1158  newContentData->_contentType = CONTENT_COUNTER;
1159 }
1160 
1161 void RenderStyle::addContent(EQuoteContent q)
1162 {
1163  if (q == NO_QUOTE) {
1164  return;
1165  }
1166 
1167  StyleGeneratedData *t_generated = generated.access();
1168 
1169  ContentData *lastContent = t_generated->content;
1170  while (lastContent && lastContent->_nextContent) {
1171  lastContent = lastContent->_nextContent;
1172  }
1173 
1174  ContentData *newContentData = new ContentData;
1175 
1176  if (lastContent) {
1177  lastContent->_nextContent = newContentData;
1178  } else {
1179  t_generated->content = newContentData;
1180  }
1181 
1182  newContentData->_content.quote = q;
1183  newContentData->_contentType = CONTENT_QUOTE;
1184 }
1185 
1186 // content: normal is the same as having no content at all
1187 void RenderStyle::setContentNormal()
1188 {
1189  if (generated->content != nullptr) {
1190  delete generated->content;
1191  generated.access()->content = nullptr;
1192  }
1193 }
1194 
1195 // content: none, add an empty content node
1196 void RenderStyle::setContentNone()
1197 {
1198  setContentNormal();
1199  generated.access()->content = new ContentData;
1200 }
1201 
1202 void RenderStyle::setContentData(ContentData *data)
1203 {
1204  if (data != generated->content) {
1205  if (data) {
1206  generated.access()->content = new ContentData(*data);
1207  } else {
1208  generated.access()->content = nullptr;
1209  }
1210  }
1211 }
1212 
1213 ContentData::ContentData(const ContentData &o) : _contentType(o._contentType)
1214 {
1215  switch (_contentType) {
1216  case CONTENT_OBJECT:
1217  _content.object = o._content.object;
1218  break;
1219  case CONTENT_TEXT:
1220  _content.text = o._content.text;
1221  _content.text->ref();
1222  break;
1223  case CONTENT_COUNTER:
1224  _content.counter = o._content.counter;
1225  _content.counter->ref();
1226  break;
1227  case CONTENT_QUOTE:
1228  _content.quote = o._content.quote;
1229  break;
1230  case CONTENT_NONE:
1231  default:
1232  break;
1233  }
1234 
1235  _nextContent = o._nextContent ? new ContentData(*o._nextContent) : nullptr;
1236 }
1237 
1238 ContentData::~ContentData()
1239 {
1240  clearContent();
1241 }
1242 
1243 void ContentData::clearContent()
1244 {
1245  delete _nextContent;
1246  _nextContent = nullptr;
1247 
1248  switch (_contentType) {
1249  case CONTENT_OBJECT:
1250  _content.object = nullptr;
1251  break;
1252  case CONTENT_TEXT:
1253  _content.text->deref();
1254  _content.text = nullptr;
1255  break;
1256  case CONTENT_COUNTER:
1257  _content.counter->deref();
1258  _content.counter = nullptr;
1259  break;
1260  case CONTENT_QUOTE:
1261  _content.quote = NO_QUOTE;
1262  break;
1263  default:
1264  ;
1265  }
1266 }
1267 
1268 void RenderStyle::setTextShadow(ShadowData *val, bool add)
1269 {
1270  StyleCSS3InheritedData *css3Data = css3InheritedData.access();
1271  if (!add) {
1272  delete css3Data->textShadow;
1273  css3Data->textShadow = val;
1274  return;
1275  }
1276 
1277  ShadowData *last = css3Data->textShadow;
1278  while (last->next) {
1279  last = last->next;
1280  }
1281  last->next = val;
1282 }
1283 
1284 ShadowData::ShadowData(const ShadowData &o)
1285  : x(o.x), y(o.y), blur(o.blur), color(o.color)
1286 {
1287  next = o.next ? new ShadowData(*o.next) : nullptr;
1288 }
1289 
1290 bool ShadowData::operator==(const ShadowData &o) const
1291 {
1292  if ((next && !o.next) || (!next && o.next) ||
1293  (next && o.next && *next != *o.next)) {
1294  return false;
1295  }
1296 
1297  return x == o.x && y == o.y && blur == o.blur && color == o.color;
1298 }
1299 
1300 static bool hasCounter(const DOM::DOMString &c, CSSValueListImpl *l)
1301 {
1302  int len = l->length();
1303  for (int i = 0; i < len; i++) {
1304  CounterActImpl *ca = static_cast<CounterActImpl *>(l->item(i));
1305  Q_ASSERT(ca != nullptr);
1306  if (ca->m_counter == c) {
1307  return true;
1308  }
1309  }
1310  return false;
1311 }
1312 
1313 bool RenderStyle::hasCounterReset(const DOM::DOMString &c) const
1314 {
1315  if (generated->counter_reset) {
1316  return hasCounter(c, generated->counter_reset);
1317  } else {
1318  return false;
1319  }
1320 }
1321 
1322 bool RenderStyle::hasCounterIncrement(const DOM::DOMString &c) const
1323 {
1324  if (generated->counter_increment) {
1325  return hasCounter(c, generated->counter_increment);
1326  } else {
1327  return false;
1328  }
1329 }
1330 
1331 short RenderStyle::counterReset(const DOM::DOMString &c) const
1332 {
1333  if (generated->counter_reset) {
1334  int len = generated->counter_reset->length();
1335  int value = 0;
1336  // Return the last matching counter-reset
1337  for (int i = 0; i < len; i++) {
1338  CounterActImpl *ca = static_cast<CounterActImpl *>(generated->counter_reset->item(i));
1339  Q_ASSERT(ca != nullptr);
1340  if (ca->m_counter == c) {
1341  value = ca->m_value;
1342  }
1343  }
1344  return value;
1345  } else {
1346  return 0;
1347  }
1348 }
1349 
1350 short RenderStyle::counterIncrement(const DOM::DOMString &c) const
1351 {
1352  if (generated->counter_increment) {
1353  int len = generated->counter_increment->length();
1354  int value = 0;
1355  // Return the sum of matching counter-increments
1356  for (int i = 0; i < len; i++) {
1357  CounterActImpl *ca = static_cast<CounterActImpl *>(generated->counter_increment->item(i));
1358  Q_ASSERT(ca != nullptr);
1359  if (ca->m_counter == c) {
1360  value += ca->m_value;
1361  }
1362  }
1363  return value;
1364  } else {
1365  return 0;
1366  }
1367 }
1368 
1369 void RenderStyle::setCounterReset(CSSValueListImpl *l)
1370 {
1371  CSSValueListImpl *t = generated->counter_reset;
1372  generated.access()->counter_reset = l;
1373  if (l) {
1374  l->ref();
1375  }
1376  if (t) {
1377  t->deref();
1378  }
1379 }
1380 
1381 void RenderStyle::setCounterIncrement(CSSValueListImpl *l)
1382 {
1383  CSSValueListImpl *t = generated->counter_increment;
1384  generated.access()->counter_increment = l;
1385  if (l) {
1386  l->ref();
1387  }
1388  if (t) {
1389  t->deref();
1390  }
1391 }
1392 
1393 #ifdef ENABLE_DUMP
1394 
1395 static QString describeFont(const QFont &f)
1396 {
1397  QString res = '\'' + f.family() + "' ";
1398 
1399  if (f.pointSize() > 0) {
1400  res += QString::number(f.pointSize()) + "pt";
1401  } else {
1402  res += QString::number(f.pixelSize()) + "px";
1403  }
1404 
1405  if (f.bold()) {
1406  res += " bold";
1407  }
1408  if (f.italic()) {
1409  res += " italic";
1410  }
1411  if (f.underline()) {
1412  res += " underline";
1413  }
1414  if (f.overline()) {
1415  res += " overline";
1416  }
1417  if (f.strikeOut()) {
1418  res += " strikeout";
1419  }
1420  return res;
1421 }
1422 
1423 QString RenderStyle::createDiff(const RenderStyle &parent) const
1424 {
1425  QString res;
1426  if (color().isValid() && parent.color() != color()) {
1427  res += " [color=" + color().name() + ']';
1428  }
1429  if (backgroundColor().isValid() && parent.backgroundColor() != backgroundColor()) {
1430  res += " [bgcolor=" + backgroundColor().name() + ']';
1431  }
1432  if (parent.font() != font()) {
1433  res += " [font=" + describeFont(font()) + ']';
1434  }
1435 
1436  return res;
1437 }
1438 #endif
1439 
1440 RenderPageStyle::RenderPageStyle() : next(nullptr), m_pageType(ANY_PAGE)
1441 {
1442 }
1443 
1444 RenderPageStyle::~RenderPageStyle()
1445 {
1446  delete next;
1447 }
1448 
1449 RenderPageStyle *RenderPageStyle::getPageStyle(PageType type)
1450 {
1451  RenderPageStyle *ps = nullptr;
1452  for (ps = this; ps; ps = ps->next)
1453  if (ps->m_pageType == type) {
1454  break;
1455  }
1456  return ps;
1457 }
1458 
1459 RenderPageStyle *RenderPageStyle::addPageStyle(PageType type)
1460 {
1461  RenderPageStyle *ps = getPageStyle(type);
1462 
1463  if (!ps) {
1464  ps = new RenderPageStyle(*this); // use the real copy constructor to get an identical copy
1465  ps->m_pageType = type;
1466 
1467  ps->next = next;
1468  next = ps;
1469  }
1470 
1471  return ps;
1472 }
1473 
1474 void RenderPageStyle::removePageStyle(PageType type)
1475 {
1476  RenderPageStyle *ps = next;
1477  RenderPageStyle *prev = this;
1478 
1479  while (ps) {
1480  if (ps->m_pageType == type) {
1481  prev->next = ps->next;
1482  delete ps;
1483  return;
1484  }
1485  prev = ps;
1486  ps = ps->next;
1487  }
1488 }
int pixelSize() const const
This file is part of the HTML rendering engine for KDE.
MESSAGECORE_EXPORT KMime::Content * next(KMime::Content *node, bool allowChildren=true)
bool bold() const const
bool italic() const const
QString number(int n, int base)
QString pattern(Mode mode=Reading)
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
bool underline() const const
bool overline() const const
This library provides a full-featured HTML parser and widget.
QString family() const const
bool isValid(QStringView ifopt)
bool strikeOut() const const
int pointSize() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:08 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.