Make nsCSSFrameConstructor::AppendFrames be smarter about looking for :after

pseudos.  Move some utility functions into nsLayoutUtils; simplify some places
that basically had copies of those functions.  Improves perf a bit in bug
145425 and its dependencies, r+sr=roc+moz
This commit is contained in:
bzbarsky%mit.edu 2003-04-21 23:06:40 +00:00
Родитель 3f1a59f26e
Коммит f09182206c
10 изменённых файлов: 288 добавлений и 210 удалений

Просмотреть файл

@ -113,6 +113,7 @@
#include "nsCSSRendering.h"
#include "nsISelectElement.h"
#include "nsLayoutErrors.h"
#include "nsLayoutUtils.h"
#include "nsAutoPtr.h"
#include "nsScrollPortFrame.h"
#include "nsXULAtoms.h"
@ -7731,35 +7732,6 @@ nsCSSFrameConstructor::GetFloaterContainingBlock(nsIPresContext* aPresContext,
return containingBlock;
}
// Helper function to determine whether a given frame is generated content
// for the specified content object. Returns PR_TRUE if the frame is associated
// with generated content and PR_FALSE otherwise
static inline PRBool
IsGeneratedContentFor(nsIContent* aContent, nsIFrame* aFrame, nsIAtom* aPseudoElement)
{
NS_PRECONDITION(aFrame, "null frame pointer");
nsFrameState state;
PRBool result = PR_FALSE;
// First check the frame state bit
aFrame->GetFrameState(&state);
if (state & NS_FRAME_GENERATED_CONTENT) {
nsCOMPtr<nsIContent> content;
// Check that it has the same content pointer
aFrame->GetContent(getter_AddRefs(content));
if (content == aContent) {
nsStyleContext* styleContext = aFrame->GetStyleContext();
// See if the pseudo element type matches
nsCOMPtr<nsIAtom> pseudoType = styleContext->GetPseudoType();
result = (pseudoType == aPseudoElement);
}
}
return result;
}
/**
* This function is called by ContentAppended() and ContentInserted()
* when appending flowed frames to a parent's principal child list. It
@ -7774,18 +7746,24 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext,
nsIFrame* aParentFrame,
nsIFrame* aFrameList)
{
nsIFrame* firstChild;
aParentFrame->FirstChild(aPresContext, nsnull, &firstChild);
nsFrameList frames(firstChild);
nsIFrame* lastChild = frames.LastChild();
// See if the parent has an :after pseudo-element. Check for the presence
// of style first, since nsLayoutUtils::GetAfterFrame is sorta expensive.
nsStyleContext* parentStyle = aParentFrame->GetStyleContext();
if (nsLayoutUtils::HasPseudoStyle(aContainer, parentStyle,
nsCSSPseudoElements::after,
aPresContext)) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aParentFrame,
aPresContext);
if (afterFrame) {
nsIFrame* firstChild;
aParentFrame->FirstChild(aPresContext, nsnull, &firstChild);
nsFrameList frames(firstChild);
// See if the parent has an :after pseudo-element
if (lastChild && IsGeneratedContentFor(aContainer, lastChild,
nsCSSPseudoElements::after)) {
// Insert the frames before the :after pseudo-element.
return aFrameManager->InsertFrames(aPresContext, *aPresShell, aParentFrame,
nsnull, frames.GetPrevSiblingFor(lastChild),
// Insert the frames before the :after pseudo-element.
return aFrameManager->InsertFrames(aPresContext, *aPresShell, aParentFrame,
nsnull, frames.GetPrevSiblingFor(afterFrame),
aFrameList);
}
}
nsresult rv = NS_OK;
@ -9248,8 +9226,9 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
nsIFrame* firstChild;
parentFrame->FirstChild(aPresContext, nsnull, &firstChild);
if (firstChild && IsGeneratedContentFor(aContainer, firstChild,
nsCSSPseudoElements::before)) {
if (firstChild &&
nsLayoutUtils::IsGeneratedContentFor(aContainer, firstChild,
nsCSSPseudoElements::before)) {
// Insert the new frames after the :before pseudo-element
prevSibling = firstChild;
}
@ -9570,21 +9549,6 @@ nsCSSFrameConstructor::RemoveMappingsForFrameSubtree(nsIPresContext* aPresContex
return DeletingFrameSubtree(aPresContext, presShell, frameManager, aRemovedFrame);
}
static PRBool
HasPseudoStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsStyleContext* aStyleContext,
nsIAtom* aPseudoElement)
{
nsRefPtr<nsStyleContext> pseudoStyleContext;
if (aContent) {
pseudoStyleContext = aPresContext->ProbePseudoStyleContextFor(aContent,
aPseudoElement,
aStyleContext);
}
return pseudoStyleContext != nsnull;
}
NS_IMETHODIMP
nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext,
nsIContent* aContainer,
@ -11694,8 +11658,8 @@ nsCSSFrameConstructor::FindFrameWithContent(nsIPresContext* aPresContext,
// next sibling.
if (aContent->IsContentOfType(nsIContent::eELEMENT) &&
IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::before)) {
nsLayoutUtils::IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::before)) {
kidFrame->GetNextSibling(&kidFrame);
#ifdef DEBUG
NS_ASSERTION(kidFrame, ":before with no next sibling");
@ -11707,8 +11671,8 @@ nsCSSFrameConstructor::FindFrameWithContent(nsIPresContext* aPresContext,
// make sure it's not the :after pseudo frame.
NS_ASSERTION(nextSiblingContent.get() == aContent &&
!IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::after),
!nsLayoutUtils::IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::after),
":before frame not followed by primary frame");
}
#endif
@ -12136,8 +12100,9 @@ nsCSSFrameConstructor::HaveFirstLetterStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsStyleContext* aStyleContext)
{
return HasPseudoStyle(aPresContext, aContent, aStyleContext,
nsCSSPseudoElements::firstLetter);
return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
nsCSSPseudoElements::firstLetter,
aPresContext);
}
PRBool
@ -12145,8 +12110,9 @@ nsCSSFrameConstructor::HaveFirstLineStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsStyleContext* aStyleContext)
{
return HasPseudoStyle(aPresContext, aContent, aStyleContext,
nsCSSPseudoElements::firstLine);
return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
nsCSSPseudoElements::firstLine,
aPresContext);
}
void

Просмотреть файл

@ -1889,19 +1889,14 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
if (!prevInFlow) {
// Checking for a :before frame is cheaper than getting the
// :before style context.
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(aFrame,
aPresContext);
if (!beforeFrame) {
// Look for a new :before style context
nsRefPtr<nsStyleContext> newBeforeContext = aPresContext->ProbePseudoStyleContextFor(localContent,
nsCSSPseudoElements::before,
newContext);
if (newBeforeContext) {
// Have to create the new :before frame
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
aChangeList.AppendChange(aFrame, content,
nsChangeHint_ReconstructFrame);
}
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);
}
}
}
@ -1910,29 +1905,24 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {
if (localContent && localContent->IsContentOfType(nsIContent::eELEMENT)) {
// Check for new :after content, but only if the frame is the first-in-flow.
// 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.
nsRefPtr<nsStyleContext> newAfterContext = aPresContext->ProbePseudoStyleContextFor(localContent,
nsCSSPseudoElements::after,
newContext);
if (newAfterContext) {
// Check whether we already have an :after frame
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aFrame,
aPresContext);
if (!afterFrame) {
// have to create one
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
aChangeList.AppendChange(aFrame, content,
nsChangeHint_ReconstructFrame);
}
// 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);
}
}
}
}
}

Просмотреть файл

@ -41,6 +41,8 @@
#include "nsIContent.h"
#include "nsFrameList.h"
#include "nsLayoutAtoms.h"
#include "nsIAtom.h"
#include "nsCSSPseudoElements.h"
/**
* A namespace class for static layout utilities.
@ -139,7 +141,8 @@ nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
aFrame->GetContent(getter_AddRefs(content));
nsIFrame* firstFrame = GetFirstChildFrame(aPresContext, aFrame, content);
if (firstFrame && firstFrame->IsGeneratedContentFrame()) {
if (firstFrame && IsGeneratedContentFor(nsnull, firstFrame,
nsCSSPseudoElements::before)) {
return firstFrame;
}
@ -156,13 +159,15 @@ nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
aFrame->GetContent(getter_AddRefs(content));
nsIFrame* lastFrame = GetLastChildFrame(aPresContext, aFrame, content);
if (lastFrame && lastFrame->IsGeneratedContentFrame()) {
if (lastFrame && IsGeneratedContentFor(nsnull, lastFrame,
nsCSSPseudoElements::after)) {
return lastFrame;
}
return nsnull;
}
// static
nsIFrame*
nsLayoutUtils::GetPageFrame(nsIFrame* aFrame)
{
@ -177,3 +182,30 @@ nsLayoutUtils::GetPageFrame(nsIFrame* aFrame)
}
return nsnull;
}
// static
PRBool
nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent,
nsIFrame* aFrame,
nsIAtom* aPseudoElement)
{
NS_PRECONDITION(aFrame, "Must have a frame");
NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
if (!aFrame->IsGeneratedContentFrame()) {
return PR_FALSE;
}
if (aContent) {
nsCOMPtr<nsIContent> content;
aFrame->GetContent(getter_AddRefs(content));
if (content != aContent) {
return PR_FALSE;
}
}
nsStyleContext* styleContext = aFrame->GetStyleContext();
nsCOMPtr<nsIAtom> pseudoType = styleContext->GetPseudoType();
return pseudoType == aPseudoElement;
}

Просмотреть файл

@ -40,6 +40,12 @@
class nsIFrame;
class nsIPresContext;
class nsIContent;
class nsIAtom;
#include "prtypes.h"
#include "nsStyleContext.h"
#include "nsAutoPtr.h"
/**
* nsLayoutUtils is a namespace class used for various helper
@ -72,11 +78,58 @@ public:
*/
static nsIFrame* GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext);
/** ---------------------------------------------------
* Giving a child frame it searches "up" the tree until it
* finds a "Page" frame.
/**
* Given a frame, search up the frame tree until we find an
* ancestor "Page" frame, if any.
*
* @param the frame to start at
* @return a frame of type nsLayoutAtoms::pageFrame or nsnull if no
* such ancestor exists
*/
static nsIFrame* GetPageFrame(nsIFrame* aFrame);
/**
* IsGeneratedContentFor returns PR_TRUE if aFrame is generated
* content of type aPseudoElement for aContent
*
* @param aContent the content node we're looking at. If this is
* null, then we just assume that aFrame has the right content
* pointer.
* @param aFrame the frame we're looking at
* @param aPseudoElement the pseudo type we're interested in
* @return whether aFrame is the generated aPseudoElement frame for aContent
*/
static PRBool IsGeneratedContentFor(nsIContent* aContent, nsIFrame* aFrame,
nsIAtom* aPseudoElement);
/**
* HasPseudoStyle returns PR_TRUE if aContent (whose primary style
* context is aStyleContext) has the aPseudoElement pseudo-style
* attached to it; returns PR_FALSE otherwise.
*
* @param aContent the content node we're looking at
* @param aStyleContext aContent's style context
* @param aPseudoElement the name of the pseudo style we care about
* @param aPresContext the presentation context
* @return whether aContent has aPseudoElement style attached to it
*/
static PRBool HasPseudoStyle(nsIContent* aContent,
nsStyleContext* aStyleContext,
nsIAtom* aPseudoElement,
nsIPresContext* aPresContext)
{
NS_PRECONDITION(aPresContext, "Must have a prescontext");
NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
nsRefPtr<nsStyleContext> pseudoContext;
if (aContent) {
pseudoContext = aPresContext->ProbePseudoStyleContextFor(aContent,
aPseudoElement,
aStyleContext);
}
return pseudoContext != nsnull;
}
};
#endif // nsLayoutUtils_h__

