Bug 551660. Switch layout code from using nsPropertyTable to FramePropertyTable. r=mats,sr=dbaron
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 29 Mar 2010 14:46:55 +1300
changeset 39965 46e3ca39d3d09af127b4dbf9cc922d6230820446
parent 39964 1f811ed2621977c367c6261509d77a491bf254cd
child 39966 f25fbbe3e978db6478b1c14e618278098fe0fa01
push idunknown
push userunknown
push dateunknown
reviewersmats, dbaron
bugs551660
milestone1.9.3a4pre
Bug 551660. Switch layout code from using nsPropertyTable to FramePropertyTable. r=mats,sr=dbaron
content/base/src/nsGkAtomList.h
layout/base/nsBidiPresUtils.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsFrameManager.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsBlockReflowState.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
layout/generic/nsFloatManager.cpp
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsHTMLReflowState.h
layout/generic/nsIFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/mathml/nsMathMLContainerFrame.cpp
layout/mathml/nsMathMLmtableFrame.cpp
layout/svg/base/src/nsSVGEffects.cpp
layout/svg/base/src/nsSVGEffects.h
layout/svg/base/src/nsSVGGeometryFrame.cpp
layout/svg/base/src/nsSVGGeometryFrame.h
layout/svg/base/src/nsSVGGradientFrame.cpp
layout/svg/base/src/nsSVGIntegrationUtils.cpp
layout/svg/base/src/nsSVGPathGeometryFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/svg/base/src/nsSVGTextPathFrame.cpp
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowGroupFrame.cpp
layout/xul/base/src/nsBox.cpp
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -127,17 +127,16 @@ GK_ATOM(autocomplete, "autocomplete")
 GK_ATOM(autoplay, "autoplay")
 #endif
 GK_ATOM(autorepeatbutton, "autorepeatbutton")
 GK_ATOM(axis, "axis")
 GK_ATOM(b, "b")
 GK_ATOM(background, "background")
 GK_ATOM(base, "base")
 GK_ATOM(basefont, "basefont")
-GK_ATOM(baseLevel, "BaseLevel")                            // PRUint8
 GK_ATOM(baseline, "baseline")
 GK_ATOM(bdo, "bdo")
 GK_ATOM(before, "before")
 GK_ATOM(before_end, "before_end")
 GK_ATOM(before_start, "before_start")
 GK_ATOM(below, "below")
 GK_ATOM(bgcolor, "bgcolor")
 GK_ATOM(big, "big")
@@ -182,17 +181,16 @@ GK_ATOM(cellpadding, "cellpadding")
 GK_ATOM(cellspacing, "cellspacing")
 GK_ATOM(center, "center")
 GK_ATOM(ch, "ch")
 GK_ATOM(change, "change")
 GK_ATOM(_char, "char")
 GK_ATOM(charcode, "charcode")
 GK_ATOM(charoff, "charoff")
 GK_ATOM(charset, "charset")
-GK_ATOM(charType, "charType")                              // PRUint8
 GK_ATOM(checkbox, "checkbox")
 GK_ATOM(checked, "checked")
 GK_ATOM(child, "child")
 GK_ATOM(children, "children")
 GK_ATOM(choose, "choose")
 GK_ATOM(circ, "circ")
 GK_ATOM(circle, "circle")
 GK_ATOM(cite, "cite")
@@ -338,17 +336,16 @@ GK_ATOM(editable, "editable")
 GK_ATOM(editing, "editing")
 GK_ATOM(editor, "editor")
 GK_ATOM(editorDisplayList, "EditorDisplay-List")
 GK_ATOM(element, "element")
 GK_ATOM(elementAvailable, "element-available")
 GK_ATOM(elements, "elements")
 GK_ATOM(em, "em")
 GK_ATOM(embed, "embed")
-GK_ATOM(embeddingLevel, "EmbeddingLevel")                  // PRUint8
 GK_ATOM(embossed, "embossed")
 GK_ATOM(empty, "empty")
 GK_ATOM(encoding, "encoding")
 GK_ATOM(enctype, "enctype")
 GK_ATOM(end, "end")
 GK_ATOM(end_after, "end_after")
 GK_ATOM(end_before, "end_before")
 GK_ATOM(equalsize, "equalsize")
@@ -1650,53 +1647,20 @@ GK_ATOM(timeupdate, "timeupdate")
 GK_ATOM(ended, "ended")
 GK_ATOM(canplay, "canplay")
 GK_ATOM(canplaythrough, "canplaythrough")
 GK_ATOM(ratechange, "ratechange")
 GK_ATOM(durationchange, "durationchange")
 GK_ATOM(volumechange, "volumechange")
 #endif
 
-// Frame property names
-GK_ATOM(boxMetricsProperty, "BoxMetricsProperty") // nsBoxLayoutMetrics*
-GK_ATOM(changeListProperty, "ChangeListProperty") // void*
-GK_ATOM(computedOffsetProperty, "ComputedOffsetProperty")  // nsPoint*
-GK_ATOM(floatContinuationProperty, "FloatContinuationProperty") // nsFrameList*
-GK_ATOM(floatRegionProperty, "FloatRegionProperty") // nsRect*
-GK_ATOM(generatedContent, "GeneratedContentProperty")  // nsCOMArray<nsIContent>*
-#ifdef MOZ_MATHML
-GK_ATOM(HTMLReflowMetricsProperty, "HTMLReflowMetricsProperty") // nsHTMLReflowMetrics*
-#endif
-GK_ATOM(IBSplitSpecialPrevSibling, "IBSplitSpecialPrevSibling")// nsIFrame*
-GK_ATOM(IBSplitSpecialSibling, "IBSplitSpecialSibling")    // nsIFrame*
-GK_ATOM(lineCursorProperty, "LineCursorProperty") // nsLineBox*
-GK_ATOM(rowCursorProperty, "RowCursorProperty") // nsTableRowGroupFrame::FrameCursorData*
-GK_ATOM(maxElementWidthProperty, "MaxElementWidthProperty")  // nscoord*
-GK_ATOM(outlineInnerRectProperty, "OutlineInnerRectProperty") // nsRect*
-GK_ATOM(outOfFlowDirtyRectProperty, "OutOfFlowDirtyRectProperty") // nsRect*
-GK_ATOM(overflowAreaProperty, "OverflowArea")              // nsRect*
-GK_ATOM(overflowProperty, "OverflowProperty")              // nsFrameList*
-GK_ATOM(overflowContainersProperty, "OverflowContainersProperty")             // nsFrameList*
-GK_ATOM(excessOverflowContainersProperty, "ExcessOverflowContainersProperty") // nsFrameList*
-GK_ATOM(overflowLinesProperty, "OverflowLinesProperty")    // list of nsLineBox*
-GK_ATOM(overflowOutOfFlowsProperty, "OverflowOutOfFlowsProperty")      // nsFrameList*
-GK_ATOM(preEffectsBBoxProperty, "PreEffectsBBoxProperty") // nsRect*
-GK_ATOM(preTransformBBoxProperty, "PreTransformBBoxProperty") // nsRect*
-GK_ATOM(rowUnpaginatedHeightProperty, "RowUnpaginatedHeightProperty")  // nscoord*
-GK_ATOM(tabWidthProperty, "TabWidthProperty")              // nsTArray<TabSetting>* array of tab widths
-GK_ATOM(tableBCProperty, "TableBCProperty")                // table border collapsing info (e.g. damage area, table border widths)
+// Content property names
 GK_ATOM(transitionsProperty, "TransitionsProperty")        // FrameTransitions*
 GK_ATOM(transitionsOfBeforeProperty, "TransitionsOfBeforeProperty") // FrameTransitions*
 GK_ATOM(transitionsOfAfterProperty, "TransitionsOfAfterProperty") // FrameTransitions*
-GK_ATOM(usedBorderProperty, "UsedBorderProperty") // nsMargin*
-GK_ATOM(usedMarginProperty, "UsedMarginProperty") // nsMargin*
-GK_ATOM(usedPaddingProperty, "UsedPaddingProperty") // nsMargin*
-GK_ATOM(viewProperty, "ViewProperty")                      
-
-// Content property names
 GK_ATOM(genConInitializerProperty, "QuoteNodeProperty")
 GK_ATOM(labelMouseDownPtProperty, "LabelMouseDownPtProperty")
 
 // Languages for lang-specific transforms
 GK_ATOM(Japanese, "ja")
 GK_ATOM(Chinese, "zh-CN")
 GK_ATOM(Taiwanese, "zh-TW")
 GK_ATOM(HongKongChinese, "zh-HK")
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -51,16 +51,18 @@
 #include "nsBidiUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsHTMLContainerFrame.h"
 #include "nsInlineFrame.h"
 #include "nsPlaceholderFrame.h"
 #include "nsContainerFrame.h"
 #include "nsFirstLetterFrame.h"
 
+using namespace mozilla;
+
 static const PRUnichar kSpace            = 0x0020;
 static const PRUnichar kLineSeparator    = 0x2028;
 static const PRUnichar kObjectSubstitute = 0xFFFC;
 static const PRUnichar kLRE              = 0x202A;
 static const PRUnichar kRLE              = 0x202B;
 static const PRUnichar kLRO              = 0x202D;
 static const PRUnichar kRLO              = 0x202E;
 static const PRUnichar kPDF              = 0x202C;
@@ -391,17 +393,17 @@ nsBidiPresUtils::Resolve(nsBlockFrame*  
   PRUint8     charType;
   PRUint8     prevType       = eCharType_LeftToRight;
   PRBool      isTextFrame    = PR_FALSE;
   nsIFrame*   frame = nsnull;
   nsIContent* content = nsnull;
   PRInt32     contentTextLength;
   nsIAtom*    frameType = nsnull;
 
-  nsPropertyTable *propTable = presContext->PropertyTable();
+  FramePropertyTable *propTable = presContext->PropertyTable();
 
   nsBlockInFlowLineIterator lineIter(aBlockFrame, aBlockFrame->begin_lines(), PR_FALSE);
   if (lineIter.GetLine() == aBlockFrame->end_lines()) {
     // Advance to first valid line (might be in a next-continuation)
     lineIter.Next();
   }
   nsIFrame* prevFrame = nsnull;
   PRBool lineNeedsUpdate = PR_FALSE;
@@ -421,21 +423,20 @@ nsBidiPresUtils::Resolve(nsBlockFrame*  
           mSuccess = NS_OK;
           break;
         }
         contentTextLength = content->TextLength();
         if (contentTextLength == 0) {
           frame->AdjustOffsetsForBidi(0, 0);
           // Set the base level and embedding level of the current run even
           // on an empty frame. Otherwise frame reordering will not be correct.
-          propTable->SetProperty(frame, nsGkAtoms::embeddingLevel,
-                                 NS_INT32_TO_PTR(embeddingLevel),
-                                 nsnull, nsnull);
-          propTable->SetProperty(frame, nsGkAtoms::baseLevel,
-                                 NS_INT32_TO_PTR(paraLevel), nsnull, nsnull);
+          propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
+                         NS_INT32_TO_PTR(embeddingLevel));
+          propTable->Set(frame, nsIFrame::BaseLevelProperty(),
+                         NS_INT32_TO_PTR(paraLevel));
           continue;
         }
         PRInt32 start, end;
         frame->GetOffsets(start, end);
         fragmentLength = end - start;
         contentOffset = start;
         isTextFrame = PR_TRUE;
       }
@@ -466,27 +467,27 @@ nsBidiPresUtils::Resolve(nsBlockFrame*  
     } // if (runLength <= 0)
 
     if (nsGkAtoms::directionalFrame == frameType) {
       frame->Destroy();
       frame = nsnull;
       ++lineOffset;
     }
     else {
-      propTable->SetProperty(frame, nsGkAtoms::embeddingLevel,
-                             NS_INT32_TO_PTR(embeddingLevel), nsnull, nsnull);
-      propTable->SetProperty(frame, nsGkAtoms::baseLevel,
-                             NS_INT32_TO_PTR(paraLevel), nsnull, nsnull);
+      propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
+                     NS_INT32_TO_PTR(embeddingLevel));
+      propTable->Set(frame, nsIFrame::BaseLevelProperty(),
+                     NS_INT32_TO_PTR(paraLevel));
       if (isTextFrame) {
         PRInt32 typeLimit = NS_MIN(logicalLimit, lineOffset + fragmentLength);
         CalculateCharType(lineOffset, typeLimit, logicalLimit, runLength,
                            runCount, charType, prevType);
         // IBMBIDI - Egypt - Start
-        propTable->SetProperty(frame, nsGkAtoms::charType,
-                               NS_INT32_TO_PTR(charType), nsnull, nsnull);
+        propTable->Set(frame, nsIFrame::CharTypeProperty(),
+                       NS_INT32_TO_PTR(charType));
         // IBMBIDI - Egypt - End
 
         if ( (runLength > 0) && (runLength < fragmentLength) ) {
           /*
            * The text in this frame continues beyond the end of this directional run.
            * Create a non-fluid continuation frame for the next directional run.
            */
           if (lineNeedsUpdate) {
@@ -1174,36 +1175,40 @@ nsBidiPresUtils::EnsureBidiContinuation(
 }
 
 void
 nsBidiPresUtils::RemoveBidiContinuation(nsIFrame*       aFrame,
                                         PRInt32         aFirstIndex,
                                         PRInt32         aLastIndex,
                                         PRInt32&        aOffset) const
 {
-  nsresult rv;
-  nsBidiLevel embeddingLevel = (nsCharType)NS_PTR_TO_INT32(aFrame->GetProperty(nsGkAtoms::embeddingLevel, &rv));
-  NS_ASSERTION(NS_SUCCEEDED(rv), "embeddingLevel attribute missing from aFrame");
-  nsBidiLevel baseLevel = (nsCharType)NS_PTR_TO_INT32(aFrame->GetProperty(nsGkAtoms::baseLevel, &rv));
-  NS_ASSERTION(NS_SUCCEEDED(rv), "baseLevel attribute missing from aFrame");
-  nsCharType charType = (nsCharType)NS_PTR_TO_INT32(aFrame->GetProperty(nsGkAtoms::charType, &rv));
-  NS_ASSERTION(NS_SUCCEEDED(rv), "charType attribute missing from aFrame");
-  
+  FrameProperties props = aFrame->Properties();
+  nsBidiLevel embeddingLevel =
+    (nsCharType)NS_PTR_TO_INT32(props.Get(nsIFrame::EmbeddingLevelProperty()));
+  nsBidiLevel baseLevel =
+    (nsCharType)NS_PTR_TO_INT32(props.Get(nsIFrame::BaseLevelProperty()));
+  nsCharType charType =
+    (nsCharType)NS_PTR_TO_INT32(props.Get(nsIFrame::CharTypeProperty()));
+
   for (PRInt32 index = aFirstIndex + 1; index <= aLastIndex; index++) {
     nsIFrame* frame = mLogicalFrames[index];
     if (nsGkAtoms::directionalFrame == frame->GetType()) {
       frame->Destroy();
       ++aOffset;
     }
     else {
       // Make the frame and its continuation ancestors fluid,
       // so they can be reused or deleted by normal reflow code
-      frame->SetProperty(nsGkAtoms::embeddingLevel, NS_INT32_TO_PTR(embeddingLevel));
-      frame->SetProperty(nsGkAtoms::baseLevel, NS_INT32_TO_PTR(baseLevel));
-      frame->SetProperty(nsGkAtoms::charType, NS_INT32_TO_PTR(charType));
+      FrameProperties frameProps = frame->Properties();
+      frameProps.Set(nsIFrame::EmbeddingLevelProperty(),
+                     NS_INT32_TO_PTR(embeddingLevel));
+      frameProps.Set(nsIFrame::BaseLevelProperty(),
+                     NS_INT32_TO_PTR(baseLevel));
+      frameProps.Set(nsIFrame::CharTypeProperty(),
+                     NS_INT32_TO_PTR(charType));
       frame->AddStateBits(NS_FRAME_IS_BIDI);
       while (frame) {
         nsIFrame* prev = frame->GetPrevContinuation();
         if (prev) {
           NS_ASSERTION (!frame->GetPrevInFlow() || frame->GetPrevInFlow() == prev, 
                         "prev-in-flow is not prev continuation!");
           frame->SetPrevInFlow(prev);
 
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -145,16 +145,18 @@
 #endif
 #ifdef MOZ_SVG
 #include "nsSVGFeatures.h"
 #include "nsSVGEffects.h"
 #include "nsSVGUtils.h"
 #include "nsSVGOuterSVGFrame.h"
 #endif
 
+using namespace mozilla;
+
 nsIFrame*
 NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 #if defined(MOZ_MEDIA)
 nsIFrame*
 NS_NewHTMLVideoFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
 #endif
 
@@ -455,32 +457,30 @@ IsFrameSpecial(nsIFrame* aFrame)
 }
 
 static nsIFrame* GetSpecialSibling(nsIFrame* aFrame)
 {
   NS_PRECONDITION(IsFrameSpecial(aFrame), "Shouldn't call this");
 
   // We only store the "special sibling" annotation with the first
   // frame in the continuation chain. Walk back to find that frame now.
-  return
-    static_cast<nsIFrame*>
+  return static_cast<nsIFrame*>
     (aFrame->GetFirstContinuation()->
-       GetProperty(nsGkAtoms::IBSplitSpecialSibling));
+       Properties().Get(nsIFrame::IBSplitSpecialSibling()));
 }
 
 static nsIFrame* GetSpecialPrevSibling(nsIFrame* aFrame)
 {
   NS_PRECONDITION(IsFrameSpecial(aFrame), "Shouldn't call this");
   
   // We only store the "special sibling" annotation with the first
   // frame in the continuation chain. Walk back to find that frame now.  
-  return
-    static_cast<nsIFrame*>
+  return static_cast<nsIFrame*>
     (aFrame->GetFirstContinuation()->
-       GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling));
+       Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
 }
 
 static nsIFrame*
 GetLastSpecialSibling(nsIFrame* aFrame, PRBool aReturnEmptyTrailingInline)
 {
   for (nsIFrame *frame = aFrame, *next; ; frame = next) {
     next = GetSpecialSibling(frame);
     if (!next ||
@@ -512,18 +512,19 @@ SetFrameIsSpecial(nsIFrame* aFrame, nsIF
 
   if (aSpecialSibling) {
     NS_ASSERTION(!aSpecialSibling->GetPrevContinuation(),
                  "assigning something other than the first continuation as the "
                  "special sibling");
 
     // Store the "special sibling" (if we were given one) with the
     // first frame in the flow.
-    aFrame->SetProperty(nsGkAtoms::IBSplitSpecialSibling, aSpecialSibling);
-    aSpecialSibling->SetProperty(nsGkAtoms::IBSplitSpecialPrevSibling, aFrame);
+    FramePropertyTable* props = aFrame->PresContext()->PropertyTable();
+    props->Set(aFrame, nsIFrame::IBSplitSpecialSibling(), aSpecialSibling);
+    props->Set(aSpecialSibling, nsIFrame::IBSplitSpecialPrevSibling(), aFrame);
   }
 }
 
 static nsIFrame*
 GetIBContainingBlockFor(nsIFrame* aFrame)
 {
   NS_PRECONDITION(IsFrameSpecial(aFrame),
                   "GetIBContainingBlockFor() should only be called on known IB frames");
@@ -5290,26 +5291,37 @@ nsCSSFrameConstructor::AddFrameConstruct
   if ((bits & FCDATA_IS_LINE_PARTICIPANT) &&
       ((bits & FCDATA_DISALLOW_OUT_OF_FLOW) ||
        !aState.GetGeometricParent(display, nsnull))) {
     item->mIsLineParticipant = PR_TRUE;
     aItems.LineParticipantItemAdded();
   }
 }
 
-static void DestroyContent(void *aObject,
-                           nsIAtom *aPropertyName,
-                           void *aPropertyValue,
-                           void *aData)
+static void
+DestroyContent(void* aPropertyValue)
 {
   nsIContent* content = static_cast<nsIContent*>(aPropertyValue);
   content->UnbindFromTree();
   NS_RELEASE(content);
 }
 
+NS_DECLARE_FRAME_PROPERTY(BeforeProperty, DestroyContent)
+NS_DECLARE_FRAME_PROPERTY(AfterProperty, DestroyContent)
+
+static const FramePropertyDescriptor*
+GenConPseudoToProperty(nsIAtom* aPseudo)
+{
+  NS_ASSERTION(aPseudo == nsCSSPseudoElements::before ||
+               aPseudo == nsCSSPseudoElements::after,
+               "Bad gen-con pseudo");
+  return aPseudo == nsCSSPseudoElements::before ? BeforeProperty()
+      : AfterProperty();
+}
+
 /**
  * Return true if the frame construction item pointed to by aIter will
  * create a frame adjacent to a line boundary in the frame tree, and that
  * line boundary is induced by a content node adjacent to the frame's
  * content node in the content tree. The latter condition is necessary so
  * that ContentAppended/ContentInserted/ContentRemoved can easily find any
  * text nodes that were suppressed here.
  */
@@ -5401,18 +5413,18 @@ nsCSSFrameConstructor::ConstructFramesFr
     // NS_FRAME_GENERATED_CONTENT.
     aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
 
     // Note that we're not necessarily setting this property on the primary
     // frame for the content for which this is generated content.  We might be
     // setting it on a table pseudo-frame inserted under that instead.  That's
     // OK, though; we just need to do the property set so that the content will
     // get cleaned up when the frame is destroyed.
-    aParentFrame->SetProperty(styleContext->GetPseudo(),
-                              item.mContent, DestroyContent);
+    aParentFrame->Properties().Set(GenConPseudoToProperty(styleContext->GetPseudo()),
+                                   item.mContent);
 
     // Now that we've passed ownership of item.mContent to the frame, unset
     // our generated content flag so we don't release or unbind it ourselves.
     item.mIsGeneratedContent = PR_FALSE;
   }
 
   // XXXbz maybe just inline ConstructFrameFromItemInternal here or something?
   nsresult rv = ConstructFrameFromItemInternal(item, aState, adjParentFrame,
@@ -7405,44 +7417,45 @@ nsCSSFrameConstructor::CharacterDataChan
     if (haveFirstLetterStyle) {
       RecoverLetterFrames(block);
     }
   }
 
   return rv;
 }
 
+NS_DECLARE_FRAME_PROPERTY(ChangeListProperty, nsnull)
+
 nsresult
 nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
 {
   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
                "Someone forgot a script blocker");
   PRInt32 count = aChangeList.Count();
   if (!count)
     return NS_OK;
 
   // Make sure to not rebuild quote or counter lists while we're
   // processing restyles
   BeginUpdate();
 
   nsPresContext* presContext = mPresShell->GetPresContext();
-  nsPropertyTable *propTable = presContext->PropertyTable();
+  FramePropertyTable* propTable = presContext->PropertyTable();
 
   // Mark frames so that we skip frames that die along the way, bug 123049.
   // A frame can be in the list multiple times with different hints. Further
   // optmization is possible if nsStyleChangeList::AppendChange could coalesce
   PRInt32 index = count;
 
   while (0 <= --index) {
     const nsStyleChangeData* changeData;
     aChangeList.ChangeAt(index, &changeData);
     if (changeData->mFrame) {
-      propTable->SetProperty(changeData->mFrame,
-                             nsGkAtoms::changeListProperty,
-                             nsnull, nsnull, nsnull);
+      propTable->Set(changeData->mFrame, ChangeListProperty(),
+                     NS_INT32_TO_PTR(1));
     }
   }
 
   index = count;
   PRBool didInvalidate = PR_FALSE;
   PRBool didReflow = PR_FALSE;
 
   while (0 <= --index) {
@@ -7461,21 +7474,17 @@ nsCSSFrameConstructor::ProcessRestyledFr
       frame = nsnull;
       if (!(hint & nsChangeHint_ReconstructFrame)) {
         continue;
       }
     }
 
     // skip any frame that has been destroyed due to a ripple effect
     if (frame) {
-      nsresult res;
-
-      propTable->GetProperty(frame, nsGkAtoms::changeListProperty, &res);
-
-      if (NS_PROPTABLE_PROP_NOT_THERE == res)
+      if (!propTable->Get(frame, ChangeListProperty()))
         continue;
     }
 
     if (hint & nsChangeHint_ReconstructFrame) {
       RecreateFramesForContent(content, PR_FALSE);
     } else {
       NS_ASSERTION(frame, "This shouldn't happen");
 #ifdef MOZ_SVG
@@ -7515,18 +7524,17 @@ nsCSSFrameConstructor::ProcessRestyledFr
   // cleanup references and verify the style tree.  Note that the latter needs
   // to happen once we've processed the whole list, since until then the tree
   // is not in fact in a consistent state.
   index = count;
   while (0 <= --index) {
     const nsStyleChangeData* changeData;
     aChangeList.ChangeAt(index, &changeData);
     if (changeData->mFrame) {
-      propTable->DeleteProperty(changeData->mFrame,
-                                nsGkAtoms::changeListProperty);
+      propTable->Delete(changeData->mFrame, ChangeListProperty());
     }
 
 #ifdef DEBUG
     // reget frame from content since it may have been regenerated...
     if (changeData->mContent) {
       nsIFrame* frame = changeData->mContent->GetPrimaryFrame();
       if (frame) {
         mPresShell->FrameManager()->DebugVerifyStyleTree(frame);
@@ -10156,20 +10164,20 @@ nsCSSFrameConstructor::ConstructInline(n
   // contain the runs of blocks, inline frames with our style context for the
   // runs of inlines, and put all these frames, in order, into aFrameItems.  We
   // put the first one into *aNewFrame.  The whole setup is called an {ib}
   // split; in what follows "frames in the split" refers to the anonymous blocks
   // and inlines that contain our children.
   //
   // {ib} splits maintain the following invariants:
   // 1) All frames in the split have the NS_FRAME_IS_SPECIAL bit set.
-  // 2) Each frame in the split has the nsGkAtoms::IBSplitSpecialSibling
+  // 2) Each frame in the split has the nsIFrame::IBSplitSpecialSibling
   //    property pointing to the next frame in the split, except for the last
   //    one, which does not have it set.
-  // 3) Each frame in the split has the nsGkAtoms::IBSplitSpecialPrevSibling
+  // 3) Each frame in the split has the nsIFrame::IBSplitSpecialPrevSibling
   //    property pointing to the previous frame in the split, except for the
   //    first one, which does not have it set.
   // 4) The first and last frame in the split are always inlines.
   //
   // An invariant that is NOT maintained is that the wrappers are actually
   // linked via GetNextSibling linkage.  A simple example is an inline
   // containing an inline that contains a block.  The three parts of the inner
   // inline end up with three different parents.
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -258,45 +258,41 @@ protected:
     
     mFrame = aFrame;
   }
 
   nsIFrame* GetPrevContinuation(nsIFrame* aFrame)
   {
     nsIFrame* prevCont = aFrame->GetPrevContinuation();
     if (!prevCont && (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
-      nsIFrame* block =
-        static_cast<nsIFrame*>
-                   (aFrame->GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling));
+      nsIFrame* block = static_cast<nsIFrame*>
+        (aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
       if (block) {
         // The {ib} properties are only stored on first continuations
         NS_ASSERTION(!block->GetPrevContinuation(),
                      "Incorrect value for IBSplitSpecialPrevSibling");
-        prevCont =
-          static_cast<nsIFrame*>
-                     (block->GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling));
+        prevCont = static_cast<nsIFrame*>
+          (block->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
         NS_ASSERTION(prevCont, "How did that happen?");
       }
     }
     return prevCont;
   }
 
   nsIFrame* GetNextContinuation(nsIFrame* aFrame)
   {
     nsIFrame* nextCont = aFrame->GetNextContinuation();
     if (!nextCont && (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
       // The {ib} properties are only stored on first continuations
       aFrame = aFrame->GetFirstContinuation();
-      nsIFrame* block =
-        static_cast<nsIFrame*>
-                   (aFrame->GetProperty(nsGkAtoms::IBSplitSpecialSibling));
+      nsIFrame* block = static_cast<nsIFrame*>
+        (aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
       if (block) {
-        nextCont =
-          static_cast<nsIFrame*>
-                     (block->GetProperty(nsGkAtoms::IBSplitSpecialSibling));
+        nextCont = static_cast<nsIFrame*>
+          (block->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
         NS_ASSERTION(nextCont, "How did that happen?");
       }
     }
     return nextCont;
   }
 
   void Init(nsIFrame* aFrame)
   {    
@@ -670,17 +666,17 @@ nsCSSRendering::PaintBorder(nsPresContex
 
   SN();
 }
 
 static nsRect
 GetOutlineInnerRect(nsIFrame* aFrame)
 {
   nsRect* savedOutlineInnerRect = static_cast<nsRect*>
-    (aFrame->GetProperty(nsGkAtoms::outlineInnerRectProperty));
+    (aFrame->Properties().Get(nsIFrame::OutlineInnerRectProperty()));
   if (savedOutlineInnerRect)
     return *savedOutlineInnerRect;
   return aFrame->GetOverflowRect();
 }
 
 void
 nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
                              nsIRenderingContext& aRenderingContext,
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -91,26 +91,16 @@ nsDisplayListBuilder::nsDisplayListBuild
     }
   }
 
   if (mIsBackgroundOnly) {
     mBuildCaret = PR_FALSE;
   }
 }
 
-// Destructor function for the dirty rect property
-static void
-DestroyRectFunc(void*    aFrame,
-                nsIAtom* aPropertyName,
-                void*    aPropertyValue,
-                void*    aDtorData)
-{
-  delete static_cast<nsRect*>(aPropertyValue);
-}
-
 static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
   nsFrameManager* frameManager = aFrame->PresContext()->PresShell()->FrameManager();
 
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, f)) {
     if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
       return;
     f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
@@ -122,27 +112,28 @@ static void MarkFrameForDisplay(nsIFrame
 }
 
 static void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
                                          const nsRect& aDirtyRect) {
   nsRect dirty = aDirtyRect - aFrame->GetOffsetTo(aDirtyFrame);
   nsRect overflowRect = aFrame->GetOverflowRect();
   if (!dirty.IntersectRect(dirty, overflowRect))
     return;
-  // if "new nsRect" fails, this won't do anything, but that's okay
-  aFrame->SetProperty(nsGkAtoms::outOfFlowDirtyRectProperty,
-                      new nsRect(dirty), DestroyRectFunc);
+  aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDirtyRectProperty(),
+                           new nsRect(dirty));
 
   MarkFrameForDisplay(aFrame, aDirtyFrame);
 }
 
 static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
-  aFrame->DeleteProperty(nsGkAtoms::outOfFlowDirtyRectProperty);
+  nsPresContext* presContext = aFrame->PresContext();
+  presContext->PropertyTable()->
+    Delete(aFrame, nsDisplayListBuilder::OutOfFlowDirtyRectProperty());
 
-  nsFrameManager* frameManager = aFrame->PresContext()->PresShell()->FrameManager();
+  nsFrameManager* frameManager = presContext->PresShell()->FrameManager();
 
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, f)) {
     if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
       return;
     f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   }
 }
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -114,16 +114,18 @@ class nsDisplayItem;
  * It contains the parameters that don't change from frame to frame and manages
  * the display list memory using a PLArena. It also establishes the reference
  * coordinate system for all display list items. Some of the parameters are
  * available from the prescontext/presshell, but we copy them into the builder
  * for faster/more convenient access.
  */
 class NS_STACK_CLASS nsDisplayListBuilder {
 public:
+  typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
+
   /**
    * @param aReferenceFrame the frame at the root of the subtree; its origin
    * is the origin of the reference coordinate system for this display list
    * @param aIsForEvents PR_TRUE if we're creating this list in order to
    * determine which frame is under the mouse position
    * @param aBuildCaret whether or not we should include the caret in any
    * display lists that we make.
    */
@@ -379,16 +381,18 @@ public:
     nsDisplayListBuilder* mBuilder;
     PRPackedBool          mOldValue;
   };  
   
   // Helpers for tables
   nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; }
   void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; }
 
+  NS_DECLARE_FRAME_PROPERTY(OutOfFlowDirtyRectProperty, nsIFrame::DestroyRect)
+
 private:
   // This class is only used on stack, so we don't have to worry about leaking
   // it.  Don't let us be heap-allocated!
   void* operator new(size_t sz) CPP_THROW_NEW;
   
   struct PresShellState {
     nsIPresShell* mPresShell;
     nsIFrame*     mCaretFrame;
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -111,17 +111,17 @@
       printf("%s",_msg);
     #define NOISY_TRACE_FRAME(_msg,_frame) \
       printf("%s ",_msg); nsFrame::ListTag(stdout,_frame); printf("\n");
   #else
     #define NOISY_TRACE(_msg);
     #define NOISY_TRACE_FRAME(_msg,_frame);
   #endif
 
-// IID's
+using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 struct PlaceholderMapEntry : public PLDHashEntryHdr {
   // key (the out of flow frame) can be obtained through placeholder frame
   nsPlaceholderFrame *placeholderFrame;
 };
 
@@ -899,17 +899,18 @@ nsFrameManager::ReParentStyleContext(nsI
         // If this frame is part of an IB split, then the style context of
         // the next part of the split might be a child of our style context.
         // Reparent its style context just in case one of our ancestors
         // (split or not) hasn't done so already). It's not a problem to
         // reparent the same frame twice because the "if (newContext !=
         // oldContext)" check will prevent us from redoing work.
         if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
             !aFrame->GetPrevContinuation()) {
-          nsIFrame* sib = static_cast<nsIFrame*>(aFrame->GetProperty(nsGkAtoms::IBSplitSpecialSibling));
+          nsIFrame* sib = static_cast<nsIFrame*>
+            (aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling()));
           if (sib) {
             ReParentStyleContext(sib);
           }
         }
 
         // do additional contexts 
         PRInt32 contextIndex = -1;
         while (1) {
@@ -1463,17 +1464,17 @@ nsFrameManager::ComputeStyleChangeFor(ns
   nsIFrame* frame2 = aFrame;
 
   NS_ASSERTION(!frame->GetPrevContinuation(), "must start with the first in flow");
 
   // We want to start with this frame and walk all its next-in-flows,
   // as well as all its special siblings and their next-in-flows,
   // reresolving style on all the frames we encounter in this walk.
 
-  nsPropertyTable *propTable = GetPresContext()->PropertyTable();
+  FramePropertyTable *propTable = GetPresContext()->PropertyTable();
 
   do {
     // Outer loop over special siblings
     do {
       // Inner loop over next-in-flows of the current frame
       nsChangeHint frameChange =
         ReResolveStyleContext(GetPresContext(), frame, nsnull,
                               aChangeList, topLevelChange, PR_TRUE);
@@ -1493,17 +1494,17 @@ nsFrameManager::ComputeStyleChangeFor(ns
 
     // Might we have special siblings?
     if (!(frame2->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
       // nothing more to do here
       return;
     }
     
     frame2 = static_cast<nsIFrame*>
-                        (propTable->GetProperty(frame2, nsGkAtoms::IBSplitSpecialSibling));
+      (propTable->Get(frame2, nsIFrame::IBSplitSpecialSibling()));
     frame = frame2;
   } while (frame2);
 }
 
 
 nsReStyleHint
 nsFrameManager::HasAttributeDependentStyle(nsIContent *aContent,
                                            nsIAtom *aAttribute,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1823,31 +1823,31 @@ nsLayoutUtils::GetNextContinuationOrSpec
   if (result)
     return result;
 
   if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) != 0) {
     // We only store the "special sibling" annotation with the first
     // frame in the continuation chain. Walk back to find that frame now.
     aFrame = aFrame->GetFirstContinuation();
 
-    void* value = aFrame->GetProperty(nsGkAtoms::IBSplitSpecialSibling);
+    void* value = aFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling());
     return static_cast<nsIFrame*>(value);
   }
 
   return nsnull;
 }
 
 nsIFrame*
 nsLayoutUtils::GetFirstContinuationOrSpecialSibling(nsIFrame *aFrame)
 {
   nsIFrame *result = aFrame->GetFirstContinuation();
   if (result->GetStateBits() & NS_FRAME_IS_SPECIAL) {
     while (PR_TRUE) {
       nsIFrame *f = static_cast<nsIFrame*>
-        (result->GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling));
+        (result->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
       if (!f)
         break;
       result = f;
     }
   }
 
   return result;
 }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1096,27 +1096,27 @@ public:
 
   /**
    * Return true if aFrame is in an {ib} split and is NOT one of the
    * continuations of the first inline in it.
    */
   static PRBool FrameIsNonFirstInIBSplit(const nsIFrame* aFrame) {
     return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
       aFrame->GetFirstContinuation()->
-        GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling);
+        Properties().Get(nsIFrame::IBSplitSpecialPrevSibling());
   }
 
   /**
    * Return true if aFrame is in an {ib} split and is NOT one of the
    * continuations of the last inline in it.
    */
   static PRBool FrameIsNonLastInIBSplit(const nsIFrame* aFrame) {
     return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) &&
       aFrame->GetFirstContinuation()->
-        GetProperty(nsGkAtoms::IBSplitSpecialSibling);
+        Properties().Get(nsIFrame::IBSplitSpecialSibling());
   }
 
   /**
    * Obtain a gfxASurface from the given DOM element, if possible.
    * This obtains the most natural surface from the element; that
    * is, the one that can be obtained with the fewest conversions.
    *
    * The flags below can modify the behaviour of this function.  The
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -52,17 +52,17 @@
 #include "nsFont.h"
 #include "nsIWeakReference.h"
 #include "nsITheme.h"
 #include "nsILanguageAtomService.h"
 #include "nsIObserver.h"
 #include "nsITimer.h"
 #include "nsCRT.h"
 #include "nsIPrintSettings.h"
-#include "nsPropertyTable.h"
+#include "FramePropertyTable.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsRefPtrHashtable.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsChangeHint.h"
 // This also pulls in gfxTypes.h, which we cannot include directly.
 #include "gfxRect.h"
 #include "nsRegion.h"
@@ -169,16 +169,18 @@ public:
 
 class nsRootPresContext;
 
 // An interface for presentation contexts. Presentation contexts are
 // objects that provide an outer context for a presentation shell.
 
 class nsPresContext : public nsIObserver {
 public:
+  typedef mozilla::FramePropertyTable FramePropertyTable;
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
   NS_DECL_CYCLE_COLLECTION_CLASS(nsPresContext)
 
   enum nsPresContextType {
     eContext_Galley,       // unpaginated screen presentation
     eContext_PrintPreview, // paginated screen presentation
@@ -778,17 +780,17 @@ public:
   NS_HIDDEN_(void) SysColorChanged();
 
   /** Printing methods below should only be used for Medium() == print **/
   NS_HIDDEN_(void) SetPrintSettings(nsIPrintSettings *aPrintSettings);
 
   nsIPrintSettings* GetPrintSettings() { return mPrintSettings; }
 
   /* Accessor for table of frame properties */
-  nsPropertyTable* PropertyTable() { return &mPropertyTable; }
+  FramePropertyTable* PropertyTable() { return &mPropertyTable; }
 
   /* Helper function that ensures that this prescontext is shown in its
      docshell if it's the most recent prescontext for the docshell.  Returns
      whether the prescontext is now being shown.
   */
   NS_HIDDEN_(PRBool) EnsureVisible();
   
 #ifdef MOZ_REFLOW_PERF
@@ -1021,17 +1023,17 @@ protected:
   nsBidiPresUtils*      mBidiUtils;
 #endif
 
   nsCOMPtr<nsITheme> mTheme;
   nsCOMPtr<nsILanguageAtomService> mLangService;
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
   nsCOMPtr<nsITimer>    mPrefChangedTimer;
 
-  nsPropertyTable       mPropertyTable;
+  FramePropertyTable    mPropertyTable;
 
   nsInvalidateRequestList mInvalidateRequests;
 
   // container for per-context fonts (downloadable, SVG, etc.)
   nsUserFontSet*        mUserFontSet;
   // The list of @font-face rules that we put into mUserFontSet
   nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
   
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1849,17 +1849,17 @@ PresShell::Destroy()
   // while destroying the frame tree, but which might contain more
   // frames within the properties.
   if (mPresContext) {
     // Clear out the prescontext's property table -- since our frame tree is
     // now dead, we shouldn't be looking up any more properties in that table.
     // We want to do this before we call SetShell() on the prescontext, so
     // property destructors can usefully call GetPresShell() on the
     // prescontext.
-    mPresContext->PropertyTable()->DeleteAllProperties();
+    mPresContext->PropertyTable()->DeleteAll();
   }
 
 
   NS_WARN_IF_FALSE(!mWeakFrames, "Weak frames alive after destroying FrameManager");
   while (mWeakFrames) {
     mWeakFrames->Clear(this);
   }
 
@@ -2749,17 +2749,17 @@ PresShell::NotifyDestroyingFrame(nsIFram
         mDirtyRoots.RemoveElementAt(idx);
       }
     }
 
     // Notify the frame manager
     FrameManager()->NotifyDestroyingFrame(aFrame);
 
     // Remove frame properties
-    mPresContext->PropertyTable()->DeleteAllPropertiesFor(aFrame);
+    mPresContext->PropertyTable()->DeleteAllFor(aFrame);
 
     if (aFrame == mCurrentEventFrame) {
       mCurrentEventContent = aFrame->GetContent();
       mCurrentEventFrame = nsnull;
     }
 
   #ifdef NS_DEBUG
     if (aFrame == mDrawEventTargetFrame) {
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -95,16 +95,18 @@
 
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLHtmlElement.h"
 
 static const int MIN_LINES_NEEDING_CURSOR = 20;
 
 #define DISABLE_FLOAT_BREAKING_IN_COLUMNS
 
+using namespace mozilla;
+
 #ifdef DEBUG
 #include "nsPrintfCString.h"
 #include "nsBlockDebugFlags.h"
 
 PRBool nsBlockFrame::gLamePaintMetrics;
 PRBool nsBlockFrame::gLameReflowMetrics;
 PRBool nsBlockFrame::gNoisy;
 PRBool nsBlockFrame::gNoisyDamageRepair;
@@ -260,16 +262,28 @@ RecordReflowStatus(PRBool aChildIsBlock,
   // Log updates to the status that yield different values
   if (record[index] != newS) {
     record[index] = newS;
     printf("record(%d): %02x %02x\n", index, record[0], record[1]);
   }
 }
 #endif
 
+// Destructor function for the overflowLines frame property
+static void
+DestroyOverflowLines(void* aPropertyValue)
+{
+  NS_ERROR("Overflow lines should never be destroyed by the FramePropertyTable");
+}
+
+NS_DECLARE_FRAME_PROPERTY(LineCursorProperty, nsnull)
+NS_DECLARE_FRAME_PROPERTY(OverflowLinesProperty, DestroyOverflowLines)
+NS_DECLARE_FRAME_PROPERTY(OverflowOutOfFlowsProperty,
+                          nsContainerFrame::DestroyFrameList)
+
 //----------------------------------------------------------------------
 
 nsIFrame*
 NS_NewBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags)
 {
   nsBlockFrame* it = new (aPresShell) nsBlockFrame(aContext);
   if (it) {
     it->SetFlags(aFlags);
@@ -363,21 +377,21 @@ nsBlockFrame::List(FILE* out, PRInt32 aI
   // Output the flow linkage
   if (nsnull != GetPrevInFlow()) {
     fprintf(out, " prev-in-flow=%p", static_cast<void*>(GetPrevInFlow()));
   }
   if (nsnull != GetNextInFlow()) {
     fprintf(out, " next-in-flow=%p", static_cast<void*>(GetNextInFlow()));
   }
 
-  void* IBsibling = GetProperty(nsGkAtoms::IBSplitSpecialSibling);
+  void* IBsibling = Properties().Get(IBSplitSpecialSibling());
   if (IBsibling) {
     fprintf(out, " IBSplitSpecialSibling=%p", IBsibling);
   }
-  void* IBprevsibling = GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling);
+  void* IBprevsibling = Properties().Get(IBSplitSpecialPrevSibling());
   if (IBprevsibling) {
     fprintf(out, " IBSplitSpecialPrevSibling=%p", IBprevsibling);
   }
 
   if (nsnull != mContent) {
     fprintf(out, " [content=%p]", static_cast<void*>(mContent));
   }
 
@@ -4485,79 +4499,62 @@ nsBlockFrame::DrainFloatContinuations(ns
 
 nsLineList*
 nsBlockFrame::GetOverflowLines() const
 {
   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES)) {
     return nsnull;
   }
   nsLineList* lines = static_cast<nsLineList*>
-                                 (GetProperty(nsGkAtoms::overflowLinesProperty));
+    (Properties().Get(OverflowLinesProperty()));
   NS_ASSERTION(lines && !lines->empty(),
                "value should always be stored and non-empty when state set");
   return lines;
 }
 
 nsLineList*
 nsBlockFrame::RemoveOverflowLines()
 {
   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES)) {
     return nsnull;
   }
   nsLineList* lines = static_cast<nsLineList*>
-                                 (UnsetProperty(nsGkAtoms::overflowLinesProperty));
+    (Properties().Remove(OverflowLinesProperty()));
   NS_ASSERTION(lines && !lines->empty(),
                "value should always be stored and non-empty when state set");
   RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
   return lines;
 }
 
-// Destructor function for the overflowLines frame property
-static void
-DestroyOverflowLines(void*           aFrame,
-                     nsIAtom*        aPropertyName,
-                     void*           aPropertyValue,
-                     void*           aDtorData)
-{
-  if (aPropertyValue) {
-    nsLineList* lines = static_cast<nsLineList*>(aPropertyValue);
-    nsPresContext *context = static_cast<nsPresContext*>(aDtorData);
-    nsLineBox::DeleteLineList(context, *lines, nsnull);
-    delete lines;
-  }
-}
-
 // This takes ownership of aOverflowLines.
 // XXX We should allocate overflowLines from presShell arena!
 nsresult
 nsBlockFrame::SetOverflowLines(nsLineList* aOverflowLines)
 {
   NS_ASSERTION(aOverflowLines, "null lines");
   NS_ASSERTION(!aOverflowLines->empty(), "empty lines");
   NS_ASSERTION(!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES),
                "Overwriting existing overflow lines");
 
-  nsPresContext *presContext = PresContext();
-  nsresult rv = presContext->PropertyTable()->
-    SetProperty(this, nsGkAtoms::overflowLinesProperty, aOverflowLines,
-                DestroyOverflowLines, presContext);
-  // Verify that we didn't overwrite an existing overflow list
-  NS_ASSERTION(rv != NS_PROPTABLE_PROP_OVERWRITTEN, "existing overflow list");
+  FrameProperties props = Properties();
+  // Verify that we won't overwrite an existing overflow list
+  NS_ASSERTION(!props.Get(OverflowLinesProperty()), "existing overflow list");
+  props.Set(OverflowLinesProperty(), aOverflowLines);
   AddStateBits(NS_BLOCK_HAS_OVERFLOW_LINES);
-  return rv;
+  return NS_OK;
 }
 
 nsFrameList*
 nsBlockFrame::GetOverflowOutOfFlows() const
 {
   if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)) {
     return nsnull;
   }
   nsFrameList* result =
-    GetPropTableFrames(PresContext(), nsGkAtoms::overflowOutOfFlowsProperty);
+    GetPropTableFrames(PresContext(), OverflowOutOfFlowsProperty());
   NS_ASSERTION(result, "value should always be non-empty when state set");
   return result;
 }
 
 // This takes ownership of the frames
 void
 nsBlockFrame::SetOverflowOutOfFlows(const nsFrameList& aList,
                                     nsFrameList* aPropValue)
@@ -4566,30 +4563,30 @@ nsBlockFrame::SetOverflowOutOfFlows(cons
                   !!aPropValue, "state does not match value");
 
   if (aList.IsEmpty()) {
     if (!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)) {
       return;
     }
     nsFrameList* list =
       RemovePropTableFrames(PresContext(),
-                            nsGkAtoms::overflowOutOfFlowsProperty);
+                            OverflowOutOfFlowsProperty());
     NS_ASSERTION(aPropValue == list, "prop value mismatch");
     delete list;
     RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
   }
   else if (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS) {
     NS_ASSERTION(aPropValue == GetPropTableFrames(PresContext(),
-                                 nsGkAtoms::overflowOutOfFlowsProperty),
+                                 OverflowOutOfFlowsProperty()),
                  "prop value mismatch");
     *aPropValue = aList;
   }
   else {
     SetPropTableFrames(PresContext(), new nsFrameList(aList),
-                       nsGkAtoms::overflowOutOfFlowsProperty);
+                       OverflowOutOfFlowsProperty());
     AddStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS);
   }
 }
 
 //////////////////////////////////////////////////////////////////////
 // Frame list manipulation routines
 
 NS_IMETHODIMP
@@ -5402,17 +5399,17 @@ nsBlockFrame::StealFrame(nsPresContext* 
 {
   NS_PRECONDITION(aPresContext && aChild, "null pointer");
 
   if ((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
       aChild->GetStyleDisplay()->IsFloating()) {
     PRBool removed = mFloats.RemoveFrameIfPresent(aChild);
     if (!removed) {
       nsFrameList* list = GetPropTableFrames(aPresContext,
-                                          nsGkAtoms::floatContinuationProperty);
+                                             FloatContinuationProperty());
       if (list) {
         removed = list->RemoveFrameIfPresent(aChild);
       }
     }
     return removed ? NS_OK : NS_ERROR_UNEXPECTED;
   }
 
   if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
@@ -6192,57 +6189,57 @@ NS_IMETHODIMP nsBlockFrame::GetAccessibl
 #endif
 
 void nsBlockFrame::ClearLineCursor()
 {
   if (!(GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR)) {
     return;
   }
 
-  UnsetProperty(nsGkAtoms::lineCursorProperty);
+  Properties().Delete(LineCursorProperty());
   RemoveStateBits(NS_BLOCK_HAS_LINE_CURSOR);
 }
 
 void nsBlockFrame::SetupLineCursor()
 {
   if (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR
       || mLines.empty()) {
     return;
   }
    
-  SetProperty(nsGkAtoms::lineCursorProperty,
-              mLines.front(), nsnull);
+  Properties().Set(LineCursorProperty(), mLines.front());
   AddStateBits(NS_BLOCK_HAS_LINE_CURSOR);
 }
 
 nsLineBox* nsBlockFrame::GetFirstLineContaining(nscoord y)
 {
   if (!(GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR)) {
     return nsnull;
   }
 
+  FrameProperties props = Properties();
+  
   nsLineBox* property = static_cast<nsLineBox*>
-                                   (GetProperty(nsGkAtoms::lineCursorProperty));
+    (props.Get(LineCursorProperty()));
   line_iterator cursor = mLines.begin(property);
   nsRect cursorArea = cursor->GetCombinedArea();
 
   while ((cursorArea.IsEmpty() || cursorArea.YMost() > y)
          && cursor != mLines.front()) {
     cursor = cursor.prev();
     cursorArea = cursor->GetCombinedArea();
   }
   while ((cursorArea.IsEmpty() || cursorArea.YMost() <= y)
          && cursor != mLines.back()) {
     cursor = cursor.next();
     cursorArea = cursor->GetCombinedArea();
   }
 
   if (cursor.get() != property) {
-    SetProperty(nsGkAtoms::lineCursorProperty,
-                cursor.get(), nsnull);
+    props.Set(LineCursorProperty(), cursor.get());
   }
 
   return cursor.get();
 }
 
 /* virtual */ void
 nsBlockFrame::ChildIsDirty(nsIFrame* aChild)
 {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -87,17 +87,17 @@ class nsIntervalSet;
 #define NS_BLOCK_LIST_COUNT  (NS_CONTAINER_LIST_COUNT_INCL_OC + 4)
 
 /**
  * Some invariants:
  * -- The overflow out-of-flows list contains the out-of-
  * flow frames whose placeholders are in the overflow list.
  * -- A given piece of content has at most one placeholder
  * frame in a block's normal child list.
- * -- While a block is being reflowed, it may have a floatContinuationProperty
+ * -- While a block is being reflowed, it may have a FloatContinuationProperty
  * frame property that points to an nsFrameList in its
  * nsBlockReflowState. This list contains continuations for
  * floats whose prev-in-flow is in the block's regular float
  * list. The list is always empty/non-existent after the
  * block has been reflowed.
  * -- In all these frame lists, if there are two frames for
  * the same content appearing in the list, then the frames
  * appear with the prev-in-flow before the next-in-flow.
@@ -151,16 +151,18 @@ public:
   const_line_iterator end_lines() const { return mLines.end(); }
   reverse_line_iterator rbegin_lines() { return mLines.rbegin(); }
   reverse_line_iterator rend_lines() { return mLines.rend(); }
   const_reverse_line_iterator rbegin_lines() const { return mLines.rbegin(); }
   const_reverse_line_iterator rend_lines() const { return mLines.rend(); }
 
   friend nsIFrame* NS_NewBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
 
+  NS_DECLARE_FRAME_PROPERTY(FloatContinuationProperty, nsnull)
+
   // nsQueryFrame
   NS_DECL_QUERYFRAME
 
   // nsIFrame
   NS_IMETHOD Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow);
   NS_IMETHOD SetInitialChildList(nsIAtom*        aListName,
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -152,17 +152,18 @@ nsBlockReflowState::~nsBlockReflowState(
   // Restore the coordinate system, unless the float manager is null,
   // which means it was just destroyed.
   if (mFloatManager) {
     const nsMargin& borderPadding = BorderPadding();
     mFloatManager->Translate(-borderPadding.left, -borderPadding.top);
   }
 
   if (GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
-    mBlock->UnsetProperty(nsGkAtoms::floatContinuationProperty);
+    mPresContext->PropertyTable()->
+      Delete(mBlock, nsBlockFrame::FloatContinuationProperty());
   }
 }
 
 nsLineBox*
 nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
                                PRInt32 aCount,
                                PRBool aIsBlock)
 {
@@ -427,18 +428,19 @@ nsBlockReflowState::ReconstructMarginAbo
     }
   }
 }
 
 void
 nsBlockReflowState::SetupFloatContinuationList()
 {
   if (!GetFlag(BRS_PROPTABLE_FLOATCLIST)) {
-    mBlock->SetProperty(nsGkAtoms::floatContinuationProperty,
-                        &mFloatContinuations, nsnull);
+    mPresContext->PropertyTable()->
+      Set(mBlock, nsBlockFrame::FloatContinuationProperty(),
+          &mFloatContinuations);
     SetFlag(BRS_PROPTABLE_FLOATCLIST, PR_TRUE);
   }
 }
 
 /**
  * Restore information about floats into the float manager for an
  * incremental reflow, and simultaneously push the floats by
  * |aDeltaY|, which is the amount |aLine| was pushed relative to its
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -75,16 +75,18 @@
 #include "nsThemeConstants.h"
 
 #ifdef NS_DEBUG
 #undef NOISY
 #else
 #undef NOISY
 #endif
 
+using namespace mozilla;
+
 NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame)
 
 nsContainerFrame::~nsContainerFrame()
 {
 }
 
 NS_QUERYFRAME_HEAD(nsContainerFrame)
   NS_QUERYFRAME_ENTRY(nsContainerFrame)
@@ -268,49 +270,27 @@ nsContainerFrame::DestroyFrom(nsIFrame* 
   mFrames.DestroyFramesFrom(aDestructRoot);
 
   // Destroy auxiliary frame lists
   nsPresContext* prescontext = PresContext();
 
   DestroyOverflowList(prescontext, aDestructRoot);
 
   if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
-    nsFrameList* frameList = RemovePropTableFrames(prescontext,
-                               nsGkAtoms::overflowContainersProperty);
+    nsFrameList* frameList =
+      RemovePropTableFrames(prescontext, OverflowContainersProperty());
     if (frameList)
       frameList->DestroyFrom(aDestructRoot);
 
     frameList = RemovePropTableFrames(prescontext,
-                  nsGkAtoms::excessOverflowContainersProperty);
+                                      ExcessOverflowContainersProperty());
     if (frameList)
       frameList->DestroyFrom(aDestructRoot);
   }
 
-  if (IsGeneratedContentFrame()) {
-    // Make sure all the content nodes for the generated content inside
-    // this frame know it's going away.
-    // See also nsCSSFrameConstructor::CreateGeneratedContentFrame which
-    // created this frame.
-    nsCOMArray<nsIContent>* generatedContent =
-      static_cast<nsCOMArray<nsIContent>*>(
-        UnsetProperty(nsGkAtoms::generatedContent));
-
-    if (generatedContent) {
-      for (int i = generatedContent->Count() - 1; i >= 0; --i) {
-        nsIContent* content = generatedContent->ObjectAt(i);
-        // Tell the ESM that this content is going away now, so it'll update
-        // its hover content, etc.
-        PresContext()->EventStateManager()->
-          ContentRemoved(content->GetCurrentDoc(), content);
-        content->UnbindFromTree();
-      }
-      delete generatedContent;
-    }
-  }
-
   // Destroy the frame and remove the flow pointers
   nsSplittableFrame::DestroyFrom(aDestructRoot);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Child frame enumeration
 
 nsFrameList
@@ -324,23 +304,23 @@ nsContainerFrame::GetChildList(nsIAtom* 
 
   if (nsGkAtoms::overflowList == aListName) {
     nsFrameList* frameList = GetOverflowFrames();
     return frameList ? *frameList : nsFrameList::EmptyList();
   }
 
   if (nsGkAtoms::overflowContainersList == aListName) {
     nsFrameList* list = GetPropTableFrames(PresContext(),
-                          nsGkAtoms::overflowContainersProperty);
+                                           OverflowContainersProperty());
     return list ? *list : nsFrameList::EmptyList();
   }
 
   if (nsGkAtoms::excessOverflowContainersList == aListName) {
     nsFrameList* list = GetPropTableFrames(PresContext(),
-                          nsGkAtoms::excessOverflowContainersProperty);
+                                           ExcessOverflowContainersProperty());
     return list ? *list : nsFrameList::EmptyList();
   }
 
   return nsFrameList::EmptyList();
 }
 
 #define NS_CONTAINER_FRAME_OVERFLOW_LIST_INDEX                   0
 #define NS_CONTAINER_FRAME_OVERFLOW_CONTAINERS_LIST_INDEX        1
@@ -877,38 +857,38 @@ nsContainerFrame::ReflowOverflowContaine
                                                   PRUint32                 aFlags,
                                                   nsReflowStatus&          aStatus)
 {
   NS_PRECONDITION(aPresContext, "null pointer");
   nsresult rv = NS_OK;
 
   nsFrameList* overflowContainers =
                GetPropTableFrames(aPresContext,
-                                  nsGkAtoms::overflowContainersProperty);
+                                  OverflowContainersProperty());
 
   NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
                  && static_cast<nsContainerFrame*>(GetPrevInFlow())
                       ->GetPropTableFrames(aPresContext,
-                          nsGkAtoms::excessOverflowContainersProperty)),
+                          ExcessOverflowContainersProperty())),
                "conflicting overflow containers lists");
 
   if (!overflowContainers) {
     // Drain excess from previnflow
     nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
     if (prev) {
       nsFrameList* excessFrames =
         prev->RemovePropTableFrames(aPresContext,
-                nsGkAtoms::excessOverflowContainersProperty);
+                                    ExcessOverflowContainersProperty());
       if (excessFrames) {
         excessFrames->ApplySetParent(this);
         nsHTMLContainerFrame::ReparentFrameViewList(aPresContext, *excessFrames,
                                                     prev, this);
         overflowContainers = excessFrames;
         rv = SetPropTableFrames(aPresContext, overflowContainers,
-                                nsGkAtoms::overflowContainersProperty);
+                                OverflowContainersProperty());
         if (NS_FAILED(rv)) {
           excessFrames->DestroyFrames();
           delete excessFrames;
           return rv;
         }
       }
     }
   }
@@ -1012,18 +992,18 @@ nsContainerFrame::ReflowOverflowContaine
   return NS_OK;
 }
 
 void
 nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder*   aBuilder,
                                             const nsRect&           aDirtyRect,
                                             const nsDisplayListSet& aLists)
 {
-  nsFrameList* overflowconts = GetPropTableFrames(PresContext(),
-                                 nsGkAtoms::overflowContainersProperty);
+  nsFrameList* overflowconts =
+    GetPropTableFrames(PresContext(), OverflowContainersProperty());
   if (overflowconts) {
     for (nsIFrame* frame = overflowconts->FirstChild(); frame;
          frame = frame->GetNextSibling()) {
       BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
     }
   }
 }
 
@@ -1032,20 +1012,20 @@ nsContainerFrame::StealFrame(nsPresConte
                              nsIFrame*      aChild,
                              PRBool         aForceNormal)
 {
   PRBool removed = PR_TRUE;
   if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
       && !aForceNormal) {
     // Try removing from the overflow container list
     if (!RemovePropTableFrame(aPresContext, aChild,
-                              nsGkAtoms::overflowContainersProperty)) {
+                              OverflowContainersProperty())) {
       // It must be in the excess overflow container list
       removed = RemovePropTableFrame(aPresContext, aChild,
-                  nsGkAtoms::excessOverflowContainersProperty);
+                                     ExcessOverflowContainersProperty());
     }
   }
   else {
     if (!mFrames.RemoveFrameIfPresent(aChild)) {
       removed = PR_FALSE;
       // We didn't find the child in the parent's principal child list.
       // Maybe it's on the overflow list?
       nsFrameList* frameList = GetOverflowFrames();
@@ -1099,17 +1079,17 @@ nsContainerFrame::StealFramesAfter(nsIFr
   return nsFrameList::EmptyList();
 }
 
 void
 nsContainerFrame::DestroyOverflowList(nsPresContext* aPresContext,
                                       nsIFrame*      aDestructRoot)
 {
   nsFrameList* list =
-    RemovePropTableFrames(aPresContext, nsGkAtoms::overflowProperty);
+    RemovePropTableFrames(aPresContext, OverflowProperty());
   if (list)
     list->DestroyFrom(aDestructRoot);
 }
 
 /**
  * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
  * pointers
  */
@@ -1151,112 +1131,87 @@ nsContainerFrame::DeleteNextInFlowChild(
 
   // Delete the next-in-flow frame and its descendants. This will also
   // remove it from its next-in-flow/prev-in-flow chain.
   aNextInFlow->Destroy();
 
   NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
 }
 
-// Destructor function for the proptable-stored framelists
-static void
-DestroyFrameList(void*           aFrame,
-                 nsIAtom*        aPropertyName,
-                 void*           aPropertyValue,
-                 void*           aDtorData)
-{
-  if (aPropertyValue)
-    static_cast<nsFrameList*>(aPropertyValue)->Destroy();
-}
-
 /**
  * Set the frames on the overflow list
  */
 nsresult
 nsContainerFrame::SetOverflowFrames(nsPresContext* aPresContext,
                                     const nsFrameList& aOverflowFrames)
 {
   NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
   nsFrameList* newList = new nsFrameList(aOverflowFrames);
   if (!newList) {
     // XXXbz should really destroy the frames here, but callers are holding
     // pointers to them.... We should switch all callers to framelists, then
     // audit and do that.
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  nsresult rv =
-    aPresContext->PropertyTable()->SetProperty(this,
-                                               nsGkAtoms::overflowProperty,
-                                               newList,
-                                               DestroyFrameList,
-                                               nsnull);
-  if (NS_FAILED(rv)) {
-    newList->Destroy();
-  }
+  aPresContext->PropertyTable()->Set(this, OverflowProperty(), newList);
+  return NS_OK;
+}
 
-  // Verify that we didn't overwrite an existing overflow list
-  NS_ASSERTION(rv != NS_PROPTABLE_PROP_OVERWRITTEN, "existing overflow list");
-
-  return rv;
+nsFrameList*
+nsContainerFrame::GetPropTableFrames(nsPresContext*                 aPresContext,
+                                     const FramePropertyDescriptor* aProperty) const
+{
+  FramePropertyTable* propTable = aPresContext->PropertyTable();
+  return static_cast<nsFrameList*>(propTable->Get(this, aProperty));
 }
 
 nsFrameList*
-nsContainerFrame::GetPropTableFrames(nsPresContext*  aPresContext,
-                                     nsIAtom*        aPropID) const
+nsContainerFrame::RemovePropTableFrames(nsPresContext*                 aPresContext,
+                                        const FramePropertyDescriptor* aProperty)
 {
-  nsPropertyTable* propTable = aPresContext->PropertyTable();
-  return static_cast<nsFrameList*>(propTable->GetProperty(this, aPropID));
-}
-
-nsFrameList*
-nsContainerFrame::RemovePropTableFrames(nsPresContext*  aPresContext,
-                                        nsIAtom*        aPropID) const
-{
-  nsPropertyTable* propTable = aPresContext->PropertyTable();
-  return static_cast<nsFrameList*>(propTable->UnsetProperty(this, aPropID));
+  FramePropertyTable* propTable = aPresContext->PropertyTable();
+  return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
 }
 
 PRBool
-nsContainerFrame::RemovePropTableFrame(nsPresContext*  aPresContext,
-                                       nsIFrame*       aFrame,
-                                       nsIAtom*        aPropID) const
+nsContainerFrame::RemovePropTableFrame(nsPresContext*                 aPresContext,
+                                       nsIFrame*                      aFrame,
+                                       const FramePropertyDescriptor* aProperty)
 {
-  nsFrameList* frameList = RemovePropTableFrames(aPresContext, aPropID);
+  nsFrameList* frameList = RemovePropTableFrames(aPresContext, aProperty);
   if (!frameList) {
     // No such list
     return PR_FALSE;
   }
   if (!frameList->RemoveFrameIfPresent(aFrame)) {
     // Found list, but it doesn't have the frame. Put list back.
-    SetPropTableFrames(aPresContext, frameList, aPropID);
+    SetPropTableFrames(aPresContext, frameList, aProperty);
     return PR_FALSE;
   }
 
   if (frameList->IsEmpty()) {
     // Removed frame and now list is empty. Delete it.
     delete frameList;
   }
   else {
     // Removed frame, but list not empty. Put it back.
-    SetPropTableFrames(aPresContext, frameList, aPropID);
+    SetPropTableFrames(aPresContext, frameList, aProperty);
   }
   return PR_TRUE;
 }
 
 nsresult
-nsContainerFrame::SetPropTableFrames(nsPresContext*  aPresContext,
-                                     nsFrameList*    aFrameList,
-                                     nsIAtom*        aPropID) const
+nsContainerFrame::SetPropTableFrames(nsPresContext*                 aPresContext,
+                                     nsFrameList*                   aFrameList,
+                                     const FramePropertyDescriptor* aProperty)
 {
-  NS_PRECONDITION(aPresContext && aPropID && aFrameList, "null ptr");
-  nsresult rv = aPresContext->PropertyTable()->SetProperty(this, aPropID,
-                  aFrameList, DestroyFrameList, nsnull);
-  NS_ASSERTION(rv != NS_PROPTABLE_PROP_OVERWRITTEN, "existing framelist");
-  return rv;
+  NS_PRECONDITION(aPresContext && aProperty && aFrameList, "null ptr");
+  aPresContext->PropertyTable()->Set(this, aProperty, aFrameList);
+  return NS_OK;
 }
 
 /**
  * Push aFromChild and its next siblings to the next-in-flow. Change the
  * geometric parent of each frame that's pushed. If there is no next-in-flow
  * the frames are placed on the overflow list (and the geometric parent is
  * left unchanged).
  *
@@ -1351,28 +1306,26 @@ nsOverflowContinuationTracker::nsOverflo
     mParent(aFrame),
     mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
     mWalkOOFFrames(aWalkOOFFrames)
 {
   NS_PRECONDITION(aFrame, "null frame pointer");
   nsContainerFrame* next = static_cast<nsContainerFrame*>
                              (aFrame->GetNextInFlow());
   if (next) {
-    mOverflowContList =
-      next->GetPropTableFrames(aPresContext,
-                               nsGkAtoms::overflowContainersProperty);
+    mOverflowContList = next->GetPropTableFrames(aPresContext,
+      nsContainerFrame::OverflowContainersProperty());
     if (mOverflowContList) {
       mParent = next;
       SetUpListWalker();
     }
   }
   if (!mOverflowContList) {
-    mOverflowContList =
-      mParent->GetPropTableFrames(aPresContext,
-                                  nsGkAtoms::excessOverflowContainersProperty);
+    mOverflowContList = mParent->GetPropTableFrames(aPresContext,
+      nsContainerFrame::ExcessOverflowContainersProperty());
     if (mOverflowContList) {
       SetUpListWalker();
     }
   }
 }
 
 /**
  * Helper function to walk past overflow continuations whose prev-in-flow
@@ -1464,18 +1417,18 @@ nsOverflowContinuationTracker::Insert(ns
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
       aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
       convertedToOverflowContainer = PR_TRUE;
     }
     if (!mOverflowContList) {
       mOverflowContList = new nsFrameList();
-      rv = mParent->SetPropTableFrames(presContext,
-             mOverflowContList, nsGkAtoms::excessOverflowContainersProperty);
+      rv = mParent->SetPropTableFrames(presContext, mOverflowContList,
+        nsContainerFrame::ExcessOverflowContainersProperty());
       NS_ENSURE_SUCCESS(rv, rv);
       SetUpListWalker();
     }
     if (aOverflowCont->GetParent() != mParent) {
       nsHTMLContainerFrame::ReparentFrameView(presContext, aOverflowCont,
                                               aOverflowCont->GetParent(),
                                               mParent);
     }
@@ -1563,21 +1516,21 @@ nsContainerFrame::List(FILE* out, PRInt3
     fprintf(out, " next=%p", static_cast<void*>(GetNextSibling()));
   }
   if (nsnull != GetPrevContinuation()) {
     fprintf(out, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
   }
   if (nsnull != GetNextContinuation()) {
     fprintf(out, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
   }
-  void* IBsibling = GetProperty(nsGkAtoms::IBSplitSpecialSibling);
+  void* IBsibling = Properties().Get(IBSplitSpecialSibling());
   if (IBsibling) {
     fprintf(out, " IBSplitSpecialSibling=%p", IBsibling);
   }
-  void* IBprevsibling = GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling);
+  void* IBprevsibling = Properties().Get(IBSplitSpecialPrevSibling());
   if (IBprevsibling) {
     fprintf(out, " IBSplitSpecialPrevSibling=%p", IBprevsibling);
   }
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
   if (0 != mState) {
     fprintf(out, " [state=%08x]", mState);
   }
   fprintf(out, " [content=%p]", static_cast<void*>(mContent));
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -322,16 +322,28 @@ public:
    * paint the background/borders/outline of this frame. This should
    * probably be avoided and eventually removed. It's currently here
    * to emulate what nsContainerFrame::Paint did.
    */
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists);
 
+  // Destructor function for the proptable-stored framelists
+  static void DestroyFrameList(void* aPropertyValue)
+  {
+    if (aPropertyValue) {
+      static_cast<nsFrameList*>(aPropertyValue)->Destroy();
+    }
+  }
+
+  NS_DECLARE_FRAME_PROPERTY(OverflowProperty, DestroyFrameList)
+  NS_DECLARE_FRAME_PROPERTY(OverflowContainersProperty, DestroyFrameList)
+  NS_DECLARE_FRAME_PROPERTY(ExcessOverflowContainersProperty, DestroyFrameList)
+
 protected:
   nsContainerFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
   ~nsContainerFrame();
 
   /**
    * Builds a display list for non-block children that behave like
    * inlines. This puts the background of each child into the
    * Content() list (suitable for inline children but not for
@@ -417,44 +429,43 @@ protected:
    * Convenience methods for nsFrameLists stored in the
    * PresContext's proptable
    */
 
   /**
    * Get the PresContext-stored nsFrameList named aPropID for this frame.
    * May return null.
    */
-  nsFrameList* GetPropTableFrames(nsPresContext*  aPresContext,
-                                  nsIAtom*        aPropID) const;
+  nsFrameList* GetPropTableFrames(nsPresContext*                 aPresContext,
+                                  const FramePropertyDescriptor* aProperty) const;
 
   /**
    * Remove and return the PresContext-stored nsFrameList named aPropID for
    * this frame. May return null.
    */
-  nsFrameList* RemovePropTableFrames(nsPresContext*  aPresContext,
-                                     nsIAtom*        aPropID) const;
+  nsFrameList* RemovePropTableFrames(nsPresContext*                 aPresContext,
+                                     const FramePropertyDescriptor* aProperty);
 
   /**
    * Remove aFrame from the PresContext-stored nsFrameList named aPropID
    * for this frame, deleting the list if it is now empty.
    * Return true if the aFrame was successfully removed,
    * Return false otherwise.
    */
-
-  PRBool RemovePropTableFrame(nsPresContext*  aPresContext,
-                              nsIFrame*       aFrame,
-                              nsIAtom*        aPropID) const;
+  PRBool RemovePropTableFrame(nsPresContext*                 aPresContext,
+                              nsIFrame*                      aFrame,
+                              const FramePropertyDescriptor* aProperty);
 
   /**
    * Set the PresContext-stored nsFrameList named aPropID for this frame
    * to the given aFrameList, which must not be null.
    */
-  nsresult SetPropTableFrames(nsPresContext*  aPresContext,
-                              nsFrameList*    aFrameList,
-                              nsIAtom*        aPropID) const;
+  nsresult SetPropTableFrames(nsPresContext*                 aPresContext,
+                              nsFrameList*                   aFrameList,
+                              const FramePropertyDescriptor* aProperty);
   // ==========================================================================
 
   nsFrameList mFrames;
 };
 
 // ==========================================================================
 /* The out-of-flow-related code below is for a hacky way of splitting
  * absolutely-positioned frames. Basically what we do is split the frame
@@ -594,24 +605,24 @@ private:
   PRBool mWalkOOFFrames;
 };
 
 inline
 nsFrameList*
 nsContainerFrame::GetOverflowFrames() const
 {
   nsFrameList* list =
-    static_cast<nsFrameList*>(GetProperty(nsGkAtoms::overflowProperty));
+    static_cast<nsFrameList*>(Properties().Get(OverflowProperty()));
   NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
   return list;
 }
 
 inline
 nsFrameList*
 nsContainerFrame::StealOverflowFrames()
 {
   nsFrameList* list =
-    static_cast<nsFrameList*>(UnsetProperty(nsGkAtoms::overflowProperty));
+    static_cast<nsFrameList*>(Properties().Remove(OverflowProperty()));
   NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
   return list;
 }
 
 #endif /* nsContainerFrame_h___ */
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -41,16 +41,18 @@
 #include "nsFloatManager.h"
 #include "nsIPresShell.h"
 #include "nsMemory.h"
 #include "nsHTMLReflowState.h"
 #include "nsHashSets.h"
 #include "nsBlockDebugFlags.h"
 #include "nsContentErrors.h"
 
+using namespace mozilla;
+
 PRInt32 nsFloatManager::sCachedFloatManagerCount = 0;
 void* nsFloatManager::sCachedFloatManagers[NS_FLOAT_MANAGER_CACHE_SIZE];
 
 /////////////////////////////////////////////////////////////////////////////
 
 // PresShell Arena allocate callback (for nsIntervalSet use below)
 static void*
 PSArenaAllocCB(size_t aSize, void* aClosure)
@@ -312,58 +314,46 @@ nsFloatManager::CalculateRegionFor(nsIFr
     region.width = 0;
   }
   if (region.height < 0) {
     region.height = 0;
   }
   return region;
 }
 
+NS_DECLARE_FRAME_PROPERTY(FloatRegionProperty, nsIFrame::DestroyMargin)
+
 nsRect
 nsFloatManager::GetRegionFor(nsIFrame* aFloat)
 {
   nsRect region = aFloat->GetRect();
-  void* storedRegion = aFloat->GetProperty(nsGkAtoms::floatRegionProperty);
+  void* storedRegion = aFloat->Properties().Get(FloatRegionProperty());
   if (storedRegion) {
     nsMargin margin = *static_cast<nsMargin*>(storedRegion);
     region.Inflate(margin);
   }
   return region;
 }
 
-static void
-DestroyMarginFunc(void*    aFrame,
-                  nsIAtom* aPropertyName,
-                  void*    aPropertyValue,
-                  void*    aDtorData)
-{
-  delete static_cast<nsMargin*>(aPropertyValue);
-}
-
 nsresult
 nsFloatManager::StoreRegionFor(nsIFrame* aFloat,
                                nsRect&   aRegion)
 {
   nsresult rv = NS_OK;
   nsRect rect = aFloat->GetRect();
+  FrameProperties props = aFloat->Properties();
   if (aRegion == rect) {
-    rv = aFloat->DeleteProperty(nsGkAtoms::floatRegionProperty);
-    if (rv == NS_PROPTABLE_PROP_NOT_THERE) rv = NS_OK;
+    props.Delete(FloatRegionProperty());
   }
   else {
-    nsMargin* storedMargin = static_cast<nsMargin*>(aFloat
-                               ->GetProperty(nsGkAtoms::floatRegionProperty));
+    nsMargin* storedMargin = static_cast<nsMargin*>
+      (props.Get(FloatRegionProperty()));
     if (!storedMargin) {
       storedMargin = new nsMargin();
-      rv = aFloat->SetProperty(nsGkAtoms::floatRegionProperty, storedMargin,
-                               DestroyMarginFunc);
-      if (NS_FAILED(rv)) {
-        delete storedMargin;
-        return rv;
-      }
+      props.Set(FloatRegionProperty(), storedMargin);
     }
     *storedMargin = aRegion - rect;
   }
   return rv;
 }
 
 nsresult
 nsFloatManager::RemoveTrailingRegions(nsIFrame* aFrameList)
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -123,16 +123,18 @@
 #include "nsIObjectLoadingContent.h"
 #ifdef MOZ_SVG
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGEffects.h"
 #endif
 
 #include "gfxContext.h"
 
+using namespace mozilla;
+
 static NS_DEFINE_CID(kLookAndFeelCID,  NS_LOOKANDFEEL_CID);
 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
 
 // Struct containing cached metrics for box-wrapped frames.
 struct nsBoxLayoutMetrics
 {
   nsSize mPrefSize;
   nsSize mMinSize;
@@ -529,47 +531,42 @@ nsFrame::DidSetStyleContext(nsStyleConte
       }
     }
 
     // If we detect a change on margin, padding or border, we store the old
     // values on the frame itself between now and reflow, so if someone
     // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
     // can give an accurate answer.
     // We don't want to set the property if one already exists.
+    FrameProperties props = Properties();
     nsMargin oldValue(0, 0, 0, 0);
     nsMargin newValue(0, 0, 0, 0);
     const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin();
     if (oldMargin && oldMargin->GetMargin(oldValue)) {
       if ((!GetStyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
-          !GetProperty(nsGkAtoms::usedMarginProperty)) {
-        SetProperty(nsGkAtoms::usedMarginProperty,
-                    new nsMargin(oldValue),
-                    nsCSSOffsetState::DestroyMarginFunc);
+          !props.Get(UsedMarginProperty())) {
+        props.Set(UsedMarginProperty(), new nsMargin(oldValue));
       }
     }
 
     const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding();
     if (oldPadding && oldPadding->GetPadding(oldValue)) {
       if ((!GetStylePadding()->GetPadding(newValue) || oldValue != newValue) &&
-          !GetProperty(nsGkAtoms::usedPaddingProperty)) {
-        SetProperty(nsGkAtoms::usedPaddingProperty,
-                    new nsMargin(oldValue),
-                    nsCSSOffsetState::DestroyMarginFunc);
+          !props.Get(UsedPaddingProperty())) {
+        props.Set(UsedPaddingProperty(), new nsMargin(oldValue));
       }
     }
 
     const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder();
     if (oldBorder) {
       oldValue = oldBorder->GetActualBorder();
       newValue = GetStyleBorder()->GetActualBorder();
       if (oldValue != newValue &&
-          !GetProperty(nsGkAtoms::usedBorderProperty)) {
-        SetProperty(nsGkAtoms::usedBorderProperty,
-                    new nsMargin(oldValue),
-                    nsCSSOffsetState::DestroyMarginFunc);
+          !props.Get(UsedBorderProperty())) {
+        props.Set(UsedBorderProperty(), new nsMargin(oldValue));
       }
     }
   }
 
   imgIRequest *oldBorderImage = aOldStyleContext
     ? aOldStyleContext->GetStyleBorder()->GetBorderImage()
     : nsnull;
   // For border-images, we can't be as conservative (we need to set the
@@ -603,17 +600,17 @@ nsFrame::DidSetStyleContext(nsStyleConte
 nsIFrame::GetUsedMargin() const
 {
   nsMargin margin(0, 0, 0, 0);
   if ((mState & NS_FRAME_FIRST_REFLOW) &&
       !(mState & NS_FRAME_IN_REFLOW))
     return margin;
 
   nsMargin *m = static_cast<nsMargin*>
-                           (GetProperty(nsGkAtoms::usedMarginProperty));
+                           (Properties().Get(UsedMarginProperty()));
   if (m) {
     margin = *m;
   } else {
 #ifdef DEBUG
     PRBool hasMargin = 
 #endif
     GetStyleMargin()->GetMargin(margin);
     NS_ASSERTION(hasMargin, "We should have a margin here! (out of memory?)");
@@ -642,17 +639,17 @@ nsIFrame::GetUsedBorder() const
     border.left = presContext->DevPixelsToAppUnits(result.left);
     border.top = presContext->DevPixelsToAppUnits(result.top);
     border.right = presContext->DevPixelsToAppUnits(result.right);
     border.bottom = presContext->DevPixelsToAppUnits(result.bottom);
     return border;
   }
 
   nsMargin *b = static_cast<nsMargin*>
-                           (GetProperty(nsGkAtoms::usedBorderProperty));
+                           (Properties().Get(UsedBorderProperty()));
   if (b) {
     border = *b;
   } else {
     border = GetStyleBorder()->GetActualBorder();
   }
   return border;
 }
 
@@ -679,17 +676,17 @@ nsIFrame::GetUsedPadding() const
       padding.right = presContext->DevPixelsToAppUnits(widget.right);
       padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
       padding.left = presContext->DevPixelsToAppUnits(widget.left);
       return padding;
     }
   }
 
   nsMargin *p = static_cast<nsMargin*>
-                           (GetProperty(nsGkAtoms::usedPaddingProperty));
+                           (Properties().Get(UsedPaddingProperty()));
   if (p) {
     padding = *p;
   } else {
 #ifdef DEBUG
     PRBool hasPadding = 
 #endif
     GetStylePadding()->GetPadding(padding);
     NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)");
@@ -1469,17 +1466,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
     // Make sure that any attempt to use childType below is disappointed. We
     // could call GetType again but since we don't currently need it, let's
     // avoid the virtual call.
     childType = nsnull;
     // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
     if (aChild->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
       return NS_OK;
     nsRect* savedDirty = static_cast<nsRect*>
-                                    (aChild->GetProperty(nsGkAtoms::outOfFlowDirtyRectProperty));
+      (aChild->Properties().Get(nsDisplayListBuilder::OutOfFlowDirtyRectProperty()));
     if (savedDirty) {
       dirty = *savedDirty;
     } else {
       // The out-of-flow frame did not intersect the dirty area. We may still
       // need to traverse into it, since it may contain placeholders we need
       // to enter to reach other out-of-flow frames that are visible.
       dirty.Empty();
     }
@@ -3452,29 +3449,28 @@ nsIFrame* nsIFrame::GetTailContinuation(
        next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
        next = frame->GetNextContinuation())  {
     frame = next;
   }
   NS_POSTCONDITION(frame, "illegal state in continuation chain.");
   return frame;
 }
 
