Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Public Attributes | Protected Attributes | Private Member Functions
nsFrameManager Class Reference

Frame manager interface. More...

#include <nsFrameManager.h>

Inheritance diagram for nsFrameManager:
Inheritance graph
[legend]
Collaboration diagram for nsFrameManager:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 nsFrameManager () NS_HIDDEN
 ~nsFrameManager () NS_HIDDEN
voidoperator new (size_t aSize, nsIPresShell *aHost)
 NS_HIDDEN_ (nsresult) Init(nsIPresShell *aPresShell
 NS_HIDDEN_ (void) Destroy()
 NS_HIDDEN_ (nsIFrame *) GetRootFrame()
 NS_HIDDEN_ (void) SetRootFrame(nsIFrame *aRootFrame)
 NS_HIDDEN_ (nsIFrame *) GetCanvasFrame()
 NS_HIDDEN_ (nsIFrame *) GetPrimaryFrameFor(nsIContent *aContent)
 NS_HIDDEN_ (nsresult) SetPrimaryFrameFor(nsIContent *aContent
 NS_HIDDEN_ (void) RemoveAsPrimaryFrame(nsIContent *aContent
 NS_HIDDEN_ (void) ClearPrimaryFrameMap()
 NS_HIDDEN_ (nsPlaceholderFrame *) GetPlaceholderFrameFor(nsIFrame *aFrame)
 RegisterPlaceholderFrame (nsPlaceholderFrame *aPlaceholderFrame)
 UnregisterPlaceholderFrame (nsPlaceholderFrame *aPlaceholderFrame)
 NS_HIDDEN_ (void) ClearPlaceholderFrameMap()
 NS_HIDDEN_ (nsStyleContext *) GetUndisplayedContent(nsIContent *aContent)
 NS_HIDDEN_ (void) SetUndisplayedContent(nsIContent *aContent
 NS_HIDDEN_ (void) ChangeUndisplayedContent(nsIContent *aContent
 NS_HIDDEN_ (void) ClearUndisplayedContentIn(nsIContent *aContent
 NS_HIDDEN_ (void) ClearAllUndisplayedContentIn(nsIContent *aParentContent)
 NS_HIDDEN_ (void) ClearUndisplayedContentMap()
 NS_HIDDEN_ (nsresult) AppendFrames(nsIFrame *aParentFrame
 NS_HIDDEN_ (nsresult) RemoveFrame(nsIFrame *aParentFrame
 NS_HIDDEN_ (nsresult) ReplaceFrame(nsIFrame *aParentFrame
 NS_HIDDEN_ (nsresult) ReParentStyleContext(nsIFrame *aFrame)
 ComputeStyleChangeFor (nsIFrame *aFrame, nsStyleChangeList *aChangeList, nsChangeHint aMinChange)
 NS_HIDDEN_ (nsReStyleHint) HasAttributeDependentStyle(nsIContent *aContent
 NS_HIDDEN_ (void) CaptureFrameState(nsIFrame *aFrame
 NS_HIDDEN_ (void) RestoreFrameState(nsIFrame *aFrame
 NS_HIDDEN_ (void) CaptureFrameStateFor(nsIFrame *aFrame
 NS_HIDDEN_ (void) RestoreFrameStateFor(nsIFrame *aFrame

Public Attributes

nsStyleSetaStyleSet
nsIFrameaPrimaryFrame
nsStyleContextaStyleContext
nsIContentaParentContent
nsIAtomaListName
nsIAtom nsIFrameaOldFrame
nsIAtomaAttribute
nsIAtom PRInt32 aModType
nsILayoutHistoryStateaState
nsILayoutHistoryState
nsIStatefulFrame::SpecialStateID 
aID

Protected Attributes

nsIPresShellmPresShell
nsStyleSetmStyleSet
nsIFramemRootFrame
PLDHashTable mPrimaryFrameMap
PLDHashTable mPlaceholderMap
UndisplayedMapmUndisplayedMap
PRBool mIsDestroyingFrames

Private Member Functions

 NS_HIDDEN_ (nsIPresShell *) GetPresShell() const
 NS_HIDDEN_ (nsPresContext *) GetPresContext() const
 ReResolveStyleContext (nsPresContext *aPresContext, nsIFrame *aFrame, nsIContent *aParentContent, nsStyleChangeList *aChangeList, nsChangeHint aMinChange)

Detailed Description

Frame manager interface.

The frame manager serves two purposes: provides a service for mapping from content to frame and from out-of-flow frame to placeholder frame. handles structural modifications to the frame model. If the frame model lock can be acquired, then the changes are processed immediately; otherwise, they're queued and processed later.

Do not add virtual methods to this class, or bryner will punish you.

Definition at line 69 of file nsFrameManager.h.


Constructor & Destructor Documentation

Definition at line 253 of file nsFrameManager.cpp.

{
}

Definition at line 257 of file nsFrameManager.cpp.

{
  NS_ASSERTION(!mPresShell, "nsFrameManager::Destroy never called");
}

Member Function Documentation

Definition at line 1376 of file nsFrameManager.cpp.

{
  nsChangeHint topLevelChange = aMinChange;

  nsIFrame* frame = aFrame;
  nsIFrame* frame2 = aFrame;

  NS_ASSERTION(!frame->GetPrevInFlow(), "must start with the first in flow");

  // We want to start with this frame and walk all its next-in-flows,
  // as well as all its special siblings and their next-in-flows,
  // reresolving style on all the frames we encounter in this walk.

  nsPropertyTable *propTable = GetPresContext()->PropertyTable();

  do {
    // Outer loop over special siblings
    do {
      // Inner loop over next-in-flows of the current frame
      nsChangeHint frameChange =
        ReResolveStyleContext(GetPresContext(), frame, nsnull,
                              aChangeList, topLevelChange);
      NS_UpdateHint(topLevelChange, frameChange);

      if (topLevelChange & nsChangeHint_ReconstructFrame) {
        // If it's going to cause a framechange, then don't bother
        // with the continuations or special siblings since they'll be
        // clobbered by the frame reconstruct anyway.
        NS_ASSERTION(!frame->GetPrevInFlow(),
                     "continuing frame had more severe impact than first-in-flow");
        return topLevelChange;
      }

      frame = frame->GetNextInFlow();
    } while (frame);

    // Might we have special siblings?
    if (!(frame2->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
      // nothing more to do here
      return topLevelChange;
    }
    
    frame2 = NS_STATIC_CAST(nsIFrame*,
         propTable->GetProperty(frame2, nsLayoutAtoms::IBSplitSpecialSibling));
    frame = frame2;
  } while (frame2);
  return topLevelChange;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 97 of file nsFrameManager.h.

{ return mRootFrame; }

Definition at line 98 of file nsFrameManager.h.

  {
    NS_ASSERTION(!mRootFrame, "already have a root frame");
    mRootFrame = aRootFrame;
  }
nsFrameManager::NS_HIDDEN_ ( nsIPresShell ) const [inline, private]

Definition at line 235 of file nsFrameManager.h.

{ return mPresShell; }
nsFrameManager::NS_HIDDEN_ ( nsPresContext ) const [inline, private]

Definition at line 236 of file nsFrameManager.h.

                                                    {
    return mPresShell->GetPresContext();
  }

Here is the call graph for this function:

void* nsFrameManager::operator new ( size_t  aSize,
nsIPresShell aHost 
) [inline]

Definition at line 75 of file nsFrameManager.h.

                                                        {
    NS_ASSERTION(aSize == sizeof(nsFrameManager), "Unexpected subclass");
    NS_ASSERTION(aSize == sizeof(nsFrameManagerBase),
                 "Superclass/subclass mismatch");
    return aHost->FrameManager();
  }

Definition at line 498 of file nsFrameManager.cpp.

{
  NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
  NS_PRECONDITION(nsLayoutAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
                  "unexpected frame type");
  if (!mPlaceholderMap.ops) {
    if (!PL_DHashTableInit(&mPlaceholderMap, &PlaceholderMapOps, nsnull,
                           sizeof(PlaceholderMapEntry), 16)) {
      mPlaceholderMap.ops = nsnull;
      return NS_ERROR_OUT_OF_MEMORY;
    }
  }
  PlaceholderMapEntry *entry = NS_STATIC_CAST(PlaceholderMapEntry*, 
         PL_DHashTableOperate(&mPlaceholderMap,
                              aPlaceholderFrame->GetOutOfFlowFrame(),
                              PL_DHASH_ADD));
  if (!entry)
    return NS_ERROR_OUT_OF_MEMORY;

  NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
  entry->placeholderFrame = aPlaceholderFrame;

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsChangeHint nsFrameManager::ReResolveStyleContext ( nsPresContext aPresContext,
nsIFrame aFrame,
nsIContent aParentContent,
nsStyleChangeList aChangeList,
nsChangeHint  aMinChange 
) [private]

Definition at line 1038 of file nsFrameManager.cpp.

{
  // 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.

  nsChangeHint assumeDifferenceHint = NS_STYLE_HINT_NONE;
  nsStyleContext* oldContext = aFrame->GetStyleContext();
  nsStyleSet* styleSet = aPresContext->StyleSet();

  if (oldContext) {
    oldContext->AddRef();
    nsIAtom* const pseudoTag = oldContext->GetPseudoType();
    nsIContent* localContent = aFrame->GetContent();
    nsIContent* content = localContent ? localContent : aParentContent;

    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).

      // assumeDifferenceHint forces the parent's change to be also
      // applied to this frame, no matter what
      // nsStyleStruct::CalcStyleDifference says. CalcStyleDifference
      // can't be trusted because it assumes any changes to the parent
      // style context provider will be automatically propagated to
      // the frame(s) with child style contexts.
      assumeDifferenceHint = ReResolveStyleContext(aPresContext, providerFrame,
                                                   content, aChangeList, aMinChange);

      // 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 = styleSet->ResolveStyleForNonElement(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 = styleSet->ProbePseudoStyleFor(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 = styleSet->ResolvePseudoStyleFor(pseudoContent,
                                                     pseudoTag,
                                                     parentContext).get();
      }
    }
    else {
      NS_ASSERTION(localContent,
                   "non pseudo-element frame without content node");
      newContext = styleSet->ResolveStyleFor(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,
                                   assumeDifferenceHint);
        if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
          // 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();

        if (oldColor->mBackgroundImage) {
          PRBool stopImages = !newColor->mBackgroundImage;
          if (!stopImages) {
            nsCOMPtr<nsIURI> oldURI, newURI;
            oldColor->mBackgroundImage->GetURI(getter_AddRefs(oldURI));
            newColor->mBackgroundImage->GetURI(getter_AddRefs(newURI));
            PRBool equal;
            stopImages =
              NS_FAILED(oldURI->Equals(newURI, &equal)) || !equal;
          }
          if (stopImages) {
            // stop the image loading for the frame, the image has changed
            aPresContext->StopImagesFor(aFrame);
          }
        }
      }
      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;
        nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudoType();
        NS_ASSERTION(extraPseudoTag &&
                     extraPseudoTag != nsCSSAnonBoxes::mozNonElement,
                     "extra style context is not pseudo element");
        newExtraContext = styleSet->ResolvePseudoStyleFor(content,
                                                          extraPseudoTag,
                                                          newContext).get();
        if (newExtraContext) {
          if (oldExtraContext != newExtraContext) {
            aMinChange = CaptureChange(oldExtraContext, newExtraContext,
                                       aFrame, content, aChangeList,
                                       aMinChange, assumeDifferenceHint);
            if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
              aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
            }
          }
          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;
        nsIAtom* const undisplayedPseudoTag = undisplayed->mStyle->GetPseudoType();
        if (!undisplayedPseudoTag) {  // child content
          undisplayedContext = styleSet->ResolveStyleFor(undisplayed->mContent,
                                                         newContext);
        }
        else if (undisplayedPseudoTag == nsCSSAnonBoxes::mozNonElement) {
          undisplayedContext = styleSet->ResolveStyleForNonElement(newContext);
        }
        else {  // pseudo element
          NS_NOTREACHED("no pseudo elements in undisplayed map");
          NS_ASSERTION(undisplayedPseudoTag, "pseudo element without tag");
          undisplayedContext = styleSet->ResolvePseudoStyleFor(localContent,
                                                               undisplayedPseudoTag,
                                                               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;
          }
        }
      }
    }

    if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
      // 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 = aFrame->GetPrevInFlow();
        if (!prevInFlow) {
          // Checking for a :before frame is cheaper than getting the
          // :before style context.
          if (!nsLayoutUtils::GetBeforeFrame(aFrame) &&
              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)) {
      // 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 = aFrame->GetNextInFlow();

        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)) {
            // have to create the new :after frame
            NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
            aChangeList->AppendChange(aFrame, content,
                                      nsChangeHint_ReconstructFrame);
          }
        }      
      }
    }
    
    if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
      
      // 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;

      do {
        nsIFrame* child = aFrame->GetFirstChild(childList);
        while (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 =
                nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
              NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
              NS_ASSERTION(outOfFlowFrame != resolvedChild,
                           "out-of-flow frame not a true descendant");

              // Note that the out-of-flow may not be a geometric descendant of
              // the frame where we started the reresolve.  Therefore, even if
              // aMinChange already includes nsChangeHint_ReflowFrame we don't
              // want to pass that on to the out-of-flow reresolve, since that
              // can lead to the out-of-flow not getting reflown when it should
              // be (eg a reresolve starting at <body> that involves reflowing
              // the <body> would miss reflowing fixed-pos nodes that also need
              // reflow).  In the cases when the out-of-flow _is_ a geometric
              // descendant of a frame we already have a reflow hint for,
              // reflow coalescing should keep us from doing the work twice.

              // |nsFrame::GetParentStyleContextFrame| checks being out
              // of flow so that this works correctly.
              ReResolveStyleContext(aPresContext, outOfFlowFrame,
                                    content, aChangeList,
                                    NS_SubtractHint(aMinChange,
                                                    nsChangeHint_ReflowFrame));

              // reresolve placeholder's context under the same parent
              // as the out-of-flow frame
              ReResolveStyleContext(aPresContext, child, content,
                                    aChangeList, aMinChange);
            }
            else {  // regular child frame
              if (child != resolvedChild) {
                ReResolveStyleContext(aPresContext, child, content,
                                      aChangeList, aMinChange);
              } else {
                NOISY_TRACE_FRAME("child frame already resolved as descendent, skipping",aFrame);
              }
            }
          }
          child = child->GetNextSibling();
        }

        childList = aFrame->GetAdditionalChildListName(listIndex++);
      } while (childList);
      // XXX need to do overflow frames???
    }

    newContext->Release();
  }

  return aMinChange;
}

Here is the call graph for this function:

Definition at line 524 of file nsFrameManager.cpp.

{
  NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
  NS_PRECONDITION(nsLayoutAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
                  "unexpected frame type");

  if (mPlaceholderMap.ops) {
    PL_DHashTableOperate(&mPlaceholderMap,
                         aPlaceholderFrame->GetOutOfFlowFrame(),
                         PL_DHASH_REMOVE);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 197 of file nsFrameManager.h.

Initial value:

Definition at line 218 of file nsFrameManager.h.

Definition at line 147 of file nsFrameManager.h.

Definition at line 197 of file nsFrameManager.h.

Definition at line 159 of file nsFrameManager.h.

Definition at line 141 of file nsFrameManager.h.

Definition at line 115 of file nsFrameManager.h.

Definition at line 207 of file nsFrameManager.h.

Definition at line 137 of file nsFrameManager.h.

Definition at line 83 of file nsFrameManager.h.

Definition at line 79 of file nsFrameManagerBase.h.

Definition at line 77 of file nsFrameManagerBase.h.

Definition at line 69 of file nsFrameManagerBase.h.

Definition at line 76 of file nsFrameManagerBase.h.

nsIFrame* nsFrameManagerBase::mRootFrame [protected, inherited]

Definition at line 75 of file nsFrameManagerBase.h.

nsStyleSet* nsFrameManagerBase::mStyleSet [protected, inherited]

Definition at line 74 of file nsFrameManagerBase.h.

Definition at line 78 of file nsFrameManagerBase.h.


The documentation for this class was generated from the following files: