Merge mozilla-central into electrolysis.

This commit is contained in:
Benjamin Smedberg 2010-01-18 10:26:52 -05:00
commit 20b787e19d
47 changed files with 1767 additions and 1728 deletions

View File

@ -55,11 +55,11 @@
class nsIPresShell;
#define NS_ACCEVENT_IMPL_CID \
{ /* 55b89892-a83d-4252-ba78-cbdf53a86936 */ \
0x55b89892, \
0xa83d, \
0x4252, \
{ 0xba, 0x78, 0xcb, 0xdf, 0x53, 0xa8, 0x69, 0x36 } \
{ /* 39bde096-317e-4294-b23b-4af4a9b283f7 */ \
0x39bde096, \
0x317e, \
0x4294, \
{ 0xb2, 0x3b, 0x4a, 0xf4, 0xa9, 0xb2, 0x83, 0xf7 } \
}
class nsAccEvent: public nsIAccessibleEvent
@ -100,6 +100,12 @@ public:
NS_DECL_NSIACCESSIBLEEVENT
// nsAccEvent
PRUint32 GetEventType() const { return mEventType; }
EEventRule GetEventRule() const { return mEventRule; }
PRBool IsAsync() const { return mIsAsync; }
PRBool IsFromUserInput() const { return mIsFromUserInput; }
static void GetLastEventAttributes(nsIDOMNode *aNode,
nsIPersistentProperties *aAttributes);
@ -121,27 +127,6 @@ private:
static nsIDOMNode* gLastEventNodeWeak;
public:
static PRUint32 EventType(nsIAccessibleEvent *aAccEvent) {
PRUint32 eventType;
aAccEvent->GetEventType(&eventType);
return eventType;
}
static EEventRule EventRule(nsIAccessibleEvent *aAccEvent) {
nsRefPtr<nsAccEvent> accEvent =
nsAccUtils::QueryObject<nsAccEvent>(aAccEvent);
return accEvent->mEventRule;
}
static PRBool IsAsyncEvent(nsIAccessibleEvent *aAccEvent) {
nsRefPtr<nsAccEvent> accEvent =
nsAccUtils::QueryObject<nsAccEvent>(aAccEvent);
return accEvent->mIsAsync;
}
static PRBool IsFromUserInput(nsIAccessibleEvent *aAccEvent) {
PRBool isFromUserInput;
aAccEvent->GetIsFromUserInput(&isFromUserInput);
return isFromUserInput;
}
static void ResetLastInputState()
{gLastEventFromUserInput = PR_FALSE; gLastEventNodeWeak = nsnull; }

View File

@ -1681,19 +1681,21 @@ nsDocAccessible::FlushPendingEvents()
if (!mWeakShell)
break;
nsCOMPtr<nsIAccessibleEvent> accessibleEvent(mEventsToFire[index]);
nsAccEvent *accEvent = mEventsToFire[index];
if (nsAccEvent::EventRule(accessibleEvent) == nsAccEvent::eDoNotEmit)
if (accEvent->GetEventRule() == nsAccEvent::eDoNotEmit)
continue;
nsCOMPtr<nsIAccessible> accessible;
accessibleEvent->GetAccessible(getter_AddRefs(accessible));
nsCOMPtr<nsIDOMNode> domNode;
accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
PRUint32 eventType = nsAccEvent::EventType(accessibleEvent);
PRBool isFromUserInput = nsAccEvent::IsFromUserInput(accessibleEvent);
accEvent->GetAccessible(getter_AddRefs(accessible));
nsCOMPtr<nsIDOMNode> domNode;
accEvent->GetDOMNode(getter_AddRefs(domNode));
PRUint32 eventType = accEvent->GetEventType();
PRBool isFromUserInput = accEvent->IsFromUserInput();
PRBool isAsync = accEvent->IsAsync();
PRBool isAsync = nsAccEvent::IsAsyncEvent(accessibleEvent);
if (domNode == gLastFocusedNode && isAsync &&
(eventType == nsIAccessibleEvent::EVENT_SHOW ||
eventType == nsIAccessibleEvent::EVENT_HIDE)) {
@ -1812,24 +1814,24 @@ nsDocAccessible::FlushPendingEvents()
// Fire reorder event if it's unconditional (see InvalidateCacheSubtree
// method) or if changed node (that is the reason of this reorder event)
// is accessible or has accessible children.
nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(accessibleEvent);
nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(accEvent);
if (reorderEvent->IsUnconditionalEvent() ||
reorderEvent->HasAccessibleInReasonSubtree()) {
nsAccEvent::PrepareForEvent(accessibleEvent);
FireAccessibleEvent(accessibleEvent);
nsAccEvent::PrepareForEvent(accEvent);
FireAccessibleEvent(accEvent);
}
}
else {
// The input state was previously stored with the nsIAccessibleEvent,
// so use that state now when firing the event
nsAccEvent::PrepareForEvent(accessibleEvent);
FireAccessibleEvent(accessibleEvent);
nsAccEvent::PrepareForEvent(accEvent);
FireAccessibleEvent(accEvent);
// Post event processing
if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
// Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in
// this subtree.
nsCOMPtr<nsIDOMNode> hidingNode;
accessibleEvent->GetDOMNode(getter_AddRefs(hidingNode));
accEvent->GetDOMNode(getter_AddRefs(hidingNode));
if (hidingNode) {
RefreshNodes(hidingNode); // Will this bite us with asynch events
}

View File

@ -432,20 +432,8 @@ __try {
groupLevel);
}
if (!description.IsEmpty()) {
*pszDescription = ::SysAllocStringLen(description.get(),
description.Length());
return *pszDescription ? S_OK : E_OUTOFMEMORY;
}
xpAccessible->GetDescription(description);
if (!description.IsEmpty()) {
// Signal to screen readers that this description is speakable
// and is not a formatted positional information description
// Don't localize the "Description: " part of this string, it will be
// parsed out by assistive technologies.
description = NS_LITERAL_STRING("Description: ") + description;
}
if (description.IsEmpty())
xpAccessible->GetDescription(description);
*pszDescription = ::SysAllocStringLen(description.get(),
description.Length());

View File

@ -78,6 +78,7 @@
<menupopup id="menu_HelpPopup" onpopupshowing="buildHelpMenu();">
<menuitem id="menu_openHelp"
oncommand="openHelpLink('firefox-help')"
onclick="checkForMiddleClick(this, event);"
label="&productHelp.label;"
accesskey="&productHelp.accesskey;"
#ifdef XP_MACOSX
@ -89,7 +90,8 @@
#ifdef XP_WIN
<menuitem label="&helpForIEUsers.label;"
accesskey="&helpForIEUsers.accesskey;"
oncommand="openHelpLink('ieusers');"/>
oncommand="openHelpLink('ieusers');"
onclick="checkForMiddleClick(this, event);"/>
#endif
<menuitem id="troubleShooting"
accesskey="&helpTroubleshootingInfo.accesskey;"

View File

@ -814,7 +814,7 @@ var allTabs = {
while (this.container.hasChildNodes())
this.container.removeChild(this.container.firstChild);
for (let i = 0; i < rows; i++)
for (let i = rows || 1; i > 0; i--)
this.container.appendChild(document.createElement("hbox"));
var row = this.container.firstChild;

File diff suppressed because it is too large Load Diff

View File

@ -46,18 +46,19 @@ import os
import sys
import logging
from getopt import getopt
import automation
from automation import Automation
PORT = 8888
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./leakprofile"))
DIST_BIN = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
os.chdir(SCRIPT_DIR)
class EasyServer(SocketServer.TCPServer):
allow_reuse_address = True
if __name__ == '__main__':
automation = Automation()
DIST_BIN = os.path.join(SCRIPT_DIR, automation.DIST_BIN)
opts, extraArgs = getopt(sys.argv[1:], 'l:')
if len(opts) > 0:
try:

View File

@ -36,7 +36,7 @@
#
# ***** END LICENSE BLOCK *****
import automation
from automation import Automation
import os
import re
import shutil
@ -47,6 +47,8 @@ import sys
#expand PROFILE_DIR = __PROFILE_DIR__
#expand CERTS_SRC_DIR = __CERTS_SRC_DIR__
automation = Automation()
dbFiles = [
re.compile("^cert[0-9]+\.db$"),
re.compile("^key[0-9]+\.db$"),

View File

@ -46,7 +46,7 @@ import os
import sys
import shutil
from datetime import datetime
import automation
from automation import Automation
PORT = 8888
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
@ -57,6 +57,7 @@ class EasyServer(SocketServer.TCPServer):
allow_reuse_address = True
if __name__ == '__main__':
automation = Automation()
httpd = EasyServer(("", PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
t = threading.Thread(target=httpd.serve_forever)
t.setDaemon(True) # don't hang on exit

View File

@ -258,10 +258,15 @@ copydir( char *from, char *to, mode_t mode, char *group, char *owner,
sprintf(destdir, "%s%s%s", to, _DIRECTORY_SEPARATOR, base);
if (mkdirs(destdir, mode) != 0) {
fail("cannot make directory %s\n", destdir);
free(destdir);
return;
}
dir = opendir(from);
if (!(dir = opendir(from))) {
fail("cannot open directory %s\n", from);
free(destdir);
return;
}
direntry = xmalloc((unsigned int)PATH_MAX);
destentry = xmalloc((unsigned int)PATH_MAX);
@ -280,6 +285,7 @@ copydir( char *from, char *to, mode_t mode, char *group, char *owner,
copyfile( direntry, destentry, mode, group, owner, dotimes, uid, gid );
}
free(destdir);
free(direntry);
free(destentry);
closedir(dir);

View File

@ -233,7 +233,7 @@ nsTextNode::List(FILE* out, PRInt32 aIndent) const
PRInt32 index;
for (index = aIndent; --index >= 0; ) fputs(" ", out);
fprintf(out, "Text@%p", this);
fprintf(out, "Text@%p", static_cast<const void*>(this));
fprintf(out, " intrinsicstate=[%08x]", IntrinsicState());
fprintf(out, " refcount=%d<", mRefCnt.get());

View File

@ -151,7 +151,8 @@ NS_IMETHODIMP
nsSVGStringProxyValue::SetValueString(const nsAString& aValue)
{
#ifdef DEBUG
printf("nsSVGStringProxyValue(%p)::SetValueString(%s)\n", this, NS_ConvertUTF16toUTF8(aValue).get());
printf("nsSVGStringProxyValue(%p)::SetValueString(%s)\n",
static_cast<void*>(this), NS_ConvertUTF16toUTF8(aValue).get());
#endif
if (NS_FAILED(mProxiedValue->SetValueString(aValue))) {
#ifdef DEBUG

View File

@ -445,8 +445,6 @@
// Drag and drop
#include "nsIDOMDataTransfer.h"
// Offline includes
#include "nsIDOMLoadStatus.h"
// Geolocation
#include "nsIDOMGeoGeolocation.h"
#include "nsIDOMGeoPosition.h"
@ -1140,8 +1138,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGTransformList, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGUnitTypes, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGZoomEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif // MOZ_SVG
@ -1208,12 +1204,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(StorageEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
// We just want this to have classinfo so it gets mark callbacks for marking
// event listeners.
// We really don't want any of the default flags!
NS_DEFINE_CLASSINFO_DATA(WindowRoot, nsEventReceiverSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DOMParser, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(XMLSerializer, nsDOMGenericSH,
@ -1242,9 +1232,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(OfflineResourceList, nsOfflineResourceListSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(LoadStatus, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(FileList, nsFileListSH,
ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(File, nsDOMGenericSH,
@ -3458,10 +3445,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGTransformList)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(SVGUnitTypes, nsIDOMSVGUnitTypes)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGUnitTypes)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(SVGZoomEvent, nsIDOMSVGZoomEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGZoomEvent)
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
@ -3538,11 +3521,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageEvent)
DOM_CLASSINFO_MAP_END
// We just want this to have classinfo so it gets mark callbacks for marking
// event listeners.
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(WindowRoot, nsISupports)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMParser, nsIDOMParser)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMParser)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMParserJS)
@ -3590,10 +3568,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(LoadStatus, nsIDOMLoadStatus)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMLoadStatus)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(ClientRect, nsIDOMClientRect)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMClientRect)
DOM_CLASSINFO_MAP_END

View File

@ -348,7 +348,6 @@ enum nsDOMClassInfoID {
eDOMClassInfo_SVGRect_id,
eDOMClassInfo_SVGTransform_id,
eDOMClassInfo_SVGTransformList_id,
eDOMClassInfo_SVGUnitTypes_id,
eDOMClassInfo_SVGZoomEvent_id,
#endif // MOZ_SVG
@ -385,8 +384,6 @@ enum nsDOMClassInfoID {
eDOMClassInfo_StorageItem_id,
eDOMClassInfo_StorageEvent_id,
eDOMClassInfo_WindowRoot_id,
// DOMParser, XMLSerializer
eDOMClassInfo_DOMParser_id,
eDOMClassInfo_XMLSerializer_id,
@ -410,7 +407,6 @@ enum nsDOMClassInfoID {
eDOMClassInfo_XULCommandEvent_id,
eDOMClassInfo_CommandEvent_id,
eDOMClassInfo_OfflineResourceList_id,
eDOMClassInfo_LoadStatus_id,
eDOMClassInfo_FileList_id,
eDOMClassInfo_File_id,

View File

@ -103,7 +103,7 @@ NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
{
char* nodename = ToNewCString(mTag);
printf("Do Create Element parent = %p <%s>, offset = %d\n",
mParent.get(), nodename, mOffsetInParent);
static_cast<void*>(mParent.get()), nodename, mOffsetInParent);
nsMemory::Free(nodename);
}
#endif
@ -126,7 +126,10 @@ NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
if (!mNewNode) return NS_ERROR_NULL_POINTER;
#ifdef NS_DEBUG
if (gNoisy) { printf(" newNode = %p\n", mNewNode.get()); }
if (gNoisy)
{
printf(" newNode = %p\n", static_cast<void*>(mNewNode.get()));
}
#endif
// insert the new node
@ -180,8 +183,12 @@ NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
NS_IMETHODIMP CreateElementTxn::UndoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("Undo Create Element, mParent = %p, node = %p\n",
mParent.get(), mNewNode.get()); }
if (gNoisy)
{
printf("Undo Create Element, mParent = %p, node = %p\n",
static_cast<void*>(mParent.get()),
static_cast<void*>(mNewNode.get()));
}
#endif
NS_ASSERTION(mEditor && mParent, "bad state");

View File

@ -98,7 +98,12 @@ NS_IMETHODIMP DeleteElementTxn::Init(nsIEditor *aEditor,
NS_IMETHODIMP DeleteElementTxn::DoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("%p Do Delete Element element = %p\n", this, mElement.get()); }
if (gNoisy)
{
printf("%p Do Delete Element element = %p\n",
static_cast<void*>(this),
static_cast<void*>(mElement.get()));
}
#endif
if (!mElement) return NS_ERROR_NOT_INITIALIZED;
@ -144,7 +149,13 @@ NS_IMETHODIMP DeleteElementTxn::DoTransaction(void)
NS_IMETHODIMP DeleteElementTxn::UndoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("%p Undo Delete Element element = %p, parent = %p\n", this, mElement.get(), mParent.get()); }
if (gNoisy)
{
printf("%p Undo Delete Element element = %p, parent = %p\n",
static_cast<void*>(this),
static_cast<void*>(mElement.get()),
static_cast<void*>(mParent.get()));
}
#endif
if (!mParent) { return NS_OK; } // this is a legal state, the txn is a no-op
@ -181,7 +192,13 @@ NS_IMETHODIMP DeleteElementTxn::UndoTransaction(void)
NS_IMETHODIMP DeleteElementTxn::RedoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("%p Redo Delete Element element = %p, parent = %p\n", this, mElement.get(), mParent.get()); }
if (gNoisy)
{
printf("%p Redo Delete Element element = %p, parent = %p\n",
static_cast<void*>(this),
static_cast<void*>(mElement.get()),
static_cast<void*>(mParent.get()));
}
#endif
if (!mParent) { return NS_OK; } // this is a legal state, the txn is a no-op

View File

@ -96,8 +96,11 @@ NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
mNode->GetNodeName(namestr);
char* nodename = ToNewCString(namestr);
printf("%p Do Insert Element of %p <%s> into parent %p at offset %d\n",
this, nodeAsContent.get(), nodename,
parentAsContent.get(), mOffset);
static_cast<void*>(this),
static_cast<void*>(nodeAsContent.get()),
nodename,
static_cast<void*>(parentAsContent.get()),
mOffset);
nsMemory::Free(nodename);
}
#endif
@ -149,8 +152,14 @@ NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
NS_IMETHODIMP InsertElementTxn::UndoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("%p Undo Insert Element of %p into parent %p at offset %d\n",
this, mNode.get(), mParent.get(), mOffset); }
if (gNoisy)
{
printf("%p Undo Insert Element of %p into parent %p at offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mNode.get()),
static_cast<void*>(mParent.get()),
mOffset);
}
#endif
if (!mNode || !mParent) return NS_ERROR_NOT_INITIALIZED;

View File

@ -93,7 +93,11 @@ NS_IMETHODIMP InsertTextTxn::Init(nsIDOMCharacterData *aElement,
NS_IMETHODIMP InsertTextTxn::DoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("Do Insert Text element = %p\n", mElement.get()); }
if (gNoisy)
{
printf("Do Insert Text element = %p\n",
static_cast<void*>(mElement.get()));
}
#endif
NS_ASSERTION(mElement && mEditor, "bad state");
@ -125,7 +129,11 @@ NS_IMETHODIMP InsertTextTxn::DoTransaction(void)
NS_IMETHODIMP InsertTextTxn::UndoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("Undo Insert Text element = %p\n", mElement.get()); }
if (gNoisy)
{
printf("Undo Insert Text element = %p\n",
static_cast<void*>(mElement.get()));
}
#endif
NS_ASSERTION(mElement && mEditor, "bad state");
@ -156,7 +164,11 @@ NS_IMETHODIMP InsertTextTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMer
mStringToInsert += otherData;
*aDidMerge = PR_TRUE;
#ifdef NS_DEBUG
if (gNoisy) { printf("InsertTextTxn assimilated %p\n", aTransaction); }
if (gNoisy)
{
printf("InsertTextTxn assimilated %p\n",
static_cast<void*>(aTransaction));
}
#endif
}
NS_RELEASE(otherInsTxn);

View File

@ -89,7 +89,13 @@ NS_IMETHODIMP JoinElementTxn::Init(nsEditor *aEditor,
NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("%p Do Join of %p and %p\n", this, mLeftNode.get(), mRightNode.get()); }
if (gNoisy)
{
printf("%p Do Join of %p and %p\n",
static_cast<void*>(this),
static_cast<void*>(mLeftNode.get()),
static_cast<void*>(mRightNode.get()));
}
#endif
NS_PRECONDITION((mEditor && mLeftNode && mRightNode), "null arg");
@ -130,7 +136,11 @@ NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
#ifdef NS_DEBUG
if (NS_SUCCEEDED(result))
{
if (gNoisy) { printf(" left node = %p removed\n", mLeftNode.get()); }
if (gNoisy)
{
printf(" left node = %p removed\n",
static_cast<void*>(mLeftNode.get()));
}
}
#endif
}
@ -147,7 +157,12 @@ NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
NS_IMETHODIMP JoinElementTxn::UndoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("%p Undo Join, right node = %p\n", this, mRightNode.get()); }
if (gNoisy)
{
printf("%p Undo Join, right node = %p\n",
static_cast<void*>(this),
static_cast<void*>(mRightNode.get()));
}
#endif
NS_ASSERTION(mRightNode && mLeftNode && mParent, "bad state");

View File

@ -83,7 +83,13 @@ NS_IMETHODIMP SplitElementTxn::Init(nsEditor *aEditor,
NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) { printf("%p Do Split of node %p offset %d\n", this, mExistingRightNode.get(), mOffset); }
if (gNoisy)
{
printf("%p Do Split of node %p offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mExistingRightNode.get()),
mOffset);
}
#endif
NS_ASSERTION(mExistingRightNode && mEditor, "bad state");
@ -97,7 +103,11 @@ NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
mEditor->MarkNodeDirty(mExistingRightNode);
#ifdef NS_DEBUG
if (gNoisy) { printf(" created left node = %p\n", mNewLeftNode.get()); }
if (gNoisy)
{
printf(" created left node = %p\n",
static_cast<void*>(mNewLeftNode.get()));
}
#endif
// get the parent node
@ -125,8 +135,11 @@ NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
{
#ifdef NS_DEBUG
if (gNoisy) {
printf("%p Undo Split of existing node %p and new node %p offset %d\n",
this, mExistingRightNode.get(), mNewLeftNode.get(), mOffset);
printf("%p Undo Split of existing node %p and new node %p offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mExistingRightNode.get()),
static_cast<void*>(mNewLeftNode.get()),
mOffset);
}
#endif
@ -140,12 +153,18 @@ NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
#ifdef NS_DEBUG
if (gNoisy)
{
printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get());
printf("** after join left child node %p into right node %p\n",
static_cast<void*>(mNewLeftNode.get()),
static_cast<void*>(mExistingRightNode.get()));
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
if (NS_SUCCEEDED(result))
{
if (gNoisy) { printf(" left node = %p removed\n", mNewLeftNode.get()); }
if (gNoisy)
{
printf(" left node = %p removed\n",
static_cast<void*>(mNewLeftNode.get()));
}
}
#endif
@ -164,8 +183,11 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
#ifdef NS_DEBUG
if (gNoisy) {
printf("%p Redo Split of existing node %p and new node %p offset %d\n",
this, mExistingRightNode.get(), mNewLeftNode.get(), mOffset);
printf("%p Redo Split of existing node %p and new node %p offset %d\n",
static_cast<void*>(this),
static_cast<void*>(mExistingRightNode.get()),
static_cast<void*>(mNewLeftNode.get()),
mOffset);
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
#endif
@ -180,7 +202,9 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
#ifdef NS_DEBUG
if (gNoisy)
{
printf("** after delete of text in right text node %p offset %d\n", rightNodeAsText.get(), mOffset);
printf("** after delete of text in right text node %p offset %d\n",
static_cast<void*>(rightNodeAsText.get()),
mOffset);
mEditor->DebugDumpContent(); // DEBUG
}
#endif
@ -203,7 +227,10 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
#ifdef NS_DEBUG
if (gNoisy)
{
printf("** move child node %p from right node %p to left node %p\n", child.get(), mExistingRightNode.get(), mNewLeftNode.get());
printf("** move child node %p from right node %p to left node %p\n",
static_cast<void*>(child.get()),
static_cast<void*>(mExistingRightNode.get()),
static_cast<void*>(mNewLeftNode.get()));
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
#endif
@ -216,7 +243,9 @@ NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
#ifdef NS_DEBUG
if (gNoisy)
{
printf("** reinsert left child node %p before right node %p\n", mNewLeftNode.get(), mExistingRightNode.get());
printf("** reinsert left child node %p before right node %p\n",
static_cast<void*>(mNewLeftNode.get()),
static_cast<void*>(mExistingRightNode.get()));
if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
}
#endif

View File

@ -85,6 +85,7 @@ public:
SurfaceTypeOS2,
SurfaceTypeWin32Printing,
SurfaceTypeQuartzImage,
SurfaceTypeScript,
SurfaceTypeQPainter,
SurfaceTypeDDraw
} gfxSurfaceType;

View File

@ -258,10 +258,15 @@ copydir( char *from, char *to, mode_t mode, char *group, char *owner,
sprintf(destdir, "%s%s%s", to, _DIRECTORY_SEPARATOR, base);
if (mkdirs(destdir, mode) != 0) {
fail("cannot make directory %s\n", destdir);
free(destdir);
return;
}
dir = opendir(from);
if (!(dir = opendir(from))) {
fail("cannot open directory %s\n", from);
free(destdir);
return;
}
direntry = xmalloc((unsigned int)PATH_MAX);
destentry = xmalloc((unsigned int)PATH_MAX);
@ -280,6 +285,7 @@ copydir( char *from, char *to, mode_t mode, char *group, char *owner,
copyfile( direntry, destentry, mode, group, owner, dotimes, uid, gid );
}
free(destdir);
free(direntry);
free(destentry);
closedir(dir);

View File

@ -4383,17 +4383,17 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
NS_NewTableCaptionFrame) },
{ NS_STYLE_DISPLAY_TABLE_ROW_GROUP,
FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
FCDATA_MAY_NEED_SCROLLFRAME | FCDATA_SKIP_ABSPOS_PUSH |
FCDATA_SKIP_ABSPOS_PUSH |
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
NS_NewTableRowGroupFrame) },
{ NS_STYLE_DISPLAY_TABLE_HEADER_GROUP,
FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
FCDATA_MAY_NEED_SCROLLFRAME | FCDATA_SKIP_ABSPOS_PUSH |
FCDATA_SKIP_ABSPOS_PUSH |
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
NS_NewTableRowGroupFrame) },
{ NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP,
FCDATA_DECL(FCDATA_IS_TABLE_PART | FCDATA_DISALLOW_OUT_OF_FLOW |
FCDATA_MAY_NEED_SCROLLFRAME | FCDATA_SKIP_ABSPOS_PUSH |
FCDATA_SKIP_ABSPOS_PUSH |
FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable),
NS_NewTableRowGroupFrame) },
{ NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP,
@ -7888,40 +7888,36 @@ nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
// See if it's a header/footer, possibly wrapped in a scroll frame.
nsTableRowGroupFrame* rowGroupFrame =
nsTableFrame::GetRowGroupFrame(childFrame);
if (rowGroupFrame) {
// If the row group was continued, then don't replicate it.
nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
if (rgNextInFlow) {
rowGroupFrame->SetRepeatable(PR_FALSE);
}
else if (rowGroupFrame->IsRepeatable()) {
// Replicate the header/footer frame.
nsTableRowGroupFrame* headerFooterFrame;
nsFrameItems childItems;
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
GetAbsoluteContainingBlock(newFrame),
nsnull);
static_cast<nsTableRowGroupFrame*>(childFrame);
// If the row group was continued, then don't replicate it.
nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
if (rgNextInFlow) {
rowGroupFrame->SetRepeatable(PR_FALSE);
}
else if (rowGroupFrame->IsRepeatable()) {
// Replicate the header/footer frame.
nsTableRowGroupFrame* headerFooterFrame;
nsFrameItems childItems;
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
GetAbsoluteContainingBlock(newFrame),
nsnull);
headerFooterFrame = static_cast<nsTableRowGroupFrame*>
(NS_NewTableRowGroupFrame(aPresShell, rowGroupFrame->GetStyleContext()));
nsIContent* headerFooter = rowGroupFrame->GetContent();
headerFooterFrame->Init(headerFooter, newFrame, nsnull);
// No ancestor bindings to worry about ordering with, so null pending
// binding is ok.
ProcessChildren(state, headerFooter, rowGroupFrame->GetStyleContext(),
headerFooterFrame, PR_TRUE, childItems, PR_FALSE,
nsnull);
NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
headerFooterFrame->SetInitialChildList(nsnull, childItems);
headerFooterFrame->SetRepeatable(PR_TRUE);
headerFooterFrame = static_cast<nsTableRowGroupFrame*>
(NS_NewTableRowGroupFrame(aPresShell, rowGroupFrame->GetStyleContext()));
nsIContent* headerFooter = rowGroupFrame->GetContent();
headerFooterFrame->Init(headerFooter, newFrame, nsnull);
ProcessChildren(state, headerFooter, rowGroupFrame->GetStyleContext(),
headerFooterFrame, PR_TRUE, childItems, PR_FALSE,
nsnull);
NS_ASSERTION(state.mFloatedItems.IsEmpty(), "unexpected floated element");
headerFooterFrame->SetInitialChildList(nsnull, childItems);
headerFooterFrame->SetRepeatable(PR_TRUE);
// Table specific initialization
headerFooterFrame->InitRepeatedFrame(aPresContext, rowGroupFrame);
// Table specific initialization
headerFooterFrame->InitRepeatedFrame(aPresContext, rowGroupFrame);
// XXX Deal with absolute and fixed frames...
childFrames.AddChild(headerFooterFrame);
}
// XXX Deal with absolute and fixed frames...
childFrames.AddChild(headerFooterFrame);
}
}

View File

@ -754,7 +754,13 @@ NS_IMETHODIMP
nsPrintEngine::Print(nsIPrintSettings* aPrintSettings,
nsIWebProgressListener* aWebProgressListener)
{
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
// If we have a print preview document, use that instead of the original
// mDocument. That way animated images etc. get printed using the same state
// as in print preview.
nsCOMPtr<nsIDOMDocument> doc =
do_QueryInterface(mPrtPreview && mPrtPreview->mPrintObject ?
mPrtPreview->mPrintObject->mDocument : mDocument);
return CommonPrint(PR_FALSE, aPrintSettings, aWebProgressListener, doc);
}

View File

@ -0,0 +1,47 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
<title>table border/css test</title>
<style type="text/css">
<!--
table {
border: 1px solid blue;
border-collapse: collapse;
}
th {
border: 1px outset silver;
}
td {
border: 1px outset silver;
}
-->
</style>
</head>
<body>
<table>
<tbody>
<tr>
<th>Table-header</th>
<th>Table-header</th>
<th>Table-header</th>
</tr>
<tr>
<td>Table-data</td>
<td>Table-data</td>
<td>Table-data</td>
</tr>
<tr>
<td>Table-data</td>
<td>Table-data</td>
<td>Table-data</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,46 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type"
content="text/html; charset=ISO-8859-1">
<title>table border/css test</title>
<style type="text/css">
<!--
table {
border: 1px solid blue;
border-collapse: collapse;
}
th {
border: 1px outset silver;
}
td {
border: 1px outset silver;
}
-->
</style>
</head>
<body>
<table border="1">
<tbody>
<tr>
<th>Table-header</th>
<th>Table-header</th>
<th>Table-header</th>
</tr>
<tr>
<td>Table-data</td>
<td>Table-data</td>
<td>Table-data</td>
</tr>
<tr>
<td>Table-data</td>
<td>Table-data</td>
<td>Table-data</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<head>
<style>
table {border-collapse:collapse}
td {border: thin solid lime}
</style>
</head>
<html >
<body style="color:lime">
<table><tr><td>cell1</td><td>cell2</td></tr>
<tr><td>cell3</td><td>cell4</td></tr></table>
</body>
</html>

View File

@ -0,0 +1,8 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html >
<body style="color:lime">
<table rules="all" frame="border" ><tr><td>cell1</td><td>cell2</td></tr>
<tr><td>cell3</td><td>cell4</td></tr></table>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<title>Bug 320979</title>
<style type="text/css">
table {border:thin hidden;
border-collapse:collapse;}
td {background: green; color: white; border:thin solid white;}
</style>
<p>There should be no red.
<TABLE>
<TBODY>
<TR>
<td>test
<td>test
</TR>
<TR>
<td>test
<td>test
</TR>
</TBODY>
</TABLE>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<title>Bug 320979</title>
<style type="text/css">
table {border-color: red}
td {background: green; color: white}
</style>
<p>There should be no red.
<TABLE rules=all border=0>
<TBODY>
<TR>
<td>test
<td>test
</TR>
<TR>
<td>test
<td>test
</TR>
</TBODY>
</TABLE>

View File

@ -135,6 +135,7 @@ random == 99850-1b.html 99850-1-ref.html # bug 471629
== 163504-1b.html 163504-1-ref.html
== 163504-2a.html 163504-2-ref.html
== 163504-2b.html 163504-2-ref.html
== 167496-1.html 167496-1-ref.html
== 169749-1.html 169749-1-ref.html
== 172073-1.html 172073-1-ref.html
== 179596-1a.html 179596-1a-ref.html
@ -170,6 +171,7 @@ random == 99850-1b.html 99850-1-ref.html # bug 471629
== 223809-1.html 223809-1-ref.html
== 228856-1.html 228856-1-ref.html
== 228856-2.html 228856-2-ref.html
== 229591-1.html 229591-1-ref.html
# == 231823-1.html 231823-1-ref.html
== 232990-1a.xhtml 232990-1-ref.xhtml
== 232990-1b.xhtml 232990-1-ref.xhtml
@ -362,6 +364,7 @@ fails == 311366-unknown-block-3.html 311366-unknown-block-3-ref.html
== 315920-29b.html 315920-29-ref.html
== 315920-30.html 315920-30-ref.html
== 316057-1.html 316057-1-ref.html
== 320979-1.html 320979-1-ref.html
!= 321402-1.html about:blank
!= 321402-2.html about:blank
== 321402-3.xul 321402-3-ref.xul
@ -702,7 +705,7 @@ fails == 386147-1.html 386147-1-ref.html # bug 447460
== 387201-3.html about:blank # Really an assertion test rather than a rendering test
== 387227-1.html 387227-1-ref.html
== 387227-2.html 387227-2-ref.html
== 387344-1.html 387344-1-ref.html
fails == 387344-1.html 387344-1-ref.html # scrolling rowgroups removed bug 28800
== 387876-1.html 387876-1-ref.html
random == 387876-2.html 387876-2-ref.html # bug 471630
== 387876-3a.html 387876-3-ref.html
@ -956,7 +959,7 @@ skip-if(MOZ_WIDGET_TOOLKIT=="cocoa") == 413292-1.html 413292-1-ref.html # disabl
== 423385-1.html 423385-1-ref.html
== 423599-1.html 423599-1-ref.html
== 423676-1.html 423676-1-ref.html
== 423823-1.html 423823-1-ref.html
fails == 423823-1.html 423823-1-ref.html # scrolling rowgroups removed bug 28800
== 424074-1.xul 424074-1-ref.xul
!= 424074-1.xul 424074-1-ref2.xul
fails-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 424074-1-ref2.xul 424074-1-ref3.xul

View File

@ -51,7 +51,7 @@ fails == border-separate-opacity-table-column.html border-separate-opacity-table
== border-separate-opacity-table-row-group.html border-separate-opacity-table-row-group-ref.html
== border-separate-opacity-table-row.html border-separate-opacity-table-row-ref.html
== border-separate-opacity-table.html border-separate-opacity-table-ref.html
!= scrollable-rowgroup-collapse-background.html scrollable-rowgroup-collapse-notref.html
!= scrollable-rowgroup-collapse-border.html scrollable-rowgroup-collapse-notref.html
!= scrollable-rowgroup-collapse-background.html scrollable-rowgroup-collapse-notref.html
!= scrollable-rowgroup-collapse-border.html scrollable-rowgroup-collapse-notref.html
!= scrollable-rowgroup-separate-background.html scrollable-rowgroup-separate-notref.html
!= scrollable-rowgroup-separate-border.html scrollable-rowgroup-separate-notref.html
== scrollable-rowgroup-separate-border.html scrollable-rowgroup-separate-notref.html # bug 28800

View File

@ -879,7 +879,8 @@ CSSImportantRule::List(FILE* out, PRInt32 aIndent) const
// Indent
for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out);
fprintf(out, "! Important rule block=%p\n", mImportantBlock.get());
fprintf(out, "! Important rule block=%p\n",
static_cast<void*>(mImportantBlock.get()));
return NS_OK;
}
#endif

View File

@ -82,7 +82,7 @@ nsTableCellMap::nsTableCellMap(nsTableFrame& aTableFrame,
nsTableRowGroupFrame* prior = nsnull;
for (PRUint32 rgX = 0; rgX < orderedRowGroups.Length(); rgX++) {
nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgX];
InsertGroupCellMap(*rgFrame, prior);
InsertGroupCellMap(rgFrame, prior);
prior = rgFrame;
}
if (aBorderCollapse) {
@ -165,7 +165,7 @@ nsTableCellMap::InsertGroupCellMap(nsCellMap* aPrevMap,
aNewMap.SetNextSibling(next);
}
void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame& aNewGroup,
void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame* aNewGroup,
nsTableRowGroupFrame*& aPrevGroup)
{
nsCellMap* newMap = new nsCellMap(aNewGroup, mBCInfo != nsnull);
@ -471,7 +471,7 @@ nsTableCellMap::ClearCols()
mBCInfo->mBottomBorders.Clear();
}
void
nsTableCellMap::InsertRows(nsTableRowGroupFrame& aParent,
nsTableCellMap::InsertRows(nsTableRowGroupFrame* aParent,
nsTArray<nsTableRowFrame*>& aRows,
PRInt32 aFirstRowIndex,
PRBool aConsiderSpans,
@ -484,7 +484,7 @@ nsTableCellMap::InsertRows(nsTableRowGroupFrame& aParent,
nsCellMap* cellMap = mFirstMap;
while (cellMap) {
nsTableRowGroupFrame* rg = cellMap->GetRowGroup();
if (rg == &aParent) {
if (rg == aParent) {
cellMap->InsertRows(*this, aRows, rowIndex, aConsiderSpans, aDamageArea);
aDamageArea.y = NS_MIN(aFirstRowIndex, aDamageArea.y);
aDamageArea.height = NS_MAX(0, GetRowCount() - aDamageArea.y);
@ -1175,10 +1175,10 @@ nsTableCellMap::SetBCBorderCorner(Corner aCorner,
else NS_ERROR("program error: Corner not found");
}
nsCellMap::nsCellMap(nsTableRowGroupFrame& aRowGroup, PRBool aIsBC)
: mRows(8), mContentRowCount(0), mRowGroupFrame(&aRowGroup),
nsCellMap::nsCellMap(nsTableRowGroupFrame* aRowGroup, PRBool aIsBC)
: mRows(8), mContentRowCount(0), mRowGroupFrame(aRowGroup),
mNextSibling(nsnull), mIsBC(aIsBC),
mPresContext(aRowGroup.PresContext())
mPresContext(aRowGroup->PresContext())
{
MOZ_COUNT_CTOR(nsCellMap);
NS_ASSERTION(mPresContext, "Must have prescontext");

View File

@ -94,7 +94,7 @@ public:
void RemoveGroupCellMap(nsTableRowGroupFrame* aRowGroup);
void InsertGroupCellMap(nsTableRowGroupFrame& aNewRowGroup,
void InsertGroupCellMap(nsTableRowGroupFrame* aNewRowGroup,
nsTableRowGroupFrame*& aPrevRowGroup);
/**
@ -140,7 +140,7 @@ public:
nsRect& aDamageArea);
/** Remove the previously gathered column information */
void ClearCols();
void InsertRows(nsTableRowGroupFrame& aRowGroup,
void InsertRows(nsTableRowGroupFrame* aRowGroup,
nsTArray<nsTableRowFrame*>& aRows,
PRInt32 aFirstRowIndex,
PRBool aConsiderSpans,
@ -306,7 +306,7 @@ public:
* @param aRowGroupFrame the row group frame this is a cellmap for
* @param aIsBC whether the table is doing border-collapse
*/
nsCellMap(nsTableRowGroupFrame& aRowGroupFrame, PRBool aIsBC);
nsCellMap(nsTableRowGroupFrame* aRowGroupFrame, PRBool aIsBC);
/** destructor
* NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED

View File

@ -65,7 +65,6 @@
#include "nsIDOMElement.h"
#include "nsIDOMHTMLElement.h"
#include "nsIDOMHTMLBodyElement.h"
#include "nsIScrollableFrame.h"
#include "nsFrameManager.h"
#include "nsCSSRendering.h"
#include "nsLayoutErrors.h"
@ -522,30 +521,24 @@ void nsTableFrame::ResetRowIndices(const nsFrameList::Slice& aRowGroupsToExclude
{
// Iterate over the row groups and adjust the row indices of all rows
// omit the rowgroups that will be inserted later
// XXXbz this code seems to assume that the row groups handed out by
// aRowGroupsToExclude are already in OrderRowGroups() order.
// There's no reason that would be true!
RowGroupArray rowGroups;
OrderRowGroups(rowGroups);
PRInt32 rowIndex = 0;
nsTableRowGroupFrame* newRgFrame = nsnull;
nsTHashtable<nsPtrHashKey<nsTableRowGroupFrame> > excludeRowGroups;
if (!excludeRowGroups.Init()) {
NS_ERROR("Failed to initialize excludeRowGroups hash.");
return;
}
nsFrameList::Enumerator excludeRowGroupsEnumerator(aRowGroupsToExclude);
if (!excludeRowGroupsEnumerator.AtEnd()) {
newRgFrame = GetRowGroupFrame(excludeRowGroupsEnumerator.get());
while (!excludeRowGroupsEnumerator.AtEnd()) {
excludeRowGroups.PutEntry(static_cast<nsTableRowGroupFrame*>(excludeRowGroupsEnumerator.get()));
excludeRowGroupsEnumerator.Next();
}
for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
nsTableRowGroupFrame* rgFrame = rowGroups[rgX];
if (rgFrame == newRgFrame) {
// omit the new rowgroup and move our iterator along
if (!excludeRowGroupsEnumerator.AtEnd()) {
newRgFrame = GetRowGroupFrame(excludeRowGroupsEnumerator.get());
excludeRowGroupsEnumerator.Next();
}
}
else {
if (!excludeRowGroups.GetEntry(rgFrame)) {
const nsFrameList& rowFrames = rgFrame->GetChildList(nsnull);
for (nsFrameList::Enumerator rows(rowFrames); !rows.AtEnd(); rows.Next()) {
if (NS_STYLE_DISPLAY_TABLE_ROW==rows.get()->GetStyleDisplay()->mDisplay) {
@ -881,7 +874,7 @@ void nsTableFrame::RemoveCell(nsTableCellFrame* aCellFrame,
}
PRInt32
nsTableFrame::GetStartRowIndex(nsTableRowGroupFrame& aRowGroupFrame)
nsTableFrame::GetStartRowIndex(nsTableRowGroupFrame* aRowGroupFrame)
{
RowGroupArray orderedRowGroups;
OrderRowGroups(orderedRowGroups);
@ -889,7 +882,7 @@ nsTableFrame::GetStartRowIndex(nsTableRowGroupFrame& aRowGroupFrame)
PRInt32 rowIndex = 0;
for (PRUint32 rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgIndex];
if (rgFrame == &aRowGroupFrame) {
if (rgFrame == aRowGroupFrame) {
break;
}
PRInt32 numRows = rgFrame->GetRowCount();
@ -899,7 +892,7 @@ nsTableFrame::GetStartRowIndex(nsTableRowGroupFrame& aRowGroupFrame)
}
// this cannot extend beyond a single row group
void nsTableFrame::AppendRows(nsTableRowGroupFrame& aRowGroupFrame,
void nsTableFrame::AppendRows(nsTableRowGroupFrame* aRowGroupFrame,
PRInt32 aRowIndex,
nsTArray<nsTableRowFrame*>& aRowFrames)
{
@ -910,20 +903,9 @@ void nsTableFrame::AppendRows(nsTableRowGroupFrame& aRowGroupFrame,
}
}
PRInt32
nsTableFrame::InsertRow(nsTableRowGroupFrame& aRowGroupFrame,
nsIFrame& aRowFrame,
PRInt32 aRowIndex,
PRBool aConsiderSpans)
{
nsAutoTArray<nsTableRowFrame*, 1> rows;
rows.AppendElement((nsTableRowFrame*)&aRowFrame);
return InsertRows(aRowGroupFrame, rows, aRowIndex, aConsiderSpans);
}
// this cannot extend beyond a single row group
PRInt32
nsTableFrame::InsertRows(nsTableRowGroupFrame& aRowGroupFrame,
nsTableFrame::InsertRows(nsTableRowGroupFrame* aRowGroupFrame,
nsTArray<nsTableRowFrame*>& aRowFrames,
PRInt32 aRowIndex,
PRBool aConsiderSpans)
@ -1004,53 +986,18 @@ void nsTableFrame::RemoveRows(nsTableRowFrame& aFirstRowFrame,
#endif
}
nsTableRowGroupFrame*
nsTableFrame::GetRowGroupFrame(nsIFrame* aFrame,
nsIAtom* aFrameTypeIn)
{
nsIFrame* rgFrame = nsnull;
nsIAtom* frameType = aFrameTypeIn;
if (!aFrameTypeIn) {
frameType = aFrame->GetType();
}
if (nsGkAtoms::tableRowGroupFrame == frameType) {
rgFrame = aFrame;
}
else if (nsGkAtoms::scrollFrame == frameType) {
nsIScrollableFrame* scrollable = do_QueryFrame(aFrame);
if (scrollable) {
nsIFrame* scrolledFrame = scrollable->GetScrolledFrame();
if (scrolledFrame) {
if (nsGkAtoms::tableRowGroupFrame == scrolledFrame->GetType()) {
rgFrame = scrolledFrame;
}
}
}
}
return (nsTableRowGroupFrame*)rgFrame;
}
// collect the rows ancestors of aFrame
PRInt32
nsTableFrame::CollectRows(nsIFrame* aFrame,
nsTArray<nsTableRowFrame*>& aCollection)
{
if (!aFrame) return 0;
NS_PRECONDITION(aFrame, "null frame");
PRInt32 numRows = 0;
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aFrame);
if (rgFrame) {
nsIFrame* childFrame = rgFrame->GetFirstChild(nsnull);
while (childFrame) {
nsTableRowFrame *rowFrame = do_QueryFrame(childFrame);
if (rowFrame) {
aCollection.AppendElement(rowFrame);
numRows++;
}
else {
numRows += CollectRows(childFrame, aCollection);
}
childFrame = childFrame->GetNextSibling();
}
nsIFrame* childFrame = aFrame->GetFirstChild(nsnull);
while (childFrame) {
aCollection.AppendElement(static_cast<nsTableRowFrame*>(childFrame));
numRows++;
childFrame = childFrame->GetNextSibling();
}
return numRows;
}
@ -1076,13 +1023,11 @@ nsTableFrame::InsertRowGroups(const nsFrameList::Slice& aRowGroups)
for (rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
for (nsFrameList::Enumerator rowgroups(aRowGroups); !rowgroups.AtEnd();
rowgroups.Next()) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(rowgroups.get());
if (orderedRowGroups[rgIndex] == rgFrame) {
if (orderedRowGroups[rgIndex] == rowgroups.get()) {
nsTableRowGroupFrame* priorRG =
(0 == rgIndex) ? nsnull : orderedRowGroups[rgIndex - 1];
// create and add the cell map for the row group
cellMap->InsertGroupCellMap(*rgFrame, priorRG);
cellMap->InsertGroupCellMap(orderedRowGroups[rgIndex], priorRG);
break;
}
@ -1095,9 +1040,7 @@ nsTableFrame::InsertRowGroups(const nsFrameList::Slice& aRowGroups)
for (rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
for (nsFrameList::Enumerator rowgroups(aRowGroups); !rowgroups.AtEnd();
rowgroups.Next()) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(rowgroups.get());
if (orderedRowGroups[rgIndex] == rgFrame) {
if (orderedRowGroups[rgIndex] == rowgroups.get()) {
nsTableRowGroupFrame* priorRG =
(0 == rgIndex) ? nsnull : orderedRowGroups[rgIndex - 1];
// collect the new row frames in an array and add them to the table
@ -1108,7 +1051,7 @@ nsTableFrame::InsertRowGroups(const nsFrameList::Slice& aRowGroups)
PRInt32 priorNumRows = priorRG->GetRowCount();
rowIndex = priorRG->GetStartRowIndex() + priorNumRows;
}
InsertRows(*rgFrame, rows, rowIndex, PR_TRUE);
InsertRows(orderedRowGroups[rgIndex], rows, rowIndex, PR_TRUE);
rows.Clear();
}
break;
@ -1697,7 +1640,6 @@ nsTableFrame::RequestSpecialHeightReflow(const nsHTMLReflowState& aReflowState)
NS_ASSERTION(IS_TABLE_CELL(frameType) ||
nsGkAtoms::tableRowFrame == frameType ||
nsGkAtoms::tableRowGroupFrame == frameType ||
nsGkAtoms::scrollFrame == frameType ||
nsGkAtoms::tableFrame == frameType,
"unexpected frame type");
@ -1993,7 +1935,7 @@ nsTableFrame::GetFirstBodyRowGroupFrame()
// Table specific version that takes into account repeated header and footer
// frames when continuing table frames
void
nsTableFrame::PushChildren(const FrameArray& aFrames,
nsTableFrame::PushChildren(const RowGroupArray& aRowGroups,
PRInt32 aPushFrom)
{
NS_PRECONDITION(aPushFrom > 0, "pushing first child");
@ -2001,17 +1943,11 @@ nsTableFrame::PushChildren(const FrameArray& aFrames,
// extract the frames from the array into a sibling list
nsFrameList frames;
PRUint32 childX;
for (childX = aPushFrom; childX < aFrames.Length(); ++childX) {
nsIFrame* f = aFrames[childX];
// Don't push repeatable frames, do push non-rowgroup frames.
// XXXbz Need to push the non-rowgroup frames, even though we don't reflow
// them, so that we don't lose them. Of course there shouldn't be any
// non-rowgroup frames here...
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(f);
NS_ASSERTION(rgFrame, "Unexpected non-row-group frame");
for (childX = aPushFrom; childX < aRowGroups.Length(); ++childX) {
nsTableRowGroupFrame* rgFrame = aRowGroups[childX];
if (!rgFrame || !rgFrame->IsRepeatable()) {
mFrames.RemoveFrame(f);
frames.AppendFrame(nsnull, f);
mFrames.RemoveFrame(rgFrame);
frames.AppendFrame(nsnull, rgFrame);
}
}
@ -2351,34 +2287,30 @@ nsTableFrame::RemoveFrame(nsIAtom* aListName,
} else {
NS_ASSERTION(!aListName, "unexpected child list");
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aOldFrame);
if (rgFrame) {
// remove the row group from the cell map
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
cellMap->RemoveGroupCellMap(rgFrame);
}
// remove the row group frame from the sibling chain
mFrames.DestroyFrame(aOldFrame);
// XXXldb [reflow branch merging 20060830] do we still need this?
if (cellMap) {
cellMap->Synchronize(this);
// Create an empty slice
ResetRowIndices(nsFrameList::Slice(mFrames, nsnull, nsnull));
nsRect damageArea;
cellMap->RebuildConsideringCells(nsnull, nsnull, 0, 0, PR_FALSE, damageArea);
}
MatchCellMapToColCache(cellMap);
} else {
// Just remove the frame
mFrames.DestroyFrame(aOldFrame);
nsTableRowGroupFrame* rgFrame =
static_cast<nsTableRowGroupFrame*>(aOldFrame);
// remove the row group from the cell map
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
cellMap->RemoveGroupCellMap(rgFrame);
}
// remove the row group frame from the sibling chain
mFrames.DestroyFrame(aOldFrame);
// the removal of a row group changes the cellmap, the columns might change
if (cellMap) {
cellMap->Synchronize(this);
// Create an empty slice
ResetRowIndices(nsFrameList::Slice(mFrames, nsnull, nsnull));
nsRect damageArea;
cellMap->RebuildConsideringCells(nsnull, nsnull, 0, 0, PR_FALSE, damageArea);
}
MatchCellMapToColCache(cellMap);
}
// for now, just bail and recalc all of the collapsing borders
// XXXldb [reflow branch merging 20060830] do we still need this?
// as the cellmap changes we need to recalc
if (IsBorderCollapse()) {
nsRect damageArea(0, 0, NS_MAX(1, GetColCount()), NS_MAX(1, GetRowCount()));
SetBCDamageArea(damageArea);
@ -2502,10 +2434,9 @@ nsTableFrame::InitChildReflowState(nsHTMLReflowState& aReflowState)
nsMargin* pCollapseBorder = nsnull;
nsPresContext* presContext = PresContext();
if (IsBorderCollapse()) {
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aReflowState.frame);
if (rgFrame) {
pCollapseBorder = rgFrame->GetBCBorderWidth(collapseBorder);
}
nsTableRowGroupFrame* rgFrame =
static_cast<nsTableRowGroupFrame*>(aReflowState.frame);
pCollapseBorder = rgFrame->GetBCBorderWidth(collapseBorder);
}
aReflowState.Init(presContext, -1, -1, pCollapseBorder, &padding);
@ -2545,7 +2476,9 @@ void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState,
}
void
nsTableFrame::OrderRowGroups(RowGroupArray& aChildren) const
nsTableFrame::OrderRowGroups(RowGroupArray& aChildren,
nsTableRowGroupFrame** aHead,
nsTableRowGroupFrame** aFoot) const
{
aChildren.Clear();
nsTableRowGroupFrame* head = nsnull;
@ -2554,33 +2487,33 @@ nsTableFrame::OrderRowGroups(RowGroupArray& aChildren) const
nsIFrame* kidFrame = mFrames.FirstChild();
while (kidFrame) {
const nsStyleDisplay* kidDisplay = kidFrame->GetStyleDisplay();
nsTableRowGroupFrame* rowGroup = GetRowGroupFrame(kidFrame);
if (NS_LIKELY(rowGroup)) {
switch(kidDisplay->mDisplay) {
case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP:
if (head) { // treat additional thead like tbody
aChildren.AppendElement(rowGroup);
}
else {
head = rowGroup;
}
break;
case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP:
if (foot) { // treat additional tfoot like tbody
aChildren.AppendElement(rowGroup);
}
else {
foot = rowGroup;
}
break;
case NS_STYLE_DISPLAY_TABLE_ROW_GROUP:
nsTableRowGroupFrame* rowGroup =
static_cast<nsTableRowGroupFrame*>(kidFrame);
switch (kidDisplay->mDisplay) {
case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP:
if (head) { // treat additional thead like tbody
aChildren.AppendElement(rowGroup);
break;
default:
NS_NOTREACHED("How did this produce an nsTableRowGroupFrame?");
// Just ignore it
break;
}
else {
head = rowGroup;
}
break;
case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP:
if (foot) { // treat additional tfoot like tbody
aChildren.AppendElement(rowGroup);
}
else {
foot = rowGroup;
}
break;
case NS_STYLE_DISPLAY_TABLE_ROW_GROUP:
aChildren.AppendElement(rowGroup);
break;
default:
NS_NOTREACHED("How did this produce an nsTableRowGroupFrame?");
// Just ignore it
break;
}
// Get the next sibling but skip it if it's also the next-in-flow, since
// a next-in-flow will not be part of the current table.
@ -2596,88 +2529,14 @@ nsTableFrame::OrderRowGroups(RowGroupArray& aChildren) const
if (head) {
aChildren.InsertElementAt(0, head);
}
if (aHead)
*aHead = head;
// put the tfoot after the last tbody
if (foot) {
aChildren.AppendElement(foot);
}
}
PRUint32
nsTableFrame::OrderRowGroups(FrameArray& aChildren,
nsTableRowGroupFrame** aHead,
nsTableRowGroupFrame** aFoot) const
{
aChildren.Clear();
// initialize out parameters
*aHead = nsnull;
*aFoot = nsnull;
FrameArray nonRowGroups;
nsIFrame* head = nsnull;
nsIFrame* foot = nsnull;
nsIFrame* kidFrame = mFrames.FirstChild();
while (kidFrame) {
const nsStyleDisplay* kidDisplay = kidFrame->GetStyleDisplay();
nsTableRowGroupFrame* rowGroup = GetRowGroupFrame(kidFrame);
if (NS_LIKELY(rowGroup)) {
switch(kidDisplay->mDisplay) {
case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP:
if (head) { // treat additional thead like tbody
aChildren.AppendElement(kidFrame);
}
else {
head = kidFrame;
*aHead = rowGroup;
}
break;
case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP:
if (foot) { // treat additional tfoot like tbody
aChildren.AppendElement(kidFrame);
}
else {
foot = kidFrame;
*aFoot = rowGroup;
}
break;
case NS_STYLE_DISPLAY_TABLE_ROW_GROUP:
aChildren.AppendElement(kidFrame);
break;
default:
break;
}
} else {
NS_NOTREACHED("Non-row-group primary frame list child of an "
"nsTableFrame? How come?");
nonRowGroups.AppendElement(kidFrame);
}
// Get the next sibling but skip it if it's also the next-in-flow, since
// a next-in-flow will not be part of the current table.
while (kidFrame) {
nsIFrame* nif = kidFrame->GetNextInFlow();
kidFrame = kidFrame->GetNextSibling();
if (kidFrame != nif)
break;
}
}
// put the thead first
if (head) {
aChildren.InsertElementAt(0, head);
}
// put the tfoot after the last tbody
if (foot) {
aChildren.AppendElement(foot);
}
PRUint32 rowGroupCount = aChildren.Length();
aChildren.AppendElements(nonRowGroups);
return rowGroupCount;
if (aFoot)
*aFoot = foot;
}
nsTableRowGroupFrame*
@ -2687,10 +2546,7 @@ nsTableFrame::GetTHead() const
while (kidFrame) {
if (kidFrame->GetStyleDisplay()->mDisplay ==
NS_STYLE_DISPLAY_TABLE_HEADER_GROUP) {
nsTableRowGroupFrame* rg = GetRowGroupFrame(kidFrame);
if (rg) {
return rg;
}
return static_cast<nsTableRowGroupFrame*>(kidFrame);
}
// Get the next sibling but skip it if it's also the next-in-flow, since
@ -2713,10 +2569,7 @@ nsTableFrame::GetTFoot() const
while (kidFrame) {
if (kidFrame->GetStyleDisplay()->mDisplay ==
NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP) {
nsTableRowGroupFrame* rg = GetRowGroupFrame(kidFrame);
if (rg) {
return rg;
}
return static_cast<nsTableRowGroupFrame*>(kidFrame);
}
// Get the next sibling but skip it if it's also the next-in-flow, since
@ -2746,13 +2599,6 @@ nsTableFrame::SetupHeaderFooterChild(const nsTableReflowState& aReflowState,
nsPresContext* presContext = PresContext();
nscoord pageHeight = presContext->GetPageSize().height;
if (aFrame->GetParent() != this || pageHeight == NS_UNCONSTRAINEDSIZE) {
// Must be a scrollable head/footer (we don't allow those to repeat), or
// page has unconstrained height for some reason.
*aDesiredHeight = 0;
return NS_OK;
}
// Reflow the child with unconstrainted height
nsHTMLReflowState kidReflowState(presContext, aReflowState.reflowState,
aFrame,
@ -2798,9 +2644,9 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
mBits.mResizedColumns ||
IsGeometryDirty();
FrameArray rowGroups;
RowGroupArray rowGroups;
nsTableRowGroupFrame *thead, *tfoot;
PRUint32 numRowGroups = OrderRowGroups(rowGroups, &thead, &tfoot);
OrderRowGroups(rowGroups, &thead, &tfoot);
PRBool pageBreak = PR_FALSE;
nscoord footerHeight = 0;
@ -2826,7 +2672,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
}
}
for (PRUint32 childX = 0; childX < numRowGroups; childX++) {
for (PRUint32 childX = 0; childX < rowGroups.Length(); childX++) {
nsIFrame* kidFrame = rowGroups[childX];
// Get the frame state bits
// See if we should only reflow the dirty child frames
@ -2845,7 +2691,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
// if the child is a tbody in paginated mode reduce the height by a repeated footer
PRBool allowRepeatedFooter = PR_FALSE;
if (isPaginated && (NS_UNCONSTRAINEDSIZE != kidAvailSize.height)) {
nsTableRowGroupFrame* kidRG = GetRowGroupFrame(kidFrame);
nsTableRowGroupFrame* kidRG =
static_cast<nsTableRowGroupFrame*>(kidFrame);
if (kidRG != thead && kidRG != tfoot && tfoot && tfoot->IsRepeatable()) {
// the child is a tbody and there is a repeatable footer
NS_ASSERTION(tfoot == rowGroups[rowGroups.Length() - 1], "Missing footer!");
@ -2894,11 +2741,11 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
if (reorder) {
// reorder row groups the reflow may have changed the nextinflows
numRowGroups = OrderRowGroups(rowGroups, &thead, &tfoot);
OrderRowGroups(rowGroups, &thead, &tfoot);
childX = rowGroups.IndexOf(kidFrame);
if (childX == RowGroupArray::NoIndex) {
// XXXbz can this happen?
childX = numRowGroups;
childX = rowGroups.Length();
}
}
// see if the rowgroup did not fit on this page might be pushed on
@ -2938,7 +2785,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
if (NS_FRAME_IS_COMPLETE(aStatus) && isPaginated &&
(NS_UNCONSTRAINEDSIZE != kidReflowState.availableHeight)) {
nsIFrame* nextKid =
(childX + 1 < numRowGroups) ? rowGroups[childX + 1] : nsnull;
(childX + 1 < rowGroups.Length()) ? rowGroups[childX + 1] : nsnull;
pageBreak = PageBreakAfter(*kidFrame, nextKid);
}
@ -2972,7 +2819,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
}
// Put the nextinflow so that it will get pushed
rowGroups.InsertElementAt(childX + 1, kidNextInFlow);
rowGroups.InsertElementAt(childX + 1,
static_cast <nsTableRowGroupFrame*>(kidNextInFlow));
// We've used up all of our available space so push the remaining
// children to the next-in-flow
@ -3066,15 +2914,10 @@ nsTableFrame::CalcDesiredHeight(const nsHTMLReflowState& aReflowState, nsHTMLRef
nscoord cellSpacingY = GetCellSpacingY();
nsMargin borderPadding = GetChildAreaOffset(&aReflowState);
// get the natural height based on the last child's (row group or scroll frame) rect
FrameArray rowGroups;
PRUint32 numRowGroups;
{
// Scope for the dummies so we don't use them by accident
nsTableRowGroupFrame *dummy1, *dummy2;
numRowGroups = OrderRowGroups(rowGroups, &dummy1, &dummy2);
}
if (numRowGroups == 0) {
// get the natural height based on the last child's (row group) rect
RowGroupArray rowGroups;
OrderRowGroups(rowGroups);
if (rowGroups.IsEmpty()) {
// tables can be used as rectangular items without content
nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
if ((NS_UNCONSTRAINEDSIZE != tableSpecifiedHeight) &&
@ -3092,7 +2935,7 @@ nsTableFrame::CalcDesiredHeight(const nsHTMLReflowState& aReflowState, nsHTMLRef
nscoord desiredHeight = borderPadding.top + borderPadding.bottom;
if (rowCount > 0 && colCount > 0) {
desiredHeight += cellSpacingY;
for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) {
for (PRUint32 rgX = 0; rgX < rowGroups.Length(); rgX++) {
desiredHeight += rowGroups[rgX]->GetSize().height + cellSpacingY;
}
}
@ -3388,7 +3231,6 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState,
PR_FALSE);
}
// Make sure child views are properly positioned
// XXX what happens if childFrame is a scroll frame and this gets skipped? see also below
}
else if (amountUsed > 0 && yOriginRG != rgRect.y) {
rgFrame->InvalidateOverflowRect();
@ -3478,8 +3320,6 @@ nsTableFrame::GetBaseline() const
OrderRowGroups(orderedRowGroups);
nsTableRowFrame* firstRow = nsnull;
for (PRUint32 rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
// XXXbz Do we really want to just let through the scrollable
// rowgroups and use their ascent?
nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgIndex];
if (rgFrame->GetRowCount()) {
firstRow = rgFrame->GetFirstRow();
@ -3625,30 +3465,31 @@ nsTableFrame::GetFrameAtOrBefore(nsIFrame* aParentFrame,
void
nsTableFrame::DumpRowGroup(nsIFrame* aKidFrame)
{
nsTableRowGroupFrame* rgFrame = GetRowGroupFrame(aKidFrame);
if (rgFrame) {
nsIFrame* cFrame = rgFrame->GetFirstChild(nsnull);
while (cFrame) {
nsTableRowFrame *rowFrame = do_QueryFrame(cFrame);
if (rowFrame) {
printf("row(%d)=%p ", rowFrame->GetRowIndex(), rowFrame);
nsIFrame* childFrame = cFrame->GetFirstChild(nsnull);
while (childFrame) {
nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
if (cellFrame) {
PRInt32 colIndex;
cellFrame->GetColIndex(colIndex);
printf("cell(%d)=%p ", colIndex, childFrame);
}
childFrame = childFrame->GetNextSibling();
if (!aKidFrame)
return;
nsIFrame* cFrame = aKidFrame->GetFirstChild(nsnull);
while (cFrame) {
nsTableRowFrame *rowFrame = do_QueryFrame(cFrame);
if (rowFrame) {
printf("row(%d)=%p ", rowFrame->GetRowIndex(),
static_cast<void*>(rowFrame));
nsIFrame* childFrame = cFrame->GetFirstChild(nsnull);
while (childFrame) {
nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
if (cellFrame) {
PRInt32 colIndex;
cellFrame->GetColIndex(colIndex);
printf("cell(%d)=%p ", colIndex, childFrame);
}
printf("\n");
childFrame = childFrame->GetNextSibling();
}
else {
DumpRowGroup(rowFrame);
}
cFrame = cFrame->GetNextSibling();
printf("\n");
}
else {
DumpRowGroup(rowFrame);
}
cFrame = cFrame->GetNextSibling();
}
}
@ -3683,7 +3524,7 @@ nsTableFrame::Dump(PRBool aDumpRows,
if (0 == (colX % 8)) {
printf("\n");
}
printf ("%d=%p ", colX, colFrame);
printf ("%d=%p ", colX, static_cast<void*>(colFrame));
nsTableColType colType = colFrame->GetColType();
switch (colType) {
case eColContent:
@ -4327,7 +4168,7 @@ BCMapCellInfo::SetInfo(nsTableRowFrame* aNewRow,
// possible
PRUint32 rgStart = aIter->mRowGroupStart;
PRUint32 rgEnd = aIter->mRowGroupEnd;
mRowGroup = mTableFrame->GetRowGroupFrame(mTopRow->GetParent());
mRowGroup = static_cast<nsTableRowGroupFrame*>(mTopRow->GetParent());
if (mRowGroup != aIter->GetCurrentRowGroup()) {
rgStart = mRowGroup->GetStartRowIndex();
rgEnd = rgStart + mRowGroup->GetRowCount() - 1;

View File

@ -480,16 +480,11 @@ public:
virtual void RemoveCell(nsTableCellFrame* aCellFrame,
PRInt32 aRowIndex);
void AppendRows(nsTableRowGroupFrame& aRowGroupFrame,
void AppendRows(nsTableRowGroupFrame* aRowGroupFrame,
PRInt32 aRowIndex,
nsTArray<nsTableRowFrame*>& aRowFrames);
PRInt32 InsertRow(nsTableRowGroupFrame& aRowGroupFrame,
nsIFrame& aFrame,
PRInt32 aRowIndex,
PRBool aConsiderSpans);
PRInt32 InsertRows(nsTableRowGroupFrame& aRowGroupFrame,
PRInt32 InsertRows(nsTableRowGroupFrame* aRowGroupFrame,
nsTArray<nsTableRowFrame*>& aFrames,
PRInt32 aRowIndex,
PRBool aConsiderSpans);
@ -629,13 +624,15 @@ protected:
const nsRect& aOriginalKidOverflowRect);
nsIFrame* GetFirstBodyRowGroupFrame();
public:
typedef nsAutoTPtrArray<nsTableRowGroupFrame, 8> RowGroupArray;
/**
* Push all our child frames from the aFrames array, in order, starting from the
* frame at aPushFrom to the end of the array. The frames are put on our overflow
* list or moved directly to our next-in-flow if one exists.
* Push all our child frames from the aRowGroups array, in order, starting
* from the frame at aPushFrom to the end of the array. The frames are put on
* our overflow list or moved directly to our next-in-flow if one exists.
*/
typedef nsAutoTPtrArray<nsIFrame, 8> FrameArray;
void PushChildren(const FrameArray& aFrames, PRInt32 aPushFrom);
protected:
void PushChildren(const RowGroupArray& aRowGroups, PRInt32 aPushFrom);
public:
// put the children frames in the display order (e.g. thead before tbodies
@ -643,8 +640,10 @@ public:
// children, and not append nulls, so the array is guaranteed to contain
// nsTableRowGroupFrames. If there are multiple theads or tfoots, all but
// the first one are treated as tbodies instead.
typedef nsAutoTPtrArray<nsTableRowGroupFrame, 8> RowGroupArray;
void OrderRowGroups(RowGroupArray& aChildren) const;
void OrderRowGroups(RowGroupArray& aChildren,
nsTableRowGroupFrame** aHead = nsnull,
nsTableRowGroupFrame** aFoot = nsnull) const;
// Return the thead, if any
nsTableRowGroupFrame* GetTHead() const;
@ -652,25 +651,6 @@ public:
// Return the tfoot, if any
nsTableRowGroupFrame* GetTFoot() const;
protected:
// As above, but does NOT actually call GetRowGroupFrame() on the kids, so
// returns an array of nsIFrames. This is to be used when you really want
// the flowable kids of the table, not the rowgroups. This outputs the thead
// and tfoot if they happen to be rowgroups. All the child nsIFrames of the
// table that return null if you call GetRowGroupFrame() on them will appear
// at the end of the array, after the tfoot, if any.
//
// aHead and aFoot must not be null.
//
// @return the number of frames in aChildren which return non-null if you
// call GetRowGroupFrame() on them.
//
// XXXbz why do we really care about the non-rowgroup kids?
PRUint32 OrderRowGroups(FrameArray& aChildren,
nsTableRowGroupFrame** aHead,
nsTableRowGroupFrame** aFoot) const;
public:
// Returns PR_TRUE if there are any cells above the row at
// aRowIndex and spanning into the row at aRowIndex, the number of
// effective columns limits the search up to that column
@ -742,11 +722,6 @@ public:
nsTArray<nsTableColFrame*>& GetColCache();
/** Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame
*/
static nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame,
nsIAtom* aFrameTypeIn = nsnull);
protected:
void SetBorderCollapse(PRBool aValue);
@ -763,7 +738,7 @@ protected:
public: /* ----- Cell Map public methods ----- */
PRInt32 GetStartRowIndex(nsTableRowGroupFrame& aRowGroupFrame);
PRInt32 GetStartRowIndex(nsTableRowGroupFrame* aRowGroupFrame);
/** returns the number of rows in this table.
*/

View File

@ -454,8 +454,7 @@ TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame,
// group may not be a child of the table.
mRowGroup.mRect.MoveTo(rg->GetOffsetTo(aTableFrame));
if (mRowGroup.mRect.Intersects(mDirtyRect - mRenderPt)) {
nsresult rv = PaintRowGroup(rg,
rg->IsPseudoStackingContextFromStyle() || rg->IsScrolled());
nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
if (NS_FAILED(rv)) return rv;
}
}

View File

@ -102,7 +102,7 @@ PRInt32 nsTableRowGroupFrame::GetStartRowIndex()
if (-1 == result) {
nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
if (tableFrame) {
return tableFrame->GetStartRowIndex(*this);
return tableFrame->GetStartRowIndex(this);
}
}
@ -253,7 +253,7 @@ nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (!IsVisibleInSelection(aBuilder))
return NS_OK;
PRBool isRoot = aBuilder->IsAtRootOfPseudoStackingContext() || IsScrolled();
PRBool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
nsDisplayTableItem* item = nsnull;
if (isRoot) {
// This background is created regardless of whether this frame is
@ -1409,7 +1409,7 @@ nsTableRowGroupFrame::AppendFrames(nsIAtom* aListName,
if (rows.Length() > 0) {
nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
if (tableFrame) {
tableFrame->AppendRows(*this, rowIndex, rows);
tableFrame->AppendRows(this, rowIndex, rows);
PresContext()->PresShell()->
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
NS_FRAME_HAS_DIRTY_CHILDREN);
@ -1463,7 +1463,7 @@ nsTableRowGroupFrame::InsertFrames(nsIAtom* aListName,
if (numRows > 0) {
nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsGkAtoms::tableRowFrame);
PRInt32 rowIndex = (prevRow) ? prevRow->GetRowIndex() + 1 : startRowIndex;
tableFrame->InsertRows(*this, rows, rowIndex, PR_TRUE);
tableFrame->InsertRows(this, rows, rowIndex, PR_TRUE);
PresContext()->PresShell()->
FrameNeedsReflow(this, nsIPresShell::eTreeChange,

View File

@ -43,7 +43,6 @@
#include "nsILineIterator.h"
#include "nsTablePainter.h"
#include "nsTArray.h"
#include "nsCSSAnonBoxes.h"
class nsTableFrame;
class nsTableRowFrame;
@ -359,13 +358,6 @@ public:
* decided not to use a cursor or we already have one set up.
*/
FrameCursorData* SetupRowCursor();
PRBool IsScrolled() {
// Note that if mOverflowY is CLIP, so is mOverflowX, and we need to clip the background
// as if the rowgroup is scrollable.
return GetStyleContext()->GetPseudo() == nsCSSAnonBoxes::scrolledContent ||
GetStyleDisplay()->mOverflowY == NS_STYLE_OVERFLOW_CLIP;
}
virtual nsILineIterator* GetLineIterator() { return this; }

View File

@ -44,54 +44,128 @@ Runs the reftest test harness.
import sys, shutil, os, os.path
SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
sys.path.append(SCRIPT_DIRECTORY)
import automation
from automation import Automation
from automationutils import *
from optparse import OptionParser
from tempfile import mkdtemp
oldcwd = os.getcwd()
os.chdir(SCRIPT_DIRECTORY)
class RefTest(object):
def getFullPath(path):
"Get an absolute path relative to oldcwd."
return os.path.normpath(os.path.join(oldcwd, os.path.expanduser(path)))
oldcwd = os.getcwd()
def createReftestProfile(options, profileDir):
"Sets up a profile for reftest."
def __init__(self, automation):
self.automation = automation
os.chdir(SCRIPT_DIRECTORY)
# Set preferences.
prefsFile = open(os.path.join(profileDir, "user.js"), "w")
prefsFile.write("""user_pref("browser.dom.window.dump.enabled", true);
""")
prefsFile.write('user_pref("reftest.timeout", %d);\n' % (options.timeout * 1000))
prefsFile.write('user_pref("ui.caretBlinkTime", -1);\n')
def getFullPath(self, path):
"Get an absolute path relative to self.oldcwd."
return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
for v in options.extraPrefs:
thispref = v.split("=")
if len(thispref) < 2:
print "Error: syntax error in --setpref=" + v
sys.exit(1)
part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
prefsFile.write(part)
# no slow script dialogs
prefsFile.write('user_pref("dom.max_script_run_time", 0);')
prefsFile.write('user_pref("dom.max_chrome_script_run_time", 0);')
prefsFile.close()
def createReftestProfile(self, options, profileDir):
"Sets up a profile for reftest."
# Set preferences.
prefsFile = open(os.path.join(profileDir, "user.js"), "w")
prefsFile.write("""user_pref("browser.dom.window.dump.enabled", true);
""")
prefsFile.write('user_pref("reftest.timeout", %d);\n' % (options.timeout * 1000))
prefsFile.write('user_pref("ui.caretBlinkTime", -1);\n')
for v in options.extraPrefs:
thispref = v.split("=")
if len(thispref) < 2:
print "Error: syntax error in --setpref=" + v
sys.exit(1)
part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
prefsFile.write(part)
# no slow script dialogs
prefsFile.write('user_pref("dom.max_script_run_time", 0);')
prefsFile.write('user_pref("dom.max_chrome_script_run_time", 0);')
prefsFile.close()
# install the reftest extension bits into the profile
profileExtensionsPath = os.path.join(profileDir, "extensions")
os.mkdir(profileExtensionsPath)
reftestExtensionPath = os.path.join(SCRIPT_DIRECTORY, "reftest")
extFile = open(os.path.join(profileExtensionsPath, "reftest@mozilla.org"), "w")
extFile.write(reftestExtensionPath)
extFile.close()
def runTests(self, manifest, options):
debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs,
options.debuggerInteractive);
profileDir = None
try:
profileDir = mkdtemp()
self.createReftestProfile(options, profileDir)
self.copyExtraFilesToProfile(options, profileDir)
# browser environment
browserEnv = self.automation.environment(xrePath = options.xrePath)
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
# Enable leaks detection to its own log file.
leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
browserEnv["XPCOM_MEM_BLOAT_LOG"] = leakLogFile
# run once with -silent to let the extension manager do its thing
# and then exit the app
self.automation.log.info("REFTEST INFO | runreftest.py | Performing extension manager registration: start.\n")
# Don't care about this |status|: |runApp()| reporting it should be enough.
status = self.automation.runApp(None, browserEnv, options.app, profileDir,
["-silent"],
utilityPath = options.utilityPath,
xrePath=options.xrePath,
symbolsPath=options.symbolsPath)
# We don't care to call |processLeakLog()| for this step.
self.automation.log.info("\nREFTEST INFO | runreftest.py | Performing extension manager registration: end.")
# Remove the leak detection file so it can't "leak" to the tests run.
# The file is not there if leak logging was not enabled in the application build.
if os.path.exists(leakLogFile):
os.remove(leakLogFile)
# then again to actually run reftest
self.automation.log.info("REFTEST INFO | runreftest.py | Running tests: start.\n")
reftestlist = self.getFullPath(manifest)
status = self.automation.runApp(None, browserEnv, options.app, profileDir,
["-reftest", reftestlist],
utilityPath = options.utilityPath,
xrePath=options.xrePath,
debuggerInfo=debuggerInfo,
symbolsPath=options.symbolsPath,
# give the JS harness 30 seconds to deal
# with its own timeouts
timeout=options.timeout + 30.0)
processLeakLog(leakLogFile, options.leakThreshold)
self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
finally:
if profileDir:
shutil.rmtree(profileDir)
return status
def copyExtraFilesToProfile(self, options, profileDir):
"Copy extra files or dirs specified on the command line to the testing profile."
for f in options.extraProfileFiles:
abspath = self.getFullPath(f)
dest = os.path.join(profileDir, os.path.basename(abspath))
if os.path.isdir(abspath):
shutil.copytree(abspath, dest)
else:
shutil.copy(abspath, dest)
# install the reftest extension bits into the profile
profileExtensionsPath = os.path.join(profileDir, "extensions")
os.mkdir(profileExtensionsPath)
reftestExtensionPath = os.path.join(SCRIPT_DIRECTORY, "reftest")
extFile = open(os.path.join(profileExtensionsPath, "reftest@mozilla.org"), "w")
extFile.write(reftestExtensionPath)
extFile.close()
def main():
automation = Automation()
parser = OptionParser()
reftest = RefTest(automation)
# we want to pass down everything from automation.__all__
addCommonOptions(parser, defaults=dict(zip(automation.__all__, [getattr(automation, x) for x in automation.__all__])))
automation.addExtraCommonOptions(parser)
addCommonOptions(parser,
defaults=dict(zip(automation.__all__,
[getattr(automation, x) for x in automation.__all__])))
automation.addCommonOptions(parser)
parser.add_option("--appname",
action = "store", type = "string", dest = "app",
default = os.path.join(SCRIPT_DIRECTORY, automation.DEFAULT_APP),
@ -118,90 +192,28 @@ def main():
"programs (xpcshell, ssltunnel, certutil)")
options, args = parser.parse_args()
if len(args) != 1:
print >>sys.stderr, "No reftest.list specified."
sys.exit(1)
options.app = getFullPath(options.app)
options.app = reftest.getFullPath(options.app)
if not os.path.exists(options.app):
print """Error: Path %(app)s doesn't exist.
Are you executing $objdir/_tests/reftest/runreftest.py?""" \
% {"app": options.app}
% {"app": options.app}
sys.exit(1)
if options.xrePath is None:
options.xrePath = os.path.dirname(options.app)
else:
# allow relative paths
options.xrePath = getFullPath(options.xrePath)
options.xrePath = reftest.getFullPath(options.xrePath)
if options.symbolsPath:
options.symbolsPath = getFullPath(options.symbolsPath)
options.utilityPath = getFullPath(options.utilityPath)
debuggerInfo = getDebuggerInfo(oldcwd, options.debugger, options.debuggerArgs,
options.debuggerInteractive);
profileDir = None
try:
profileDir = mkdtemp()
createReftestProfile(options, profileDir)
copyExtraFilesToProfile(options, profileDir)
# browser environment
browserEnv = automation.environment(xrePath = options.xrePath)
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
# Enable leaks detection to its own log file.
leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
browserEnv["XPCOM_MEM_BLOAT_LOG"] = leakLogFile
# run once with -silent to let the extension manager do its thing
# and then exit the app
automation.log.info("REFTEST INFO | runreftest.py | Performing extension manager registration: start.\n")
# Don't care about this |status|: |runApp()| reporting it should be enough.
status = automation.runApp(None, browserEnv, options.app, profileDir,
["-silent"],
utilityPath = options.utilityPath,
xrePath=options.xrePath,
symbolsPath=options.symbolsPath)
# We don't care to call |processLeakLog()| for this step.
automation.log.info("\nREFTEST INFO | runreftest.py | Performing extension manager registration: end.")
# Remove the leak detection file so it can't "leak" to the tests run.
# The file is not there if leak logging was not enabled in the application build.
if os.path.exists(leakLogFile):
os.remove(leakLogFile)
# then again to actually run reftest
automation.log.info("REFTEST INFO | runreftest.py | Running tests: start.\n")
reftestlist = getFullPath(args[0])
status = automation.runApp(None, browserEnv, options.app, profileDir,
["-reftest", reftestlist],
utilityPath = options.utilityPath,
xrePath=options.xrePath,
debuggerInfo=debuggerInfo,
symbolsPath=options.symbolsPath,
# give the JS harness 30 seconds to deal
# with its own timeouts
timeout=options.timeout + 30.0)
processLeakLog(leakLogFile, options.leakThreshold)
automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
finally:
if profileDir:
shutil.rmtree(profileDir)
sys.exit(status)
def copyExtraFilesToProfile(options, profileDir):
"Copy extra files or dirs specified on the command line to the testing profile."
for f in options.extraProfileFiles:
abspath = getFullPath(f)
dest = os.path.join(profileDir, os.path.basename(abspath))
if os.path.isdir(abspath):
shutil.copytree(abspath, dest)
else:
shutil.copy(abspath, dest)
options.symbolsPath = reftest.getFullPath(options.symbolsPath)
options.utilityPath = reftest.getFullPath(options.utilityPath)
sys.exit(reftest.runTests(args[0], options))
if __name__ == "__main__":
main()

View File

@ -52,40 +52,9 @@ import shutil
from urllib import quote_plus as encodeURIComponent
import urllib2
import commands
import automation
from automation import Automation
from automationutils import *
# Path to the test script on the server
TEST_SERVER_HOST = "localhost:8888"
TEST_PATH = "/tests/"
CHROME_PATH = "/redirect.html";
A11Y_PATH = "/redirect-a11y.html"
TESTS_URL = "http://" + TEST_SERVER_HOST + TEST_PATH
CHROMETESTS_URL = "http://" + TEST_SERVER_HOST + CHROME_PATH
A11YTESTS_URL = "http://" + TEST_SERVER_HOST + A11Y_PATH
SERVER_SHUTDOWN_URL = "http://" + TEST_SERVER_HOST + "/server/shutdown"
# main browser chrome URL, same as browser.chromeURL pref
#ifdef MOZ_SUITE
BROWSER_CHROME_URL = "chrome://navigator/content/navigator.xul"
#else
BROWSER_CHROME_URL = "chrome://browser/content/browser.xul"
#endif
# Max time in seconds to wait for server startup before tests will fail -- if
# this seems big, it's mostly for debug machines where cold startup
# (particularly after a build) takes forever.
if automation.IS_DEBUG_BUILD:
SERVER_STARTUP_TIMEOUT = 180
else:
SERVER_STARTUP_TIMEOUT = 90
oldcwd = os.getcwd()
SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
os.chdir(SCRIPT_DIRECTORY)
PROFILE_DIRECTORY = os.path.abspath("./mochitesttestingprofile")
LEAK_REPORT_FILE = os.path.join(PROFILE_DIRECTORY, "runtests_leaks.log")
#######################
# COMMANDLINE OPTIONS #
@ -93,13 +62,15 @@ LEAK_REPORT_FILE = os.path.join(PROFILE_DIRECTORY, "runtests_leaks.log")
class MochitestOptions(optparse.OptionParser):
"""Parses Mochitest commandline options."""
def __init__(self, **kwargs):
def __init__(self, automation, scriptdir, **kwargs):
self._automation = automation
optparse.OptionParser.__init__(self, **kwargs)
defaults = {}
# we want to pass down everything from automation.__all__
addCommonOptions(self, defaults=dict(zip(automation.__all__, [getattr(automation, x) for x in automation.__all__])))
automation.addExtraCommonOptions(self)
# we want to pass down everything from self._automation.__all__
addCommonOptions(self, defaults=dict(zip(self._automation.__all__,
[getattr(self._automation, x) for x in self._automation.__all__])))
self._automation.addCommonOptions(self)
self.add_option("--close-when-done",
action = "store_true", dest = "closeWhenDone",
@ -109,17 +80,17 @@ class MochitestOptions(optparse.OptionParser):
self.add_option("--appname",
action = "store", type = "string", dest = "app",
help = "absolute path to application, overriding default")
defaults["app"] = os.path.join(SCRIPT_DIRECTORY, automation.DEFAULT_APP)
defaults["app"] = os.path.join(scriptdir, self._automation.DEFAULT_APP)
self.add_option("--utility-path",
action = "store", type = "string", dest = "utilityPath",
help = "absolute path to directory containing utility programs (xpcshell, ssltunnel, certutil)")
defaults["utilityPath"] = automation.DIST_BIN
defaults["utilityPath"] = self._automation.DIST_BIN
self.add_option("--certificate-path",
action = "store", type = "string", dest = "certPath",
help = "absolute path to directory containing certificate store to use testing profile")
defaults["certPath"] = automation.CERTS_SRC_DIR
defaults["certPath"] = self._automation.CERTS_SRC_DIR
self.add_option("--log-file",
action = "store", type = "string",
@ -249,17 +220,19 @@ See <http://mochikit.com/doc/html/MochiKit/Logging.html> for details on the logg
class MochitestServer:
"Web server used to serve Mochitests, for closer fidelity to the real web."
def __init__(self, options):
def __init__(self, automation, options, profileDir):
self._automation = automation
self._closeWhenDone = options.closeWhenDone
self._utilityPath = options.utilityPath
self._xrePath = options.xrePath
self._profileDir = profileDir
def start(self):
"Run the Mochitest server, returning the process ID of the server."
env = automation.environment(xrePath = self._xrePath)
env = self._automation.environment(xrePath = self._xrePath)
env["XPCOM_DEBUG_BREAK"] = "warn"
if automation.IS_WIN32:
if self._automation.IS_WIN32:
env["PATH"] = env["PATH"] + ";" + self._xrePath
args = ["-g", self._xrePath,
@ -268,19 +241,18 @@ class MochitestServer:
"-f", "./" + "server.js"]
xpcshell = os.path.join(self._utilityPath,
"xpcshell" + automation.BIN_SUFFIX)
self._process = automation.Process([xpcshell] + args, env = env)
"xpcshell" + self._automation.BIN_SUFFIX)
self._process = self._automation.Process([xpcshell] + args, env = env)
pid = self._process.pid
if pid < 0:
print "Error starting server."
sys.exit(2)
automation.log.info("INFO | runtests.py | Server pid: %d", pid)
self._automation.log.info("INFO | runtests.py | Server pid: %d", pid)
def ensureReady(self, timeout):
assert timeout >= 0
aliveFile = os.path.join(PROFILE_DIRECTORY, "server_alive.txt")
aliveFile = os.path.join(self._profileDir, "server_alive.txt")
i = 0
while i < timeout:
if os.path.exists(aliveFile):
@ -301,16 +273,261 @@ class MochitestServer:
except:
self._process.kill()
def getFullPath(path):
"Get an absolute path relative to oldcwd."
return os.path.normpath(os.path.join(oldcwd, os.path.expanduser(path)))
#################
# MAIN FUNCTION #
#################
class Mochitest(object):
# Path to the test script on the server
TEST_SERVER_HOST = "localhost:8888"
TEST_PATH = "/tests/"
CHROME_PATH = "/redirect.html";
A11Y_PATH = "/redirect-a11y.html"
TESTS_URL = "http://" + TEST_SERVER_HOST + TEST_PATH
CHROMETESTS_URL = "http://" + TEST_SERVER_HOST + CHROME_PATH
A11YTESTS_URL = "http://" + TEST_SERVER_HOST + A11Y_PATH
SERVER_SHUTDOWN_URL = "http://" + TEST_SERVER_HOST + "/server/shutdown"
oldcwd = os.getcwd()
def __init__(self, automation):
self.automation = automation
# Max time in seconds to wait for server startup before tests will fail -- if
# this seems big, it's mostly for debug machines where cold startup
# (particularly after a build) takes forever.
if self.automation.IS_DEBUG_BUILD:
self.SERVER_STARTUP_TIMEOUT = 180
else:
self.SERVER_STARTUP_TIMEOUT = 90
self.SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
os.chdir(self.SCRIPT_DIRECTORY)
self.PROFILE_DIRECTORY = os.path.abspath("./mochitesttestingprofile")
self.LEAK_REPORT_FILE = os.path.join(self.PROFILE_DIRECTORY, "runtests_leaks.log")
def getFullPath(self, path):
"Get an absolute path relative to self.oldcwd."
return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
def runTests(self, options):
debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs,
options.debuggerInteractive);
# browser environment
browserEnv = self.automation.environment(xrePath = options.xrePath)
# These variables are necessary for correct application startup; change
# via the commandline at your own risk.
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
for v in options.environment:
ix = v.find("=")
if ix <= 0:
print "Error: syntax error in --setenv=" + v
return 1
browserEnv[v[:ix]] = v[ix + 1:]
self.automation.initializeProfile(self.PROFILE_DIRECTORY, options.extraPrefs)
manifest = self.addChromeToProfile(options)
self.copyExtraFilesToProfile(options)
server = MochitestServer(self.automation, options, self.PROFILE_DIRECTORY)
server.start()
# If we're lucky, the server has fully started by now, and all paths are
# ready, etc. However, xpcshell cold start times suck, at least for debug
# builds. We'll try to connect to the server for awhile, and if we fail,
# we'll try to kill the server and exit with an error.
server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
# URL parameters to test URL:
#
# autorun -- kick off tests automatically
# closeWhenDone -- runs quit.js after tests
# logFile -- logs test run to an absolute path
# totalChunks -- how many chunks to split tests into
# thisChunk -- which chunk to run
# timeout -- per-test timeout in seconds
#
# consoleLevel, fileLevel: set the logging level of the console and
# file logs, if activated.
# <http://mochikit.com/doc/html/MochiKit/Logging.html>
testURL = self.TESTS_URL + options.testPath
urlOpts = []
if options.chrome:
testURL = self.CHROMETESTS_URL
if options.testPath:
urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
elif options.a11y:
testURL = self.A11YTESTS_URL
if options.testPath:
urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
elif options.browserChrome:
testURL = "about:blank"
# allow relative paths for logFile
if options.logFile:
options.logFile = self.getFullPath(options.logFile)
if options.browserChrome:
self.makeTestConfig(options)
else:
if options.autorun:
urlOpts.append("autorun=1")
if options.timeout:
urlOpts.append("timeout=%d" % options.timeout)
if options.closeWhenDone:
urlOpts.append("closeWhenDone=1")
if options.logFile:
urlOpts.append("logFile=" + encodeURIComponent(options.logFile))
urlOpts.append("fileLevel=" + encodeURIComponent(options.fileLevel))
if options.consoleLevel:
urlOpts.append("consoleLevel=" + encodeURIComponent(options.consoleLevel))
if options.totalChunks:
urlOpts.append("totalChunks=%d" % options.totalChunks)
urlOpts.append("thisChunk=%d" % options.thisChunk)
if options.chunkByDir:
urlOpts.append("chunkByDir=%d" % options.chunkByDir)
if options.shuffle:
urlOpts.append("shuffle=1")
if len(urlOpts) > 0:
testURL += "?" + "&".join(urlOpts)
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.LEAK_REPORT_FILE
if options.fatalAssertions:
browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
# run once with -silent to let the extension manager do its thing
# and then exit the app
self.automation.log.info("INFO | runtests.py | Performing extension manager registration: start.\n")
# Don't care about this |status|: |runApp()| reporting it should be enough.
status = self.automation.runApp(None, browserEnv, options.app,
self.PROFILE_DIRECTORY, ["-silent"],
utilityPath = options.utilityPath,
xrePath = options.xrePath,
symbolsPath=options.symbolsPath)
# We don't care to call |processLeakLog()| for this step.
self.automation.log.info("\nINFO | runtests.py | Performing extension manager registration: end.")
# Remove the leak detection file so it can't "leak" to the tests run.
# The file is not there if leak logging was not enabled in the application build.
if os.path.exists(self.LEAK_REPORT_FILE):
os.remove(self.LEAK_REPORT_FILE)
# then again to actually run mochitest
if options.timeout:
timeout = options.timeout + 30
elif options.autorun:
timeout = None
else:
timeout = 330.0 # default JS harness timeout is 300 seconds
self.automation.log.info("INFO | runtests.py | Running tests: start.\n")
status = self.automation.runApp(testURL, browserEnv, options.app,
self.PROFILE_DIRECTORY, options.browserArgs,
runSSLTunnel = True,
utilityPath = options.utilityPath,
xrePath = options.xrePath,
certPath=options.certPath,
debuggerInfo=debuggerInfo,
symbolsPath=options.symbolsPath,
timeout = timeout)
# Server's no longer needed, and perhaps more importantly, anything it might
# spew to console shouldn't disrupt the leak information table we print next.
server.stop()
processLeakLog(self.LEAK_REPORT_FILE, options.leakThreshold)
self.automation.log.info("\nINFO | runtests.py | Running tests: end.")
# delete the profile and manifest
os.remove(manifest)
# hanging due to non-halting threads is no fun; assume we hit the errors we
# were going to hit already and exit.
return status
def makeTestConfig(self, options):
"Creates a test configuration file for customizing test execution."
def boolString(b):
if b:
return "true"
return "false"
logFile = options.logFile.replace("\\", "\\\\")
testPath = options.testPath.replace("\\", "\\\\")
content = """\
({
autoRun: %(autorun)s,
closeWhenDone: %(closeWhenDone)s,
logPath: "%(logPath)s",
testPath: "%(testPath)s"
})""" % {"autorun": boolString(options.autorun),
"closeWhenDone": boolString(options.closeWhenDone),
"logPath": logFile,
"testPath": testPath}
config = open(os.path.join(self.PROFILE_DIRECTORY, "testConfig.js"), "w")
config.write(content)
config.close()
def addChromeToProfile(self, options):
"Adds MochiKit chrome tests to the profile."
chromedir = os.path.join(self.PROFILE_DIRECTORY, "chrome")
os.mkdir(chromedir)
chrome = """
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
toolbar,
toolbarpalette {
background-color: rgb(235, 235, 235) !important;
}
toolbar#nav-bar {
background-image: none !important;
}
"""
# write userChrome.css
chromeFile = open(os.path.join(self.PROFILE_DIRECTORY, "userChrome.css"), "a")
chromeFile.write(chrome)
chromeFile.close()
# register our chrome dir
chrometestDir = os.path.abspath(".") + "/"
if self.automation.IS_WIN32:
chrometestDir = "file:///" + chrometestDir.replace("\\", "/")
(path, leaf) = os.path.split(options.app)
manifest = os.path.join(path, "chrome", "mochikit.manifest")
manifestFile = open(manifest, "w")
manifestFile.write("content mochikit " + chrometestDir + " contentaccessible=yes\n")
if options.browserChrome:
manifestFile.write("""overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
""")
manifestFile.close()
return manifest
def copyExtraFilesToProfile(self, options):
"Copy extra files or dirs specified on the command line to the testing profile."
for f in options.extraProfileFiles:
abspath = self.getFullPath(f)
dest = os.path.join(self.PROFILE_DIRECTORY, os.path.basename(abspath))
if os.path.isdir(abspath):
shutil.copytree(abspath, dest)
else:
shutil.copy(abspath, dest)
def main():
parser = MochitestOptions()
automation = Automation()
mochitest = Mochitest(automation)
parser = MochitestOptions(automation, mochitest.SCRIPT_DIRECTORY)
options, args = parser.parse_args()
if options.totalChunks is not None and options.thisChunk is None:
@ -318,7 +535,7 @@ def main():
if options.totalChunks:
if not 1 <= options.thisChunk <= options.totalChunks:
parser.error("thisChunk must be between 1 and totalChunks")
parser.error("thisChunk must be between 1 and totalChunks")
if options.xrePath is None:
# default xrePath to the app path if not provided
@ -330,248 +547,22 @@ def main():
options.xrePath = automation.DIST_BIN
# allow relative paths
options.xrePath = getFullPath(options.xrePath)
options.xrePath = mochitest.getFullPath(options.xrePath)
options.app = getFullPath(options.app)
options.app = mochitest.getFullPath(options.app)
if not os.path.exists(options.app):
msg = """\
Error: Path %(app)s doesn't exist.
Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
Error: Path %(app)s doesn't exist.
Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
print msg % {"app": options.app}
sys.exit(1)
options.utilityPath = getFullPath(options.utilityPath)
options.certPath = getFullPath(options.certPath)
options.utilityPath = mochitest.getFullPath(options.utilityPath)
options.certPath = mochitest.getFullPath(options.certPath)
if options.symbolsPath:
options.symbolsPath = getFullPath(options.symbolsPath)
options.symbolsPath = mochitest.getFullPath(options.symbolsPath)
debuggerInfo = getDebuggerInfo(oldcwd, options.debugger, options.debuggerArgs,
options.debuggerInteractive);
# browser environment
browserEnv = automation.environment(xrePath = options.xrePath)
# These variables are necessary for correct application startup; change
# via the commandline at your own risk.
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
for v in options.environment:
ix = v.find("=")
if ix <= 0:
print "Error: syntax error in --setenv=" + v
sys.exit(1)
browserEnv[v[:ix]] = v[ix + 1:]
automation.initializeProfile(PROFILE_DIRECTORY, options.extraPrefs)
manifest = addChromeToProfile(options)
copyExtraFilesToProfile(options)
server = MochitestServer(options)
server.start()
# If we're lucky, the server has fully started by now, and all paths are
# ready, etc. However, xpcshell cold start times suck, at least for debug
# builds. We'll try to connect to the server for awhile, and if we fail,
# we'll try to kill the server and exit with an error.
server.ensureReady(SERVER_STARTUP_TIMEOUT)
# URL parameters to test URL:
#
# autorun -- kick off tests automatically
# closeWhenDone -- runs quit.js after tests
# logFile -- logs test run to an absolute path
# totalChunks -- how many chunks to split tests into
# thisChunk -- which chunk to run
# timeout -- per-test timeout in seconds
#
# consoleLevel, fileLevel: set the logging level of the console and
# file logs, if activated.
# <http://mochikit.com/doc/html/MochiKit/Logging.html>
testURL = TESTS_URL + options.testPath
urlOpts = []
if options.chrome:
testURL = CHROMETESTS_URL
if options.testPath:
urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
elif options.a11y:
testURL = A11YTESTS_URL
if options.testPath:
urlOpts.append("testPath=" + encodeURIComponent(options.testPath))
elif options.browserChrome:
testURL = "about:blank"
# allow relative paths for logFile
if options.logFile:
options.logFile = getFullPath(options.logFile)
if options.browserChrome:
makeTestConfig(options)
else:
if options.autorun:
urlOpts.append("autorun=1")
if options.timeout:
urlOpts.append("timeout=%d" % options.timeout)
if options.closeWhenDone:
urlOpts.append("closeWhenDone=1")
if options.logFile:
urlOpts.append("logFile=" + encodeURIComponent(options.logFile))
urlOpts.append("fileLevel=" + encodeURIComponent(options.fileLevel))
if options.consoleLevel:
urlOpts.append("consoleLevel=" + encodeURIComponent(options.consoleLevel))
if options.totalChunks:
urlOpts.append("totalChunks=%d" % options.totalChunks)
urlOpts.append("thisChunk=%d" % options.thisChunk)
if options.chunkByDir:
urlOpts.append("chunkByDir=%d" % options.chunkByDir)
if options.shuffle:
urlOpts.append("shuffle=1")
if len(urlOpts) > 0:
testURL += "?" + "&".join(urlOpts)
browserEnv["XPCOM_MEM_BLOAT_LOG"] = LEAK_REPORT_FILE
if options.fatalAssertions:
browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
# run once with -silent to let the extension manager do its thing
# and then exit the app
automation.log.info("INFO | runtests.py | Performing extension manager registration: start.\n")
# Don't care about this |status|: |runApp()| reporting it should be enough.
status = automation.runApp(None, browserEnv, options.app,
PROFILE_DIRECTORY, ["-silent"],
utilityPath = options.utilityPath,
xrePath = options.xrePath,
symbolsPath=options.symbolsPath)
# We don't care to call |processLeakLog()| for this step.
automation.log.info("\nINFO | runtests.py | Performing extension manager registration: end.")
# Remove the leak detection file so it can't "leak" to the tests run.
# The file is not there if leak logging was not enabled in the application build.
if os.path.exists(LEAK_REPORT_FILE):
os.remove(LEAK_REPORT_FILE)
# then again to actually run mochitest
if options.timeout:
timeout = options.timeout + 30
elif options.autorun:
timeout = None
else:
timeout = 330.0 # default JS harness timeout is 300 seconds
automation.log.info("INFO | runtests.py | Running tests: start.\n")
status = automation.runApp(testURL, browserEnv, options.app,
PROFILE_DIRECTORY, options.browserArgs,
runSSLTunnel = True,
utilityPath = options.utilityPath,
xrePath = options.xrePath,
certPath=options.certPath,
debuggerInfo=debuggerInfo,
symbolsPath=options.symbolsPath,
timeout = timeout)
# Server's no longer needed, and perhaps more importantly, anything it might
# spew to console shouldn't disrupt the leak information table we print next.
server.stop()
processLeakLog(LEAK_REPORT_FILE, options.leakThreshold)
automation.log.info("\nINFO | runtests.py | Running tests: end.")
# delete the profile and manifest
os.remove(manifest)
# hanging due to non-halting threads is no fun; assume we hit the errors we
# were going to hit already and exit.
sys.exit(status)
#######################
# CONFIGURATION SETUP #
#######################
def makeTestConfig(options):
"Creates a test configuration file for customizing test execution."
def boolString(b):
if b:
return "true"
return "false"
logFile = options.logFile.replace("\\", "\\\\")
testPath = options.testPath.replace("\\", "\\\\")
content = """\
({
autoRun: %(autorun)s,
closeWhenDone: %(closeWhenDone)s,
logPath: "%(logPath)s",
testPath: "%(testPath)s"
})""" % {"autorun": boolString(options.autorun),
"closeWhenDone": boolString(options.closeWhenDone),
"logPath": logFile,
"testPath": testPath}
config = open(os.path.join(PROFILE_DIRECTORY, "testConfig.js"), "w")
config.write(content)
config.close()
def addChromeToProfile(options):
"Adds MochiKit chrome tests to the profile."
chromedir = os.path.join(PROFILE_DIRECTORY, "chrome")
os.mkdir(chromedir)
chrome = []
part = """
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
toolbar,
toolbarpalette {
background-color: rgb(235, 235, 235) !important;
}
toolbar#nav-bar {
background-image: none !important;
}
"""
chrome.append(part)
# write userChrome.css
chromeFile = open(os.path.join(PROFILE_DIRECTORY, "userChrome.css"), "a")
chromeFile.write("".join(chrome))
chromeFile.close()
# register our chrome dir
chrometestDir = os.path.abspath(".") + "/"
if automation.IS_WIN32:
chrometestDir = "file:///" + chrometestDir.replace("\\", "/")
(path, leaf) = os.path.split(options.app)
manifest = os.path.join(path, "chrome", "mochikit.manifest")
manifestFile = open(manifest, "w")
manifestFile.write("content mochikit " + chrometestDir + " contentaccessible=yes\n")
if options.browserChrome:
overlayLine = "overlay " + BROWSER_CHROME_URL + " " \
"chrome://mochikit/content/browser-test-overlay.xul\n"
manifestFile.write(overlayLine)
manifestFile.close()
return manifest
def copyExtraFilesToProfile(options):
"Copy extra files or dirs specified on the command line to the testing profile."
for f in options.extraProfileFiles:
abspath = getFullPath(f)
dest = os.path.join(PROFILE_DIRECTORY, os.path.basename(abspath))
if os.path.isdir(abspath):
shutil.copytree(abspath, dest)
else:
shutil.copy(abspath, dest)
#########
# DO IT #
#########
sys.exit(mochitest.runTests(options))
if __name__ == "__main__":
main()

View File

@ -200,10 +200,18 @@ bool ReadConnectRequest(server_info_t* server_info,
relayBuffer& buffer, PRInt32* result, string& certificate,
client_auth_option* clientauth, string& host)
{
if (buffer.present() < 4)
if (buffer.present() < 4) {
printf(" !! only %d bytes present in the buffer", (int)buffer.present());
return false;
if (strncmp(buffer.buffertail-4, "\r\n\r\n", 4))
}
if (strncmp(buffer.buffertail-4, "\r\n\r\n", 4)) {
printf(" !! request is not tailed with CRLFCRLF but with %x %x %x %x",
*(buffer.buffertail-4),
*(buffer.buffertail-3),
*(buffer.buffertail-2),
*(buffer.buffertail-1));
return false;
}
*result = 400;
@ -293,6 +301,7 @@ bool AdjustRequestURI(relayBuffer& buffer, string *host)
// Cannot use strnchr so add a null char at the end. There is always some space left
// because we preserve a margin.
buffer.buffertail[1] = '\0';
printf(" incoming request to adjust:\n%s\n", buffer.bufferhead);
char *token, *path;
path = strchr(buffer.bufferhead, ' ') + 1;
@ -548,6 +557,9 @@ void HandleConnection(void* data)
else
{
printf(", writen %d bytes", bytesWrite);
buffers[s2].buffertail[1] = '\0';
printf(" dump:\n%.*s\n", bytesWrite, buffers[s2].bufferhead);
buffers[s2].bufferhead += bytesWrite;
if (buffers[s2].present())
{

View File

@ -22,6 +22,7 @@
# Contributor(s):
# Serge Gautherie <sgautherie.bz@free.fr>
# Ted Mielczarek <ted.mielczarek@gmail.com>
# Joel Maher <joel.maher@gmail.com>
#
# 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
@ -45,243 +46,246 @@ from tempfile import mkdtemp
from automationutils import *
# Init logging
log = logging.getLogger()
handler = logging.StreamHandler(sys.stdout)
log.setLevel(logging.INFO)
log.addHandler(handler)
class XPCShellTests(object):
oldcwd = os.getcwd()
log = logging.getLogger()
oldcwd = os.getcwd()
def readManifest(manifest):
"""Given a manifest file containing a list of test directories,
return a list of absolute paths to the directories contained within."""
manifestdir = os.path.dirname(manifest)
testdirs = []
try:
f = open(manifest, "r")
for line in f:
dir = line.rstrip()
path = os.path.join(manifestdir, dir)
if os.path.isdir(path):
testdirs.append(path)
f.close()
except:
pass # just eat exceptions
return testdirs
def __init__(self):
# Init logging
handler = logging.StreamHandler(sys.stdout)
self.log.setLevel(logging.INFO)
self.log.addHandler(handler)
def runTests(xpcshell, xrePath=None, symbolsPath=None,
manifest=None, testdirs=[], testPath=None,
interactive=False, logfiles=True,
debuggerInfo=None):
"""Run xpcshell tests.
def readManifest(self, manifest):
"""Given a manifest file containing a list of test directories,
return a list of absolute paths to the directories contained within."""
manifestdir = os.path.dirname(manifest)
testdirs = []
try:
f = open(manifest, "r")
for line in f:
dir = line.rstrip()
path = os.path.join(manifestdir, dir)
if os.path.isdir(path):
testdirs.append(path)
f.close()
except:
pass # just eat exceptions
return testdirs
|xpcshell|, is the xpcshell executable to use to run the tests.
|xrePath|, if provided, is the path to the XRE to use.
|symbolsPath|, if provided is the path to a directory containing
breakpad symbols for processing crashes in tests.
|manifest|, if provided, is a file containing a list of
test directories to run.
|testdirs|, if provided, is a list of absolute paths of test directories.
No-manifest only option.
|testPath|, if provided, indicates a single path and/or test to run.
|interactive|, if set to True, indicates to provide an xpcshell prompt
instead of automatically executing the test.
|logfiles|, if set to False, indicates not to save output to log files.
Non-interactive only option.
|debuggerInfo|, if set, specifies the debugger and debugger arguments
that will be used to launch xpcshell.
"""
def runTests(self, xpcshell, xrePath=None, symbolsPath=None,
manifest=None, testdirs=[], testPath=None,
interactive=False, logfiles=True,
debuggerInfo=None):
"""Run xpcshell tests.
if not testdirs and not manifest:
# nothing to test!
print >>sys.stderr, "Error: No test dirs or test manifest specified!"
return False
|xpcshell|, is the xpcshell executable to use to run the tests.
|xrePath|, if provided, is the path to the XRE to use.
|symbolsPath|, if provided is the path to a directory containing
breakpad symbols for processing crashes in tests.
|manifest|, if provided, is a file containing a list of
test directories to run.
|testdirs|, if provided, is a list of absolute paths of test directories.
No-manifest only option.
|testPath|, if provided, indicates a single path and/or test to run.
|interactive|, if set to True, indicates to provide an xpcshell prompt
instead of automatically executing the test.
|logfiles|, if set to False, indicates not to save output to log files.
Non-interactive only option.
|debuggerInfo|, if set, specifies the debugger and debugger arguments
that will be used to launch xpcshell.
"""
passCount = 0
failCount = 0
if not testdirs and not manifest:
# nothing to test!
print >>sys.stderr, "Error: No test dirs or test manifest specified!"
return False
testharnessdir = os.path.dirname(os.path.abspath(__file__))
xpcshell = os.path.abspath(xpcshell)
# we assume that httpd.js lives in components/ relative to xpcshell
httpdJSPath = os.path.join(os.path.dirname(xpcshell), "components", "httpd.js").replace("\\", "/");
passCount = 0
failCount = 0
env = dict(os.environ)
# Make assertions fatal
env["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
# Don't launch the crash reporter client
env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
testharnessdir = os.path.dirname(os.path.abspath(__file__))
xpcshell = os.path.abspath(xpcshell)
# we assume that httpd.js lives in components/ relative to xpcshell
httpdJSPath = os.path.join(os.path.dirname(xpcshell), "components", "httpd.js").replace("\\", "/");
if xrePath is None:
xrePath = os.path.dirname(xpcshell)
else:
xrePath = os.path.abspath(xrePath)
if sys.platform == 'win32':
env["PATH"] = env["PATH"] + ";" + xrePath
elif sys.platform in ('os2emx', 'os2knix'):
os.environ["BEGINLIBPATH"] = xrePath + ";" + env["BEGINLIBPATH"]
os.environ["LIBPATHSTRICT"] = "T"
elif sys.platform == 'osx':
env["DYLD_LIBRARY_PATH"] = xrePath
else: # unix or linux?
env["LD_LIBRARY_PATH"] = xrePath
env = dict(os.environ)
# Make assertions fatal
env["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
# Don't launch the crash reporter client
env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
# xpcsRunArgs: <head.js> function to call to run the test.
# pStdout, pStderr: Parameter values for later |Popen()| call.
if interactive:
xpcsRunArgs = [
if xrePath is None:
xrePath = os.path.dirname(xpcshell)
else:
xrePath = os.path.abspath(xrePath)
if sys.platform == 'win32':
env["PATH"] = env["PATH"] + ";" + xrePath
elif sys.platform in ('os2emx', 'os2knix'):
os.environ["BEGINLIBPATH"] = xrePath + ";" + env["BEGINLIBPATH"]
os.environ["LIBPATHSTRICT"] = "T"
elif sys.platform == 'osx':
env["DYLD_LIBRARY_PATH"] = xrePath
else: # unix or linux?
env["LD_LIBRARY_PATH"] = xrePath
# xpcsRunArgs: <head.js> function to call to run the test.
# pStdout, pStderr: Parameter values for later |Popen()| call.
if interactive:
xpcsRunArgs = [
'-e', 'print("To start the test, type |_execute_test();|.");',
'-i']
pStdout = None
pStderr = None
else:
xpcsRunArgs = ['-e', '_execute_test();']
if (debuggerInfo and debuggerInfo["interactive"]):
pStdout = None
pStderr = None
else:
if sys.platform == 'os2emx':
xpcsRunArgs = ['-e', '_execute_test();']
if (debuggerInfo and debuggerInfo["interactive"]):
pStdout = None
pStderr = None
else:
pStdout = PIPE
pStderr = STDOUT
if sys.platform == 'os2emx':
pStdout = None
else:
pStdout = PIPE
pStderr = STDOUT
# <head.js> has to be loaded by xpchell: it can't load itself.
xpcsCmd = [xpcshell, '-g', xrePath, '-j', '-s'] + \
['-e', 'const _HTTPD_JS_PATH = "%s";' % httpdJSPath,
'-f', os.path.join(testharnessdir, 'head.js')]
# <head.js> has to be loaded by xpchell: it can't load itself.
xpcsCmd = [xpcshell, '-g', xrePath, '-j', '-s'] + \
['-e', 'const _HTTPD_JS_PATH = "%s";' % httpdJSPath,
'-f', os.path.join(testharnessdir, 'head.js')]
if debuggerInfo:
xpcsCmd = [debuggerInfo["path"]] + debuggerInfo["args"] + xpcsCmd
if debuggerInfo:
xpcsCmd = [debuggerInfo["path"]] + debuggerInfo["args"] + xpcsCmd
# |testPath| will be the optional path only, or |None|.
# |singleFile| will be the optional test only, or |None|.
singleFile = None
if testPath:
if testPath.endswith('.js'):
# Split into path and file.
if testPath.find('/') == -1:
# Test only.
singleFile = testPath
testPath = None
# |testPath| will be the optional path only, or |None|.
# |singleFile| will be the optional test only, or |None|.
singleFile = None
if testPath:
if testPath.endswith('.js'):
# Split into path and file.
if testPath.find('/') == -1:
# Test only.
singleFile = testPath
testPath = None
else:
# Both path and test.
# Reuse |testPath| temporarily.
testPath = testPath.rsplit('/', 1)
singleFile = testPath[1]
testPath = testPath[0]
else:
# Both path and test.
# Reuse |testPath| temporarily.
testPath = testPath.rsplit('/', 1)
singleFile = testPath[1]
testPath = testPath[0]
else:
# Path only.
# Simply remove optional ending separator.
testPath = testPath.rstrip("/")
# Path only.
# Simply remove optional ending separator.
testPath = testPath.rstrip("/")
# Override testdirs.
if manifest is not None:
testdirs = readManifest(os.path.abspath(manifest))
# Override testdirs.
if manifest is not None:
testdirs = self.readManifest(os.path.abspath(manifest))
# Process each test directory individually.
for testdir in testdirs:
if testPath and not testdir.endswith(testPath):
continue
testdir = os.path.abspath(testdir)
# get the list of head and tail files from the directory
testHeadFiles = []
for f in sorted(glob(os.path.join(testdir, "head_*.js"))):
if os.path.isfile(f):
testHeadFiles += [f]
testTailFiles = []
# Tails are executed in the reverse order, to "match" heads order,
# as in "h1-h2-h3 then t3-t2-t1".
for f in reversed(sorted(glob(os.path.join(testdir, "tail_*.js")))):
if os.path.isfile(f):
testTailFiles += [f]
# if a single test file was specified, we only want to execute that test
testfiles = sorted(glob(os.path.join(testdir, "test_*.js")))
if singleFile:
if singleFile in [os.path.basename(x) for x in testfiles]:
testfiles = [os.path.join(testdir, singleFile)]
else: # not in this dir? skip it
# Process each test directory individually.
for testdir in testdirs:
if testPath and not testdir.endswith(testPath):
continue
cmdH = ", ".join(['"' + f.replace('\\', '/') + '"'
for f in testHeadFiles])
cmdT = ", ".join(['"' + f.replace('\\', '/') + '"'
for f in testTailFiles])
cmdH = xpcsCmd + \
['-e', 'const _HEAD_FILES = [%s];' % cmdH] + \
['-e', 'const _TAIL_FILES = [%s];' % cmdT]
testdir = os.path.abspath(testdir)
# Now execute each test individually.
for test in testfiles:
# The test file will have to be loaded after the head files.
cmdT = ['-e', 'const _TEST_FILE = ["%s"];' %
os.path.join(testdir, test).replace('\\', '/')]
# get the list of head and tail files from the directory
testHeadFiles = []
for f in sorted(glob(os.path.join(testdir, "head_*.js"))):
if os.path.isfile(f):
testHeadFiles += [f]
testTailFiles = []
# Tails are executed in the reverse order, to "match" heads order,
# as in "h1-h2-h3 then t3-t2-t1".
for f in reversed(sorted(glob(os.path.join(testdir, "tail_*.js")))):
if os.path.isfile(f):
testTailFiles += [f]
# create a temp dir that the JS harness can stick a profile in
profileDir = None
try:
profileDir = mkdtemp()
env["XPCSHELL_TEST_PROFILE_DIR"] = profileDir
# if a single test file was specified, we only want to execute that test
testfiles = sorted(glob(os.path.join(testdir, "test_*.js")))
if singleFile:
if singleFile in [os.path.basename(x) for x in testfiles]:
testfiles = [os.path.join(testdir, singleFile)]
else: # not in this dir? skip it
continue
# Enable leaks (only) detection to its own log file.
leakLogFile = os.path.join(profileDir, "runxpcshelltests_leaks.log")
env["XPCOM_MEM_LEAK_LOG"] = leakLogFile
cmdH = ", ".join(['"' + f.replace('\\', '/') + '"'
for f in testHeadFiles])
cmdT = ", ".join(['"' + f.replace('\\', '/') + '"'
for f in testTailFiles])
cmdH = xpcsCmd + \
['-e', 'const _HEAD_FILES = [%s];' % cmdH] + \
['-e', 'const _TAIL_FILES = [%s];' % cmdT]
proc = Popen(cmdH + cmdT + xpcsRunArgs,
stdout=pStdout, stderr=pStderr, env=env, cwd=testdir)
# Now execute each test individually.
for test in testfiles:
# The test file will have to be loaded after the head files.
cmdT = ['-e', 'const _TEST_FILE = ["%s"];' %
os.path.join(testdir, test).replace('\\', '/')]
# allow user to kill hung subprocess with SIGINT w/o killing this script
# - don't move this line above Popen, or child will inherit the SIG_IGN
signal.signal(signal.SIGINT, signal.SIG_IGN)
# |stderr == None| as |pStderr| was either |None| or redirected to |stdout|.
stdout, stderr = proc.communicate()
signal.signal(signal.SIGINT, signal.SIG_DFL)
# create a temp dir that the JS harness can stick a profile in
profileDir = None
try:
profileDir = mkdtemp()
env["XPCSHELL_TEST_PROFILE_DIR"] = profileDir
if interactive:
# Not sure what else to do here...
return True
# Enable leaks (only) detection to its own log file.
leakLogFile = os.path.join(profileDir, "runxpcshelltests_leaks.log")
env["XPCOM_MEM_LEAK_LOG"] = leakLogFile
if proc.returncode != 0 or (stdout and re.search("^TEST-UNEXPECTED-FAIL", stdout, re.MULTILINE)):
print """TEST-UNEXPECTED-FAIL | %s | test failed (with xpcshell return code: %d), see following log:
proc = Popen(cmdH + cmdT + xpcsRunArgs,
stdout=pStdout, stderr=pStderr, env=env, cwd=testdir)
# allow user to kill hung subprocess with SIGINT w/o killing this script
# - don't move this line above Popen, or child will inherit the SIG_IGN
signal.signal(signal.SIGINT, signal.SIG_IGN)
# |stderr == None| as |pStderr| was either |None| or redirected to |stdout|.
stdout, stderr = proc.communicate()
signal.signal(signal.SIGINT, signal.SIG_DFL)
if interactive:
# Not sure what else to do here...
return True
if proc.returncode != 0 or (stdout and re.search("^TEST-UNEXPECTED-FAIL", stdout, re.MULTILINE)):
print """TEST-UNEXPECTED-FAIL | %s | test failed (with xpcshell return code: %d), see following log:
>>>>>>>
%s
<<<<<<<""" % (test, proc.returncode, stdout)
failCount += 1
else:
print "TEST-PASS | %s | test passed" % test
passCount += 1
failCount += 1
else:
print "TEST-PASS | %s | test passed" % test
passCount += 1
checkForCrashes(testdir, symbolsPath, testName=test)
dumpLeakLog(leakLogFile, True)
checkForCrashes(testdir, symbolsPath, testName=test)
dumpLeakLog(leakLogFile, True)
if logfiles and stdout:
try:
f = open(test + ".log", "w")
f.write(stdout)
if logfiles and stdout:
try:
f = open(test + ".log", "w")
f.write(stdout)
if os.path.exists(leakLogFile):
leaks = open(leakLogFile, "r")
f.write(leaks.read())
leaks.close()
finally:
if f:
f.close()
finally:
if profileDir:
shutil.rmtree(profileDir)
if os.path.exists(leakLogFile):
leaks = open(leakLogFile, "r")
f.write(leaks.read())
leaks.close()
finally:
if f:
f.close()
finally:
if profileDir:
shutil.rmtree(profileDir)
if passCount == 0 and failCount == 0:
print "TEST-UNEXPECTED-FAIL | runxpcshelltests.py | No tests run. Did you pass an invalid --test-path?"
failCount = 1
if passCount == 0 and failCount == 0:
print "TEST-UNEXPECTED-FAIL | runxpcshelltests.py | No tests run. Did you pass an invalid --test-path?"
failCount = 1
print """INFO | Result summary:
print """INFO | Result summary:
INFO | Passed: %d
INFO | Failed: %d""" % (passCount, failCount)
return failCount == 0
return failCount == 0
def main():
"""Process command line arguments and call runTests() to do the real work."""
@ -307,27 +311,29 @@ def main():
if len(args) < 2 and options.manifest is None or \
(len(args) < 1 and options.manifest is not None):
print >>sys.stderr, """Usage: %s <path to xpcshell> <test dirs>
or: %s --manifest=test.manifest <path to xpcshell>""" % (sys.argv[0],
print >>sys.stderr, """Usage: %s <path to xpcshell> <test dirs>
or: %s --manifest=test.manifest <path to xpcshell>""" % (sys.argv[0],
sys.argv[0])
sys.exit(1)
sys.exit(1)
debuggerInfo = getDebuggerInfo(oldcwd, options.debugger, options.debuggerArgs,
xpcsh = XPCShellTests()
debuggerInfo = getDebuggerInfo(xpcsh.oldcwd, options.debugger, options.debuggerArgs,
options.debuggerInteractive);
if options.interactive and not options.testPath:
print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
sys.exit(1)
if not runTests(args[0],
xrePath=options.xrePath,
symbolsPath=options.symbolsPath,
manifest=options.manifest,
testdirs=args[1:],
testPath=options.testPath,
interactive=options.interactive,
logfiles=options.logfiles,
debuggerInfo=debuggerInfo):
if not xpcsh.runTests(args[0],
xrePath=options.xrePath,
symbolsPath=options.symbolsPath,
manifest=options.manifest,
testdirs=args[1:],
testPath=options.testPath,
interactive=options.interactive,
logfiles=options.logfiles,
debuggerInfo=debuggerInfo):
sys.exit(1)
if __name__ == '__main__':

View File

@ -286,12 +286,6 @@ var gUpdates = {
*/
sourceEvent: SRCEVT_FOREGROUND,
/**
* The global error message - the reason the update failed. This is human
* readable text, used to initialize the error page.
*/
errorMessage: "",
/**
* Helper function for onLoad
* Saves default button label & accesskey for use by _setButton
@ -364,26 +358,24 @@ var gUpdates = {
var p = this.update.selectedPatch;
if (p) {
var state = p.state;
if (state == STATE_DOWNLOADING) {
var patchFailed = false;
try {
patchFailed = this.update.getProperty("patchingFailed");
}
catch (e) {
}
if (patchFailed == "partial") {
// If the system failed to apply the partial patch, show the
// screen which best describes this condition, which is triggered
// by the |STATE_FAILED| state.
state = STATE_FAILED;
}
else if (patchFailed == "complete") {
// Otherwise, if the complete patch failed, which is far less
// likely, show the error text held by the update object in the
// generic errors page, triggered by the |STATE_DOWNLOAD_FAILED|
// state.
state = STATE_DOWNLOAD_FAILED;
}
var patchFailed;
try {
patchFailed = this.update.getProperty("patchingFailed");
}
catch (e) {
}
if (patchFailed == "partial") {
// If the system failed to apply the partial patch, show the
// screen which best describes this condition, which is triggered
// by the |STATE_FAILED| state.
state = STATE_FAILED;
}
else if (patchFailed == "complete") {
// Otherwise, if the complete patch failed, which is far less
// likely, show the error text held by the update object in the
// generic errors page, triggered by the |STATE_DOWNLOAD_FAILED|
// state.
state = STATE_DOWNLOAD_FAILED;
}
// Now select the best page to start with, given the current state of
@ -1165,6 +1157,12 @@ var gDownloadingPage = {
gUpdates.wiz.getButton("extra1").focus();
},
showVerificationError: function() {
var verificationError = gUpdates.getAUSString("verificationError",
[gUpdates.brandName]);
gUpdates.advanceToErrorPage(verificationError);
},
/**
* Updates the text status message
*/

View File

@ -341,7 +341,6 @@ protected:
void OnWindowPosChanged(WINDOWPOS *wp, PRBool& aResult);
#if defined(CAIRO_HAS_DDRAW_SURFACE)
PRBool OnPaintImageDDraw16();
HRESULT PaintRectImageDDraw16(RECT aRect, nsPaintEvent* aEvent);
#endif // defined(CAIRO_HAS_DDRAW_SURFACE)
PRBool OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam,
PRBool& result, PRBool& getWheelInfo,

View File

@ -878,147 +878,31 @@ HBITMAP nsWindowGfx::DataToBitmap(PRUint8* aImageData,
// Windows Mobile Special image/direct draw painting fun
#if defined(CAIRO_HAS_DDRAW_SURFACE)
HRESULT nsWindow::PaintRectImageDDraw16(RECT rcPaint, nsPaintEvent* event){
HRESULT hr;
PRBool nsWindow::OnPaintImageDDraw16()
{
PRBool result = PR_FALSE;
PAINTSTRUCT ps;
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
gfxIntSize surfaceSize;
nsRefPtr<gfxImageSurface> targetSurfaceImage;
nsRefPtr<gfxContext> thebesContext;
nsCOMPtr<nsIRenderingContext> rc;
nsEventStatus eventStatus = nsEventStatus_eIgnore;
RECT renderArea;
surfaceSize = gfxIntSize(rcPaint.right - rcPaint.left,
rcPaint.bottom - rcPaint.top);
if (!EnsureSharedSurfaceSize(surfaceSize)) {
NS_ERROR("Couldn't allocate shared surface!");
return E_FAIL;
}
targetSurfaceImage = new gfxImageSurface(sSharedSurfaceData.get(),
surfaceSize,
surfaceSize.width * 4,
gfxASurface::ImageFormatRGB24);
if (!targetSurfaceImage || targetSurfaceImage->CairoStatus()) {
NS_ERROR("Invalid targetSurfaceImage!");
return E_FAIL;
}
targetSurfaceImage->SetDeviceOffset(gfxPoint(-rcPaint.left, -rcPaint.top));
thebesContext = new gfxContext(targetSurfaceImage);
thebesContext->SetFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
thebesContext->SetFlag(gfxContext::FLAG_SIMPLIFY_OPERATORS);
nsresult rv = mContext->CreateRenderingContextInstance (*getter_AddRefs(rc));
if (NS_FAILED(rv)) {
NS_WARNING("CreateRenderingContextInstance failed");
return E_FAIL;
}
rv = rc->Init(mContext, thebesContext);
if (NS_FAILED(rv)) {
NS_WARNING("RC::Init failed");
return E_FAIL;
}
event->renderingContext = rc;
nsresult result = DispatchWindowEvent(event, eventStatus);
event->renderingContext = nsnull;
if (!result) {
printf("result is null from dispatch\n");
return E_FAIL;
}
hr = glpDDSecondary->Lock(0, &gDDSDSecondary, DDLOCK_WAITNOTBUSY | DDLOCK_DISCARD, 0); /* should we wait here? */
if (FAILED(hr)) {
#ifdef DEBUG
DDError("Failed to lock renderer", hr);
#endif
return E_FAIL;
}
// Convert RGB24 -> RGB565
pixman_image_t *srcPixmanImage = pixman_image_create_bits(PIXMAN_x8r8g8b8,
surfaceSize.width,
surfaceSize.height,
(uint32_t*) sSharedSurfaceData.get(),
surfaceSize.width * 4);
pixman_image_t *dstPixmanImage = pixman_image_create_bits(PIXMAN_r5g6b5,
gDDSDSecondary.dwWidth,
gDDSDSecondary.dwHeight,
(uint32_t*) gDDSDSecondary.lpSurface,
gDDSDSecondary.dwWidth * 2);
pixman_image_composite(PIXMAN_OP_SRC,
srcPixmanImage,
NULL,
dstPixmanImage,
0, 0,
0, 0,
0, 0,
surfaceSize.width,
surfaceSize.height);
pixman_image_unref(dstPixmanImage);
pixman_image_unref(srcPixmanImage);
hr = glpDDSecondary->Unlock(0);
if (FAILED(hr)) {
#ifdef DEBUG
DDError("Failed to unlock renderer", hr);
#endif
return E_FAIL;
}
hr = glpDDClipper->SetHWnd(0, mWnd);
if (FAILED(hr)) {
#ifdef DEBUG
DDError("SetHWnd", hr);
#endif
return E_FAIL;
}
// translate the paint region to screen coordinates
renderArea = rcPaint;
MapWindowPoints(mWnd, 0, (LPPOINT)&renderArea, 2);
// set the rect to be 0,0 based
rcPaint.right = surfaceSize.width;
rcPaint.bottom = surfaceSize.height;
rcPaint.left = rcPaint.top = 0;
return glpDDPrimary->Blt(&renderArea,
glpDDSecondary,
&rcPaint,
DDBLT_WAITNOTBUSY, /* should we really wait here? */
NULL);
}
PRBool nsWindow::OnPaintImageDDraw16()
{
PRBool result = PR_TRUE;
PAINTSTRUCT ps;
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
mPainting = PR_TRUE;
PRInt32 brx, bry, brw, brh;
gfxIntSize newSize;
newSize.height = GetSystemMetrics(SM_CYSCREEN);
newSize.width = GetSystemMetrics(SM_CXSCREEN);
mPainting = PR_TRUE;
HDC hDC = ::BeginPaint(mWnd, &ps);
mPaintDC = hDC;
nsCOMPtr<nsIRegion> paintRgnWin = GetRegionToPaint(PR_FALSE, ps, hDC);
if (!paintRgnWin || paintRgnWin->IsEmpty() || !mEventCallback) {
printf("nothing to paint\n");
result = PR_TRUE;
goto cleanup;
}
InitEvent(event);
event.region = paintRgnWin;
@ -1058,22 +942,111 @@ PRBool nsWindow::OnPaintImageDDraw16()
goto cleanup;
}
}
paintRgnWin->GetBoundingBox(&brx, &bry, &brw, &brh);
surfaceSize = gfxIntSize(brw, brh);
if (!EnsureSharedSurfaceSize(surfaceSize))
goto cleanup;
targetSurfaceImage = new gfxImageSurface(sSharedSurfaceData.get(),
surfaceSize,
surfaceSize.width * 4,
gfxASurface::ImageFormatRGB24);
if (!targetSurfaceImage || targetSurfaceImage->CairoStatus())
goto cleanup;
targetSurfaceImage->SetDeviceOffset(gfxPoint(-brx, -bry));
thebesContext = new gfxContext(targetSurfaceImage);
thebesContext->SetFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
thebesContext->SetFlag(gfxContext::FLAG_SIMPLIFY_OPERATORS);
nsresult rv = mContext->CreateRenderingContextInstance (*getter_AddRefs(rc));
if (NS_FAILED(rv))
goto cleanup;
rv = rc->Init(mContext, thebesContext);
if (NS_FAILED(rv))
goto cleanup;
event.renderingContext = rc;
PRBool res = DispatchWindowEvent(&event, eventStatus);
event.renderingContext = nsnull;
if (!res && eventStatus == nsEventStatus_eConsumeNoDefault)
goto cleanup;
nsRegionRectSet *rects = nsnull;
RECT r;
paintRgnWin->GetRects(&rects);
HRESULT hr = glpDDSecondary->Lock(0, &gDDSDSecondary, DDLOCK_WAITNOTBUSY | DDLOCK_DISCARD, 0);
if (FAILED(hr))
goto cleanup;
pixman_image_t *srcPixmanImage =
pixman_image_create_bits(PIXMAN_x8r8g8b8, surfaceSize.width,
surfaceSize.height,
(uint32_t*) sSharedSurfaceData.get(),
surfaceSize.width * 4);
pixman_image_t *dstPixmanImage =
pixman_image_create_bits(PIXMAN_r5g6b5, gDDSDSecondary.dwWidth,
gDDSDSecondary.dwHeight,
(uint32_t*) gDDSDSecondary.lpSurface,
gDDSDSecondary.dwWidth * 2);
for (unsigned int i = 0; i < rects->mNumRects; i++) {
pixman_image_composite(PIXMAN_OP_SRC, srcPixmanImage, NULL, dstPixmanImage,
rects->mRects[i].x - brx, rects->mRects[i].y - bry,
0, 0,
rects->mRects[i].x, rects->mRects[i].y,
rects->mRects[i].width, rects->mRects[i].height);
}
pixman_image_unref(dstPixmanImage);
pixman_image_unref(srcPixmanImage);
hr = glpDDSecondary->Unlock(0);
if (FAILED(hr))
goto cleanup;
hr = glpDDClipper->SetHWnd(0, mWnd);
if (FAILED(hr))
goto cleanup;
for (unsigned int i = 0; i < rects->mNumRects; i++) {
r.left = rects->mRects[i].x;
r.top = rects->mRects[i].y;
r.right = rects->mRects[i].width + rects->mRects[i].x;
r.bottom = rects->mRects[i].height + rects->mRects[i].y;
PaintRectImageDDraw16(r, &event);
RECT renderRect = r;
SetLastError(0); // See http://msdn.microsoft.com/en-us/library/dd145046%28VS.85%29.aspx
if (MapWindowPoints(mWnd, 0, (LPPOINT)&renderRect, 2) || 0 == (hr = GetLastError()))
hr = glpDDPrimary->Blt(&renderRect, glpDDSecondary, &r, 0, NULL);
#ifdef WINCE_WINDOWS_MOBILE
if (FAILED(hr))
// add this rect back to the invalidated region so we'll attempt paint it next time around
mInvalidatedRegion->Union(rects->mRects[i].x, rects->mRects[i].y,
rects->mRects[i].width, rects->mRects[i].height);
#endif
}
result = PR_TRUE;
cleanup:
#ifdef WINCE_WINDOWS_MOBILE
// re-invalidate the region if we failed.
if (!result)
mInvalidatedRegion->Union(*paintRgnWin.get());
#endif
::EndPaint(mWnd, &ps);
mPaintDC = nsnull;
mPainting = PR_FALSE;
return result;
}
#endif // defined(CAIRO_HAS_DDRAW_SURFACE)