[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    KDE/kdelibs/khtml
From:       Allan Sandfeld Jensen <kde () carewolf ! com>
Date:       2007-09-10 18:08:26
Message-ID: 1189447706.960459.923.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 710723 by carewolf:

Fix an issue in the non-deterministic matching that had a O(h^2) worst
time behaviour, where h is the height of the tree.
This fixes a runtime issues with invalid XHTML, like that used in Trolltech Qt
documentation.
BUG: 148715



 M  +8 -0      ChangeLog  
 M  +24 -15    css/cssstyleselector.cpp  
 M  +2 -1      css/cssstyleselector.h  


--- trunk/KDE/kdelibs/khtml/ChangeLog #710722:710723
@@ -1,3 +1,11 @@
+2007-10-09  Allan Sandfeld Jensen <kde@carewolf.com>
+
+        Optimize the case of double descendant selectors "a b c",
+        to avoid O(n^2) run-time where n is the depth of the DOM tree.
+
+        * css/cssstyleselector.h: Define new early termination value for \
checkSelector +        * css/cssstyleselector.cpp: Bail-out when the selector-chain \
can't possibly match +
 2007-01-21  Allan Sandfeld Jensen <kde@carewolf.com>
 
         Handle dynamic updates of default non-inherited properties that are \
                inherited explicitly
--- trunk/KDE/kdelibs/khtml/css/cssstyleselector.cpp #710722:710723
@@ -998,17 +998,21 @@
 }
 
 // Recursive check of selectors and combinators
-DOM::ElementImpl* CSSStyleSelector::checkSelector(DOM::CSSSelector *sel, \
DOM::ElementImpl *e, bool isAncestor, bool isSubSelector) +// It can return 3 \
different values: +// * SelectorMatches - the selector is match for the node e
+// * SelectorFailsLocal - the selector fails for the node e
+// * SelectorFails - the selector fails for e and any sibling or ancestor of e
+CSSStyleSelector::SelectorMatch CSSStyleSelector::checkSelector(DOM::CSSSelector \
*sel, DOM::ElementImpl *e, bool isAncestor, bool isSubSelector)  {
     // The simple selector has to match
-    if(!checkSimpleSelector(sel, e, isAncestor, isSubSelector)) return 0;
+    if(!checkSimpleSelector(sel, e, isAncestor, isSubSelector)) return \
SelectorFailsLocal;  
     // The rest of the selectors has to match
     CSSSelector::Relation relation = sel->relation;
 
     // Prepare next sel
     sel = sel->tagHistory;
-    if (!sel) return e;
+    if (!sel) return SelectorMatches;
 
     switch(relation) {
         case CSSSelector::Descendant:
@@ -1016,9 +1020,11 @@
             while(true)
             {
                 DOM::NodeImpl* n = e->parentNode();
-                if(!n || !n->isElementNode()) return 0;
+                if(!n || !n->isElementNode()) return SelectorFails;
                 e = static_cast<ElementImpl *>(n);
-                if(checkSelector(sel, e, true)) return e;
+                SelectorMatch match = checkSelector(sel, e, true);
+                if (match != SelectorFailsLocal)
+                    return match;
             }
             break;
         }
@@ -1027,10 +1033,9 @@
             DOM::NodeImpl* n = e->parentNode();
             if (!strictParsing)
                 while (n && n->implicitNode()) n = n->parentNode();
-            if(!n || !n->isElementNode()) return 0;
+            if(!n || !n->isElementNode()) return SelectorFails;
             e = static_cast<ElementImpl *>(n);
-            if(checkSelector(sel, e, true)) return e;
-            break;
+            return checkSelector(sel, e, true);
         }
         case CSSSelector::IndirectAdjacent:
         {
@@ -1043,9 +1048,11 @@
                 DOM::NodeImpl* n = e->previousSibling();
                 while( n && !n->isElementNode() )
                     n = n->previousSibling();
-                if( !n ) return 0;
+                if( !n ) return SelectorFailsLocal;
                 e = static_cast<ElementImpl *>(n);
-                if(checkSelector(sel, e, false)) return e;
+                SelectorMatch match = checkSelector(sel, e, false);
+                if (match != SelectorFailsLocal)
+                    return match;
             };
             break;
         }
@@ -1056,15 +1063,15 @@
             DOM::NodeImpl* n = e->previousSibling();
             while( n && !n->isElementNode() )
                 n = n->previousSibling();
-            if( !n ) return 0;
+            if( !n ) return SelectorFailsLocal;
             e = static_cast<ElementImpl *>(n);
-            if(checkSelector(sel, e, false)) return e;
-            break;
+            return checkSelector(sel, e, false);
         }
         case CSSSelector::SubSelector:
             return checkSelector(sel, e, isAncestor, true);
     }
-    return 0;
+    assert(false); // never reached
+    return SelectorFails;
 }
 
 void CSSStyleSelector::checkSelector(int selIndex, DOM::ElementImpl * e)
@@ -1075,8 +1082,10 @@
 
     selectorCache[ selIndex ].state = Invalid;
     CSSSelector *sel = selectors[ selIndex ];
+
     // Check the selector
-    if(!checkSelector(sel, e, true)) return;
+    SelectorMatch match = checkSelector(sel, e, true);
+    if(match != SelectorMatches) return;
 
     if ( dynamicPseudo != RenderStyle::NOPSEUDO ) {
 	selectorCache[selIndex].state = AppliesPseudo;
--- trunk/KDE/kdelibs/khtml/css/cssstyleselector.h #710722:710723
@@ -152,7 +152,8 @@
 	/* checks if the selector matches the given Element */
 	bool checkSimpleSelector(DOM::CSSSelector *selector, DOM::ElementImpl *e, bool \
isAncestor, bool isSubSelector = false);  
-       DOM::ElementImpl* checkSelector(DOM::CSSSelector *sel, DOM::ElementImpl *e, \
bool isAncestor, bool isSubSelector = false); +        enum SelectorMatch \
{SelectorMatches = 0, SelectorFailsLocal, SelectorFails}; +        SelectorMatch \
checkSelector(DOM::CSSSelector *sel, DOM::ElementImpl *e, bool isAncestor, bool \
isSubSelector = false);  
         void addDependency(StructuralDependencyType dependencyType, \
DOM::ElementImpl* dependency);  #ifdef APPLE_CHANGES


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic