Bug 100507

Summary: Progress bar shadow tree sometimes is not relayouted.
Product: WebKit Reporter: Andrey Khalyavin <halyavin>
Component: Layout and RenderingAssignee: Nobody <webkit-unassigned>
Status: RESOLVED DUPLICATE    
Severity: Normal CC: tasak
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: PC   
OS: All   
Attachments:
Description Flags
test page none

Description Andrey Khalyavin 2012-10-26 05:06:54 PDT
Created attachment 170899 [details]
test page

Progress bar shadow tree sometimes is not relayouted.
Steps to reproduce:
1. Open page in attachment.
2. Click on a button.
3. See that first bar is updated while second bar is not.

What is going on behind the cover:
HTMLProgressElement has a shadow tree which consist in 3 nested divs. The most nested div (HTMLProgressElement::m_value) represents progress bar value and is updated by HTMLProgressElement::didElementStateChange method.

When javascripts on the page sets the second progress bar value, m_value node loses IsStyleAttributeValidFlag flag. Then <progress> element is inserted into tree and InDocumentFlag is set in m_value. Then Element::recalcStyle is called on HTMLProgressElement and it executes reattach method for it. Method reattach calls attach and as result m_value receives IsAttachedFlag. Then HTMLProgressElement::attach calls didElementStateChange method which calls m_value->setWidthPercentage which sets InlineStyleChange flag to m_value node and ChildNeedsStyleRecalc flag to all its parent nodes. But then reattach methods returns and Element::recalcStyle calls clearNeedsStyleRecalc and clearChildNeedsStyleRecalc methods on HTMLProgressElement node. 

So now we have m_value node that needs style recalculation but HTMLProgressElement node doesn't have ChildNeedsStyleRecalcFlag flag. As a result, any subsequent changes to progress element doesn't do anything since m_value is already marked as needed to recalculate style. But m_value never recalculates style since HTMLProgressElement doesn't have ChildNeedsRecalcFlag.
Comment 1 Takashi Sakamoto 2012-10-29 02:18:01 PDT
The reason why progress bar is not re-layouted is:
- HTMLProgressElement updates inline styles, i.e. setWidthPercentage, in HTMLProgressElement::attach().
- Element::recalcStyle updates HTMLProgressElement's style by using "reattach()".

Element::reaclcStyle()
...
            // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
            reattach();
            // attach recalculates the style for all children. No need to do it twice.
            clearNeedsStyleRecalc();
            clearChildNeedsStyleRecalc();
...

So after reattach(), clearNeedsStyleRecalc() and clearChildNeedsStyleRecalc() reset update flags set by setWidthPercentage. Now ProgressValueElement has had "InlineStyleChange" style change type, but its relayout flag is cleared. This disables "setNeedsStyleRecalc" to relayout:

void Node::setNeedsStyleRecalc(...)
...
    if (existingChangeType == NoStyleChange)
        markAncestorsWithChildNeedsStyleRecalc();
...

I will fix this issue by bug 83664.

Best regards,
Takashi Sakamoto

*** This bug has been marked as a duplicate of bug 83664 ***