/** * This method gets called when a tag needs to write it's attributes * * @update gess 3/25/98 * @param * @return result status */ nsresult CViewSourceHTML::WriteAttributes(const nsAString& tagName, nsTokenAllocator* allocator, PRInt32 attrCount, PRBool aOwnerInError) { nsresult result=NS_OK; if(attrCount){ //go collect the attributes... int attr = 0; for(attr = 0; attr < attrCount; ++attr){ CToken* theToken = mTokenizer->PeekToken(); if(theToken) { eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); if(eToken_attribute == theType){ mTokenizer->PopToken(); //pop it for real... mTokenNode.AddAttribute(theToken); //and add it to the node. CAttributeToken* theAttrToken = (CAttributeToken*)theToken; const nsSubstring& theKey = theAttrToken->GetKey(); // The attribute is only in error if its owner is NOT in error. const PRBool attributeInError = !aOwnerInError && theAttrToken->IsInError(); result = WriteTag(kAttributeName,theKey,0,attributeInError); const nsSubstring& theValue = theAttrToken->GetValue(); if(!theValue.IsEmpty() || theAttrToken->mHasEqualWithoutValue){ if (IsUrlAttribute(tagName, theKey, theValue)) { WriteHrefAttribute(allocator, theValue); } else { WriteTag(kAttributeValue,theValue,0,attributeInError); } } } } else return kEOF; } } return result; }
/** * This method scans the sequence of tokens to determine whether or not the * tag structure of the document is well formed. In well formed cases, we can * skip doing residual style handling and allow inlines to contain block-level * elements. * * @param aFinalChunk Is unused. * @return Success (currently, this function cannot fail). */ nsresult nsHTMLTokenizer::ScanDocStructure(bool aFinalChunk) { nsresult result = NS_OK; if (!mTokenDeque.GetSize()) { return result; } CHTMLToken* theToken = (CHTMLToken*)mTokenDeque.ObjectAt(mTokenScanPos); // Start by finding the first start tag that hasn't been reviewed. while (mTokenScanPos > 0) { if (theToken) { eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); if (theType == eToken_start && theToken->GetContainerInfo() == eFormUnknown) { break; } } theToken = (CHTMLToken*)mTokenDeque.ObjectAt(--mTokenScanPos); } // Now that we know where to start, let's walk through the // tokens to see which are well-formed. Stop when you run out // of fresh tokens. nsDeque theStack(0); nsDeque tempStack(0); int32_t theStackDepth = 0; // Don't bother if we get ridiculously deep. static const int32_t theMaxStackDepth = 200; while (theToken && theStackDepth < theMaxStackDepth) { eHTMLTokenTypes theType = eHTMLTokenTypes(theToken->GetTokenType()); eHTMLTags theTag = (eHTMLTags)theToken->GetTypeID(); if (nsHTMLElement::IsContainer(theTag)) { // Bug 54117 bool theTagIsBlock = gHTMLElements[theTag].IsMemberOf(kBlockEntity); bool theTagIsInline = theTagIsBlock ? false : gHTMLElements[theTag].IsMemberOf(kInlineEntity); if (theTagIsBlock || theTagIsInline || eHTMLTag_table == theTag) { switch(theType) { case eToken_start: { if (gHTMLElements[theTag].ShouldVerifyHierarchy()) { int32_t earlyPos = FindLastIndexOfTag(theTag, theStack); if (earlyPos != kNotFound) { // Uh-oh, we've found a tag that is not allowed to nest at // all. Mark the previous one and all of its children as // malformed to increase our chances of doing RS handling // on all of them. We want to do this for cases such as: // <a><div><a></a></div></a>. // Note that we have to iterate through all of the chilren // of the original malformed tag to protect against: // <a><font><div><a></a></div></font></a>, so that the <font> // is allowed to contain the <div>. // XXX What about <a><span><a>, where the second <a> closes // the <span>? nsDequeIterator it(theStack, earlyPos), end(theStack.End()); while (it < end) { CHTMLToken *theMalformedToken = static_cast<CHTMLToken*>(it++); theMalformedToken->SetContainerInfo(eMalformed); } } } theStack.Push(theToken); ++theStackDepth; } break; case eToken_end: { CHTMLToken *theLastToken = static_cast<CHTMLToken*>(theStack.Peek()); if (theLastToken) { if (theTag == theLastToken->GetTypeID()) { theStack.Pop(); // Yank it for real theStackDepth--; theLastToken->SetContainerInfo(eWellFormed); } else { // This token wasn't what we expected it to be! We need to // go searching for its real start tag on our stack. Each // tag in between the end tag and start tag must be malformed if (FindLastIndexOfTag(theTag, theStack) != kNotFound) { // Find theTarget in the stack, marking each (malformed!) // tag in our way. theStack.Pop(); // Pop off theLastToken for real. do { theLastToken->SetContainerInfo(eMalformed); tempStack.Push(theLastToken); theLastToken = static_cast<CHTMLToken*>(theStack.Pop()); } while (theLastToken && theTag != theLastToken->GetTypeID()); // XXX The above test can confuse two different userdefined // tags. NS_ASSERTION(theLastToken, "FindLastIndexOfTag lied to us!" " We couldn't find theTag on theStack"); theLastToken->SetContainerInfo(eMalformed); // Great, now push all of the other tokens back onto the // stack to preserve the general structure of the document. // Note that we don't push the target token back onto the // the stack (since it was just closed). while (tempStack.GetSize() != 0) { theStack.Push(tempStack.Pop()); } } } } } break; default: break; } } } theToken = (CHTMLToken*)mTokenDeque.ObjectAt(++mTokenScanPos); } return result; }
nsNodeAllocator::nsNodeAllocator():mSharedNodes(0){ #ifdef DEBUG_TRACK_NODES mCount=0; #endif #else static const size_t kNodeBuckets[] = { sizeof(nsCParserNode), sizeof(nsCParserStartNode) }; static const PRInt32 kNumNodeBuckets = sizeof(kNodeBuckets) / sizeof(size_t); static const PRInt32 kInitialNodePoolSize = NS_SIZE_IN_HEAP(sizeof(nsCParserNode)) * 35; // optimal size based on space-trace data nsNodeAllocator::nsNodeAllocator() { mNodePool.Init("NodePool", kNodeBuckets, kNumNodeBuckets, kInitialNodePoolSize); #endif MOZ_COUNT_CTOR(nsNodeAllocator); } nsNodeAllocator::~nsNodeAllocator() { MOZ_COUNT_DTOR(nsNodeAllocator); #ifdef HEAP_ALLOCATED_NODES nsCParserNode* theNode = 0; while((theNode=(nsCParserNode*)mSharedNodes.Pop())){ #ifdef DEBUG_TRACK_NODES RemoveNode(theNode); #endif ::operator delete(theNode); theNode=nsnull; } #ifdef DEBUG_TRACK_NODES if(mCount) { printf("**************************\n"); printf("%i out of %i nodes leaked!\n",gAllNodeCount,mCount); printf("**************************\n"); } #endif #endif } nsCParserNode* nsNodeAllocator::CreateNode(CToken* aToken, nsTokenAllocator* aTokenAllocator) { nsCParserNode* result = 0; #ifdef HEAP_ALLOCATED_NODES #if 0 if(gAllNodeCount!=mSharedNodes.GetSize()) { int x=10; //this is very BAD! } #endif result = static_cast<nsCParserNode*>(mSharedNodes.Pop()); if (result) { result->Init(aToken, aTokenAllocator,this); } else{ result = nsCParserNode::Create(aToken, aTokenAllocator,this); #ifdef DEBUG_TRACK_NODES ++mCount; AddNode(static_cast<nsCParserNode*>(result)); #endif IF_HOLD(result); } #else eHTMLTokenTypes type = aToken ? eHTMLTokenTypes(aToken->GetTokenType()) : eToken_unknown; switch (type) { case eToken_start: result = nsCParserStartNode::Create(aToken, aTokenAllocator,this); break; default : result = nsCParserNode::Create(aToken, aTokenAllocator,this); break; } IF_HOLD(result); #endif return result; }