+NS_DECLARE_FRAME_PROPERTY(ViewProperty, nsnull)
+
 // Associated view object
 nsIView*
 nsIFrame::GetView() const
 {
   // Check the frame state bit and see if the frame has a view
   if (!(GetStateBits() & NS_FRAME_HAS_VIEW))
     return nsnull;
 
   // Check for a property on the frame
-  nsresult rv;
-  void *value = GetProperty(nsGkAtoms::viewProperty, &rv);
-
-  NS_ENSURE_SUCCESS(rv, nsnull);
+  void* value = Properties().Get(ViewProperty());
   NS_ASSERTION(value, "frame state bit was set but frame has no view");
   return static_cast<nsIView*>(value);
 }
 
 /* virtual */ nsIView*
 nsIFrame::GetViewExternal() const
 {
   return GetView();
@@ -3482,18 +3478,17 @@ nsIFrame::GetViewExternal() const
 
 nsresult
 nsIFrame::SetView(nsIView* aView)
 {
   if (aView) {
     aView->SetClientData(this);
 
     // Set a property on the frame
-    nsresult rv = SetProperty(nsGkAtoms::viewProperty, aView, nsnull);
-    NS_ENSURE_SUCCESS(rv, rv);
+    Properties().Set(ViewProperty(), aView);
 
     // Set the frame state bit that says the frame has a view
     AddStateBits(NS_FRAME_HAS_VIEW);
 
     // Let all of the ancestors know they have a descendant with a view.
     for (nsIFrame* f = GetParent();
          f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
          f = f->GetParent())
@@ -3838,34 +3833,16 @@ nsIFrame::InvalidateRoot(const nsRect& a
 {
   PRUint32 flags =
     (aFlags & INVALIDATE_IMMEDIATE) ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC;
   nsIView* view = GetView();
   NS_ASSERTION(view, "This can only be called on frames with views");
   view->GetViewManager()->UpdateView(view, aDamageRect, flags);
 }
 
-static void
-DestroyRectFunc(void*    aFrame,
-                nsIAtom* aPropertyName,
-                void*    aPropertyValue,
-                void*    aDtorData)
-{
-  delete static_cast<nsRect*>(aPropertyValue);
-}
-
-static void
-SetRectProperty(nsIFrame* aFrame, nsIAtom* aProp, const nsRect& aRect)
-{
-  nsRect* r = new nsRect(aRect);
-  if (!r)
-    return;
-  aFrame->SetProperty(aProp, r, DestroyRectFunc);
-}
-
 /**
  * @param aAnyOutlineOrEffects set to true if this frame has any
  * outline, SVG effects or box shadows that mean we need to invalidate
  * the whole overflow area if the frame's size changes.
  */
 static nsRect
 ComputeOutlineAndEffectsRect(nsIFrame* aFrame, PRBool* aAnyOutlineOrEffects,
                              const nsRect& aOverflowRect,
@@ -3902,17 +3879,18 @@ ComputeOutlineAndEffectsRect(nsIFrame* a
     nscoord width;
 #ifdef DEBUG
     PRBool result = 
 #endif
       outline->GetOutlineWidth(width);
     NS_ASSERTION(result, "GetOutlineWidth had no cached outline width");
     if (width > 0) {
       if (aStoreRectProperties) {
-        SetRectProperty(aFrame, nsGkAtoms::outlineInnerRectProperty, r);
+        aFrame->Properties().
+          Set(nsIFrame::OutlineInnerRectProperty(), new nsRect(r));
       }
 
       nscoord offset = outline->mOutlineOffset;
       nscoord inflateBy = NS_MAX(width + offset, 0);
       r.Inflate(inflateBy, inflateBy);
       *aAnyOutlineOrEffects = PR_TRUE;
     }
   }
@@ -3923,31 +3901,32 @@ ComputeOutlineAndEffectsRect(nsIFrame* a
   // or something like that. It's not worth doing that here. At most it's
   // only one heap-allocated rect per frame and it will be cleaned up when
   // the frame dies.
 
 #ifdef MOZ_SVG
   if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
     *aAnyOutlineOrEffects = PR_TRUE;
     if (aStoreRectProperties) {
-      SetRectProperty(aFrame, nsGkAtoms::preEffectsBBoxProperty, r);
+      aFrame->Properties().
+        Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
     }
     r = nsSVGIntegrationUtils::ComputeFrameEffectsRect(aFrame, r);
   }
 #endif
 
   return r;
 }
 
 nsPoint
 nsIFrame::GetRelativeOffset(const nsStyleDisplay* aDisplay) const
 {
   if (!aDisplay || NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) {
     nsPoint *offsets = static_cast<nsPoint*>
-                         (GetProperty(nsGkAtoms::computedOffsetProperty));
+      (Properties().Get(ComputedOffsetProperty()));
     if (offsets) {
       return *offsets;
     }
   }
   return nsPoint(0,0);
 }
 
 nsRect
@@ -3985,17 +3964,17 @@ nsIFrame::GetOverflowRectRelativeToParen
   
 nsRect
 nsIFrame::GetOverflowRectRelativeToSelf() const
 {
   if (!(mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) ||
       !GetStyleDisplay()->HasTransform())
     return GetOverflowRect();
   nsRect* preEffectsBBox = static_cast<nsRect*>
-    (GetProperty(nsGkAtoms::preEffectsBBoxProperty));
+    (Properties().Get(PreEffectsBBoxProperty()));
   if (!preEffectsBBox)
     return GetOverflowRect();
   return *preEffectsBBox;
 }
 
 void
 nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize)
 {
@@ -5530,41 +5509,48 @@ nsFrame::ChildIsDirty(nsIFrame* aChild)
 #ifdef ACCESSIBILITY
 NS_IMETHODIMP
 nsFrame::GetAccessible(nsIAccessible** aAccessible)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 #endif
 
+NS_DECLARE_FRAME_PROPERTY(OverflowAreaProperty, nsIFrame::DestroyRect)
+
+void
+nsIFrame::ClearOverflowRect()
+{
+  Properties().Delete(OverflowAreaProperty());
+  mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
+}
+
 /** Create or retrieve the previously stored overflow area, if the frame does 
  * not overflow and no creation is required return nsnull.
  * @param aCreateIfNecessary  create a new nsRect for the overflow area
  * @return pointer to the overflow area rectangle 
  */
 nsRect*
 nsIFrame::GetOverflowAreaProperty(PRBool aCreateIfNecessary) 
 {
   if (!((mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) ||
         aCreateIfNecessary)) {
     return nsnull;
   }
 
-  nsPropertyTable *propTable = PresContext()->PropertyTable();
-  void *value = propTable->GetProperty(this,
-                                       nsGkAtoms::overflowAreaProperty);
+  FrameProperties props = Properties();
+  void *value = props.Get(OverflowAreaProperty());
 
   if (value) {
     return (nsRect*)value;  // the property already exists
   } else if (aCreateIfNecessary) {
     // The property isn't set yet, so allocate a new rect, set the property,
     // and return the newly allocated rect
     nsRect*  overflow = new nsRect(0, 0, 0, 0);
-    propTable->SetProperty(this, nsGkAtoms::overflowAreaProperty,
-                           overflow, DestroyRectFunc, nsnull);
+    props.Set(OverflowAreaProperty(), overflow);
     return overflow;
   }
 
   NS_NOTREACHED("Frame abuses GetOverflowAreaProperty()");
   return nsnull;
 }
 
 /** Set the overflowArea rect, storing it as deltas or a separate rect
@@ -5582,17 +5568,17 @@ nsIFrame::SetOverflowRect(const nsRect& 
       r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
       b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
       (l | t | r | b) != 0) {
     // It's a "small" overflow area so we store the deltas for each edge
     // directly in the frame, rather than allocating a separate rect.
     // Note that we do NOT store in this way if *all* the deltas are zero,
     // as that would be indistinguishable from the complete absence of
     // an overflow rect.
-    DeleteProperty(nsGkAtoms::overflowAreaProperty);
+    Properties().Delete(OverflowAreaProperty());
     mOverflow.mDeltas.mLeft   = l;
     mOverflow.mDeltas.mTop    = t;
     mOverflow.mDeltas.mRight  = r;
     mOverflow.mDeltas.mBottom = b;
   } else {
     // it's a large overflow area that we need to store as a property
     mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
     nsRect* overflowArea = GetOverflowAreaProperty(PR_TRUE); 
@@ -5673,19 +5659,16 @@ nsIFrame::FinishAndStoreOverflow(nsRect*
 
   PRBool hasOutlineOrEffects;
   *aOverflowArea = GetAdditionalOverflow(*aOverflowArea, aNewSize,
       &hasOutlineOrEffects);
 
   /* If we're transformed, transform the overflow rect by the current transformation. */
   if ((mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) && 
       GetStyleDisplay()->HasTransform()) {
-    // Save overflow area before the transform
-    SetRectProperty(this, nsGkAtoms::preTransformBBoxProperty, *aOverflowArea);
-
     /* Since our size might not actually have been computed yet, we need to make sure that we use the
      * correct dimensions by overriding the stored bounding rectangle with the value the caller has
      * ensured us we'll use.
      */
     nsRect newBounds(nsPoint(0, 0), aNewSize);
     *aOverflowArea = nsDisplayTransform::TransformRect(*aOverflowArea, this, nsPoint(0, 0), &newBounds);
   }
 
@@ -5768,18 +5751,18 @@ GetIBSpecialSiblingForAnonymousBlock(nsI
   // Find the first continuation of the frame.  (Ugh.  This ends up
   // being O(N^2) when it is called O(N) times.)
   aFrame = aFrame->GetFirstContinuation();
 
   /*
    * Now look up the nsGkAtoms::IBSplitSpecialPrevSibling
    * property.
    */
-  nsIFrame *specialSibling =
-    static_cast<nsIFrame*>(aFrame->GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling));
+  nsIFrame *specialSibling = static_cast<nsIFrame*>
+    (aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()));
   NS_ASSERTION(specialSibling, "Broken frame tree?");
   return specialSibling;
 }
 
 /**
  * Get the parent, corrected for the mangled frame tree resulting from
  * having a block within an inline.  The result only differs from the
  * result of |GetParent| when |GetParent| returns an anonymous block
@@ -5963,52 +5946,16 @@ nsFrame::GetFirstLeaf(nsPresContext* aPr
   while (1){
     child = child->GetFirstChild(nsnull);
     if (!child)
       return;//nothing to do
     *aFrame = child;
   }
 }
 
-nsresult
-nsIFrame::SetProperty(nsIAtom*           aPropName,
-                      void*              aPropValue,
-                      NSPropertyDtorFunc aPropDtorFunc,
-                      void*              aDtorData)
-{
-  return PresContext()->PropertyTable()->
-    SetProperty(this, aPropName, aPropValue, aPropDtorFunc, aDtorData);
-}
-
-void* 
-nsIFrame::GetProperty(nsIAtom* aPropName, nsresult* aStatus) const
-{
-  return PresContext()->PropertyTable()->GetProperty(this, aPropName,
-                                                        aStatus);
-}
-
-/* virtual */ void* 
-nsIFrame::GetPropertyExternal(nsIAtom* aPropName, nsresult* aStatus) const
-{
-  return GetProperty(aPropName, aStatus);
-}
-
-nsresult
-nsIFrame::DeleteProperty(nsIAtom* aPropName) const
-{
-  return PresContext()->PropertyTable()->DeleteProperty(this, aPropName);
-}
-
-void*
-nsIFrame::UnsetProperty(nsIAtom* aPropName, nsresult* aStatus) const
-{
-  return PresContext()->PropertyTable()->UnsetProperty(this, aPropName,
-                                                          aStatus);
-}
-
 /* virtual */ const void*
 nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
 {
   NS_ASSERTION(mStyleContext, "unexpected null pointer");
   return mStyleContext->GetStyleData(aSID);
 }
 
 /* virtual */ PRBool
@@ -6622,55 +6569,57 @@ nsFrame::BoxReflow(nsBoxLayoutState&    
 
 #ifdef DEBUG_REFLOW
   gIndent2--;
 #endif
 
   return NS_OK;
 }
 
+static void
+DestroyBoxMetrics(void* aPropertyValue)
+{
+  delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue);
+}
+
+NS_DECLARE_FRAME_PROPERTY(BoxMetricsProperty, DestroyBoxMetrics)
+
 nsBoxLayoutMetrics*
 nsFrame::BoxMetrics() const
 {
   nsBoxLayoutMetrics* metrics =
-    static_cast<nsBoxLayoutMetrics*>(GetProperty(nsGkAtoms::boxMetricsProperty));
+    static_cast<nsBoxLayoutMetrics*>(Properties().Get(BoxMetricsProperty()));
   NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
   return metrics;
 }
 
 NS_IMETHODIMP
 nsFrame::SetParent(const nsIFrame* aParent)
 {
   PRBool wasBoxWrapped = IsBoxWrapped();
   nsIFrame::SetParent(aParent);
-  if (!wasBoxWrapped && IsBoxWrapped())
+  if (!wasBoxWrapped && IsBoxWrapped()) {
     InitBoxMetrics(PR_TRUE);
-  else if (wasBoxWrapped && !IsBoxWrapped())
-    DeleteProperty(nsGkAtoms::boxMetricsProperty);
+  } else if (wasBoxWrapped && !IsBoxWrapped()) {
+    Properties().Delete(BoxMetricsProperty());
+  }
 
   return NS_OK;
 }
 
-static void
-DeleteBoxMetrics(void    *aObject,
-                 nsIAtom *aPropertyName,
-                 void    *aPropertyValue,
-                 void    *aData)
-{
-  delete static_cast<nsBoxLayoutMetrics*>(aPropertyValue);
-}
-
 void
 nsFrame::InitBoxMetrics(PRBool aClear)
 {
-  if (aClear)
-    DeleteProperty(nsGkAtoms::boxMetricsProperty);
+  FrameProperties props = Properties();
+  if (aClear) {
+    props.Delete(BoxMetricsProperty());
+  }
 
   nsBoxLayoutMetrics *metrics = new nsBoxLayoutMetrics();
-  SetProperty(nsGkAtoms::boxMetricsProperty, metrics, DeleteBoxMetrics);
+  props.Set(BoxMetricsProperty(), metrics);
 
   nsFrame::MarkIntrinsicWidthsDirty();
   metrics->mBlockAscent = 0;
   metrics->mLastSize.SizeTo(0, 0);
 }
 
 // Box layout debugging
 #ifdef DEBUG_REFLOW
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -464,24 +464,24 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
   }
 
   if (aAssumeVScroll) {
     nsSize vScrollbarPrefSize = 
       mInner.mVScrollbarBox->GetPrefSize(const_cast<nsBoxLayoutState&>(aState->mBoxState));
     availWidth = NS_MAX(0, availWidth - vScrollbarPrefSize.width);
   }
 
+  nsPresContext* presContext = PresContext();
+
   // We're forcing the padding on our scrolled frame, so let it know what that
   // padding is.
-  mInner.mScrolledFrame->
-    SetProperty(nsGkAtoms::usedPaddingProperty,
-                new nsMargin(aState->mReflowState.mComputedPadding),
-                nsCSSOffsetState::DestroyMarginFunc);  
-  
-  nsPresContext* presContext = PresContext();
+  presContext->PropertyTable()->
+    Set(mInner.mScrolledFrame, UsedPaddingProperty(),
+        new nsMargin(aState->mReflowState.mComputedPadding));
+
   // Pass PR_FALSE for aInit so we can pass in the correct padding
   nsHTMLReflowState kidReflowState(presContext, aState->mReflowState,
                                    mInner.mScrolledFrame,
                                    nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
                                    -1, -1, PR_FALSE);
   kidReflowState.Init(presContext, -1, -1, nsnull,
                       &aState->mReflowState.mComputedPadding);
   kidReflowState.mFlags.mAssumingHScrollbar = aAssumeHScroll;
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -62,16 +62,18 @@
 #endif
 
 #ifdef NS_DEBUG
 #undef NOISY_VERTICAL_ALIGN
 #else
 #undef NOISY_VERTICAL_ALIGN
 #endif
 
+using namespace mozilla;
+
 // Prefs-driven control for |text-decoration: blink|
 static PRPackedBool sPrefIsLoaded = PR_FALSE;
 static PRPackedBool sBlinkIsAllowed = PR_TRUE;
 
 enum eNormalLineHeightControl {
   eUninitialized = -1,
   eNoExternalLeading = 0,   // does not include external leading 
   eIncludeExternalLeading,  // use whatever value font vendor provides
@@ -583,24 +585,16 @@ nsHTMLReflowState::InitFrameType()
     frameType = NS_FRAME_REPLACED_CONTAINS_BLOCK(frameType);
   } else if (frame->IsFrameOfType(nsIFrame::eReplaced)) {
     frameType = NS_FRAME_REPLACED(frameType);
   }
 
   mFrameType = frameType;
 }
 
-static void
-nsPointDtor(void *aFrame, nsIAtom *aPropertyName,
-            void *aPropertyValue, void *aDtorData)
-{
-  nsPoint *point = static_cast<nsPoint*>(aPropertyValue);
-  delete point;
-}
-
 void
 nsHTMLReflowState::ComputeRelativeOffsets(const nsHTMLReflowState* cbrs,
                                           nscoord aContainingBlockWidth,
                                           nscoord aContainingBlockHeight,
                                           nsPresContext* aPresContext)
 {
   // Compute the 'left' and 'right' values. 'Left' moves the boxes to the right,
   // and 'right' moves the boxes to the left. The computed values are always:
@@ -700,26 +694,24 @@ nsHTMLReflowState::ComputeRelativeOffset
       ComputeHeightDependentValue(aContainingBlockHeight,
                                   mStylePosition->mOffset.GetTop());
 
     // Computed value for 'bottom' is minus the value of 'top'
     mComputedOffsets.bottom = -mComputedOffsets.top;
   }
 
   // Store the offset
-  nsPropertyTable* propTable = aPresContext->PropertyTable();
+  FrameProperties props(aPresContext->PropertyTable(), frame);
   nsPoint* offsets = static_cast<nsPoint*>
