Reviewed by Darin.
authorbdakin <bdakin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Oct 2006 23:15:31 +0000 (23:15 +0000)
committerbdakin <bdakin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Oct 2006 23:15:31 +0000 (23:15 +0000)
        Initial implementation of CSS2 counters. See http://
        bugs.webkit.org/show_bug.cgi?id=4980 for more details.

        * WebCore.xcodeproj/project.pbxproj:
        * css/CSSComputedStyleDeclaration.cpp:
        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Return
        the increment/reset list now that this is implemented.
        * css/CSSPrimitiveValue.cpp:
        (WebCore::CSSPrimitiveValue::cssText):
        * css/Counter.h:
        (WebCore::Counter::Counter):
        (WebCore::Counter::~Counter):
        (WebCore::Counter::identifier):
        (WebCore::Counter::listStyle):
        (WebCore::Counter::separator):
        (WebCore::Counter::listStyleNumber):
        (WebCore::Counter::setIdentifier):
        (WebCore::Counter::setListStyle):
        (WebCore::Counter::setSeparator):
        * css/cssparser.cpp:
        (WebCore::CSSParser::addProperty): Take care of reset/increment
        (WebCore::CSSParser::parseValue):
        (WebCore::CSSParser::parseContent): content can now take counters
        (WebCore::CSSParser::parseCounterContent): Parse counter() and
        counters()
        (WebCore::CSSParser::parseCounter): Parse counter-reset and
        counter-increment
        * css/cssparser.h:
        * css/cssstyleselector.cpp:
        (WebCore::CSSStyleSelector::matchUARules):
        (WebCore::CSSStyleSelector::applyProperty):
        * platform/PlatformString.h:
        * platform/String.cpp:
        (WebCore::String::insert): Implemented a version of insert that
        accepts a UChar* and a length.
        * platform/StringImpl.cpp:
        (WebCore::StringImpl::insert): Same as above.
        * platform/StringImpl.h:
        * rendering/CounterListItem.h: Added.
        * rendering/CounterNode.cpp: Added.
        (WebCore::CounterNode::CounterNode):
        (WebCore::CounterNode::insertAfter):
        (WebCore::CounterNode::removeChild):
        (WebCore::CounterNode::remove):
        (WebCore::CounterNode::setUsesSeparator):
        (WebCore::CounterNode::recountAndGetNext):
        (WebCore::CounterNode::recountTree):
        (WebCore::CounterNode::setSelfDirty):
        (WebCore::CounterNode::setParentDirty):
        * rendering/CounterNode.h: Added.
        (WebCore::CounterNode::~CounterNode):
        (WebCore::CounterNode::parent):
        (WebCore::CounterNode::previousSibling):
        (WebCore::CounterNode::nextSibling):
        (WebCore::CounterNode::firstChild):
        (WebCore::CounterNode::lastChild):
        (WebCore::CounterNode::value):
        (WebCore::CounterNode::setValue):
        (WebCore::CounterNode::count):
        (WebCore::CounterNode::setCount):
        (WebCore::CounterNode::setHasSeparator):
        (WebCore::CounterNode::isReset):
        (WebCore::CounterNode::hasSeparator):
        (WebCore::CounterNode::willNeedLayout):
        (WebCore::CounterNode::setWillNeedLayout):
        (WebCore::CounterNode::isRoot):
        (WebCore::CounterNode::setRenderer):
        (WebCore::CounterNode::renderer):
        * rendering/CounterResetNode.cpp: Added.
        (WebCore::CounterResetNode::CounterResetNode):
        (WebCore::CounterResetNode::insertAfter):
        (WebCore::CounterResetNode::removeChild):
        (WebCore::CounterResetNode::recountAndGetNext):
        (WebCore::CounterResetNode::setParentDirty):
        (WebCore::CounterResetNode::updateTotal):
        * rendering/CounterResetNode.h: Added.
        (WebCore::CounterResetNode::firstChild):
        (WebCore::CounterResetNode::lastChild):
        (WebCore::CounterResetNode::isReset):
        (WebCore::CounterResetNode::total):
        * rendering/RenderContainer.cpp:
        (WebCore::RenderContainer::updatePseudoChildForObject): Account for
        counter content.
        * rendering/RenderCounter.cpp: Added.
        (WebCore::RenderCounter::RenderCounter):
        (WebCore::RenderCounter::layout):
        (WebCore::toRoman):
        (WebCore::toLetterString):
        (WebCore::toHebrew):
        (WebCore::RenderCounter::convertValueToType):
        (WebCore::RenderCounter::calcMinMaxWidth):
        * rendering/RenderCounter.h: Added.
        (WebCore::RenderCounter::renderName):
        (WebCore::RenderCounter::isCounter):
        * rendering/RenderObject.cpp:
        (WebCore::getRenderObjectsToCounterNodeMaps): Maps RenderObjects to
        maps of CounterNodes
        (WebCore::RenderObject::RenderObject):
        (WebCore::RenderObject::destroy): Destroy the maps.
        (WebCore::RenderObject::findCounter): Finds/creates counters.
        * rendering/RenderObject.h:
        (WebCore::RenderObject::isCounter):
        * rendering/RenderStyle.cpp:
        (WebCore::StyleVisualData::StyleVisualData):
        (WebCore::RenderStyle::arenaDelete):
        (WebCore::RenderStyle::RenderStyle):
        (WebCore::RenderStyle::diff):
        (WebCore::RenderStyle::setContent):
        (WebCore::ContentData::clearContent):
        (WebCore::RenderStyle::counterDataEquivalent):
        (WebCore::hasCounter):
        (WebCore::RenderStyle::hasCounterReset):
        (WebCore::RenderStyle::hasCounterIncrement):
        (WebCore::readCounter):
        (WebCore::RenderStyle::counterReset):
        (WebCore::RenderStyle::counterIncrement):
        * rendering/RenderStyle.h:
        (WebCore::StyleVisualData::operator==):
        (WebCore::CounterData::CounterData):
        (WebCore::CounterData::identifier):
        (WebCore::CounterData::listStyle):
        (WebCore::CounterData::separator):
        (WebCore::ContentData::contentCounter):
        (WebCore::ContentData::):
        (WebCore::RenderStyle::counterIncrement):
        (WebCore::RenderStyle::counterReset):
        (WebCore::RenderStyle::setCounterIncrement):
        (WebCore::RenderStyle::setCounterReset):
        (WebCore::RenderStyle::setCounterResetList):
        (WebCore::RenderStyle::setCounterIncrementList):
        (WebCore::RenderStyle::counterResetValueList):
        (WebCore::RenderStyle::counterIncrementValueList):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@16721 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
WebCore/ChangeLog
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/css/CSSComputedStyleDeclaration.cpp
WebCore/css/CSSPrimitiveValue.cpp
WebCore/css/Counter.h
WebCore/css/cssparser.cpp
WebCore/css/cssparser.h
WebCore/css/cssstyleselector.cpp
WebCore/platform/PlatformString.h
WebCore/platform/String.cpp
WebCore/platform/StringImpl.cpp
WebCore/platform/StringImpl.h
WebCore/rendering/CounterListItem.h [new file with mode: 0644]
WebCore/rendering/CounterNode.cpp [new file with mode: 0644]
WebCore/rendering/CounterNode.h [new file with mode: 0644]
WebCore/rendering/CounterResetNode.cpp [new file with mode: 0644]
WebCore/rendering/CounterResetNode.h [new file with mode: 0644]
WebCore/rendering/RenderContainer.cpp
WebCore/rendering/RenderCounter.cpp [new file with mode: 0644]
WebCore/rendering/RenderCounter.h [new file with mode: 0644]
WebCore/rendering/RenderObject.cpp
WebCore/rendering/RenderObject.h
WebCore/rendering/RenderStyle.cpp
WebCore/rendering/RenderStyle.h

