diff --git a/mozilla/dom/public/idl/css/nsIDOMCSS2Properties.idl b/mozilla/dom/public/idl/css/nsIDOMCSS2Properties.idl index 697014f0eab..5141c33a51e 100644 --- a/mozilla/dom/public/idl/css/nsIDOMCSS2Properties.idl +++ b/mozilla/dom/public/idl/css/nsIDOMCSS2Properties.idl @@ -406,7 +406,7 @@ interface nsIDOMCSS2Properties : nsISupports // raises(DOMException) on setting }; -[scriptable, uuid(f130d650-5304-4e77-b8cb-cfa100702ea9)] +[scriptable, uuid(06b42e9d-61b5-400d-9561-b43f0e9883c0)] interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties { /* Non-DOM 2 extensions */ @@ -484,12 +484,6 @@ interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties attribute DOMString MozColumnGap; // raises(DOMException) on setting - attribute DOMString MozCounterIncrement; - // raises(DOMException) on setting - - attribute DOMString MozCounterReset; - // raises(DOMException) on setting - attribute DOMString MozFloatEdge; // raises(DOMException) on setting diff --git a/mozilla/layout/base/Makefile.in b/mozilla/layout/base/Makefile.in index d0906bcbc56..8ce065b9e82 100644 --- a/mozilla/layout/base/Makefile.in +++ b/mozilla/layout/base/Makefile.in @@ -118,10 +118,12 @@ CPPSRCS = \ nsCSSRendering.cpp \ nsCaret.cpp \ nsChildIterator.cpp \ + nsCounterManager.cpp \ nsDocumentViewer.cpp \ nsFrameContentIterator.cpp \ nsFrameManager.cpp \ nsFrameTraversal.cpp \ + nsGenConList.cpp \ nsImageLoader.cpp \ nsLayoutAtoms.cpp \ nsLayoutDebugger.cpp \ diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 4150e3939ef..7d807b4a13b 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -1889,6 +1889,7 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument, , mGfxScrollFrame(nsnull) , mUpdateCount(0) , mQuotesDirty(PR_FALSE) + , mCountersDirty(PR_FALSE) { if (!gGotXBLFormPrefs) { gGotXBLFormPrefs = PR_TRUE; @@ -1968,10 +1969,19 @@ nsIXBLService * nsCSSFrameConstructor::GetXBLService() } void -nsCSSFrameConstructor::GeneratedContentFrameRemoved(nsIFrame* aFrame) +nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame) { - if (mQuoteList.DestroyNodesFor(aFrame)) - QuotesDirty(); + if (aFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) { + if (mQuoteList.DestroyNodesFor(aFrame)) + QuotesDirty(); + } + + if (mCounterManager.DestroyNodesFor(aFrame)) { + // Technically we don't need to update anything if we destroyed only + // USE nodes. However, this is unlikely to happen in the real world + // since USE nodes generally go along with INCREMENT nodes. + CountersDirty(); + } } nsresult @@ -2043,16 +2053,18 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram } else { - nsAutoString contentString(data.mContent.mString); + nsAutoString contentString; switch (type) { case eStyleContentType_String: + contentString = data.mContent.mString; break; case eStyleContentType_Attr: - { + { nsCOMPtr attrName; PRInt32 attrNameSpace = kNameSpaceID_None; + contentString = data.mContent.mString; PRInt32 barIndex = contentString.FindChar('|'); // CSS namespace delimiter if (-1 != barIndex) { nsAutoString nameSpaceVal; @@ -2100,7 +2112,31 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram case eStyleContentType_Counter: case eStyleContentType_Counters: - return NS_ERROR_NOT_IMPLEMENTED; // XXX not supported yet... + { + nsCSSValue::Array *counters = data.mContent.mCounters; + nsCounterList *counterList = mCounterManager.CounterListFor( + nsDependentString(counters->Item(0).GetStringBufferValue())); + if (!counterList) + return NS_ERROR_OUT_OF_MEMORY; + + nsCounterUseNode* node = + new nsCounterUseNode(counters, aParentFrame, aContentIndex, + type == eStyleContentType_Counters); + if (!node) + return NS_ERROR_OUT_OF_MEMORY; + + counterList->Insert(node); + if (counterList->IsLast(node)) + node->Calc(counterList); + else { + counterList->SetDirty(); + CountersDirty(); + } + + textPtr = &node->mText; // text node assigned below + node->GetText(contentString); + } + break; case eStyleContentType_Image: NS_NOTREACHED("handled by if above"); @@ -2111,12 +2147,13 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram case eStyleContentType_NoOpenQuote: case eStyleContentType_NoCloseQuote: { - nsQuoteListNode* node = - new nsQuoteListNode(type, aParentFrame, aContentIndex); + nsQuoteNode* node = new nsQuoteNode(type, aParentFrame, aContentIndex); if (!node) return NS_ERROR_OUT_OF_MEMORY; mQuoteList.Insert(node); - if (!mQuoteList.IsLast(node)) + if (mQuoteList.IsLast(node)) + mQuoteList.Calc(node); + else QuotesDirty(); // Don't generate a text node or any text for 'no-open-quote' and @@ -2124,7 +2161,7 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram if (node->IsHiddenQuote()) return NS_OK; - textPtr = &node->mText; // Delayed storage of text node. + textPtr = &node->mText; // text node assigned below contentString = *node->Text(); } break; @@ -2141,8 +2178,10 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram // Set the text textContent->SetText(contentString, PR_TRUE); - if (textPtr) + if (textPtr) { *textPtr = do_QueryInterface(textContent); + NS_ASSERTION(*textPtr, "must implement nsIDOMCharacterData"); + } // Set aContent as the parent content so that event handling works. textContent->SetParent(aContent); @@ -2153,6 +2192,9 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram // Create a text frame and initialize it NS_NewTextFrame(mPresShell, &textFrame); if (!textFrame) { + // XXX The quotes/counters code doesn't like the text pointer + // being null in case of dynamic changes! + NS_NOTREACHED("this OOM case isn't handled very well"); return NS_ERROR_OUT_OF_MEMORY; } @@ -2160,6 +2202,10 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram nsnull); content = textContent; + } else { + // XXX The quotes/counters code doesn't like the text pointer + // being null in case of dynamic changes! + NS_NOTREACHED("this OOM case isn't handled very well"); } // Return the text frame @@ -6827,6 +6873,11 @@ nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState aState.mFrameManager->RestoreFrameStateFor(aNewFrame, aState.mFrameState); } + if (!aPrevInFlow && + mCounterManager.AddCounterResetsAndIncrements(aNewFrame)) { + CountersDirty(); + } + return rv; } @@ -10481,14 +10532,23 @@ nsCSSFrameConstructor::EndUpdate() mQuoteList.RecalcAll(); mQuotesDirty = PR_FALSE; } + if (mCountersDirty) { + mCounterManager.RecalcAll(); + mCountersDirty = PR_FALSE; + } } } void nsCSSFrameConstructor::WillDestroyFrameTree() { +#if defined(DEBUG_dbaron_off) + mCounterManager.Dump(); +#endif + // Prevent frame tree destruction from being O(N^2) mQuoteList.Clear(); + mCounterManager.Clear(); // Cancel all pending reresolves mRestyleEventQueue = nsnull; diff --git a/mozilla/layout/base/nsCSSFrameConstructor.h b/mozilla/layout/base/nsCSSFrameConstructor.h index 438eefd1c6c..52078f88fdf 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.h +++ b/mozilla/layout/base/nsCSSFrameConstructor.h @@ -41,6 +41,7 @@ #include "nsILayoutHistoryState.h" #include "nsIXBLService.h" #include "nsQuoteList.h" +#include "nsCounterManager.h" #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "plevent.h" @@ -120,7 +121,9 @@ public: nsIContent* aContent2, PRInt32 aStateMask); - void GeneratedContentFrameRemoved(nsIFrame* aFrame); + // Should be called when a frame is going to be destroyed and + // WillDestroyFrameTree hasn't been called yet. + void NotifyDestroyingFrame(nsIFrame* aFrame); nsresult AttributeChanged(nsIContent* aContent, PRInt32 aNameSpaceID, @@ -943,6 +946,13 @@ private: mQuoteList.RecalcAll(); } + void CountersDirty() { + if (mUpdateCount != 0) + mCountersDirty = PR_TRUE; + else + mCounterManager.RecalcAll(); + } + inline NS_HIDDEN_(nsresult) CreateInsertionPointChildren(nsFrameConstructorState &aState, nsIFrame *aNewFrame, @@ -990,8 +1000,10 @@ private: nsIFrame* mDocElementContainingBlock; nsIFrame* mGfxScrollFrame; nsQuoteList mQuoteList; + nsCounterManager mCounterManager; PRUint16 mUpdateCount; PRPackedBool mQuotesDirty; + PRPackedBool mCountersDirty; nsCOMPtr mTempFrameTreeState; diff --git a/mozilla/layout/base/nsCounterManager.cpp b/mozilla/layout/base/nsCounterManager.cpp new file mode 100644 index 00000000000..27187372226 --- /dev/null +++ b/mozilla/layout/base/nsCounterManager.cpp @@ -0,0 +1,336 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// vim:cindent:ai:sw=4:ts=4:et: +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is nsCounterManager. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsCounterManager.h" +#include "nsBulletFrame.h" // legacy location for list style type to text code +#include "nsContentUtils.h" + +// assign the correct |mValueAfter| value to a node that has been inserted +// Should be called immediately after calling |Insert|. +void nsCounterUseNode::Calc(nsCounterList *aList) +{ + mValueAfter = aList->ValueBefore(this); +} + +// assign the correct |mValueAfter| value to a node that has been inserted +// Should be called immediately after calling |Insert|. +void nsCounterChangeNode::Calc(nsCounterList *aList) +{ + if (mType == RESET) { + mValueAfter = mChangeValue; + } else { + NS_ASSERTION(mType == INCREMENT, "invalid type"); + mValueAfter = aList->ValueBefore(this) + mChangeValue; + } +} + +// The text that should be displayed for this counter. +void +nsCounterUseNode::GetText(nsString& aResult) +{ + aResult.Truncate(); + + nsAutoVoidArray stack; + stack.AppendElement(NS_STATIC_CAST(nsCounterNode*, this)); + + if (mAllCounters && mScopeStart) + for (nsCounterNode *n = mScopeStart; n->mScopePrev; n = n->mScopeStart) + stack.AppendElement(n->mScopePrev); + + PRInt32 style = mCounterStyle->Item(mAllCounters ? 2 : 1).GetIntValue(); + const PRUnichar* separator; + if (mAllCounters) + separator = mCounterStyle->Item(1).GetStringBufferValue(); + + for (PRInt32 i = stack.Count() - 1;; --i) { + nsCounterNode *n = NS_STATIC_CAST(nsCounterNode*, stack[i]); + nsBulletFrame::AppendCounterText(style, n->mValueAfter, aResult); + if (i == 0) + break; + NS_ASSERTION(mAllCounters, "yikes, separator is uninitalized"); + aResult.Append(separator); + } +} + +void +nsCounterList::SetScope(nsCounterNode *aNode) +{ + // This function is responsible for setting |mScopeStart| and + // |mScopePrev| (whose purpose is described in nsCounterManager.h). + // We do this by starting from the node immediately preceding + // |aNode| in content tree order, which is reasonably likely to be + // the previous element in our scope (or, for a reset, the previous + // element in the containing scope, which is what we want). If + // we're not in the same scope that it is, then it's too deep in the + // frame tree, so we walk up parent scopes until we find something + // appropriate. + + if (aNode == First()) { + aNode->mScopeStart = nsnull; + aNode->mScopePrev = nsnull; + return; + } + + // Get the content node for aNode's rendering object's *parent*, + // since scope includes siblings, so we want a descendant check on + // parents. If aNode is for a pseudo-element, then the parent + // rendering object is the frame's content; if aNode is for an + // element, then the parent rendering object is the frame's + // content's parent. + nsIContent *nodeContent = aNode->mPseudoFrame->GetContent(); + if (!aNode->mPseudoFrame->GetStyleContext()->GetPseudoType()) { + nodeContent = nodeContent->GetParent(); + } + + for (nsCounterNode *prev = Prev(aNode), *start; + prev; prev = start->mScopePrev) { + // If |prev| starts a scope (because it's a real or implied + // reset), we want it as the scope start rather than the start + // of its enclosing scope. Otherwise, there's no enclosing + // scope, so the next thing in prev's scope shares its scope + // start. + start = (prev->mType == nsCounterNode::RESET || !prev->mScopeStart) + ? prev : prev->mScopeStart; + + // |startContent| is analogous to |nodeContent| (see above). + nsIContent *startContent = start->mPseudoFrame->GetContent(); + if (!start->mPseudoFrame->GetStyleContext()->GetPseudoType()) { + startContent = startContent->GetParent(); + } + NS_ASSERTION(nodeContent || !startContent, + "null check on startContent should be sufficient to " + "null check nodeContent as well, since if nodeContent " + "is for the root, startContent (which is before it) " + "must be too"); + + // A reset's outer scope can't be a scope created by a sibling. + if (!(aNode->mType == nsCounterNode::RESET && + nodeContent == startContent) && + // everything is inside the root (except the case above, + // a second reset on the root) + (!startContent || + nsContentUtils::ContentIsDescendantOf(nodeContent, + startContent))) { + aNode->mScopeStart = start; + aNode->mScopePrev = prev; + return; + } + } + + aNode->mScopeStart = nsnull; + aNode->mScopePrev = nsnull; +} + +void +nsCounterList::RecalcAll() +{ + mDirty = PR_FALSE; + + nsCounterNode *node = First(); + if (!node) + return; + + do { + SetScope(node); + node->Calc(this); + + if (node->mType == nsCounterNode::USE) { + nsCounterUseNode *useNode = node->UseNode(); + // Null-check mText, since if the frame constructor isn't + // batching, we could end up here while the node is being + // constructed. + if (useNode->mText) { + nsAutoString text; + useNode->GetText(text); + useNode->mText->SetData(text); + } + } + } while ((node = Next(node)) != First()); +} + +nsCounterManager::nsCounterManager() +{ + mNames.Init(16); +} + +PRBool +nsCounterManager::AddCounterResetsAndIncrements(nsIFrame *aFrame) +{ + const nsStyleContent *styleContent = aFrame->GetStyleContent(); + if (!styleContent->CounterIncrementCount() && + !styleContent->CounterResetCount()) + return PR_FALSE; + + // Add in order, resets first, so all the comparisons will be optimized + // for addition at the end of the list. + PRInt32 i, i_end; + PRBool dirty = PR_FALSE; + for (i = 0, i_end = styleContent->CounterResetCount(); i != i_end; ++i) + dirty |= AddResetOrIncrement(aFrame, i, + styleContent->GetCounterResetAt(i), + nsCounterChangeNode::RESET); + for (i = 0, i_end = styleContent->CounterIncrementCount(); i != i_end; ++i) + dirty |= AddResetOrIncrement(aFrame, i, + styleContent->GetCounterIncrementAt(i), + nsCounterChangeNode::INCREMENT); + return dirty; +} + +PRBool +nsCounterManager::AddResetOrIncrement(nsIFrame *aFrame, PRInt32 aIndex, + const nsStyleCounterData *aCounterData, + nsCounterNode::Type aType) +{ + nsCounterChangeNode *node = + new nsCounterChangeNode(aFrame, aType, aCounterData->mValue, aIndex); + if (!node) + return PR_FALSE; + + nsCounterList *counterList = CounterListFor(aCounterData->mCounter); + if (!counterList) { + NS_NOTREACHED("CounterListFor failed (should only happen on OOM)"); + return PR_FALSE; + } + + counterList->Insert(node); + if (!counterList->IsLast(node)) { + // Tell the caller it's responsible for recalculating the entire + // list. + return PR_TRUE; + } + node->Calc(counterList); + return PR_FALSE; +} + +nsCounterList* +nsCounterManager::CounterListFor(const nsSubstring& aCounterName) +{ + // XXX Why doesn't nsTHashtable provide an API that allows us to use + // get/put in one hashtable lookup? + nsCounterList *counterList; + if (!mNames.Get(aCounterName, &counterList)) { + counterList = new nsCounterList(); + if (!counterList) + return nsnull; + if (!mNames.Put(aCounterName, counterList)) { + delete counterList; + return nsnull; + } + } + return counterList; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +RecalcDirtyLists(const nsAString& aKey, nsCounterList* aList, void* aClosure) +{ + if (aList->IsDirty()) + aList->RecalcAll(); + return PL_DHASH_NEXT; +} + +void +nsCounterManager::RecalcAll() +{ + mNames.EnumerateRead(RecalcDirtyLists, nsnull); +} + +struct DestroyNodesData { + DestroyNodesData(nsIFrame *aFrame) + : mFrame(aFrame) + , mDestroyedAny(PR_FALSE) + { + } + + nsIFrame *mFrame; + PRBool mDestroyedAny; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +DestroyNodesInList(const nsAString& aKey, nsCounterList* aList, void* aClosure) +{ + DestroyNodesData *data = NS_STATIC_CAST(DestroyNodesData*, aClosure); + if (aList->DestroyNodesFor(data->mFrame)) { + data->mDestroyedAny = PR_TRUE; + aList->SetDirty(); + } + return PL_DHASH_NEXT; +} + +PRBool +nsCounterManager::DestroyNodesFor(nsIFrame *aFrame) +{ + DestroyNodesData data(aFrame); + mNames.EnumerateRead(DestroyNodesInList, &data); + return data.mDestroyedAny; +} + +#ifdef DEBUG +PR_STATIC_CALLBACK(PLDHashOperator) +DumpList(const nsAString& aKey, nsCounterList* aList, void* aClosure) +{ + printf("Counter named \"%s\":\n", NS_ConvertUTF16toUTF8(aKey).get()); + nsCounterNode *node = aList->First(); + + if (node) { + PRInt32 i = 0; + do { + const char *types[] = { "RESET", "INCREMENT", "USE" }; + printf(" Node #%d @%p frame=%p index=%d type=%s valAfter=%d\n" + " scope-start=%p scope-prev=%p", + i++, (void*)node, (void*)node->mPseudoFrame, + node->mContentIndex, types[node->mType], node->mValueAfter, + (void*)node->mScopeStart, (void*)node->mScopePrev); + if (node->mType == nsCounterNode::USE) { + nsAutoString text; + node->UseNode()->GetText(text); + printf(" text=%s", NS_ConvertUTF16toUTF8(text).get()); + } + printf("\n"); + } while ((node = aList->Next(node)) != aList->First()); + } + return PL_DHASH_NEXT; +} + +void +nsCounterManager::Dump() +{ + printf("\n\nCounter Manager Lists:\n"); + mNames.EnumerateRead(DumpList, nsnull); + printf("\n\n"); +} +#endif diff --git a/mozilla/layout/base/nsCounterManager.h b/mozilla/layout/base/nsCounterManager.h new file mode 100644 index 00000000000..a62bf3571b8 --- /dev/null +++ b/mozilla/layout/base/nsCounterManager.h @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// vim:cindent:ai:sw=4:ts=4:et: +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is nsCounterManager. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsCounterManager_h_ +#define nsCounterManager_h_ + +#include "nsGenConList.h" +#include "nsAutoPtr.h" +#include "nsClassHashtable.h" + +class nsCounterList; +struct nsCounterUseNode; +struct nsCounterChangeNode; + +struct nsCounterNode : public nsGenConNode { + enum Type { + RESET, // a "counter number" pair in 'counter-reset' + INCREMENT, // a "counter number" pair in 'counter-increment' + USE // counter() or counters() in 'content' + }; + + Type mType; + + // Counter value after this node + PRInt32 mValueAfter; + + // mScopeStart points to the node (usually a RESET, but not in the + // case of an implied 'counter-reset') that created the scope for + // this element (for a RESET, its outer scope, i.e., the one it is + // inside rather than the one it creates). + + // May be null for all types, but only when mScopePrev is also null. + // Being null for a non-RESET means that it is an implied + // 'counter-reset'. Being null for a RESET means it has no outer + // scope. + nsCounterNode *mScopeStart; + + // mScopePrev points to the previous node that is in the same scope, + // or for a RESET, the previous node in the scope outside of the + // reset. + + // May be null for all types, but only when mScopeStart is also + // null. Following the mScopePrev links will eventually lead to + // mScopeStart. Being null for a non-RESET means that it is an + // implied 'counter-reset'. Being null for a RESET means it has no + // outer scope. + nsCounterNode *mScopePrev; + + inline nsCounterUseNode* UseNode(); + inline nsCounterChangeNode* ChangeNode(); + + // For RESET and INCREMENT nodes, aPseudoFrame need not be a + // pseudo-element, and aContentIndex represents the index within the + // 'counter-reset' or 'counter-increment' property instead of within + // the 'content' property but offset to ensure that (reset, + // increment, use) sort in that order. (This slight weirdness + // allows sharing a lot of code with 'quotes'.) + nsCounterNode(nsIFrame* aPseudoFrame, PRInt32 aContentIndex, Type aType) + : nsGenConNode(aPseudoFrame, aContentIndex) + , mType(aType) + , mValueAfter(0) + , mScopeStart(nsnull) + , mScopePrev(nsnull) + { + } + + // to avoid virtual function calls in the common case + inline void Calc(nsCounterList* aList); +}; + +struct nsCounterUseNode : public nsCounterNode { + // The same structure passed through the style system: an array + // containing the values in the counter() or counters() in the order + // given in the CSS spec. + nsRefPtr mCounterStyle; + + // false for counter(), true for counters() + PRBool mAllCounters; + + // args go directly to member variables here and of nsGenConNode + nsCounterUseNode(nsCSSValue::Array* aCounterStyle, nsIFrame* aPseudoFrame, + PRUint32 aContentIndex, PRBool aAllCounters) + : nsCounterNode(aPseudoFrame, aContentIndex, USE) + , mCounterStyle(aCounterStyle) + , mAllCounters(aAllCounters) + { + NS_ASSERTION(aContentIndex >= 0, "out of range"); + } + + // assign the correct |mValueAfter| value to a node that has been inserted + // Should be called immediately after calling |Insert|. + void Calc(nsCounterList* aList); + + // The text that should be displayed for this counter. + void GetText(nsString& aResult); +}; + +struct nsCounterChangeNode : public nsCounterNode { + PRInt32 mChangeValue; // the numeric value of the increment or reset + + // |aPseudoFrame| is not necessarily a pseudo-element's frame, but + // since it is for every other subclass of nsGenConNode, we follow + // the naming convention here. + // |aPropIndex| is the index of the value within the list in the + // 'counter-increment' or 'counter-reset' property. + nsCounterChangeNode(nsIFrame* aPseudoFrame, + nsCounterNode::Type aChangeType, + PRInt32 aChangeValue, + PRInt32 aPropIndex) + : nsCounterNode(aPseudoFrame, + // Fake a content index for resets and increments + // that comes before all the real content, with + // the resets first, in order, and then the increments. + aPropIndex + (aChangeType == RESET + ? (PR_INT32_MIN) + : (PR_INT32_MIN / 2)), + aChangeType) + , mChangeValue(aChangeValue) + { + NS_ASSERTION(aPropIndex >= 0, "out of range"); + NS_ASSERTION(aChangeType == INCREMENT || aChangeType == RESET, + "bad type"); + } + + // assign the correct |mValueAfter| value to a node that has been inserted + // Should be called immediately after calling |Insert|. + void Calc(nsCounterList* aList); +}; + +inline nsCounterUseNode* nsCounterNode::UseNode() +{ + NS_ASSERTION(mType == USE, "wrong type"); + return NS_STATIC_CAST(nsCounterUseNode*, this); +} + +inline nsCounterChangeNode* nsCounterNode::ChangeNode() +{ + NS_ASSERTION(mType == INCREMENT || mType == RESET, "wrong type"); + return NS_STATIC_CAST(nsCounterChangeNode*, this); +} + +inline void nsCounterNode::Calc(nsCounterList* aList) +{ + if (mType == USE) + UseNode()->Calc(aList); + else + ChangeNode()->Calc(aList); +} + +class nsCounterList : public nsGenConList { +public: + nsCounterList() : nsGenConList() {} + + void Insert(nsCounterNode* aNode) { + nsGenConList::Insert(aNode); + SetScope(aNode); + } + + nsCounterNode* First() { + return NS_STATIC_CAST(nsCounterNode*, mFirstNode); + } + + static nsCounterNode* Next(nsCounterNode* aNode) { + return NS_STATIC_CAST(nsCounterNode*, nsGenConList::Next(aNode)); + } + static nsCounterNode* Prev(nsCounterNode* aNode) { + return NS_STATIC_CAST(nsCounterNode*, nsGenConList::Prev(aNode)); + } + + static PRInt32 ValueBefore(nsCounterNode* aNode) { + return aNode->mScopePrev ? aNode->mScopePrev->mValueAfter : 0; + } + + // Correctly set |aNode->mScopeStart| and |aNode->mScopePrev| + void SetScope(nsCounterNode *aNode); + + // Recalculate |mScopeStart|, |mScopePrev|, and |mValueAfter| for + // all nodes and update text in text content nodes. + void RecalcAll(); + + PRBool IsDirty() { return mDirty; } + void SetDirty() { mDirty = PR_TRUE; } + +private: + PRBool mDirty; +}; + +/** + * The counter manager maintains an |nsCounterList| for each named + * counter to keep track of all scopes with that name. + */ +class nsCounterManager { +public: + nsCounterManager(); + // Returns true if dirty + PRBool AddCounterResetsAndIncrements(nsIFrame *aFrame); + + // Gets the appropriate counter list, creating it if necessary. + // Returns null only on out-of-memory. + nsCounterList* CounterListFor(const nsSubstring& aCounterName); + + // Clean up data in any dirty counter lists. + void RecalcAll(); + + // Destroy nodes for the frame in any lists, and return whether any + // nodes were destroyed. + PRBool DestroyNodesFor(nsIFrame *aFrame); + + // Clear all data. + void Clear() { mNames.Clear(); } + +#ifdef DEBUG + void Dump(); +#endif + +private: + // for |AddCounterResetsAndIncrements| only + PRBool AddResetOrIncrement(nsIFrame *aFrame, PRInt32 aIndex, + const nsStyleCounterData *aCounterData, + nsCounterNode::Type aType); + + nsClassHashtable mNames; +}; + +#endif /* nsCounterManager_h_ */ diff --git a/mozilla/layout/base/nsGenConList.cpp b/mozilla/layout/base/nsGenConList.cpp new file mode 100644 index 00000000000..5a7c6f46011 --- /dev/null +++ b/mozilla/layout/base/nsGenConList.cpp @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:cindent:ts=2:et:sw=2: +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Esben Mose Hansen. + * + * Contributor(s): + * Esben Mose Hansen (original author) + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsGenConList.h" +#include "nsLayoutUtils.h" + +void +nsGenConList::Clear() +{ + //Delete entire list + if (!mFirstNode) + return; + for (nsGenConNode *node = Next(mFirstNode); node != mFirstNode; + node = Next(mFirstNode)) + { + Remove(node); + delete node; + } + delete mFirstNode; + + mFirstNode = nsnull; + mSize = 0; +} + +PRBool +nsGenConList::DestroyNodesFor(nsIFrame* aFrame) +{ + if (!mFirstNode) + return PR_FALSE; // list empty + nsGenConNode* node; + PRBool destroyed = PR_FALSE; + while (mFirstNode->mPseudoFrame == aFrame) { + destroyed = PR_TRUE; + node = Next(mFirstNode); + if (node == mFirstNode) { // Last link + mFirstNode = nsnull; + delete node; + return PR_TRUE; + } + else { + Remove(mFirstNode); + delete mFirstNode; + mFirstNode = node; + } + } + node = Next(mFirstNode); + while (node != mFirstNode) { + if (node->mPseudoFrame == aFrame) { + destroyed = PR_TRUE; + nsGenConNode *nextNode = Next(node); + Remove(node); + delete node; + node = nextNode; + } else { + node = Next(node); + } + } + return destroyed; +} + +// return -1 for ::before, +1 for ::after, and 0 otherwise. +inline PRBool PseudoCompareType(nsIFrame *aFrame) +{ + nsIAtom *pseudo = aFrame->GetStyleContext()->GetPseudoType(); + if (pseudo == nsCSSPseudoElements::before) + return -1; + if (pseudo == nsCSSPseudoElements::after) + return 1; + return 0; +} + +/* static */ PRBool +nsGenConList::NodeAfter(const nsGenConNode* aNode1, const nsGenConNode* aNode2) +{ + nsIFrame *frame1 = aNode1->mPseudoFrame; + nsIFrame *frame2 = aNode2->mPseudoFrame; + if (frame1 == frame2) { + NS_ASSERTION(aNode2->mContentIndex != aNode1->mContentIndex, "identical"); + return aNode1->mContentIndex > aNode2->mContentIndex; + } + PRInt32 pseudoType1 = PseudoCompareType(frame1); + PRInt32 pseudoType2 = PseudoCompareType(frame2); + nsIContent *content1 = frame1->GetContent(); + nsIContent *content2 = frame2->GetContent(); + if (pseudoType1 == 0 || pseudoType2 == 0) { + if (content1 == content2) { + NS_ASSERTION(pseudoType1 != pseudoType2, "identical"); + return pseudoType2 == 0; + } + // We want to treat an element as coming before its :before (preorder + // traversal), so treating both as :before now works. + if (pseudoType1 == 0) pseudoType1 = -1; + if (pseudoType2 == 0) pseudoType2 = -1; + } else { + if (content1 == content2) { + NS_ASSERTION(pseudoType1 != pseudoType2, "identical"); + return pseudoType1 == 1; + } + } + PRInt32 cmp = nsLayoutUtils::DoCompareTreePosition(content1, content2, + pseudoType1, -pseudoType2); + NS_ASSERTION(cmp != 0, "same content, different frames"); + return cmp > 0; +} + +void +nsGenConList::Insert(nsGenConNode* aNode) +{ + if (mFirstNode) { + // Check for append. + if (NodeAfter(aNode, Prev(mFirstNode))) { + PR_INSERT_BEFORE(aNode, mFirstNode); + } + else { + // Binary search. + + // the range of indices at which |aNode| could end up. + PRUint32 first = 0, last = mSize - 1; + + // A cursor to avoid walking more than the length of the list. + nsGenConNode *curNode = Prev(mFirstNode); + PRUint32 curIndex = mSize - 1; + + while (first != last) { + PRUint32 test = (first + last) / 2; + if (last == curIndex) { + for ( ; curIndex != test; --curIndex) + curNode = Prev(curNode); + } else { + for ( ; curIndex != test; ++curIndex) + curNode = Next(curNode); + } + + if (NodeAfter(aNode, curNode)) { + first = test + 1; + // if we exit the loop, we need curNode to be right + ++curIndex; + curNode = Next(curNode); + } else { + last = test; + } + } + PR_INSERT_BEFORE(aNode, curNode); + if (curNode == mFirstNode) { + mFirstNode = aNode; + } + } + } + else { + // initialize list with first node + PR_INIT_CLIST(aNode); + mFirstNode = aNode; + } + ++mSize; +} diff --git a/mozilla/layout/base/nsGenConList.h b/mozilla/layout/base/nsGenConList.h new file mode 100644 index 00000000000..81ebf6347d8 --- /dev/null +++ b/mozilla/layout/base/nsGenConList.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Esben Mose Hansen. + * + * Contributor(s): + * Esben Mose Hansen (original author) + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsGenConList_h___ +#define nsGenConList_h___ + +#include "nsIFrame.h" +#include "nsStyleStruct.h" +#include "prclist.h" +#include "nsIDOMCharacterData.h" +#include "nsCSSPseudoElements.h" + +struct nsGenConNode : public PRCList { + // The wrapper frame for all of the pseudo-element's content. This + // frame generally has useful style data and has the + // NS_FRAME_GENERATED_CONTENT bit set (so we use it to track removal), + // but does not necessarily for |nsCounterChangeNode|s. + nsIFrame* const mPseudoFrame; + + // Index within the list of things specified by the 'content' property, + // which is needed to do 'content: open-quote open-quote' correctly, + // and needed for similar cases for counters. + const PRInt32 mContentIndex; + + // null for 'content:no-open-quote', 'content:no-close-quote' and for + // counter nodes for increments and resets (rather than uses) + nsCOMPtr mText; + + nsGenConNode(nsIFrame* aPseudoFrame, PRInt32 aContentIndex) + : mPseudoFrame(aPseudoFrame) + , mContentIndex(aContentIndex) + { + NS_ASSERTION(aContentIndex < + PRInt32(aPseudoFrame->GetStyleContent()->ContentCount()), + "index out of range"); + // We allow negative values of mContentIndex for 'counter-reset' and + // 'counter-increment'. + + NS_ASSERTION(aContentIndex < 0 || + aPseudoFrame->GetStyleContext()->GetPseudoType() == + nsCSSPseudoElements::before || + aPseudoFrame->GetStyleContext()->GetPseudoType() == + nsCSSPseudoElements::after, + "not :before/:after generated content and not counter change"); + NS_ASSERTION(aContentIndex < 0 || + aPseudoFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT, + "not generated content and not counter change"); + } + + virtual ~nsGenConNode() {} // XXX Avoid, perhaps? +}; + +class nsGenConList { +protected: + nsGenConNode* mFirstNode; + PRUint32 mSize; +public: + nsGenConList() : mFirstNode(nsnull), mSize(0) {} + ~nsGenConList() { Clear(); } + void Clear(); + static nsGenConNode* Next(nsGenConNode* aNode) { + return NS_STATIC_CAST(nsGenConNode*, PR_NEXT_LINK(aNode)); + } + static nsGenConNode* Prev(nsGenConNode* aNode) { + return NS_STATIC_CAST(nsGenConNode*, PR_PREV_LINK(aNode)); + } + void Insert(nsGenConNode* aNode); + // returns whether any nodes have been destroyed + PRBool DestroyNodesFor(nsIFrame* aFrame); //destroy all nodes with aFrame as parent + + // Return true if |aNode1| is after |aNode2|. + static PRBool NodeAfter(const nsGenConNode* aNode1, + const nsGenConNode* aNode2); + + void Remove(nsGenConNode* aNode) { PR_REMOVE_LINK(aNode); mSize--; } + PRBool IsLast(nsGenConNode* aNode) { return (Next(aNode) == mFirstNode); } +}; + +#endif /* nsGenConList_h___ */ diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 99584f11f71..90f1903f123 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -3096,6 +3096,8 @@ NS_IMETHODIMP PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) { if (!mIgnoreFrameDestruction) { + mFrameConstructor->NotifyDestroyingFrame(aFrame); + // Cancel any pending reflow commands targeted at this frame CancelReflowCommandInternal(aFrame, nsnull); diff --git a/mozilla/layout/base/nsQuoteList.cpp b/mozilla/layout/base/nsQuoteList.cpp index 8aa2f45a569..12ef792b0f9 100644 --- a/mozilla/layout/base/nsQuoteList.cpp +++ b/mozilla/layout/base/nsQuoteList.cpp @@ -37,13 +37,10 @@ * ***** END LICENSE BLOCK ***** */ #include "nsQuoteList.h" -#include "nsIDOMCharacterData.h" -#include "nsCSSPseudoElements.h" -#include "nsLayoutUtils.h" #include "nsReadableUtils.h" const nsString* -nsQuoteListNode::Text() +nsQuoteNode::Text() { NS_ASSERTION(mType == eStyleContentType_OpenQuote || mType == eStyleContentType_CloseQuote, @@ -72,9 +69,9 @@ nsQuoteListNode::Text() } void -nsQuoteList::Calc(nsQuoteListNode* aNode) +nsQuoteList::Calc(nsQuoteNode* aNode) { - if (aNode == mFirstNode) { + if (aNode == FirstNode()) { aNode->mDepthBefore = 0; } else { aNode->mDepthBefore = Prev(aNode)->DepthAfter(); @@ -84,7 +81,7 @@ nsQuoteList::Calc(nsQuoteListNode* aNode) void nsQuoteList::RecalcAll() { - nsQuoteListNode *node = mFirstNode; + nsQuoteNode *node = FirstNode(); if (!node) return; @@ -97,7 +94,7 @@ nsQuoteList::RecalcAll() // Next node node = Next(node); - } while (node != mFirstNode); + } while (node != FirstNode()); } #ifdef DEBUG @@ -105,12 +102,12 @@ void nsQuoteList::PrintChain() { printf("Chain: \n"); - if (!mFirstNode) { + if (!FirstNode()) { return; } - nsQuoteListNode* node = mFirstNode; + nsQuoteNode* node = FirstNode(); do { - printf(" %p %d - ", node, node->mDepthBefore); + printf(" %p %d - ", NS_STATIC_CAST(void*, node), node->mDepthBefore); switch(node->mType) { case (eStyleContentType_OpenQuote): printf("open"); @@ -135,145 +132,6 @@ nsQuoteList::PrintChain() } printf("\n"); node = Next(node); - } while (node != mFirstNode); + } while (node != FirstNode()); } #endif - -void -nsQuoteList::Clear() -{ - //Delete entire list - if (!mFirstNode) - return; - for (nsQuoteListNode *node = Next(mFirstNode); node != mFirstNode; - node = Next(mFirstNode)) - { - Remove(node); - delete node; - } - delete mFirstNode; - - mFirstNode = nsnull; - mSize = 0; -} - -PRBool -nsQuoteList::DestroyNodesFor(nsIFrame* aFrame) -{ - if (!mFirstNode) - return PR_FALSE; // list empty - nsQuoteListNode* node; - PRBool destroyed = PR_FALSE; - while (mFirstNode->mPseudoFrame == aFrame) { - destroyed = PR_TRUE; - node = Next(mFirstNode); - if (node == mFirstNode) { // Last link - mFirstNode = nsnull; - delete node; - return PR_TRUE; - } - else { - Remove(mFirstNode); - delete mFirstNode; - mFirstNode = node; - } - } - node = Next(mFirstNode); - while (node != mFirstNode) { - if (node->mPseudoFrame == aFrame) { - destroyed = PR_TRUE; - nsQuoteListNode *nextNode = Next(node); - Remove(node); - delete node; - node = nextNode; - } else { - node = Next(node); - } - } - return destroyed; -} - -// return -1 for ::before and +1 for ::after -inline PRBool PseudoCompareType(nsIFrame *aFrame) -{ - nsIAtom *pseudo = aFrame->GetStyleContext()->GetPseudoType(); - NS_ASSERTION(pseudo == nsCSSPseudoElements::before || - pseudo == nsCSSPseudoElements::after, - "not a pseudo-element frame"); - return pseudo == nsCSSPseudoElements::before ? -1 : 1; -} - -static PRBool NodeAfter(nsQuoteListNode* aNode1, nsQuoteListNode* aNode2) -{ - nsIFrame *frame1 = aNode1->mPseudoFrame; - nsIFrame *frame2 = aNode2->mPseudoFrame; - if (frame1 == frame2) { - NS_ASSERTION(aNode2->mContentIndex != aNode1->mContentIndex, "identical"); - return aNode1->mContentIndex > aNode2->mContentIndex; - } - PRInt32 pseudoType1 = PseudoCompareType(frame1); - PRInt32 pseudoType2 = PseudoCompareType(frame2); - nsIContent *content1 = frame1->GetContent(); - nsIContent *content2 = frame2->GetContent(); - if (content1 == content2) { - NS_ASSERTION(pseudoType1 != pseudoType2, "identical"); - return pseudoType1 == 1; - } - PRInt32 cmp = nsLayoutUtils::DoCompareTreePosition(content1, content2, - pseudoType1, -pseudoType2); - NS_ASSERTION(cmp != 0, "same content, different frames"); - return cmp > 0; -} - -void -nsQuoteList::Insert(nsQuoteListNode* aNode) -{ - if (mFirstNode) { - // Check for append. - if (NodeAfter(aNode, Prev(mFirstNode))) { - PR_INSERT_BEFORE(aNode, mFirstNode); - } - else { - // Binary search. - - // the range of indices at which |aNode| could end up. - PRUint32 first = 0, last = mSize - 1; - - // A cursor to avoid walking more than the length of the list. - nsQuoteListNode *curNode = Prev(mFirstNode); - PRUint32 curIndex = mSize - 1; - - while (first != last) { - PRUint32 test = (first + last) / 2; - if (last == curIndex) { - for ( ; curIndex != test; --curIndex) - curNode = Prev(curNode); - } else { - for ( ; curIndex != test; ++curIndex) - curNode = Next(curNode); - } - - if (NodeAfter(aNode, curNode)) { - first = test + 1; - // if we exit the loop, we need curNode to be right - ++curIndex; - curNode = Next(curNode); - } else { - last = test; - } - } - PR_INSERT_BEFORE(aNode, curNode); - if (curNode == mFirstNode) { - mFirstNode = aNode; - } - } - } - else { - // initialize list with first node - PR_INIT_CLIST(aNode); - mFirstNode = aNode; - } - ++mSize; - - Calc(aNode); -} diff --git a/mozilla/layout/base/nsQuoteList.h b/mozilla/layout/base/nsQuoteList.h index a741685e4d9..db3c4939063 100644 --- a/mozilla/layout/base/nsQuoteList.h +++ b/mozilla/layout/base/nsQuoteList.h @@ -37,54 +37,28 @@ #ifndef nsQuoteList_h___ #define nsQuoteList_h___ -#include "nsIFrame.h" -#include "nsStyleStruct.h" -#include "prclist.h" -#include "nsIDOMCharacterData.h" -#include "nsCSSPseudoElements.h" +#include "nsGenConList.h" -struct nsQuoteListNode : public PRCList { +struct nsQuoteNode : public nsGenConNode { // open-quote, close-quote, no-open-quote, or no-close-quote const nsStyleContentType mType; // Quote depth before this quote, which is always non-negative. PRInt32 mDepthBefore; - // Index within the list of things specified by the 'content' property, - // which is needed to do 'content: open-quote open-quote' correctly. - const PRUint32 mContentIndex; - // null for 'content:no-open-quote', 'content:no-close-quote' - nsCOMPtr mText; - - // The wrapper frame for all of the pseudo-element's content. This - // frame has useful style data and has the NS_FRAME_GENERATED_CONTENT - // bit set (so we use it to track removal). - nsIFrame* const mPseudoFrame; - - - nsQuoteListNode(nsStyleContentType& aType, nsIFrame* aPseudoFrame, - PRUint32 aContentIndex) - : mType(aType) + nsQuoteNode(nsStyleContentType& aType, nsIFrame* aPseudoFrame, + PRUint32 aContentIndex) + : nsGenConNode(aPseudoFrame, aContentIndex) + , mType(aType) , mDepthBefore(0) - , mContentIndex(aContentIndex) - , mPseudoFrame(aPseudoFrame) { NS_ASSERTION(aType == eStyleContentType_OpenQuote || aType == eStyleContentType_CloseQuote || aType == eStyleContentType_NoOpenQuote || aType == eStyleContentType_NoCloseQuote, "incorrect type"); - NS_ASSERTION(aPseudoFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT, - "not generated content"); - NS_ASSERTION(aPseudoFrame->GetStyleContext()->GetPseudoType() == - nsCSSPseudoElements::before || - aPseudoFrame->GetStyleContext()->GetPseudoType() == - nsCSSPseudoElements::after, - "not :before/:after generated content"); - NS_ASSERTION(aContentIndex < - aPseudoFrame->GetStyleContent()->ContentCount(), - "index out of range"); + NS_ASSERTION(aContentIndex >= 0, "out of range"); } // is this 'open-quote' or 'no-open-quote'? @@ -126,28 +100,22 @@ struct nsQuoteListNode : public PRCList { const nsString* Text(); }; -class nsQuoteList { +class nsQuoteList : public nsGenConList { private: - nsQuoteListNode* mFirstNode; - PRUint32 mSize; - // assign the correct |mDepthBefore| value to a node that has been inserted - void Calc(nsQuoteListNode* aNode); + nsQuoteNode* FirstNode() { return NS_STATIC_CAST(nsQuoteNode*, mFirstNode); } public: - nsQuoteList() : mFirstNode(nsnull), mSize(0) {} - ~nsQuoteList() { Clear(); } - void Clear(); - nsQuoteListNode* Next(nsQuoteListNode* aNode) { - return NS_STATIC_CAST(nsQuoteListNode*, PR_NEXT_LINK(aNode)); + // assign the correct |mDepthBefore| value to a node that has been inserted + // Should be called immediately after calling |Insert|. + void Calc(nsQuoteNode* aNode); + + nsQuoteNode* Next(nsQuoteNode* aNode) { + return NS_STATIC_CAST(nsQuoteNode*, nsGenConList::Next(aNode)); } - nsQuoteListNode* Prev(nsQuoteListNode* aNode) { - return NS_STATIC_CAST(nsQuoteListNode*, PR_PREV_LINK(aNode)); + nsQuoteNode* Prev(nsQuoteNode* aNode) { + return NS_STATIC_CAST(nsQuoteNode*, nsGenConList::Prev(aNode)); } - void Insert(nsQuoteListNode* aNode); - // returns whether any nodes have been destroyed - PRBool DestroyNodesFor(nsIFrame* aFrame); //destroy all nodes with aFrame as parent - void Remove(nsQuoteListNode* aNode) { PR_REMOVE_LINK(aNode); mSize--; } + void RecalcAll(); - PRBool IsLast(nsQuoteListNode* aNode) { return (Next(aNode) == mFirstNode); } #ifdef DEBUG void PrintChain(); #endif diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 8ee9080d4a6..6cd7e7705b5 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -6605,7 +6605,7 @@ NS_IMETHODIMP nsBlockFrame::GetAccessible(nsIAccessible** aAccessible) bulletText.Assign(PRUnichar(0x2022));; // Unicode bullet character } else if (myList->mListStyleType != NS_STYLE_LIST_STYLE_NONE) { - mBullet->GetListItemText(aPresContext, *myList, bulletText); + mBullet->GetListItemText(*myList, bulletText); } return accService->CreateHTMLLIAccessible(NS_STATIC_CAST(nsIFrame*, this), @@ -7105,12 +7105,13 @@ nsBlockFrame::SetInitialChildList(nsPresContext* aPresContext, PRBool nsBlockFrame::FrameStartsCounterScope(nsIFrame* aFrame) { - const nsStyleContent* styleContent = aFrame->GetStyleContent(); - if (0 != styleContent->CounterResetCount()) { - // Winner - return PR_TRUE; - } - return PR_FALSE; + if (!mContent->IsContentOfType(nsIContent::eHTML)) + return PR_FALSE; + nsINodeInfo *ni = mContent->GetNodeInfo(); + return ni->Equals(nsHTMLAtoms::ol) || + ni->Equals(nsHTMLAtoms::ul) || + ni->Equals(nsHTMLAtoms::dir) || + ni->Equals(nsHTMLAtoms::menu); } void diff --git a/mozilla/layout/generic/nsBulletFrame.cpp b/mozilla/layout/generic/nsBulletFrame.cpp index 3aed501c87a..ca85502c942 100644 --- a/mozilla/layout/generic/nsBulletFrame.cpp +++ b/mozilla/layout/generic/nsBulletFrame.cpp @@ -249,12 +249,12 @@ nsBulletFrame::Paint(nsPresContext* aPresContext, case NS_STYLE_LIST_STYLE_OLD_DECIMAL: case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO: #ifdef IBMBIDI - GetListItemText(aPresContext, *myList, text); + GetListItemText(*myList, text); charType = eCharType_EuropeanNumber; break; case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC: - if (GetListItemText(aPresContext, *myList, text)) + if (GetListItemText(*myList, text)) charType = eCharType_ArabicNumber; else charType = eCharType_EuropeanNumber; @@ -264,7 +264,7 @@ nsBulletFrame::Paint(nsPresContext* aPresContext, aRenderingContext.GetHints(hints); isBidiSystem = (hints & NS_RENDERING_HINT_BIDI_REORDERING); if (!isBidiSystem) { - if (GetListItemText(aPresContext, *myList, text)) { + if (GetListItemText(*myList, text)) { charType = eCharType_RightToLeft; level = 1; } else { @@ -338,7 +338,7 @@ nsBulletFrame::Paint(nsPresContext* aPresContext, // system, we'll be using "decimal"... PRBool usedChars = #endif // IBMBIDI - GetListItemText(aPresContext, *myList, text); + GetListItemText(*myList, text); #ifdef IBMBIDI if (!usedChars) charType = eCharType_EuropeanNumber; @@ -1106,9 +1106,247 @@ static PRBool EthiopicToText(PRInt32 ordinal, nsString& result) } +/* static */ PRBool +nsBulletFrame::AppendCounterText(PRInt32 aListStyleType, + PRInt32 aOrdinal, + nsString& result) +{ + PRBool success; + + switch (aListStyleType) { + case NS_STYLE_LIST_STYLE_NONE: // used by counters code only + break; + + case NS_STYLE_LIST_STYLE_DISC: // used by counters code only + // XXX We really need to do this the same way we do list bullets. + result.Append(PRUnichar(0x2022)); + break; + + case NS_STYLE_LIST_STYLE_CIRCLE: // used by counters code only + // XXX We really need to do this the same way we do list bullets. + result.Append(PRUnichar(0x25E6)); + break; + + case NS_STYLE_LIST_STYLE_SQUARE: // used by counters code only + // XXX We really need to do this the same way we do list bullets. + result.Append(PRUnichar(0x25FE)); + break; + + case NS_STYLE_LIST_STYLE_DECIMAL: + case NS_STYLE_LIST_STYLE_OLD_DECIMAL: + default: // CSS2 say "A users agent that does not recognize a numbering system + // should use 'decimal' + success = DecimalToText(aOrdinal, result); + break; + + case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO: + success = DecimalLeadingZeroToText(aOrdinal, result); + break; + + case NS_STYLE_LIST_STYLE_LOWER_ROMAN: + case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN: + success = RomanToText(aOrdinal, result, + gLowerRomanCharsA, gLowerRomanCharsB); + break; + case NS_STYLE_LIST_STYLE_UPPER_ROMAN: + case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN: + success = RomanToText(aOrdinal, result, + gUpperRomanCharsA, gUpperRomanCharsB); + break; + + case NS_STYLE_LIST_STYLE_LOWER_ALPHA: + case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA: + success = CharListToText(aOrdinal, result, gLowerAlphaChars, ALPHA_SIZE); + break; + + case NS_STYLE_LIST_STYLE_UPPER_ALPHA: + case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA: + success = CharListToText(aOrdinal, result, gUpperAlphaChars, ALPHA_SIZE); + break; + + case NS_STYLE_LIST_STYLE_KATAKANA: + success = CharListToText(aOrdinal, result, gKatakanaChars, + KATAKANA_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_HIRAGANA: + success = CharListToText(aOrdinal, result, gHiraganaChars, + HIRAGANA_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_KATAKANA_IROHA: + success = CharListToText(aOrdinal, result, gKatakanaIrohaChars, + KATAKANA_IROHA_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA: + success = CharListToText(aOrdinal, result, gHiraganaIrohaChars, + HIRAGANA_IROHA_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_LOWER_GREEK: + success = CharListToText(aOrdinal, result, gLowerGreekChars , + LOWER_GREEK_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: + success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1, + gCJKIdeographicUnit1, + gCJKIdeographic10KUnit1); + break; + + case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: + success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2, + gCJKIdeographicUnit2, + gCJKIdeographic10KUnit1); + break; + + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: + success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1, + gCJKIdeographicUnit1, + gCJKIdeographic10KUnit2); + break; + + case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: + success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit3, + gCJKIdeographicUnit2, + gCJKIdeographic10KUnit2); + break; + + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: + success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit1, + gCJKIdeographicUnit1, + gCJKIdeographic10KUnit3); + break; + + case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: + success = CJKIdeographicToText(aOrdinal, result, gCJKIdeographicDigit2, + gCJKIdeographicUnit2, + gCJKIdeographic10KUnit3); + break; + + case NS_STYLE_LIST_STYLE_HEBREW: + success = HebrewToText(aOrdinal, result); + break; + + case NS_STYLE_LIST_STYLE_ARMENIAN: + success = ArmenianToText(aOrdinal, result); + break; + + case NS_STYLE_LIST_STYLE_GEORGIAN: + success = GeorgianToText(aOrdinal, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC: + success = OtherDecimalToText(aOrdinal, 0x0660, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_PERSIAN: + case NS_STYLE_LIST_STYLE_MOZ_URDU: + success = OtherDecimalToText(aOrdinal, 0x06f0, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI: + success = OtherDecimalToText(aOrdinal, 0x0966, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI: + success = OtherDecimalToText(aOrdinal, 0x0a66, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_GUJARATI: + success = OtherDecimalToText(aOrdinal, 0x0AE6, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_ORIYA: + success = OtherDecimalToText(aOrdinal, 0x0B66, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_KANNADA: + success = OtherDecimalToText(aOrdinal, 0x0CE6, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM: + success = OtherDecimalToText(aOrdinal, 0x0D66, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_THAI: + success = OtherDecimalToText(aOrdinal, 0x0E50, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_LAO: + success = OtherDecimalToText(aOrdinal, 0x0ED0, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_MYANMAR: + success = OtherDecimalToText(aOrdinal, 0x1040, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_KHMER: + success = OtherDecimalToText(aOrdinal, 0x17E0, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_BENGALI: + success = OtherDecimalToText(aOrdinal, 0x09E6, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_TELUGU: + success = OtherDecimalToText(aOrdinal, 0x0C66, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_TAMIL: + success = TamilToText(aOrdinal, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM: + success = CharListToText(aOrdinal, result, gCJKHeavenlyStemChars, + CJK_HEAVENLY_STEM_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH: + success = CharListToText(aOrdinal, result, gCJKEarthlyBranchChars, + CJK_EARTHLY_BRANCH_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_MOZ_HANGUL: + success = CharListToText(aOrdinal, result, gHangulChars, HANGUL_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT: + success = CharListToText(aOrdinal, result, gHangulConsonantChars, + HANGUL_CONSONANT_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME: + success = CharListToText(aOrdinal, result, gEthiopicHalehameChars, + ETHIOPIC_HALEHAME_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC: + success = EthiopicToText(aOrdinal, result); + break; + + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM: + success = CharListToText(aOrdinal, result, gEthiopicHalehameAmChars, + ETHIOPIC_HALEHAME_AM_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER: + success = CharListToText(aOrdinal, result, gEthiopicHalehameTiErChars, + ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE); + break; + + case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET: + success = CharListToText(aOrdinal, result, gEthiopicHalehameTiEtChars, + ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE); + break; + } + return success; +} + PRBool -nsBulletFrame::GetListItemText(nsPresContext* aCX, - const nsStyleList& aListStyle, +nsBulletFrame::GetListItemText(const nsStyleList& aListStyle, nsString& result) { #ifdef IBMBIDI @@ -1121,219 +1359,14 @@ nsBulletFrame::GetListItemText(nsPresContext* aCX, } #endif // IBMBIDI - PRBool success = PR_TRUE; - - switch (aListStyle.mListStyleType) { - case NS_STYLE_LIST_STYLE_DECIMAL: - case NS_STYLE_LIST_STYLE_OLD_DECIMAL: - default: // CSS2 say "A users agent that does not recognize a numbering system - // should use 'decimal' - success = DecimalToText(mOrdinal, result); - break; + NS_ASSERTION(aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_NONE && + aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_DISC && + aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_CIRCLE && + aListStyle.mListStyleType != NS_STYLE_LIST_STYLE_SQUARE, + "we should be using specialized code for these types"); + PRBool success = + AppendCounterText(aListStyle.mListStyleType, mOrdinal, result); - case NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO: - success = DecimalLeadingZeroToText(mOrdinal, result); - break; - - case NS_STYLE_LIST_STYLE_LOWER_ROMAN: - case NS_STYLE_LIST_STYLE_OLD_LOWER_ROMAN: - success = RomanToText(mOrdinal, result, - gLowerRomanCharsA, gLowerRomanCharsB); - break; - case NS_STYLE_LIST_STYLE_UPPER_ROMAN: - case NS_STYLE_LIST_STYLE_OLD_UPPER_ROMAN: - success = RomanToText(mOrdinal, result, - gUpperRomanCharsA, gUpperRomanCharsB); - break; - - case NS_STYLE_LIST_STYLE_LOWER_ALPHA: - case NS_STYLE_LIST_STYLE_OLD_LOWER_ALPHA: - success = CharListToText(mOrdinal, result, gLowerAlphaChars, ALPHA_SIZE); - break; - - case NS_STYLE_LIST_STYLE_UPPER_ALPHA: - case NS_STYLE_LIST_STYLE_OLD_UPPER_ALPHA: - success = CharListToText(mOrdinal, result, gUpperAlphaChars, ALPHA_SIZE); - break; - - case NS_STYLE_LIST_STYLE_KATAKANA: - success = CharListToText(mOrdinal, result, gKatakanaChars, - KATAKANA_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_HIRAGANA: - success = CharListToText(mOrdinal, result, gHiraganaChars, - HIRAGANA_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_KATAKANA_IROHA: - success = CharListToText(mOrdinal, result, gKatakanaIrohaChars, - KATAKANA_IROHA_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_HIRAGANA_IROHA: - success = CharListToText(mOrdinal, result, gHiraganaIrohaChars, - HIRAGANA_IROHA_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_LOWER_GREEK: - success = CharListToText(mOrdinal, result, gLowerGreekChars , - LOWER_GREEK_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_CJK_IDEOGRAPHIC: - case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_INFORMAL: - success = CJKIdeographicToText(mOrdinal, result, gCJKIdeographicDigit1, - gCJKIdeographicUnit1, - gCJKIdeographic10KUnit1); - break; - - case NS_STYLE_LIST_STYLE_MOZ_TRAD_CHINESE_FORMAL: - success = CJKIdeographicToText(mOrdinal, result, gCJKIdeographicDigit2, - gCJKIdeographicUnit2, - gCJKIdeographic10KUnit1); - break; - - case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_INFORMAL: - success = CJKIdeographicToText(mOrdinal, result, gCJKIdeographicDigit1, - gCJKIdeographicUnit1, - gCJKIdeographic10KUnit2); - break; - - case NS_STYLE_LIST_STYLE_MOZ_SIMP_CHINESE_FORMAL: - success = CJKIdeographicToText(mOrdinal, result, gCJKIdeographicDigit3, - gCJKIdeographicUnit2, - gCJKIdeographic10KUnit2); - break; - - case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_INFORMAL: - success = CJKIdeographicToText(mOrdinal, result, gCJKIdeographicDigit1, - gCJKIdeographicUnit1, - gCJKIdeographic10KUnit3); - break; - - case NS_STYLE_LIST_STYLE_MOZ_JAPANESE_FORMAL: - success = CJKIdeographicToText(mOrdinal, result, gCJKIdeographicDigit2, - gCJKIdeographicUnit2, - gCJKIdeographic10KUnit3); - break; - - case NS_STYLE_LIST_STYLE_HEBREW: - success = HebrewToText(mOrdinal, result); - break; - - case NS_STYLE_LIST_STYLE_ARMENIAN: - success = ArmenianToText(mOrdinal, result); - break; - - case NS_STYLE_LIST_STYLE_GEORGIAN: - success = GeorgianToText(mOrdinal, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_ARABIC_INDIC: - success = OtherDecimalToText(mOrdinal, 0x0660, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_PERSIAN: - case NS_STYLE_LIST_STYLE_MOZ_URDU: - success = OtherDecimalToText(mOrdinal, 0x06f0, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_DEVANAGARI: - success = OtherDecimalToText(mOrdinal, 0x0966, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_GURMUKHI: - success = OtherDecimalToText(mOrdinal, 0x0a66, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_GUJARATI: - success = OtherDecimalToText(mOrdinal, 0x0AE6, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_ORIYA: - success = OtherDecimalToText(mOrdinal, 0x0B66, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_KANNADA: - success = OtherDecimalToText(mOrdinal, 0x0CE6, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_MALAYALAM: - success = OtherDecimalToText(mOrdinal, 0x0D66, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_THAI: - success = OtherDecimalToText(mOrdinal, 0x0E50, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_LAO: - success = OtherDecimalToText(mOrdinal, 0x0ED0, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_MYANMAR: - success = OtherDecimalToText(mOrdinal, 0x1040, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_KHMER: - success = OtherDecimalToText(mOrdinal, 0x17E0, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_BENGALI: - success = OtherDecimalToText(mOrdinal, 0x09E6, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_TELUGU: - success = OtherDecimalToText(mOrdinal, 0x0C66, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_TAMIL: - success = TamilToText(mOrdinal, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_CJK_HEAVENLY_STEM: - success = CharListToText(mOrdinal, result, gCJKHeavenlyStemChars, - CJK_HEAVENLY_STEM_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_MOZ_CJK_EARTHLY_BRANCH: - success = CharListToText(mOrdinal, result, gCJKEarthlyBranchChars, - CJK_EARTHLY_BRANCH_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_MOZ_HANGUL: - success = CharListToText(mOrdinal, result, gHangulChars, HANGUL_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_MOZ_HANGUL_CONSONANT: - success = CharListToText(mOrdinal, result, gHangulConsonantChars, - HANGUL_CONSONANT_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME: - success = CharListToText(mOrdinal, result, gEthiopicHalehameChars, - ETHIOPIC_HALEHAME_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_NUMERIC: - success = EthiopicToText(mOrdinal, result); - break; - - case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM: - success = CharListToText(mOrdinal, result, gEthiopicHalehameAmChars, - ETHIOPIC_HALEHAME_AM_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER: - success = CharListToText(mOrdinal, result, gEthiopicHalehameTiErChars, - ETHIOPIC_HALEHAME_TI_ER_CHARS_SIZE); - break; - - case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET: - success = CharListToText(mOrdinal, result, gEthiopicHalehameTiEtChars, - ETHIOPIC_HALEHAME_TI_ET_CHARS_SIZE); - break; - } // XXX For some of these systems, "." is wrong! This should really be // pushed up into the cases... #ifdef IBMBIDI @@ -1545,7 +1578,7 @@ nsBulletFrame::GetDesiredSize(nsPresContext* aCX, case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_AM: case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ER: case NS_STYLE_LIST_STYLE_MOZ_ETHIOPIC_HALEHAME_TI_ET: - GetListItemText(aCX, *myList, text); + GetListItemText(*myList, text); fm->GetHeight(aMetrics.height); aReflowState.rendContext->SetFont(fm); aReflowState.rendContext->GetWidth(text, aMetrics.width); diff --git a/mozilla/layout/generic/nsBulletFrame.h b/mozilla/layout/generic/nsBulletFrame.h index fcebde686ff..af3cf6b2c29 100644 --- a/mozilla/layout/generic/nsBulletFrame.h +++ b/mozilla/layout/generic/nsBulletFrame.h @@ -87,10 +87,14 @@ public: gfxIImageFrame *aNewframe, nsRect *aDirtyRect); - PRBool GetListItemText(nsPresContext* aCX, - const nsStyleList& aStyleList, - nsString& aResult); + /* get list item text, without '.' */ + static PRBool AppendCounterText(PRInt32 aListStyleType, + PRInt32 aOrdinal, + nsString& aResult); + /* get list item text, with '.' */ + PRBool GetListItemText(const nsStyleList& aStyleList, + nsString& aResult); protected: void GetDesiredSize(nsPresContext* aPresContext, diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 2cb9a6a9e85..3d83c5c81c8 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -648,15 +648,6 @@ nsFrame::Destroy(nsPresContext* aPresContext) } } - // If the frame contains generated context, remove it from - // the quoteList. - if (mState & NS_FRAME_GENERATED_CONTENT) { - shell->FrameConstructor()->GeneratedContentFrameRemoved(this); - } - - // XXX Rather than always doing this it would be better if it was part of - // a frame observer mechanism and the pres shell could register as an - // observer of the frame while the reflow command is pending... shell->NotifyDestroyingFrame(this); if ((mState & NS_FRAME_EXTERNAL_REFERENCE) || diff --git a/mozilla/layout/style/html.css b/mozilla/layout/style/html.css index b67d1b6d4ed..dae695ee81c 100644 --- a/mozilla/layout/style/html.css +++ b/mozilla/layout/style/html.css @@ -322,7 +322,6 @@ ul, menu, dir { list-style-type: disc; margin: 1em 0; -moz-padding-start: 40px; - -moz-counter-reset: -html-counter 0; } ol { @@ -330,7 +329,6 @@ ol { list-style-type: decimal; margin: 1em 0; -moz-padding-start: 40px; - -moz-counter-reset: -html-counter 0; } li { diff --git a/mozilla/layout/style/nsCSSDeclaration.cpp b/mozilla/layout/style/nsCSSDeclaration.cpp index eed01cf191f..06cb77b6847 100644 --- a/mozilla/layout/style/nsCSSDeclaration.cpp +++ b/mozilla/layout/style/nsCSSDeclaration.cpp @@ -301,20 +301,39 @@ PRBool nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty, const n return PR_FALSE; } - if ((eCSSUnit_String <= unit) && (unit <= eCSSUnit_Counters)) { - switch (unit) { - case eCSSUnit_Attr: aResult.AppendLiteral("attr("); - break; - case eCSSUnit_Counter: aResult.AppendLiteral("counter("); - break; - case eCSSUnit_Counters: aResult.AppendLiteral("counters("); - break; - default: break; + if (eCSSUnit_String <= unit && unit <= eCSSUnit_Attr) { + if (unit == eCSSUnit_Attr) { + aResult.AppendLiteral("attr("); } nsAutoString buffer; aValue.GetStringValue(buffer); aResult.Append(buffer); } + else if (eCSSUnit_Array <= unit && unit <= eCSSUnit_Counters) { + switch (unit) { + case eCSSUnit_Counter: aResult.AppendLiteral("counter("); break; + case eCSSUnit_Counters: aResult.AppendLiteral("counters("); break; + default: break; + } + + nsCSSValue::Array *array = aValue.GetArrayValue(); + PRBool mark = PR_FALSE; + for (PRUint16 i = 0, i_end = array->Count(); i < i_end; ++i) { + if (mark && array->Item(i).GetUnit() != eCSSUnit_Null) { + if (unit == eCSSUnit_Array) + aResult.AppendLiteral(" "); + else + aResult.AppendLiteral(", "); + } + nsCSSProperty prop = + ((eCSSUnit_Counter <= unit && unit <= eCSSUnit_Counters) && + i == array->Count() - 1) + ? eCSSProperty_list_style_type : aProperty; + if (AppendCSSValueToString(prop, array->Item(i), aResult)) { + mark = PR_TRUE; + } + } + } else if (eCSSUnit_Integer == unit) { switch (aProperty) { case eCSSProperty_color: @@ -440,6 +459,7 @@ PRBool nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty, const n case eCSSUnit_String: break; case eCSSUnit_URL: break; case eCSSUnit_Image: break; + case eCSSUnit_Array: break; case eCSSUnit_Attr: case eCSSUnit_Counter: case eCSSUnit_Counters: aResult.Append(PRUnichar(')')); break; diff --git a/mozilla/layout/style/nsCSSParser.cpp b/mozilla/layout/style/nsCSSParser.cpp index c1f6f17b9e3..3d1173176ee 100644 --- a/mozilla/layout/style/nsCSSParser.cpp +++ b/mozilla/layout/style/nsCSSParser.cpp @@ -79,8 +79,6 @@ #include "prprf.h" #include "math.h" -//#define ENABLE_COUNTERS // un-comment this to enable counters (bug 15174) - //---------------------------------------------------------------------- // Your basic top-down recursive descent style parser @@ -166,6 +164,7 @@ protected: void SkipRuleSet(nsresult& aErrorCode); PRBool SkipAtRule(nsresult& aErrorCode); PRBool SkipDeclaration(nsresult& aErrorCode, PRBool aCheckForBraces); + PRBool GetNonCloseParenToken(nsresult& aErrorCode, PRBool aSkipWS); PRBool PushGroup(nsICSSGroupRule* aRule); void PopGroup(void); @@ -284,10 +283,6 @@ protected: nsCSSProperty aPropID); PRBool DoParseRect(nsCSSRect& aRect, nsresult& aErrorCode); PRBool ParseContent(nsresult& aErrorCode); - PRBool SetSingleCounterValue(nsCSSCounterData** aResult, - nsresult& aErrorCode, - nsCSSProperty aPropID, - const nsCSSValue& aValue); PRBool ParseCounterData(nsresult& aErrorCode, nsCSSCounterData** aResult, nsCSSProperty aPropID); @@ -1531,6 +1526,17 @@ void CSSParserImpl::SkipUntil(nsresult& aErrorCode, PRUnichar aStopSymbol) } } +PRBool CSSParserImpl::GetNonCloseParenToken(nsresult& aErrorCode, PRBool aSkipWS) +{ + if (!GetToken(aErrorCode, aSkipWS)) + return PR_FALSE; + if (mToken.mType == eCSSToken_Symbol && mToken.mSymbol == ')') { + UngetToken(); + return PR_FALSE; + } + return PR_TRUE; +} + PRBool CSSParserImpl::SkipDeclaration(nsresult& aErrorCode, PRBool aCheckForBraces) { @@ -3598,21 +3604,12 @@ PRBool CSSParserImpl::ParseVariant(nsresult& aErrorCode, nsCSSValue& aValue, (eCSSToken_Function == tk->mType) && (tk->mIdent.LowerCaseEqualsLiteral("counter") || tk->mIdent.LowerCaseEqualsLiteral("counters"))) { -#ifdef ENABLE_COUNTERS - if (ParseCounter(aErrorCode, aValue)) { - return PR_TRUE; - } -#endif - return PR_FALSE; + return ParseCounter(aErrorCode, aValue); } if (((aVariantMask & VARIANT_ATTR) != 0) && (eCSSToken_Function == tk->mType) && tk->mIdent.LowerCaseEqualsLiteral("attr")) { - - if (ParseAttr(aErrorCode, aValue)) { - return PR_TRUE; - } - return PR_FALSE; + return ParseAttr(aErrorCode, aValue); } UngetToken(); @@ -3625,59 +3622,66 @@ PRBool CSSParserImpl::ParseCounter(nsresult& aErrorCode, nsCSSValue& aValue) nsCSSUnit unit = (mToken.mIdent.LowerCaseEqualsLiteral("counter") ? eCSSUnit_Counter : eCSSUnit_Counters); - if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) { - if (GetToken(aErrorCode, PR_TRUE)) { - if (eCSSToken_Ident == mToken.mType) { - nsAutoString counter; - counter.Append(mToken.mIdent); + if (!ExpectSymbol(aErrorCode, '(', PR_FALSE)) + return PR_FALSE; - if (eCSSUnit_Counters == unit) { - // get mandatory string - if (! ExpectSymbol(aErrorCode, ',', PR_TRUE)) { - return PR_FALSE; - } - if (GetToken(aErrorCode, PR_TRUE) && (eCSSToken_String == mToken.mType)) { - counter.Append(PRUnichar(',')); - counter.Append(mToken.mSymbol); // quote too - counter.Append(mToken.mIdent); - counter.Append(mToken.mSymbol); // quote too - } - else { - UngetToken(); - return PR_FALSE; - } - } - // get optional type - if (ExpectSymbol(aErrorCode, ',', PR_TRUE)) { - if (GetToken(aErrorCode, PR_TRUE) && (eCSSToken_Ident == mToken.mType)) { - nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); - PRInt32 dummy; - if ((eCSSKeyword_UNKNOWN < keyword) && - nsCSSProps::FindKeyword(keyword, nsCSSProps::kListStyleKTable, dummy)) { - counter.Append(PRUnichar(',')); - counter.Append(mToken.mIdent); - } - else { - return PR_FALSE; - } - } - else { - UngetToken(); - return PR_FALSE; - } - } + if (!GetNonCloseParenToken(aErrorCode, PR_TRUE) || + eCSSToken_Ident != mToken.mType) { + SkipUntil(aErrorCode, ')'); + return PR_FALSE; + } - if (ExpectSymbol(aErrorCode, ')', PR_TRUE)) { - aValue.SetStringValue(counter, unit); - return PR_TRUE; - } - } - else { - UngetToken(); + nsRefPtr val = + nsCSSValue::Array::Create(unit == eCSSUnit_Counter ? 2 : 3); + if (!val) { + aErrorCode = NS_ERROR_OUT_OF_MEMORY; + return PR_FALSE; + } + + val->Item(0).SetStringValue(mToken.mIdent, eCSSUnit_String); + + if (eCSSUnit_Counters == unit) { + // get mandatory separator string + if (!ExpectSymbol(aErrorCode, ',', PR_TRUE) || + !(GetNonCloseParenToken(aErrorCode, PR_TRUE) && + eCSSToken_String == mToken.mType)) { + SkipUntil(aErrorCode, ')'); + return PR_FALSE; + } + val->Item(1).SetStringValue(mToken.mIdent, eCSSUnit_String); + } + + // get optional type + PRInt32 type = NS_STYLE_LIST_STYLE_DECIMAL; + if (ExpectSymbol(aErrorCode, ',', PR_TRUE)) { + nsCSSKeyword keyword; + PRBool success = GetNonCloseParenToken(aErrorCode, PR_TRUE) && + eCSSToken_Ident == mToken.mType && + (keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent)) != + eCSSKeyword_UNKNOWN; + if (success) { + if (keyword == eCSSKeyword_none) { + type = NS_STYLE_LIST_STYLE_NONE; + } else { + success = nsCSSProps::FindKeyword(keyword, + nsCSSProps::kListStyleKTable, type); } } + if (!success) { + SkipUntil(aErrorCode, ')'); + return PR_FALSE; + } } - return PR_FALSE; + PRInt32 typeItem = eCSSUnit_Counters == unit ? 2 : 1; + val->Item(typeItem).SetIntValue(type, eCSSUnit_Enumerated); + + if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) { + SkipUntil(aErrorCode, ')'); + return PR_FALSE; + } + + aValue.SetArrayValue(val, unit); + return PR_TRUE; } PRBool CSSParserImpl::ParseAttr(nsresult& aErrorCode, nsCSSValue& aValue) @@ -3993,10 +3997,10 @@ PRBool CSSParserImpl::ParseProperty(nsresult& aErrorCode, eCSSProperty_clip); case eCSSProperty_content: return ParseContent(aErrorCode); - case eCSSProperty__moz_counter_increment: + case eCSSProperty_counter_increment: return ParseCounterData(aErrorCode, &mTempData.mContent.mCounterIncrement, aPropID); - case eCSSProperty__moz_counter_reset: + case eCSSProperty_counter_reset: return ParseCounterData(aErrorCode, &mTempData.mContent.mCounterReset, aPropID); case eCSSProperty_cue: @@ -4144,8 +4148,8 @@ PRBool CSSParserImpl::ParseSingleValueProperty(nsresult& aErrorCode, case eCSSProperty__moz_border_radius: case eCSSProperty_clip: case eCSSProperty_content: - case eCSSProperty__moz_counter_increment: - case eCSSProperty__moz_counter_reset: + case eCSSProperty_counter_increment: + case eCSSProperty_counter_reset: case eCSSProperty_cue: case eCSSProperty_cursor: case eCSSProperty_font: @@ -5069,6 +5073,7 @@ CSSParserImpl::DoParseRect(nsCSSRect& aRect, nsresult& aErrorCode) VARIANT_KEYWORD) PRBool CSSParserImpl::ParseContent(nsresult& aErrorCode) { + // XXX Rewrite to make it look more like ParseCursor or ParseCounterData? nsCSSValue value; if (ParseVariant(aErrorCode, value, VARIANT_CONTENT | VARIANT_INHERIT | VARIANT_NORMAL, @@ -5113,22 +5118,10 @@ PRBool CSSParserImpl::ParseContent(nsresult& aErrorCode) return PR_FALSE; } -PRBool -CSSParserImpl::SetSingleCounterValue(nsCSSCounterData** aResult, - nsresult& aErrorCode, - nsCSSProperty aPropID, - const nsCSSValue& aValue) -{ - nsCSSCounterData* dataHead = new nsCSSCounterData(); - if (!dataHead) { - aErrorCode = NS_ERROR_OUT_OF_MEMORY; - return PR_FALSE; - } - dataHead->mCounter = aValue; - *aResult = dataHead; - mTempData.SetPropertyBit(aPropID); - return PR_TRUE; -} +struct SingleCounterPropValue { + char str[13]; + nsCSSUnit unit; +}; PRBool CSSParserImpl::ParseCounterData(nsresult& aErrorCode, nsCSSCounterData** aResult, @@ -5138,74 +5131,59 @@ PRBool CSSParserImpl::ParseCounterData(nsresult& aErrorCode, if (nsnull == ident) { return PR_FALSE; } - if (ident->LowerCaseEqualsLiteral("none")) { - if (ExpectEndProperty(aErrorCode, PR_TRUE)) { - return SetSingleCounterValue(aResult, aErrorCode, aPropID, - nsCSSValue(eCSSUnit_None)); - } - return PR_FALSE; - } - else if (ident->LowerCaseEqualsLiteral("inherit")) { - if (ExpectEndProperty(aErrorCode, PR_TRUE)) { - return SetSingleCounterValue(aResult, aErrorCode, aPropID, - nsCSSValue(eCSSUnit_Inherit)); - } - return PR_FALSE; - } - else if (ident->LowerCaseEqualsLiteral("-moz-initial")) { - if (ExpectEndProperty(aErrorCode, PR_TRUE)) { - return SetSingleCounterValue(aResult, aErrorCode, aPropID, - nsCSSValue(eCSSUnit_Initial)); - } - return PR_FALSE; - } - else { - nsCSSCounterData* dataHead = new nsCSSCounterData(); - nsCSSCounterData* data = dataHead; - if (nsnull == data) { - aErrorCode = NS_ERROR_OUT_OF_MEMORY; - return PR_FALSE; - } - data->mCounter.SetStringValue(*ident, eCSSUnit_String); - - while (nsnull != data) { + static const SingleCounterPropValue singleValues[] = { + { "none", eCSSUnit_None }, + { "inherit", eCSSUnit_Inherit }, + { "-moz-initial", eCSSUnit_Initial } + }; + for (const SingleCounterPropValue *sv = singleValues, + *sv_end = singleValues + NS_ARRAY_LENGTH(singleValues); + sv != sv_end; ++sv) { + if (ident->LowerCaseEqualsLiteral(sv->str)) { if (ExpectEndProperty(aErrorCode, PR_TRUE)) { - mTempData.SetPropertyBit(aPropID); + nsCSSCounterData* dataHead = new nsCSSCounterData(); + if (!dataHead) { + aErrorCode = NS_ERROR_OUT_OF_MEMORY; + return PR_FALSE; + } + dataHead->mCounter = nsCSSValue(sv->unit); *aResult = dataHead; - aErrorCode = NS_OK; + mTempData.SetPropertyBit(aPropID); return PR_TRUE; } - if (! GetToken(aErrorCode, PR_TRUE)) { - break; - } - if ((eCSSToken_Number == mToken.mType) && (mToken.mIntegerValid)) { + return PR_FALSE; + } + } + UngetToken(); // undo NextIdent + + nsCSSCounterData* dataHead = nsnull; + nsCSSCounterData **next = &dataHead; + for (;;) { + if (!GetToken(aErrorCode, PR_TRUE) || mToken.mType != eCSSToken_Ident) { + break; + } + nsCSSCounterData *data = *next = new nsCSSCounterData(); + if (!data) { + aErrorCode = NS_ERROR_OUT_OF_MEMORY; + break; + } + next = &data->mNext; + data->mCounter.SetStringValue(mToken.mIdent, eCSSUnit_String); + if (GetToken(aErrorCode, PR_TRUE)) { + if (eCSSToken_Number == mToken.mType && mToken.mIntegerValid) { data->mValue.SetIntValue(mToken.mInteger, eCSSUnit_Integer); - if (ExpectEndProperty(aErrorCode, PR_TRUE)) { - mTempData.SetPropertyBit(aPropID); - *aResult = dataHead; - aErrorCode = NS_OK; - return PR_TRUE; - } - if (! GetToken(aErrorCode, PR_TRUE)) { - break; - } - } - if (eCSSToken_Ident == mToken.mType) { - data->mNext = new nsCSSCounterData(); - data = data->mNext; - if (nsnull != data) { - data->mCounter.SetStringValue(mToken.mIdent, eCSSUnit_String); - } - else { - aErrorCode = NS_ERROR_OUT_OF_MEMORY; - } - } - else { - break; + } else { + UngetToken(); } } - delete dataHead; + if (ExpectEndProperty(aErrorCode, PR_TRUE)) { + mTempData.SetPropertyBit(aPropID); + *aResult = dataHead; + aErrorCode = NS_OK; + return PR_TRUE; + } } + delete dataHead; return PR_FALSE; } @@ -5435,7 +5413,7 @@ PRBool CSSParserImpl::ParseFamily(nsresult& aErrorCode, nsCSSValue& aValue) family.Append(PRUnichar(',')); } family.Append(tk->mSymbol); // replace the quotes - family.Append(tk->mIdent); + family.Append(tk->mIdent); // XXX What if it had escaped quotes? family.Append(tk->mSymbol); firstOne = PR_FALSE; } else if (eCSSToken_Symbol == tk->mType) { diff --git a/mozilla/layout/style/nsCSSPropList.h b/mozilla/layout/style/nsCSSPropList.h index b5514e4eb5f..863c7ed30bb 100644 --- a/mozilla/layout/style/nsCSSPropList.h +++ b/mozilla/layout/style/nsCSSPropList.h @@ -323,10 +323,8 @@ CSS_PROP_COLUMN(-moz-column-count, _moz_column_count, MozColumnCount, Column, mC CSS_PROP_COLUMN(-moz-column-width, _moz_column_width, MozColumnWidth, Column, mColumnWidth, eCSSType_Value, nsnull) CSS_PROP_COLUMN(-moz-column-gap, _moz_column_gap, MozColumnGap, Column, mColumnGap, eCSSType_Value, nsnull) CSS_PROP_CONTENT(content, content, Content, Content, mContent, eCSSType_ValueList, kContentKTable) -CSS_PROP_NOTIMPLEMENTED(counter-increment, counter_increment, CounterIncrement) -CSS_PROP_NOTIMPLEMENTED(counter-reset, counter_reset, CounterReset) -CSS_PROP_CONTENT(-moz-counter-increment, _moz_counter_increment, MozCounterIncrement, Content, mCounterIncrement, eCSSType_CounterData, nsnull) // XXX bug 137285 -CSS_PROP_CONTENT(-moz-counter-reset, _moz_counter_reset, MozCounterReset, Content, mCounterReset, eCSSType_CounterData, nsnull) // XXX bug 137285 +CSS_PROP_CONTENT(counter-increment, counter_increment, CounterIncrement, Content, mCounterIncrement, eCSSType_CounterData, nsnull) // XXX bug 137285 +CSS_PROP_CONTENT(counter-reset, counter_reset, CounterReset, Content, mCounterReset, eCSSType_CounterData, nsnull) // XXX bug 137285 CSS_PROP_SHORTHAND(cue, cue, Cue) CSS_PROP_BACKENDONLY(cue-after, cue_after, CueAfter, Aural, mCueAfter, eCSSType_Value, nsnull) CSS_PROP_BACKENDONLY(cue-before, cue_before, CueBefore, Aural, mCueBefore, eCSSType_Value, nsnull) diff --git a/mozilla/layout/style/nsCSSStruct.cpp b/mozilla/layout/style/nsCSSStruct.cpp index 76c4a924740..7045af3352b 100644 --- a/mozilla/layout/style/nsCSSStruct.cpp +++ b/mozilla/layout/style/nsCSSStruct.cpp @@ -990,13 +990,13 @@ void nsCSSContent::List(FILE* out, PRInt32 aIndent) const } nsCSSCounterData* counter = mCounterIncrement; while (nsnull != counter) { - counter->mCounter.AppendToString(buffer, eCSSProperty__moz_counter_increment); + counter->mCounter.AppendToString(buffer, eCSSProperty_counter_increment); counter->mValue.AppendToString(buffer, eCSSProperty_UNKNOWN); counter = counter->mNext; } counter = mCounterReset; while (nsnull != counter) { - counter->mCounter.AppendToString(buffer, eCSSProperty__moz_counter_reset); + counter->mCounter.AppendToString(buffer, eCSSProperty_counter_reset); counter->mValue.AppendToString(buffer, eCSSProperty_UNKNOWN); counter = counter->mNext; } diff --git a/mozilla/layout/style/nsCSSStruct.h b/mozilla/layout/style/nsCSSStruct.h index bd097de8bd2..1504fa923e4 100644 --- a/mozilla/layout/style/nsCSSStruct.h +++ b/mozilla/layout/style/nsCSSStruct.h @@ -77,6 +77,7 @@ struct nsRuleDataFont : public nsCSSFont { PRBool mFamilyFromHTML; // Is the family from an HTML FONT element }; +// Prefer nsCSSValue::Array for lists of fixed size. struct nsCSSValueList { nsCSSValueList(void); nsCSSValueList(const nsCSSValueList& aCopy); @@ -111,6 +112,7 @@ struct nsCSSColor : public nsCSSStruct { struct nsRuleDataColor : public nsCSSColor { }; +// Should be replaced with nsCSSValue::List. struct nsCSSShadow { nsCSSShadow(void); nsCSSShadow(const nsCSSShadow& aCopy); @@ -431,6 +433,7 @@ struct nsCSSPage : public nsCSSStruct { // NEW struct nsRuleDataPage : public nsCSSPage { }; +// Should be replaced with nsCSSValue::List. struct nsCSSCounterData { nsCSSCounterData(void); nsCSSCounterData(const nsCSSCounterData& aCopy); @@ -443,6 +446,7 @@ struct nsCSSCounterData { nsCSSCounterData* mNext; }; +// Should be replaced with nsCSSValue::List. struct nsCSSQuotes { nsCSSQuotes(void); nsCSSQuotes(const nsCSSQuotes& aCopy); diff --git a/mozilla/layout/style/nsCSSValue.cpp b/mozilla/layout/style/nsCSSValue.cpp index 5a83e3f4389..97d3b729f41 100644 --- a/mozilla/layout/style/nsCSSValue.cpp +++ b/mozilla/layout/style/nsCSSValue.cpp @@ -79,8 +79,8 @@ nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit) nsCSSValue::nsCSSValue(const nsAString& aValue, nsCSSUnit aUnit) : mUnit(aUnit) { - NS_ASSERTION((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Counters), "not a string value"); - if ((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Counters)) { + NS_ASSERTION((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr), "not a string value"); + if ((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr)) { mValue.mString = ToNewUnicode(aValue); } else { @@ -95,6 +95,15 @@ nsCSSValue::nsCSSValue(nscolor aValue) mValue.mColor = aValue; } +nsCSSValue::nsCSSValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit) + : mUnit(aUnit) +{ + NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Counters, + "bad unit"); + mValue.mArray = aValue; + mValue.mArray->AddRef(); +} + nsCSSValue::nsCSSValue(nsCSSValue::URL* aValue) : mUnit(eCSSUnit_URL) { @@ -112,7 +121,7 @@ nsCSSValue::nsCSSValue(nsCSSValue::Image* aValue) nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) : mUnit(aCopy.mUnit) { - if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Counters)) { + if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Attr)) { if (nsnull != aCopy.mValue.mString) { mValue.mString = nsCRT::strdup(aCopy.mValue.mString); } @@ -126,6 +135,10 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) else if (eCSSUnit_Color == mUnit){ mValue.mColor = aCopy.mValue.mColor; } + else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) { + mValue.mArray = aCopy.mValue.mArray; + mValue.mArray->AddRef(); + } else if (eCSSUnit_URL == mUnit){ mValue.mURL = aCopy.mValue.mURL; mValue.mURL->AddRef(); @@ -148,7 +161,7 @@ nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) { Reset(); mUnit = aCopy.mUnit; - if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Counters)) { + if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Attr)) { if (nsnull != aCopy.mValue.mString) { mValue.mString = nsCRT::strdup(aCopy.mValue.mString); } @@ -159,6 +172,10 @@ nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) else if (eCSSUnit_Color == mUnit){ mValue.mColor = aCopy.mValue.mColor; } + else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) { + mValue.mArray = aCopy.mValue.mArray; + mValue.mArray->AddRef(); + } else if (eCSSUnit_URL == mUnit){ mValue.mURL = aCopy.mValue.mURL; mValue.mURL->AddRef(); @@ -176,7 +193,7 @@ nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const { if (mUnit == aOther.mUnit) { - if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Counters)) { + if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Attr)) { if (nsnull == mValue.mString) { if (nsnull == aOther.mValue.mString) { return PR_TRUE; @@ -192,6 +209,9 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const else if (eCSSUnit_Color == mUnit) { return mValue.mColor == aOther.mValue.mColor; } + else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) { + return *mValue.mArray == *aOther.mValue.mArray; + } else if (eCSSUnit_URL == mUnit) { return *mValue.mURL == *aOther.mValue.mURL; } @@ -281,9 +301,9 @@ void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit) void nsCSSValue::SetStringValue(const nsAString& aValue, nsCSSUnit aUnit) { - NS_ASSERTION((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Counters), "not a string unit"); + NS_ASSERTION((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr), "not a string unit"); Reset(); - if ((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Counters)) { + if ((eCSSUnit_String <= aUnit) && (aUnit <= eCSSUnit_Attr)) { mUnit = aUnit; mValue.mString = ToNewUnicode(aValue); } @@ -296,6 +316,16 @@ void nsCSSValue::SetColorValue(nscolor aValue) mValue.mColor = aValue; } +void nsCSSValue::SetArrayValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit) +{ + NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Counters, + "bad unit"); + Reset(); + mUnit = aUnit; + mValue.mArray = aValue; + mValue.mArray->AddRef(); +} + void nsCSSValue::SetURLValue(nsCSSValue::URL* aValue) { Reset(); @@ -415,7 +445,7 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, case eCSSUnit_Counters: aBuffer.AppendLiteral("counters("); break; default: break; } - if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Counters)) { + if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Attr)) { if (nsnull != mValue.mString) { aBuffer.Append(PRUnichar('"')); aBuffer.Append(mValue.mString); @@ -465,6 +495,11 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, aBuffer.Append(PRUnichar(')')); } + else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) { + for (PRUint16 i = 0, i_end = mValue.mArray->Count(); i != i_end; ++i) { + (*mValue.mArray)[i].AppendToString(aBuffer, aPropID); + } + } else if (eCSSUnit_URL == mUnit) { aBuffer.Append(mValue.mURL->mString); } @@ -489,6 +524,7 @@ void nsCSSValue::AppendToString(nsAString& aBuffer, case eCSSUnit_Initial: aBuffer.AppendLiteral("-moz-initial"); break; case eCSSUnit_None: aBuffer.AppendLiteral("none"); break; case eCSSUnit_Normal: aBuffer.AppendLiteral("normal"); break; + case eCSSUnit_Array: case eCSSUnit_String: break; case eCSSUnit_URL: case eCSSUnit_Image: diff --git a/mozilla/layout/style/nsCSSValue.h b/mozilla/layout/style/nsCSSValue.h index 41c4c0770c8..e45d4c8de6c 100644 --- a/mozilla/layout/style/nsCSSValue.h +++ b/mozilla/layout/style/nsCSSValue.h @@ -59,10 +59,11 @@ enum nsCSSUnit { eCSSUnit_Normal = 5, // (n/a) value is normal (algorithmic, different than auto) eCSSUnit_String = 10, // (PRUnichar*) a string value eCSSUnit_Attr = 11, // (PRUnichar*) a attr(string) value - eCSSUnit_Counter = 12, // (PRUnichar*) a counter(string,[string]) value - eCSSUnit_Counters = 13, // (PRUnichar*) a counters(string,string[,string]) value - eCSSUnit_URL = 14, // (nsCSSValue::URL*) value - eCSSUnit_Image = 15, // (nsCSSValue::Image*) value + eCSSUnit_Array = 20, // (nsCSSValue::Array*) a list of values + eCSSUnit_Counter = 21, // (nsCSSValue::Array*) a counter(string,[string]) value + eCSSUnit_Counters = 22, // (nsCSSValue::Array*) a counters(string,string[,string]) value + eCSSUnit_URL = 30, // (nsCSSValue::URL*) value + eCSSUnit_Image = 31, // (nsCSSValue::Image*) value eCSSUnit_Integer = 50, // (int) simple value eCSSUnit_Enumerated = 51, // (int) value has enumerated meaning eCSSUnit_Color = 80, // (color) an RGBA value @@ -71,7 +72,7 @@ enum nsCSSUnit { // Length units - fixed // US English - eCSSUnit_Inch = 100, // (float) Standard length + eCSSUnit_Inch = 100, // (float) 0.0254 meters eCSSUnit_Foot = 101, // (float) 12 inches eCSSUnit_Mile = 102, // (float) 5280 feet @@ -98,7 +99,7 @@ enum nsCSSUnit { eCSSUnit_Char = 804, // (float) number of characters, used for width with monospace font // Screen relative measure - eCSSUnit_Pixel = 900, // (float) + eCSSUnit_Pixel = 900, // (float) CSS pixel unit // Proportional Unit (for columns in tables) eCSSUnit_Proportional = 950, @@ -106,19 +107,22 @@ enum nsCSSUnit { // Angular units eCSSUnit_Degree = 1000, // (float) 360 per circle eCSSUnit_Grad = 1001, // (float) 400 per circle - eCSSUnit_Radian = 1002, // (float) 2pi per circle + eCSSUnit_Radian = 1002, // (float) 2*pi per circle // Frequency units - eCSSUnit_Hertz = 2000, // (float) - eCSSUnit_Kilohertz = 2001, // (float) + eCSSUnit_Hertz = 2000, // (float) 1/seconds + eCSSUnit_Kilohertz = 2001, // (float) 1000 Hertz // Time units - eCSSUnit_Seconds = 3000, // (float) - eCSSUnit_Milliseconds = 3001 // (float) + eCSSUnit_Seconds = 3000, // (float) Standard time + eCSSUnit_Milliseconds = 3001 // (float) 1/1000 second }; class nsCSSValue { public: + struct Array; + friend struct Array; + struct URL; friend struct URL; @@ -140,6 +144,7 @@ public: nsCSSValue(float aValue, nsCSSUnit aUnit) NS_HIDDEN; nsCSSValue(const nsAString& aValue, nsCSSUnit aUnit) NS_HIDDEN; explicit nsCSSValue(nscolor aValue) NS_HIDDEN; + nsCSSValue(Array* aArray, nsCSSUnit aUnit) NS_HIDDEN; explicit nsCSSValue(URL* aValue) NS_HIDDEN; explicit nsCSSValue(Image* aValue) NS_HIDDEN; nsCSSValue(const nsCSSValue& aCopy) NS_HIDDEN; @@ -188,7 +193,7 @@ public: nsAString& GetStringValue(nsAString& aBuffer) const { - NS_ASSERTION(eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Counters, + NS_ASSERTION(eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Attr, "not a string value"); aBuffer.Truncate(); if (nsnull != mValue.mString) { @@ -199,7 +204,7 @@ public: const PRUnichar* GetStringBufferValue() const { - NS_ASSERTION(eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Counters, + NS_ASSERTION(eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Attr, "not a string value"); return mValue.mString; } @@ -210,6 +215,13 @@ public: return mValue.mColor; } + Array* GetArrayValue() const + { + NS_ASSERTION(eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters, + "not an array value"); + return mValue.mArray; + } + nsIURI* GetURLValue() const { NS_ASSERTION(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, @@ -230,14 +242,16 @@ public: // imgIRequest.h, which leads to REQUIRES hell, since this header is included // all over. NS_HIDDEN_(imgIRequest*) GetImageValue() const; - + NS_HIDDEN_(nscoord) GetLengthTwips() const; NS_HIDDEN_(void) Reset() // sets to null { - if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Counters) && + if ((eCSSUnit_String <= mUnit) && (mUnit <= eCSSUnit_Attr) && (nsnull != mValue.mString)) { nsCRT::free(mValue.mString); + } else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) { + mValue.mArray->Release(); } else if (eCSSUnit_URL == mUnit) { mValue.mURL->Release(); } else if (eCSSUnit_Image == mUnit) { @@ -252,6 +266,7 @@ public: NS_HIDDEN_(void) SetFloatValue(float aValue, nsCSSUnit aUnit); NS_HIDDEN_(void) SetStringValue(const nsAString& aValue, nsCSSUnit aUnit); NS_HIDDEN_(void) SetColorValue(nscolor aValue); + NS_HIDDEN_(void) SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit); NS_HIDDEN_(void) SetURLValue(nsCSSValue::URL* aURI); NS_HIDDEN_(void) SetImageValue(nsCSSValue::Image* aImage); NS_HIDDEN_(void) SetAutoValue(); @@ -272,6 +287,98 @@ public: nsCSSProperty aPropID = eCSSProperty_UNKNOWN) const; #endif + MOZ_DECL_CTOR_COUNTER(nsCSSValue::Array) + + struct Array { + + // return |Array| with reference count of zero + static Array* Create(PRUint16 aItemCount) { + return new (aItemCount) Array(aItemCount); + } + + nsCSSValue& operator[](PRUint16 aIndex) { + NS_ASSERTION(aIndex < mCount, "out of range"); + return *(First() + aIndex); + } + + const nsCSSValue& operator[](PRUint16 aIndex) const { + NS_ASSERTION(aIndex < mCount, "out of range"); + return *(First() + aIndex); + } + + nsCSSValue& Item(PRUint16 aIndex) { return (*this)[aIndex]; } + const nsCSSValue& Item(PRUint16 aIndex) const { return (*this)[aIndex]; } + + PRUint16 Count() { return mCount; } + + PRBool operator==(const Array& aOther) + { + if (mCount != aOther.mCount) + return PR_FALSE; + for (PRUint16 i = 0; i < mCount; ++i) + if ((*this)[i] != aOther[i]) + return PR_FALSE; + return PR_TRUE; + } + + void AddRef() { + ++mRefCnt; + NS_LOG_ADDREF(this, mRefCnt, "nsCSSValue::Array", sizeof(*this)); + } + void Release() { + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "nsCSSValue::Array"); + if (mRefCnt == 0) + delete this; + } + + private: + + PRUint16 mRefCnt; + PRUint16 mCount; + + void* operator new(size_t aSelfSize, PRUint16 aItemCount) CPP_THROW_NEW { + return ::operator new(aSelfSize + sizeof(nsCSSValue)*aItemCount); + } + + void operator delete(void* aPtr) { ::operator delete(aPtr); } + + nsCSSValue* First() { + return (nsCSSValue*) (((char*)this) + sizeof(*this)); + } + + const nsCSSValue* First() const { + return (const nsCSSValue*) (((const char*)this) + sizeof(*this)); + } + +#define CSSVALUE_LIST_FOR_VALUES(var) \ + for (nsCSSValue *var = First(), *var##_end = var + mCount; \ + var != var##_end; ++var) + + Array(PRUint16 aItemCount) + : mRefCnt(0) + , mCount(aItemCount) + { + MOZ_COUNT_CTOR(nsCSSValue::Array); + CSSVALUE_LIST_FOR_VALUES(val) { + new (val) nsCSSValue(); + } + } + + ~Array() + { + MOZ_COUNT_DTOR(nsCSSValue::Array); + CSSVALUE_LIST_FOR_VALUES(val) { + val->~nsCSSValue(); + } + } + +#undef CSSVALUE_LIST_FOR_VALUES + + private: + Array(const Array& aOther); // not to be implemented + }; + MOZ_DECL_CTOR_COUNTER(nsCSSValue::URL) struct URL { @@ -341,6 +448,7 @@ protected: float mFloat; PRUnichar* mString; nscolor mColor; + Array* mArray; URL* mURL; Image* mImage; } mValue; diff --git a/mozilla/layout/style/nsComputedDOMStyle.cpp b/mozilla/layout/style/nsComputedDOMStyle.cpp index 38606954f49..2b309fb291d 100644 --- a/mozilla/layout/style/nsComputedDOMStyle.cpp +++ b/mozilla/layout/style/nsComputedDOMStyle.cpp @@ -609,6 +609,106 @@ nsComputedDOMStyle::GetColumnGap(nsIFrame *aFrame, return CallQueryInterface(val, aValue); } +nsresult +nsComputedDOMStyle::GetCounterIncrement(nsIFrame *aFrame, + nsIDOMCSSValue** aValue) +{ + const nsStyleContent *content = nsnull; + GetStyleData(eStyleStruct_Content, (const nsStyleStruct*&)content, aFrame); + + if (content && content->CounterIncrementCount() == 0) { + nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue(); + NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY); + val->SetIdent(nsLayoutAtoms::none); + return CallQueryInterface(val, aValue); + } + + nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE); + NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY); + + if (content) { + for (PRUint32 i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) { + nsROCSSPrimitiveValue* name = GetROCSSPrimitiveValue(); + if (!name) { + delete valueList; + return NS_ERROR_OUT_OF_MEMORY; + } + if (!valueList->AppendCSSValue(name)) { + delete valueList; + delete name; + return NS_ERROR_OUT_OF_MEMORY; + } + + nsROCSSPrimitiveValue* value = GetROCSSPrimitiveValue(); + if (!value) { + delete valueList; + return NS_ERROR_OUT_OF_MEMORY; + } + if (!valueList->AppendCSSValue(value)) { + delete valueList; + delete value; + return NS_ERROR_OUT_OF_MEMORY; + } + + const nsStyleCounterData *data = content->GetCounterIncrementAt(i); + name->SetString(data->mCounter); + value->SetNumber(data->mValue); // XXX This should really be integer + } + } + + return CallQueryInterface(valueList, aValue); +} + +nsresult +nsComputedDOMStyle::GetCounterReset(nsIFrame *aFrame, + nsIDOMCSSValue** aValue) +{ + const nsStyleContent *content = nsnull; + GetStyleData(eStyleStruct_Content, (const nsStyleStruct*&)content, aFrame); + + if (content && content->CounterResetCount() == 0) { + nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue(); + NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY); + val->SetIdent(nsLayoutAtoms::none); + return CallQueryInterface(val, aValue); + } + + nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE); + NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY); + + if (content) { + for (PRUint32 i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) { + nsROCSSPrimitiveValue* name = GetROCSSPrimitiveValue(); + if (!name) { + delete valueList; + return NS_ERROR_OUT_OF_MEMORY; + } + if (!valueList->AppendCSSValue(name)) { + delete valueList; + delete name; + return NS_ERROR_OUT_OF_MEMORY; + } + + nsROCSSPrimitiveValue* value = GetROCSSPrimitiveValue(); + if (!value) { + delete valueList; + return NS_ERROR_OUT_OF_MEMORY; + } + if (!valueList->AppendCSSValue(value)) { + delete valueList; + delete value; + return NS_ERROR_OUT_OF_MEMORY; + } + + const nsStyleCounterData *data = content->GetCounterResetAt(i); + name->SetString(data->mCounter); + value->SetNumber(data->mValue); // XXX This should really be integer + } + } + + return CallQueryInterface(valueList, aValue); +} + nsresult nsComputedDOMStyle::GetFontFamily(nsIFrame *aFrame, nsIDOMCSSValue** aValue) @@ -3599,8 +3699,8 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength) COMPUTED_STYLE_MAP_ENTRY(clip, Clip), COMPUTED_STYLE_MAP_ENTRY(color, Color), // COMPUTED_STYLE_MAP_ENTRY(content, Content), - // COMPUTED_STYLE_MAP_ENTRY(counter_increment, CounterIncrement), - // COMPUTED_STYLE_MAP_ENTRY(counter_reset, CounterReset), + COMPUTED_STYLE_MAP_ENTRY(counter_increment, CounterIncrement), + COMPUTED_STYLE_MAP_ENTRY(counter_reset, CounterReset), //// COMPUTED_STYLE_MAP_ENTRY(cue, Cue), // COMPUTED_STYLE_MAP_ENTRY(cue_after, CueAfter), // COMPUTED_STYLE_MAP_ENTRY(cue_before, CueBefore), diff --git a/mozilla/layout/style/nsComputedDOMStyle.h b/mozilla/layout/style/nsComputedDOMStyle.h index 99e5502a9be..9af769bf303 100644 --- a/mozilla/layout/style/nsComputedDOMStyle.h +++ b/mozilla/layout/style/nsComputedDOMStyle.h @@ -240,7 +240,9 @@ private: nsresult GetOutlineRadiusTopLeft(nsIFrame *aFrame, nsIDOMCSSValue** aValue); nsresult GetOutlineRadiusTopRight(nsIFrame *aFrame, nsIDOMCSSValue** aValue); - /*Marker Properties */ + /* Content Properties */ + nsresult GetCounterIncrement(nsIFrame *aFrame, nsIDOMCSSValue** aValue); + nsresult GetCounterReset(nsIFrame *aFrame, nsIDOMCSSValue** aValue); nsresult GetMarkerOffset(nsIFrame *aFrame, nsIDOMCSSValue** aValue); /* z-index */ diff --git a/mozilla/layout/style/nsHTMLCSSStyleSheet.cpp b/mozilla/layout/style/nsHTMLCSSStyleSheet.cpp index 299f5344e93..a4d907413fd 100644 --- a/mozilla/layout/style/nsHTMLCSSStyleSheet.cpp +++ b/mozilla/layout/style/nsHTMLCSSStyleSheet.cpp @@ -76,10 +76,19 @@ public: #ifdef DEBUG NS_IMETHOD List(FILE* out = stdout, PRInt32 aIndent = 0) const; #endif +protected: + nsCSSValueList mInheritList; + nsCSSQuotes mInheritQuotes; + nsCSSCounterData mNoneCounter; }; CSSDisablePropsRule::CSSDisablePropsRule() { + nsCSSValue none(eCSSUnit_None); + mNoneCounter.mCounter = none; + nsCSSValue inherit(eCSSUnit_Inherit); + mInheritList.mValue = inherit; + mInheritQuotes.mOpen = inherit; } class CSSFirstLineRule : public CSSDisablePropsRule { @@ -115,8 +124,9 @@ CSSDisablePropsRule::List(FILE* out, PRInt32 aIndent) const /* * Note: These rule mapping functions, unlike practically all others, * will overwrite the properties even if they're not |eCSSUnit_Null|. - * This is only a partial fix for the fact that they should be higher in - * the cascade (at the very top). + * XXX This is only a partial fix for the fact that they should be + * higher in the cascade (at the very top). It doesn't work in the case + * where something higher in the cascade fully specifies the struct. * * XXX This should be cleaned up once we implement eCSSUnit_Initial * throughout. @@ -204,17 +214,15 @@ CSSDisablePropsRule::CommonMapRuleInfoInto(nsRuleData* aData) if (aData->mSID == eStyleStruct_Content) { // Don't bother resetting 'content'. - // Don't bother with '-moz-counter-increment' and - // '-moz-counter-reset' since they're '-moz-'ed and should be - // removed soon. + aData->mContentData->mCounterIncrement = &mNoneCounter; + aData->mContentData->mCounterReset = &mNoneCounter; nsCSSValue autovalue(eCSSUnit_Auto); aData->mContentData->mMarkerOffset = autovalue; } if (aData->mSID == eStyleStruct_Quotes) { - // XXX |mQuotes| is a pain, because we have to have our own cursor - // structure allocated. + aData->mContentData->mQuotes = &mInheritQuotes; } // Disable everything in the UserInterface struct. @@ -223,8 +231,7 @@ CSSDisablePropsRule::CommonMapRuleInfoInto(nsRuleData* aData) aData->mUserInterfaceData->mUserInput = inherit; aData->mUserInterfaceData->mUserModify = inherit; aData->mUserInterfaceData->mUserFocus = inherit; - // XXX |mCursor| is a pain, because we have to have our own cursor - // structure allocated. + aData->mUserInterfaceData->mCursor = &mInheritList; } if (aData->mSID == eStyleStruct_UIReset) { diff --git a/mozilla/layout/style/nsRuleNode.cpp b/mozilla/layout/style/nsRuleNode.cpp index 95dfd57e7c9..f11b82f90f0 100644 --- a/mozilla/layout/style/nsRuleNode.cpp +++ b/mozilla/layout/style/nsRuleNode.cpp @@ -172,6 +172,7 @@ static void EnsureBlockDisplay(PRUint8& display) } } +// XXX This should really be done in the CSS parser. nsString& Unquote(nsString& aString) { PRUnichar start = aString.First(); @@ -4192,11 +4193,15 @@ nsRuleNode::ComputeContentData(nsStyleStruct* aStartStruct, data.mContent.mImage = value.GetImageValue(); NS_IF_ADDREF(data.mContent.mImage); } - else if (type < eStyleContentType_OpenQuote) { + else if (type <= eStyleContentType_Attr) { value.GetStringValue(buffer); Unquote(buffer); data.mContent.mString = nsCRT::strdup(buffer.get()); } + else if (type <= eStyleContentType_Counters) { + data.mContent.mCounters = value.GetArrayValue(); + data.mContent.mCounters->AddRef(); + } else { data.mContent.mString = nsnull; } @@ -4217,10 +4222,10 @@ nsRuleNode::ComputeContentData(nsStyleStruct* aStartStruct, inherited = PR_TRUE; count = parentContent->CounterIncrementCount(); if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) { - PRInt32 increment; while (0 < count--) { - parentContent->GetCounterIncrementAt(count, buffer, increment); - content->SetCounterIncrementAt(count, buffer, increment); + const nsStyleCounterData *data = + parentContent->GetCounterIncrementAt(count); + content->SetCounterIncrementAt(count, data->mCounter, data->mValue); } } } @@ -4233,8 +4238,8 @@ nsRuleNode::ComputeContentData(nsStyleStruct* aStartStruct, if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) { count = 0; ourIncrement = contentData.mCounterIncrement; - PRInt32 increment; while (ourIncrement) { + PRInt32 increment; if (eCSSUnit_Integer == ourIncrement->mValue.GetUnit()) { increment = ourIncrement->mValue.GetIntValue(); } @@ -4260,10 +4265,10 @@ nsRuleNode::ComputeContentData(nsStyleStruct* aStartStruct, inherited = PR_TRUE; count = parentContent->CounterResetCount(); if (NS_SUCCEEDED(content->AllocateCounterResets(count))) { - PRInt32 reset; while (0 < count--) { - parentContent->GetCounterResetAt(count, buffer, reset); - content->SetCounterResetAt(count, buffer, reset); + const nsStyleCounterData *data = + parentContent->GetCounterResetAt(count); + content->SetCounterResetAt(count, data->mCounter, data->mValue); } } } @@ -4276,8 +4281,8 @@ nsRuleNode::ComputeContentData(nsStyleStruct* aStartStruct, if (NS_SUCCEEDED(content->AllocateCounterResets(count))) { count = 0; ourReset = contentData.mCounterReset; - PRInt32 reset; while (ourReset) { + PRInt32 reset; if (eCSSUnit_Integer == ourReset->mValue.GetUnit()) { reset = ourReset->mValue.GetIntValue(); } diff --git a/mozilla/layout/style/nsStyleStruct.cpp b/mozilla/layout/style/nsStyleStruct.cpp index f7da9e78396..7aaec34e746 100644 --- a/mozilla/layout/style/nsStyleStruct.cpp +++ b/mozilla/layout/style/nsStyleStruct.cpp @@ -1399,6 +1399,9 @@ nsStyleContentData::~nsStyleContentData() { if (mType == eStyleContentType_Image) { NS_IF_RELEASE(mContent.mImage); + } else if (mType == eStyleContentType_Counter || + mType == eStyleContentType_Counters) { + mContent.mCounters->Release(); } else if (mContent.mString) { nsCRT::free(mContent.mString); } @@ -1406,10 +1409,17 @@ nsStyleContentData::~nsStyleContentData() nsStyleContentData& nsStyleContentData::operator=(const nsStyleContentData& aOther) { + if (this == &aOther) + return *this; + this->~nsStyleContentData(); mType = aOther.mType; if (mType == eStyleContentType_Image) { mContent.mImage = aOther.mContent.mImage; NS_IF_ADDREF(mContent.mImage); + } else if (mType == eStyleContentType_Counter || + mType == eStyleContentType_Counters) { + mContent.mCounters = aOther.mContent.mCounters; + mContent.mCounters->AddRef(); } else if (aOther.mContent.mString) { mContent.mString = nsCRT::strdup(aOther.mContent.mString); } else { @@ -1432,6 +1442,9 @@ PRBool nsStyleContentData::operator==(const nsStyleContentData& aOther) NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) && eq); } + if (mType == eStyleContentType_Counter || + mType == eStyleContentType_Counters) + return *mContent.mCounters == *aOther.mContent.mCounters; return nsCRT::strcmp(mContent.mString, aOther.mContent.mString) == 0; } @@ -1478,53 +1491,56 @@ nsStyleContent::nsStyleContent(const nsStyleContent& aSource) if (NS_SUCCEEDED(AllocateCounterIncrements(aSource.CounterIncrementCount()))) { for (index = 0; index < mIncrementCount; index++) { - aSource.GetCounterIncrementAt(index, mIncrements[index].mCounter, - mIncrements[index].mValue); + const nsStyleCounterData *data = aSource.GetCounterIncrementAt(index); + mIncrements[index].mCounter = data->mCounter; + mIncrements[index].mValue = data->mValue; } } if (NS_SUCCEEDED(AllocateCounterResets(aSource.CounterResetCount()))) { for (index = 0; index < mResetCount; index++) { - aSource.GetCounterResetAt(index, mResets[index].mCounter, - mResets[index].mValue); + const nsStyleCounterData *data = aSource.GetCounterResetAt(index); + mResets[index].mCounter = data->mCounter; + mResets[index].mValue = data->mValue; } } } nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const { - if (mContentCount == aOther.mContentCount) { - if ((mMarkerOffset == aOther.mMarkerOffset) && - (mIncrementCount == aOther.mIncrementCount) && - (mResetCount == aOther.mResetCount)) { - PRUint32 ix = mContentCount; - while (0 < ix--) { - if (mContents[ix] != aOther.mContents[ix]) { - // Unfortunately we need to reframe here; a simple reflow - // will not pick up different text or different image URLs, - // since we set all that up in the CSSFrameConstructor - return NS_STYLE_HINT_FRAMECHANGE; - } - } - ix = mIncrementCount; - while (0 < ix--) { - if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) || - (mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) { - return NS_STYLE_HINT_REFLOW; - } - } - ix = mResetCount; - while (0 < ix--) { - if ((mResets[ix].mValue != aOther.mResets[ix].mValue) || - (mResets[ix].mCounter != aOther.mResets[ix].mCounter)) { - return NS_STYLE_HINT_REFLOW; - } - } - return NS_STYLE_HINT_NONE; + if (mContentCount != aOther.mContentCount || + mIncrementCount != aOther.mIncrementCount || + mResetCount != aOther.mResetCount) { + return NS_STYLE_HINT_FRAMECHANGE; + } + + PRUint32 ix = mContentCount; + while (0 < ix--) { + if (mContents[ix] != aOther.mContents[ix]) { + // Unfortunately we need to reframe here; a simple reflow + // will not pick up different text or different image URLs, + // since we set all that up in the CSSFrameConstructor + return NS_STYLE_HINT_FRAMECHANGE; } + } + ix = mIncrementCount; + while (0 < ix--) { + if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) || + (mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) { + return NS_STYLE_HINT_FRAMECHANGE; + } + } + ix = mResetCount; + while (0 < ix--) { + if ((mResets[ix].mValue != aOther.mResets[ix].mValue) || + (mResets[ix].mCounter != aOther.mResets[ix].mCounter)) { + return NS_STYLE_HINT_FRAMECHANGE; + } + } + if (mMarkerOffset != aOther.mMarkerOffset) { return NS_STYLE_HINT_REFLOW; } - return NS_STYLE_HINT_FRAMECHANGE; + return NS_STYLE_HINT_NONE; } #ifdef DEBUG diff --git a/mozilla/layout/style/nsStyleStruct.h b/mozilla/layout/style/nsStyleStruct.h index b75310b70d5..682005bdcdb 100644 --- a/mozilla/layout/style/nsStyleStruct.h +++ b/mozilla/layout/style/nsStyleStruct.h @@ -53,6 +53,7 @@ #include "nsCOMArray.h" #include "nsIAtom.h" #include "nsIURI.h" +#include "nsCSSValue.h" class nsIFrame; class imgIRequest; @@ -885,10 +886,10 @@ struct nsStyleContentData { union { PRUnichar *mString; imgIRequest *mImage; + nsCSSValue::Array* mCounters; } mContent; - // empty constructor to keep Sun compiler happy - nsStyleContentData() {} + nsStyleContentData() : mType(nsStyleContentType(0)) { mContent.mString = nsnull; } ~nsStyleContentData(); nsStyleContentData& operator=(const nsStyleContentData& aOther); PRBool operator==(const nsStyleContentData& aOther); @@ -896,6 +897,8 @@ struct nsStyleContentData { PRBool operator!=(const nsStyleContentData& aOther) { return !(*this == aOther); } +private: + nsStyleContentData(const nsStyleContentData&); // not to be implemented }; struct nsStyleCounterData { @@ -1013,13 +1016,9 @@ struct nsStyleContent: public nsStyleStruct { nsresult AllocateContents(PRUint32 aCount); PRUint32 CounterIncrementCount(void) const { return mIncrementCount; } // [reset] - nsresult GetCounterIncrementAt(PRUint32 aIndex, nsString& aCounter, PRInt32& aIncrement) const { - if (aIndex < mIncrementCount) { - aCounter = mIncrements[aIndex].mCounter; - aIncrement = mIncrements[aIndex].mValue; - return NS_OK; - } - return NS_ERROR_ILLEGAL_VALUE; + const nsStyleCounterData* GetCounterIncrementAt(PRUint32 aIndex) const { + NS_ASSERTION(aIndex < mIncrementCount, "out of range"); + return &mIncrements[aIndex]; } nsresult AllocateCounterIncrements(PRUint32 aCount) { @@ -1047,13 +1046,9 @@ struct nsStyleContent: public nsStyleStruct { } PRUint32 CounterResetCount(void) const { return mResetCount; } // [reset] - nsresult GetCounterResetAt(PRUint32 aIndex, nsString& aCounter, PRInt32& aValue) const { - if (aIndex < mResetCount) { - aCounter = mResets[aIndex].mCounter; - aValue = mResets[aIndex].mValue; - return NS_OK; - } - return NS_ERROR_ILLEGAL_VALUE; + const nsStyleCounterData* GetCounterResetAt(PRUint32 aIndex) const { + NS_ASSERTION(aIndex < mResetCount, "out of range"); + return &mResets[aIndex]; } nsresult AllocateCounterResets(PRUint32 aCount) { diff --git a/mozilla/layout/style/ua.css b/mozilla/layout/style/ua.css index 7d93ec7dffb..5e31ba8767c 100644 --- a/mozilla/layout/style/ua.css +++ b/mozilla/layout/style/ua.css @@ -143,7 +143,6 @@ padding: inherit; display: inherit; -moz-box-orient: inherit; - -moz-counter-reset: inherit; /* make unicode-bidi inherit, otherwise it has no effect on text inputs and blocks with overflow: scroll; */ unicode-bidi: inherit;