NS_IF_RELEASE(childList); aFrame->GetAdditionalChildListName(listIndex++, &childList);
childList = aFrame->GetAdditionalChildListName(listIndex++);
FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,                                    nsIFrame* aFrame,                                    nsIContent* aParentContent,                                    PRInt32 aAttrNameSpaceID,                                    nsIAtom* aAttribute,                                    nsStyleChangeList& aChangeList,                                     nsChangeHint aMinChange,                                    nsChangeHint& aResultChange){  // XXXldb get new context from prev-in-flow if possible, to avoid  // duplication.  (Or should we just let |GetContext| handle that?)  // Getting the hint would be nice too, but that's harder.  // XXXbryner we may be able to avoid some of the refcounting goop here.  // We do need a reference to oldContext for the lifetime of this function, and it's possible  // that the frame has the last reference to it, so AddRef it here.  nsStyleContext* oldContext = aFrame->GetStyleContext();  nsresult result = NS_OK;  if (oldContext) {    oldContext->AddRef();    nsIAtom* pseudoTag = oldContext->GetPseudoType();    nsIContent* localContent = aFrame->GetContent();    nsIContent* content = localContent ? localContent : aParentContent;    if (aParentContent && aAttribute) { // attribute came from parent, we don't care about it here when recursing      if (!(aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT)) { // keep it for generated content        aAttribute = nsnull;      }    }    nsStyleContext* parentContext;    nsIFrame* resolvedChild = nsnull;    // Get the frame providing the parent style context.  If it is a    // child, then resolve the provider first.    nsIFrame* providerFrame = nsnull;    PRBool providerIsChild = PR_FALSE;    aFrame->GetParentStyleContextFrame(aPresContext,                                       &providerFrame, &providerIsChild);     if (!providerIsChild) {      if (providerFrame)        parentContext = providerFrame->GetStyleContext();      else        parentContext = nsnull;    }    else {      // resolve the provider here (before aFrame below)      ReResolveStyleContext(aPresContext, providerFrame, content,                             aAttrNameSpaceID, aAttribute, aChangeList,                            aMinChange, aResultChange);      // The provider's new context becomes the parent context of      // aFrame's context.      parentContext = providerFrame->GetStyleContext();      // Set |resolvedChild| so we don't bother resolving the      // provider again.      resolvedChild = providerFrame;    }        // do primary context    nsStyleContext* newContext = nsnull;    if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {      NS_ASSERTION(localContent,                   "non pseudo-element frame without content node");      newContext = aPresContext->ResolveStyleContextForNonElement(parentContext).get();    }    else if (pseudoTag) {      nsIContent* pseudoContent =          aParentContent ? aParentContent : localContent;      if (pseudoTag == nsCSSPseudoElements::before ||          pseudoTag == nsCSSPseudoElements::after) {        // XXX what other pseudos do we need to treat like this?        newContext = aPresContext->ProbePseudoStyleContextFor(pseudoContent,                                                              pseudoTag,                                                              parentContext).get();        if (!newContext) {          // This pseudo should no longer exist; gotta reframe          NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);          aChangeList.AppendChange(aFrame, pseudoContent,                                   nsChangeHint_ReconstructFrame);          // We're reframing anyway; just keep the same context          newContext = oldContext;          newContext->AddRef();        }      } else {        newContext = aPresContext->ResolvePseudoStyleContextFor(pseudoContent,                                                                pseudoTag,                                                                parentContext).get();      }    }    else {      NS_ASSERTION(localContent,                   "non pseudo-element frame without content node");      newContext = aPresContext->ResolveStyleContextFor(content, parentContext).get();    }    NS_ASSERTION(newContext, "failed to get new style context");    if (newContext) {      if (!parentContext) {        if (oldContext->GetRuleNode() == newContext->GetRuleNode()) {          // We're the root of the style context tree and the new style          // context returned has the same rule node.  This means that          // we can use FindChildWithRules to keep a lot of the old          // style contexts around.  However, we need to start from the          // same root.          newContext->Release();          newContext = oldContext;          newContext->AddRef();        }      }      if (newContext != oldContext) {        aMinChange = CaptureChange(oldContext, newContext, aFrame, content, aChangeList, aMinChange);        if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {          // if frame gets regenerated, let it keep old context          aFrame->SetStyleContext(aPresContext, newContext);        }        // if old context had image and new context does not have the same image,         // stop the image load for the frame        const nsStyleBackground* oldColor = oldContext->GetStyleBackground();        const nsStyleBackground* newColor = newContext->GetStyleBackground();        PRBool equal;        if (oldColor->mBackgroundImage &&            (!newColor->mBackgroundImage ||             NS_FAILED(oldColor->mBackgroundImage->Equals(                                        newColor->mBackgroundImage, &equal)) ||             !equal)) {          // stop the image loading for the frame, the image has changed          aPresContext->StopImagesFor(aFrame);        }      }      else {        if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement &&            aAttribute &&            (!(aMinChange &               (nsChangeHint_ReflowFrame | nsChangeHint_ReconstructFrame                | nsChangeHint_ReconstructDoc))) &&            HasAttributeContent(oldContext, aAttrNameSpaceID, aAttribute)) {          aChangeList.AppendChange(aFrame, content, NS_STYLE_HINT_REFLOW);        }      }      oldContext->Release();    }    else {      NS_ERROR("resolve style context failed");      newContext = oldContext;  // new context failed, recover... (take ref)      oldContext = nsnull;    }    // do additional contexts     PRInt32 contextIndex = -1;    while (1 == 1) {      nsStyleContext* oldExtraContext = nsnull;      oldExtraContext = aFrame->GetAdditionalStyleContext(++contextIndex);      if (oldExtraContext) {        nsStyleContext* newExtraContext = nsnull;        pseudoTag = oldExtraContext->GetPseudoType();        NS_ASSERTION(pseudoTag &&                     pseudoTag != nsCSSAnonBoxes::mozNonElement,                     "extra style context is not pseudo element");        newExtraContext = aPresContext->ResolvePseudoStyleContextFor(content,                                                                     pseudoTag,                                                                     newContext).get();        if (newExtraContext) {          if (oldExtraContext != newExtraContext) {            aMinChange = CaptureChange(oldExtraContext, newExtraContext, aFrame,                                        content, aChangeList, aMinChange);            if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {              aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);            }          }          else {#if 0            // XXXldb |oldContext| is null by this point, so this will            // never do anything.            if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement &&                aAttribute && (aMinChange < NS_STYLE_HINT_REFLOW) &&                HasAttributeContent(oldContext, aAttrNameSpaceID, aAttribute)) {              aChangeList.AppendChange(aFrame, content, NS_STYLE_HINT_REFLOW);            }#endif          }          newExtraContext->Release();        }      }      else {        break;      }    }    // now look for undisplayed child content and pseudos    if (localContent && mUndisplayedMap) {      for (UndisplayedNode* undisplayed =                                   mUndisplayedMap->GetFirstNode(localContent);           undisplayed; undisplayed = undisplayed->mNext) {        nsRefPtr<nsStyleContext> undisplayedContext;        pseudoTag = undisplayed->mStyle->GetPseudoType();        if (pseudoTag == nsnull) {  // child content          undisplayedContext = aPresContext->ResolveStyleContextFor(undisplayed->mContent,                                                                    newContext);        }        else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {          undisplayedContext = aPresContext->ResolveStyleContextForNonElement(newContext);        }        else {  // pseudo element          NS_NOTREACHED("no pseudo elements in undisplayed map");          NS_ASSERTION(pseudoTag, "pseudo element without tag");          undisplayedContext = aPresContext->ResolvePseudoStyleContextFor(localContent,                                                                          pseudoTag,                                                                          newContext);        }        if (undisplayedContext) {          const nsStyleDisplay* display = undisplayedContext->GetStyleDisplay();          if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {            aChangeList.AppendChange(nsnull,                                     undisplayed->mContent                                       ? NS_STATIC_CAST(nsIContent*,                                                        undisplayed->mContent)                                       : localContent,                                      NS_STYLE_HINT_FRAMECHANGE);            // The node should be removed from the undisplayed map when            // we reframe it.          } else {            // update the undisplayed node with the new context            undisplayed->mStyle = undisplayedContext;          }        }      }    }    aResultChange = aMinChange;    if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {      // Make sure not to do this for pseudo-frames -- those can't have :before      // or :after content.      if (!pseudoTag && localContent &&          localContent->IsContentOfType(nsIContent::eELEMENT)) {        // Check for a new :before pseudo and an existing :before        // frame, but only if the frame is the first-in-flow.        nsIFrame* prevInFlow = nsnull;        aFrame->GetPrevInFlow(&prevInFlow);        if (!prevInFlow) {          // Checking for a :before frame is cheaper than getting the          // :before style context.          if (!nsLayoutUtils::GetBeforeFrame(aFrame, aPresContext) &&              nsLayoutUtils::HasPseudoStyle(localContent, newContext,                                            nsCSSPseudoElements::before,                                            aPresContext)) {            // Have to create the new :before frame            NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);            aChangeList.AppendChange(aFrame, content,                                     nsChangeHint_ReconstructFrame);          }        }      }    }        if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {      // Make sure not to do this for pseudo-frames -- those can't have :before      // or :after content.      if (!pseudoTag && localContent &&          localContent->IsContentOfType(nsIContent::eELEMENT)) {        // Check for new :after content, but only if the frame is the        // first-in-flow.        nsIFrame* nextInFlow = nsnull;        aFrame->GetNextInFlow(&nextInFlow);        if (!nextInFlow) {          // Getting the :after frame is more expensive than getting the pseudo          // context, so get the pseudo context first.          if (nsLayoutUtils::HasPseudoStyle(localContent, newContext,                                            nsCSSPseudoElements::after,                                            aPresContext) &&              !nsLayoutUtils::GetAfterFrame(aFrame, aPresContext)) {            // have to create the new :after frame            NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);            aChangeList.AppendChange(aFrame, content,                                     nsChangeHint_ReconstructFrame);          }        }            }    }        if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {            // There is no need to waste time crawling into a frame's children on a frame change.      // The act of reconstructing frames will force new style contexts to be resolved on all      // of this frame's descendants anyway, so we want to avoid wasting time processing      // style contexts that we're just going to throw away anyway. - dwh      // now do children      PRInt32 listIndex = 0;      nsIAtom* childList = nsnull;      nsChangeHint childChange;      do {        nsIFrame* child = nsnull;        result = aFrame->FirstChild(aPresContext, childList, &child);        while (NS_SUCCEEDED(result) && child) {          if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {            // only do frames that are in flow            if (nsLayoutAtoms::placeholderFrame == child->GetType()) { // placeholder              // get out of flow frame and recur there              nsIFrame* outOfFlowFrame =                NS_STATIC_CAST(nsPlaceholderFrame*,child)->GetOutOfFlowFrame();              NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");              NS_ASSERTION(outOfFlowFrame != resolvedChild,                           "out-of-flow frame not a true descendant");              // |nsFrame::GetParentStyleContextFrame| checks being out              // of flow so that this works correctly.              ReResolveStyleContext(aPresContext, outOfFlowFrame, content,                                    aAttrNameSpaceID, aAttribute,                                    aChangeList, aMinChange, childChange);              // reresolve placeholder's context under the same parent              // as the out-of-flow frame              ReResolveStyleContext(aPresContext, child, content,                                    kNameSpaceID_Unknown, nsnull,                                    aChangeList, aMinChange, childChange);            }            else {  // regular child frame              if (child != resolvedChild) {                ReResolveStyleContext(aPresContext, child, content,                                      aAttrNameSpaceID, aAttribute,                                      aChangeList, aMinChange, childChange);              } else {                NOISY_TRACE_FRAME("child frame already resolved as descendent, skipping",aFrame);              }            }          }          child = child->GetNextSibling();        }        NS_IF_RELEASE(childList);        aFrame->GetAdditionalChildListName(listIndex++, &childList);      } while (childList);      // XXX need to do overflow frames???    }    newContext->Release();  }}