-                                (propTable->GetProperty(frame, nsGkAtoms::computedOffsetProperty));
-  if (offsets)
+    (props.Get(nsIFrame::ComputedOffsetProperty()));
+  if (offsets) {
     offsets->MoveTo(mComputedOffsets.left, mComputedOffsets.top);
-  else {
-    offsets = new nsPoint(mComputedOffsets.left, mComputedOffsets.top);
-    if (offsets)
-      propTable->SetProperty(frame, nsGkAtoms::computedOffsetProperty,
-                              offsets, nsPointDtor, nsnull);
+  } else {
+    props.Set(nsIFrame::ComputedOffsetProperty(),
+              new nsPoint(mComputedOffsets.left, mComputedOffsets.top));
   }
 }
 
 nsIFrame*
 nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame,
                                                nscoord& aCBLeftEdge,
                                                nscoord& aCBWidth)
 {
@@ -1645,19 +1637,20 @@ IsSideCaption(nsIFrame* aFrame, const ns
 void
 nsHTMLReflowState::InitConstraints(nsPresContext* aPresContext,
                                    nscoord         aContainingBlockWidth,
                                    nscoord         aContainingBlockHeight,
                                    const nsMargin* aBorder,
                                    const nsMargin* aPadding)
 {
   // Since we are in reflow, we don't need to store these properties anymore
-  frame->DeleteProperty(nsGkAtoms::usedBorderProperty);
-  frame->DeleteProperty(nsGkAtoms::usedPaddingProperty);
-  frame->DeleteProperty(nsGkAtoms::usedMarginProperty);
+  FrameProperties props(aPresContext->PropertyTable(), frame);
+  props.Delete(nsIFrame::UsedBorderProperty());
+  props.Delete(nsIFrame::UsedPaddingProperty());
+  props.Delete(nsIFrame::UsedMarginProperty());
 
   // If this is the root frame, then set the computed width and
   // height equal to the available space
   if (nsnull == parentReflowState) {
     // XXXldb This doesn't mean what it used to!
     InitOffsets(aContainingBlockWidth, aBorder, aPadding);
     // Override mComputedMargin since reflow roots start from the
     // frame's boundary, which is inside the margin.
@@ -2142,26 +2135,16 @@ nsHTMLReflowState::CalcLineHeight(nsStyl
   
   nscoord lineHeight = ComputeLineHeight(aStyleContext, aBlockHeight);
 
   NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up");
 
   return lineHeight;
 }
 
-/* static */
-void
-nsCSSOffsetState::DestroyMarginFunc(void*    aFrame,
-                                    nsIAtom* aPropertyName,
-                                    void*    aPropertyValue,
-                                    void*    aDtorData)
-{
-  delete static_cast<nsMargin*>(aPropertyValue);
-}
-
 void
 nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth)
 {
   // If style style can provide us the margin directly, then use it.
   const nsStyleMargin *styleMargin = frame->GetStyleMargin();
   if (!styleMargin->GetMargin(mComputedMargin)) {
     // We have to compute the value
     if (NS_UNCONSTRAINEDSIZE == aContainingBlockWidth) {
@@ -2194,19 +2177,18 @@ nsCSSOffsetState::ComputeMargin(nscoord 
     mComputedMargin.bottom = nsLayoutUtils::
       ComputeWidthDependentValue(aContainingBlockWidth,
                                  styleMargin->mMargin.GetBottom());
 
     // XXX We need to include 'auto' horizontal margins in this too!
     // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
     // to use it even when the margins are all zero (since sometimes
     // they get treated as auto)
-    frame->SetProperty(nsGkAtoms::usedMarginProperty,
-                       new nsMargin(mComputedMargin),
-                       DestroyMarginFunc);
+    frame->Properties().Set(nsIFrame::UsedMarginProperty(),
+                            new nsMargin(mComputedMargin));
   }
 }
 
 void
 nsCSSOffsetState::ComputePadding(nscoord aContainingBlockWidth)
 {
   // If style can provide us the padding directly, then use it.
   const nsStylePadding *stylePadding = frame->GetStylePadding();
@@ -2223,19 +2205,18 @@ nsCSSOffsetState::ComputePadding(nscoord
     // containing block width for padding-top and padding-bottom
     mComputedPadding.top = nsLayoutUtils::
       ComputeWidthDependentValue(aContainingBlockWidth,
                                  stylePadding->mPadding.GetTop());
     mComputedPadding.bottom = nsLayoutUtils::
       ComputeWidthDependentValue(aContainingBlockWidth,
                                  stylePadding->mPadding.GetBottom());
 
-    frame->SetProperty(nsGkAtoms::usedPaddingProperty,
-                       new nsMargin(mComputedPadding),
-                       DestroyMarginFunc);
+    frame->Properties().Set(nsIFrame::UsedPaddingProperty(),
+                            new nsMargin(mComputedPadding));
   }
   // a table row/col group, row/col doesn't have padding
   // XXXldb Neither do border-collapse tables.
   nsIAtom* frameType = frame->GetType();
   if (nsGkAtoms::tableRowGroupFrame == frameType ||
       nsGkAtoms::tableColGroupFrame == frameType ||
       nsGkAtoms::tableRowFrame      == frameType ||
       nsGkAtoms::tableColFrame      == frameType) {
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -168,22 +168,16 @@ public:
   nsCSSOffsetState(nsIFrame *aFrame, nsIRenderingContext *aRenderingContext,
                    nscoord aContainingBlockWidth)
     : frame(aFrame)
     , rendContext(aRenderingContext)
   {
     InitOffsets(aContainingBlockWidth);
   }
 
-  // Destructor for usedPaddingProperty
-  static void DestroyMarginFunc(void*    aFrame,
-                                nsIAtom* aPropertyName,
-                                void*    aPropertyValue,
-                                void*    aDtorData);
-
 private:
   // Computes margin values from the specified margin style information, and
   // fills in the mComputedMargin member
   void ComputeMargin(nscoord aContainingBlockWidth);
   
   // Computes padding values from the specified padding style information, and
   // fills in the mComputedPadding member
   void ComputePadding(nscoord aContainingBlockWidth);
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -51,16 +51,17 @@
 #include "nsEvent.h"
 #include "nsStyleStruct.h"
 #include "nsStyleContext.h"
 #include "nsIContent.h"
 #include "nsHTMLReflowMetrics.h"
 #include "gfxMatrix.h"
 #include "nsFrameList.h"
 #include "nsAlgorithm.h"
+#include "FramePropertyTable.h"
 
 /**
  * New rules of reflow:
  * 1. you get a WillReflow() followed by a Reflow() followed by a DidReflow() in order
  *    (no separate pass over the tree)
  * 2. it's the parent frame's responsibility to size/position the child's view (not
  *    the child frame's responsibility as it is today) during reflow (and before
  *    sending the DidReflow() notification)
@@ -175,19 +176,16 @@ enum {
 
   // If this bit is set, this frame or one of its descendants has a
   // percentage height that depends on an ancestor of this frame.
   // (Or it did at one point in the past, since we don't necessarily clear
   // the bit when it's no longer needed; it's an optimization.)
   NS_FRAME_CONTAINS_RELATIVE_HEIGHT =           0x00000020,
 
   // If this bit is set, then the frame corresponds to generated content
-  // Such frames store an nsCOMArray<nsIContent> of their generated content
-  // in the nsGkAtoms::generatedContent frame property, except for continuation
-  // frames.
   NS_FRAME_GENERATED_CONTENT =                  0x00000040,
 
   // If this bit is set the frame is a continuation that is holding overflow,
   // i.e. it is a next-in-flow created to hold overflow after the box's
   // height has ended. This means the frame should be a) at the top of the
   // page and b) invisible: no borders, zero height, ignored in margin
   // collapsing, etc. See nsContainerFrame.h
   NS_FRAME_IS_OVERFLOW_CONTAINER =              0x00000080,
@@ -484,16 +482,19 @@ typedef PRBool nsDidReflowStatus;
  * link to many of the functions defined here. Too bad.
  *
  * If you're not in layout but you must call functions in here, at least
  * restrict yourself to calling virtual methods, which won't hurt you as badly.
  */
 class nsIFrame : public nsQueryFrame
 {
 public:
+  typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
+  typedef mozilla::FrameProperties FrameProperties;
+
   NS_DECL_QUERYFRAME_TARGET(nsIFrame)
 
   nsPresContext* PresContext() const {
     return GetStyleContext()->GetRuleNode()->GetPresContext();
   }
 
   /**
    * Called to initialize the frame. This is called immediately after creating
@@ -797,16 +798,49 @@ public:
   virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
   { return aChild->GetPosition(); }
   
   nsPoint GetPositionIgnoringScrolling() {
     return mParent ? mParent->GetPositionOfChildIgnoringScrolling(this)
       : GetPosition();
   }
 
+  static void DestroyMargin(void* aPropertyValue)
+  {
+    delete static_cast<nsMargin*>(aPropertyValue);
+  }
+
+  static void DestroyRect(void* aPropertyValue)
+  {
+    delete static_cast<nsRect*>(aPropertyValue);
+  }
+
+  static void DestroyPoint(void* aPropertyValue)
+  {
+    delete static_cast<nsPoint*>(aPropertyValue);
+  }
+
+#define NS_DECLARE_FRAME_PROPERTY(prop, dtor)                   \
+  static const FramePropertyDescriptor* prop() {                \
+    static const FramePropertyDescriptor descriptor = { dtor }; \
+    return &descriptor;                                         \
+  }
+
+  NS_DECLARE_FRAME_PROPERTY(IBSplitSpecialSibling, nsnull)
+  NS_DECLARE_FRAME_PROPERTY(IBSplitSpecialPrevSibling, nsnull)
+
+  NS_DECLARE_FRAME_PROPERTY(ComputedOffsetProperty, DestroyPoint)
+
+  NS_DECLARE_FRAME_PROPERTY(OutlineInnerRectProperty, DestroyRect)
+  NS_DECLARE_FRAME_PROPERTY(PreEffectsBBoxProperty, DestroyRect)
+
+  NS_DECLARE_FRAME_PROPERTY(UsedMarginProperty, DestroyMargin)
+  NS_DECLARE_FRAME_PROPERTY(UsedPaddingProperty, DestroyMargin)
+  NS_DECLARE_FRAME_PROPERTY(UsedBorderProperty, DestroyMargin)
+
   /**
    * Return the distance between the border edge of the frame and the
    * margin edge of the frame.  Like GetRect(), returns the dimensions
    * as of the most recent reflow.
    *
    * This doesn't include any margin collapsing that may have occurred.
    *
    * It also treats 'auto' margins as zero, and treats any margins that
@@ -1898,20 +1932,17 @@ public:
    */
   PRBool HasOverflowRect() const {
     return mOverflow.mType != NS_FRAME_OVERFLOW_NONE;
   }
 
   /**
    * Removes any stored overflow rect from the frame.
    */
-  void ClearOverflowRect() {
-    DeleteProperty(nsGkAtoms::overflowAreaProperty);
-    mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
-  }
+  void ClearOverflowRect();
 
   /**
    * Determine whether borders should not be painted on certain sides of the
    * frame.
    */
   virtual PRIntn GetSkipSides() const { return 0; }
 
   /** Selection related calls
@@ -2120,34 +2151,29 @@ public:
    *
    * @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;
   }
 
+  FrameProperties Properties() const {
+    return FrameProperties(PresContext()->PropertyTable(), this);
+  }
 
-  NS_HIDDEN_(void*) GetProperty(nsIAtom* aPropertyName,
-                                nsresult* aStatus = nsnull) const;
-  virtual NS_HIDDEN_(void*) GetPropertyExternal(nsIAtom*  aPropertyName,
-                                                nsresult* aStatus) const;
-  NS_HIDDEN_(nsresult) SetProperty(nsIAtom*           aPropertyName,
-                                   void*              aValue,
-                                   NSPropertyDtorFunc aDestructor = nsnull,
-                                   void*              aDtorData = nsnull);
-  NS_HIDDEN_(nsresult) DeleteProperty(nsIAtom* aPropertyName) const;
-  NS_HIDDEN_(void*) UnsetProperty(nsIAtom* aPropertyName,
-                                  nsresult* aStatus = nsnull) const;
+  NS_DECLARE_FRAME_PROPERTY(BaseLevelProperty, nsnull)
+  NS_DECLARE_FRAME_PROPERTY(EmbeddingLevelProperty, nsnull)
+  NS_DECLARE_FRAME_PROPERTY(CharTypeProperty, nsnull)
 
 #define NS_GET_BASE_LEVEL(frame) \
-NS_PTR_TO_INT32(frame->GetProperty(nsGkAtoms::baseLevel))
+NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::BaseLevelProperty()))
 
 #define NS_GET_EMBEDDING_LEVEL(frame) \
-NS_PTR_TO_INT32(frame->GetProperty(nsGkAtoms::embeddingLevel))
+NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::EmbeddingLevelProperty()))
 
   /**
    * Return PR_TRUE if and only if this frame obeys visibility:hidden.
    * if it does not, then nsContainerFrame will hide its view even though
    * this means children can't be made visible again.
    */
   virtual PRBool SupportsVisibilityHidden() { return PR_TRUE; }
 
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -125,16 +125,25 @@
 #undef NOISY_REFLOW
 #undef NOISY_TRIM
 #else
 #undef NOISY_BLINK
 #undef NOISY_REFLOW
 #undef NOISY_TRIM
 #endif
 
+using namespace mozilla;
+
+static void DestroyTabWidth(void* aPropertyValue)
+{
+  delete static_cast<nsTArray<gfxFloat>*>(aPropertyValue);
+}
+
+NS_DECLARE_FRAME_PROPERTY(TabWidthProperty, DestroyTabWidth)
+
 // The following flags are set during reflow
 
 // This bit is set on the first frame in a continuation indicating
 // that it was chopped short because of :first-letter style.
 #define TEXT_FIRST_LETTER    0x00100000
 // This bit is set on frames that are logically adjacent to the start of the
 // line (i.e. no prior frame on line with actual displayed in-flow content).
 #define TEXT_START_OF_LINE   0x00200000
@@ -2477,22 +2486,16 @@ PropertyProvider::GetSpacingInternal(PRU
             aSpacing[clusterLastChar - aStart].mAfter += halfJustificationSpace;
           }
         }
       }
     }
   }
 }
 
-static void TabWidthDestructor(void* aObject, nsIAtom* aProp, void* aValue,
-                               void* aData)
-{
-  delete static_cast<nsTArray<gfxFloat>*>(aValue);
-}
-
 static gfxFloat
 ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
 {
   // Get the number of spaces from CSS -moz-tab-size
   const nsStyleText* textStyle = aFrame->GetStyleText();
   
   // Round the space width when converting to appunits the same way
   // textruns do
@@ -2519,35 +2522,32 @@ AdvanceToNextTab(gfxFloat aX, nsIFrame* 
 }
 
 gfxFloat*
 PropertyProvider::GetTabWidths(PRUint32 aStart, PRUint32 aLength)
 {
   if (!mTabWidths) {
     if (!mReflowing) {
       mTabWidths = static_cast<nsTArray<gfxFloat>*>
-                              (mFrame->GetProperty(nsGkAtoms::tabWidthProperty));
+        (mFrame->Properties().Get(TabWidthProperty()));
       if (!mTabWidths) {
         NS_WARNING("We need precomputed tab widths, but they're not here...");
         return nsnull;
       }
     } else {
       if (!mLineContainer) {
         // Intrinsic width computation does its own tab processing. We
         // just don't do anything here.
         return nsnull;
       }
 
       nsAutoPtr<nsTArray<gfxFloat> > tabs(new nsTArray<gfxFloat>());
       if (!tabs)
         return nsnull;
-      nsresult rv = mFrame->SetProperty(nsGkAtoms::tabWidthProperty, tabs,
-                                        TabWidthDestructor, nsnull);
-      if (NS_FAILED(rv))
-        return nsnull;
+      mFrame->Properties().Set(TabWidthProperty(), tabs);
       mTabWidths = tabs.forget();
     }
   }
 
   PRUint32 startOffset = mStart.GetSkippedOffset();
   PRUint32 tabsEnd = startOffset + mTabWidths->Length();
   if (tabsEnd < aStart + aLength) {
     if (!mReflowing) {
@@ -3516,40 +3516,37 @@ nsContinuingTextFrame::Init(nsIContent* 
     // We're taking part of prev's text, and its style may be different
     // so clear its textrun which may no longer be valid (and don't set ours)
     prev->ClearTextRun();
   } else {
     mTextRun = prev->GetTextRun();
   }
 #ifdef IBMBIDI
   if (aPrevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) {
-    nsPropertyTable *propTable = PresContext()->PropertyTable();
-    propTable->SetProperty(this, nsGkAtoms::embeddingLevel,
-          propTable->GetProperty(aPrevInFlow, nsGkAtoms::embeddingLevel),
-                           nsnull, nsnull);
-    propTable->SetProperty(this, nsGkAtoms::baseLevel,
-              propTable->GetProperty(aPrevInFlow, nsGkAtoms::baseLevel),
-                           nsnull, nsnull);
-    propTable->SetProperty(this, nsGkAtoms::charType,
-               propTable->GetProperty(aPrevInFlow, nsGkAtoms::charType),
-                           nsnull, nsnull);
+    FramePropertyTable *propTable = PresContext()->PropertyTable();
+    // Get all the properties from the prev-in-flow first to take
+    // advantage of the propTable's cache and simplify the assertion below
+    void* embeddingLevel = propTable->Get(aPrevInFlow, EmbeddingLevelProperty());
+    void* baseLevel = propTable->Get(aPrevInFlow, BaseLevelProperty());
+    void* charType = propTable->Get(aPrevInFlow, CharTypeProperty());
+    propTable->Set(this, EmbeddingLevelProperty(), embeddingLevel);
+    propTable->Set(this, BaseLevelProperty(), baseLevel);
+    propTable->Set(this, CharTypeProperty(), charType);
+
     if (nextContinuation) {
       SetNextContinuation(nextContinuation);
       nextContinuation->SetPrevContinuation(this);
       // Adjust next-continuations' content offset as needed.
       while (nextContinuation &&
              nextContinuation->GetContentOffset() < mContentOffset) {
         NS_ASSERTION(
-          propTable->GetProperty(this, nsGkAtoms::embeddingLevel) ==
-          propTable->GetProperty(nextContinuation, nsGkAtoms::embeddingLevel) &&
-          propTable->GetProperty(this, nsGkAtoms::baseLevel) ==
-          propTable->GetProperty(nextContinuation, nsGkAtoms::baseLevel) &&
-          propTable->GetProperty(this, nsGkAtoms::charType) ==
-          propTable->GetProperty(nextContinuation, nsGkAtoms::charType),
-            "stealing text from different type of BIDI continuation");
+          embeddingLevel == propTable->Get(nextContinuation, EmbeddingLevelProperty()) &&
+          baseLevel == propTable->Get(nextContinuation, BaseLevelProperty()) &&
+          charType == propTable->Get(nextContinuation, CharTypeProperty()),
+          "stealing text from different type of BIDI continuation");
         nextContinuation->mContentOffset = mContentOffset;
         nextContinuation = static_cast<nsTextFrame*>(nextContinuation->GetNextContinuation());
       }
     }
     mState |= NS_FRAME_IS_BIDI;
   } // prev frame is bidi
 #endif // IBMBIDI
 
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -60,16 +60,18 @@
 #include "nsMathMLParts.h"
 #include "nsMathMLContainerFrame.h"
 #include "nsAutoPtr.h"
 #include "nsStyleSet.h"
 #include "nsDisplayList.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsIReflowCallback.h"
 
+using namespace mozilla;
+
 //
 // nsMathMLContainerFrame implementation
 //
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLContainerFrame)
 
 NS_QUERYFRAME_HEAD(nsMathMLContainerFrame)
   NS_QUERYFRAME_ENTRY(nsMathMLFrame)
@@ -167,44 +169,44 @@ IsForeignChild(const nsIFrame* aFrame)
 {
   // This counts nsMathMLmathBlockFrame as a foreign child, because it
   // uses block reflow
   return !(aFrame->IsFrameOfType(nsIFrame::eMathML)) ||
     aFrame->GetType() == nsGkAtoms::blockFrame;
 }
 
 static void
-DeleteHTMLReflowMetrics(void *aObject, nsIAtom *aPropertyName,
-                        void *aPropertyValue, void *aData)
+DestroyHTMLReflowMetrics(void *aPropertyValue)
 {
   delete static_cast<nsHTMLReflowMetrics*>(aPropertyValue);
 }
 
+NS_DECLARE_FRAME_PROPERTY(HTMLReflowMetricsProperty, DestroyHTMLReflowMetrics)
+
 /* static */ void
 nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame*                  aFrame,
                                                         const nsHTMLReflowMetrics& aReflowMetrics,
                                                         const nsBoundingMetrics&   aBoundingMetrics)
 {
   nsHTMLReflowMetrics *metrics = new nsHTMLReflowMetrics(aReflowMetrics);
   metrics->mBoundingMetrics = aBoundingMetrics;
-  aFrame->SetProperty(nsGkAtoms::HTMLReflowMetricsProperty, metrics,
-                      DeleteHTMLReflowMetrics);
+  aFrame->Properties().Set(HTMLReflowMetricsProperty(), metrics);
 }
 
 // helper method to facilitate getting the reflow and bounding metrics
 /* static */ void
 nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame*            aFrame,
                                                        nsHTMLReflowMetrics& aReflowMetrics,
                                                        nsBoundingMetrics&   aBoundingMetrics,
                                                        eMathMLFrameType*    aMathMLFrameType)
 {
   NS_PRECONDITION(aFrame, "null arg");
 
   nsHTMLReflowMetrics *metrics = static_cast<nsHTMLReflowMetrics*>
-    (aFrame->GetProperty(nsGkAtoms::HTMLReflowMetricsProperty));
+    (aFrame->Properties().Get(HTMLReflowMetricsProperty()));
 
   // IMPORTANT: This function is only meant to be called in Place() methods
   // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the
   // information.
   NS_ASSERTION(metrics, "Didn't SaveReflowAndBoundingMetricsFor frame!");
   if (metrics) {
     aReflowMetrics = *metrics;
     aBoundingMetrics = metrics->mBoundingMetrics;
@@ -222,18 +224,19 @@ nsMathMLContainerFrame::GetReflowAndBoun
   }
 
 }
 
 void
 nsMathMLContainerFrame::ClearSavedChildMetrics()
 {
   nsIFrame* childFrame = mFrames.FirstChild();
+  FramePropertyTable* props = PresContext()->PropertyTable();
   while (childFrame) {
-    childFrame->DeleteProperty(nsGkAtoms::HTMLReflowMetricsProperty);
+    props->Delete(childFrame, HTMLReflowMetricsProperty());
     childFrame = childFrame->GetNextSibling();
   }
 }
 
 // helper to get the preferred size that a container frame should use to fire
 // the stretch on its stretchy child frames.
 void
 nsMathMLContainerFrame::GetPreferredStretchSize(nsIRenderingContext& aRenderingContext,
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -50,16 +50,18 @@
 #include "nsCSSFrameConstructor.h"
 #include "nsTableOuterFrame.h"
 #include "nsTableFrame.h"
 #include "nsTableCellFrame.h"
 #include "celldata.h"
 
 #include "nsMathMLmtableFrame.h"
 
+using namespace mozilla;
+
 //
 // <mtable> -- table or matrix - implementation
 //
 
 // helper function to perform an in-place split of a space-delimited string,
 // and return an array of pointers for the beginning of each segment, i.e.,
 // aOffset[0] is the first string, aOffset[1] is the second string, etc.
 // Used to parse attributes like columnalign='left right', rowalign='top bottom'
@@ -107,42 +109,58 @@ struct nsValueList
 // Each rowalign='top bottom' or columnalign='left right center' (from
 // <mtable> or <mtr>) is split once (lazily) into a nsValueList which is
 // stored in the property table. Row/Cell frames query the property table
 // to see what values apply to them.
 
 // XXX See bug 69409 - MathML attributes are not mapped to style.
 
 static void
-DestroyValueListFunc(void*    aFrame,
-                     nsIAtom* aPropertyName,
-                     void*    aPropertyValue,
-                     void*    aDtorData)
+DestroyValueList(void* aPropertyValue)
 {
   delete static_cast<nsValueList*>(aPropertyValue);
 }
 
+NS_DECLARE_FRAME_PROPERTY(RowAlignProperty, DestroyValueList)
+NS_DECLARE_FRAME_PROPERTY(RowLinesProperty, DestroyValueList)
+NS_DECLARE_FRAME_PROPERTY(ColumnAlignProperty, DestroyValueList)
+NS_DECLARE_FRAME_PROPERTY(ColumnLinesProperty, DestroyValueList)
+
+static const FramePropertyDescriptor*
+AttributeToProperty(nsIAtom* aAttribute)
+{
+  if (aAttribute == nsGkAtoms::rowalign_)
+    return RowAlignProperty();
+  if (aAttribute == nsGkAtoms::rowlines_)
+    return RowLinesProperty();
+  if (aAttribute == nsGkAtoms::columnalign_)
+    return ColumnAlignProperty();
+  NS_ASSERTION(aAttribute == nsGkAtoms::columnlines_, "Invalid attribute");
+  return ColumnLinesProperty();
+}
+
 static PRUnichar*
-GetValueAt(nsIFrame* aTableOrRowFrame,
-           nsIAtom*  aAttribute,
-           PRInt32   aRowOrColIndex)
+GetValueAt(nsIFrame*                      aTableOrRowFrame,
+           const FramePropertyDescriptor* aProperty,
+           nsIAtom*                       aAttribute,
+           PRInt32                        aRowOrColIndex)
 {
-  nsValueList* valueList = static_cast<nsValueList*>
-                                      (aTableOrRowFrame->GetProperty(aAttribute));
+  FrameProperties props = aTableOrRowFrame->Properties();
+  nsValueList* valueList = static_cast<nsValueList*>(props.Get(aProperty));
   if (!valueList) {
     // The property isn't there yet, so set it
     nsAutoString values;
     aTableOrRowFrame->GetContent()->GetAttr(kNameSpaceID_None, aAttribute, values);
     if (!values.IsEmpty())
       valueList = new nsValueList(values);
     if (!valueList || !valueList->mArray.Length()) {
       delete valueList; // ok either way, delete is null safe
       return nsnull;
     }
-    aTableOrRowFrame->SetProperty(aAttribute, valueList, DestroyValueListFunc);
+    props.Set(aProperty, valueList);
   }
   PRInt32 count = valueList->mArray.Length();
   return (aRowOrColIndex < count)
          ? valueList->mArray[aRowOrColIndex]
          : valueList->mArray[count-1];
 }
 
 #ifdef NS_DEBUG
@@ -175,32 +193,34 @@ MapRowAttributesIntoCSS(nsIFrame* aTable
   PRInt32 rowIndex = ((nsTableRowFrame*)aRowFrame)->GetRowIndex();
   nsIContent* rowContent = aRowFrame->GetContent();
   PRUnichar* attr;
 
   // see if the rowalign attribute is not already set
   if (!rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::rowalign_) &&
       !rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowalign_)) {
     // see if the rowalign attribute was specified on the table
-    attr = GetValueAt(aTableFrame, nsGkAtoms::rowalign_, rowIndex);
+    attr = GetValueAt(aTableFrame, RowAlignProperty(),
+                      nsGkAtoms::rowalign_, rowIndex);
     if (attr) {
       // set our special _moz attribute on the row without notifying a reflow
       rowContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowalign_,
                           nsDependentString(attr), PR_FALSE);
     }
   }
 
   // if we are not on the first row, see if |rowlines| was specified on the table.
   // Note that we pass 'rowIndex-1' because the CSS rule in mathml.css is associated
   // to 'border-top', and it is as if we draw the line on behalf of the previous cell.
   // This way of doing so allows us to handle selective lines, [row]\hline[row][row]',
   // and cases of spanning cells without further complications.
   if (rowIndex > 0 &&
       !rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowline_)) {
-    attr = GetValueAt(aTableFrame, nsGkAtoms::rowlines_, rowIndex-1);
+    attr = GetValueAt(aTableFrame, RowLinesProperty(),
+                      nsGkAtoms::rowlines_, rowIndex-1);
     if (attr) {
       // set our special _moz attribute on the row without notifying a reflow
       rowContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowline_,
                           nsDependentString(attr), PR_FALSE);
     }
   }
 }
 
@@ -219,37 +239,40 @@ MapColAttributesIntoCSS(nsIFrame* aTable
   nsIContent* cellContent = aCellFrame->GetContent();
   PRUnichar* attr;
 
   // see if the columnalign attribute is not already set
   if (!cellContent->HasAttr(kNameSpaceID_None, nsGkAtoms::columnalign_) &&
       !cellContent->HasAttr(kNameSpaceID_None,
                             nsGkAtoms::_moz_math_columnalign_)) {
     // see if the columnalign attribute was specified on the row
-    attr = GetValueAt(aRowFrame, nsGkAtoms::columnalign_, colIndex);
+    attr = GetValueAt(aRowFrame, ColumnAlignProperty(),
+                      nsGkAtoms::columnalign_, colIndex);
     if (!attr) {
       // see if the columnalign attribute was specified on the table
-      attr = GetValueAt(aTableFrame, nsGkAtoms::columnalign_, colIndex);
+      attr = GetValueAt(aTableFrame, ColumnAlignProperty(),
+                        nsGkAtoms::columnalign_, colIndex);
     }
     if (attr) {
       // set our special _moz attribute without notifying a reflow
       cellContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_columnalign_,
                            nsDependentString(attr), PR_FALSE);
     }
   }
 
   // if we are not on the first column, see if |columnlines| was specified on
   // the table. Note that we pass 'colIndex-1' because the CSS rule in mathml.css
   // is associated to 'border-left', and it is as if we draw the line on behalf
   // of the previous cell. This way of doing so allows us to handle selective lines,
   // e.g., 'r|cl', and cases of spanning cells without further complications.
   if (colIndex > 0 &&
       !cellContent->HasAttr(kNameSpaceID_None,
                             nsGkAtoms::_moz_math_columnline_)) {
-    attr = GetValueAt(aTableFrame, nsGkAtoms::columnlines_, colIndex-1);
+    attr = GetValueAt(aTableFrame, ColumnLinesProperty(),
+                      nsGkAtoms::columnlines_, colIndex-1);
     if (attr) {
       // set our special _moz attribute without notifying a reflow
       cellContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_columnline_,
                            nsDependentString(attr), PR_FALSE);
     }
   }
 }
 
