mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
574 lines
20 KiB
C++
574 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla 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/MPL/
|
|
*
|
|
* 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 the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* David Hyatt <hyatt@netscape.com>
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of 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 MPL, 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 MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/* the interface (to internal code) for retrieving computed style data */
|
|
|
|
#include "nsStyleConsts.h"
|
|
#include "nsString.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsIStyleRule.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsStyleSet.h"
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsRuleNode.h"
|
|
#include "nsStyleContext.h"
|
|
|
|
#ifdef DEBUG
|
|
// #define NOISY_DEBUG
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
nsStyleContext::nsStyleContext(nsStyleContext* aParent,
|
|
nsIAtom* aPseudoTag,
|
|
nsRuleNode* aRuleNode,
|
|
nsPresContext* aPresContext)
|
|
: mParent(aParent),
|
|
mChild(nsnull),
|
|
mEmptyChild(nsnull),
|
|
mPseudoTag(aPseudoTag),
|
|
mRuleNode(aRuleNode),
|
|
mBits(0),
|
|
mRefCnt(0)
|
|
{
|
|
mNextSibling = this;
|
|
mPrevSibling = this;
|
|
if (mParent) {
|
|
mParent->AddRef();
|
|
mParent->AddChild(this);
|
|
#ifdef DEBUG
|
|
nsRuleNode *r1 = mParent->GetRuleNode(), *r2 = aRuleNode;
|
|
while (r1->GetParent())
|
|
r1 = r1->GetParent();
|
|
while (r2->GetParent())
|
|
r2 = r2->GetParent();
|
|
NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
|
|
#endif
|
|
}
|
|
|
|
ApplyStyleFixups(aPresContext);
|
|
|
|
#define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
|
|
NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
|
|
"NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
|
|
#undef eStyleStruct_LastItem
|
|
}
|
|
|
|
nsStyleContext::~nsStyleContext()
|
|
{
|
|
NS_ASSERTION((nsnull == mChild) && (nsnull == mEmptyChild), "destructing context with children");
|
|
|
|
nsPresContext *presContext = mRuleNode->GetPresContext();
|
|
|
|
presContext->PresShell()->StyleSet()->
|
|
NotifyStyleContextDestroyed(presContext, this);
|
|
|
|
if (mParent) {
|
|
mParent->RemoveChild(this);
|
|
mParent->Release();
|
|
}
|
|
|
|
// Free up our data structs.
|
|
if (mCachedStyleData.mResetData || mCachedStyleData.mInheritedData) {
|
|
mCachedStyleData.Destroy(mBits, presContext);
|
|
}
|
|
}
|
|
|
|
void nsStyleContext::AddChild(nsStyleContext* aChild)
|
|
{
|
|
NS_ASSERTION(aChild->mPrevSibling == aChild &&
|
|
aChild->mNextSibling == aChild,
|
|
"child already in a child list");
|
|
|
|
nsStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
|
|
|
|
// Insert at the beginning of the list. See also FindChildWithRules.
|
|
if (*list) {
|
|
// Link into existing elements, if there are any.
|
|
aChild->mNextSibling = (*list);
|
|
aChild->mPrevSibling = (*list)->mPrevSibling;
|
|
(*list)->mPrevSibling->mNextSibling = aChild;
|
|
(*list)->mPrevSibling = aChild;
|
|
}
|
|
(*list) = aChild;
|
|
}
|
|
|
|
void nsStyleContext::RemoveChild(nsStyleContext* aChild)
|
|
{
|
|
NS_PRECONDITION(nsnull != aChild && this == aChild->mParent, "bad argument");
|
|
|
|
nsStyleContext **list = aChild->mRuleNode->IsRoot() ? &mEmptyChild : &mChild;
|
|
|
|
if (aChild->mPrevSibling != aChild) { // has siblings
|
|
if ((*list) == aChild) {
|
|
(*list) = (*list)->mNextSibling;
|
|
}
|
|
}
|
|
else {
|
|
NS_ASSERTION((*list) == aChild, "bad sibling pointers");
|
|
(*list) = nsnull;
|
|
}
|
|
|
|
aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
|
|
aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
|
|
aChild->mNextSibling = aChild;
|
|
aChild->mPrevSibling = aChild;
|
|
}
|
|
|
|
already_AddRefed<nsStyleContext>
|
|
nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag,
|
|
nsRuleNode* aRuleNode)
|
|
{
|
|
PRUint32 threshold = 10; // The # of siblings we're willing to examine
|
|
// before just giving this whole thing up.
|
|
|
|
nsStyleContext* result = nsnull;
|
|
nsStyleContext *list = aRuleNode->IsRoot() ? mEmptyChild : mChild;
|
|
|
|
if (list) {
|
|
nsStyleContext *child = list;
|
|
do {
|
|
if (child->mRuleNode == aRuleNode && child->mPseudoTag == aPseudoTag) {
|
|
result = child;
|
|
break;
|
|
}
|
|
child = child->mNextSibling;
|
|
threshold--;
|
|
if (threshold == 0)
|
|
break;
|
|
} while (child != list);
|
|
}
|
|
|
|
if (result) {
|
|
if (result != list) {
|
|
// Move result to the front of the list.
|
|
RemoveChild(result);
|
|
AddChild(result);
|
|
}
|
|
|
|
// Add reference for the caller.
|
|
result->AddRef();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const void* nsStyleContext::GetStyleData(nsStyleStructID aSID)
|
|
{
|
|
const void* cachedData = mCachedStyleData.GetStyleData(aSID);
|
|
if (cachedData)
|
|
return cachedData; // We have computed data stored on this node in the context tree.
|
|
return mRuleNode->GetStyleData(aSID, this, PR_TRUE); // Our rule node will take care of it for us.
|
|
}
|
|
|
|
#define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
|
|
const nsStyle##name_ * nsStyleContext::GetStyle##name_ () \
|
|
{ \
|
|
const nsStyle##name_ * cachedData = mCachedStyleData.GetStyle##name_(); \
|
|
if (cachedData) \
|
|
return cachedData; /* We have computed data stored on this node */ \
|
|
/* in the context tree. */ \
|
|
/* Else our rule node will take care of it for us. */ \
|
|
return mRuleNode->GetStyle##name_(this, PR_TRUE); \
|
|
}
|
|
#include "nsStyleStructList.h"
|
|
#undef STYLE_STRUCT
|
|
|
|
const void* nsStyleContext::PeekStyleData(nsStyleStructID aSID)
|
|
{
|
|
const void* cachedData = mCachedStyleData.GetStyleData(aSID);
|
|
if (cachedData)
|
|
return cachedData; // We have computed data stored on this node in the context tree.
|
|
return mRuleNode->GetStyleData(aSID, this, PR_FALSE); // Our rule node will take care of it for us.
|
|
}
|
|
|
|
// This is an evil evil function, since it forces you to alloc your own separate copy of
|
|
// style data! Do not use this function unless you absolutely have to! You should avoid
|
|
// this at all costs! -dwh
|
|
void*
|
|
nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
|
|
{
|
|
// If we already own the struct and no kids could depend on it, then
|
|
// just return it. (We leak in this case if there are kids -- and this
|
|
// function really shouldn't be called for style contexts that could
|
|
// have kids depending on the data. ClearStyleData would be OK, but
|
|
// this test for no mChild or mEmptyChild doesn't catch that case.)
|
|
const void *current = GetStyleData(aSID);
|
|
if (!mChild && !mEmptyChild &&
|
|
!(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
|
|
mCachedStyleData.GetStyleData(aSID))
|
|
return const_cast<void*>(current);
|
|
|
|
void* result;
|
|
nsPresContext *presContext = PresContext();
|
|
switch (aSID) {
|
|
|
|
#define UNIQUE_CASE(c_) \
|
|
case eStyleStruct_##c_: \
|
|
result = new (presContext) nsStyle##c_( \
|
|
* static_cast<const nsStyle##c_ *>(current)); \
|
|
break;
|
|
|
|
UNIQUE_CASE(Display)
|
|
UNIQUE_CASE(Background)
|
|
UNIQUE_CASE(Text)
|
|
UNIQUE_CASE(TextReset)
|
|
|
|
#undef UNIQUE_CASE
|
|
|
|
default:
|
|
NS_ERROR("Struct type not supported. Please find another way to do this if you can!\n");
|
|
return nsnull;
|
|
}
|
|
|
|
if (!result) {
|
|
NS_WARNING("Ran out of memory while trying to allocate memory for a unique style struct! "
|
|
"Returning the non-unique data.");
|
|
return const_cast<void*>(current);
|
|
}
|
|
|
|
SetStyle(aSID, result);
|
|
mBits &= ~nsCachedStyleData::GetBitForSID(aSID);
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
|
|
{
|
|
// This method should only be called from nsRuleNode! It is not a public
|
|
// method!
|
|
|
|
NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
|
|
|
|
// NOTE: nsCachedStyleData::GetStyleData works roughly the same way.
|
|
// See the comments there (in nsRuleNode.h) for more details about
|
|
// what this is doing and why.
|
|
|
|
const nsCachedStyleData::StyleStructInfo& info =
|
|
nsCachedStyleData::gInfo[aSID];
|
|
char* resetOrInheritSlot = reinterpret_cast<char*>(&mCachedStyleData) +
|
|
info.mCachedStyleDataOffset;
|
|
char* resetOrInherit = reinterpret_cast<char*>
|
|
(*reinterpret_cast<void**>(resetOrInheritSlot));
|
|
if (!resetOrInherit) {
|
|
nsPresContext *presContext = mRuleNode->GetPresContext();
|
|
if (mCachedStyleData.IsReset(aSID)) {
|
|
mCachedStyleData.mResetData = new (presContext) nsResetStyleData;
|
|
resetOrInherit = reinterpret_cast<char*>(mCachedStyleData.mResetData);
|
|
} else {
|
|
mCachedStyleData.mInheritedData =
|
|
new (presContext) nsInheritedStyleData;
|
|
resetOrInherit =
|
|
reinterpret_cast<char*>(mCachedStyleData.mInheritedData);
|
|
}
|
|
}
|
|
char* dataSlot = resetOrInherit + info.mInheritResetOffset;
|
|
*reinterpret_cast<void**>(dataSlot) = aStruct;
|
|
}
|
|
|
|
void
|
|
nsStyleContext::ApplyStyleFixups(nsPresContext* aPresContext)
|
|
{
|
|
// See if we have any text decorations.
|
|
// First see if our parent has text decorations. If our parent does, then we inherit the bit.
|
|
if (mParent && mParent->HasTextDecorations())
|
|
mBits |= NS_STYLE_HAS_TEXT_DECORATIONS;
|
|
else {
|
|
// We might have defined a decoration.
|
|
const nsStyleTextReset* text = GetStyleTextReset();
|
|
if (text->mTextDecoration != NS_STYLE_TEXT_DECORATION_NONE &&
|
|
text->mTextDecoration != NS_STYLE_TEXT_DECORATION_OVERRIDE_ALL)
|
|
mBits |= NS_STYLE_HAS_TEXT_DECORATIONS;
|
|
}
|
|
|
|
// Correct tables.
|
|
const nsStyleDisplay* disp = GetStyleDisplay();
|
|
if (disp->mDisplay == NS_STYLE_DISPLAY_TABLE) {
|
|
// -moz-center and -moz-right are used for HTML's alignment
|
|
// This is covering the <div align="right"><table>...</table></div> case.
|
|
// In this case, we don't want to inherit the text alignment into the table.
|
|
const nsStyleText* text = GetStyleText();
|
|
|
|
if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
|
|
text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
|
|
{
|
|
nsStyleText* uniqueText = (nsStyleText*)GetUniqueStyleData(eStyleStruct_Text);
|
|
uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
|
|
}
|
|
}
|
|
|
|
// CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
|
|
// the root element. We can't implement them in nsRuleNode because we
|
|
// don't want to store all display structs that aren't 'block',
|
|
// 'inline', or 'table' in the style context tree on the off chance
|
|
// that the root element has its style reresolved later. So do them
|
|
// here if needed, by changing the style data, so that other code
|
|
// doesn't get confused by looking at the style data.
|
|
if (!mParent) {
|
|
if (disp->mDisplay != NS_STYLE_DISPLAY_NONE &&
|
|
disp->mDisplay != NS_STYLE_DISPLAY_BLOCK &&
|
|
disp->mDisplay != NS_STYLE_DISPLAY_TABLE) {
|
|
nsStyleDisplay *mutable_display = static_cast<nsStyleDisplay*>
|
|
(GetUniqueStyleData(eStyleStruct_Display));
|
|
if (mutable_display->mDisplay == NS_STYLE_DISPLAY_INLINE_TABLE)
|
|
mutable_display->mDisplay = NS_STYLE_DISPLAY_TABLE;
|
|
else
|
|
mutable_display->mDisplay = NS_STYLE_DISPLAY_BLOCK;
|
|
}
|
|
}
|
|
|
|
// Computer User Interface style, to trigger loads of cursors
|
|
GetStyleUserInterface();
|
|
}
|
|
|
|
nsChangeHint
|
|
nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
|
|
{
|
|
nsChangeHint hint = NS_STYLE_HINT_NONE;
|
|
NS_ENSURE_TRUE(aOther, hint);
|
|
// We must always ensure that we populate the structs on the new style
|
|
// context that are filled in on the old context, so that if we get
|
|
// two style changes in succession, the second of which causes a real
|
|
// style change, the PeekStyleData doesn't return null (implying that
|
|
// nobody ever looked at that struct's data). In other words, we
|
|
// can't skip later structs if we get a big change up front, because
|
|
// we could later get a small change in one of those structs that we
|
|
// don't want to miss.
|
|
|
|
// If our rule nodes are the same, then we are looking at the same
|
|
// style data. We know this because CalcStyleDifference is always
|
|
// called on two style contexts that point to the same element, so we
|
|
// know that our position in the style context tree is the same and
|
|
// our position in the rule node tree is also the same.
|
|
PRBool compare = mRuleNode != aOther->mRuleNode;
|
|
|
|
nsChangeHint maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
|
|
nsChangeHint_UpdateCursor);
|
|
|
|
#define DO_STRUCT_DIFFERENCE(struct_) \
|
|
PR_BEGIN_MACRO \
|
|
NS_ASSERTION(NS_IsHintSubset(nsStyle##struct_::MaxDifference(), maxHint), \
|
|
"Struct placed in the wrong maxHint section"); \
|
|
const nsStyle##struct_* this##struct_ = \
|
|
static_cast<const nsStyle##struct_*>( \
|
|
PeekStyleData(eStyleStruct_##struct_)); \
|
|
if (this##struct_) { \
|
|
const nsStyle##struct_* other##struct_ = aOther->GetStyle##struct_(); \
|
|
if (compare && \
|
|
!NS_IsHintSubset(maxHint, hint) && \
|
|
this##struct_ != other##struct_) { \
|
|
NS_ASSERTION(NS_IsHintSubset( \
|
|
this##struct_->CalcDifference(*other##struct_), \
|
|
nsStyle##struct_::MaxDifference()), \
|
|
"CalcDifference() returned bigger hint than MaxDifference()"); \
|
|
NS_UpdateHint(hint, this##struct_->CalcDifference(*other##struct_)); \
|
|
} \
|
|
} \
|
|
PR_END_MACRO
|
|
|
|
// We begin by examining those style structs that are capable of
|
|
// causing the maximal difference, a FRAMECHANGE.
|
|
// FRAMECHANGE Structs: Display, XUL, Content, UserInterface,
|
|
// Visibility, Outline, TableBorder, Table, Text, UIReset, Quotes
|
|
DO_STRUCT_DIFFERENCE(Display);
|
|
DO_STRUCT_DIFFERENCE(XUL);
|
|
DO_STRUCT_DIFFERENCE(Column);
|
|
DO_STRUCT_DIFFERENCE(Content);
|
|
DO_STRUCT_DIFFERENCE(UserInterface);
|
|
DO_STRUCT_DIFFERENCE(Visibility);
|
|
DO_STRUCT_DIFFERENCE(Outline);
|
|
DO_STRUCT_DIFFERENCE(TableBorder);
|
|
DO_STRUCT_DIFFERENCE(Table);
|
|
DO_STRUCT_DIFFERENCE(UIReset);
|
|
DO_STRUCT_DIFFERENCE(Text);
|
|
DO_STRUCT_DIFFERENCE(List);
|
|
// If the quotes implementation is ever going to change we might not need
|
|
// a framechange here and a reflow should be sufficient. See bug 35768.
|
|
DO_STRUCT_DIFFERENCE(Quotes);
|
|
|
|
#ifdef MOZ_SVG
|
|
maxHint = nsChangeHint(NS_STYLE_HINT_REFLOW | nsChangeHint_UpdateEffects);
|
|
DO_STRUCT_DIFFERENCE(SVGReset);
|
|
DO_STRUCT_DIFFERENCE(SVG);
|
|
#endif
|
|
|
|
// At this point, we know that the worst kind of damage we could do is
|
|
// a reflow.
|
|
maxHint = NS_STYLE_HINT_REFLOW;
|
|
|
|
// The following structs cause (as their maximal difference) a reflow
|
|
// to occur. REFLOW Structs: Font, Margin, Padding, Border, List,
|
|
// Position, Text, TextReset
|
|
DO_STRUCT_DIFFERENCE(Font);
|
|
DO_STRUCT_DIFFERENCE(Margin);
|
|
DO_STRUCT_DIFFERENCE(Padding);
|
|
DO_STRUCT_DIFFERENCE(Border);
|
|
DO_STRUCT_DIFFERENCE(Position);
|
|
DO_STRUCT_DIFFERENCE(TextReset);
|
|
|
|
// At this point, we know that the worst kind of damage we could do is
|
|
// a re-render (i.e., a VISUAL change).
|
|
maxHint = NS_STYLE_HINT_VISUAL;
|
|
|
|
// The following structs cause (as their maximal difference) a
|
|
// re-render to occur. VISUAL Structs: Color, Background
|
|
DO_STRUCT_DIFFERENCE(Color);
|
|
DO_STRUCT_DIFFERENCE(Background);
|
|
|
|
#undef DO_STRUCT_DIFFERENCE
|
|
|
|
return hint;
|
|
}
|
|
|
|
void
|
|
nsStyleContext::Mark()
|
|
{
|
|
// Mark our rule node.
|
|
mRuleNode->Mark();
|
|
|
|
// Mark our children (i.e., tell them to mark their rule nodes, etc.).
|
|
if (mChild) {
|
|
nsStyleContext* child = mChild;
|
|
do {
|
|
child->Mark();
|
|
child = child->mNextSibling;
|
|
} while (mChild != child);
|
|
}
|
|
|
|
if (mEmptyChild) {
|
|
nsStyleContext* child = mEmptyChild;
|
|
do {
|
|
child->Mark();
|
|
child = child->mNextSibling;
|
|
} while (mEmptyChild != child);
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void nsStyleContext::List(FILE* out, PRInt32 aIndent)
|
|
{
|
|
// Indent
|
|
PRInt32 ix;
|
|
for (ix = aIndent; --ix >= 0; ) fputs(" ", out);
|
|
fprintf(out, "%p(%d) parent=%p ",
|
|
(void*)this, mRefCnt, (void *)mParent);
|
|
if (mPseudoTag) {
|
|
nsAutoString buffer;
|
|
mPseudoTag->ToString(buffer);
|
|
fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
|
|
fputs(" ", out);
|
|
}
|
|
|
|
if (mRuleNode) {
|
|
fputs("{\n", out);
|
|
nsRuleNode* ruleNode = mRuleNode;
|
|
while (ruleNode) {
|
|
nsIStyleRule *styleRule = ruleNode->GetRule();
|
|
if (styleRule) {
|
|
styleRule->List(out, aIndent + 1);
|
|
}
|
|
ruleNode = ruleNode->GetParent();
|
|
}
|
|
for (ix = aIndent; --ix >= 0; ) fputs(" ", out);
|
|
fputs("}\n", out);
|
|
}
|
|
else {
|
|
fputs("{}\n", out);
|
|
}
|
|
|
|
if (nsnull != mChild) {
|
|
nsStyleContext* child = mChild;
|
|
do {
|
|
child->List(out, aIndent + 1);
|
|
child = child->mNextSibling;
|
|
} while (mChild != child);
|
|
}
|
|
if (nsnull != mEmptyChild) {
|
|
nsStyleContext* child = mEmptyChild;
|
|
do {
|
|
child->List(out, aIndent + 1);
|
|
child = child->mNextSibling;
|
|
} while (mEmptyChild != child);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Overloaded new operator. Initializes the memory to 0 and relies on an arena
|
|
// (which comes from the presShell) to perform the allocation.
|
|
void*
|
|
nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
|
|
{
|
|
// Check the recycle list first.
|
|
return aPresContext->AllocateFromShell(sz);
|
|
}
|
|
|
|
// Overridden to prevent the global delete from being called, since the memory
|
|
// came out of an nsIArena instead of the global delete operator's heap.
|
|
void
|
|
nsStyleContext::Destroy()
|
|
{
|
|
// Get the pres context from our rule node.
|
|
nsCOMPtr<nsPresContext> presContext = mRuleNode->GetPresContext();
|
|
|
|
// Call our destructor.
|
|
this->~nsStyleContext();
|
|
|
|
// Don't let the memory be freed, since it will be recycled
|
|
// instead. Don't call the global operator delete.
|
|
presContext->FreeToShell(sizeof(nsStyleContext), this);
|
|
}
|
|
|
|
already_AddRefed<nsStyleContext>
|
|
NS_NewStyleContext(nsStyleContext* aParentContext,
|
|
nsIAtom* aPseudoTag,
|
|
nsRuleNode* aRuleNode,
|
|
nsPresContext* aPresContext)
|
|
{
|
|
nsStyleContext* context = new (aPresContext) nsStyleContext(aParentContext, aPseudoTag,
|
|
aRuleNode, aPresContext);
|
|
if (context)
|
|
context->AddRef();
|
|
return context;
|
|
}
|
|
|