Bug 62785 - konqueror hangs listbox selection
Summary: konqueror hangs listbox selection
Status: RESOLVED FIXED
Alias: None
Product: konqueror
Classification: Applications
Component: khtml ecma (show other bugs)
Version: unspecified
Platform: Mandrake RPMs Linux
: NOR normal
Target Milestone: ---
Assignee: Maksim Orlovich
URL:
Keywords:
: 42707 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-08-16 20:00 UTC by Salva
Modified: 2006-01-19 18:42 UTC (History)
4 users (show)

See Also:
Latest Commit:
Version Fixed In:
Sentry Crash Report:


Attachments
patch (5.63 KB, patch)
2005-12-13 18:24 UTC, Maksim Orlovich
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Salva 2003-08-16 20:00:56 UTC
Version:           desconocido (using KDE 3.1.0)
Installed from:    Mandrake Linux Cooker i586 - Cooker
Compiler:          gcc version 3.2.2 (Mandrake Linux 9.1 3.2.2-3mdk)
OS:          Linux (i686) release 2.4.21-0.13mdk

Konqueror stops indefinitely  or causes KHTML hangs when doing few clicks on listbox at http://www.netbeans.org/issues/query.cgi

I don't tested it on other computers.
Comment 1 Aaron J. Seigo 2003-08-17 22:05:25 UTC
to clarify: it's when clicking on the Component listbox, which causes the horrific 
bugzilla javascript to run. they have a lot of subcomponents/versions in their bugzilla, 
so the tripple-nested for loops in the script really bog things down. 
 
using CVS HEAD, konqueror takes ~12seconds of wall time to complete the script. a 
recent version of mozilla takes ~10seconds of wall time (during which period it's 
unrespsonsive as well). 
 
in CVS, however, konqueror provides the option to suspend the offending javascript 
after a few seconds via a dialog box. 
 
personally, i'd consider this more a problem with the javascript on the page, and even 
be inclined to close it since Konqueror now provides a way to abort the script. 
Comment 2 Frauke Oster 2003-08-18 12:28:12 UTC
I tried to open the website in the Internet Explorer and clicked on the listbox around. 
There weren't any problems while clicking on the listbox.  
I hope this information helps. 
Comment 3 Aaron J. Seigo 2003-08-18 19:38:43 UTC
thanks for checking that Frauke...  
 
so our javascript implementation has some rather serious performance issues left to 
be addressed. i'll keep my eye on its progress for this BR... 
Comment 4 Daniel Arnold 2005-02-25 01:24:23 UTC
I tested it with KDE 3.3.2a and this bug ist still present (although you get the message that asks if you want to abort the execution of the JavaScript). However Mozilla 1.4 also shows this lag on that page...

Comment 5 Ismail Donmez 2005-12-10 06:12:07 UTC
Also got this on http://bugzilla.ubuntu.com/query.cgi?format=advanced when selection Ubuntu as product and this is a bug not a wishlist.
Comment 6 Thiago Macieira 2005-12-11 15:51:46 UTC
It's a wishlist as long as it's requesting performance improvements.
Comment 7 Maksim Orlovich 2005-12-11 16:58:41 UTC
I disagree -- and I am the person likely to fix it. It's not a wishlist if it's talking about -horrible- performance
Comment 8 Maksim Orlovich 2005-12-13 09:13:50 UTC
*** Bug 42707 has been marked as a duplicate of this bug. ***
Comment 9 Maksim Orlovich 2005-12-13 17:15:42 UTC
Original report is down to a couple seconds or so on current tree. Not too stellar, but IMHO not unacceptable --- and the website forces us to go through 2 layers of caching(!) to make stuff reasonably fast, something that would be trivial to change in the code...

As for cartman's part: testing a patch right now.
Comment 10 Maksim Orlovich 2005-12-13 17:20:44 UTC
Hmm, actually, that may be with my patched tree...
Comment 11 Maksim Orlovich 2005-12-13 18:24:43 UTC
Created attachment 13896 [details]
patch 

here is the patch for the problem Ismail reported. Might make the original
faster, too
Comment 12 Ismail Donmez 2005-12-13 18:39:17 UTC
I can confirm it fixes my test case. Thanks Maksim ( once again ) !
Comment 13 Ismail Donmez 2005-12-13 20:02:25 UTC
Salı 13 Aralık 2005 19:24 tarihinde, Maksim Orlovich şunları yazmıştı: 
[bugs.kde.org quoted mail]

I can confirm it fixes my test case. Thanks Maksim ( once again ) !
Comment 14 Maksim Orlovich 2006-01-19 18:42:53 UTC
SVN commit 500223 by orlovich:

Optimize appends and clears to/of selects via explicit APIs. 
BUG:62785


 M  +1 -1      ecma/kjs_html.cpp  
 M  +42 -13    html/html_formimpl.cpp  
 M  +3 -2      html/html_formimpl.h  