index 87ca2aaf34ec97e896e9e9739f70192e28399b4d..e9b1d34cecfd86cacf02a2bf6e747b2344cc9afd 100644 (file)
@@ -1,3 +1,140 @@
+2006-10-02  Beth Dakin  <bdakin@apple.com>
+
+        Reviewed by Darin.
+
+        Initial implementation of CSS2 counters. See http://
+        bugs.webkit.org/show_bug.cgi?id=4980 for more details.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSComputedStyleDeclaration.cpp: 
+        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Return 
+        the increment/reset list now that this is implemented.
+        * css/CSSPrimitiveValue.cpp:
+        (WebCore::CSSPrimitiveValue::cssText): 
+        * css/Counter.h:
+        (WebCore::Counter::Counter):
+        (WebCore::Counter::~Counter):
+        (WebCore::Counter::identifier):
+        (WebCore::Counter::listStyle):
+        (WebCore::Counter::separator):
+        (WebCore::Counter::listStyleNumber):
+        (WebCore::Counter::setIdentifier):
+        (WebCore::Counter::setListStyle):
+        (WebCore::Counter::setSeparator):
+        * css/cssparser.cpp:
+        (WebCore::CSSParser::addProperty): Take care of reset/increment
+        (WebCore::CSSParser::parseValue):
+        (WebCore::CSSParser::parseContent): content can now take counters
+        (WebCore::CSSParser::parseCounterContent): Parse counter() and 
+        counters()
+        (WebCore::CSSParser::parseCounter): Parse counter-reset and 
+        counter-increment
+        * css/cssparser.h:
+        * css/cssstyleselector.cpp:
+        (WebCore::CSSStyleSelector::matchUARules):
+        (WebCore::CSSStyleSelector::applyProperty):
+        * platform/PlatformString.h:
+        * platform/String.cpp:
+        (WebCore::String::insert): Implemented a version of insert that 
+        accepts a UChar* and a length.
+        * platform/StringImpl.cpp:
+        (WebCore::StringImpl::insert): Same as above.
+        * platform/StringImpl.h:
+        * rendering/CounterListItem.h: Added.
+        * rendering/CounterNode.cpp: Added.
+        (WebCore::CounterNode::CounterNode):
+        (WebCore::CounterNode::insertAfter):
+        (WebCore::CounterNode::removeChild):
+        (WebCore::CounterNode::remove):
+        (WebCore::CounterNode::setUsesSeparator):
+        (WebCore::CounterNode::recountAndGetNext):
+        (WebCore::CounterNode::recountTree):
+        (WebCore::CounterNode::setSelfDirty):
+        (WebCore::CounterNode::setParentDirty):
+        * rendering/CounterNode.h: Added.
+        (WebCore::CounterNode::~CounterNode):
+        (WebCore::CounterNode::parent):
+        (WebCore::CounterNode::previousSibling):
+        (WebCore::CounterNode::nextSibling):
+        (WebCore::CounterNode::firstChild):
+        (WebCore::CounterNode::lastChild):
+        (WebCore::CounterNode::value):
+        (WebCore::CounterNode::setValue):
+        (WebCore::CounterNode::count):
+        (WebCore::CounterNode::setCount):
+        (WebCore::CounterNode::setHasSeparator):
+        (WebCore::CounterNode::isReset):
+        (WebCore::CounterNode::hasSeparator):
+        (WebCore::CounterNode::willNeedLayout):
+        (WebCore::CounterNode::setWillNeedLayout):
+        (WebCore::CounterNode::isRoot):
+        (WebCore::CounterNode::setRenderer):
+        (WebCore::CounterNode::renderer):
+        * rendering/CounterResetNode.cpp: Added.
+        (WebCore::CounterResetNode::CounterResetNode):
+        (WebCore::CounterResetNode::insertAfter):
+        (WebCore::CounterResetNode::removeChild):
+        (WebCore::CounterResetNode::recountAndGetNext):
+        (WebCore::CounterResetNode::setParentDirty):
+        (WebCore::CounterResetNode::updateTotal):
+        * rendering/CounterResetNode.h: Added.
+        (WebCore::CounterResetNode::firstChild):
+        (WebCore::CounterResetNode::lastChild):
+        (WebCore::CounterResetNode::isReset):
+        (WebCore::CounterResetNode::total):
+        * rendering/RenderContainer.cpp:
+        (WebCore::RenderContainer::updatePseudoChildForObject): Account for 
+        counter content.
+        * rendering/RenderCounter.cpp: Added.
+        (WebCore::RenderCounter::RenderCounter):
+        (WebCore::RenderCounter::layout):
+        (WebCore::toRoman):
+        (WebCore::toLetterString):
+        (WebCore::toHebrew):
+        (WebCore::RenderCounter::convertValueToType):
+        (WebCore::RenderCounter::calcMinMaxWidth):
+        * rendering/RenderCounter.h: Added.
+        (WebCore::RenderCounter::renderName):
+        (WebCore::RenderCounter::isCounter):
+        * rendering/RenderObject.cpp:
+        (WebCore::getRenderObjectsToCounterNodeMaps): Maps RenderObjects to 
+        maps of CounterNodes
+        (WebCore::RenderObject::RenderObject):
+        (WebCore::RenderObject::destroy): Destroy the maps.
+        (WebCore::RenderObject::findCounter): Finds/creates counters.
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::isCounter):
+        * rendering/RenderStyle.cpp:
+        (WebCore::StyleVisualData::StyleVisualData):
+        (WebCore::RenderStyle::arenaDelete):
+        (WebCore::RenderStyle::RenderStyle):
+        (WebCore::RenderStyle::diff):
+        (WebCore::RenderStyle::setContent):
+        (WebCore::ContentData::clearContent):
+        (WebCore::RenderStyle::counterDataEquivalent):
+        (WebCore::hasCounter):
+        (WebCore::RenderStyle::hasCounterReset):
+        (WebCore::RenderStyle::hasCounterIncrement):
+        (WebCore::readCounter):
+        (WebCore::RenderStyle::counterReset):
+        (WebCore::RenderStyle::counterIncrement):
+        * rendering/RenderStyle.h:
+        (WebCore::StyleVisualData::operator==):
+        (WebCore::CounterData::CounterData):
+        (WebCore::CounterData::identifier):
+        (WebCore::CounterData::listStyle):
+        (WebCore::CounterData::separator):
+        (WebCore::ContentData::contentCounter):
+        (WebCore::ContentData::):
+        (WebCore::RenderStyle::counterIncrement):
+        (WebCore::RenderStyle::counterReset):
+        (WebCore::RenderStyle::setCounterIncrement):
+        (WebCore::RenderStyle::setCounterReset):
+        (WebCore::RenderStyle::setCounterResetList):
+        (WebCore::RenderStyle::setCounterIncrementList):
+        (WebCore::RenderStyle::counterResetValueList):
+        (WebCore::RenderStyle::counterIncrementValueList):
+
 2006-10-02  Adele Peterson  <adele@apple.com>
 
         Reviewed by Adam.
index aaa14f96fcde2e9446ab8a2051da0291e6597ddf..ed2bb4305ca5ad3e74b31257f180f2d48943aa5a 100644 (file)
                938E666209F09B87008A48EC /* JSHTMLCanvasElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 938E666109F09B87008A48EC /* JSHTMLCanvasElement.h */; };
                938E683C09F0BD7B008A48EC /* GraphicsTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 938E683B09F0BD7A008A48EC /* GraphicsTypes.h */; };
                938E685409F0BE04008A48EC /* GraphicsTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 938E685309F0BE04008A48EC /* GraphicsTypes.cpp */; };
+               9392F1420AD185F400691BD4 /* RenderCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F1410AD185F400691BD4 /* RenderCounter.h */; };
+               9392F1440AD185FE00691BD4 /* RenderCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9392F1430AD185FE00691BD4 /* RenderCounter.cpp */; };
+               9392F1460AD1860C00691BD4 /* CounterResetNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F1450AD1860C00691BD4 /* CounterResetNode.h */; };
+               9392F14A0AD1861300691BD4 /* CounterResetNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9392F1490AD1861300691BD4 /* CounterResetNode.cpp */; };
+               9392F14C0AD1861B00691BD4 /* CounterNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F14B0AD1861B00691BD4 /* CounterNode.h */; };
+               9392F1500AD1862300691BD4 /* CounterNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9392F14F0AD1862300691BD4 /* CounterNode.cpp */; };
+               9392F1520AD1862B00691BD4 /* CounterListItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F1510AD1862B00691BD4 /* CounterListItem.h */; };
                939885C308B7E3D100E707C4 /* EventNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 939885C108B7E3D100E707C4 /* EventNames.cpp */; };
                939885C408B7E3D100E707C4 /* EventNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 939885C208B7E3D100E707C4 /* EventNames.h */; };
                93A1EAA00A5634C9006960A0 /* ImageDocumentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 93A1EA9F0A5634C9006960A0 /* ImageDocumentMac.mm */; };
                938E666109F09B87008A48EC /* JSHTMLCanvasElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSHTMLCanvasElement.h; sourceTree = "<group>"; };
                938E683B09F0BD7A008A48EC /* GraphicsTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphicsTypes.h; sourceTree = "<group>"; };
                938E685309F0BE04008A48EC /* GraphicsTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsTypes.cpp; sourceTree = "<group>"; };
+               9392F1410AD185F400691BD4 /* RenderCounter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RenderCounter.h; sourceTree = "<group>"; };
+               9392F1430AD185FE00691BD4 /* RenderCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderCounter.cpp; sourceTree = "<group>"; };
+               9392F1450AD1860C00691BD4 /* CounterResetNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CounterResetNode.h; sourceTree = "<group>"; };
+               9392F1490AD1861300691BD4 /* CounterResetNode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CounterResetNode.cpp; sourceTree = "<group>"; };
+               9392F14B0AD1861B00691BD4 /* CounterNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CounterNode.h; sourceTree = "<group>"; };
+               9392F14F0AD1862300691BD4 /* CounterNode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CounterNode.cpp; sourceTree = "<group>"; };
+               9392F1510AD1862B00691BD4 /* CounterListItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CounterListItem.h; sourceTree = "<group>"; };
                9394E0A403AA5BBE008635CE /* WebCorePageState.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = WebCorePageState.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                9394E0A503AA5BBE008635CE /* WebCorePageState.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCorePageState.mm; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                93955A4103D72932008635CE /* RenderTreeAsText.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeAsText.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                                BCEA4814097D93020094C9E4 /* bidi.h */,
                                BCEA4815097D93020094C9E4 /* break_lines.cpp */,
                                BCEA4816097D93020094C9E4 /* break_lines.h */,
+                               9392F1510AD1862B00691BD4 /* CounterListItem.h */,
+                               9392F14F0AD1862300691BD4 /* CounterNode.cpp */,
+                               9392F14B0AD1861B00691BD4 /* CounterNode.h */,
+                               9392F1490AD1861300691BD4 /* CounterResetNode.cpp */,
+                               9392F1450AD1860C00691BD4 /* CounterResetNode.h */,
                                BCEA4817097D93020094C9E4 /* DataRef.h */,
                                ABE7B5210A489F830031881C /* DeprecatedRenderSelect.cpp */,
                                ABE7B5220A489F830031881C /* DeprecatedRenderSelect.h */,
                                BCEA4829097D93020094C9E4 /* RenderView.h */,
                                BCEA482C097D93020094C9E4 /* RenderContainer.cpp */,
                                BCEA482D097D93020094C9E4 /* RenderContainer.h */,
+                               9392F1430AD185FE00691BD4 /* RenderCounter.cpp */,
+                               9392F1410AD185F400691BD4 /* RenderCounter.h */,
                                A8EA73AF0A1900E300A8EF5F /* RenderFieldset.cpp */,
                                A8EA73B00A1900E300A8EF5F /* RenderFieldset.h */,
                                066C772E0AB603FD00238CC4 /* RenderFileUploadControl.cpp */,
                                85004DA60ACEEB5A00C438F6 /* DOMSVGDocumentInternal.h in Headers */,
                                85004DA70ACEEB5A00C438F6 /* DOMSVGEllipseElementInternal.h in Headers */,
                                ABB5419F0ACDDFE4002820EB /* RenderListBox.h in Headers */,