Просмотреть файл

@ -4718,13 +4718,11 @@ PresShell::GetGeneratedContentIterator(nsIContent* aContent,
// Avoid finding the :after frame unless we need to (it's
// expensive). Instead probe for the existence of the pseudo-element
nsStyleContext *styleContext;
nsRefPtr<nsStyleContext> pseudoStyleContext;
styleContext = primaryFrame->GetStyleContext();
pseudoStyleContext = mPresContext->ProbePseudoStyleContextFor(aContent,
nsCSSPseudoElements::after,
styleContext);
if (pseudoStyleContext) {
if (nsLayoutUtils::HasPseudoStyle(aContent, styleContext,
nsCSSPseudoElements::after,
mPresContext)) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(primaryFrame,
mPresContext);
if (afterFrame)

Просмотреть файл

@ -40,6 +40,12 @@
class nsIFrame;
class nsIPresContext;
class nsIContent;
class nsIAtom;
#include "prtypes.h"
#include "nsStyleContext.h"
#include "nsAutoPtr.h"
/**
* nsLayoutUtils is a namespace class used for various helper
@ -72,11 +78,58 @@ public:
*/
static nsIFrame* GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext);
/** ---------------------------------------------------
* Giving a child frame it searches "up" the tree until it
* finds a "Page" frame.
/**
* Given a frame, search up the frame tree until we find an
* ancestor "Page" frame, if any.
*
* @param the frame to start at
* @return a frame of type nsLayoutAtoms::pageFrame or nsnull if no
* such ancestor exists
*/
static nsIFrame* GetPageFrame(nsIFrame* aFrame);
/**
* IsGeneratedContentFor returns PR_TRUE if aFrame is generated
* content of type aPseudoElement for aContent
*
* @param aContent the content node we're looking at. If this is
* null, then we just assume that aFrame has the right content
* pointer.
* @param aFrame the frame we're looking at
* @param aPseudoElement the pseudo type we're interested in
* @return whether aFrame is the generated aPseudoElement frame for aContent
*/
static PRBool IsGeneratedContentFor(nsIContent* aContent, nsIFrame* aFrame,
nsIAtom* aPseudoElement);
/**
* HasPseudoStyle returns PR_TRUE if aContent (whose primary style
* context is aStyleContext) has the aPseudoElement pseudo-style
* attached to it; returns PR_FALSE otherwise.
*
* @param aContent the content node we're looking at
* @param aStyleContext aContent's style context
* @param aPseudoElement the name of the pseudo style we care about
* @param aPresContext the presentation context
* @return whether aContent has aPseudoElement style attached to it
*/
static PRBool HasPseudoStyle(nsIContent* aContent,
nsStyleContext* aStyleContext,
nsIAtom* aPseudoElement,
nsIPresContext* aPresContext)
{
NS_PRECONDITION(aPresContext, "Must have a prescontext");
NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
nsRefPtr<nsStyleContext> pseudoContext;
if (aContent) {
pseudoContext = aPresContext->ProbePseudoStyleContextFor(aContent,
aPseudoElement,
aStyleContext);
}
return pseudoContext != nsnull;
}
};
#endif // nsLayoutUtils_h__