--- branches/KDE/3.5/kdelibs/khtml/ecma/kjs_html.cpp #500222:500223
@@ -3336,7 +3336,7 @@
     }
     else // remove elements
       while (diff-- > 0)
-        element.remove(newLen);
+        element.remove(newLen + diff);
 
     return;
   }
--- branches/KDE/3.5/kdelibs/khtml/html/html_formimpl.cpp #500222:500223
@@ -1893,6 +1893,7 @@
     // 0 means invalid (i.e. not set)
     m_size = 0;
     m_minwidth = 0;
+    m_length   = 0;
 }
 
 HTMLSelectElementImpl::~HTMLSelectElementImpl()
@@ -1946,15 +1947,9 @@
 
 long HTMLSelectElementImpl::length() const
 {
-    int len = 0;
-    uint i;
-    QMemArray<HTMLGenericFormElementImpl*> items = listItems();
-    const uint itemsSize = items.size();
-    for (i = 0; i < itemsSize; ++i) {
-        if (items[i]->id() == ID_OPTION)
-            ++len;
-    }
-    return len;
+    if (m_recalcListItems)
+        recalcListItems();
+    return m_length;
 }
 
 void HTMLSelectElementImpl::add( const HTMLElement &element, const HTMLElement &before, int& exceptioncode )
@@ -1962,8 +1957,21 @@
     if(element.isNull() || element.handle()->id() != ID_OPTION)
         return;
 
-    insertBefore(element.handle(), before.handle(), exceptioncode );
-    if (!exceptioncode)
+    HTMLOptionElementImpl* option = static_cast<HTMLOptionElementImpl*>(element.handle());;
+    //Fast path for appending an item. Can't be done if it is selected and 
+    //we're single-select, since we may need to drop an implicitly-selected item
+    bool fastAppendLast = false;
+    if (before.handle() == 0 && (m_multiple || !option->selected()) && !m_recalcListItems)
+        fastAppendLast = true;
+
+    insertBefore(option, before.handle(), exceptioncode );
+
+    if (fastAppendLast) {
+        m_listItems.resize(m_listItems.size() + 1);
+        m_listItems[m_listItems.size() - 1] = option;
+        ++m_length;
+        m_recalcListItems = false;
+    } else if (!exceptioncode)
         setRecalcListItems();
 }
 
@@ -1976,8 +1984,22 @@
     if(listIndex < 0 || index >= int(items.size()))
         return; // ### what should we do ? remove the last item?
 
+    //Fast path for last element, for e.g. clearing the box
+    //Note that if this is a single-select, we may have to recompute
+    //anyway if the item was selected, since we may want to set 
+    //a different one
+    bool fastRemoveLast = false;
+    if ((listIndex == items.size() - 1) && !m_recalcListItems && 
+        (m_multiple || !static_cast<HTMLOptionElementImpl*>(items[listIndex])->selected()))
+            fastRemoveLast = true;
+
     removeChild(items[listIndex], exceptioncode);
-    if( !exceptioncode )
+
+    if (fastRemoveLast) {
+        m_listItems.resize(m_listItems.size() - 1);
+        --m_length;
+        m_recalcListItems = false;
+    } else if( !exceptioncode)
         setRecalcListItems();
 }
 
@@ -2220,6 +2242,11 @@
     if (optionIndex < 0 || optionIndex >= itemsSize)
         return -1;
 
+    //See if we're asked for the very last item, and check whether it's an <option>
+    //to fastpath clear
+    if (optionIndex == (m_length - 1) && items[itemsSize - 1]->id() == ID_OPTION)
+        return itemsSize - 1;
+
     int listIndex = 0;
     int optionIndex2 = 0;
     for (;
@@ -2247,11 +2274,12 @@
     return optionIndex;
 }
 
-void HTMLSelectElementImpl::recalcListItems()
+void HTMLSelectElementImpl::recalcListItems() const
 {
     NodeImpl* current = firstChild();
     m_listItems.resize(0);
     HTMLOptionElementImpl* foundSelected = 0;
+    m_length = 0;
     while(current) {
         if (current->id() == ID_OPTGROUP && current->firstChild()) {
             // ### what if optgroup contains just comments? don't want one of no options in it...
@@ -2260,6 +2288,7 @@
             current = current->firstChild();
         }
         if (current->id() == ID_OPTION) {
+            ++m_length;
             m_listItems.resize(m_listItems.size()+1);
             m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
             if (!foundSelected && !m_multiple && m_size <= 1) {
--- branches/KDE/3.5/kdelibs/khtml/html/html_formimpl.h #500222:500223
@@ -431,14 +431,15 @@
     void notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected);
 
 private:
-    void recalcListItems();
+    void recalcListItems() const;
 
 protected:
     mutable QMemArray<HTMLGenericFormElementImpl*> m_listItems;
     short m_minwidth;
     signed short m_size : 15;
     bool m_multiple : 1;
-    bool m_recalcListItems;
+    mutable bool m_recalcListItems :1;
+    mutable unsigned int   m_length:31;
 };
 
 // -------------------------------------------------------------------------