зеркало из https://github.com/mozilla/gecko-dev.git
ReResolveStyleContext needs to deal with :before/:after pseudos correctly. Bug
126072, r=dbaron, sr=roc+moz. Also fixes bug 141259 (incorrect warnings about style tree integrity).
This commit is contained in:
Родитель
48739cd3f1
Коммит
8c8465ff11
|
@ -10336,6 +10336,22 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList,
|
|||
ApplyRenderingChangeToTree(aPresContext, frame, nsnull, hint);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// reget from content since it may have been regenerated...
|
||||
if (content) {
|
||||
nsIFrame* frame;
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
aPresContext->GetShell(getter_AddRefs(shell));
|
||||
shell->GetPrimaryFrameFor(content, &frame);
|
||||
if (frame) {
|
||||
nsCOMPtr<nsIFrameManager> frameManager;
|
||||
shell->GetFrameManager(getter_AddRefs(frameManager));
|
||||
frameManager->DebugVerifyStyleTree(aPresContext, frame);
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("Unable to test style tree integrity -- no content node");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
aChangeList.Clear();
|
||||
return NS_OK;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#ifdef NS_DEBUG
|
||||
#include "nsISupportsArray.h"
|
||||
|
@ -75,6 +76,7 @@
|
|||
#include "nsPrintfCString.h"
|
||||
#include "nsDummyLayoutRequest.h"
|
||||
#include "nsLayoutErrors.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
//#define NOISY_DEBUG
|
||||
|
@ -1742,9 +1744,26 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
|
|||
else if (pseudoTag) {
|
||||
nsIContent* pseudoContent =
|
||||
aParentContent ? aParentContent : localContent;
|
||||
aPresContext->ResolvePseudoStyleContextFor(pseudoContent, pseudoTag,
|
||||
if (pseudoTag == nsCSSPseudoElements::before ||
|
||||
pseudoTag == nsCSSPseudoElements::after) {
|
||||
// XXX what other pseudos do we need to treat like this?
|
||||
aPresContext->ProbePseudoStyleContextFor(pseudoContent, pseudoTag,
|
||||
parentContext,
|
||||
&newContext);
|
||||
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;
|
||||
NS_ADDREF(newContext);
|
||||
}
|
||||
} else {
|
||||
aPresContext->ResolvePseudoStyleContextFor(pseudoContent, pseudoTag,
|
||||
parentContext,
|
||||
&newContext);
|
||||
}
|
||||
NS_RELEASE(pseudoTag);
|
||||
}
|
||||
else {
|
||||
|
@ -1895,6 +1914,67 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
|
|||
aResultChange = aMinChange;
|
||||
|
||||
if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {
|
||||
if (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.
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(aFrame,
|
||||
aPresContext);
|
||||
if (!beforeFrame) {
|
||||
// Look for a new :before style context
|
||||
nsCOMPtr<nsIStyleContext> newBeforeContext;
|
||||
aPresContext->ProbePseudoStyleContextFor(localContent,
|
||||
nsCSSPseudoElements::before,
|
||||
newContext,
|
||||
getter_AddRefs(newBeforeContext));
|
||||
if (newBeforeContext) {
|
||||
// Have to create the new :before frame
|
||||
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
|
||||
aChangeList.AppendChange(aFrame, content,
|
||||
nsChangeHint_ReconstructFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
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.
|
||||
nsCOMPtr<nsIStyleContext> newAfterContext;
|
||||
aPresContext->ProbePseudoStyleContextFor(localContent,
|
||||
nsCSSPseudoElements::after,
|
||||
newContext,
|
||||
getter_AddRefs(newAfterContext));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1993,9 +2073,6 @@ FrameManager::ComputeStyleChangeFor(nsIPresContext* aPresContext,
|
|||
ReResolveStyleContext(aPresContext, frame, nsnull,
|
||||
aAttrNameSpaceID, aAttribute,
|
||||
aChangeList, aMinChange, frameChange);
|
||||
#ifdef NS_DEBUG
|
||||
VerifyStyleTree(aPresContext, frame, nsnull);
|
||||
#endif
|
||||
NS_UpdateHint(aTopLevelChange, frameChange);
|
||||
|
||||
if (aTopLevelChange & (nsChangeHint_ReconstructDoc | nsChangeHint_ReconstructFrame)) {
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsFrameList.h"
|
||||
|
||||
/**
|
||||
* A namespace class for static layout utilities.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GetFirstChildFrame returns the first "real" child frame of a
|
||||
* given frame. It will descend down into pseudo-frames (unless the
|
||||
* pseudo-frame is the :before generated frame).
|
||||
* @param aPresContext the prescontext
|
||||
* @param aFrame the frame
|
||||
* @param aFrame the frame's content node
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetFirstChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
nsIFrame* childFrame;
|
||||
|
||||
// Get the first child frame
|
||||
aFrame->FirstChild(aPresContext, nsnull, &childFrame);
|
||||
|
||||
// If the child frame is a pseudo-frame, then return its first child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (childFrame &&
|
||||
childFrame->IsPseudoFrame(aContent) &&
|
||||
!childFrame->IsGeneratedContentFrame()) {
|
||||
return GetFirstChildFrame(aPresContext, childFrame, aContent);
|
||||
}
|
||||
|
||||
return childFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLastChildFrame returns the last "real" child frame of a
|
||||
* given frame. It will descend down into pseudo-frames (unless the
|
||||
* pseudo-frame is the :after generated frame).
|
||||
* @param aPresContext the prescontext
|
||||
* @param aFrame the frame
|
||||
* @param aFrame the frame's content node
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetLastChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
// Get the last in flow frame
|
||||
nsIFrame* lastInFlow;
|
||||
do {
|
||||
lastInFlow = aFrame;
|
||||
lastInFlow->GetNextInFlow(&aFrame);
|
||||
} while (aFrame);
|
||||
|
||||
// Get the last child frame
|
||||
nsIFrame* firstChildFrame;
|
||||
lastInFlow->FirstChild(aPresContext, nsnull, &firstChildFrame);
|
||||
if (firstChildFrame) {
|
||||
nsFrameList frameList(firstChildFrame);
|
||||
nsIFrame* lastChildFrame = frameList.LastChild();
|
||||
|
||||
NS_ASSERTION(lastChildFrame, "unexpected error");
|
||||
|
||||
// Get the frame's first-in-flow. This matters in case the frame has
|
||||
// been continuted across multiple lines
|
||||
while (PR_TRUE) {
|
||||
nsIFrame* prevInFlow;
|
||||
lastChildFrame->GetPrevInFlow(&prevInFlow);
|
||||
if (prevInFlow) {
|
||||
lastChildFrame = prevInFlow;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the last child frame is a pseudo-frame, then return its last child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (lastChildFrame &&
|
||||
lastChildFrame->IsPseudoFrame(aContent) &&
|
||||
!lastChildFrame->IsGeneratedContentFrame()) {
|
||||
return GetLastChildFrame(aPresContext, lastChildFrame, aContent);
|
||||
}
|
||||
|
||||
return lastChildFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
#ifdef DEBUG
|
||||
nsIFrame* prevInFlow = nsnull;
|
||||
aFrame->GetPrevInFlow(&prevInFlow);
|
||||
NS_ASSERTION(!prevInFlow, "aFrame must be first-in-flow");
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
aFrame->GetContent(getter_AddRefs(content));
|
||||
nsIFrame* firstFrame = GetFirstChildFrame(aPresContext, aFrame, content);
|
||||
|
||||
if (firstFrame && firstFrame->IsGeneratedContentFrame()) {
|
||||
return firstFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
aFrame->GetContent(getter_AddRefs(content));
|
||||
nsIFrame* lastFrame = GetLastChildFrame(aPresContext, aFrame, content);
|
||||
|
||||
if (lastFrame && lastFrame->IsGeneratedContentFrame()) {
|
||||
return lastFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Boris Zbarsky <bzbarsky@mit.edu>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsLayoutUtils_h__
|
||||
#define nsLayoutUtils_h__
|
||||
|
||||
class nsIFrame;
|
||||
class nsIPresContext;
|
||||
|
||||
/**
|
||||
* nsLayoutUtils is a namespace class used for various helper
|
||||
* functions that are useful in multiple places in layout. The goal
|
||||
* is not to define multiple copies of the same static helper.
|
||||
*/
|
||||
class nsLayoutUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* GetBeforeFrame returns the :before frame of the given frame, if
|
||||
* one exists. This is typically O(1). The frame passed in must be
|
||||
* the first-in-flow.
|
||||
*
|
||||
* @param aFrame the frame whose :before is wanted
|
||||
* @param aPresContext the prescontext
|
||||
* @return the :before frame or nsnull if there isn't one
|
||||
*/
|
||||
static nsIFrame* GetBeforeFrame(nsIFrame* aFrame, nsIPresContext* aPresContext);
|
||||
|
||||
/**
|
||||
* GetAfterFrame returns the :after frame of the given frame, if one
|
||||
* exists. This will walk the in-flow chain to the last-in-flow if
|
||||
* needed. This function is typically O(N) in the number of child
|
||||
* frames, following in-flows, etc.
|
||||
*
|
||||
* @param aFrame the frame whose :after is wanted
|
||||
* @param aPresContext the prescontext
|
||||
* @return the :after frame or nsnull if there isn't one
|
||||
*/
|
||||
static nsIFrame* GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext);
|
||||
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
|
@ -108,6 +108,7 @@
|
|||
#include "nsIDocShell.h" // for reflow observation
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsLayoutErrors.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#ifdef MOZ_PERF_METRICS
|
||||
#include "nsITimeRecorder.h"
|
||||
#endif
|
||||
|
@ -4569,94 +4570,6 @@ PresShell::SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
IsGeneratedContentFrame(nsIFrame* aFrame)
|
||||
{
|
||||
nsFrameState frameState;
|
||||
|
||||
aFrame->GetFrameState(&frameState);
|
||||
return (frameState & NS_FRAME_GENERATED_CONTENT) != 0;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
IsPseudoFrame(nsIFrame* aFrame, nsIContent* aParentContent)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content;
|
||||
|
||||
aFrame->GetContent(getter_AddRefs(content));
|
||||
return content.get() == aParentContent;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
GetFirstChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
nsIFrame* childFrame;
|
||||
|
||||
// Get the first child frame
|
||||
aFrame->FirstChild(aPresContext, nsnull, &childFrame);
|
||||
|
||||
// If the child frame is a pseudo-frame, then return its first child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (childFrame && IsPseudoFrame(childFrame, aContent) &&
|
||||
!IsGeneratedContentFrame(childFrame)) {
|
||||
return GetFirstChildFrame(aPresContext, childFrame, aContent);
|
||||
}
|
||||
|
||||
return childFrame;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
GetLastChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
// Get the last in flow frame
|
||||
nsIFrame* lastInFlow;
|
||||
do {
|
||||
lastInFlow = aFrame;
|
||||
lastInFlow->GetNextInFlow(&aFrame);
|
||||
} while (aFrame);
|
||||
|
||||
// Get the last child frame
|
||||
nsIFrame* firstChildFrame;
|
||||
lastInFlow->FirstChild(aPresContext, nsnull, &firstChildFrame);
|
||||
if (firstChildFrame) {
|
||||
nsFrameList frameList(firstChildFrame);
|
||||
nsIFrame* lastChildFrame = frameList.LastChild();
|
||||
|
||||
NS_ASSERTION(lastChildFrame, "unexpected error");
|
||||
|
||||
// Get the frame's first-in-flow. This matters in case the frame has
|
||||
// been continuted across multiple lines
|
||||
while (PR_TRUE) {
|
||||
nsIFrame* prevInFlow;
|
||||
lastChildFrame->GetPrevInFlow(&prevInFlow);
|
||||
if (prevInFlow) {
|
||||
lastChildFrame = prevInFlow;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the last child frame is a pseudo-frame, then return its last child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (lastChildFrame && IsPseudoFrame(lastChildFrame, aContent) &&
|
||||
!IsGeneratedContentFrame(lastChildFrame)) {
|
||||
return GetLastChildFrame(aPresContext, lastChildFrame, aContent);
|
||||
}
|
||||
|
||||
return lastChildFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::GetGeneratedContentIterator(nsIContent* aContent,
|
||||
GeneratedContentType aType,
|
||||
|
@ -4673,17 +4586,16 @@ PresShell::GetGeneratedContentIterator(nsIContent* aContent,
|
|||
if (primaryFrame) {
|
||||
// See whether it's a request for the before or after generated content
|
||||
if (Before == aType) {
|
||||
// The most efficient thing to do is to get the first child frame,
|
||||
// and see if it is associated with generated content
|
||||
nsIFrame* firstChildFrame = GetFirstChildFrame(mPresContext, primaryFrame, aContent);
|
||||
if (firstChildFrame && IsGeneratedContentFrame(firstChildFrame)) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame,
|
||||
mPresContext);
|
||||
if (beforeFrame) {
|
||||
// Create an iterator
|
||||
rv = NS_NewFrameContentIterator(mPresContext, firstChildFrame, aIterator);
|
||||
rv = NS_NewFrameContentIterator(mPresContext, beforeFrame, aIterator);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Avoid finding the last child frame unless we need to. Instead probe
|
||||
// for the existence of the pseudo-element
|
||||
// Avoid finding the :after frame unless we need to (it's
|
||||
// expensive). Instead probe for the existence of the pseudo-element
|
||||
nsCOMPtr<nsIStyleContext> styleContext;
|
||||
nsCOMPtr<nsIStyleContext> pseudoStyleContext;
|
||||
|
||||
|
@ -4693,15 +4605,14 @@ PresShell::GetGeneratedContentIterator(nsIContent* aContent,
|
|||
styleContext,
|
||||
getter_AddRefs(pseudoStyleContext));
|
||||
if (pseudoStyleContext) {
|
||||
nsIFrame* lastChildFrame = GetLastChildFrame(mPresContext, primaryFrame, aContent);
|
||||
if (lastChildFrame)
|
||||
{ // it is now legal for GetLastChildFrame to return null. see bug 52307 (a regression from bug 18754)
|
||||
// in the case of a null child frame, we treat the frame as having no "after" style
|
||||
// the "before" handler above already does this check
|
||||
NS_ASSERTION(IsGeneratedContentFrame(lastChildFrame),
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(primaryFrame,
|
||||
mPresContext);
|
||||
if (afterFrame)
|
||||
{
|
||||
NS_ASSERTION(afterFrame->IsGeneratedContentFrame(),
|
||||
"can't find generated content frame");
|
||||
// Create an iterator
|
||||
rv = NS_NewFrameContentIterator(mPresContext, lastChildFrame, aIterator);
|
||||
rv = NS_NewFrameContentIterator(mPresContext, afterFrame, aIterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5490,6 +5401,9 @@ PresShell::ReconstructStyleData(PRBool aRebuildRuleTree)
|
|||
|
||||
if (aRebuildRuleTree)
|
||||
set->EndRuleTreeReconstruct();
|
||||
|
||||
VERIFY_STYLE_TREE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ nsIStyleFrameConstruction.h
|
|||
nsIStyleSet.h
|
||||
nsITextFrame.h
|
||||
nsLayoutErrors.h
|
||||
nsLayoutUtils.h
|
||||
nsReflowType.h
|
||||
nsStyleChangeList.h
|
||||
nsStyleConsts.h
|
||||
|
|
|
@ -68,6 +68,7 @@ nsIStyleContext.h \
|
|||
nsIStyleFrameConstruction.h \
|
||||
nsIStyleSet.h \
|
||||
nsLayoutErrors.h \
|
||||
nsLayoutUtils.h \
|
||||
nsReflowType.h \
|
||||
nsStyleChangeList.h \
|
||||
nsStyleConsts.h \
|
||||
|
|
|
@ -1165,6 +1165,30 @@ public:
|
|||
PRBool aIsPre,
|
||||
PRBool* aResult) = 0;
|
||||
|
||||
/**
|
||||
* IsGeneratedContentFrame returns whether a frame corresponds to
|
||||
* generated content
|
||||
*
|
||||
* @return whether the frame correspods to generated content
|
||||
*/
|
||||
PRBool IsGeneratedContentFrame() {
|
||||
return (mState & NS_FRAME_GENERATED_CONTENT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsPseudoFrame returns whether a frame is a pseudo frame (eg an
|
||||
* anonymous table-row frame created for a CSS table-cell without an
|
||||
* enclosing table-row.
|
||||
*
|
||||
* @param aParentContent the content node corresponding to the parent frame
|
||||
* @return whether the frame is a pseudo frame
|
||||
*/
|
||||
PRBool IsPseudoFrame(nsIContent* aParentContent) {
|
||||
return mContent == aParentContent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void* GetProperty(nsIPresContext* aPresContext,
|
||||
nsIAtom* aPropertyName,
|
||||
PRBool aRemoveProperty) const = 0;
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Boris Zbarsky <bzbarsky@mit.edu>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsLayoutUtils_h__
|
||||
#define nsLayoutUtils_h__
|
||||
|
||||
class nsIFrame;
|
||||
class nsIPresContext;
|
||||
|
||||
/**
|
||||
* nsLayoutUtils is a namespace class used for various helper
|
||||
* functions that are useful in multiple places in layout. The goal
|
||||
* is not to define multiple copies of the same static helper.
|
||||
*/
|
||||
class nsLayoutUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* GetBeforeFrame returns the :before frame of the given frame, if
|
||||
* one exists. This is typically O(1). The frame passed in must be
|
||||
* the first-in-flow.
|
||||
*
|
||||
* @param aFrame the frame whose :before is wanted
|
||||
* @param aPresContext the prescontext
|
||||
* @return the :before frame or nsnull if there isn't one
|
||||
*/
|
||||
static nsIFrame* GetBeforeFrame(nsIFrame* aFrame, nsIPresContext* aPresContext);
|
||||
|
||||
/**
|
||||
* GetAfterFrame returns the :after frame of the given frame, if one
|
||||
* exists. This will walk the in-flow chain to the last-in-flow if
|
||||
* needed. This function is typically O(N) in the number of child
|
||||
* frames, following in-flows, etc.
|
||||
*
|
||||
* @param aFrame the frame whose :after is wanted
|
||||
* @param aPresContext the prescontext
|
||||
* @return the :after frame or nsnull if there isn't one
|
||||
*/
|
||||
static nsIFrame* GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext);
|
||||
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
|
@ -58,6 +58,7 @@ CPPSRCS = \
|
|||
nsIntervalSet.cpp \
|
||||
nsLayoutDebugger.cpp \
|
||||
nsLayoutHistoryState.cpp \
|
||||
nsLayoutUtils.cpp \
|
||||
nsPresContext.cpp \
|
||||
nsPresState.cpp \
|
||||
nsPrintContext.cpp \
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsFrameList.h"
|
||||
|
||||
/**
|
||||
* A namespace class for static layout utilities.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GetFirstChildFrame returns the first "real" child frame of a
|
||||
* given frame. It will descend down into pseudo-frames (unless the
|
||||
* pseudo-frame is the :before generated frame).
|
||||
* @param aPresContext the prescontext
|
||||
* @param aFrame the frame
|
||||
* @param aFrame the frame's content node
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetFirstChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
nsIFrame* childFrame;
|
||||
|
||||
// Get the first child frame
|
||||
aFrame->FirstChild(aPresContext, nsnull, &childFrame);
|
||||
|
||||
// If the child frame is a pseudo-frame, then return its first child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (childFrame &&
|
||||
childFrame->IsPseudoFrame(aContent) &&
|
||||
!childFrame->IsGeneratedContentFrame()) {
|
||||
return GetFirstChildFrame(aPresContext, childFrame, aContent);
|
||||
}
|
||||
|
||||
return childFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLastChildFrame returns the last "real" child frame of a
|
||||
* given frame. It will descend down into pseudo-frames (unless the
|
||||
* pseudo-frame is the :after generated frame).
|
||||
* @param aPresContext the prescontext
|
||||
* @param aFrame the frame
|
||||
* @param aFrame the frame's content node
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetLastChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
// Get the last in flow frame
|
||||
nsIFrame* lastInFlow;
|
||||
do {
|
||||
lastInFlow = aFrame;
|
||||
lastInFlow->GetNextInFlow(&aFrame);
|
||||
} while (aFrame);
|
||||
|
||||
// Get the last child frame
|
||||
nsIFrame* firstChildFrame;
|
||||
lastInFlow->FirstChild(aPresContext, nsnull, &firstChildFrame);
|
||||
if (firstChildFrame) {
|
||||
nsFrameList frameList(firstChildFrame);
|
||||
nsIFrame* lastChildFrame = frameList.LastChild();
|
||||
|
||||
NS_ASSERTION(lastChildFrame, "unexpected error");
|
||||
|
||||
// Get the frame's first-in-flow. This matters in case the frame has
|
||||
// been continuted across multiple lines
|
||||
while (PR_TRUE) {
|
||||
nsIFrame* prevInFlow;
|
||||
lastChildFrame->GetPrevInFlow(&prevInFlow);
|
||||
if (prevInFlow) {
|
||||
lastChildFrame = prevInFlow;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the last child frame is a pseudo-frame, then return its last child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (lastChildFrame &&
|
||||
lastChildFrame->IsPseudoFrame(aContent) &&
|
||||
!lastChildFrame->IsGeneratedContentFrame()) {
|
||||
return GetLastChildFrame(aPresContext, lastChildFrame, aContent);
|
||||
}
|
||||
|
||||
return lastChildFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
#ifdef DEBUG
|
||||
nsIFrame* prevInFlow = nsnull;
|
||||
aFrame->GetPrevInFlow(&prevInFlow);
|
||||
NS_ASSERTION(!prevInFlow, "aFrame must be first-in-flow");
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
aFrame->GetContent(getter_AddRefs(content));
|
||||
nsIFrame* firstFrame = GetFirstChildFrame(aPresContext, aFrame, content);
|
||||
|
||||
if (firstFrame && firstFrame->IsGeneratedContentFrame()) {
|
||||
return firstFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame, nsIPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
nsCOMPtr<nsIContent> content;
|
||||
aFrame->GetContent(getter_AddRefs(content));
|
||||
nsIFrame* lastFrame = GetLastChildFrame(aPresContext, aFrame, content);
|
||||
|
||||
if (lastFrame && lastFrame->IsGeneratedContentFrame()) {
|
||||
return lastFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
|
@ -1165,6 +1165,30 @@ public:
|
|||
PRBool aIsPre,
|
||||
PRBool* aResult) = 0;
|
||||
|
||||
/**
|
||||
* IsGeneratedContentFrame returns whether a frame corresponds to
|
||||
* generated content
|
||||
*
|
||||
* @return whether the frame correspods to generated content
|
||||
*/
|
||||
PRBool IsGeneratedContentFrame() {
|
||||
return (mState & NS_FRAME_GENERATED_CONTENT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsPseudoFrame returns whether a frame is a pseudo frame (eg an
|
||||
* anonymous table-row frame created for a CSS table-cell without an
|
||||
* enclosing table-row.
|
||||
*
|
||||
* @param aParentContent the content node corresponding to the parent frame
|
||||
* @return whether the frame is a pseudo frame
|
||||
*/
|
||||
PRBool IsPseudoFrame(nsIContent* aParentContent) {
|
||||
return mContent == aParentContent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void* GetProperty(nsIPresContext* aPresContext,
|
||||
nsIAtom* aPropertyName,
|
||||
PRBool aRemoveProperty) const = 0;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#ifdef NS_DEBUG
|
||||
#include "nsISupportsArray.h"
|
||||
|
@ -75,6 +76,7 @@
|
|||
#include "nsPrintfCString.h"
|
||||
#include "nsDummyLayoutRequest.h"
|
||||
#include "nsLayoutErrors.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
//#define NOISY_DEBUG
|
||||
|
@ -1742,9 +1744,26 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
|
|||
else if (pseudoTag) {
|
||||
nsIContent* pseudoContent =
|
||||
aParentContent ? aParentContent : localContent;
|
||||
aPresContext->ResolvePseudoStyleContextFor(pseudoContent, pseudoTag,
|
||||
if (pseudoTag == nsCSSPseudoElements::before ||
|
||||
pseudoTag == nsCSSPseudoElements::after) {
|
||||
// XXX what other pseudos do we need to treat like this?
|
||||
aPresContext->ProbePseudoStyleContextFor(pseudoContent, pseudoTag,
|
||||
parentContext,
|
||||
&newContext);
|
||||
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;
|
||||
NS_ADDREF(newContext);
|
||||
}
|
||||
} else {
|
||||
aPresContext->ResolvePseudoStyleContextFor(pseudoContent, pseudoTag,
|
||||
parentContext,
|
||||
&newContext);
|
||||
}
|
||||
NS_RELEASE(pseudoTag);
|
||||
}
|
||||
else {
|
||||
|
@ -1895,6 +1914,67 @@ FrameManager::ReResolveStyleContext(nsIPresContext* aPresContext,
|
|||
aResultChange = aMinChange;
|
||||
|
||||
if (!(aMinChange & (nsChangeHint_ReconstructFrame | nsChangeHint_ReconstructDoc))) {
|
||||
if (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.
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(aFrame,
|
||||
aPresContext);
|
||||
if (!beforeFrame) {
|
||||
// Look for a new :before style context
|
||||
nsCOMPtr<nsIStyleContext> newBeforeContext;
|
||||
aPresContext->ProbePseudoStyleContextFor(localContent,
|
||||
nsCSSPseudoElements::before,
|
||||
newContext,
|
||||
getter_AddRefs(newBeforeContext));
|
||||
if (newBeforeContext) {
|
||||
// Have to create the new :before frame
|
||||
NS_UpdateHint(aMinChange, nsChangeHint_ReconstructFrame);
|
||||
aChangeList.AppendChange(aFrame, content,
|
||||
nsChangeHint_ReconstructFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
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.
|
||||
nsCOMPtr<nsIStyleContext> newAfterContext;
|
||||
aPresContext->ProbePseudoStyleContextFor(localContent,
|
||||
nsCSSPseudoElements::after,
|
||||
newContext,
|
||||
getter_AddRefs(newAfterContext));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1993,9 +2073,6 @@ FrameManager::ComputeStyleChangeFor(nsIPresContext* aPresContext,
|
|||
ReResolveStyleContext(aPresContext, frame, nsnull,
|
||||
aAttrNameSpaceID, aAttribute,
|
||||
aChangeList, aMinChange, frameChange);
|
||||
#ifdef NS_DEBUG
|
||||
VerifyStyleTree(aPresContext, frame, nsnull);
|
||||
#endif
|
||||
NS_UpdateHint(aTopLevelChange, frameChange);
|
||||
|
||||
if (aTopLevelChange & (nsChangeHint_ReconstructDoc | nsChangeHint_ReconstructFrame)) {
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
#include "nsIDocShell.h" // for reflow observation
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsLayoutErrors.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#ifdef MOZ_PERF_METRICS
|
||||
#include "nsITimeRecorder.h"
|
||||
#endif
|
||||
|
@ -4569,94 +4570,6 @@ PresShell::SetHistoryState(nsILayoutHistoryState* aLayoutHistoryState)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
IsGeneratedContentFrame(nsIFrame* aFrame)
|
||||
{
|
||||
nsFrameState frameState;
|
||||
|
||||
aFrame->GetFrameState(&frameState);
|
||||
return (frameState & NS_FRAME_GENERATED_CONTENT) != 0;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
IsPseudoFrame(nsIFrame* aFrame, nsIContent* aParentContent)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content;
|
||||
|
||||
aFrame->GetContent(getter_AddRefs(content));
|
||||
return content.get() == aParentContent;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
GetFirstChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
nsIFrame* childFrame;
|
||||
|
||||
// Get the first child frame
|
||||
aFrame->FirstChild(aPresContext, nsnull, &childFrame);
|
||||
|
||||
// If the child frame is a pseudo-frame, then return its first child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (childFrame && IsPseudoFrame(childFrame, aContent) &&
|
||||
!IsGeneratedContentFrame(childFrame)) {
|
||||
return GetFirstChildFrame(aPresContext, childFrame, aContent);
|
||||
}
|
||||
|
||||
return childFrame;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
GetLastChildFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "NULL frame pointer");
|
||||
|
||||
// Get the last in flow frame
|
||||
nsIFrame* lastInFlow;
|
||||
do {
|
||||
lastInFlow = aFrame;
|
||||
lastInFlow->GetNextInFlow(&aFrame);
|
||||
} while (aFrame);
|
||||
|
||||
// Get the last child frame
|
||||
nsIFrame* firstChildFrame;
|
||||
lastInFlow->FirstChild(aPresContext, nsnull, &firstChildFrame);
|
||||
if (firstChildFrame) {
|
||||
nsFrameList frameList(firstChildFrame);
|
||||
nsIFrame* lastChildFrame = frameList.LastChild();
|
||||
|
||||
NS_ASSERTION(lastChildFrame, "unexpected error");
|
||||
|
||||
// Get the frame's first-in-flow. This matters in case the frame has
|
||||
// been continuted across multiple lines
|
||||
while (PR_TRUE) {
|
||||
nsIFrame* prevInFlow;
|
||||
lastChildFrame->GetPrevInFlow(&prevInFlow);
|
||||
if (prevInFlow) {
|
||||
lastChildFrame = prevInFlow;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the last child frame is a pseudo-frame, then return its last child.
|
||||
// Note that the frame we create for the generated content is also a
|
||||
// pseudo-frame and so don't drill down in that case
|
||||
if (lastChildFrame && IsPseudoFrame(lastChildFrame, aContent) &&
|
||||
!IsGeneratedContentFrame(lastChildFrame)) {
|
||||
return GetLastChildFrame(aPresContext, lastChildFrame, aContent);
|
||||
}
|
||||
|
||||
return lastChildFrame;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::GetGeneratedContentIterator(nsIContent* aContent,
|
||||
GeneratedContentType aType,
|
||||
|
@ -4673,17 +4586,16 @@ PresShell::GetGeneratedContentIterator(nsIContent* aContent,
|
|||
if (primaryFrame) {
|
||||
// See whether it's a request for the before or after generated content
|
||||
if (Before == aType) {
|
||||
// The most efficient thing to do is to get the first child frame,
|
||||
// and see if it is associated with generated content
|
||||
nsIFrame* firstChildFrame = GetFirstChildFrame(mPresContext, primaryFrame, aContent);
|
||||
if (firstChildFrame && IsGeneratedContentFrame(firstChildFrame)) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame,
|
||||
mPresContext);
|
||||
if (beforeFrame) {
|
||||
// Create an iterator
|
||||
rv = NS_NewFrameContentIterator(mPresContext, firstChildFrame, aIterator);
|
||||
rv = NS_NewFrameContentIterator(mPresContext, beforeFrame, aIterator);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Avoid finding the last child frame unless we need to. Instead probe
|
||||
// for the existence of the pseudo-element
|
||||
// Avoid finding the :after frame unless we need to (it's
|
||||
// expensive). Instead probe for the existence of the pseudo-element
|
||||
nsCOMPtr<nsIStyleContext> styleContext;
|
||||
nsCOMPtr<nsIStyleContext> pseudoStyleContext;
|
||||
|
||||
|
@ -4693,15 +4605,14 @@ PresShell::GetGeneratedContentIterator(nsIContent* aContent,
|
|||
styleContext,
|
||||
getter_AddRefs(pseudoStyleContext));
|
||||
if (pseudoStyleContext) {
|
||||
nsIFrame* lastChildFrame = GetLastChildFrame(mPresContext, primaryFrame, aContent);
|
||||
if (lastChildFrame)
|
||||
{ // it is now legal for GetLastChildFrame to return null. see bug 52307 (a regression from bug 18754)
|
||||
// in the case of a null child frame, we treat the frame as having no "after" style
|
||||
// the "before" handler above already does this check
|
||||
NS_ASSERTION(IsGeneratedContentFrame(lastChildFrame),
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(primaryFrame,
|
||||
mPresContext);
|
||||
if (afterFrame)
|
||||
{
|
||||
NS_ASSERTION(afterFrame->IsGeneratedContentFrame(),
|
||||
"can't find generated content frame");
|
||||
// Create an iterator
|
||||
rv = NS_NewFrameContentIterator(mPresContext, lastChildFrame, aIterator);
|
||||
rv = NS_NewFrameContentIterator(mPresContext, afterFrame, aIterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5490,6 +5401,9 @@ PresShell::ReconstructStyleData(PRBool aRebuildRuleTree)
|
|||
|
||||
if (aRebuildRuleTree)
|
||||
set->EndRuleTreeReconstruct();
|
||||
|
||||
VERIFY_STYLE_TREE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -10336,6 +10336,22 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList,
|
|||
ApplyRenderingChangeToTree(aPresContext, frame, nsnull, hint);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// reget from content since it may have been regenerated...
|
||||
if (content) {
|
||||
nsIFrame* frame;
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
aPresContext->GetShell(getter_AddRefs(shell));
|
||||
shell->GetPrimaryFrameFor(content, &frame);
|
||||
if (frame) {
|
||||
nsCOMPtr<nsIFrameManager> frameManager;
|
||||
shell->GetFrameManager(getter_AddRefs(frameManager));
|
||||
frameManager->DebugVerifyStyleTree(aPresContext, frame);
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("Unable to test style tree integrity -- no content node");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
aChangeList.Clear();
|
||||
return NS_OK;
|
||||
|
|
|
@ -941,6 +941,13 @@
|
|||
<FILEKIND>Text</FILEKIND>
|
||||
<FILEFLAGS>Debug</FILEFLAGS>
|
||||
</FILE>
|
||||
<FILE>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsLayoutUtils.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
<FILEKIND>Text</FILEKIND>
|
||||
<FILEFLAGS>Debug</FILEFLAGS>
|
||||
</FILE>
|
||||
<FILE>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsPresContext.cpp</PATH>
|
||||
|
@ -2137,6 +2144,11 @@
|
|||
<PATH>nsGalleyContext.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
</FILEREF>
|
||||
<FILEREF>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsLayoutUtils.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
</FILEREF>
|
||||
<FILEREF>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsPresContext.cpp</PATH>
|
||||
|
@ -3852,6 +3864,13 @@
|
|||
<FILEKIND>Text</FILEKIND>
|
||||
<FILEFLAGS>Debug</FILEFLAGS>
|
||||
</FILE>
|
||||
<FILE>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsLayoutUtils.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
<FILEKIND>Text</FILEKIND>
|
||||
<FILEFLAGS>Debug</FILEFLAGS>
|
||||
</FILE>
|
||||
<FILE>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsPresContext.cpp</PATH>
|
||||
|
@ -5068,6 +5087,11 @@
|
|||
<PATH>nsGalleyContext.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
</FILEREF>
|
||||
<FILEREF>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsLayoutUtils.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
</FILEREF>
|
||||
<FILEREF>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsPresContext.cpp</PATH>
|
||||
|
@ -5932,6 +5956,12 @@
|
|||
<PATH>nsGalleyContext.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
</FILEREF>
|
||||
<FILEREF>
|
||||
<TARGETNAME>layout.shlb</TARGETNAME>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
<PATH>nsLayoutUtils.cpp</PATH>
|
||||
<PATHFORMAT>MacOS</PATHFORMAT>
|
||||
</FILEREF>
|
||||
<FILEREF>
|
||||
<TARGETNAME>layout.shlb</TARGETNAME>
|
||||
<PATHTYPE>Name</PATHTYPE>
|
||||
|
|
|
@ -674,6 +674,13 @@ nsMathMLContainerFrame::PropagateScriptStyleFor(nsIPresContext* aPresContext,
|
|||
fm->ComputeStyleChangeFor(aPresContext, aFrame,
|
||||
kNameSpaceID_None, nsMathMLAtoms::fontsize,
|
||||
changeList, minChange, maxChange);
|
||||
#ifdef DEBUG
|
||||
// Use the parent frame to make sure we catch in-flows and such
|
||||
nsIFrame* parentFrame;
|
||||
aFrame->GetParent(&parentFrame);
|
||||
fm->DebugVerifyStyleTree(aPresContext,
|
||||
parentFrame ? parentFrame : aFrame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -717,6 +717,13 @@ nsMathMLFrame::MapAttributesIntoCSS(nsIPresContext* aPresContext,
|
|||
fm->ComputeStyleChangeFor(aPresContext, aFrame,
|
||||
kNameSpaceID_None, nsnull,
|
||||
changeList, minChange, maxChange);
|
||||
#ifdef DEBUG
|
||||
// Use the parent frame to make sure we catch in-flows and such
|
||||
nsIFrame* parentFrame;
|
||||
aFrame->GetParent(&parentFrame);
|
||||
fm->DebugVerifyStyleTree(aPresContext,
|
||||
parentFrame ? parentFrame : aFrame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -358,6 +358,13 @@ nsMathMLTokenFrame::SetTextStyle(nsIPresContext* aPresContext)
|
|||
fm->ComputeStyleChangeFor(aPresContext, this,
|
||||
kNameSpaceID_None, nsMathMLAtoms::fontstyle,
|
||||
changeList, minChange, maxChange);
|
||||
#ifdef DEBUG
|
||||
// Use the parent frame to make sure we catch in-flows and such
|
||||
nsIFrame* parentFrame;
|
||||
GetParent(&parentFrame);
|
||||
fm->DebugVerifyStyleTree(aPresContext,
|
||||
parentFrame ? parentFrame : this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -299,6 +299,13 @@ MapAttributesInto(nsIPresContext* aPresContext,
|
|||
nsStyleChangeList changeList;
|
||||
fm->ComputeStyleChangeFor(aPresContext, aCellFrame, kNameSpaceID_None, nsnull,
|
||||
changeList, minChange, maxChange);
|
||||
#ifdef DEBUG
|
||||
// Use the parent frame to make sure we catch in-flows and such
|
||||
nsIFrame* parentFrame;
|
||||
aCellFrame->GetParent(&parentFrame);
|
||||
fm->DebugVerifyStyleTree(aPresContext,
|
||||
parentFrame ? parentFrame : aCellFrame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче