Add notification batching to HTML5

This commit is contained in:
Henri Sivonen 2009-03-02 16:02:31 +02:00
parent fb89a672c3
commit 3e559d71fd
7 changed files with 188 additions and 13 deletions

View File

@ -85,6 +85,7 @@ CPPSRCS = \
nsHtml5ReleasableElementName.cpp \
nsHtml5MetaScanner.cpp \
nsHtml5TreeOperation.cpp \
nsHtml5PendingNotification.cpp \
$(NULL)
FORCE_STATIC_LIB = 1

View File

@ -0,0 +1,45 @@
/* ***** 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 HTML Parser C++ Translator code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Henri Sivonen <hsivonen@iki.fi>
*
* 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 "nsHtml5TreeBuilder.h"
#include "nsHtml5PendingNotification.h"
void
nsHtml5PendingNotification::Fire(nsHtml5TreeBuilder* aBuilder)
{
aBuilder->NotifyAppend(mParent, mChildCount);
}

View File

@ -0,0 +1,63 @@
/* ***** 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 HTML Parser C++ Translator code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Henri Sivonen <hsivonen@iki.fi>
*
* 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 nsHtml5PendingNotification_h__
#define nsHtml5PendingNotification_h__
class nsHtml5TreeBuilder;
class nsHtml5PendingNotification {
public:
nsHtml5PendingNotification(nsIContent* aParent)
: mParent(aParent),
mChildCount(aParent->GetChildCount())
{
MOZ_COUNT_CTOR(nsHtml5PendingNotification);
}
~nsHtml5PendingNotification() {
MOZ_COUNT_DTOR(nsHtml5PendingNotification);
}
void Fire(nsHtml5TreeBuilder* aBuilder);
inline PRBool Contains(nsIContent* aNode) {
return !!(mParent == aNode);
}
private:
nsIContent* mParent;
PRUint32 mChildCount;
};
#endif // nsHtml5PendingNotification_h__

View File

@ -47,6 +47,7 @@
#include "nsHtml5Atoms.h"
#include "nsHtml5ByteReadable.h"
#include "nsHtml5TreeOperation.h"
#include "nsHtml5PendingNotification.h"
class nsHtml5Parser;
@ -59,6 +60,8 @@ class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5Portability;
typedef nsIContent* nsIContentPtr;
class nsHtml5TreeBuilder
{
private:

View File

@ -252,7 +252,7 @@ nsHtml5TreeBuilder::start(PRBool fragment)
void
nsHtml5TreeBuilder::end()
{
mOpQueue.Clear();
Flush();
}
void
@ -441,9 +441,12 @@ nsHtml5TreeBuilder::Flush()
{
if (!mFlushing) {
mFlushing = PR_TRUE;
for (PRUint32 i = 0; i < mOpQueue.Length(); ++i) {
mOpQueue[i].Perform(this);
const nsHtml5TreeOperation* start = mOpQueue.Elements();
const nsHtml5TreeOperation* end = start + mOpQueue.Length();
for (nsHtml5TreeOperation* iter = (nsHtml5TreeOperation*)start; iter < end; ++iter) {
iter->Perform(this);
}
FlushPendingAppendNotifications();
mOpQueue.Clear();
mFlushing = PR_FALSE;
}

View File

@ -40,23 +40,75 @@
PRBool mHasProcessedBase;
PRBool mFlushing;
nsTArray<nsHtml5TreeOperation> mOpQueue;
nsTArray<nsIContentPtr> mElementsSeenInThisAppendBatch;
nsTArray<nsHtml5PendingNotification> mPendingNotifications;
void MaybeFlushAndMaybeSuspend();
public:
nsHtml5TreeBuilder(nsHtml5Parser* aParser);
~nsHtml5TreeBuilder();
void Flush();
inline void PostPendingAppendNotification(nsIContent* aParent, nsIContent* aChild) {
nsIContent* parent = aParent; // this gets nulled when found
nsIContent* child = aChild->IsNodeOfType(nsINode::eELEMENT) ? aChild : nsnull; // this gets nulled when found
const nsIContentPtr* start = mElementsSeenInThisAppendBatch.Elements();
const nsIContentPtr* end = start + mElementsSeenInThisAppendBatch.Length();
// XXX backwards iterate
for (const nsIContentPtr* iter = start; iter < end; ++iter) {
if (*iter == parent) {
parent = nsnull;
}
if (*iter == child) {
child = nsnull;
}
if (!(parent || child)) {
break;
}
}
if (child) {
mElementsSeenInThisAppendBatch.AppendElement(child);
}
if (parent) {
// parents that are in mPendingNotifications don't need to be added to
// mElementsSeenInThisAppendBatch
const nsHtml5PendingNotification* startNotifications = mPendingNotifications.Elements();
const nsHtml5PendingNotification* endNotifications = startNotifications + mPendingNotifications.Length();
// XXX backwards iterate
for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)startNotifications; iter < endNotifications; ++iter) {
if (iter->Contains(parent)) {
return;
}
}
mPendingNotifications.AppendElement(parent);
}
}
inline void FlushPendingAppendNotifications() {
const nsHtml5PendingNotification* start = mPendingNotifications.Elements();
const nsHtml5PendingNotification* end = start + mPendingNotifications.Length();
for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) {
iter->Fire(this);
}
mPendingNotifications.Clear();
mElementsSeenInThisAppendBatch.Clear();
}
inline void NotifyAppend(nsIContent* aParent, PRUint32 aChildCount) {
mParser->NotifyAppend(aParent, aChildCount);
}
inline nsIDocument* GetDocument() {
return mParser->GetDocument();
}
inline void SetScriptElement(nsIContent* aScript) {
mParser->SetScriptElement(aScript);
}
inline void UpdateStyleSheet(nsIContent* aSheet) {
mParser->UpdateStyleSheet(aSheet);
}
inline nsresult ProcessBase(nsIContent* aBase) {
if (!mHasProcessedBase) {
nsresult rv = mParser->ProcessBASETag(aBase);
@ -65,6 +117,7 @@
}
return NS_OK;
}
inline void StartLayout() {
mParser->StartLayout(PR_FALSE);
}

View File

@ -60,14 +60,12 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeBuilder* aBuilder)
nsresult rv = NS_OK;
switch(mOpCode) {
case eTreeOpAppend: {
PRUint32 childCount = mParent->GetChildCount();
aBuilder->PostPendingAppendNotification(mParent, mNode);
rv = mParent->AppendChildTo(mNode, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// XXX move notify away
aBuilder->NotifyAppend(mParent, childCount);
return rv;
}
case eTreeOpDetach: {
aBuilder->FlushPendingAppendNotifications();
nsIContent* parent = mNode->GetParent();
if (parent) {
PRUint32 pos = parent->IndexOf(mNode);
@ -79,14 +77,19 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeBuilder* aBuilder)
return rv;
}
case eTreeOpAppendChildrenToNewParent: {
aBuilder->FlushPendingAppendNotifications();
PRUint32 childCount = mParent->GetChildCount();
PRBool didAppend = PR_FALSE;
while (mNode->GetChildCount()) {
nsCOMPtr<nsIContent> child = mNode->GetChildAt(0);
rv = mNode->RemoveChildAt(0, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
nsNodeUtils::ContentRemoved(mNode, child, 0);
PRUint32 childCount = mParent->GetChildCount();
rv = mParent->AppendChildTo(child, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
didAppend = PR_TRUE;
}
if (didAppend) {
aBuilder->NotifyAppend(mParent, childCount);
}
return rv;
@ -94,19 +97,19 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeBuilder* aBuilder)
case eTreeOpFosterParent: {
nsIContent* parent = mTable->GetParent();
if (parent && parent->IsNodeOfType(nsINode::eELEMENT)) {
aBuilder->FlushPendingAppendNotifications();
PRUint32 pos = parent->IndexOf(mTable);
rv = parent->InsertChildAt(mNode, pos, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
nsNodeUtils::ContentInserted(parent, mNode, pos);
} else {
PRUint32 childCount = mParent->GetChildCount();
aBuilder->PostPendingAppendNotification(mParent, mNode);
rv = mParent->AppendChildTo(mNode, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
aBuilder->NotifyAppend(mParent, childCount);
}
return rv;
}
case eTreeOpAppendToDocument: {
aBuilder->FlushPendingAppendNotifications();
nsIDocument* doc = aBuilder->GetDocument();
PRUint32 childCount = doc->GetChildCount();
rv = doc->AppendChildTo(mNode, PR_FALSE);
@ -135,18 +138,22 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeBuilder* aBuilder)
return rv;
}
case eTreeOpDoneAddingChildren: {
mNode->DoneAddingChildren(PR_TRUE);
// aBuilder->FlushPendingAppendNotifications();
mNode->DoneAddingChildren(PR_FALSE);
return rv;
}
case eTreeOpUpdateStyleSheet: {
// aBuilder->FlushPendingAppendNotifications();
aBuilder->UpdateStyleSheet(mNode);
return rv;
}
case eTreeOpProcessBase: {
// aBuilder->FlushPendingAppendNotifications();
rv = aBuilder->ProcessBase(mNode);
return rv;
}
case eTreeOpStartLayout: {
aBuilder->FlushPendingAppendNotifications();
aBuilder->StartLayout();
return rv;
}