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

List:       kde-commits
Subject:    branches/KDE/4.0/kdelibs/khtml/rendering
From:       Maks Orlovich <maksim () kde ! org>
Date:       2008-01-17 17:33:09
Message-ID: 1200591189.876592.16725.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 762684 by orlovich:

Do not emit onchange on synthetic toggling of radio buttons and checkboxes.
That's incompatible, and also led to #155973, crash on the beta BBC's page
location selector, as we have the following scenario:

1. JS sets checked.
2. We do updateFromElement, ask Qt to update the widget
3. The widget emits the change signal
4. The change signal handler does ref() [rc = 2]
5. The change signal handler does onchange(). The event running
causes a detach, which does a deref() [rc = 1]
6. The change signal handler does deref() [rc = 0], so the Render* gets destroyed
7. The common parts of updateFromElement, such as RenderWidget::updateFromElement, etc.,
run on a deleted RenderCheckBox/RadioButton, trying to access deleted
RenderStyle, etc. boom.

BUG: 155973

 M  +14 -2     render_form.cpp  
 M  +4 -0      render_form.h  


--- branches/KDE/4.0/kdelibs/khtml/rendering/render_form.cpp #762683:762684
@@ -242,6 +242,7 @@
     b->setChecked(element->checked());
 
     connect(b,SIGNAL(stateChanged(int)),this,SLOT(slotStateChanged(int)));
+    m_ignoreStateChanged = false;
 }
 
 
@@ -260,14 +261,19 @@
 
 void RenderCheckBox::updateFromElement()
 {
-    if (widget()->isChecked() != element()->checked())
+    if (widget()->isChecked() != element()->checked()) {
+        m_ignoreStateChanged = true; // We don't want an onchange here,
+                                     // or us getting yanked in a recalcStyle in the process, etc.
         widget()->setChecked(element()->checked());
+        m_ignoreStateChanged = false;
+    }
 
     RenderButton::updateFromElement();
 }
 
 void RenderCheckBox::slotStateChanged(int state)
 {
+    if (m_ignoreStateChanged) return;
     element()->setChecked(state == Qt::Checked);
 
     ref();
@@ -294,7 +300,7 @@
 
 RenderRadioButton::RenderRadioButton(HTMLInputElementImpl *element)
     : RenderButton(element)
-{
+{    
     RadioButtonWidget* b = new RadioButtonWidget(view()->widget());
     b->setMouseTracking(true);
     b->setAutoExclusive(false);
@@ -304,11 +310,14 @@
     b->setChecked(element->checked());
 
     connect(b,SIGNAL(toggled(bool)),this,SLOT(slotToggled(bool)));
+    m_ignoreToggled = false;
 }
 
 void RenderRadioButton::updateFromElement()
 {
+    m_ignoreToggled = true;
     widget()->setChecked(element()->checked());
+    m_ignoreToggled = false;
 
     RenderButton::updateFromElement();
 }
@@ -328,6 +337,9 @@
 
 void RenderRadioButton::slotToggled(bool activated)
 {
+    if (m_ignoreToggled)
+      return;
+
     if(activated) {
       ref();
       element()->onChange();
--- branches/KDE/4.0/kdelibs/khtml/rendering/render_form.h #762683:762684
@@ -153,6 +153,8 @@
 
 public Q_SLOTS:
     virtual void slotStateChanged(int state);
+private:
+    bool m_ignoreStateChanged;
 };
 
 // -------------------------------------------------------------------------
@@ -180,6 +182,8 @@
 
 public Q_SLOTS:
     virtual void slotToggled(bool);
+private:
+    bool m_ignoreToggled;
 };
 
 
[prev in list] [next in list] [prev in thread] [next in thread] 

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