Просмотреть файл

@ -41,6 +41,8 @@
#include "nsIContent.h"
#include "nsFrameList.h"
#include "nsLayoutAtoms.h"
#include "nsIAtom.h"
#include "nsCSSPseudoElements.h"
/**
* A namespace class for static layout utilities.
@ -139,7 +141,8 @@ nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
aFrame->GetContent(getter_AddRefs(content));
nsIFrame* firstFrame = GetFirstChildFrame(aPresContext, aFrame, content);
if (firstFrame && firstFrame->IsGeneratedContentFrame()) {
if (firstFrame && IsGeneratedContentFor(nsnull, firstFrame,
nsCSSPseudoElements::before)) {
return firstFrame;
}
@ -156,13 +159,15 @@ nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
aFrame->GetContent(getter_AddRefs(content));
nsIFrame* lastFrame = GetLastChildFrame(aPresContext, aFrame, content);
if (lastFrame && lastFrame->IsGeneratedContentFrame()) {
if (lastFrame && IsGeneratedContentFor(nsnull, lastFrame,
nsCSSPseudoElements::after)) {
return lastFrame;
}
return nsnull;
}
// static
nsIFrame*
nsLayoutUtils::GetPageFrame(nsIFrame* aFrame)
{
@ -177,3 +182,30 @@ nsLayoutUtils::GetPageFrame(nsIFrame* aFrame)
}
return nsnull;
}
// static
PRBool
nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent,
nsIFrame* aFrame,
nsIAtom* aPseudoElement)
{
NS_PRECONDITION(aFrame, "Must have a frame");
NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
if (!aFrame->IsGeneratedContentFrame()) {
return PR_FALSE;
}
if (aContent) {
nsCOMPtr<nsIContent> content;
aFrame->GetContent(getter_AddRefs(content));
if (content != aContent) {
return PR_FALSE;
}
}
nsStyleContext* styleContext = aFrame->GetStyleContext();
nsCOMPtr<nsIAtom> pseudoType = styleContext->GetPseudoType();
return pseudoType == aPseudoElement;
}

Просмотреть файл

@ -1889,19 +1889,14 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
if (!prevInFlow) {
// Checking for a :before frame is cheaper than getting the
// :before style context.
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(aFrame,
aPresContext);
if (!beforeFrame) {
// Look for a new :before style context
nsRefPtr<nsStyleContext> newBeforeContext = aPresContext->ProbePseudoStyleContextFor(localContent,
nsCSSPseudoElements::before,
newContext);
if (newBeforeContext) {
// Have to create the new :before frame
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
aChangeList.AppendChange(aFrame, content,
nsChangeHint_ReconstructFrame);
}
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);
}
}
}
@ -1910,29 +1905,24 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {
if (localContent && localContent->IsContentOfType(nsIContent::eELEMENT)) {
// Check for new :after content, but only if the frame is the first-in-flow.
// 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.
nsRefPtr<nsStyleContext> newAfterContext = aPresContext->ProbePseudoStyleContextFor(localContent,
nsCSSPseudoElements::after,
newContext);
if (newAfterContext) {
// Check whether we already have an :after frame
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aFrame,
aPresContext);
if (!afterFrame) {
// have to create one
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
aChangeList.AppendChange(aFrame, content,
nsChangeHint_ReconstructFrame);
}
// 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);
}
}
}
}
}

Просмотреть файл

@ -4718,13 +4718,11 @@ PresShell::GetGeneratedContentIterator(nsIContent* aContent,
// Avoid finding the :after frame unless we need to (it's
// expensive). Instead probe for the existence of the pseudo-element
nsStyleContext *styleContext;
nsRefPtr<nsStyleContext> pseudoStyleContext;
styleContext = primaryFrame->GetStyleContext();
pseudoStyleContext = mPresContext->ProbePseudoStyleContextFor(aContent,
nsCSSPseudoElements::after,
styleContext);
if (pseudoStyleContext) {
if (nsLayoutUtils::HasPseudoStyle(aContent, styleContext,
nsCSSPseudoElements::after,
mPresContext)) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(primaryFrame,
mPresContext);
if (afterFrame)

Просмотреть файл

@ -113,6 +113,7 @@
#include "nsCSSRendering.h"
#include "nsISelectElement.h"
#include "nsLayoutErrors.h"
#include "nsLayoutUtils.h"
#include "nsAutoPtr.h"
#include "nsScrollPortFrame.h"
#include "nsXULAtoms.h"
@ -7731,35 +7732,6 @@ nsCSSFrameConstructor::GetFloaterContainingBlock(nsIPresContext* aPresContext,
return containingBlock;
}
// Helper function to determine whether a given frame is generated content
// for the specified content object. Returns PR_TRUE if the frame is associated
// with generated content and PR_FALSE otherwise
static inline PRBool
IsGeneratedContentFor(nsIContent* aContent, nsIFrame* aFrame, nsIAtom* aPseudoElement)
{
NS_PRECONDITION(aFrame, "null frame pointer");
nsFrameState state;
PRBool result = PR_FALSE;
// First check the frame state bit
aFrame->GetFrameState(&state);
if (state & NS_FRAME_GENERATED_CONTENT) {
nsCOMPtr<nsIContent> content;
// Check that it has the same content pointer
aFrame->GetContent(getter_AddRefs(content));
if (content == aContent) {
nsStyleContext* styleContext = aFrame->GetStyleContext();
// See if the pseudo element type matches
nsCOMPtr<nsIAtom> pseudoType = styleContext->GetPseudoType();
result = (pseudoType == aPseudoElement);
}
}
return result;
}
/**
* This function is called by ContentAppended() and ContentInserted()
* when appending flowed frames to a parent's principal child list. It
@ -7774,18 +7746,24 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext,
nsIFrame* aParentFrame,
nsIFrame* aFrameList)
{
nsIFrame* firstChild;
aParentFrame->FirstChild(aPresContext, nsnull, &firstChild);
nsFrameList frames(firstChild);
nsIFrame* lastChild = frames.LastChild();
// See if the parent has an :after pseudo-element. Check for the presence
// of style first, since nsLayoutUtils::GetAfterFrame is sorta expensive.
nsStyleContext* parentStyle = aParentFrame->GetStyleContext();
if (nsLayoutUtils::HasPseudoStyle(aContainer, parentStyle,
nsCSSPseudoElements::after,
aPresContext)) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(aParentFrame,
aPresContext);
if (afterFrame) {
nsIFrame* firstChild;
aParentFrame->FirstChild(aPresContext, nsnull, &firstChild);
nsFrameList frames(firstChild);
// See if the parent has an :after pseudo-element
if (lastChild && IsGeneratedContentFor(aContainer, lastChild,
nsCSSPseudoElements::after)) {
// Insert the frames before the :after pseudo-element.
return aFrameManager->InsertFrames(aPresContext, *aPresShell, aParentFrame,
nsnull, frames.GetPrevSiblingFor(lastChild),
// Insert the frames before the :after pseudo-element.
return aFrameManager->InsertFrames(aPresContext, *aPresShell, aParentFrame,
nsnull, frames.GetPrevSiblingFor(afterFrame),
aFrameList);
}
}
nsresult rv = NS_OK;
@ -9248,8 +9226,9 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
nsIFrame* firstChild;
parentFrame->FirstChild(aPresContext, nsnull, &firstChild);
if (firstChild && IsGeneratedContentFor(aContainer, firstChild,
nsCSSPseudoElements::before)) {
if (firstChild &&
nsLayoutUtils::IsGeneratedContentFor(aContainer, firstChild,
nsCSSPseudoElements::before)) {
// Insert the new frames after the :before pseudo-element
prevSibling = firstChild;
}
@ -9570,21 +9549,6 @@ nsCSSFrameConstructor::RemoveMappingsForFrameSubtree(nsIPresContext* aPresContex
return DeletingFrameSubtree(aPresContext, presShell, frameManager, aRemovedFrame);
}
static PRBool
HasPseudoStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsStyleContext* aStyleContext,
nsIAtom* aPseudoElement)
{
nsRefPtr<nsStyleContext> pseudoStyleContext;
if (aContent) {
pseudoStyleContext = aPresContext->ProbePseudoStyleContextFor(aContent,
aPseudoElement,
aStyleContext);
}
return pseudoStyleContext != nsnull;
}
NS_IMETHODIMP
nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext,
nsIContent* aContainer,
@ -11694,8 +11658,8 @@ nsCSSFrameConstructor::FindFrameWithContent(nsIPresContext* aPresContext,
// next sibling.
if (aContent->IsContentOfType(nsIContent::eELEMENT) &&
IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::before)) {
nsLayoutUtils::IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::before)) {
kidFrame->GetNextSibling(&kidFrame);
#ifdef DEBUG
NS_ASSERTION(kidFrame, ":before with no next sibling");
@ -11707,8 +11671,8 @@ nsCSSFrameConstructor::FindFrameWithContent(nsIPresContext* aPresContext,
// make sure it's not the :after pseudo frame.
NS_ASSERTION(nextSiblingContent.get() == aContent &&
!IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::after),
!nsLayoutUtils::IsGeneratedContentFor(aContent, kidFrame,
nsCSSPseudoElements::after),
":before frame not followed by primary frame");
}
#endif
@ -12136,8 +12100,9 @@ nsCSSFrameConstructor::HaveFirstLetterStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsStyleContext* aStyleContext)
{
return HasPseudoStyle(aPresContext, aContent, aStyleContext,
nsCSSPseudoElements::firstLetter);
return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
nsCSSPseudoElements::firstLetter,
aPresContext);
}
PRBool
@ -12145,8 +12110,9 @@ nsCSSFrameConstructor::HaveFirstLineStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsStyleContext* aStyleContext)
{
return HasPseudoStyle(aPresContext, aContent, aStyleContext,
nsCSSPseudoElements::firstLine);
return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext,
nsCSSPseudoElements::firstLine,
aPresContext);
}
void