@@ -355,17 +378,17 @@ NS_QUERYFRAME_TAIL_INHERITING(nsTableOut
 
 nsIFrame*
 NS_NewMathMLmtableOuterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsMathMLmtableOuterFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableOuterFrame)
-
+ 
 nsMathMLmtableOuterFrame::~nsMathMLmtableOuterFrame()
 {
 }
 
 NS_IMETHODIMP
 nsMathMLmtableOuterFrame::InheritAutomaticData(nsIFrame* aParent)
 {
   // XXX the REC says that by default, displaystyle=false in <mtable>
@@ -471,18 +494,20 @@ nsMathMLmtableOuterFrame::AttributeChang
   else if (aAttribute == nsGkAtoms::columnalign_)
     MOZcolAtom = nsGkAtoms::_moz_math_columnalign_;
   else if (aAttribute == nsGkAtoms::columnlines_)
     MOZcolAtom = nsGkAtoms::_moz_math_columnline_;
 
   if (!MOZrowAtom && !MOZcolAtom)
     return NS_OK;
 
+  nsPresContext* presContext = tableFrame->PresContext();
   // clear any cached nsValueList for this table
-  tableFrame->DeleteProperty(aAttribute);
+  presContext->PropertyTable()->
+    Delete(tableFrame, AttributeToProperty(aAttribute));
 
   // unset any _moz attribute that we may have set earlier, and re-sync
   nsIFrame* rowFrame = rgFrame->GetFirstChild(nsnull);
   for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
     if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) {
       if (MOZrowAtom) { // let rows do the work
         rowFrame->GetContent()->UnsetAttr(kNameSpaceID_None, MOZrowAtom, PR_FALSE);
         MapRowAttributesIntoCSS(tableFrame, rowFrame);    
@@ -494,17 +519,17 @@ nsMathMLmtableOuterFrame::AttributeChang
             MapColAttributesIntoCSS(tableFrame, rowFrame, cellFrame);
           }
         }
       }
     }
   }
 
   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
-  PresContext()->PresShell()->FrameConstructor()->
+  presContext->PresShell()->FrameConstructor()->
     PostRestyleEvent(mContent, eReStyle_Self, nsChangeHint_ReflowFrame);
 
   return NS_OK;
 }
 
 nsIFrame*
 nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext,
                                         PRInt32         aRowIndex)
@@ -715,34 +740,35 @@ nsMathMLmtrFrame::AttributeChanged(PRInt
     MapRowAttributesIntoCSS(nsTableFrame::GetTableFrame(this), this);
     // That's all - see comment above.
     return NS_OK;
   }
 
   if (aAttribute != nsGkAtoms::columnalign_)
     return NS_OK;
 
+  nsPresContext* presContext = PresContext();
   // Clear any cached columnalign's nsValueList for this row
-  DeleteProperty(aAttribute);
+  presContext->PropertyTable()->Delete(this, AttributeToProperty(aAttribute));
 
   // Clear any internal _moz attribute that we may have set earlier
   // in our cells and re-sync their columnalign attribute
   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   nsIFrame* cellFrame = GetFirstChild(nsnull);
   for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
     if (IS_TABLE_CELL(cellFrame->GetType())) {
       cellFrame->GetContent()->
         UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_columnalign_,
                   PR_FALSE);
       MapColAttributesIntoCSS(tableFrame, this, cellFrame);
     }
   }
 
   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
-  PresContext()->PresShell()->FrameConstructor()->
+  presContext->PresShell()->FrameConstructor()->
     PostRestyleEvent(mContent, eReStyle_Self, nsChangeHint_ReflowFrame);
 
   return NS_OK;
 }
 
 // --------
 // implementation of nsMathMLmtdFrame
 
--- a/layout/svg/base/src/nsSVGEffects.cpp
+++ b/layout/svg/base/src/nsSVGEffects.cpp
@@ -41,16 +41,18 @@
 #include "nsSVGOuterSVGFrame.h"
 #include "nsSVGFilterFrame.h"
 #include "nsSVGClipPathFrame.h"
 #include "nsSVGMaskFrame.h"
 #include "nsSVGTextPathFrame.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsFrameManager.h"
 
+using namespace mozilla;
+
 /**
  * Note that in the current setup there are two separate observer lists.
  *
  * In nsSVGRenderingObserver's ctor, the new object adds itself to the mutation
  * observer list maintained by the referenced *element*. In this way the
  * nsSVGRenderingObserver is notified if there are any attribute or content
  * tree changes to the element or any of its *descendants*.
  *
@@ -314,67 +316,74 @@ static nsSVGRenderingObserver *
 CreateTextPathProperty(nsIURI *aURI, nsIFrame *aFrame)
 { return new nsSVGTextPathProperty(aURI, aFrame); }
 
 static nsSVGRenderingObserver *
 CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame)
 { return new nsSVGPaintingProperty(aURI, aFrame); }
 
 static nsSVGRenderingObserver *
-GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp,
+GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame,
+                  const FramePropertyDescriptor *aProperty,
                   nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *))
 {
   if (!aURI)
     return nsnull;
+
+  FrameProperties props = aFrame->Properties();
   nsSVGRenderingObserver *prop =
-    static_cast<nsSVGRenderingObserver*>(aFrame->GetProperty(aProp));
+    static_cast<nsSVGRenderingObserver*>(props.Get(aProperty));
   if (prop)
     return prop;
   prop = aCreate(aURI, aFrame);
   if (!prop)
     return nsnull;
   NS_ADDREF(prop);
-  aFrame->SetProperty(aProp,
-                      static_cast<nsISupports*>(prop),
-                      nsPropertyTable::SupportsDtorFunc);
+  props.Set(aProperty, static_cast<nsISupports*>(prop));
   return prop;
 }
 
 nsSVGMarkerProperty *
-nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
+nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
+                                const FramePropertyDescriptor *aProp)
 {
   return static_cast<nsSVGMarkerProperty*>(
           GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty));
 }
 
 nsSVGTextPathProperty *
-nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
+nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
+                                  const FramePropertyDescriptor *aProp)
 {
   return static_cast<nsSVGTextPathProperty*>(
           GetEffectProperty(aURI, aFrame, aProp, CreateTextPathProperty));
 }
 
 nsSVGPaintingProperty *
-nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
+nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
+                                  const FramePropertyDescriptor *aProp)
 {
   return static_cast<nsSVGPaintingProperty*>(
           GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty));
 }
 
 nsSVGEffects::EffectProperties
 nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
 
   EffectProperties result;
   const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
   result.mFilter = static_cast<nsSVGFilterProperty*>
-    (GetEffectProperty(style->mFilter, aFrame, nsGkAtoms::filter, CreateFilterProperty));
-  result.mClipPath = GetPaintingProperty(style->mClipPath, aFrame, nsGkAtoms::clipPath);
-  result.mMask = GetPaintingProperty(style->mMask, aFrame, nsGkAtoms::mask);
+    (GetEffectProperty(style->mFilter, aFrame, FilterProperty(),
+                       CreateFilterProperty));
+  result.mClipPath =
+    GetPaintingProperty(style->mClipPath, aFrame, ClipPathProperty());
+  result.mMask =
+    GetPaintingProperty(style->mMask, aFrame, MaskProperty());
   return result;
 }
 
 nsSVGClipPathFrame *
 nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool *aOK)
 {
   if (!mClipPath)
     return nsnull;
@@ -396,40 +405,39 @@ nsSVGEffects::EffectProperties::GetMaskF
 }
 
 void
 nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
 {
   NS_ASSERTION(aFrame->GetContent()->IsNodeOfType(nsINode::eELEMENT),
                "aFrame's content should be an element");
 
-  aFrame->DeleteProperty(nsGkAtoms::filter);
-  aFrame->DeleteProperty(nsGkAtoms::mask);
-  aFrame->DeleteProperty(nsGkAtoms::clipPath);
-
-  aFrame->DeleteProperty(nsGkAtoms::marker_start);
-  aFrame->DeleteProperty(nsGkAtoms::marker_mid);
-  aFrame->DeleteProperty(nsGkAtoms::marker_end);
-
-  aFrame->DeleteProperty(nsGkAtoms::stroke);
-  aFrame->DeleteProperty(nsGkAtoms::fill);
+  FrameProperties props = aFrame->Properties();
+  props.Delete(FilterProperty());
+  props.Delete(MaskProperty());
+  props.Delete(ClipPathProperty());
+  props.Delete(MarkerBeginProperty());
+  props.Delete(MarkerMiddleProperty());
+  props.Delete(MarkerEndProperty());
+  props.Delete(FillProperty());
+  props.Delete(StrokeProperty());
 
   // Ensure that the filter is repainted correctly
   // We can't do that in DoUpdate as the referenced frame may not be valid
   GetEffectProperty(aFrame->GetStyleSVGReset()->mFilter,
-                    aFrame, nsGkAtoms::filter, CreateFilterProperty);
+                    aFrame, FilterProperty(), CreateFilterProperty);
 
   if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
     // Set marker properties here to avoid reference loops
     const nsStyleSVG *style = aFrame->GetStyleSVG();
-    GetEffectProperty(style->mMarkerStart, aFrame, nsGkAtoms::marker_start,
+    GetEffectProperty(style->mMarkerStart, aFrame, MarkerBeginProperty(),
                       CreateMarkerProperty);
-    GetEffectProperty(style->mMarkerMid, aFrame, nsGkAtoms::marker_mid,
+    GetEffectProperty(style->mMarkerMid, aFrame, MarkerMiddleProperty(),
                       CreateMarkerProperty);
-    GetEffectProperty(style->mMarkerEnd, aFrame, nsGkAtoms::marker_end,
+    GetEffectProperty(style->mMarkerEnd, aFrame, MarkerEndProperty(),
                       CreateMarkerProperty);
   }
 
   nsIFrame *kid = aFrame->GetFirstChild(nsnull);
   while (kid) {
     if (kid->GetContent()->IsNodeOfType(nsINode::eELEMENT)) {
       UpdateEffects(kid);
     }
@@ -440,17 +448,18 @@ nsSVGEffects::UpdateEffects(nsIFrame *aF
 nsSVGFilterProperty *
 nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
 
   if (!aFrame->GetStyleSVGReset()->mFilter)
     return nsnull;
 
-  return static_cast<nsSVGFilterProperty *>(aFrame->GetProperty(nsGkAtoms::filter));
+  return static_cast<nsSVGFilterProperty *>
+    (aFrame->Properties().Get(FilterProperty()));
 }
 
 static PLDHashOperator
 GatherEnumerator(nsVoidPtrHashKey* aEntry, void* aArg)
 {
   nsTArray<nsSVGRenderingObserver*>* array =
     static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg);
   array->AppendElement(static_cast<nsSVGRenderingObserver*>(
@@ -469,47 +478,47 @@ nsSVGRenderingObserverList::InvalidateAl
   // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
   mObservers.EnumerateEntries(GatherEnumerator, &observers);
 
   for (PRUint32 i = 0; i < observers.Length(); ++i) {
     observers[i]->InvalidateViaReferencedFrame();
   }
 }
 
+static void
+DestroyObservers(void* aPropertyValue)
+{
+  delete static_cast<nsSVGRenderingObserverList*>(aPropertyValue);
+}
+
+NS_DECLARE_FRAME_PROPERTY(ObserversProperty, DestroyObservers)
+
 static nsSVGRenderingObserverList *
 GetObserverList(nsIFrame *aFrame)
 {
   if (!(aFrame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS))
     return nsnull;
-  return static_cast<nsSVGRenderingObserverList*>(aFrame->GetProperty(nsGkAtoms::observer));
-}
-
-static void
-DeleteObserverList(void    *aObject,
-                   nsIAtom *aPropertyName,
-                   void    *aPropertyValue,
-                   void    *aData)
-{
-  delete static_cast<nsSVGRenderingObserverList*>(aPropertyValue);
+  return static_cast<nsSVGRenderingObserverList*>
+    (aFrame->Properties().Get(ObserversProperty()));
 }
 
 void
 nsSVGEffects::AddRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
 
   nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
   if (!observerList) {
     observerList = new nsSVGRenderingObserverList();
     if (!observerList)
       return;
     for (nsIFrame* f = aFrame; f; f = f->GetNextContinuation()) {
       f->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS);
     }
-    aFrame->SetProperty(nsGkAtoms::observer, observerList, DeleteObserverList);
+    aFrame->Properties().Set(ObserversProperty(), observerList);
   }
   observerList->Add(aObserver);
 }
 
 void
 nsSVGEffects::RemoveRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
--- a/layout/svg/base/src/nsSVGEffects.h
+++ b/layout/svg/base/src/nsSVGEffects.h
@@ -211,16 +211,33 @@ public:
   void InvalidateAll();
 
 private:
   nsTHashtable<nsVoidPtrHashKey> mObservers;
 };
 
 class nsSVGEffects {
 public:
+  typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
+
+  static void DestroySupports(void* aPropertyValue)
+  {
+    (static_cast<nsISupports*>(aPropertyValue))->Release();
+  }
+
+  NS_DECLARE_FRAME_PROPERTY(FilterProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(MaskProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(ClipPathProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(MarkerBeginProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(MarkerMiddleProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(MarkerEndProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(FillProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(StrokeProperty, DestroySupports)
+  NS_DECLARE_FRAME_PROPERTY(HrefProperty, DestroySupports)
+
   struct EffectProperties {
     nsSVGFilterProperty*   mFilter;
     nsSVGPaintingProperty* mMask;
     nsSVGPaintingProperty* mClipPath;
 
     /**
      * @return the clip-path frame, or null if there is no clip-path frame
      * @param aOK if a clip-path was specified but the designated element
@@ -299,22 +316,25 @@ public:
    * any, are invalidated.
    */
   static void InvalidateDirectRenderingObservers(nsIFrame *aFrame);
 
   /**
    * Get an nsSVGMarkerProperty for the frame, creating a fresh one if necessary
    */
   static nsSVGMarkerProperty *
-  GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp);
+  GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
+                    const FramePropertyDescriptor *aProperty);
   /**
    * Get an nsSVGTextPathProperty for the frame, creating a fresh one if necessary
    */
   static nsSVGTextPathProperty *
-  GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp);
+  GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
+                      const FramePropertyDescriptor *aProperty);
   /**
    * Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary
    */
   static nsSVGPaintingProperty *
-  GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp);
+  GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
+                      const FramePropertyDescriptor *aProperty);
 };
 
 #endif /*NSSVGEFFECTS_H_*/