+                               9392F1420AD185F400691BD4 /* RenderCounter.h in Headers */,
+                               9392F1460AD1860C00691BD4 /* CounterResetNode.h in Headers */,
+                               9392F14C0AD1861B00691BD4 /* CounterNode.h in Headers */,
+                               9392F1520AD1862B00691BD4 /* CounterListItem.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                85004D990ACEEAEF00C438F6 /* DOMSVGDocument.mm in Sources */,
                                85004D9B0ACEEAEF00C438F6 /* DOMSVGEllipseElement.mm in Sources */,
                                ABB5419E0ACDDFE4002820EB /* RenderListBox.cpp in Sources */,
+                               9392F1440AD185FE00691BD4 /* RenderCounter.cpp in Sources */,
+                               9392F14A0AD1861300691BD4 /* CounterResetNode.cpp in Sources */,
+                               9392F1500AD1862300691BD4 /* CounterNode.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 8fee8805084d9bd92f7dd90eae4199079f623346..7c8710c8ea2b812c4b44ee9e4a636e126b3267b8 100644 (file)
@@ -602,11 +602,9 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int proper
         // FIXME: unimplemented
         break;
     case CSS_PROP_COUNTER_INCREMENT:
-        // FIXME: unimplemented
-        break;
+        return style->counterIncrementValueList();
     case CSS_PROP_COUNTER_RESET:
-        // FIXME: unimplemented
-        break;
+        return style->counterResetValueList();
     case CSS_PROP_CURSOR: {
         CSSValueList* list = 0;
         CSSValue* value = 0;
index 036cf106ae3f7a50e57197866c0646a32f716674..2096ec123f44c8753f79180448b31fbbf765f820 100644 (file)
@@ -524,7 +524,10 @@ String CSSPrimitiveValue::cssText() const
             // ###
             break;
         case CSS_COUNTER:
-            // ###
+            text = "counter(";
+            text += String::number(m_value.num);
+            text += ")";
+            // FIXME: Add list-style and separator
             break;
         case CSS_RECT: {
             RectImpl* rectVal = getRectValue();
index 2f65424d08020b09d4a34a4293485b880d215ef3..ad0c348c7dec69f78690e73a2dc690911f0d2c30 100644 (file)
 #ifndef Counter_H
 #define Counter_H
 
-#include "Shared.h"
+#include "CSSPrimitiveValue.h"
 #include "PlatformString.h"
+#include "Shared.h"
+#include <wtf/PassRefPtr.h>
 
 namespace WebCore {
 
 class Counter : public Shared<Counter> {
 public:
-    String identifier() const { return m_identifier; }
-    String listStyle() const { return m_listStyle; }
-    String separator() const { return m_separator; }
+    Counter() : m_identifier(0), m_listStyle(0), m_separator(0) { }
+    Counter(PassRefPtr<CSSPrimitiveValue> identifier, PassRefPtr<CSSPrimitiveValue> listStyle,
+        PassRefPtr<CSSPrimitiveValue> separator)
+        : m_identifier(identifier), m_listStyle(listStyle), m_separator(separator) { }
+    ~Counter() { }
+
+    String identifier() const { return m_identifier ? m_identifier->getStringValue() : String(); }
+    String listStyle() const { return m_listStyle ? m_listStyle->getStringValue() : String(); }
+    String separator() const { return m_separator ? m_separator->getStringValue() : String(); }
 
-private:
-    String m_identifier;
-    String m_listStyle;
-    String m_separator;
-};
+    int listStyleNumber() const { return m_listStyle ? (int) m_listStyle->getFloatValue() : 0; }
+    
+    void setIdentifier(PassRefPtr<CSSPrimitiveValue> identifier) { m_identifier = identifier; }
+    void setListStyle(PassRefPtr<CSSPrimitiveValue> listStyle) { m_listStyle = listStyle; }
+    void setSeparator(PassRefPtr<CSSPrimitiveValue> separator) { m_separator = separator; }
+protected:
+    RefPtr<CSSPrimitiveValue> m_identifier; // String
+    RefPtr<CSSPrimitiveValue> m_listStyle;  // int
+    RefPtr<CSSPrimitiveValue> m_separator;  // String
+ };
 
-} // namespace
+} //namespace
 
 #endif
index 3377be9bb5776da46065a78ca0eea84658c338bd..8e02f3918f0d6e249449d8e2d2a14248fcb98469 100644 (file)
@@ -43,6 +43,7 @@
 #include "CSSQuirkPrimitiveValue.h"
 #include "CSSValueKeywords.h"
 #include "CSSValueList.h"
+#include "Counter.h"
 #include "DashboardRegion.h"
 #include "Document.h"
 #include "FontFamilyValue.h"
@@ -335,7 +336,7 @@ bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
 }
 
 
-void CSSParser::addProperty(int propId, CSSValue *value, bool important)
+void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
 {
     CSSProperty *prop = new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand);
     if (numParsedProperties >= maxParsedProperties) {
@@ -913,6 +914,16 @@ bool CSSParser::parseValue(int propId, bool important)
         else
             valid_primitive = (!id && validUnit(value, FNumber|FLength|FPercent, strict));
         break;
+    case CSS_PROP_COUNTER_INCREMENT:    // [ <identifier> <integer>? ]+ | none | inherit
+        if (id != CSS_VAL_NONE)
+            return parseCounter(propId, 1, important);
+        valid_primitive = true;
+        break;
+     case CSS_PROP_COUNTER_RESET:        // [ <identifier> <integer>? ]+ | none | inherit
+        if (id != CSS_VAL_NONE)
+            return parseCounter(propId, 0, important);
+        valid_primitive = true;
+        break;
     case CSS_PROP_FONT_FAMILY:
         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
     {
@@ -1566,28 +1577,38 @@ bool CSSParser::parse4Values(int propId, const int *properties,  bool important)
 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
 bool CSSParser::parseContent(int propId, bool important)
 {
-    CSSValueList* values = new CSSValueList;
+    RefPtr<CSSValueList> values = new CSSValueList;
 
     while (Value* val = valueList->current()) {
-        CSSValue* parsedValue = 0;
+        RefPtr<CSSValue> parsedValue;
         if (val->unit == CSSPrimitiveValue::CSS_URI) {
             // url
             String value = parseURL(domString(val->string));
             parsedValue = new CSSImageValue(
                 String(KURL(styleElement->baseURL().deprecatedString(), value.deprecatedString()).url()), styleElement);
         } else if (val->unit == Value::Function) {
-            // attr(X)
+            // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z])
             ValueList *args = val->function->args;
             String fname = domString(val->function->name).lower();
-            if (fname != "attr(" || !args)
+            if (!args)
                 return false;
-            if (args->size() != 1)
+            if (fname == "attr(") {
+                if (args->size() != 1)
+                    return false;
+                Value* a = args->current();
+                String attrName = domString(a->string);
+                if (document()->isHTMLDocument())
+                    attrName = attrName.lower();
+                parsedValue = new CSSPrimitiveValue(attrName, CSSPrimitiveValue::CSS_ATTR);
+            } else if (fname == "counter(") {
+                parsedValue = parseCounterContent(args, false);
+                if (!parsedValue) return false;
+            } else if (fname == "counters(") {
+                parsedValue = parseCounterContent(args, true);
+                if (!parsedValue)
+                    return false;
+            } else
                 return false;
-            Value *a = args->current();
-            String attrName = domString(a->string);
-            if (document()->isHTMLDocument())
-                attrName = attrName.lower();
-            parsedValue = new CSSPrimitiveValue(attrName, CSSPrimitiveValue::CSS_ATTR);
         } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
             // open-quote
             // close-quote
@@ -1599,17 +1620,16 @@ bool CSSParser::parseContent(int propId, bool important)
         }
         if (!parsedValue)
             break;
-        values->append(parsedValue);
+        values->append(parsedValue.release());
         valueList->next();
     }
 
     if (values->length()) {
-        addProperty(propId, values, important);
+        addProperty(propId, values.release(), important);
         valueList->next();
         return true;
     }
 
-    delete values;
     return false;
 }
 
@@ -2021,6 +2041,59 @@ bool CSSParser::parseDashboardRegions(int propId, bool important)
 }
 #endif
 
+PassRefPtr<CSSValue> CSSParser::parseCounterContent(ValueList* args, bool counters)
+{
+    unsigned numArgs = args->size();
+    if (counters && numArgs != 3 && numArgs != 5)
+        return 0;
+    if (!counters && numArgs != 1 && numArgs != 3)
+        return 0;
+    
+    Value* i = args->current();
+    RefPtr<CSSPrimitiveValue> identifier = new CSSPrimitiveValue(domString(i->string),
+        CSSPrimitiveValue::CSS_STRING);
+
+    RefPtr<CSSPrimitiveValue> separator;
+    if (!counters)
+        separator = new CSSPrimitiveValue(String(), CSSPrimitiveValue::CSS_STRING);
+    else {
+        i = args->next();
+        if (i->unit != Value::Operator || i->iValue != ',')
+            return 0;
+        
+        i = args->next();
+        if (i->unit != CSSPrimitiveValue::CSS_STRING)
+            return 0;
+        
+        separator = new CSSPrimitiveValue(domString(i->string), (CSSPrimitiveValue::UnitTypes) i->unit);
+    }
+
+    RefPtr<CSSPrimitiveValue> listStyle;
+    i = args->next();
+    if (!i) // Make the list style default decimal
+        listStyle = new CSSPrimitiveValue(CSS_VAL_DECIMAL - CSS_VAL_DISC, CSSPrimitiveValue::CSS_NUMBER);
+    else {
+        if (i->unit != Value::Operator || i->iValue != ',')
+            return 0;
+        
+        i = args->next();
+        if (i->unit != CSSPrimitiveValue::CSS_IDENT)
+            return 0;
+        
+        short ls = 0;
+        if (i->id == CSS_VAL_NONE)
+            ls = CSS_VAL_KATAKANA_IROHA - CSS_VAL_DISC + 1;
+        else if (i->id >= CSS_VAL_DISC && i->id <= CSS_VAL_KATAKANA_IROHA)
+            ls = i->id - CSS_VAL_DISC;
+        else
+            return 0;
+
+        listStyle = new CSSPrimitiveValue(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
+    }
+
+    return new CSSPrimitiveValue(new Counter(identifier.release(), listStyle.release(), separator.release()));
+}
+
 bool CSSParser::parseShape(int propId, bool important)
 {
     Value *value = valueList->current();
@@ -2719,6 +2792,48 @@ bool CSSParser::parseBorderImage(int propId, bool important)
     return context.failed();
 }
 
+bool CSSParser::parseCounter(int propId, int defaultValue, bool important)
+{
+    enum { ID, VAL } state = ID;
+
+    RefPtr<CSSValueList> list = new CSSValueList;
+    RefPtr<CSSPrimitiveValue> counterName;
+    
+    while (true) {
+        Value* val = valueList->current();
+        switch (state) {
+            case ID:
+                if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
+                    counterName = new CSSPrimitiveValue(domString(val->string), CSSPrimitiveValue::CSS_STRING);
+                    state = VAL;
+                    valueList->next();
+                    continue;
+                }
+                break;
+            case VAL: {
+                int i = defaultValue;
+                if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
+                    i = (int)val->fValue;
+                    valueList->next();
+                }
+
+                list->append(new CSSPrimitiveValue(new Pair(counterName.release(),
+                    new CSSPrimitiveValue(i, CSSPrimitiveValue::CSS_NUMBER))));
+                state = ID;
+                continue;
+            }
+        }
+        break;
+    }
+    
+    if (list->length() > 0) {
+        addProperty(propId, list.release(), important);
+        return true;
+    }
+
+    return false;
+}
+
 #ifdef CSS_DEBUG
 
 static inline int yyerror(const char *str)
index cfef6883aae2d537a8dcc4cbc890ffc3d990c1b3..7650329265f1da75c5a25e7cb7097717d57b2aa4 100644 (file)
@@ -120,7 +120,7 @@ namespace WebCore {
 
         Document* document() const;
 
-        void addProperty(int propId, CSSValue*, bool important);
+        void addProperty(int propId, PassRefPtr<CSSValue>, bool important);
         void rollbackLastProperties(int num);
         bool hasProperties() const { return numParsedProperties > 0; }
 
@@ -146,11 +146,13 @@ namespace WebCore {
 
         bool parseShape(int propId, bool important);
         bool parseFont(bool important);
+        bool parseCounter(int propId, int defaultValue, bool important);
         CSSValueList* parseFontFamily();
         bool parseColorParameters(Value*, int* colorValues, bool parseAlpha);
         bool parseHSLParameters(Value*, double* colorValues, bool parseAlpha);
         CSSPrimitiveValue* parseColor();
         CSSPrimitiveValue* parseColorFromValue(Value*);
+        PassRefPtr<CSSValue> parseCounterContent(ValueList* args, bool counters);
         
 #ifdef SVG_SUPPORT
         bool parseSVGValue(int propId, bool important);
index 365e0538fc57f8201b2eb3455a83ef7c84cea0e8..be7999f8c297c2d5043601ed0c3643028c3aefd0 100644 (file)
@@ -38,6 +38,7 @@
 #include "CSSStyleSheet.h"
 #include "CSSValueKeywords.h"
 #include "CSSValueList.h"
+#include "Counter.h"
 #include "CachedImage.h"
 #include "DashboardRegion.h"
 #include "FontFamilyValue.h"
@@ -757,18 +758,16 @@ RenderStyle* CSSStyleSelector::locateSharedStyle()
 
 void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule)
 {
-    // 1. First we match rules from the user agent sheet.
-    matchRules(defaultStyle, firstUARule, lastUARule);
+    // First we match rules from the user agent sheet.
+    CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatch("print")
+        ? defaultPrintStyle : defaultStyle;
+    matchRules(userAgentStyleSheet, firstUARule, lastUARule);
 
-    // 2. In quirks mode, we match rules from the quirks user agent sheet.
+    // In quirks mode, we match rules from the quirks user agent sheet.
     if (!strictParsing)
         matchRules(defaultQuirksStyle, firstUARule, lastUARule);
-
-    // 3. If our medium is print, then we match rules from the print sheet.
-    if (m_medium->mediaTypeMatch("print"))
-        matchRules(defaultPrintStyle, firstUARule, lastUARule);
         
-    // 4. If we're in view source mode, then we match rules from the view source style sheet.
+    // If we're in view source mode, then we match rules from the view source style sheet.
     if (view && view->frame() && view->frame()->inViewSourceMode())
         matchRules(defaultViewSourceStyle, firstUARule, lastUARule);
 }
@@ -3176,7 +3175,9 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value)
 
         for (int i = 0; i < len; i++) {
             CSSValue *item = list->item(i);
-            if (!item->isPrimitiveValue()) continue;
+            if (!item->isPrimitiveValue())
+                continue;
+            
             CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item);
             if (val->primitiveType()==CSSPrimitiveValue::CSS_STRING)
                 style->setContent(val->getStringValue().impl(), i != 0);
@@ -3190,19 +3191,28 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value)
                 style->setContent(element->getAttribute(attr).impl(), i != 0);
                 // register the fact that the attribute value affects the style
                 m_selectorAttrs.add(attr.localName().impl());
-            }
-            else if (val->primitiveType()==CSSPrimitiveValue::CSS_URI) {
+            } else if (val->primitiveType()==CSSPrimitiveValue::CSS_URI) {
                 CSSImageValue *image = static_cast<CSSImageValue*>(val);
                 style->setContent(image->image(element->document()->docLoader()), i != 0);
-            }
+            } else if (val->primitiveType()==CSSPrimitiveValue::CSS_COUNTER) {
+                Counter* counterValue = val->getCounterValue();
+                CounterData counter(counterValue->identifier(),
+                    (EListStyleType)counterValue->listStyleNumber(), counterValue->separator());
+                style->setContent(new CounterData(counter), i != 0);
+           }
         }
         break;
     }
 
     case CSS_PROP_COUNTER_INCREMENT:
-        // list of CSS2CounterIncrement
+        if (!value->isValueList())
+            return;
+        style->setCounterIncrementList(static_cast<CSSValueList*>(value));
+        break;
     case CSS_PROP_COUNTER_RESET:
-        // list of CSS2CounterReset
+        if (!value->isValueList())
+            return;
+        style->setCounterResetList(static_cast<CSSValueList*>(value));
         break;
     case CSS_PROP_FONT_FAMILY: {
         // list of strings and ids
index c190f603ab7ebeedbf4e0619f7df80eb7f5e2b25..1ac1e45fd0e4b790ebca757914bdc0277e8f7a9e 100644 (file)
@@ -91,6 +91,7 @@ public:
     void append(char);
     void append(UChar);
     void insert(const String&, unsigned pos);
+    void insert(const UChar*, unsigned length, unsigned pos);
 
     String& replace(UChar a, UChar b) { if (m_impl) m_impl = m_impl->replace(a, b); return *this; }
     String& replace(UChar a, const String& b) { if (m_impl) m_impl = m_impl->replace(a, b.impl()); return *this; }
index c6fc3ab189ffbd68d9db1f56d90daa93562dc6ba..251380d42950339dc9ea47d6ca5e316a5f3924d6 100644 (file)
@@ -157,6 +157,14 @@ void String::insert(const String& str, unsigned pos)
         m_impl->insert(str.m_impl.get(), pos);
 }
 
+void String::insert(const UChar* str, unsigned length, unsigned pos)
+{
+    if (!m_impl)
+        m_impl = new StringImpl(str, length);
+    else
+        m_impl->insert(str, length, pos);
+}
+
 UChar String::operator[](unsigned i) const
 {
     if (!m_impl || i >= m_impl->length())
index 70f43d4594b59cfcfedd1585ebd6ed0e52632a0f..b61c5ecf006fc8bd41b446dc1c35c4f245d83bcf 100644 (file)
@@ -200,6 +200,27 @@ void StringImpl::insert(const StringImpl* str, unsigned pos)
     }
 }
 
+void StringImpl::insert(const UChar* str, unsigned length, unsigned pos)
+{
+    assert(!m_inTable);
+    if (pos >= m_length) {
+        RefPtr<StringImpl> s = new StringImpl(str, length);
+        append(s.get());
+        return;
+    }
+    if (str && length != 0) {
+        size_t newlen = m_length + length;
+        UChar* c = newUCharVector(newlen);
+        memcpy(c, m_data, pos * sizeof(UChar));
+        memcpy(c + pos, str, length * sizeof(UChar));
+        memcpy(c + pos + length, m_data + pos, (m_length - pos) * sizeof(UChar));
+        deleteUCharVector(m_data);
+        m_data = c;
+        m_length = newlen;
+        m_hasTerminatingNullCharacter = false;
+    }
+}
+
 void StringImpl::truncate(int len)
 {
     assert(!m_inTable);
index 354d6859f1204f9fea20e0fdb050744a731f8ff8..fdc20e358186c59e96b5526d9346202facd1f216 100644 (file)
@@ -83,6 +83,7 @@ public:
     void append(char);
     void append(UChar);
     void insert(const StringImpl*, unsigned pos);
+    void insert(const UChar* str, unsigned length, unsigned pos);
     void truncate(int len);
     void remove(unsigned pos, int len = 1);
 
diff --git a/WebCore/rendering/CounterListItem.h b/WebCore/rendering/CounterListItem.h
new file mode 100644 (file)
index 0000000..d6a7b6b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+#ifndef CounterListItem_H
+#define CounterListItem_H
+
+#include "CounterNode.h"
+
+namespace WebCore {
+
+class CounterListItem : public CounterNode
+{
+public:
+    int count() const;
+
+    virtual void recount(bool setDirty = true);
+    virtual void setSelfDirty();
+
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/rendering/CounterNode.cpp b/WebCore/rendering/CounterNode.cpp
new file mode 100644 (file)
index 0000000..c967250
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the HTML rendering engine for KDE.
+ *
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "CounterNode.h"
+
+#include "CounterResetNode.h"
+#include "RenderObject.h"
+
+namespace WebCore {
+
+CounterNode::CounterNode(RenderObject* o)
+    : m_hasSeparator(false)
+    , m_willNeedLayout(false)
+    , m_value(0)
+    , m_count (0)
+    , m_parent(0)
+    , m_previous(0)
+    , m_next(0)
+    , m_renderer(o)
+{   
+}
+
+void CounterNode::insertAfter(CounterNode*, CounterNode*)
+{
+    ASSERT(false);
+}
+
+void CounterNode::removeChild(CounterNode*)
+{
+    ASSERT(false);
+}
+
+void CounterNode::remove()
+{
+    if (m_parent)
+        m_parent->removeChild(this);
+    else {
+        ASSERT(isReset());
+        ASSERT(!firstChild());
+        ASSERT(!lastChild());
+    }
+}
+
+void CounterNode::setUsesSeparator()
+{
+    for (CounterNode* c = this; c; c = c->parent())
+        c->setHasSeparator();
+}
+
+CounterNode* CounterNode::recountAndGetNext(bool setDirty)
+{
+    int old_count = m_count;
+    if (m_previous)
+        m_count = m_previous->count() + m_value;
+    else {
+        assert(m_parent->firstChild() == this);
+        m_count = m_parent->value() + m_value;
+    }
+    
+    if (old_count != m_count && setDirty)
+        setSelfDirty();
+    if (old_count != m_count || !setDirty) {
+        if (m_parent)
+            m_parent->updateTotal(m_count);
+        return m_next;
+    }
+    
+    return 0;
+}
+
+void CounterNode::recountTree(bool setDirty)
+{
+    CounterNode* counterNode = this;
+    while (counterNode)
+        counterNode = counterNode->recountAndGetNext(setDirty);
+}
+
+void CounterNode::setSelfDirty()
+{
+    if (m_renderer && m_willNeedLayout)
+        m_renderer->setNeedsLayoutAndMinMaxRecalc();
+}
+
+void CounterNode::setParentDirty()
+{
+    if (m_renderer && m_willNeedLayout && m_hasSeparator)
+        m_renderer->setNeedsLayoutAndMinMaxRecalc();
+}
+
+} // namespace
diff --git a/WebCore/rendering/CounterNode.h b/WebCore/rendering/CounterNode.h
new file mode 100644 (file)
index 0000000..9d318cc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the HTML rendering engine for KDE.
+ *
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+*/
+#ifndef Counter_Node_h_
+#define Counter_Node_h_
+
+#include "RenderObject.h"
+
+namespace WebCore {
+
+class CounterResetNode;
+
+// This file implements a counter-tree that is used for finding all parents in counters() lookup,
+// and for propagating count-changes when nodes are added or removed.
+// Please note that only counter-reset and root can be parents here, and that render-tree parents
+// are just counter-tree siblings
+
+class CounterNode {
+public:
+    CounterNode(RenderObject*);
+    virtual ~CounterNode() {}
+
+    CounterResetNode* parent() const { return m_parent; }
+    CounterNode* previousSibling() const { return m_previous; }
+    virtual CounterNode* nextSibling() const { return m_next; }
+    virtual CounterNode* firstChild() const { return 0; }
+    virtual CounterNode* lastChild() const { return 0; }
+    virtual void insertAfter(CounterNode* newChild, CounterNode* refChild);
+    virtual void removeChild (CounterNode* oldChild);
+    void remove();
+
+    int value() const { return m_value; }
+    void setValue(int v) { m_value = v; }
+    int count() const { return m_count; }
+    void setCount(int c) { m_count = c; }
+    void setHasSeparator() { m_hasSeparator = true; }
+
+    virtual bool isReset() const{ return false; }
+    virtual CounterNode* recountAndGetNext(bool setDirty = true);
+    virtual void recountTree(bool setDirty = true);
+    virtual void setSelfDirty();
+    virtual void setParentDirty();
+
+    bool hasSeparator() const { return m_hasSeparator; }
+    bool willNeedLayout() const { return m_willNeedLayout; }
+    void setUsesSeparator();
+    void setWillNeedLayout() { m_willNeedLayout = true; }
+    bool isRoot() const { return m_renderer && m_renderer->isRoot(); }
+
+    void setRenderer(RenderObject* o) { m_renderer = o; }
+    RenderObject* renderer() const { return m_renderer; }
+
+    friend class CounterResetNode;
+protected:
+    bool m_hasSeparator;
+    bool m_willNeedLayout;
+    int m_value;
+    int m_count;
+    CounterResetNode* m_parent;
+    CounterNode* m_previous;
+    CounterNode* m_next;
+    RenderObject* m_renderer;
+};
+
+} // namespace WebCore
+
+#endif // CounterNode_h
diff --git a/WebCore/rendering/CounterResetNode.cpp b/WebCore/rendering/CounterResetNode.cpp
new file mode 100644 (file)
index 0000000..0da567c
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the HTML rendering engine for KDE.
+ *
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "CounterResetNode.h"
+
+#include "RenderObject.h"
+
+namespace WebCore {
+
+CounterResetNode::CounterResetNode(RenderObject* o)
+    : CounterNode(o)
+    , m_total(0)
+    , m_first(0)
+    , m_last(0)
+{
+}
+
+void CounterResetNode::insertAfter(CounterNode* newChild, CounterNode* refChild)
+{
+    ASSERT(newChild);
+    ASSERT(!refChild || refChild->parent() == this);
+
+    newChild->m_parent = this;
+    newChild->m_previous = refChild;
+
+    if (refChild) {
+        newChild->m_next = refChild->m_next;
+        refChild->m_next = newChild;
+    } else {
+        newChild->m_next = m_first;
+        m_first = newChild;
+    }
+
+    if (newChild->m_next) {
+        ASSERT(newChild->m_next->m_previous == refChild);
+        newChild->m_next->m_previous = newChild;
+    } else {
+        ASSERT(m_last == refChild);
+        m_last = newChild;
+    }
+
+    newChild->recountAndGetNext(false);
+}
+
+void CounterResetNode::removeChild(CounterNode* oldChild)
+{
+    ASSERT(oldChild);
+
+    CounterNode* next = oldChild->m_next;
+    CounterNode* prev = oldChild->m_previous;
+
+    if (oldChild->firstChild()) {
+        CounterNode* first = oldChild->firstChild();
+        CounterNode* last = oldChild->lastChild();
+        if (prev) {
+            prev->m_next = first;
+            first->m_previous = prev;
+        } else
+            m_first = first;
+
+        if (next) {
+            next->m_previous = last;
+            last->m_next = next;
+        } else
+            m_last = last;
+
+        next = first;
+        while (next) {
+            next->m_parent = this;
+            next = next->m_next;
+        }
+
+        first->recountAndGetNext(true);
+    } else {
+        if (prev) 
+            prev->m_next = next;
+        else {
+            assert ( m_first == oldChild );
+            m_first = next;
+        }
+        
+        if (next)
+            next->m_previous = prev;
+        else {
+            assert ( m_last == oldChild );
+            m_last = prev;
+        }
+        
+        if (next)
+            next->recountTree();
+    }
+
+
+    oldChild->m_next = 0;
+    oldChild->m_previous = 0;
+    oldChild->m_parent = 0;
+}
+
+CounterNode* CounterResetNode::recountAndGetNext(bool setDirty)
+{
+    int old_count = m_count;
+    if (m_previous)
+        m_count = m_previous->count();
+    else if (m_parent)
+        m_count = m_parent->value();
+    else
+        m_count = 0;
+
+    updateTotal(m_value);
+    
+    if (setDirty)
+        setSelfDirty();
+    if (!setDirty || m_count != old_count)
+        return m_next;
+    
+    return 0;
+}
+
+void CounterResetNode::setParentDirty()
+{
+    if (hasSeparator())
+        setSelfDirty();
+        
+    for (CounterNode* n = firstChild(); n; n = n->nextSibling())
+        if (n->hasSeparator())
+            n->setSelfDirty();
+}
+
+void CounterResetNode::updateTotal(int value)
+{
+    if (value > m_total)
+        m_total = value;
+}
+
+} // namespace
diff --git a/WebCore/rendering/CounterResetNode.h b/WebCore/rendering/CounterResetNode.h
new file mode 100644 (file)
index 0000000..f761b86
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the HTML rendering engine for KDE.
+ *
+ * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+*/
+#ifndef Counter_Reset_Node_h_
+#define Counter_Reset_Node_h_
+
+#include "CounterNode.h"
+
+namespace WebCore {
+
+// This file implements a counter-tree that is used for finding all parents in counters() lookup,
+// and for propagating count-changes when nodes are added or removed.
+// Please note that only counter-reset and root can be parents here, and that render-tree parents
+// are just counter-tree siblings
+
+// Implementation of counter-reset and root
+class CounterResetNode : public CounterNode {
+
+public:
+    CounterResetNode(RenderObject*);
+
+    virtual CounterNode* firstChild() const { return m_first; };
+    virtual CounterNode* lastChild() const { return m_last; };
+    virtual void insertAfter(CounterNode* newChild, CounterNode* refChild);
+    virtual void removeChild (CounterNode*);
+
+    virtual bool isReset() const { return true; };
+    virtual CounterNode* recountAndGetNext(bool setDirty = true);
+    virtual void setParentDirty();
+
+    void updateTotal(int value);
+    // The highest value among children
+    int total() const { return m_total; };
+
+private:
+    int m_total;
+    CounterNode* m_first;
+    CounterNode* m_last;
+};
+
+} // namespace WebCore
+
+#endif // CounterResetNode_h
index 8f669372684211f6ce49e64718a967bf364c7eb8..d09898e7a47b106132ef59f11947558786f29dcb 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ *           (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
  *
@@ -28,6 +29,7 @@
 #include "RenderContainer.h"
 
 #include "htmlediting.h"
+#include "RenderCounter.h"
 #include "RenderListItem.h"
 #include "RenderTable.h"
 #include "RenderTextFragment.h"
@@ -296,7 +298,7 @@ void RenderContainer::updatePseudoChildForObject(RenderStyle::PseudoId type, Ren
         // determined that the pseudo is not display NONE, any display other than
         // inline should be mutated to INLINE.
         pseudo->setDisplay(INLINE);
-    
+
     if (oldContentPresent) {
         if (child && child->style()->styleType() == type) {
             // We have generated content present still.  We want to walk this content and update our
@@ -334,20 +336,24 @@ void RenderContainer::updatePseudoChildForObject(RenderStyle::PseudoId type, Ren
         if (!pseudoContainer)
             pseudoContainer = RenderFlow::createAnonymousFlow(document(), pseudo); /* anonymous box */
         
-        if (contentData->contentType() == CONTENT_TEXT)
-        {
+        if (contentData->contentType() == CONTENT_TEXT) {
             RenderText* t = new (renderArena()) RenderTextFragment(document() /*anonymous object */, contentData->contentText());
             t->setStyle(pseudo);
             pseudoContainer->addChild(t);
-        }
-        else if (contentData->contentType() == CONTENT_OBJECT)
-        {
+        } else if (contentData->contentType() == CONTENT_OBJECT) {
             RenderImage* img = new (renderArena()) RenderImage(document()); /* Anonymous object */
             RenderStyle* style = new (renderArena()) RenderStyle();
             style->inheritFrom(pseudo);
             img->setStyle(style);
             img->setContentObject(contentData->contentObject());
             pseudoContainer->addChild(img);
+        } else if (contentData->_contentType == CONTENT_COUNTER) {
+            RenderCounter* c = new (renderArena()) RenderCounter(element(), contentData->contentCounter());
+            RenderStyle* style = new (renderArena()) RenderStyle();
+            style->inheritFrom(pseudo);
+            c->setIsAnonymous(true);
+            c->setStyle(style);
+            pseudoContainer->addChild(c);
         }
     }
 
diff --git a/WebCore/rendering/RenderCounter.cpp b/WebCore/rendering/RenderCounter.cpp
new file mode 100644 (file)
index 0000000..088d9ed
--- /dev/null
@@ -0,0 +1,245 @@
+/**
+ * This file is part of the HTML rendering engine for KDE.
+ *
+ * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderCounter.h"
+
+#include "CounterNode.h"
+#include "CounterResetNode.h"
+#include "Document.h"
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+const int cMarkerPadding = 7;
+
+RenderCounter::RenderCounter(Node* node, CounterData* counter)
+    : RenderText(node, 0), m_counter(counter), m_counterNode(0)
+{
+}
+
+void RenderCounter::layout()
+{
+    ASSERT(needsLayout());
+
+    if (!minMaxKnown())
+        calcMinMaxWidth();
+
+    RenderText::layout();
+}
+
+static String toRoman(int number, bool upper)
+{ 
+    String roman;
+    const UChar ldigits[] = { 'i', 'v', 'x', 'l', 'c', 'd', 'm' };
+    const UChar udigits[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' };
+    const UChar* digits = upper ? udigits : ldigits;
+    int d = 0;
+    do {
+        int num = number % 10;
+        if (num % 5 < 4)
+            for (int i = num % 5; i > 0; i--)
+                roman.insert(&digits[d], 1, 0);
+        if (num >= 4 && num <= 8)
+            roman.insert(&digits[d + 1], 1, 0);
+        if (num == 9)
+            roman.insert(&digits[d + 2], 1, 0);
+        if (num % 5 == 4)
+            roman.insert(&digits[d], 1, 0);
+        number /= 10;
+        d += 2;
+    } while (number);
+    return roman;
+}
+
+static String toLetterString(int number, UChar letterA)
+{ 
+    if (number < 2)
+        return String(&letterA, 1); // match WinIE (A.) not FireFox (0.)
+
+    String letterString;
+    UChar c;
+    while (number > 0) {
+        int onesDigit = (number - 1) % 26;
+        c = letterA + onesDigit;
+        letterString = String(&c, 1) + letterString;
+        number -= onesDigit;
+        number /= 26;
+    }
+
+    return letterString;
+}
+
+static String toHebrew(int number)
+{
+    if (number < 1)
+        return String::number(number);
+    
+    static const UChar tenDigit[] = {1497, 1499, 1500, 1502, 1504, 1505, 1506, 1508, 1510};
+
+    String letter;
+    UChar c;
+    if (number > 999) {
+        letter = toHebrew(number / 1000) + "'";
+        number = number % 1000;
+    }
+    int fourHundreds = number / 400;
+    for (int i = 0; i < fourHundreds; i++) {
+        c = 1511 + 3;
+        letter.append(c);
+    }
+    number %= 400;
+    if (number / 100) {
+        c = 1511 + (number / 100) - 1;
+        letter.append(c);
+    }
+    number %= 100;
+    if (number == 15 || number == 16) {
+        c = 1487 + 9;
+        letter.append(c);
+        c = 1487 + number - 9;
+        letter.append(c);
+    } else {
+        int tens = number / 10;
+        if (tens) {
+            c = tenDigit[tens - 1];
+            letter.append(c);
+        }
+        number = number % 10;
+        if (number) {
+            c = 1487 + number;
+            letter.append(c);
+        }
+    }
+    return letter;
+}
+
+String RenderCounter::convertValueToType(int value, int total, EListStyleType type)
+{
+    String item;
+    UChar c;
+    switch(type) {
+        case LNONE:
+            break;
+        // Glyphs:
+        case DISC:
+            c = 0x2022;
+            item = String(&c, 1);
+            break;
+        case CIRCLE:
+            c = 0x25e6;
+            item = String(&c, 1);
+            break;
+        case SQUARE:
+            c = 0x25a0;
+            item = String(&c, 1);
+            break;
+        case ARMENIAN:
+        case GEORGIAN:
+        case CJK_IDEOGRAPHIC:
+        case HIRAGANA:
+        case KATAKANA:
+        case HIRAGANA_IROHA:
+        case KATAKANA_IROHA:
+        case DECIMAL_LEADING_ZERO:
+            // FIXME: These are currently unsupported. For now we'll use decimal instead.
+        case LDECIMAL:
+            item = String::number(value);
+            break;
+        // Algoritmic:
+        case LOWER_ROMAN:
+            item = toRoman(value, false);
+            break;
+        case UPPER_ROMAN:
+            item = toRoman(value, true);
+            break;
+        case LOWER_GREEK: {
+            int number = value - 1;
+            int l = (number % 24);
+            if (l > 16)
+                l++; // Skip GREEK SMALL LETTER FINAL SIGMA
+            c = 945 + l;
+            item = String(&c, 1);
+            for (int i = 0; i < (number / 24); i++)
+                item += "'";
+            break;
+        }
+        case HEBREW:
+            item = toHebrew(value);
+            break;
+        case LOWER_ALPHA:
+        case LOWER_LATIN:
+            item = toLetterString(value, 'a');
+            break;
+        case UPPER_ALPHA:
+        case UPPER_LATIN:
+            item = toLetterString(value, 'A');
+            break;
+        default:
+            item = String::number(value);
+            break;
+    }
+    return item;
+}
+
+void RenderCounter::calcMinMaxWidth()
+{
+    ASSERT(!minMaxKnown());
+
+    if (!style())
+        return;
+
+    bool hasSeparator = !m_counter->separator().isNull();
+
+    if (!m_counterNode && parent()->parent())
+        m_counterNode = parent()->parent()->findCounter(m_counter->identifier(), true, hasSeparator);
+
+    int value = m_counterNode->count();
+    if (m_counterNode->isReset())
+        value = m_counterNode->value();
+    
+    int total = value;
+    if (m_counterNode->parent())
+        total = m_counterNode->parent()->total();
+    
+    m_item = convertValueToType(value, total, m_counter->listStyle());
+
+    if (hasSeparator) {
+        CounterNode* counter = m_counterNode->parent();
+        bool first = true;
+        while  (counter->parent() && (first || !(counter->isReset() && counter->parent()->isRoot()))) {
+            value = counter->count() ? counter->count() : 1;
+            total = counter->parent()->total();
+            m_item = convertValueToType(value, total, m_counter->listStyle()) 
+                + m_counter->separator() + m_item;
+            counter = counter->parent();
+            first = false;
+        }
+    }
+
+    str = new StringImpl(m_item.characters(), m_item.length());
+    
+    RenderText::calcMinMaxWidth();
+}
+
+} // namespace WebCore
diff --git a/WebCore/rendering/RenderCounter.h b/WebCore/rendering/RenderCounter.h
new file mode 100644 (file)
index 0000000..97ae72b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the HTML rendering engine for KDE.
+ *
+ * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+#ifndef RENDER_COUNTER_H_
+#define RENDER_COUNTER_H_
+
+#include "RenderText.h"
+
+namespace WebCore {
+    class CounterNode;
+
+// -----------------------------------------------------------------------------
+
+class RenderCounter : public RenderText {
+
+public:
+    RenderCounter(Node*, CounterData*);
+    
+    virtual const char* renderName() const { return "RenderCounter"; }
+
+    virtual bool isCounter() const { return true; }
+    virtual void layout();
+    virtual void calcMinMaxWidth();
+
+private:
+    String convertValueToType(int value, int total, EListStyleType);
+
+    String m_item;
+    CounterData* m_counter;
+    CounterNode* m_counterNode;
+};
+
+} //namespace
+
+#endif
index e3735afc9988f2e65befcafd331971883fcd4bfa..1a91c1936357fb40ccd3fe95b2a2e49b01475c8c 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ *           (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -29,6 +30,8 @@
 #include "AXObjectCache.h" 
 #include "AffineTransform.h"
 #include "CachedImage.h"
+#include "CounterNode.h"
+#include "CounterResetNode.h"
 #include "Decoder.h"
 #include "Document.h"
 #include "Element.h"
@@ -37,6 +40,7 @@
 #include "Frame.h"
 #include "GraphicsContext.h"
 #include "HTMLNames.h"
+#include "HTMLOListElement.h"
 #include "Position.h"
 #include "RenderArena.h"
 #include "RenderFlexibleBox.h"
@@ -65,6 +69,15 @@ using namespace HTMLNames;
 static void *baseOfRenderObjectBeingDeleted;
 #endif
 
+typedef HashMap<String, CounterNode*> CounterNodeMap;
+typedef HashMap<const RenderObject*, CounterNodeMap*> RenderObjectsToCounterNodeMaps;
+
+static RenderObjectsToCounterNodeMaps* getRenderObjectsToCounterNodeMaps()
+{
+    static RenderObjectsToCounterNodeMaps objectsMap;
+    return &objectsMap;
+}
+
 void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw()
 {
     return renderArena->allocate(sz);
@@ -177,7 +190,8 @@ m_inline( true ),
 
 m_replaced( false ),
 m_isDragging( false ),
-m_hasOverflowClip(false)
+m_hasOverflowClip(false),
+m_hasCounterNodeMap(false)
 {
 #ifndef NDEBUG
     ++RenderObjectCounter::count;
@@ -2406,6 +2420,21 @@ bool RenderObject::documentBeingDestroyed() const
 
 void RenderObject::destroy()
 {
+    if (m_hasCounterNodeMap) {
+        RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
+        if (CounterNodeMap* counterNodesMap = objectsMap->get(this)) {
+            CounterNodeMap::const_iterator end = counterNodesMap->end();
+            for (CounterNodeMap::const_iterator it = counterNodesMap->begin(); it != end; ++it) {
+                CounterNode* counterNode = it->second;
+                counterNode->remove();
+                delete counterNode;
+                counterNode = 0;
+            }
+            objectsMap->remove(this);
+            delete counterNodesMap;
+        }
+    }
+    
     document()->axObjectCache()->remove(this);
 
     // By default no ref-counting. RenderWidget::destroy() doesn't call
@@ -2848,6 +2877,132 @@ bool RenderObject::usesLineWidth() const
     return (avoidsFloats() && (style()->width().isAuto() || isHR() || (style()->htmlHacks() && !isTable())));
 }
 
+CounterNode* RenderObject::findCounter(const String& counterName, bool willNeedLayout,
+    bool usesSeparator, bool createIfNotFound)
+{
+    if (!style())
+        return 0;
+
+    RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
+    CounterNode* newNode = 0;
+    if (CounterNodeMap* counterNodesMap = objectsMap->get(this))
+        if (counterNodesMap)
+            newNode = counterNodesMap->get(counterName);
+        
+    if (newNode)
+        return newNode;
+
+    int val = 0;
+    if (style()->hasCounterReset(counterName) || isRoot()) {
+        newNode = new CounterResetNode(this);
+        val = style()->counterReset(counterName);
+        if (style()->hasCounterIncrement(counterName))
+            val += style()->counterIncrement(counterName);
+        newNode->setValue(val);
+    } else if (style()->hasCounterIncrement(counterName)) {
+        newNode = new CounterNode(this);
+        newNode->setValue(style()->counterIncrement(counterName));
+    } else if (counterName == "list-item") {
+        if (isListItem()) {
+            if (element()) {
+                String v = static_cast<Element*>(element())->getAttribute("value");
+                if (!v.isEmpty()) {
+                    newNode = new CounterResetNode(this);
+                    val = v.toInt();
+                }
+            } 
+            
+            if (!newNode) {
+                newNode = new CounterNode(this);
+                val = 1;
+            }
+
+            newNode->setValue(val);
+        } else if (element() && element()->hasTagName(olTag)) {
+            newNode = new CounterResetNode(this);
+            newNode->setValue(static_cast<HTMLOListElement*>(element())->start());
+        } else if (element() &&
+            (element()->hasTagName(ulTag) ||
+             element()->hasTagName(menuTag) ||
+             element()->hasTagName(dirTag))) {
+            newNode = new CounterResetNode(this);
+            newNode->setValue(0);
+        }
+    } 
+    
+    if (!newNode && !createIfNotFound)
+        return 0;
+    else if (!newNode) {
+        newNode = new CounterNode(this);
+        newNode->setValue(0);
+    }
+
+    if (willNeedLayout)
+        newNode->setWillNeedLayout();
+    if (usesSeparator)
+        newNode->setUsesSeparator();
+
+    CounterNodeMap* nodeMap;
+    if (m_hasCounterNodeMap)
+        nodeMap = objectsMap->get(this);
+    else {
+        nodeMap = new CounterNodeMap;
+        objectsMap->set(this, nodeMap);
+        m_hasCounterNodeMap = true;
+    }
+    
+    nodeMap->set(counterName, newNode);
+
+    if (!isRoot()) {
+        RenderObject* n = !isListItem() && previousSibling()
+            ? previousSibling()->previousSibling() : previousSibling();
+
+        CounterNode* current = 0;
+        for (; n; n = n->previousSibling()) {
+            current = n->findCounter(counterName, false, false, false);
+            if (current)
+                break;
+        }
+        
+        CounterNode* last = current;
+        CounterNode* sibling = current;
+        if (last && !newNode->isReset()) {
+            // Found render-sibling, now search for later counter-siblings among its render-children
+            n = n->lastChild();
+            while (n) {
+                current = n->findCounter(counterName, false, false, false);
+                if (current && (last->parent() == current->parent() || sibling == current->parent())) {
+                    last = current;
+                    // If the current counter is not the last, search deeper
+                    if (current->nextSibling()) {
+                        n = n->lastChild();
+                        continue;
+                    } else
+                        break;
+                }
+                n = n->previousSibling();
+            }
+            
+            if (sibling->isReset()) {
+                if (last != sibling)
+                    sibling->insertAfter(newNode, last);
+                else
+                    sibling->insertAfter(newNode, 0);
+            } else
+                last->parent()->insertAfter(newNode, last);
+        } else {
+            // Nothing found among siblings, let our parent search
+            last = parent()->findCounter(counterName, false);
+            if (last->isReset())
+                last->insertAfter(newNode, 0);
+            else
+                last->parent()->insertAfter(newNode, last);
+        }
+    }
+
+    return newNode;
+}
+
 UChar RenderObject::backslashAsCurrencySymbol() const
 {
     if (Node *node = element())
index aaf5e20ebd76a21e3db4f1783d78aae5ad903ba9..62d3519233fc0eb871403d218b5a461d0e43d594 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
  *           (C) 2000 Antti Koivisto (koivisto@kde.org)
  *           (C) 2000 Dirk Mueller (mueller@kde.org)
+ *           (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -31,6 +32,7 @@
 #include "RenderStyle.h"
 #include "ScrollBar.h"
 #include "VisiblePosition.h"
+#include <wtf/HashMap.h>
 
 /*
  *  The painting of a layer occurs in three distinct phases.  Each phase involves
@@ -46,6 +48,7 @@ namespace WebCore {
 class AffineTransform;
 class CollapsedBorderValue;
 class Color;
+class CounterNode;
 class Document;
 class Element;
 class Event;
@@ -193,6 +196,10 @@ public:
     virtual int staticX() const { return 0; }
     virtual int staticY() const { return 0; }
     
+    CounterNode* findCounter(const String& counterName, bool willNeedLayout = false,
+        bool usesSeparator = false, bool createIfNotFound = true);
+
+public:
     // RenderObject tree manipulation
     //////////////////////////////////////////
     virtual bool canHaveChildren() const;
@@ -254,6 +261,7 @@ public:
     
     virtual bool isListItem() const { return false; }
     virtual bool isListMarker() const { return false; }
+    virtual bool isCounter() const { return false; }
     virtual bool isRenderView() const { return false; }
     bool isRoot() const;
     bool isBody() const;
@@ -932,8 +940,9 @@ private:
     bool m_isDragging                : 1;
     
     bool m_hasOverflowClip           : 1;
+    
+    bool m_hasCounterNodeMap         : 1;
 
-    // note: do not add unnecessary bitflags, we have 32 bit already!
     friend class RenderListItem;
     friend class RenderContainer;
     friend class RenderView;
index c98c10cdfa0670e0f63d8eb5cf44d2610109d104..66c871d0f9ccb77a95ee4f84cdfa8bb913d1e27d 100644 (file)
@@ -90,8 +90,8 @@ StyleVisualData::StyleVisualData()
     : hasClip(false)
     , textDecoration(RenderStyle::initialTextDecoration())
     , colspan(1)
-    , counter_increment(0)
-    , counter_reset(0)
+    , counterIncrement(0)
+    , counterReset(0)
 {
 }
 
@@ -105,8 +105,8 @@ StyleVisualData::StyleVisualData(const StyleVisualData& o)
     , hasClip(o.hasClip)
     , textDecoration(o.textDecoration)
     , colspan(o.colspan)
-    , counter_increment(o.counter_increment)
-    , counter_reset(o.counter_reset)
+    , counterIncrement(o.counterIncrement)
+    , counterReset(o.counterReset)
 {
 }
 
@@ -577,7 +577,6 @@ void RenderStyle::arenaDelete(RenderArena *arena)
         prev->deref(arena);
     }
     delete content;
-    
     delete this;
     
     // Recover the size left there for us by operator delete and free the memory.
@@ -649,6 +648,8 @@ RenderStyle::RenderStyle(const RenderStyle& o)
     , inherited(o.inherited)
     , pseudoStyle(0)
     , content(o.content)
+    , counterResetList(o.counterResetList)
+    , counterIncrementList(o.counterIncrementList)
     , m_pseudoState(o.m_pseudoState)
     , m_affectedByAttributeSelectors(false)
     , m_unique(false)
@@ -838,8 +839,8 @@ RenderStyle::Diff RenderStyle::diff( const RenderStyle *other ) const
         !(noninherited_flags._floating == other->noninherited_flags._floating) ||
         !(noninherited_flags._originalDisplay == other->noninherited_flags._originalDisplay) ||
          visual->colspan != other->visual->colspan ||
-         visual->counter_increment != other->visual->counter_increment ||
-         visual->counter_reset != other->visual->counter_reset ||
+         visual->counterIncrement != other->visual->counterIncrement ||
+         visual->counterReset != other->visual->counterReset ||
          css3NonInheritedData->textOverflow != other->css3NonInheritedData->textOverflow ||
          (css3InheritedData->textSecurity != other->css3InheritedData->textSecurity))
         return Layout;
@@ -925,6 +926,10 @@ RenderStyle::Diff RenderStyle::diff( const RenderStyle *other ) const
     // If regions change trigger a relayout to re-calc regions.
     if (!(css3NonInheritedData->m_dashboardRegions == other->css3NonInheritedData->m_dashboardRegions))
         return Layout;
+    
+    // If the counter lists change, trigger a relayout to re-calc CounterNodes.
+    if (counterResetList != other->counterResetList || counterIncrementList != other->counterIncrementList)
+        return Layout;
 
     // Make sure these left/top/right/bottom checks stay below all layout checks and above
     // all visible checks.
@@ -1109,6 +1114,32 @@ void RenderStyle::setContent(StringImpl* s, bool add)
     newContentData->_contentType = CONTENT_TEXT;
 }
 
+void RenderStyle::setContent(CounterData* c, bool add)
+{
+    if (!c)
+        return;
+
+    ContentData* lastContent = content;
+    while (lastContent && lastContent->_nextContent)
+        lastContent = lastContent->_nextContent;
+
+    bool reuseContent = !add;
+    ContentData* newContentData = 0;
+    if (reuseContent && content) {
+        content->clearContent();
+        newContentData = content;
+    } else
+        newContentData = new ContentData;
+
+    if (lastContent && !reuseContent)
+        lastContent->_nextContent = newContentData;
+    else
+        content = newContentData;
+
+    newContentData->_content.counter = c;
+    newContentData->_contentType = CONTENT_COUNTER;
+}
+
 ContentData::~ContentData()
 {
     clearContent();
@@ -1127,6 +1158,11 @@ void ContentData::clearContent()
         case CONTENT_TEXT:
             _content.text->deref();
             _content.text = 0;
+            break;
+        case CONTENT_COUNTER:
+            delete _content.counter;
+            _content.counter = 0;
+            break;
         default:
             ;
     }
@@ -1214,6 +1250,82 @@ bool ShadowData::operator==(const ShadowData& o) const
     return x == o.x && y == o.y && blur == o.blur && color == o.color;
 }
 
+bool RenderStyle::counterDataEquivalent(RenderStyle* otherStyle)
+{
+    // FIXME: Should we also compare the CounterData? 
+    return counterResetList == otherStyle->counterResetList &&
+           counterIncrementList == otherStyle->counterIncrementList;
+}
+
+static bool hasCounter(const String& c, CSSValueList* l)
+{
+    int len = l->length();
+    for (int i = 0; i < len; i++) {
+        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(l->item(i));
+        Pair* pair = primitiveValue->getPairValue();
+        ASSERT(pair);
+        CSSPrimitiveValue* counterName = static_cast<CSSPrimitiveValue*>(pair->first());
+        ASSERT(counterName);
+        if (counterName->getStringValue() == c)
+            return true;
+    }
+    return false;
+}
+
+bool RenderStyle::hasCounterReset(const String& counterName) const
+{
+    if (counterResetList)
+        return hasCounter(counterName, counterResetList.get());
+    return false;
+}
+
+bool RenderStyle::hasCounterIncrement(const String& counterName) const
+{
+    if (counterIncrementList)
+        return hasCounter(counterName, counterIncrementList.get());
+    return false;
+}
+
+static int readCounter(const String& c, CSSValueList* l, bool isReset)
+{
+    int len = l->length();
+    int total = 0;
+    
+    for (int i = 0; i < len; i++) {
+        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(l->item(i));
+        Pair* pair = primitiveValue->getPairValue();
+        ASSERT(pair);
+        CSSPrimitiveValue* counterName = static_cast<CSSPrimitiveValue*>(pair->first());
+        CSSPrimitiveValue* counterValue = static_cast<CSSPrimitiveValue*>(pair->second());
+        ASSERT(counterName);
+        ASSERT(counterValue);
+
+        if (counterName->getStringValue() == c) {
+            total += (int)counterValue->getFloatValue();
+            if (isReset)
+                return total;
+        }
+    }
+    
+    return total;
+}
+
+int RenderStyle::counterReset(const String& counterName) const
+{
+    if (counterResetList)
+        return readCounter(counterName, counterResetList.get(), true);
+    else
+        return 0;
+}
+
+int RenderStyle::counterIncrement(const String& counterName) const
+{
+    if (counterIncrementList)
+        return readCounter(counterName, counterIncrementList.get(), false);
+    else
+        return 0;
+}
+
 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
 { 
     static Vector<StyleDashboardRegion> emptyList;
index d730f0d5e01886f47bb5404a89382525bcd555b4..4ce0f94bb14a97db4c5d1a69f534e38413dc67e1 100644 (file)
@@ -35,6 +35,8 @@
  * and produce invaliud results.
  */
 
+#include "CSSPrimitiveValue.h"
+#include "CSSValueList.h"
 #include "Color.h"
 #include "CSSCursorImageValue.h"
 #include "DataRef.h"
@@ -42,6 +44,7 @@
 #include "GraphicsTypes.h"
 #include "IntRect.h"
 #include "Length.h"
+#include "Pair.h"
 #include "Shared.h"
 #include "TextDirection.h"
 #include <wtf/Vector.h>
@@ -60,11 +63,13 @@ namespace WebCore {
 
 using std::max;
 
-class CSSStyleSelector;
 class CachedImage;
 class CachedResource;
+class CSSStyleSelector;
+class CSSValueList;
 struct CursorData;
 class CursorList;
+class Pair;
 class RenderArena;
 class ShadowValue;
 class StringImpl;
@@ -410,8 +415,8 @@ public:
         return ( clip == o.clip &&
                  hasClip == o.hasClip &&
                  colspan == o.colspan &&
-                 counter_increment == o.counter_increment &&
-                 counter_reset == o.counter_reset &&
+                 counterIncrement == o.counterIncrement &&
+                 counterReset == o.counterReset &&
                  textDecoration == o.textDecoration);
     }
     bool operator!=( const StyleVisualData &o ) const {
@@ -424,8 +429,8 @@ public:
     
     short colspan; // for html, not a css2 attribute
 
-    short counter_increment; //ok, so these are not visual mode spesific
-    short counter_reset;     //can't go to inherited, since these are not inherited
+    short counterIncrement; // ok, so these are not visual mode specific
+    short counterReset;     // can't go to inherited, since these are not inherited
 
 };
 
@@ -898,6 +903,23 @@ enum ContentType {
     CONTENT_NONE, CONTENT_OBJECT, CONTENT_TEXT, CONTENT_COUNTER
 };
 
+class CounterData {
+    
+public:
+    CounterData() {}
+    CounterData(const String& i, EListStyleType l, const String& s)
+        : m_identifier(i), m_listStyle(l), m_separator(s) {}
+    
+    String identifier() { return m_identifier; }
+    EListStyleType listStyle() { return m_listStyle; }
+    String separator() { return m_separator; }
+
+private:
+    String m_identifier;
+    EListStyleType m_listStyle;
+    String m_separator;
+};
+
 struct ContentData {
     ContentData() :_contentType(CONTENT_NONE), _nextContent(0) {}
     ~ContentData();
@@ -907,13 +929,14 @@ struct ContentData {
 
     StringImpl* contentText() { if (contentType() == CONTENT_TEXT) return _content.text; return 0; }
     CachedResource* contentObject() { if (contentType() == CONTENT_OBJECT) return _content.object; return 0; }
+    CounterData* contentCounter() { if (contentType() == CONTENT_COUNTER) return _content.counter; return 0; }
     
     ContentType _contentType;
 
     union {
         CachedResource* object;
         StringImpl* text;
-        // counters...
+        CounterData* counter;
     } _content ;
 
     ContentData* _nextContent;
@@ -1071,7 +1094,9 @@ protected:
     
     // added this here, so we can get rid of the vptr in this class.
     // makes up for the same size.
-    ContentData *content;
+    ContentData* content;
+    RefPtr<CSSValueList> counterResetList;
+    RefPtr<CSSValueList> counterIncrementList;
 
     unsigned m_pseudoState : 3; // PseudoState
     bool m_affectedByAttributeSelectors : 1;
@@ -1321,8 +1346,8 @@ public:
     EEmptyCell emptyCells() const { return static_cast<EEmptyCell>(inherited_flags._empty_cells); }
     ECaptionSide captionSide() const { return static_cast<ECaptionSide>(inherited_flags._caption_side); }
 
-    short counterIncrement() const { return visual->counter_increment; }
-    short counterReset() const { return visual->counter_reset; }
+    short counterIncrement() const { return visual->counterIncrement; }
+    short counterReset() const { return visual->counterReset; }
 
     EListStyleType listStyleType() const { return static_cast<EListStyleType>(inherited_flags._list_style_type); }
     CachedImage *listStyleImage() const { return inherited->style_image; }
@@ -1527,8 +1552,8 @@ public:
     void setCaptionSide(ECaptionSide v) { inherited_flags._caption_side = v; }
 
 
-    void setCounterIncrement(short v) {  SET_VAR(visual,counter_increment,v) }
-    void setCounterReset(short v) {  SET_VAR(visual,counter_reset,v) }
+    void setCounterIncrement(short v) {  SET_VAR(visual,counterIncrement,v) }
+    void setCounterReset(short v) {  SET_VAR(visual,counterReset,v) }
 
     void setListStyleType(EListStyleType v) { inherited_flags._list_style_type = v; }
     void setListStyleImage(CachedImage *v) {  SET_VAR(inherited,style_image,v)}
@@ -1626,6 +1651,17 @@ public:
     bool contentDataEquivalent(const RenderStyle *otherStyle) const;
     void setContent(StringImpl* s, bool add = false);
     void setContent(CachedResource* o, bool add = false);
+    void setContent(CounterData*, bool add = false);
+
+    bool counterDataEquivalent(RenderStyle*);
+    void setCounterResetList(PassRefPtr<CSSValueList> l) { counterResetList = l; }
+    void setCounterIncrementList(PassRefPtr<CSSValueList> l) { counterIncrementList = l; }
+    bool hasCounterReset(const String&) const;
+    bool hasCounterIncrement(const String&) const;
+    int counterReset(const String&) const;
+    int counterIncrement(const String&) const;
+    CSSValueList* counterResetValueList() { return counterResetList.get(); }
+    CSSValueList* counterIncrementValueList() { return counterIncrementList.get(); }
 
     bool inheritedNotEqual( RenderStyle *other ) const;