mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 08:35:26 +00:00
Merge mozilla-central into electrolysis.
This commit is contained in:
commit
20b787e19d
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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;"
|
||||
|
@ -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
@ -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:
|
||||
|
@ -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$"),
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
SurfaceTypeOS2,
|
||||
SurfaceTypeWin32Printing,
|
||||
SurfaceTypeQuartzImage,
|
||||
SurfaceTypeScript,
|
||||
SurfaceTypeQPainter,
|
||||
SurfaceTypeDDraw
|
||||
} gfxSurfaceType;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
47
layout/reftests/bugs/167496-1-ref.html
Normal file
47
layout/reftests/bugs/167496-1-ref.html
Normal 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>
|
46
layout/reftests/bugs/167496-1.html
Normal file
46
layout/reftests/bugs/167496-1.html
Normal 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>
|
14
layout/reftests/bugs/229591-1-ref.html
Normal file
14
layout/reftests/bugs/229591-1-ref.html
Normal 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>
|
8
layout/reftests/bugs/229591-1.html
Normal file
8
layout/reftests/bugs/229591-1.html
Normal 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>
|
21
layout/reftests/bugs/320979-1-ref.html
Normal file
21
layout/reftests/bugs/320979-1-ref.html
Normal 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>
|
20
layout/reftests/bugs/320979-1.html
Normal file
20
layout/reftests/bugs/320979-1.html
Normal 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>
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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__':
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user