summaryrefslogtreecommitdiffstats
path: root/khtml/rendering/render_style.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'khtml/rendering/render_style.cpp')
-rw-r--r--khtml/rendering/render_style.cpp1300
1 files changed, 1300 insertions, 0 deletions
diff --git a/khtml/rendering/render_style.cpp b/khtml/rendering/render_style.cpp
new file mode 100644
index 000000000..936964b98
--- /dev/null
+++ b/khtml/rendering/render_style.cpp
@@ -0,0 +1,1300 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2002-2003 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2002-2005 Apple Computer, Inc.
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xml/dom_stringimpl.h"
+#include "css/cssstyleselector.h"
+#include "css/css_valueimpl.h"
+#include "render_style.h"
+
+#include "kdebug.h"
+
+using namespace khtml;
+using namespace DOM;
+
+/* CSS says Fixed for the default padding value, but we treat variable as 0 padding anyways, and like
+ * this is works fine for table paddings aswell
+ */
+StyleSurroundData::StyleSurroundData()
+ : margin( Fixed ), padding( Variable )
+{
+}
+
+StyleSurroundData::StyleSurroundData(const StyleSurroundData& o )
+ : Shared<StyleSurroundData>(),
+ offset( o.offset ), margin( o.margin ), padding( o.padding ),
+ border( o.border )
+{
+}
+
+bool StyleSurroundData::operator==(const StyleSurroundData& o) const
+{
+ return offset==o.offset && margin==o.margin &&
+ padding==o.padding && border==o.border;
+}
+
+StyleBoxData::StyleBoxData()
+ : z_index( 0 ), z_auto( true )
+{
+ min_width = min_height = RenderStyle::initialMinSize();
+ max_width = max_height = RenderStyle::initialMaxSize();
+ box_sizing = RenderStyle::initialBoxSizing();
+}
+
+StyleBoxData::StyleBoxData(const StyleBoxData& o )
+ : Shared<StyleBoxData>(),
+ width( o.width ), height( o.height ),
+ min_width( o.min_width ), max_width( o.max_width ),
+ min_height ( o.min_height ), max_height( o.max_height ),
+ box_sizing( o.box_sizing),
+ z_index( o.z_index ), z_auto( o.z_auto )
+{
+}
+
+bool StyleBoxData::operator==(const StyleBoxData& o) const
+{
+ return
+ width == o.width &&
+ height == o.height &&
+ min_width == o.min_width &&
+ max_width == o.max_width &&
+ min_height == o.min_height &&
+ max_height == o.max_height &&
+ box_sizing == o.box_sizing &&
+ z_index == o.z_index &&
+ z_auto == o.z_auto;
+}
+
+StyleVisualData::StyleVisualData()
+ : textDecoration(RenderStyle::initialTextDecoration()),
+ palette( QApplication::palette() )
+{
+}
+
+StyleVisualData::~StyleVisualData() {
+}
+
+StyleVisualData::StyleVisualData(const StyleVisualData& o )
+ : Shared<StyleVisualData>(),
+ clip( o.clip ), textDecoration(o.textDecoration),
+ palette( o.palette )
+{
+}
+
+BackgroundLayer::BackgroundLayer()
+:m_image(RenderStyle::initialBackgroundImage()),
+ m_bgAttachment(RenderStyle::initialBackgroundAttachment()),
+ m_bgClip(RenderStyle::initialBackgroundClip()),
+ m_bgOrigin(RenderStyle::initialBackgroundOrigin()),
+ m_bgRepeat(RenderStyle::initialBackgroundRepeat()),
+ m_backgroundSize(RenderStyle::initialBackgroundSize()),
+ m_next(0)
+{
+ m_imageSet = m_attachmentSet = m_clipSet = m_originSet =
+ m_repeatSet = m_xPosSet = m_yPosSet = m_backgroundSizeSet = false;
+}
+
+BackgroundLayer::BackgroundLayer(const BackgroundLayer& o)
+{
+ m_next = o.m_next ? new BackgroundLayer(*o.m_next) : 0;
+ m_image = o.m_image;
+ m_xPosition = o.m_xPosition;
+ m_yPosition = o.m_yPosition;
+ m_bgAttachment = o.m_bgAttachment;
+ m_bgClip = o.m_bgClip;
+ m_bgOrigin = o.m_bgOrigin;
+ m_bgRepeat = o.m_bgRepeat;
+ m_backgroundSize = o.m_backgroundSize;
+ m_imageSet = o.m_imageSet;
+ m_attachmentSet = o.m_attachmentSet;
+ m_clipSet = o.m_clipSet;
+ m_originSet = o.m_originSet;
+ m_repeatSet = o.m_repeatSet;
+ m_xPosSet = o.m_xPosSet;
+ m_yPosSet = o.m_yPosSet;
+ m_backgroundSizeSet = o.m_backgroundSizeSet;
+}
+
+BackgroundLayer::~BackgroundLayer()
+{
+ delete m_next;
+}
+
+BackgroundLayer& BackgroundLayer::operator=(const BackgroundLayer& o) {
+ if (m_next != o.m_next) {
+ delete m_next;
+ m_next = o.m_next ? new BackgroundLayer(*o.m_next) : 0;
+ }
+
+ m_image = o.m_image;
+ m_xPosition = o.m_xPosition;
+ m_yPosition = o.m_yPosition;
+ m_bgAttachment = o.m_bgAttachment;
+ m_bgClip = o.m_bgClip;
+ m_bgOrigin = o.m_bgOrigin;
+ m_bgRepeat = o.m_bgRepeat;
+ m_backgroundSize = o.m_backgroundSize;
+
+ m_imageSet = o.m_imageSet;
+ m_attachmentSet = o.m_attachmentSet;
+ m_originSet = o.m_originSet;
+ m_repeatSet = o.m_repeatSet;
+ m_xPosSet = o.m_xPosSet;
+ m_yPosSet = o.m_yPosSet;
+ m_backgroundSizeSet = o.m_backgroundSizeSet;
+
+ return *this;
+}
+
+bool BackgroundLayer::operator==(const BackgroundLayer& o) const {
+ return m_image == o.m_image && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition &&
+ m_bgAttachment == o.m_bgAttachment && m_bgClip == o.m_bgClip && m_bgOrigin == o.m_bgOrigin && m_bgRepeat == o.m_bgRepeat &&
+ m_backgroundSize.width == o.m_backgroundSize.width && m_backgroundSize.height == o.m_backgroundSize.height &&
+ m_imageSet == o.m_imageSet && m_attachmentSet == o.m_attachmentSet && m_repeatSet == o.m_repeatSet &&
+ m_xPosSet == o.m_xPosSet && m_yPosSet == o.m_yPosSet && m_backgroundSizeSet == o.m_backgroundSizeSet &&
+ ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
+}
+
+void BackgroundLayer::fillUnsetProperties()
+{
+ BackgroundLayer* curr;
+ for (curr = this; curr && curr->isBackgroundImageSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_image = pattern->m_image;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isBackgroundXPositionSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_xPosition = pattern->m_xPosition;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isBackgroundYPositionSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_yPosition = pattern->m_yPosition;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isBackgroundAttachmentSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_bgAttachment = pattern->m_bgAttachment;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isBackgroundClipSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_bgClip = pattern->m_bgClip;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isBackgroundOriginSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_bgOrigin = pattern->m_bgOrigin;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isBackgroundRepeatSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_bgRepeat = pattern->m_bgRepeat;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+
+ for (curr = this; curr && curr->isBackgroundSizeSet(); curr = curr->next());
+ if (curr && curr != this) {
+ // We need to fill in the remaining values with the pattern specified.
+ for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+ curr->m_backgroundSize = pattern->m_backgroundSize;
+ pattern = pattern->next();
+ if (pattern == curr || !pattern)
+ pattern = this;
+ }
+ }
+}
+
+void BackgroundLayer::cullEmptyLayers()
+{
+ BackgroundLayer *next;
+ for (BackgroundLayer *p = this; p; p = next) {
+ next = p->m_next;
+ if (next && !next->isBackgroundImageSet() &&
+ !next->isBackgroundXPositionSet() && !next->isBackgroundYPositionSet() &&
+ !next->isBackgroundAttachmentSet() && !next->isBackgroundClipSet() &&
+ !next->isBackgroundOriginSet() && !next->isBackgroundRepeatSet() &&
+ !next->isBackgroundSizeSet()) {
+ delete next;
+ p->m_next = 0;
+ break;
+ }
+ }
+}
+
+StyleBackgroundData::StyleBackgroundData()
+{}
+
+StyleBackgroundData::StyleBackgroundData(const StyleBackgroundData& o)
+ : Shared<StyleBackgroundData>(), m_background(o.m_background), m_outline(o.m_outline)
+{}
+
+bool StyleBackgroundData::operator==(const StyleBackgroundData& o) const
+{
+ return m_background == o.m_background && m_color == o.m_color && m_outline == o.m_outline;
+}
+
+StyleGeneratedData::StyleGeneratedData() : Shared<StyleGeneratedData>(), content(0), counter_reset(0), counter_increment(0) {}
+
+StyleGeneratedData::~StyleGeneratedData()
+{
+ if (counter_reset) counter_reset->deref();
+ if (counter_increment) counter_increment->deref();
+ delete content;
+}
+
+StyleGeneratedData::StyleGeneratedData(const StyleGeneratedData& o)
+ : Shared<StyleGeneratedData>(), content(0),
+ counter_reset(o.counter_reset), counter_increment(o.counter_increment)
+{
+ if (o.content) content = new ContentData(*o.content);
+ if (counter_reset) counter_reset->ref();
+ if (counter_increment) counter_increment->ref();
+}
+
+bool StyleGeneratedData::contentDataEquivalent(const StyleGeneratedData* otherStyle) const
+{
+ ContentData* c1 = content;
+ ContentData* c2 = otherStyle->content;
+
+ while (c1 && c2) {
+ if (c1->_contentType != c2->_contentType)
+ return false;
+ if (c1->_contentType == CONTENT_TEXT) {
+ DOM::DOMString c1Str(c1->_content.text);
+ DOM::DOMString c2Str(c2->_content.text);
+ if (c1Str != c2Str)
+ return false;
+ }
+ else if (c1->_contentType == CONTENT_OBJECT) {
+ if (c1->_content.object != c2->_content.object)
+ return false;
+ }
+ else if (c1->_contentType == CONTENT_COUNTER) {
+ if (c1->_content.counter != c2->_content.counter)
+ return false;
+ }
+ else if (c1->_contentType == CONTENT_QUOTE) {
+ if (c1->_content.quote != c2->_content.quote)
+ return false;
+ }
+
+ c1 = c1->_nextContent;
+ c2 = c2->_nextContent;
+ }
+
+ return !c1 && !c2;
+}
+
+static bool compareCounterActList(const CSSValueListImpl* ca, const CSSValueListImpl* cb) {
+ // weeee....
+ CSSValueListImpl* a = const_cast<CSSValueListImpl*>(ca);
+ CSSValueListImpl* b = const_cast<CSSValueListImpl*>(cb);
+
+ if (!a && !b) return true;
+ if (!a || !b) return false;
+ if (a->length() != b->length()) return false;
+ for(uint i=0; i< a->length(); i++) {
+ CSSValueImpl *ai = a->item(i);
+ CSSValueImpl *bi = b->item(i);
+ assert(ai && ai->cssValueType() == CSSValue::CSS_CUSTOM);
+ assert(bi && bi->cssValueType() == CSSValue::CSS_CUSTOM);
+ CounterActImpl* caa = static_cast<CounterActImpl*>(ai);
+ CounterActImpl* cab = static_cast<CounterActImpl*>(bi);
+ if (caa->value() != cab->value()) return false;
+ if (caa->counter() != cab->counter()) return false;
+ }
+ return true;
+}
+
+bool StyleGeneratedData::counterDataEquivalent(const StyleGeneratedData* otherStyle) const
+{
+ return compareCounterActList(counter_reset, otherStyle->counter_reset) &&
+ compareCounterActList(counter_increment, otherStyle->counter_increment);
+}
+
+bool StyleGeneratedData::operator==(const StyleGeneratedData& o) const
+{
+ return contentDataEquivalent(&o) && counterDataEquivalent(&o);
+}
+
+StyleMarqueeData::StyleMarqueeData()
+{
+ increment = RenderStyle::initialMarqueeIncrement();
+ speed = RenderStyle::initialMarqueeSpeed();
+ direction = RenderStyle::initialMarqueeDirection();
+ behavior = RenderStyle::initialMarqueeBehavior();
+ loops = RenderStyle::initialMarqueeLoopCount();
+}
+
+StyleMarqueeData::StyleMarqueeData(const StyleMarqueeData& o)
+:Shared<StyleMarqueeData>(), increment(o.increment), speed(o.speed), loops(o.loops),
+ behavior(o.behavior), direction(o.direction)
+{}
+
+bool StyleMarqueeData::operator==(const StyleMarqueeData& o) const
+{
+ return (increment == o.increment && speed == o.speed && direction == o.direction &&
+ behavior == o.behavior && loops == o.loops);
+}
+
+StyleCSS3NonInheritedData::StyleCSS3NonInheritedData()
+:Shared<StyleCSS3NonInheritedData>()
+, opacity(RenderStyle::initialOpacity())
+{
+}
+
+StyleCSS3NonInheritedData::StyleCSS3NonInheritedData(const StyleCSS3NonInheritedData& o)
+:Shared<StyleCSS3NonInheritedData>(),
+ opacity(o.opacity),
+#ifdef APPLE_CHANGES
+ flexibleBox(o.flexibleBox),
+#endif
+ marquee(o.marquee)
+{
+}
+
+bool StyleCSS3NonInheritedData::operator==(const StyleCSS3NonInheritedData& o) const
+{
+ return
+ opacity == o.opacity &&
+#ifdef APPLE_CHANGES
+ flexibleBox == o.flexibleBox &&
+#endif
+ marquee == o.marquee;
+}
+
+StyleCSS3InheritedData::StyleCSS3InheritedData()
+:Shared<StyleCSS3InheritedData>(), textShadow(0)
+#ifdef APPLE_CHANGES
+, userModify(READ_ONLY), textSizeAdjust(RenderStyle::initialTextSizeAdjust())
+#endif
+{
+
+}
+
+StyleCSS3InheritedData::StyleCSS3InheritedData(const StyleCSS3InheritedData& o)
+:Shared<StyleCSS3InheritedData>()
+{
+ textShadow = o.textShadow ? new ShadowData(*o.textShadow) : 0;
+#ifdef APPLE_CHANGES
+ userModify = o.userModify;
+ textSizeAdjust = o.textSizeAdjust;
+#endif
+}
+
+StyleCSS3InheritedData::~StyleCSS3InheritedData()
+{
+ delete textShadow;
+}
+
+bool StyleCSS3InheritedData::operator==(const StyleCSS3InheritedData& o) const
+{
+ return shadowDataEquivalent(o)
+#ifdef APPLE_CHANGES
+ && (userModify == o.userModify) && (textSizeAdjust == o.textSizeAdjust)
+#endif
+ ;
+}
+
+bool StyleCSS3InheritedData::shadowDataEquivalent(const StyleCSS3InheritedData& o) const
+{
+ if (!textShadow && o.textShadow || textShadow && !o.textShadow)
+ return false;
+ if (textShadow && o.textShadow && (*textShadow != *o.textShadow))
+ return false;
+ return true;
+}
+
+StyleInheritedData::StyleInheritedData()
+ : indent( RenderStyle::initialTextIndent() ), line_height( RenderStyle::initialLineHeight() ),
+ style_image( RenderStyle::initialListStyleImage() ),
+ font(), color( RenderStyle::initialColor() ),
+ border_hspacing( RenderStyle::initialBorderHorizontalSpacing() ),
+ border_vspacing( RenderStyle::initialBorderVerticalSpacing() ),
+ widows( RenderStyle::initialWidows() ), orphans( RenderStyle::initialOrphans() ),
+ quotes(0)
+{
+}
+
+StyleInheritedData::~StyleInheritedData()
+{
+ if (quotes) quotes->deref();
+}
+
+StyleInheritedData::StyleInheritedData(const StyleInheritedData& o )
+ : Shared<StyleInheritedData>(),
+ indent( o.indent ), line_height( o.line_height ), style_image( o.style_image ),
+ font( o.font ), color( o.color ),
+ border_hspacing( o.border_hspacing ),
+ border_vspacing( o.border_vspacing ),
+ widows(o.widows), orphans(o.orphans)
+{
+ quotes = o.quotes;
+ if (quotes) quotes->ref();
+}
+
+bool StyleInheritedData::operator==(const StyleInheritedData& o) const
+{
+ return
+ indent == o.indent &&
+ line_height == o.line_height &&
+ border_hspacing == o.border_hspacing &&
+ border_vspacing == o.border_vspacing &&
+ style_image == o.style_image &&
+ font == o.font &&
+ color == o.color &&
+ border_hspacing == o.border_hspacing &&
+ border_vspacing == o.border_vspacing &&
+ quotes == o.quotes &&
+ widows == o.widows &&
+ orphans == o.orphans ;
+
+ // doesn't work because structs are not packed
+ //return memcmp(this, &o, sizeof(*this))==0;
+}
+
+RenderStyle::RenderStyle()
+{
+// counter++;
+ if (!_default)
+ _default = new RenderStyle(true);
+
+ box = _default->box;
+ visual = _default->visual;
+ background = _default->background;
+ surround = _default->surround;
+ generated = _default->generated;
+ css3NonInheritedData = _default->css3NonInheritedData;
+ css3InheritedData = _default->css3InheritedData;
+
+ inherited = _default->inherited;
+
+ setBitDefaults();
+
+ pseudoStyle = 0;
+}
+
+RenderStyle::RenderStyle(bool)
+{
+ setBitDefaults();
+
+ box.init();
+ visual.init();
+ background.init();
+ surround.init();
+ generated.init();
+ css3NonInheritedData.init();
+#ifdef APPLE_CHANGES // ### yet to be merged
+ css3NonInheritedData.access()->flexibleBox.init();
+#endif
+ css3NonInheritedData.access()->marquee.init();
+ css3InheritedData.init();
+ inherited.init();
+
+ pseudoStyle = 0;
+}
+
+RenderStyle::RenderStyle(const RenderStyle& o)
+ : Shared<RenderStyle>(),
+ inherited_flags( o.inherited_flags ), noninherited_flags( o.noninherited_flags ),
+ box( o.box ), visual( o.visual ), background( o.background ), surround( o.surround ), generated(o.generated),
+ css3NonInheritedData( o.css3NonInheritedData ), css3InheritedData( o.css3InheritedData ),
+ inherited( o.inherited ), pseudoStyle( 0 )
+{}
+
+void RenderStyle::inheritFrom(const RenderStyle* inheritParent)
+{
+ css3InheritedData = inheritParent->css3InheritedData;
+ inherited = inheritParent->inherited;
+ inherited_flags = inheritParent->inherited_flags;
+
+ // Simulate ":after,:before { white-space: pre-line }"
+ if (styleType() == AFTER || styleType() == BEFORE)
+ setWhiteSpace(PRE_LINE);
+}
+
+RenderStyle::~RenderStyle()
+{
+ RenderStyle *ps = pseudoStyle;
+ RenderStyle *prev = 0;
+
+ while (ps) {
+ prev = ps;
+ ps = ps->pseudoStyle;
+ // to prevent a double deletion.
+ // this works only because the styles below aren't really shared
+ // Dirk said we need another construct as soon as these are shared
+ prev->pseudoStyle = 0;
+ prev->deref();
+ }
+}
+
+bool RenderStyle::operator==(const RenderStyle& o) const
+{
+// compare everything except the pseudoStyle pointer
+ return (inherited_flags == o.inherited_flags &&
+ noninherited_flags == o.noninherited_flags &&
+ box == o.box &&
+ visual == o.visual &&
+ background == o.background &&
+ surround == o.surround &&
+ generated == o.generated &&
+ css3NonInheritedData == o.css3NonInheritedData &&
+ css3InheritedData == o.css3InheritedData &&
+ inherited == o.inherited);
+}
+
+enum EPseudoBit { NO_BIT = 0x0,
+ FIRST_LINE_BIT = 0x1, FIRST_LETTER_BIT = 0x2, SELECTION_BIT = 0x4,
+ BEFORE_BIT = 0x8, AFTER_BIT = 0x10, MARKER_BIT = 0x20,
+ REPLACED_BIT = 0x40
+ };
+
+static int pseudoBit(RenderStyle::PseudoId pseudo)
+{
+ switch (pseudo) {
+ case RenderStyle::BEFORE:
+ return BEFORE_BIT;
+ case RenderStyle::AFTER:
+ return AFTER_BIT;
+ case RenderStyle::MARKER:
+ return MARKER_BIT;
+ case RenderStyle::REPLACED:
+ return REPLACED_BIT;
+ case RenderStyle::FIRST_LINE:
+ return FIRST_LINE_BIT;
+ case RenderStyle::FIRST_LETTER:
+ return FIRST_LETTER_BIT;
+ case RenderStyle::SELECTION:
+ return SELECTION_BIT;
+ default:
+ return NO_BIT;
+ }
+}
+
+bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const
+{
+ return (pseudoBit(pseudo) & noninherited_flags.f._pseudoBits) != 0;
+}
+
+void RenderStyle::setHasPseudoStyle(PseudoId pseudo, bool b)
+{
+ if (b)
+ noninherited_flags.f._pseudoBits |= pseudoBit(pseudo);
+ else
+ noninherited_flags.f._pseudoBits &= ~(pseudoBit(pseudo));
+}
+
+RenderStyle* RenderStyle::getPseudoStyle(PseudoId pid) const
+{
+ if (!hasPseudoStyle(pid)) return 0;
+
+ RenderStyle *ps = 0;
+ if (noninherited_flags.f._styleType==NOPSEUDO)
+ for (ps = pseudoStyle; ps; ps = ps->pseudoStyle)
+ if (ps->noninherited_flags.f._styleType==pid)
+ break;
+ return ps;
+}
+
+RenderStyle* RenderStyle::addPseudoStyle(PseudoId pid)
+{
+ if (hasPseudoStyle(pid)) return getPseudoStyle(pid);
+
+ RenderStyle *ps = 0;
+
+ switch (pid) {
+ case FIRST_LETTER: // pseudo-elements (FIRST_LINE has a special handling)
+ case SELECTION:
+ case BEFORE:
+ case AFTER:
+ ps = new RenderStyle();
+ break;
+ default:
+ ps = new RenderStyle(*this); // use the real copy constructor to get an identical copy
+ }
+ ps->ref();
+ ps->noninherited_flags.f._styleType = pid;
+ ps->pseudoStyle = pseudoStyle;
+
+ pseudoStyle = ps;
+
+ setHasPseudoStyle(pid, true);
+
+ return ps;
+}
+
+void RenderStyle::removePseudoStyle(PseudoId pid)
+{
+ RenderStyle *ps = pseudoStyle;
+ RenderStyle *prev = this;
+
+ while (ps) {
+ if (ps->noninherited_flags.f._styleType==pid) {
+ prev->pseudoStyle = ps->pseudoStyle;
+ ps->deref();
+ return;
+ }
+ prev = ps;
+ ps = ps->pseudoStyle;
+ }
+
+ setHasPseudoStyle(pid, false);
+}
+
+
+bool RenderStyle::inheritedNotEqual( RenderStyle *other ) const
+{
+ return
+ (
+ inherited_flags != other->inherited_flags ||
+ inherited != other->inherited ||
+ css3InheritedData != other->css3InheritedData
+ );
+}
+
+/*
+ compares two styles. The result gives an idea of the action that
+ needs to be taken when replacing the old style with a new one.
+
+ CbLayout: The containing block of the object needs a relayout.
+ Layout: the RenderObject needs a relayout after the style change
+ Visible: The change is visible, but no relayout is needed
+ NonVisible: The object does need neither repaint nor relayout after
+ the change.
+
+ ### TODO:
+ A lot can be optimised here based on the display type, lots of
+ optimisations are unimplemented, and currently result in the
+ worst case result causing a relayout of the containing block.
+*/
+RenderStyle::Diff RenderStyle::diff( const RenderStyle *other ) const
+{
+ // we anyway assume they are the same
+// EDisplay _display : 5;
+
+ // NonVisible:
+// ECursor _cursor_style : 4;
+// EUserInput _user_input : 2; as long as :enabled is not impl'd
+
+// ### this needs work to know more exactly if we need a relayout
+// or just a repaint
+
+// non-inherited attributes
+// DataRef<StyleBoxData> box;
+// DataRef<StyleVisualData> visual;
+// DataRef<StyleSurroundData> surround;
+
+// inherited attributes
+// DataRef<StyleInheritedData> inherited;
+
+ if ( *box.get() != *other->box.get() ||
+ *visual.get() != *other->visual.get() ||
+ (*surround.get() != *other->surround.get()
+ && (other->position() == STATIC || other->position() != position())) ||
+ !(inherited->indent == other->inherited->indent) ||
+ !(inherited->line_height == other->inherited->line_height) ||
+ !(inherited->style_image == other->inherited->style_image) ||
+ !(inherited->font == other->inherited->font) ||
+ !(inherited->border_hspacing == other->inherited->border_hspacing) ||
+ !(inherited->border_vspacing == other->inherited->border_vspacing) ||
+ !(inherited_flags.f._visuallyOrdered == other->inherited_flags.f._visuallyOrdered) ||
+ !(inherited_flags.f._htmlHacks == other->inherited_flags.f._htmlHacks) ||
+ !(noninherited_flags.f._textOverflow == other->noninherited_flags.f._textOverflow) )
+ return CbLayout;
+
+ // changes causing Layout changes:
+
+// only for tables:
+// _border_collapse
+// EEmptyCell _empty_cells : 2 ;
+// ECaptionSide _caption_side : 2;
+// ETableLayout _table_layout : 1;
+// EPosition _position : 2;
+// EFloat _floating : 2;
+ if ( ((int)noninherited_flags.f._display) >= TABLE ) {
+ if ( !(inherited_flags.f._empty_cells == other->inherited_flags.f._empty_cells) ||
+ !(inherited_flags.f._caption_side == other->inherited_flags.f._caption_side) ||
+ !(inherited_flags.f._border_collapse == other->inherited_flags.f._border_collapse) ||
+ !(noninherited_flags.f._table_layout == other->noninherited_flags.f._table_layout) ||
+ !(noninherited_flags.f._position == other->noninherited_flags.f._position) ||
+ !(noninherited_flags.f._floating == other->noninherited_flags.f._floating) ||
+ !(noninherited_flags.f._flowAroundFloats == other->noninherited_flags.f._flowAroundFloats) ||
+ !(noninherited_flags.f._unicodeBidi == other->noninherited_flags.f._unicodeBidi) )
+ return CbLayout;
+ }
+
+// only for lists:
+// EListStyleType _list_style_type : 5 ;
+// EListStylePosition _list_style_position :1;
+ if (noninherited_flags.f._display == LIST_ITEM ) {
+ if ( !(inherited_flags.f._list_style_type == other->inherited_flags.f._list_style_type) ||
+ !(inherited_flags.f._list_style_position == other->inherited_flags.f._list_style_position) )
+ return Layout;
+ }
+
+// ### These could be better optimised
+// ETextAlign _text_align : 3;
+// ETextTransform _text_transform : 4;
+// EDirection _direction : 1;
+// EWhiteSpace _white_space : 2;
+// EClear _clear : 2;
+ if ( !(inherited_flags.f._text_align == other->inherited_flags.f._text_align) ||
+ !(inherited_flags.f._text_transform == other->inherited_flags.f._text_transform) ||
+ !(inherited_flags.f._direction == other->inherited_flags.f._direction) ||
+ !(inherited_flags.f._white_space == other->inherited_flags.f._white_space) ||
+ !(noninherited_flags.f._clear == other->noninherited_flags.f._clear)
+ )
+ return Layout;
+
+ // Overflow returns a layout hint.
+ if (noninherited_flags.f._overflowX != other->noninherited_flags.f._overflowX ||
+ noninherited_flags.f._overflowY != other->noninherited_flags.f._overflowY)
+ return Layout;
+
+// only for inline:
+// EVerticalAlign _vertical_align : 4;
+
+ if ( !(noninherited_flags.f._display == INLINE) &&
+ !(noninherited_flags.f._vertical_align == other->noninherited_flags.f._vertical_align) )
+ return Layout;
+
+ if (*surround.get() != *other->surround.get()) {
+ assert( other->position() != STATIC ); // this style is positioned or relatively positioned
+ if ( surround->hasSamePBMData(*other->surround.get()) && // padding/border/margin are identical
+ (other->position() == RELATIVE ||
+ !(other->left().isVariable() && other->right().isVariable()) && // X isn't static
+ !(other->top().isVariable() && other->bottom().isVariable()) )) // neither is Y
+ // therefore only the offset is different
+ return Position;
+ return Layout;
+ }
+
+ // Visible:
+// EVisibility _visibility : 2;
+// int _text_decorations : 4;
+// DataRef<StyleBackgroundData> background;
+ if (inherited->color != other->inherited->color ||
+ !(inherited_flags.f._visibility == other->inherited_flags.f._visibility) ||
+ !(inherited_flags.f._text_decorations == other->inherited_flags.f._text_decorations) ||
+ !(noninherited_flags.f._hasClip == other->noninherited_flags.f._hasClip) ||
+ visual->textDecoration != other->visual->textDecoration ||
+ *background.get() != *other->background.get() ||
+ css3NonInheritedData->opacity != other->css3NonInheritedData->opacity ||
+ !css3InheritedData->shadowDataEquivalent(*other->css3InheritedData.get())
+ )
+ return Visible;
+
+ RenderStyle::Diff ch = Equal;
+ // Check for visible pseudo-changes:
+ if (hasPseudoStyle(FIRST_LINE) != other->hasPseudoStyle(FIRST_LINE))
+ ch = Visible;
+ else
+ if (hasPseudoStyle(FIRST_LINE) && other->hasPseudoStyle(FIRST_LINE))
+ ch = getPseudoStyle(FIRST_LINE)->diff(other->getPseudoStyle(FIRST_LINE));
+
+ if (ch != Equal) return ch;
+
+ // Check for visible pseudo-changes:
+ if (hasPseudoStyle(SELECTION) != other->hasPseudoStyle(SELECTION))
+ ch = Visible;
+ else
+ if (hasPseudoStyle(SELECTION) && other->hasPseudoStyle(SELECTION))
+ ch = getPseudoStyle(SELECTION)->diff(other->getPseudoStyle(SELECTION));
+
+ return ch;
+}
+
+
+RenderStyle* RenderStyle::_default = 0;
+
+void RenderStyle::cleanup()
+{
+ delete _default;
+ _default = 0;
+}
+
+void RenderStyle::setPaletteColor(QPalette::ColorGroup g, QColorGroup::ColorRole r, const QColor& c)
+{
+ visual.access()->palette.setColor(g,r,c);
+}
+
+void RenderStyle::adjustBackgroundLayers()
+{
+ if (backgroundLayers()->next()) {
+ // First we cull out layers that have no properties set.
+ accessBackgroundLayers()->cullEmptyLayers();
+
+ // Next we repeat patterns into layers that don't have some properties set.
+ accessBackgroundLayers()->fillUnsetProperties();
+ }
+}
+
+void RenderStyle::setClip( Length top, Length right, Length bottom, Length left )
+{
+ StyleVisualData *data = visual.access();
+ data->clip.top = top;
+ data->clip.right = right;
+ data->clip.bottom = bottom;
+ data->clip.left = left;
+}
+
+void RenderStyle::setQuotes(DOM::QuotesValueImpl* q)
+{
+ DOM::QuotesValueImpl *t = inherited->quotes;
+ inherited.access()->quotes = q;
+ if (q) q->ref();
+ if (t) t->deref();
+}
+
+QString RenderStyle::openQuote(int level) const
+{
+ if (inherited->quotes)
+ return inherited->quotes->openQuote(level);
+ else
+ return "\""; // 0 is default quotes
+}
+
+QString RenderStyle::closeQuote(int level) const
+{
+ if (inherited->quotes)
+ return inherited->quotes->closeQuote(level);
+ else
+ return "\""; // 0 is default quotes
+}
+
+void RenderStyle::addContent(CachedObject* o)
+{
+ if (!o)
+ return; // The object is null. Nothing to do. Just bail.
+
+ StyleGeneratedData *t_generated = generated.access();
+
+ ContentData* lastContent = t_generated->content;
+ while (lastContent && lastContent->_nextContent)
+ lastContent = lastContent->_nextContent;
+
+ ContentData* newContentData = new ContentData;
+
+ if (lastContent)
+ lastContent->_nextContent = newContentData;
+ else
+ t_generated->content = newContentData;
+
+ // o->ref();
+ newContentData->_content.object = o;
+ newContentData->_contentType = CONTENT_OBJECT;
+}
+
+void RenderStyle::addContent(DOM::DOMStringImpl* s)
+{
+ if (!s)
+ return; // The string is null. Nothing to do. Just bail.
+
+ StyleGeneratedData *t_generated = generated.access();
+
+ ContentData* lastContent = t_generated->content;
+ while (lastContent && lastContent->_nextContent)
+ lastContent = lastContent->_nextContent;
+
+ if (lastContent) {
+ if (lastContent->_contentType == CONTENT_TEXT) {
+ // We can augment the existing string and share this ContentData node.
+ DOMStringImpl* oldStr = lastContent->_content.text;
+ DOMStringImpl* newStr = oldStr->copy();
+ newStr->ref();
+ oldStr->deref();
+ newStr->append(s);
+ lastContent->_content.text = newStr;
+ return;
+ }
+ }
+
+ ContentData* newContentData = new ContentData;
+
+ if (lastContent)
+ lastContent->_nextContent = newContentData;
+ else
+ t_generated->content = newContentData;
+
+ newContentData->_content.text = s;
+ newContentData->_content.text->ref();
+ newContentData->_contentType = CONTENT_TEXT;
+
+}
+
+void RenderStyle::addContent(DOM::CounterImpl* c)
+{
+ if (!c)
+ return;
+
+ StyleGeneratedData *t_generated = generated.access();
+
+ ContentData* lastContent = t_generated->content;
+ while (lastContent && lastContent->_nextContent)
+ lastContent = lastContent->_nextContent;
+
+ ContentData* newContentData = new ContentData;
+
+ if (lastContent)
+ lastContent->_nextContent = newContentData;
+ else
+ t_generated->content = newContentData;
+
+ c->ref();
+ newContentData->_content.counter = c;
+ newContentData->_contentType = CONTENT_COUNTER;
+}
+
+void RenderStyle::addContent(EQuoteContent q)
+{
+ if (q == NO_QUOTE)
+ return;
+
+ StyleGeneratedData *t_generated = generated.access();
+
+ ContentData* lastContent = t_generated->content;
+ while (lastContent && lastContent->_nextContent)
+ lastContent = lastContent->_nextContent;
+
+ ContentData* newContentData = new ContentData;
+
+ if (lastContent)
+ lastContent->_nextContent = newContentData;
+ else
+ t_generated->content = newContentData;
+
+ newContentData->_content.quote = q;
+ newContentData->_contentType = CONTENT_QUOTE;
+}
+
+// content: normal is the same as having no content at all
+void RenderStyle::setContentNormal() {
+ if (generated->content != 0) {
+ delete generated->content;
+ generated.access()->content = 0;
+ }
+}
+
+// content: none, add an empty content node
+void RenderStyle::setContentNone() {
+ setContentNormal();
+ generated.access()->content = new ContentData;
+}
+
+void RenderStyle::setContentData(ContentData *data) {
+ if (data != generated->content) {
+ if (data)
+ generated.access()->content = new ContentData(*data);
+ else
+ generated.access()->content = 0;
+ }
+}
+
+ContentData::ContentData(const ContentData& o) : _contentType(o._contentType)
+{
+ switch (_contentType) {
+ case CONTENT_OBJECT:
+ _content.object = o._content.object;
+ break;
+ case CONTENT_TEXT:
+ _content.text = o._content.text;
+ _content.text->ref();
+ break;
+ case CONTENT_COUNTER:
+ _content.counter = o._content.counter;
+ _content.counter->ref();
+ break;
+ case CONTENT_QUOTE:
+ _content.quote = o._content.quote;
+ break;
+ case CONTENT_NONE:
+ default:
+ break;
+ }
+
+ _nextContent = o._nextContent ? new ContentData(*o._nextContent) : 0;
+}
+
+ContentData::~ContentData()
+{
+ clearContent();
+}
+
+void ContentData::clearContent()
+{
+ delete _nextContent;
+ _nextContent = 0;
+
+ switch (_contentType)
+ {
+ case CONTENT_OBJECT:
+ _content.object = 0;
+ break;
+ case CONTENT_TEXT:
+ _content.text->deref();
+ _content.text = 0;
+ break;
+ case CONTENT_COUNTER:
+ _content.counter->deref();
+ _content.counter = 0;
+ break;
+ case CONTENT_QUOTE:
+ _content.quote = NO_QUOTE;
+ break;
+ default:
+ ;
+ }
+}
+
+void RenderStyle::setTextShadow(ShadowData* val, bool add)
+{
+ StyleCSS3InheritedData* css3Data = css3InheritedData.access();
+ if (!add) {
+ delete css3Data->textShadow;
+ css3Data->textShadow = val;
+ return;
+ }
+
+ ShadowData* last = css3Data->textShadow;
+ while (last->next) last = last->next;
+ last->next = val;
+}
+
+ShadowData::ShadowData(const ShadowData& o)
+:x(o.x), y(o.y), blur(o.blur), color(o.color)
+{
+ next = o.next ? new ShadowData(*o.next) : 0;
+}
+
+bool ShadowData::operator==(const ShadowData& o) const
+{
+ if ((next && !o.next) || (!next && o.next) ||
+ (next && o.next && *next != *o.next))
+ return false;
+
+ return x == o.x && y == o.y && blur == o.blur && color == o.color;
+}
+
+static bool hasCounter(const DOM::DOMString& c, CSSValueListImpl *l)
+{
+ int len = l->length();
+ for(int i=0; i<len; i++) {
+ CounterActImpl* ca = static_cast<CounterActImpl*>(l->item(i));
+ Q_ASSERT(ca != 0);
+ if (ca->m_counter == c) return true;
+ }
+ return false;
+}
+
+bool RenderStyle::hasCounterReset(const DOM::DOMString& c) const
+{
+ if (generated->counter_reset)
+ return hasCounter(c, generated->counter_reset);
+ else
+ return false;
+}
+
+bool RenderStyle::hasCounterIncrement(const DOM::DOMString& c) const
+{
+ if (generated->counter_increment)
+ return hasCounter(c, generated->counter_increment);
+ else
+ return false;
+}
+
+static short readCounter(const DOM::DOMString& c, CSSValueListImpl *l)
+{
+ int len = l->length();
+ for(int i=0; i<len; i++) {
+ CounterActImpl* ca = static_cast<CounterActImpl*>(l->item(i));
+ Q_ASSERT(ca != 0);
+ if (ca->m_counter == c) return ca->m_value;
+ }
+ return 0;
+}
+
+short RenderStyle::counterReset(const DOM::DOMString& c) const
+{
+ if (generated->counter_reset)
+ return readCounter(c, generated->counter_reset);
+ else
+ return 0;
+}
+
+short RenderStyle::counterIncrement(const DOM::DOMString& c) const
+{
+ if (generated->counter_increment)
+ return readCounter(c, generated->counter_increment);
+ else
+ return 0;
+}
+
+void RenderStyle::setCounterReset(CSSValueListImpl *l)
+{
+ CSSValueListImpl *t = generated->counter_reset;
+ generated.access()->counter_reset = l;
+ if (l) l->ref();
+ if (t) t->deref();
+}
+
+void RenderStyle::setCounterIncrement(CSSValueListImpl *l)
+{
+ CSSValueListImpl *t = generated->counter_increment;
+ generated.access()->counter_increment = l;
+ if (l) l->ref();
+ if (t) t->deref();
+}
+
+#ifdef ENABLE_DUMP
+
+static QString describeFont( const QFont &f)
+{
+ QString res = "'" + f.family() + "' ";
+
+ if ( f.pointSize() > 0)
+ res += QString::number( f.pointSize() ) + "pt";
+ else
+ res += QString::number( f.pixelSize() ) + "px";
+
+ if ( f.bold() )
+ res += " bold";
+ if ( f.italic() )
+ res += " italic";
+ if ( f.underline() )
+ res += " underline";
+ if ( f.overline() )
+ res += " overline";
+ if ( f.strikeOut() )
+ res += " strikeout";
+ return res;
+}
+
+QString RenderStyle::createDiff( const RenderStyle &parent ) const
+{
+ QString res;
+ if ( color().isValid() && parent.color() != color() )
+ res += " [color=" + color().name() + "]";
+ if ( backgroundColor().isValid() && parent.backgroundColor() != backgroundColor() )
+ res += " [bgcolor=" + backgroundColor().name() + "]";
+ if ( parent.font() != font() )
+ res += " [font=" + describeFont( font() ) + "]";
+
+ return res;
+}
+#endif
+
+RenderPageStyle::RenderPageStyle() : next(0), m_pageType(ANY_PAGE)
+{
+}
+
+RenderPageStyle::~RenderPageStyle()
+{
+ delete next;
+}
+
+RenderPageStyle* RenderPageStyle::getPageStyle(PageType type)
+{
+ RenderPageStyle *ps = 0;
+ for (ps = this; ps; ps = ps->next)
+ if (ps->m_pageType==type)
+ break;
+ return ps;
+}
+
+RenderPageStyle* RenderPageStyle::addPageStyle(PageType type)
+{
+ RenderPageStyle *ps = getPageStyle(type);
+
+ if (!ps)
+ {
+ ps = new RenderPageStyle(*this); // use the real copy constructor to get an identical copy
+ ps->m_pageType = type;
+
+ ps->next = next;
+ next = ps;
+ }
+
+ return ps;
+}
+
+void RenderPageStyle::removePageStyle(PageType type)
+{
+ RenderPageStyle *ps = next;
+ RenderPageStyle *prev = this;
+
+ while (ps) {
+ if (ps->m_pageType==type) {
+ prev->next = ps->next;
+ delete ps;
+ return;
+ }
+ prev = ps;
+ ps = ps->next;
+ }
+}