--- a/layout/svg/base/src/nsSVGGeometryFrame.cpp
+++ b/layout/svg/base/src/nsSVGGeometryFrame.cpp
@@ -57,17 +57,17 @@ nsSVGGeometryFrame::Init(nsIContent* aCo
   nsresult rv = nsSVGGeometryFrameBase::Init(aContent, aParent, aPrevInFlow);
   return rv;
 }
 
 //----------------------------------------------------------------------
 
 nsSVGPaintServerFrame *
 nsSVGGeometryFrame::GetPaintServer(const nsStyleSVGPaint *aPaint,
-                                   nsIAtom *aType)
+                                   const FramePropertyDescriptor *aType)
 {
   if (aPaint->mType != eStyleSVGPaintType_Server)
     return nsnull;
 
   nsSVGPaintingProperty *property =
     nsSVGEffects::GetPaintingProperty(aPaint->mPaint.mPaintServer, this, aType);
   if (!property)
     return nsnull;
@@ -211,17 +211,17 @@ nsSVGGeometryFrame::SetupCairoFill(gfxCo
   if (style->mFillRule == NS_STYLE_FILL_RULE_EVENODD)
     aContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
   else
     aContext->SetFillRule(gfxContext::FILL_RULE_WINDING);
 
   float opacity = MaybeOptimizeOpacity(style->mFillOpacity);
 
   nsSVGPaintServerFrame *ps =
-    GetPaintServer(&style->mFill, nsGkAtoms::fill);
+    GetPaintServer(&style->mFill, nsSVGEffects::FillProperty());
   if (ps && ps->SetupPaintServer(aContext, this, opacity))
     return PR_TRUE;
 
   // On failure, use the fallback colour in case we have an
   // objectBoundingBox where the width or height of the object is zero.
   // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
   if (style->mFill.mType == eStyleSVGPaintType_Server) {
     SetupCairoColor(aContext,
@@ -302,17 +302,17 @@ nsSVGGeometryFrame::SetupCairoStroke(gfx
     return PR_FALSE;
   }
   SetupCairoStrokeHitGeometry(aContext);
 
   const nsStyleSVG* style = GetStyleSVG();
   float opacity = MaybeOptimizeOpacity(style->mStrokeOpacity);
 
   nsSVGPaintServerFrame *ps =
-    GetPaintServer(&style->mStroke, nsGkAtoms::stroke);
+    GetPaintServer(&style->mStroke, nsSVGEffects::StrokeProperty());
   if (ps && ps->SetupPaintServer(aContext, this, opacity))
     return PR_TRUE;
 
   // On failure, use the fallback colour in case we have an
   // objectBoundingBox where the width or height of the object is zero.
   // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
   if (style->mStroke.mType == eStyleSVGPaintType_Server) {
     SetupCairoColor(aContext,
--- a/layout/svg/base/src/nsSVGGeometryFrame.h
+++ b/layout/svg/base/src/nsSVGGeometryFrame.h
@@ -96,17 +96,17 @@ public:
   /*
    * Set up a cairo context for stroking a path
    * @return PR_FALSE to skip rendering
    */
   PRBool SetupCairoStroke(gfxContext *aContext);
 
 protected:
   nsSVGPaintServerFrame *GetPaintServer(const nsStyleSVGPaint *aPaint,
-                                        nsIAtom *aType);
+                                        const FramePropertyDescriptor *aProperty);
 
 private:
   nsresult GetStrokeDashArray(double **arr, PRUint32 *count);
   float GetStrokeDashoffset();
 
   /**
    * Returns the given 'fill-opacity' or 'stroke-opacity' value multiplied by
    * the value of the 'opacity' property if it's possible to avoid the expense
--- a/layout/svg/base/src/nsSVGGradientFrame.cpp
+++ b/layout/svg/base/src/nsSVGGradientFrame.cpp
@@ -79,17 +79,17 @@ nsSVGGradientFrame::AttributeChanged(PRI
   if (aNameSpaceID == kNameSpaceID_None &&
       (aAttribute == nsGkAtoms::gradientUnits ||
        aAttribute == nsGkAtoms::gradientTransform ||
        aAttribute == nsGkAtoms::spreadMethod)) {
     nsSVGEffects::InvalidateRenderingObservers(this);
   } else if (aNameSpaceID == kNameSpaceID_XLink &&
              aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
-    DeleteProperty(nsGkAtoms::href);
+    Properties().Delete(nsSVGEffects::HrefProperty());
     mNoHRefURI = PR_FALSE;
     // And update whoever references us
     nsSVGEffects::InvalidateRenderingObservers(this);
   }
 
   return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
                                                   aAttribute, aModType);
 }
@@ -265,18 +265,18 @@ nsSVGGradientFrame::SetupPaintServer(gfx
 // Private (helper) methods
 
 nsSVGGradientFrame *
 nsSVGGradientFrame::GetReferencedGradient()
 {
   if (mNoHRefURI)
     return nsnull;
 
-  nsSVGPaintingProperty *property =
-    static_cast<nsSVGPaintingProperty*>(GetProperty(nsGkAtoms::href));
+  nsSVGPaintingProperty *property = static_cast<nsSVGPaintingProperty*>
+    (Properties().Get(nsSVGEffects::HrefProperty()));
 
   if (!property) {
     // Fetch our gradient element's xlink:href attribute
     nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(mContent);
     nsAutoString href;
     grad->mStringAttributes[nsSVGGradientElement::HREF].GetAnimValue(href, grad);
     if (href.IsEmpty()) {
       mNoHRefURI = PR_TRUE;
@@ -284,17 +284,18 @@ nsSVGGradientFrame::GetReferencedGradien
     }
 
     // Convert href to an nsIURI
     nsCOMPtr<nsIURI> targetURI;
     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
                                               mContent->GetCurrentDoc(), base);
 
-    property = nsSVGEffects::GetPaintingProperty(targetURI, this, nsGkAtoms::href);
+    property =
+      nsSVGEffects::GetPaintingProperty(targetURI, this, nsSVGEffects::HrefProperty());
     if (!property)
       return nsnull;
   }
 
   nsIFrame *result = property->GetReferencedFrame();
   if (!result)
     return nsnull;
 
--- a/layout/svg/base/src/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/base/src/nsSVGIntegrationUtils.cpp
@@ -63,17 +63,18 @@ static nsRect GetNonSVGUserSpace(nsIFram
 {
   NS_ASSERTION(!aFirst->GetPrevContinuation(), "Not first continuation");
   return nsLayoutUtils::GetAllInFlowRectsUnion(aFirst, aFirst);
 }
 
 static nsRect
 GetPreEffectsOverflowRect(nsIFrame* aFrame)
 {
-  nsRect* r = static_cast<nsRect*>(aFrame->GetProperty(nsGkAtoms::preEffectsBBoxProperty));
+  nsRect* r = static_cast<nsRect*>
+    (aFrame->Properties().Get(nsIFrame::PreEffectsBBoxProperty()));
   if (r)
     return *r;
   return aFrame->GetOverflowRect();
 }
 
 struct BBoxCollector : public nsLayoutUtils::BoxCallback {
   nsIFrame*     mReferenceFrame;
   nsIFrame*     mCurrentFrame;
--- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
@@ -386,22 +386,25 @@ nsSVGPathGeometryFrame::GetCanvasTM()
 
 nsSVGPathGeometryFrame::MarkerProperties
 nsSVGPathGeometryFrame::GetMarkerProperties(nsSVGPathGeometryFrame *aFrame)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
 
   MarkerProperties result;
   const nsStyleSVG *style = aFrame->GetStyleSVG();
-  result.mMarkerStart = nsSVGEffects::GetMarkerProperty(
-                          style->mMarkerStart, aFrame, nsGkAtoms::marker_start);
-  result.mMarkerMid = nsSVGEffects::GetMarkerProperty(
-                        style->mMarkerMid, aFrame, nsGkAtoms::marker_mid);
-  result.mMarkerEnd = nsSVGEffects::GetMarkerProperty(
-                        style->mMarkerEnd, aFrame, nsGkAtoms::marker_end);
+  result.mMarkerStart =
+    nsSVGEffects::GetMarkerProperty(style->mMarkerStart, aFrame,
+                                    nsSVGEffects::MarkerBeginProperty());
+  result.mMarkerMid =
+    nsSVGEffects::GetMarkerProperty(style->mMarkerMid, aFrame,
+                                    nsSVGEffects::MarkerMiddleProperty());
+  result.mMarkerEnd =
+    nsSVGEffects::GetMarkerProperty(style->mMarkerEnd, aFrame,
+                                    nsSVGEffects::MarkerEndProperty());
   return result;
 }
 
 nsSVGMarkerFrame *
 nsSVGPathGeometryFrame::MarkerProperties::GetMarkerStartFrame()
 {
   if (!mMarkerStart)
     return nsnull;
--- a/layout/svg/base/src/nsSVGPatternFrame.cpp
+++ b/layout/svg/base/src/nsSVGPatternFrame.cpp
@@ -95,17 +95,17 @@ nsSVGPatternFrame::AttributeChanged(PRIn
        aAttribute == nsGkAtoms::preserveAspectRatio ||
        aAttribute == nsGkAtoms::viewBox)) {
     nsSVGEffects::InvalidateRenderingObservers(this);
   }
 
   if (aNameSpaceID == kNameSpaceID_XLink &&
       aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
-    DeleteProperty(nsGkAtoms::href);
+    Properties().Delete(nsSVGEffects::HrefProperty());
     mNoHRefURI = PR_FALSE;
     // And update whoever references us
     nsSVGEffects::InvalidateRenderingObservers(this);
   }
 
   return nsSVGPatternFrameBase::AttributeChanged(aNameSpaceID,
                                                  aAttribute, aModType);
 }
@@ -416,18 +416,18 @@ nsSVGPatternFrame::GetHeight()
 
 // Private (helper) methods
 nsSVGPatternFrame *
 nsSVGPatternFrame::GetReferencedPattern()
 {
   if (mNoHRefURI)
     return nsnull;
 
-  nsSVGPaintingProperty *property =
-    static_cast<nsSVGPaintingProperty*>(GetProperty(nsGkAtoms::href));
+  nsSVGPaintingProperty *property = static_cast<nsSVGPaintingProperty*>
+    (Properties().Get(nsSVGEffects::HrefProperty()));
 
   if (!property) {
     // Fetch our pattern element's xlink:href attribute
     nsSVGPatternElement *pattern = static_cast<nsSVGPatternElement *>(mContent);
     nsAutoString href;
     pattern->mStringAttributes[nsSVGPatternElement::HREF].GetAnimValue(href, pattern);
     if (href.IsEmpty()) {
       mNoHRefURI = PR_TRUE;
@@ -435,17 +435,18 @@ nsSVGPatternFrame::GetReferencedPattern(
     }
 
     // Convert href to an nsIURI
     nsCOMPtr<nsIURI> targetURI;
     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
                                               mContent->GetCurrentDoc(), base);
 
-    property = nsSVGEffects::GetPaintingProperty(targetURI, this, nsGkAtoms::href);
+    property =
+      nsSVGEffects::GetPaintingProperty(targetURI, this, nsSVGEffects::HrefProperty());
     if (!property)
       return nsnull;
   }
 
   nsIFrame *result = property->GetReferencedFrame();
   if (!result)
     return nsnull;
 
--- a/layout/svg/base/src/nsSVGTextPathFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextPathFrame.cpp
@@ -109,34 +109,34 @@ nsSVGTextPathFrame::GetDy()
 }
 
 //----------------------------------------------------------------------
 // nsSVGTextPathFrame methods:
 
 nsIFrame *
 nsSVGTextPathFrame::GetPathFrame()
 {
-  nsSVGTextPathProperty *property =
-    static_cast<nsSVGTextPathProperty*>(GetProperty(nsGkAtoms::href));
+  nsSVGTextPathProperty *property = static_cast<nsSVGTextPathProperty*>
+    (Properties().Get(nsSVGEffects::HrefProperty()));
 
   if (!property) {
     nsSVGTextPathElement *tp = static_cast<nsSVGTextPathElement*>(mContent);
     nsAutoString href;
     tp->mStringAttributes[nsSVGTextPathElement::HREF].GetAnimValue(href, tp);
     if (href.IsEmpty()) {
       return nsnull; // no URL
     }
 
     nsCOMPtr<nsIURI> targetURI;
     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
                                               mContent->GetCurrentDoc(), base);
 
-    property = nsSVGEffects::GetTextPathProperty(
-                               targetURI, this, nsGkAtoms::href);
+    property =
+      nsSVGEffects::GetTextPathProperty(targetURI, this, nsSVGEffects::HrefProperty());
     if (!property)
       return nsnull;
   }
 
   return property->GetReferencedFrame(nsGkAtoms::svgPathGeometryFrame, nsnull);
 }
 
 already_AddRefed<gfxFlattenedPath>
@@ -201,14 +201,14 @@ nsSVGTextPathFrame::AttributeChanged(PRI
                                      PRInt32         aModType)
 {
   if (aNameSpaceID == kNameSpaceID_None &&
       aAttribute == nsGkAtoms::startOffset) {
     NotifyGlyphMetricsChange();
   } else if (aNameSpaceID == kNameSpaceID_XLink &&
              aAttribute == nsGkAtoms::href) {
     // Blow away our reference, if any
-    DeleteProperty(nsGkAtoms::href);
+    Properties().Delete(nsSVGEffects::HrefProperty());
     NotifyGlyphMetricsChange();
   }
 
   return NS_OK;
 }
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -69,16 +69,18 @@
 #include "nsCSSRendering.h"
 #include "nsLayoutErrors.h"
 #include "nsAutoPtr.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsStyleSet.h"
 #include "nsDisplayList.h"
 #include "nsIScrollableFrame.h"
 
+using namespace mozilla;
+
 /********************************************************************************
  ** nsTableReflowState                                                         **
  ********************************************************************************/
 
 struct nsTableReflowState {
 
   // the real reflow state
   const nsHTMLReflowState& reflowState;
@@ -2336,16 +2338,25 @@ nsTableFrame::GetUsedBorder() const
 nsTableFrame::GetUsedPadding() const
 {
   if (!IsBorderCollapse())
     return nsHTMLContainerFrame::GetUsedPadding();
 
   return nsMargin(0,0,0,0);
 }
 
+// Destructor function for BCPropertyData properties
+static void
+DestroyBCProperty(void* aPropertyValue)
+{
+  delete static_cast<BCPropertyData*>(aPropertyValue);
+}
+
+NS_DECLARE_FRAME_PROPERTY(TableBCProperty, DestroyBCProperty)
+
 static void
 DivideBCBorderSize(BCPixelSize  aPixelSize,
                    BCPixelSize& aSmallHalf,
                    BCPixelSize& aLargeHalf)
 {
   aSmallHalf = aPixelSize / 2;
   aLargeHalf = aPixelSize - aSmallHalf;
 }
@@ -2353,18 +2364,18 @@ DivideBCBorderSize(BCPixelSize  aPixelSi
 nsMargin
 nsTableFrame::GetOuterBCBorder() const
 {
   if (NeedToCalcBCBorders())
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
 
   nsMargin border(0, 0, 0, 0);
   PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
-  BCPropertyData* propData = 
-    (BCPropertyData*)nsTableFrame::GetProperty((nsIFrame*)this, nsGkAtoms::tableBCProperty, PR_FALSE);
+  BCPropertyData* propData = static_cast<BCPropertyData*>
+    (Properties().Get(TableBCProperty()));
   if (propData) {
     border.top    = BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
     border.right  = BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightBorderWidth);
     border.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
     border.left   = BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftBorderWidth);
   }
   return border;
 }
@@ -2372,20 +2383,18 @@ nsTableFrame::GetOuterBCBorder() const
 nsMargin
 nsTableFrame::GetIncludedOuterBCBorder() const
 {
   if (NeedToCalcBCBorders())
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
 
   nsMargin border(0, 0, 0, 0);
   PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
-  BCPropertyData* propData =
-    (BCPropertyData*)nsTableFrame::GetProperty((nsIFrame*)this,
-                                                nsGkAtoms::tableBCProperty,
-                                                PR_FALSE);
+  BCPropertyData* propData = static_cast<BCPropertyData*>
+    (Properties().Get(TableBCProperty()));
   if (propData) {
     border.top += BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
     border.right += BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightCellBorderWidth);
     border.bottom += BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
     border.left += BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftCellBorderWidth);
   }
   return border;
 }
@@ -3808,23 +3817,27 @@ nsTableFrame::SetBCDamageArea(const nsRe
   newRect.width  = NS_MAX(1, newRect.width);
   newRect.height = NS_MAX(1, newRect.height);
 
   if (!IsBorderCollapse()) {
     NS_ASSERTION(PR_FALSE, "invalid call - not border collapse model");
     return;
   }
   SetNeedToCalcBCBorders(PR_TRUE);
-  // Get the property 
-  BCPropertyData* value = (BCPropertyData*)nsTableFrame::GetProperty(this, nsGkAtoms::tableBCProperty, PR_TRUE);
-  if (value) {
-    // for now just construct a union of the new and old damage areas
-    value->mDamageArea.UnionRect(value->mDamageArea, newRect);
-    CheckFixDamageArea(GetRowCount(), GetColCount(), value->mDamageArea);
-  }
+  // Get the property
+  FrameProperties props = Properties();
+  BCPropertyData* value = static_cast<BCPropertyData*>
+    (props.Get(TableBCProperty()));
+  if (!value) {
+    value = new BCPropertyData();
+    props.Set(TableBCProperty(), value);
+  }
+  // for now just construct a union of the new and old damage areas
+  value->mDamageArea.UnionRect(value->mDamageArea, newRect);
+  CheckFixDamageArea(GetRowCount(), GetColCount(), value->mDamageArea);
 }
 
 /* BCCellBorder represents a border segment which can be either a horizontal
  * or a vertical segment. For each segment we need to know the color, width,
  * style, who owns it and how long it is in cellmap coordinates.
  * Ownership of these segments is important to calculate which corners should
  * be bevelled. This structure has dual use, its used first to compute the
  * dominant border for horizontal and vertical segments and to store the
@@ -3993,19 +4006,18 @@ BCMapCellInfo::BCMapCellInfo(nsTableFram
     mEndSide = NS_SIDE_RIGHT;
   }
   else {
     mStartSide = NS_SIDE_RIGHT;
     mEndSide = NS_SIDE_LEFT;
   }
   mNumTableRows = mTableFrame->GetRowCount();
   mNumTableCols = mTableFrame->GetColCount();
-  mTableBCData =
-    static_cast <BCPropertyData*>(nsTableFrame::GetProperty(mTableFrame,
-                 nsGkAtoms::tableBCProperty, PR_FALSE));
+  mTableBCData = static_cast<BCPropertyData*>
+    (mTableFrame->Properties().Get(TableBCProperty()));
                  
   ResetCellInfo();
 }
 
 void BCMapCellInfo::ResetCellInfo()
 {
   mCellData  = nsnull;
   mRowGroup  = nsnull;
@@ -5470,19 +5482,18 @@ nsTableFrame::CalcBCBorders()
                "calling CalcBCBorders on separated-border table");
   nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT0();
   PRInt32 numRows = GetRowCount();
   PRInt32 numCols = GetColCount();
   if (!numRows || !numCols)
     return; // nothing to do
 
   // Get the property holding the table damage area and border widths
-  BCPropertyData* propData =
-    (BCPropertyData*)nsTableFrame::GetProperty(this, nsGkAtoms::tableBCProperty,
-                                               PR_FALSE);
+  BCPropertyData* propData = static_cast<BCPropertyData*>
+    (Properties().Get(TableBCProperty()));
   if (!propData) ABORT0();
 
   
   
   CheckFixDamageArea(numRows, numCols, propData->mDamageArea);
   // calculate an expanded damage area 
   nsRect damageArea(propData->mDamageArea);
   ExpandBCDamageArea(damageArea);
@@ -7209,76 +7220,16 @@ PRBool nsTableFrame::ColIsSpannedInto(PR
   nsTableCellMap * cellMap = GetCellMap();
   NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated.");
   if (cellMap) {
     result = cellMap->ColIsSpannedInto(aColIndex);
   }
   return result;
 }
 
-// Destructor function for nscoord properties
-static void
-DestroyCoordFunc(void*           aFrame,
-                 nsIAtom*        aPropertyName,
-                 void*           aPropertyValue,
-                 void*           aDtorData)
-{
-  delete static_cast<nscoord*>(aPropertyValue);
-}
-
-// Destructor function point properties
-static void
-DestroyPointFunc(void*           aFrame,
-                 nsIAtom*        aPropertyName,
-                 void*           aPropertyValue,
-                 void*           aDtorData)
-{
-  delete static_cast<nsPoint*>(aPropertyValue);
-}
-
-// Destructor function for BCPropertyData properties
-static void
-DestroyBCPropertyDataFunc(void*           aFrame,
-                          nsIAtom*        aPropertyName,
-                          void*           aPropertyValue,
-                          void*           aDtorData)
-{
-  delete static_cast<BCPropertyData*>(aPropertyValue);
-}
-
-void*
-nsTableFrame::GetProperty(nsIFrame*            aFrame,
-                          nsIAtom*             aPropertyName,
-                          PRBool               aCreateIfNecessary)
-{
-  nsPropertyTable *propTable = aFrame->PresContext()->PropertyTable();
-  void *value = propTable->GetProperty(aFrame, aPropertyName);
-  if (value) {
-    return (nsPoint*)value;  // the property already exists
-  }
-  if (aCreateIfNecessary) {
-    // The property isn't set yet, so allocate a new value, set the property,
-    // and return the newly allocated value
-    NSPropertyDtorFunc dtorFunc = nsnull;
-    if (aPropertyName == nsGkAtoms::rowUnpaginatedHeightProperty) {
-      value = new nscoord;
-      dtorFunc = DestroyCoordFunc;
-    }
-    else if (aPropertyName == nsGkAtoms::tableBCProperty) {
-      value = new BCPropertyData;
-      dtorFunc = DestroyBCPropertyDataFunc;
-    }
-    if (value) {
-      propTable->SetProperty(aFrame, aPropertyName, value, dtorFunc, nsnull);
-    }
-    return value;
-  }
-  return nsnull;
-}
-
 /* static */
 void
 nsTableFrame::InvalidateFrame(nsIFrame* aFrame,
                               const nsRect& aOrigRect,
                               const nsRect& aOrigOverflowRect,
                               PRBool aIsFirstReflow)
 {
   nsIFrame* parent = aFrame->GetParent();
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -154,21 +154,16 @@ public:
 
   /** sets defaults for table-specific style.
     * @see nsIFrame::Init 
     */
   NS_IMETHOD Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow);
 
-
-  static void* GetProperty(nsIFrame*            aFrame,
-                           nsIAtom*             aPropertyName,
-                           PRBool               aCreateIfNecessary = PR_FALSE);
-
   static float GetTwipsToPixels(nsPresContext* aPresContext);
 
   // Return true if aParentReflowState.frame or any of its ancestors within
   // the containing table have non-auto height. (e.g. pct or fixed height)
   static PRBool AncestorsHaveStyleHeight(const nsHTMLReflowState& aParentReflowState);
 
   // See if a special height reflow will occur due to having a pct height when
   // the pct height basis may not yet be valid.
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -47,16 +47,18 @@
 #include "nsTableCellFrame.h"
 #include "nsCSSRendering.h"
 #include "nsHTMLParts.h"
 #include "nsTableColGroupFrame.h"
 #include "nsTableColFrame.h"
 #include "nsCOMPtr.h"
 #include "nsDisplayList.h"
 
+using namespace mozilla;
+
 struct nsTableCellReflowState : public nsHTMLReflowState
 {
   nsTableCellReflowState(nsPresContext*           aPresContext,
                          const nsHTMLReflowState& aParentReflowState,
                          nsIFrame*                aFrame,
                          const nsSize&            aAvailableSpace,
                          PRBool                   aInit = PR_TRUE)
     : nsHTMLReflowState(aPresContext, aParentReflowState, aFrame,
@@ -1345,37 +1347,33 @@ nsTableRowFrame::GetNextRow() const
 	  NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == childFrame->GetStyleDisplay()->mDisplay, "wrong display type on rowframe");
       return rowFrame;
     }
     childFrame = childFrame->GetNextSibling();
   }
   return nsnull;
 }
 
+NS_DECLARE_FRAME_PROPERTY(RowUnpaginatedHeightProperty, nsnull)
+
 void 
 nsTableRowFrame::SetUnpaginatedHeight(nsPresContext* aPresContext,
                                       nscoord        aValue)
 {
   NS_ASSERTION(!GetPrevInFlow(), "program error");
-  // Get the property 
-  nscoord* value = (nscoord*)nsTableFrame::GetProperty(this, nsGkAtoms::rowUnpaginatedHeightProperty, PR_TRUE);
-  if (value) {
-    *value = aValue;
-  }
+  // Get the property
+  aPresContext->PropertyTable()->
+    Set(this, RowUnpaginatedHeightProperty(), NS_INT32_TO_PTR(aValue));
 }
 
 nscoord
 nsTableRowFrame::GetUnpaginatedHeight(nsPresContext* aPresContext)
 {
-  // See if the property is set
-  nscoord* value = (nscoord*)nsTableFrame::GetProperty(GetFirstInFlow(), nsGkAtoms::rowUnpaginatedHeightProperty);
-  if (value) 
-    return *value;
-  else 
-    return 0;
+  FrameProperties props = GetFirstInFlow()->Properties();
+  return NS_PTR_TO_INT32(props.Get(RowUnpaginatedHeightProperty()));
 }
 
 void nsTableRowFrame::SetContinuousBCBorderWidth(PRUint8     aForSide,
                                                  BCPixelSize aPixelValue)
 {
   switch (aForSide) {
     case NS_SIDE_RIGHT:
       mRightContBorderWidth = aPixelValue;
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -49,16 +49,18 @@
 #include "nsIPresShell.h"
 #include "nsCSSRendering.h"
 #include "nsHTMLParts.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDisplayList.h"
 
 #include "nsCellMap.h"//table cell navigation
 
+using namespace mozilla;
+
 nsTableRowGroupFrame::nsTableRowGroupFrame(nsStyleContext* aContext):
   nsHTMLContainerFrame(aContext)
 {
   SetRepeatable(PR_FALSE);
 }
 
 nsTableRowGroupFrame::~nsTableRowGroupFrame()
 {
@@ -1805,30 +1807,31 @@ nsTableRowGroupFrame::GetNextSiblingOnLi
   NS_ENSURE_ARG_POINTER(aFrame);
   aFrame = aFrame->GetNextSibling();
   return NS_OK;
 }
 
 //end nsLineIterator methods
 
 static void
-DestroyFrameCursorData(void* aObject, nsIAtom* aPropertyName,
-                       void* aPropertyValue, void* aData)
+DestroyFrameCursorData(void* aPropertyValue)
 {
   delete static_cast<nsTableRowGroupFrame::FrameCursorData*>(aPropertyValue);
 }
 
+NS_DECLARE_FRAME_PROPERTY(RowCursorProperty, DestroyFrameCursorData)
+
 void
 nsTableRowGroupFrame::ClearRowCursor()
 {
   if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR))
     return;
 
   RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
-  DeleteProperty(nsGkAtoms::rowCursorProperty);
+  Properties().Delete(RowCursorProperty());
 }
 
 nsTableRowGroupFrame::FrameCursorData*
 nsTableRowGroupFrame::SetupRowCursor()
 {
   if (GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR) {
     // We already have a valid row cursor. Don't waste time rebuilding it.
     return nsnull;
@@ -1842,34 +1845,29 @@ nsTableRowGroupFrame::SetupRowCursor()
   if (!f) {
     // Less than MIN_ROWS_NEEDING_CURSOR rows, so just don't bother
     return nsnull;
   }
 
   FrameCursorData* data = new FrameCursorData();
   if (!data)
     return nsnull;
-  nsresult rv = SetProperty(nsGkAtoms::rowCursorProperty, data,
-                            DestroyFrameCursorData);
-  if (NS_FAILED(rv)) {
-    delete data;
-    return nsnull;
-  }
+  Properties().Set(RowCursorProperty(), data);
   AddStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
   return data;
 }
 
 nsIFrame*
 nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove)
 {
   if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR))
     return nsnull;
 
   FrameCursorData* property = static_cast<FrameCursorData*>
-                                         (GetProperty(nsGkAtoms::rowCursorProperty));
+    (Properties().Get(RowCursorProperty()));
   PRUint32 cursorIndex = property->mCursorIndex;
   PRUint32 frameCount = property->mFrames.Length();
   if (cursorIndex >= frameCount)
     return nsnull;
   nsIFrame* cursorFrame = property->mFrames[cursorIndex];
 
   // The cursor's frame list excludes frames with empty overflow-area, so
   // we don't need to check that here.
--- a/layout/xul/base/src/nsBox.cpp
+++ b/layout/xul/base/src/nsBox.cpp
@@ -175,19 +175,20 @@ nsBox::BeginLayout(nsBoxLayoutState& aSt
     // does this too).
     nsIFrame* box;
     for (box = GetChildBox(); box; box = box->GetNextBox())
       box->AddStateBits(NS_FRAME_IS_DIRTY);
   }
 
   // Another copy-over from nsHTMLReflowState.
   // Since we are in reflow, we don't need to store these properties anymore.
-  DeleteProperty(nsGkAtoms::usedBorderProperty);
-  DeleteProperty(nsGkAtoms::usedPaddingProperty);
-  DeleteProperty(nsGkAtoms::usedMarginProperty);
+  FrameProperties props = Properties();
+  props.Delete(UsedBorderProperty());
+  props.Delete(UsedPaddingProperty());
+  props.Delete(UsedMarginProperty());
 
 #ifdef DEBUG_LAYOUT
   PropagateDebug(aState);
 #endif
 
   return NS_OK;
 }