summaryrefslogtreecommitdiffstats
path: root/WebCore/css/CSSSelector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/css/CSSSelector.cpp')
-rw-r--r--WebCore/css/CSSSelector.cpp75
1 files changed, 74 insertions, 1 deletions
diff --git a/WebCore/css/CSSSelector.cpp b/WebCore/css/CSSSelector.cpp
index 47ead5f..b1de4ec 100644
--- a/WebCore/css/CSSSelector.cpp
+++ b/WebCore/css/CSSSelector.cpp
@@ -31,11 +31,83 @@
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
namespace WebCore {
using namespace HTMLNames;
+// A helper class to hold CSSSelectors.
+class CSSSelectorBag : public Noncopyable {
+public:
+ ~CSSSelectorBag()
+ {
+ deleteAllValues(m_stack);
+ }
+
+ bool isEmpty() const
+ {
+ return m_stack.isEmpty();
+ }
+
+ void append(PassOwnPtr<CSSSelector> selector)
+ {
+ if (selector)
+ m_stack.append(selector.leakPtr());
+ }
+
+ PassOwnPtr<CSSSelector> takeAny()
+ {
+ ASSERT(!isEmpty());
+ OwnPtr<CSSSelector> selector = adoptPtr(m_stack.last());
+ m_stack.removeLast();
+ return selector.release();
+ }
+
+private:
+ Vector<CSSSelector*, 16> m_stack;
+};
+
+CSSSelector::~CSSSelector()
+{
+ // We should avoid a recursive destructor call, which causes stack overflow
+ // if CSS Selectors are deeply nested.
+
+ // Early exit if we have already processed the children of this selector.
+ if (m_hasRareData) {
+ if (!m_data.m_rareData)
+ return;
+ } else if (!m_data.m_tagHistory)
+ return;
+
+ CSSSelectorBag selectorsToBeDeleted;
+ if (m_hasRareData) {
+ selectorsToBeDeleted.append(m_data.m_rareData->m_tagHistory.release());
+ selectorsToBeDeleted.append(m_data.m_rareData->m_simpleSelector.release());
+ delete m_data.m_rareData;
+ } else
+ selectorsToBeDeleted.append(adoptPtr(m_data.m_tagHistory));
+
+ // Traverse the tree of CSSSelector and delete each CSSSelector iteratively.
+ while (!selectorsToBeDeleted.isEmpty()) {
+ OwnPtr<CSSSelector> selector(selectorsToBeDeleted.takeAny());
+ ASSERT(selector);
+ if (selector->m_hasRareData) {
+ ASSERT(selector->m_data.m_rareData);
+ selectorsToBeDeleted.append(selector->m_data.m_rareData->m_tagHistory.release());
+ selectorsToBeDeleted.append(selector->m_data.m_rareData->m_simpleSelector.release());
+ delete selector->m_data.m_rareData;
+ // Clear the pointer so that a destructor of the selector, which is
+ // about to be called, can know the children are already processed.
+ selector->m_data.m_rareData = 0;
+ } else {
+ selectorsToBeDeleted.append(adoptPtr(selector->m_data.m_tagHistory));
+ // Clear the pointer for the same reason.
+ selector->m_data.m_tagHistory = 0;
+ }
+ }
+}
+
unsigned int CSSSelector::specificity()
{
if (m_isForPage)
@@ -63,6 +135,7 @@ unsigned int CSSSelector::specificity()
break;
}
+ // FIXME: Avoid recursive calls to prevent possible stack overflow.
if (CSSSelector* tagHistory = this->tagHistory())
s += tagHistory->specificity();
@@ -906,5 +979,5 @@ bool CSSSelector::RareData::matchNth(int count)
return (m_b - count) % (-m_a) == 0;
}
}
-
+
} // namespace WebCore