зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
bea15ba99c
|
@ -1360,7 +1360,7 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
|||
#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { *aIsProbablyForLayout = isLayout; return NS_OK; }
|
||||
#endif
|
||||
|
||||
*aIsProbablyForLayout = PR_FALSE;
|
||||
*aIsProbablyForLayout = false;
|
||||
|
||||
if (IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1369,7 +1369,7 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
|||
if (docAccessible) {
|
||||
PRUint64 docState = docAccessible->State();
|
||||
if (docState & states::EDITABLE) { // Need to see all elements while document is being edited
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "In editable document");
|
||||
RETURN_LAYOUT_ANSWER(false, "In editable document");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1377,45 +1377,77 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
|||
// but for which we still expose table semantics (treegrid, for example).
|
||||
bool hasNonTableRole = (Role() != nsIAccessibleRole::ROLE_TABLE);
|
||||
if (hasNonTableRole) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute");
|
||||
RETURN_LAYOUT_ANSWER(false, "Has role attribute");
|
||||
}
|
||||
|
||||
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) {
|
||||
// Role attribute is present, but overridden roles have already been dealt with.
|
||||
// Only landmarks and other roles that don't override the role from native
|
||||
// markup are left to deal with here.
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute, weak role, and role is table");
|
||||
RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
|
||||
}
|
||||
|
||||
// Check for legitimate data table elements or attributes
|
||||
|
||||
// Check for legitimate data table attributes.
|
||||
nsAutoString summary;
|
||||
if ((mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
|
||||
!summary.IsEmpty()) ||
|
||||
HasDescendant(NS_LITERAL_STRING("caption"), PR_FALSE) ||
|
||||
HasDescendant(NS_LITERAL_STRING("th")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("thead")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("tfoot")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("colgroup"))) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has caption, summary, th, thead, tfoot or colgroup -- legitimate table structures");
|
||||
if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
|
||||
!summary.IsEmpty())
|
||||
RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
|
||||
|
||||
// Check for legitimate data table elements.
|
||||
nsAccessible* caption = FirstChild();
|
||||
if (caption && caption->Role() == nsIAccessibleRole::ROLE_CAPTION &&
|
||||
caption->HasChildren()) {
|
||||
RETURN_LAYOUT_ANSWER(false,
|
||||
"Not empty caption -- legitimate table structures");
|
||||
}
|
||||
|
||||
for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
|
||||
childElm = childElm->GetNextSibling()) {
|
||||
if (!childElm->IsHTML())
|
||||
continue;
|
||||
|
||||
if (childElm->Tag() == nsGkAtoms::col ||
|
||||
childElm->Tag() == nsGkAtoms::colgroup ||
|
||||
childElm->Tag() == nsGkAtoms::tfoot ||
|
||||
childElm->Tag() == nsGkAtoms::thead) {
|
||||
RETURN_LAYOUT_ANSWER(false,
|
||||
"Has col, colgroup, tfoot or thead -- legitimate table structures");
|
||||
}
|
||||
|
||||
if (childElm->Tag() == nsGkAtoms::tbody) {
|
||||
for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
|
||||
rowElm = rowElm->GetNextSibling()) {
|
||||
if (rowElm->IsHTML() && rowElm->Tag() == nsGkAtoms::tr) {
|
||||
for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
|
||||
cellElm = cellElm->GetNextSibling()) {
|
||||
if (cellElm->IsHTML() && cellElm->Tag() == nsGkAtoms::th) {
|
||||
RETURN_LAYOUT_ANSWER(false,
|
||||
"Has th -- legitimate table structures");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDescendant(NS_LITERAL_STRING("table"))) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has a nested table within it");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
|
||||
}
|
||||
|
||||
// If only 1 column or only 1 row, it's for layout
|
||||
PRInt32 columns, rows;
|
||||
GetColumnCount(&columns);
|
||||
if (columns <=1) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 column");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
|
||||
}
|
||||
GetRowCount(&rows);
|
||||
if (rows <=1) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 row");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
|
||||
}
|
||||
|
||||
// Check for many columns
|
||||
if (columns >= 5) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, ">=5 columns");
|
||||
RETURN_LAYOUT_ANSWER(false, ">=5 columns");
|
||||
}
|
||||
|
||||
// Now we know there are 2-4 columns and 2 or more rows
|
||||
|
@ -1434,7 +1466,7 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
|||
nsMargin border;
|
||||
cellFrame->GetBorder(border);
|
||||
if (border.top && border.bottom && border.left && border.right) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "Has nonzero border-width on table cell");
|
||||
RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1462,21 +1494,21 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
|||
lastRowColor = color;
|
||||
styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"), color);
|
||||
if (rowCount > 0 && PR_FALSE == lastRowColor.Equals(color)) {
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "2 styles of row background color, non-bordered");
|
||||
RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for many rows
|
||||
const PRInt32 kMaxLayoutRows = 20;
|
||||
if (rows > kMaxLayoutRows) { // A ton of rows, this is probably for data
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, ">= kMaxLayoutRows (20) and non-bordered");
|
||||
RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
|
||||
}
|
||||
|
||||
// Check for very wide table
|
||||
nsAutoString styledWidth;
|
||||
GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("width"), styledWidth);
|
||||
if (styledWidth.EqualsLiteral("100%")) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns and 100% width");
|
||||
RETURN_LAYOUT_ANSWER(true, "<=4 columns and 100% width");
|
||||
}
|
||||
if (styledWidth.Find(NS_LITERAL_STRING("px"))) { // Hardcoded in pixels
|
||||
nsIFrame *tableFrame = GetFrame();
|
||||
|
@ -1494,24 +1526,24 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
|
|||
if (percentageOfDocWidth > 95) {
|
||||
// 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
|
||||
// Probably for layout
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width");
|
||||
RETURN_LAYOUT_ANSWER(true, "<=4 columns, width hardcoded in pixels and 95% of document width");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Two column rules
|
||||
if (rows * columns <= 10) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "2-4 columns, 10 cells or less, non-bordered");
|
||||
RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
|
||||
}
|
||||
|
||||
if (HasDescendant(NS_LITERAL_STRING("embed")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("object")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("applet")) ||
|
||||
HasDescendant(NS_LITERAL_STRING("iframe"))) {
|
||||
RETURN_LAYOUT_ANSWER(PR_TRUE, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements");
|
||||
RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements");
|
||||
}
|
||||
|
||||
RETURN_LAYOUT_ANSWER(PR_FALSE, "no layout factor strong enough, so will guess data");
|
||||
RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,9 +36,6 @@
|
|||
// table with empty caption
|
||||
testAttrs("table4.2", attr, true);
|
||||
|
||||
// table with two captions
|
||||
testAbsentAttrs("table4.3", attr);
|
||||
|
||||
// table with th element
|
||||
testAbsentAttrs("table5", attr);
|
||||
|
||||
|
@ -48,8 +45,9 @@
|
|||
// table with tfoot element
|
||||
testAbsentAttrs("table7", attr);
|
||||
|
||||
// table with colgroup element
|
||||
// table with colgroup or col elements
|
||||
testAbsentAttrs("table8", attr);
|
||||
testAbsentAttrs("table8.2", attr);
|
||||
|
||||
// layout table with nested table
|
||||
testAttrs("table9", attr, true);
|
||||
|
@ -87,6 +85,14 @@
|
|||
// tree grid, no layout table
|
||||
testAbsentAttrs("table20", attr);
|
||||
|
||||
// layout table containing nested data table (having data structures)
|
||||
testAttrs("table21", attr, true);
|
||||
testAttrs("table21.2", attr, true);
|
||||
testAttrs("table21.3", attr, true);
|
||||
testAttrs("table21.4", attr, true);
|
||||
testAttrs("table21.5", attr, true);
|
||||
testAttrs("table21.6", attr, true);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -101,6 +107,11 @@
|
|||
title="Don't treat tables that have a landmark role as layout table">
|
||||
Mozilla Bug 495388
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=690222"
|
||||
title="Data table elements used to determine layout-guess attribute shouldn't be picked from nested tables">
|
||||
Mozilla Bug 690222
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
|
@ -178,15 +189,6 @@
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- table with two captions -->
|
||||
<table id="table4.3">
|
||||
<caption> </caption>
|
||||
<tr>
|
||||
<td>Cell1</td><td>cell2</td>
|
||||
</tr>
|
||||
<caption>a caption</caption>
|
||||
</table>
|
||||
|
||||
<!-- table with th element -->
|
||||
<table id="table5">
|
||||
<tr>
|
||||
|
@ -212,10 +214,17 @@
|
|||
</tfoot>
|
||||
</table>
|
||||
|
||||
<!-- table with colgroup element -->
|
||||
<!-- table with colgroup and col elements -->
|
||||
<table id="table8">
|
||||
<colgroup width="20"></colgroup>
|
||||
<tr>
|
||||
<colgroup><td>Cell1</td><td>cell2</td></colgroup>
|
||||
<td>Cell1</td><td>cell2</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table8.2">
|
||||
<col width="20">
|
||||
<tr>
|
||||
<td>Cell1</td><td>cell2</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -339,5 +348,68 @@
|
|||
<table id="table20" role="treegrid">
|
||||
<tr role="treeitem"><td>Cell1</td><td>Cell2</td></tr>
|
||||
</table>
|
||||
|
||||
<!-- layout table with nested data table containing data table elements -->
|
||||
<table id="table21">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<caption>table</caption>
|
||||
<tr><td>Cell</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.2">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<colgroup width="20"></colgroup>
|
||||
<tr><th>Cell</th></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.3">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<col width="20"></col>
|
||||
<tr><th>Cell</th></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.4">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr><th>Cell</th></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.5">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><td>Cell</td></tr>
|
||||
</thead>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="table21.6">
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tfoot>
|
||||
<tr><td>Cell</td></tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -51,9 +51,7 @@ DIRS = \
|
|||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = test_bug408328.html \
|
||||
bug408328-data.xml \
|
||||
test_bug368464.html \
|
||||
_TEST_FILES = bug408328-data.xml \
|
||||
bug368464-data.xml \
|
||||
test_bug494328.html \
|
||||
bug494328-data.xml \
|
||||
|
|
|
@ -51,6 +51,8 @@ _HTTP_FILES = \
|
|||
|
||||
_CHROME_FILES = \
|
||||
test_423060.xul \
|
||||
test_bug368464.html \
|
||||
test_bug408328.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_HTTP_FILES)
|
||||
|
|
|
@ -5,12 +5,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=368464
|
|||
-->
|
||||
<head>
|
||||
<title>Test that RSS 0.90 isn't sniffed</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=368464">Mozilla Bug 368464</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug368464-data.xml"></iframe></p>
|
||||
<p id="display"><iframe id="testFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/bug368464-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
@ -21,7 +21,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=368464
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
|
||||
ok($("testFrame").contentDocument.documentElement.id != "feedHandler",
|
||||
"RSS 0.90 shouldn't be sniffed as a feed");
|
||||
});
|
|
@ -5,12 +5,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408328
|
|||
-->
|
||||
<head>
|
||||
<title>Test feed preview safe-linkification</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408328">Mozilla Bug 408328</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug408328-data.xml"></iframe></p>
|
||||
<p id="display"><iframe id="testFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/bug408328-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
@ -21,7 +21,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408328
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
|
||||
var links = $("testFrame").contentDocument.getElementById("feedContent").getElementsByTagName("a");
|
||||
is(links.length, 5, "wrong number of linked items in feed preview");
|
||||
for (var i = 0; i < links.length; i++) {
|
|
@ -449,7 +449,17 @@ class DeviceManagerADB(DeviceManager):
|
|||
# failure: None
|
||||
def updateApp(self, appBundlePath, processName=None, destPath=None, ipAddr=None, port=30000):
|
||||
return self.runCmd(["install", "-r", appBundlePath]).stdout.read()
|
||||
|
||||
|
||||
# external function
|
||||
# returns:
|
||||
# success: time in ms
|
||||
# failure: None
|
||||
def getCurrentTime(self):
|
||||
timestr = self.runCmd(["shell", "date", "+%s"]).stdout.read().strip()
|
||||
if (not timestr or not timestr.isdigit()):
|
||||
return None
|
||||
return str(int(timestr)*1000)
|
||||
|
||||
# Returns information about the device:
|
||||
# Directive indicates the information you want to get, your choices are:
|
||||
# os - name of the os
|
||||
|
|
|
@ -265,8 +265,12 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
Open(aChannel, aParentHandle, aIOLoop);
|
||||
sSingleton = this;
|
||||
|
||||
#if defined(ANDROID) && defined(MOZ_CRASHREPORTER)
|
||||
PCrashReporterChild* crashreporter = SendPCrashReporterConstructor();
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
|
||||
XRE_GetProcessType());
|
||||
#if defined(ANDROID)
|
||||
PCrashReporterChild* crashreporter = ManagedPCrashReporterChild()[0];
|
||||
|
||||
InfallibleTArray<Mapping> mappings;
|
||||
const struct mapping_info *info = getLibraryMapping();
|
||||
while (info && info->name) {
|
||||
|
@ -278,6 +282,7 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
info++;
|
||||
}
|
||||
crashreporter->SendAddLibraryMappings(mappings);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
@ -418,9 +423,14 @@ ContentChild::DeallocPBrowser(PBrowserChild* iframe)
|
|||
}
|
||||
|
||||
PCrashReporterChild*
|
||||
ContentChild::AllocPCrashReporter()
|
||||
ContentChild::AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
|
||||
const PRUint32& processType)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
return new CrashReporterChild();
|
||||
#else
|
||||
return nsnull;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -80,8 +80,11 @@ public:
|
|||
virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags);
|
||||
virtual bool DeallocPBrowser(PBrowserChild*);
|
||||
|
||||
virtual PCrashReporterChild* AllocPCrashReporter();
|
||||
virtual bool DeallocPCrashReporter(PCrashReporterChild*);
|
||||
virtual PCrashReporterChild*
|
||||
AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
|
||||
const PRUint32& processType);
|
||||
virtual bool
|
||||
DeallocPCrashReporter(PCrashReporterChild*);
|
||||
|
||||
virtual PMemoryReportRequestChild*
|
||||
AllocPMemoryReportRequest();
|
||||
|
|
|
@ -355,27 +355,14 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||
props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), PR_TRUE);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
nsAutoString dumpID;
|
||||
|
||||
nsCOMPtr<nsILocalFile> crashDump;
|
||||
TakeMinidump(getter_AddRefs(crashDump)) &&
|
||||
CrashReporter::GetIDFromMinidump(crashDump, dumpID);
|
||||
MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
|
||||
CrashReporterParent* crashReporter =
|
||||
static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
|
||||
|
||||
crashReporter->GenerateCrashReport(this, NULL);
|
||||
|
||||
nsAutoString dumpID(crashReporter->ChildDumpID());
|
||||
props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
|
||||
|
||||
if (!dumpID.IsEmpty()) {
|
||||
CrashReporter::AnnotationTable notes;
|
||||
notes.Init();
|
||||
notes.Put(NS_LITERAL_CSTRING("ProcessType"), NS_LITERAL_CSTRING("content"));
|
||||
|
||||
char startTime[32];
|
||||
sprintf(startTime, "%lld", static_cast<long long>(mProcessStartTime));
|
||||
notes.Put(NS_LITERAL_CSTRING("StartupTime"),
|
||||
nsDependentCString(startTime));
|
||||
|
||||
// TODO: Additional per-process annotations.
|
||||
CrashReporter::AppendExtraData(dumpID, notes);
|
||||
}
|
||||
#endif
|
||||
|
||||
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nsnull);
|
||||
|
@ -415,12 +402,19 @@ ContentParent::DestroyTestShell(TestShellParent* aTestShell)
|
|||
return PTestShellParent::Send__delete__(aTestShell);
|
||||
}
|
||||
|
||||
TestShellParent*
|
||||
ContentParent::GetTestShellSingleton()
|
||||
{
|
||||
if (!ManagedPTestShellParent().Length())
|
||||
return nsnull;
|
||||
return static_cast<TestShellParent*>(ManagedPTestShellParent()[0]);
|
||||
}
|
||||
|
||||
ContentParent::ContentParent()
|
||||
: mGeolocationWatchID(-1)
|
||||
, mRunToCompletionDepth(0)
|
||||
, mShouldCallUnblockChild(false)
|
||||
, mIsAlive(true)
|
||||
, mProcessStartTime(time(NULL))
|
||||
, mSendPermissionUpdates(false)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
@ -791,9 +785,23 @@ ContentParent::DeallocPBrowser(PBrowserParent* frame)
|
|||
}
|
||||
|
||||
PCrashReporterParent*
|
||||
ContentParent::AllocPCrashReporter()
|
||||
ContentParent::AllocPCrashReporter(const NativeThreadId& tid,
|
||||
const PRUint32& processType)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
return new CrashReporterParent();
|
||||
#else
|
||||
return nsnull;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvPCrashReporterConstructor(PCrashReporterParent* actor,
|
||||
const NativeThreadId& tid,
|
||||
const PRUint32& processType)
|
||||
{
|
||||
static_cast<CrashReporterParent*>(actor)->SetChildData(tid, processType);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -91,6 +91,7 @@ public:
|
|||
|
||||
TestShellParent* CreateTestShell();
|
||||
bool DestroyTestShell(TestShellParent* aTestShell);
|
||||
TestShellParent* GetTestShellSingleton();
|
||||
|
||||
void ReportChildAlreadyBlocked();
|
||||
bool RequestRunToCompletion();
|
||||
|
@ -99,6 +100,10 @@ public:
|
|||
|
||||
void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
|
||||
|
||||
GeckoChildProcessHost* Process() {
|
||||
return mSubprocess;
|
||||
}
|
||||
|
||||
bool NeedsPermissionsUpdate() {
|
||||
return mSendPermissionUpdates;
|
||||
}
|
||||
|
@ -123,8 +128,12 @@ private:
|
|||
virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags);
|
||||
virtual bool DeallocPBrowser(PBrowserParent* frame);
|
||||
|
||||
virtual PCrashReporterParent* AllocPCrashReporter();
|
||||
virtual PCrashReporterParent* AllocPCrashReporter(const NativeThreadId& tid,
|
||||
const PRUint32& processType);
|
||||
virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
|
||||
virtual bool RecvPCrashReporterConstructor(PCrashReporterParent* actor,
|
||||
const NativeThreadId& tid,
|
||||
const PRUint32& processType);
|
||||
|
||||
virtual PMemoryReportRequestParent* AllocPMemoryReportRequest();
|
||||
virtual bool DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor);
|
||||
|
@ -230,11 +239,12 @@ private:
|
|||
|
||||
bool mIsAlive;
|
||||
nsCOMPtr<nsIPrefServiceInternal> mPrefService;
|
||||
time_t mProcessStartTime;
|
||||
|
||||
bool mSendPermissionUpdates;
|
||||
|
||||
nsRefPtr<nsFrameMessageManager> mMessageManager;
|
||||
|
||||
friend class CrashReporterParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set sw=4 ts=8 et tw=80 :
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Crash Reporter.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Josh Matthews <josh@joshmatthews.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "mozilla/plugins/PluginModuleChild.h"
|
||||
#include "ContentChild.h"
|
||||
#include "CrashReporterChild.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using mozilla::plugins::PluginModuleChild;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*static*/
|
||||
PCrashReporterChild*
|
||||
CrashReporterChild::GetCrashReporter()
|
||||
{
|
||||
const InfallibleTArray<PCrashReporterChild*>* reporters = nsnull;
|
||||
switch (XRE_GetProcessType()) {
|
||||
case GeckoProcessType_Content: {
|
||||
ContentChild* child = ContentChild::GetSingleton();
|
||||
reporters = &child->ManagedPCrashReporterChild();
|
||||
break;
|
||||
}
|
||||
case GeckoProcessType_Plugin: {
|
||||
PluginModuleChild* child = PluginModuleChild::current();
|
||||
reporters = &child->ManagedPCrashReporterChild();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (reporters && reporters->Length() > 0) {
|
||||
return reporters->ElementAt(0);
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -36,7 +36,15 @@
|
|||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef mozilla_dom_CrashReporterChild_h
|
||||
#define mozilla_dom_CrashReporterChild_h
|
||||
|
||||
#include "mozilla/dom/PCrashReporterChild.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -45,11 +53,16 @@ class CrashReporterChild :
|
|||
{
|
||||
public:
|
||||
CrashReporterChild() {
|
||||
MOZ_COUNT_CTOR(CrashReporterChild);
|
||||
MOZ_COUNT_CTOR(CrashReporterChild);
|
||||
}
|
||||
virtual ~CrashReporterChild() {
|
||||
MOZ_COUNT_DTOR(CrashReporterChild);
|
||||
~CrashReporterChild() {
|
||||
MOZ_COUNT_DTOR(CrashReporterChild);
|
||||
}
|
||||
|
||||
static PCrashReporterChild* GetCrashReporter();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_CrashReporterChild_h
|
||||
|
|
|
@ -37,12 +37,11 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "CrashReporterParent.h"
|
||||
#if defined(MOZ_CRASHREPORTER)
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
|
||||
#include "base/process_util.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
using namespace base;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -73,9 +72,32 @@ CrashReporterParent::RecvAddLibraryMappings(const InfallibleTArray<Mapping>& map
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CrashReporterParent::RecvAnnotateCrashReport(const nsCString& key,
|
||||
const nsCString& data)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
mNotes.Put(key, data);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CrashReporterParent::RecvAppendAppNotes(const nsCString& data)
|
||||
{
|
||||
mAppNotes.Append(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
CrashReporterParent::CrashReporterParent()
|
||||
: mStartTime(time(NULL))
|
||||
, mInitialized(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CrashReporterParent);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
mNotes.Init(4);
|
||||
#endif
|
||||
}
|
||||
|
||||
CrashReporterParent::~CrashReporterParent()
|
||||
|
@ -83,5 +105,67 @@ CrashReporterParent::~CrashReporterParent()
|
|||
MOZ_COUNT_DTOR(CrashReporterParent);
|
||||
}
|
||||
|
||||
void
|
||||
CrashReporterParent::SetChildData(const NativeThreadId& tid,
|
||||
const PRUint32& processType)
|
||||
{
|
||||
mInitialized = true;
|
||||
mMainThread = tid;
|
||||
mProcessType = processType;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
bool
|
||||
CrashReporterParent::GenerateHangCrashReport(const AnnotationTable* processNotes)
|
||||
{
|
||||
if (mChildDumpID.IsEmpty())
|
||||
return false;
|
||||
|
||||
GenerateChildData(processNotes);
|
||||
|
||||
CrashReporter::AnnotationTable notes;
|
||||
if (!notes.Init(4))
|
||||
return false;
|
||||
notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
|
||||
if (!CrashReporter::AppendExtraData(mParentDumpID, notes))
|
||||
NS_WARNING("problem appending parent data to .extra");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes)
|
||||
{
|
||||
MOZ_ASSERT(mInitialized);
|
||||
|
||||
nsCAutoString type;
|
||||
switch (mProcessType) {
|
||||
case GeckoProcessType_Content:
|
||||
type = NS_LITERAL_CSTRING("content");
|
||||
break;
|
||||
case GeckoProcessType_Plugin:
|
||||
type = NS_LITERAL_CSTRING("plugin");
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("unknown process type");
|
||||
break;
|
||||
}
|
||||
mNotes.Put(NS_LITERAL_CSTRING("ProcessType"), type);
|
||||
|
||||
char startTime[32];
|
||||
sprintf(startTime, "%lld", static_cast<PRInt64>(mStartTime));
|
||||
mNotes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime));
|
||||
|
||||
if (!mAppNotes.IsEmpty())
|
||||
mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes);
|
||||
|
||||
bool ret = CrashReporter::AppendExtraData(mChildDumpID, mNotes);
|
||||
if (ret && processNotes)
|
||||
ret = CrashReporter::AppendExtraData(mChildDumpID, *processNotes);
|
||||
if (!ret)
|
||||
NS_WARNING("problem appending child data to .extra");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set sw=4 ts=8 et tw=80 :
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
|
@ -37,21 +37,162 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "mozilla/dom/PCrashReporterParent.h"
|
||||
#include "mozilla/dom/TabMessageUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsILocalFile.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ProcessReporter;
|
||||
|
||||
class CrashReporterParent :
|
||||
public PCrashReporterParent
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
typedef CrashReporter::AnnotationTable AnnotationTable;
|
||||
#endif
|
||||
public:
|
||||
CrashReporterParent();
|
||||
virtual ~CrashReporterParent();
|
||||
CrashReporterParent();
|
||||
virtual ~CrashReporterParent();
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
/* Attempt to generate a parent/child pair of minidumps from the given
|
||||
toplevel actor in the event of a hang. Returns true if successful,
|
||||
false otherwise.
|
||||
*/
|
||||
template<class Toplevel>
|
||||
bool
|
||||
GeneratePairedMinidump(Toplevel* t);
|
||||
|
||||
/* Attempt to create a bare-bones crash report for a hang, along with extra
|
||||
process-specific annotations present in the given AnnotationTable. Returns
|
||||
true if successful, false otherwise.
|
||||
*/
|
||||
bool
|
||||
GenerateHangCrashReport(const AnnotationTable* processNotes);
|
||||
|
||||
/* Attempt to create a bare-bones crash report, along with extra process-
|
||||
specific annotations present in the given AnnotationTable. Returns true if
|
||||
successful, false otherwise.
|
||||
*/
|
||||
template<class Toplevel>
|
||||
bool
|
||||
GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes);
|
||||
|
||||
/* Instantiate a new crash reporter actor from a given parent that manages
|
||||
the protocol.
|
||||
*/
|
||||
template<class Toplevel>
|
||||
static void CreateCrashReporter(Toplevel* actor);
|
||||
#endif
|
||||
/* Initialize this reporter with data from the child process */
|
||||
void
|
||||
SetChildData(const NativeThreadId& id, const PRUint32& processType);
|
||||
|
||||
/* Returns the shared hang ID of a parent/child paired minidump.
|
||||
GeneratePairedMinidump must be called first.
|
||||
*/
|
||||
const nsString& HangID() {
|
||||
return mHangID;
|
||||
}
|
||||
/* Returns the ID of the parent minidump.
|
||||
GeneratePairedMinidump must be called first.
|
||||
*/
|
||||
const nsString& ParentDumpID() {
|
||||
return mParentDumpID;
|
||||
}
|
||||
/* Returns the ID of the child minidump.
|
||||
GeneratePairedMinidump or GenerateCrashReport must be called first.
|
||||
*/
|
||||
const nsString& ChildDumpID() {
|
||||
return mChildDumpID;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void ActorDestroy(ActorDestroyReason why);
|
||||
|
||||
virtual bool
|
||||
RecvAddLibraryMappings(const InfallibleTArray<Mapping>& m);
|
||||
virtual bool
|
||||
RecvAnnotateCrashReport(const nsCString& key, const nsCString& data);
|
||||
virtual bool
|
||||
RecvAppendAppNotes(const nsCString& data);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
bool
|
||||
GenerateChildData(const AnnotationTable* processNotes);
|
||||
|
||||
AnnotationTable mNotes;
|
||||
#endif
|
||||
nsCString mAppNotes;
|
||||
nsString mHangID;
|
||||
nsString mChildDumpID;
|
||||
nsString mParentDumpID;
|
||||
NativeThreadId mMainThread;
|
||||
time_t mStartTime;
|
||||
PRUint32 mProcessType;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
template<class Toplevel>
|
||||
inline bool
|
||||
CrashReporterParent::GeneratePairedMinidump(Toplevel* t)
|
||||
{
|
||||
CrashReporter::ProcessHandle child;
|
||||
#ifdef XP_MACOSX
|
||||
child = t->Process()->GetChildTask();
|
||||
#else
|
||||
child = t->OtherProcess();
|
||||
#endif
|
||||
nsCOMPtr<nsILocalFile> childDump;
|
||||
nsCOMPtr<nsILocalFile> parentDump;
|
||||
if (CrashReporter::CreatePairedMinidumps(child,
|
||||
mMainThread,
|
||||
&mHangID,
|
||||
getter_AddRefs(childDump),
|
||||
getter_AddRefs(parentDump)) &&
|
||||
CrashReporter::GetIDFromMinidump(childDump, mChildDumpID) &&
|
||||
CrashReporter::GetIDFromMinidump(parentDump, mParentDumpID)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class Toplevel>
|
||||
inline bool
|
||||
CrashReporterParent::GenerateCrashReport(Toplevel* t,
|
||||
const AnnotationTable* processNotes)
|
||||
{
|
||||
nsCOMPtr<nsILocalFile> crashDump;
|
||||
if (t->TakeMinidump(getter_AddRefs(crashDump)) &&
|
||||
CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) {
|
||||
return GenerateChildData(processNotes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class Toplevel>
|
||||
/* static */ void
|
||||
CrashReporterParent::CreateCrashReporter(Toplevel* actor)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
NativeThreadId id;
|
||||
PRUint32 processType;
|
||||
PCrashReporterParent* p =
|
||||
actor->CallPCrashReporterConstructor(&id, &processType);
|
||||
if (p) {
|
||||
static_cast<CrashReporterParent*>(p)->SetChildData(id, processType);
|
||||
} else {
|
||||
NS_ERROR("Error creating crash reporter actor");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -65,6 +65,7 @@ EXPORTS_mozilla/dom = \
|
|||
CrashReporterParent.h \
|
||||
TabParent.h \
|
||||
TabChild.h \
|
||||
TabMessageUtils.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
@ -72,6 +73,7 @@ CPPSRCS = \
|
|||
ContentParent.cpp \
|
||||
ContentChild.cpp \
|
||||
CrashReporterParent.cpp \
|
||||
CrashReporterChild.cpp \
|
||||
TabParent.cpp \
|
||||
TabChild.cpp \
|
||||
TabMessageUtils.cpp \
|
||||
|
@ -88,7 +90,6 @@ CPPSRCS += \
|
|||
$(NULL)
|
||||
endif
|
||||
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -47,6 +47,7 @@ include protocol PMemoryReportRequest;
|
|||
|
||||
include "mozilla/chrome/RegistryMessageUtils.h";
|
||||
include "mozilla/net/NeckoMessageUtils.h";
|
||||
include "mozilla/dom/TabMessageUtils.h";
|
||||
|
||||
include "nsGeoPositionIPCSerialiser.h";
|
||||
include "PPrefTuple.h";
|
||||
|
@ -60,6 +61,7 @@ using OverrideMapping;
|
|||
using IPC::URI;
|
||||
using IPC::Permission;
|
||||
using mozilla::null_t;
|
||||
using mozilla::dom::NativeThreadId;
|
||||
using gfxIntSize;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -143,12 +145,13 @@ child:
|
|||
|
||||
parent:
|
||||
PNecko();
|
||||
PCrashReporter();
|
||||
|
||||
PStorage(StorageConstructData data);
|
||||
|
||||
PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
|
||||
|
||||
sync PCrashReporter(NativeThreadId tid, PRUint32 processType);
|
||||
|
||||
// Services remoting
|
||||
|
||||
async StartVisitedQuery(URI uri);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
include protocol PContent;
|
||||
include protocol PPluginModule;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -51,11 +52,13 @@ struct Mapping {
|
|||
};
|
||||
|
||||
protocol PCrashReporter {
|
||||
manager PContent;
|
||||
manager PContent or PPluginModule;
|
||||
parent:
|
||||
AddLibraryMappings(Mapping[] m);
|
||||
AnnotateCrashReport(nsCString key, nsCString data);
|
||||
AppendAppNotes(nsCString data);
|
||||
__delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@
|
|||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
struct RemoteDOMEvent
|
||||
|
@ -53,6 +57,13 @@ struct RemoteDOMEvent
|
|||
bool ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
|
||||
mozilla::dom::RemoteDOMEvent* aResult);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
typedef CrashReporter::ThreadId NativeThreadId;
|
||||
#else
|
||||
// unused in this case
|
||||
typedef int32 NativeThreadId;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +89,6 @@ struct ParamTraits<mozilla::dom::RemoteDOMEvent>
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,14 +40,16 @@
|
|||
include protocol PPluginIdentifier;
|
||||
include protocol PPluginInstance;
|
||||
include protocol PPluginScriptableObject;
|
||||
include protocol PCrashReporter;
|
||||
|
||||
include "npapi.h";
|
||||
include "mozilla/plugins/PluginMessageUtils.h";
|
||||
include "mozilla/dom/TabMessageUtils.h";
|
||||
|
||||
using NPError;
|
||||
using NPNVariable;
|
||||
using base::FileDescriptor;
|
||||
using mozilla::plugins::NativeThreadId;
|
||||
using mozilla::dom::NativeThreadId;
|
||||
using mac_plugin_interposing::NSCursorInfo;
|
||||
using nsID;
|
||||
|
||||
|
@ -58,6 +60,7 @@ rpc protocol PPluginModule
|
|||
{
|
||||
manages PPluginInstance;
|
||||
manages PPluginIdentifier;
|
||||
manages PCrashReporter;
|
||||
|
||||
both:
|
||||
/**
|
||||
|
@ -84,9 +87,8 @@ child:
|
|||
rpc NP_GetEntryPoints()
|
||||
returns (NPError rv);
|
||||
|
||||
// Return the plugin's thread ID, if it can be found.
|
||||
rpc NP_Initialize()
|
||||
returns (NativeThreadId tid, NPError rv);
|
||||
returns (NPError rv);
|
||||
|
||||
rpc PPluginInstance(nsCString aMimeType,
|
||||
uint16_t aMode,
|
||||
|
@ -114,6 +116,9 @@ child:
|
|||
|
||||
async SetParentHangTimeout(uint32_t seconds);
|
||||
|
||||
rpc PCrashReporter()
|
||||
returns (NativeThreadId tid, PRUint32 processType);
|
||||
|
||||
parent:
|
||||
/**
|
||||
* This message is only used on X11 platforms.
|
||||
|
@ -141,8 +146,6 @@ parent:
|
|||
// native events, then "livelock" and some other glitches can occur.
|
||||
rpc ProcessSomeEvents();
|
||||
|
||||
sync AppendNotesToCrashReport(nsCString aNotes);
|
||||
|
||||
// OS X Specific calls to manage the plugin's window
|
||||
// when interposing system calls.
|
||||
async PluginShowWindow(uint32_t aWindowId, bool aModal,
|
||||
|
|
|
@ -142,13 +142,6 @@ typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
|
|||
typedef mozilla::null_t WindowsSharedMemoryHandle;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
typedef CrashReporter::ThreadId NativeThreadId;
|
||||
#else
|
||||
// unused in this case
|
||||
typedef int32 NativeThreadId;
|
||||
#endif
|
||||
|
||||
// XXX maybe not the best place for these. better one?
|
||||
|
||||
#define VARSTR(v_) case v_: return #v_
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include "mozilla/plugins/BrowserStreamChild.h"
|
||||
#include "mozilla/plugins/PluginStreamChild.h"
|
||||
#include "PluginIdentifierChild.h"
|
||||
#include "mozilla/dom/CrashReporterChild.h"
|
||||
|
||||
#include "nsNPAPIPlugin.h"
|
||||
|
||||
|
@ -81,6 +82,8 @@
|
|||
#endif
|
||||
|
||||
using namespace mozilla::plugins;
|
||||
using mozilla::dom::CrashReporterChild;
|
||||
using mozilla::dom::PCrashReporterChild;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
const PRUnichar * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
|
||||
|
@ -592,7 +595,6 @@ PluginModuleChild::InitGraphics()
|
|||
// Do this after initializing GDK, or GDK will install its own handler.
|
||||
XRE_InstallX11ErrorHandler();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -705,6 +707,33 @@ PluginModuleChild::QuickExit()
|
|||
_exit(0);
|
||||
}
|
||||
|
||||
PCrashReporterChild*
|
||||
PluginModuleChild::AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
|
||||
PRUint32* processType)
|
||||
{
|
||||
return new CrashReporterChild();
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::DeallocPCrashReporter(PCrashReporterChild* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::AnswerPCrashReporterConstructor(
|
||||
PCrashReporterChild* actor,
|
||||
mozilla::dom::NativeThreadId* id,
|
||||
PRUint32* processType)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
*id = CrashReporter::CurrentThreadId();
|
||||
*processType = XRE_GetProcessType();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChild::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
|
@ -1801,17 +1830,11 @@ PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
|
|||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::AnswerNP_Initialize(NativeThreadId* tid, NPError* _retval)
|
||||
PluginModuleChild::AnswerNP_Initialize(NPError* _retval)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
AssertPluginThread();
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
*tid = CrashReporter::CurrentThreadId();
|
||||
#else
|
||||
*tid = 0;
|
||||
#endif
|
||||
|
||||
#ifdef OS_WIN
|
||||
SetEventHooks();
|
||||
#endif
|
||||
|
|
|
@ -91,6 +91,10 @@ typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFun
|
|||
typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class PCrashReporterChild;
|
||||
}
|
||||
|
||||
namespace plugins {
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
|
@ -103,6 +107,7 @@ class PluginInstanceChild;
|
|||
|
||||
class PluginModuleChild : public PPluginModuleChild
|
||||
{
|
||||
typedef mozilla::dom::PCrashReporterChild PCrashReporterChild;
|
||||
protected:
|
||||
NS_OVERRIDE
|
||||
virtual mozilla::ipc::RPCChannel::RacyRPCPolicy
|
||||
|
@ -116,7 +121,7 @@ protected:
|
|||
|
||||
// Implement the PPluginModuleChild interface
|
||||
virtual bool AnswerNP_GetEntryPoints(NPError* rv);
|
||||
virtual bool AnswerNP_Initialize(NativeThreadId* tid, NPError* rv);
|
||||
virtual bool AnswerNP_Initialize(NPError* rv);
|
||||
|
||||
virtual PPluginIdentifierChild*
|
||||
AllocPPluginIdentifier(const nsCString& aString,
|
||||
|
@ -174,6 +179,16 @@ protected:
|
|||
virtual bool
|
||||
RecvSetParentHangTimeout(const uint32_t& aSeconds);
|
||||
|
||||
virtual PCrashReporterChild*
|
||||
AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
|
||||
PRUint32* processType);
|
||||
virtual bool
|
||||
DeallocPCrashReporter(PCrashReporterChild* actor);
|
||||
virtual bool
|
||||
AnswerPCrashReporterConstructor(PCrashReporterChild* actor,
|
||||
mozilla::dom::NativeThreadId* id,
|
||||
PRUint32* processType);
|
||||
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason why);
|
||||
|
||||
|
|
|
@ -56,12 +56,13 @@
|
|||
#include "mozilla/ipc/SyncChannel.h"
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
#include "mozilla/plugins/BrowserStreamParent.h"
|
||||
#include "mozilla/dom/PCrashReporterParent.h"
|
||||
#include "PluginIdentifierParent.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "mozilla/dom/CrashReporterParent.h"
|
||||
#endif
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "nsILocalFile.h"
|
||||
|
@ -74,6 +75,8 @@ using base::KillProcess;
|
|||
|
||||
using mozilla::PluginLibrary;
|
||||
using mozilla::ipc::SyncChannel;
|
||||
using mozilla::dom::PCrashReporterParent;
|
||||
using mozilla::dom::CrashReporterParent;
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::plugins;
|
||||
|
@ -111,19 +114,22 @@ PluginModuleParent::LoadModule(const char* aFilePath)
|
|||
parent->mSubprocess->GetChildProcessHandle());
|
||||
|
||||
TimeoutChanged(kChildTimeoutPref, parent);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporterParent::CreateCrashReporter(parent.get());
|
||||
#endif
|
||||
|
||||
return parent.forget();
|
||||
}
|
||||
|
||||
|
||||
PluginModuleParent::PluginModuleParent(const char* aFilePath)
|
||||
: mSubprocess(new PluginProcessParent(aFilePath))
|
||||
, mPluginThread(0)
|
||||
, mShutdown(false)
|
||||
, mClearSiteDataSupported(false)
|
||||
, mGetSitesWithDataSupported(false)
|
||||
, mNPNIface(NULL)
|
||||
, mPlugin(NULL)
|
||||
, mProcessStartTime(time(NULL))
|
||||
, mTaskFactory(this)
|
||||
{
|
||||
NS_ASSERTION(mSubprocess, "Out of memory!");
|
||||
|
@ -164,20 +170,10 @@ PluginModuleParent::~PluginModuleParent()
|
|||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
void
|
||||
PluginModuleParent::WritePluginExtraDataForMinidump(const nsAString& id)
|
||||
PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
|
||||
{
|
||||
typedef nsDependentCString CS;
|
||||
|
||||
CrashReporter::AnnotationTable notes;
|
||||
if (!notes.Init(32))
|
||||
return;
|
||||
|
||||
notes.Put(CS("ProcessType"), CS("plugin"));
|
||||
|
||||
char startTime[32];
|
||||
sprintf(startTime, "%lld", static_cast<PRInt64>(mProcessStartTime));
|
||||
notes.Put(CS("StartupTime"), CS(startTime));
|
||||
|
||||
// Get the plugin filename, try to get just the file leafname
|
||||
const std::string& pluginFile = mSubprocess->GetPluginFilePath();
|
||||
size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
|
||||
|
@ -192,39 +188,12 @@ PluginModuleParent::WritePluginExtraDataForMinidump(const nsAString& id)
|
|||
notes.Put(CS("PluginName"), CS(""));
|
||||
notes.Put(CS("PluginVersion"), CS(""));
|
||||
|
||||
if (!mCrashNotes.IsEmpty())
|
||||
notes.Put(CS("Notes"), CS(mCrashNotes.get()));
|
||||
|
||||
if (!mHangID.IsEmpty())
|
||||
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(mHangID));
|
||||
|
||||
if (!CrashReporter::AppendExtraData(id, notes))
|
||||
NS_WARNING("problem appending plugin data to .extra");
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleParent::WriteExtraDataForHang()
|
||||
{
|
||||
// this writes HangID
|
||||
WritePluginExtraDataForMinidump(mPluginDumpID);
|
||||
|
||||
CrashReporter::AnnotationTable notes;
|
||||
if (!notes.Init(4))
|
||||
return;
|
||||
|
||||
notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
|
||||
if (!CrashReporter::AppendExtraData(mBrowserDumpID, notes))
|
||||
NS_WARNING("problem appending browser data to .extra");
|
||||
const nsString& hangID = CrashReporter()->HangID();
|
||||
if (!hangID.IsEmpty())
|
||||
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
|
||||
}
|
||||
#endif // MOZ_CRASHREPORTER
|
||||
|
||||
bool
|
||||
PluginModuleParent::RecvAppendNotesToCrashReport(const nsCString& aNotes)
|
||||
{
|
||||
mCrashNotes.Append(aNotes);
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
|
||||
{
|
||||
|
@ -254,29 +223,16 @@ bool
|
|||
PluginModuleParent::ShouldContinueFromReplyTimeout()
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
nsCOMPtr<nsILocalFile> pluginDump;
|
||||
nsCOMPtr<nsILocalFile> browserDump;
|
||||
CrashReporter::ProcessHandle child;
|
||||
#ifdef XP_MACOSX
|
||||
child = mSubprocess->GetChildTask();
|
||||
#else
|
||||
child = OtherProcess();
|
||||
#endif
|
||||
if (CrashReporter::CreatePairedMinidumps(child,
|
||||
mPluginThread,
|
||||
&mHangID,
|
||||
getter_AddRefs(pluginDump),
|
||||
getter_AddRefs(browserDump)) &&
|
||||
CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID) &&
|
||||
CrashReporter::GetIDFromMinidump(browserDump, mBrowserDumpID)) {
|
||||
|
||||
CrashReporterParent* crashReporter = CrashReporter();
|
||||
if (crashReporter->GeneratePairedMinidump(this)) {
|
||||
mBrowserDumpID = crashReporter->ParentDumpID();
|
||||
mPluginDumpID = crashReporter->ChildDumpID();
|
||||
PLUGIN_LOG_DEBUG(
|
||||
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
|
||||
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(mHangID).get()));
|
||||
}
|
||||
else {
|
||||
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
|
||||
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
|
||||
NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
|
||||
} else {
|
||||
NS_WARNING("failed to capture paired minidumps from hang");
|
||||
}
|
||||
#endif
|
||||
|
@ -294,21 +250,34 @@ PluginModuleParent::ShouldContinueFromReplyTimeout()
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporterParent*
|
||||
PluginModuleParent::CrashReporter()
|
||||
{
|
||||
MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
|
||||
return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
PluginModuleParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
switch (why) {
|
||||
case AbnormalShutdown: {
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
nsCOMPtr<nsILocalFile> pluginDump;
|
||||
if (TakeMinidump(getter_AddRefs(pluginDump)) &&
|
||||
CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID)) {
|
||||
CrashReporterParent* crashReporter = CrashReporter();
|
||||
|
||||
CrashReporter::AnnotationTable notes;
|
||||
notes.Init(4);
|
||||
WriteExtraDataForMinidump(notes);
|
||||
|
||||
if (crashReporter->GenerateCrashReport(this, ¬es)) {
|
||||
mPluginDumpID = crashReporter->ChildDumpID();
|
||||
PLUGIN_LOG_DEBUG(("got child minidump: %s",
|
||||
NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
|
||||
WritePluginExtraDataForMinidump(mPluginDumpID);
|
||||
}
|
||||
else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
|
||||
WriteExtraDataForHang();
|
||||
crashReporter->GenerateHangCrashReport(¬es);
|
||||
}
|
||||
else {
|
||||
NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
|
||||
|
@ -781,7 +750,7 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!CallNP_Initialize(&mPluginThread, error)) {
|
||||
if (!CallNP_Initialize(error)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
else if (*error != NPERR_NO_ERROR) {
|
||||
|
@ -805,7 +774,7 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!CallNP_Initialize(&mPluginThread, error))
|
||||
if (!CallNP_Initialize(error))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
#if defined XP_WIN && MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
|
@ -1106,6 +1075,24 @@ PluginModuleParent::RecvPluginHideWindow(const uint32_t& aWindowId)
|
|||
#endif
|
||||
}
|
||||
|
||||
PCrashReporterParent*
|
||||
PluginModuleParent::AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
|
||||
PRUint32* processType)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
return new CrashReporterParent();
|
||||
#else
|
||||
return nsnull;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleParent::DeallocPCrashReporter(PCrashReporterParent* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
|
||||
{
|
||||
|
|
|
@ -65,6 +65,11 @@
|
|||
#include "nsITimer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class PCrashReporterParent;
|
||||
class CrashReporterParent;
|
||||
}
|
||||
|
||||
namespace plugins {
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -85,6 +90,8 @@ class PluginModuleParent : public PPluginModuleParent, PluginLibrary
|
|||
{
|
||||
private:
|
||||
typedef mozilla::PluginLibrary PluginLibrary;
|
||||
typedef mozilla::dom::PCrashReporterParent PCrashReporterParent;
|
||||
typedef mozilla::dom::CrashReporterParent CrashReporterParent;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -184,9 +191,6 @@ protected:
|
|||
NS_OVERRIDE virtual bool
|
||||
RecvProcessNativeEventsInRPCCall();
|
||||
|
||||
virtual bool
|
||||
RecvAppendNotesToCrashReport(const nsCString& aNotes);
|
||||
|
||||
NS_OVERRIDE virtual bool
|
||||
RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
|
||||
const int32_t& aX, const int32_t& aY,
|
||||
|
@ -195,6 +199,12 @@ protected:
|
|||
NS_OVERRIDE virtual bool
|
||||
RecvPluginHideWindow(const uint32_t& aWindowId);
|
||||
|
||||
NS_OVERRIDE virtual PCrashReporterParent*
|
||||
AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
|
||||
PRUint32* processType);
|
||||
NS_OVERRIDE virtual bool
|
||||
DeallocPCrashReporter(PCrashReporterParent* actor);
|
||||
|
||||
NS_OVERRIDE virtual bool
|
||||
RecvSetCursor(const NSCursorInfo& aCursorInfo);
|
||||
|
||||
|
@ -302,13 +312,15 @@ private:
|
|||
#endif
|
||||
|
||||
private:
|
||||
void WritePluginExtraDataForMinidump(const nsAString& id);
|
||||
void WriteExtraDataForHang();
|
||||
CrashReporterParent* CrashReporter();
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
|
||||
#endif
|
||||
void CleanupFromTimeout();
|
||||
static int TimeoutChanged(const char* aPref, void* aModule);
|
||||
void NotifyPluginCrashed();
|
||||
|
||||
nsCString mCrashNotes;
|
||||
PluginProcessParent* mSubprocess;
|
||||
// the plugin thread in mSubprocess
|
||||
NativeThreadId mPluginThread;
|
||||
|
@ -318,7 +330,6 @@ private:
|
|||
const NPNetscapeFuncs* mNPNIface;
|
||||
nsDataHashtable<nsVoidPtrHashKey, PluginIdentifierParent*> mIdentifiers;
|
||||
nsNPAPIPlugin* mPlugin;
|
||||
time_t mProcessStartTime;
|
||||
ScopedRunnableMethodFactory<PluginModuleParent> mTaskFactory;
|
||||
nsString mPluginDumpID;
|
||||
nsString mBrowserDumpID;
|
||||
|
@ -334,6 +345,8 @@ private:
|
|||
// object instead of the plugin process's lifetime
|
||||
ScopedClose mPluginXSocketFdDup;
|
||||
#endif
|
||||
|
||||
friend class mozilla::dom::CrashReporterParent;
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
|
|
@ -175,17 +175,5 @@ PluginProcessChild::CleanUp()
|
|||
nsRegion::ShutdownStatic();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
PluginProcessChild::AppendNotesToCrashReport(const nsCString& aNotes)
|
||||
{
|
||||
AssertPluginThread();
|
||||
|
||||
PluginProcessChild* p = PluginProcessChild::current();
|
||||
if (p) {
|
||||
p->mPlugin.SendAppendNotesToCrashReport(aNotes);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -61,9 +61,6 @@ public:
|
|||
NS_OVERRIDE virtual bool Init();
|
||||
NS_OVERRIDE virtual void CleanUp();
|
||||
|
||||
// For use on the plugin thread.
|
||||
static void AppendNotesToCrashReport(const nsCString& aNotes);
|
||||
|
||||
protected:
|
||||
static PluginProcessChild* current() {
|
||||
return static_cast<PluginProcessChild*>(ProcessChild::current());
|
||||
|
|
|
@ -99,16 +99,18 @@
|
|||
|
||||
<activity android:name="Restarter"
|
||||
android:process="@ANDROID_PACKAGE_NAME@Restarter"
|
||||
android:theme="@style/GreyTheme">
|
||||
android:theme="@style/GreyTheme"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.restart"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
#if MOZ_CRASHREPORTER
|
||||
<activity android:name="CrashReporter"
|
||||
android:label="@string/crash_reporter_title"
|
||||
android:icon="@drawable/crash_reporter" >
|
||||
<activity android:name="CrashReporter"
|
||||
android:label="@string/crash_reporter_title"
|
||||
android:icon="@drawable/crash_reporter"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.reportCrash" />
|
||||
</intent-filter>
|
||||
|
|
|
@ -1677,7 +1677,7 @@ GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
|
|||
GLenum aWrapMode,
|
||||
bool aUseNearestFilter)
|
||||
{
|
||||
nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType);
|
||||
nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aUseNearestFilter);
|
||||
return t.forget();
|
||||
};
|
||||
|
||||
|
|
|
@ -146,3 +146,18 @@ TestShellCommandParent::ReleaseCallback()
|
|||
{
|
||||
mCallback.Release();
|
||||
}
|
||||
|
||||
bool
|
||||
TestShellCommandParent::ExecuteCallback(const nsString& aResponse)
|
||||
{
|
||||
return static_cast<TestShellParent*>(Manager())->CommandDone(
|
||||
this, aResponse);
|
||||
}
|
||||
|
||||
void
|
||||
TestShellCommandParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (why == AbnormalShutdown) {
|
||||
ExecuteCallback(EmptyString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,9 +92,12 @@ public:
|
|||
void ReleaseCallback();
|
||||
|
||||
protected:
|
||||
bool ExecuteCallback(const nsString& aResponse);
|
||||
|
||||
void ActorDestroy(ActorDestroyReason why);
|
||||
|
||||
bool Recv__delete__(const nsString& aResponse) {
|
||||
return static_cast<TestShellParent*>(Manager())->CommandDone(
|
||||
this, aResponse);
|
||||
return ExecuteCallback(aResponse);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -726,8 +726,10 @@ xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
|
|||
|
||||
size_t len;
|
||||
const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
|
||||
if (!chars)
|
||||
if (!chars) {
|
||||
mValid = JS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
new(mBuf) implementation_type(chars, len);
|
||||
mValid = JS_TRUE;
|
||||
|
@ -772,8 +774,10 @@ xpc_qsAUTF8String::xpc_qsAUTF8String(JSContext *cx, jsval v, jsval *pval)
|
|||
|
||||
size_t len;
|
||||
const PRUnichar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
|
||||
if (!chars)
|
||||
if (!chars) {
|
||||
mValid = JS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
new(mBuf) implementation_type(chars, len);
|
||||
mValid = JS_TRUE;
|
||||
|
|
|
@ -941,7 +941,9 @@ function StartCurrentURI(aState)
|
|||
// there's already a canvas for this URL
|
||||
setTimeout(RecordResult, 0);
|
||||
} else {
|
||||
gDumpLog("REFTEST TEST-START | " + gCurrentURL + "\n");
|
||||
var currentTest = gTotalTests - gURLs.length;
|
||||
gDumpLog("REFTEST TEST-START | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests +
|
||||
" (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n");
|
||||
LogInfo("START " + gCurrentURL);
|
||||
var type = gURLs[0].type
|
||||
if (TYPE_SCRIPT == type) {
|
||||
|
|
|
@ -41,6 +41,9 @@ var TabsPopup = {
|
|||
Elements.tabs.addEventListener("TabRemove", this, true);
|
||||
|
||||
this._updateTabsCount();
|
||||
|
||||
// Bind resizeHandler so we can pass it to addEventListener/removeEventListener.
|
||||
this.resizeHandler = this.resizeHandler.bind(this);
|
||||
},
|
||||
|
||||
get box() {
|
||||
|
@ -117,12 +120,7 @@ var TabsPopup = {
|
|||
this.box.anchorTo(this.button, "after_end");
|
||||
BrowserUI.pushPopup(this, [this.box, this.button]);
|
||||
|
||||
window.addEventListener("resize", function resizeHandler(aEvent) {
|
||||
if (aEvent.target != window)
|
||||
return;
|
||||
if (!Util.isPortrait())
|
||||
TabsPopup._hidePortraitMenu();
|
||||
}, false);
|
||||
window.addEventListener("resize", this.resizeHandler, false);
|
||||
},
|
||||
|
||||
toggle: function toggle() {
|
||||
|
@ -140,7 +138,7 @@ var TabsPopup = {
|
|||
if (!this.box.hidden) {
|
||||
this.box.hidden = true;
|
||||
BrowserUI.popPopup(this);
|
||||
window.removeEventListener("resize", resizeHandler, false);
|
||||
window.removeEventListener("resize", this.resizeHandler, false);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -172,6 +170,13 @@ var TabsPopup = {
|
|||
cmd.setAttribute("label", Browser.tabs.length);
|
||||
},
|
||||
|
||||
resizeHandler: function resizeHandler(aEvent) {
|
||||
if (aEvent.target != window)
|
||||
return;
|
||||
if (!Util.isPortrait())
|
||||
this._hidePortraitMenu();
|
||||
},
|
||||
|
||||
handleEvent: function handleEvent(aEvent) {
|
||||
this._updateTabsCount();
|
||||
}
|
||||
|
|
|
@ -1356,14 +1356,16 @@ Browser.MainDragger.prototype = {
|
|||
let isTablet = Util.isTablet();
|
||||
this._panToolbars = !isTablet;
|
||||
|
||||
this._grabSidebar = false;
|
||||
this._canGrabSidebar = false;
|
||||
// In landscape portrait mode, swiping from the left margin drags the tab sidebar.
|
||||
this._grabSidebar = isTablet && !Util.isPortrait() &&
|
||||
((Util.localeDir == Util.LOCALE_DIR_LTR) ?
|
||||
(clientX - bcr.left < 30) :
|
||||
(bcr.right - clientX < 30));
|
||||
|
||||
if (this._grabSidebar)
|
||||
Browser.grabSidebar();
|
||||
if (isTablet && !Util.isPortrait()) {
|
||||
let grabSidebarMargin = TabsPopup.visible ? 30 : 5;
|
||||
// Don't actually grab until we see whether the swipe is horizontal in dragMove.
|
||||
this._canGrabSidebar = ((Util.localeDir == Util.LOCALE_DIR_LTR)
|
||||
? (clientX - bcr.left < 30)
|
||||
: (bcr.right - clientX < 30));
|
||||
}
|
||||
|
||||
if (this._sidebarTimeout) {
|
||||
clearTimeout(this._sidebarTimeout);
|
||||
|
@ -1376,6 +1378,7 @@ Browser.MainDragger.prototype = {
|
|||
Browser.ungrabSidebar();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._contentView && this._contentView._updateCacheViewport)
|
||||
this._contentView._updateCacheViewport();
|
||||
this._contentView = null;
|
||||
|
@ -1384,6 +1387,10 @@ Browser.MainDragger.prototype = {
|
|||
},
|
||||
|
||||
dragMove: function dragMove(dx, dy, scroller, aIsKinetic) {
|
||||
if (this._canGrabSidebar && !this._grabSidebar && dx) {
|
||||
this._grabSidebar = true;
|
||||
Browser.grabSidebar();
|
||||
}
|
||||
if (this._grabSidebar) {
|
||||
Browser.slideSidebarBy(dx);
|
||||
return;
|
||||
|
|
|
@ -65,22 +65,23 @@ function starttest() {
|
|||
is(computedStyle(divObj, 'display'), 'block', 'computedStyle did not get right display value');
|
||||
document.body.removeChild(div1);
|
||||
|
||||
//use waitForFocus
|
||||
/* note: expectChildProcessCrash is not being tested here, as it causes wildly variable
|
||||
* run times. It is currently being tested in:
|
||||
* dom/plugins/test/test_hanging.html and dom/plugins/test/test_crashing.html
|
||||
*/
|
||||
|
||||
//note: this also adds a short wait period
|
||||
SimpleTest.executeSoon(
|
||||
function () {
|
||||
//finish() calls a slew of SimpleTest functions
|
||||
SimpleTest.finish();
|
||||
//call this after finish so we can make sure it works and doesn't hang our process
|
||||
SimpleTest.expectUncaughtException();
|
||||
throw "i am an uncaught exception"
|
||||
/**
|
||||
* Actually testing a crash of a child process ended up with wildly variable runtimes,
|
||||
* on the scale of >1 second, so just make sure we can safely call the method
|
||||
*/
|
||||
SimpleTest.expectChildProcessCrash();
|
||||
var endTime = new Date();
|
||||
SimpleTest.info("Profile::SimpleTestRunTime: " + (endTime-startTime));
|
||||
//expect and throw exception here. Otherwise, any code that follows the throw call will never be executed
|
||||
SimpleTest.expectUncaughtException();
|
||||
//make sure we catch this error
|
||||
throw "i am an uncaught exception"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -78,6 +78,9 @@ skip-if = !debug
|
|||
[include:toolkit/crashreporter/test/unit/xpcshell.ini]
|
||||
skip-if = os == "linux" || !crashreporter
|
||||
|
||||
[include:toolkit/crashreporter/test/unit_ipc/xpcshell.ini]
|
||||
skip-if.os == "linux" || !crashreporter
|
||||
|
||||
#XXX: we don't actually set os = maemo
|
||||
[include:toolkit/crashreporter/client/maemo-unit/xpcshell.ini]
|
||||
run-if = os == "maemo"
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<stack flex="1">
|
||||
<label id="topleft" value="Top Left" left="15" top="15"/>
|
||||
<label id="topleft" value="Top Left Corner" left="15" top="15"/>
|
||||
<label id="topright" value="Top Right" right="15" top="15"/>
|
||||
<label id="bottomleft" value="Bottom Left" left="15" bottom="15"/>
|
||||
<label id="bottomleft" value="Bottom Left Corner" left="15" bottom="15"/>
|
||||
<label id="bottomright" value="Bottom Right" right="15" bottom="15"/>
|
||||
<!-- Our SimpleTest/TestRunner.js runs tests inside an iframe which sizes are W=500 H=300.
|
||||
'left' and 'top' values need to be set so that the panel (popup) has enough room to display on its 4 sides. -->
|
||||
|
@ -35,7 +35,7 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var expectedAnchor = null;
|
||||
var expectedSide = "", expectedAnchorEdge = "";
|
||||
var expectedSide = "", expectedAnchorEdge = "", expectedPack = "";
|
||||
var zoomFactor = 1;
|
||||
var runNextTest;
|
||||
|
||||
|
@ -49,96 +49,107 @@ function nextTest()
|
|||
{
|
||||
var panel = $("panel");
|
||||
|
||||
function openPopup(position, anchor, expected, anchorEdge)
|
||||
function openPopup(position, anchor, expected, anchorEdge, pack)
|
||||
{
|
||||
expectedAnchor = anchor instanceof Node ? anchor : $(anchor);
|
||||
expectedSide = expected;
|
||||
expectedAnchorEdge = anchorEdge;
|
||||
expectedPack = pack;
|
||||
|
||||
panel.removeAttribute("side");
|
||||
panel.openPopup(expectedAnchor, position, 0, 0, false, false, null);
|
||||
}
|
||||
|
||||
openPopup("after_start", "topleft", "top", "left");
|
||||
openPopup("after_start", "topleft", "top", "left", "start");
|
||||
yield;
|
||||
openPopup("after_start", "bottomleft", "bottom", "left");
|
||||
openPopup("after_start", "bottomleft", "bottom", "left", "start");
|
||||
yield;
|
||||
openPopup("before_start", "topleft", "top", "left");
|
||||
openPopup("before_start", "topleft", "top", "left", "start");
|
||||
yield;
|
||||
openPopup("before_start", "bottomleft", "bottom", "left");
|
||||
openPopup("before_start", "bottomleft", "bottom", "left", "start");
|
||||
yield;
|
||||
openPopup("after_start", "middle", "top", "left");
|
||||
openPopup("after_start", "middle", "top", "left", "start");
|
||||
yield;
|
||||
openPopup("before_start", "middle", "bottom", "left");
|
||||
openPopup("before_start", "middle", "bottom", "left", "start");
|
||||
yield;
|
||||
|
||||
openPopup("after_start", "topright", "top", "right");
|
||||
openPopup("after_start", "topright", "top", "right", "end");
|
||||
yield;
|
||||
openPopup("after_start", "bottomright", "bottom", "right");
|
||||
openPopup("after_start", "bottomright", "bottom", "right", "end");
|
||||
yield;
|
||||
openPopup("before_start", "topright", "top", "right");
|
||||
openPopup("before_start", "topright", "top", "right", "end");
|
||||
yield;
|
||||
openPopup("before_start", "bottomright", "bottom", "right");
|
||||
openPopup("before_start", "bottomright", "bottom", "right", "end");
|
||||
yield;
|
||||
|
||||
openPopup("start_before", "topleft", "left", "top");
|
||||
openPopup("after_end", "middle", "top", "right", "end");
|
||||
yield;
|
||||
openPopup("start_before", "topright", "right", "top");
|
||||
yield;
|
||||
openPopup("end_before", "topleft", "left", "top");
|
||||
yield;
|
||||
openPopup("end_before", "topright", "right", "top");
|
||||
yield;
|
||||
openPopup("start_before", "middle", "right", "top");
|
||||
yield;
|
||||
openPopup("end_before", "middle", "left", "top");
|
||||
openPopup("before_end", "middle", "bottom", "right", "end");
|
||||
yield;
|
||||
|
||||
openPopup("start_before", "bottomleft", "left", "bottom");
|
||||
openPopup("start_before", "topleft", "left", "top", "start");
|
||||
yield;
|
||||
openPopup("start_before", "bottomright", "right", "bottom");
|
||||
openPopup("start_before", "topright", "right", "top", "start");
|
||||
yield;
|
||||
openPopup("end_before", "bottomleft", "left", "bottom");
|
||||
openPopup("end_before", "topleft", "left", "top", "start");
|
||||
yield;
|
||||
openPopup("end_before", "bottomright", "right", "bottom");
|
||||
openPopup("end_before", "topright", "right", "top", "start");
|
||||
yield;
|
||||
openPopup("start_before", "middle", "right", "top", "start");
|
||||
yield;
|
||||
openPopup("end_before", "middle", "left", "top", "start");
|
||||
yield;
|
||||
|
||||
openPopup("topcenter bottomleft", "bottomleft", "bottom", "center left");
|
||||
openPopup("start_before", "bottomleft", "left", "bottom", "end");
|
||||
yield;
|
||||
openPopup("bottomcenter topleft", "topleft", "top", "center left");
|
||||
openPopup("start_before", "bottomright", "right", "bottom", "end");
|
||||
yield;
|
||||
openPopup("topcenter bottomright", "bottomright", "bottom", "center right");
|
||||
openPopup("end_before", "bottomleft", "left", "bottom", "end");
|
||||
yield;
|
||||
openPopup("bottomcenter topright", "topright", "top", "center right");
|
||||
yield;
|
||||
openPopup("topcenter bottomleft", "middle", "bottom", "center left");
|
||||
yield;
|
||||
openPopup("bottomcenter topleft", "middle", "top", "center left");
|
||||
openPopup("end_before", "bottomright", "right", "bottom", "end");
|
||||
yield;
|
||||
|
||||
openPopup("leftcenter topright", "middle", "right", "center top");
|
||||
openPopup("start_after", "middle", "right", "bottom", "end");
|
||||
yield;
|
||||
openPopup("rightcenter bottomleft", "middle", "left", "center bottom");
|
||||
openPopup("end_after", "middle", "left", "bottom", "end");
|
||||
yield;
|
||||
|
||||
openPopup("topcenter bottomleft", "bottomleft", "bottom", "center left", "start");
|
||||
yield;
|
||||
openPopup("bottomcenter topleft", "topleft", "top", "center left", "start");
|
||||
yield;
|
||||
openPopup("topcenter bottomright", "bottomright", "bottom", "center right", "end");
|
||||
yield;
|
||||
openPopup("bottomcenter topright", "topright", "top", "center right", "end");
|
||||
yield;
|
||||
openPopup("topcenter bottomleft", "middle", "bottom", "center left", "start");
|
||||
yield;
|
||||
openPopup("bottomcenter topleft", "middle", "top", "center left", "start");
|
||||
yield;
|
||||
|
||||
openPopup("leftcenter topright", "middle", "right", "center top", "start");
|
||||
yield;
|
||||
openPopup("rightcenter bottomleft", "middle", "left", "center bottom", "end");
|
||||
yield;
|
||||
|
||||
/*
|
||||
XXXndeakin disable these parts of the test which often cause problems, see bug 626563
|
||||
|
||||
openPopup("after_start", frames[0].document.getElementById("input"), "top", "left");
|
||||
openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
|
||||
yield;
|
||||
|
||||
setScale(frames[0], 1.5);
|
||||
openPopup("after_start", frames[0].document.getElementById("input"), "top", "left");
|
||||
openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
|
||||
yield;
|
||||
|
||||
setScale(frames[0], 2.5);
|
||||
openPopup("before_start", frames[0].document.getElementById("input"), "bottom", "left");
|
||||
openPopup("before_start", frames[0].document.getElementById("input"), "bottom", "left", "start");
|
||||
yield;
|
||||
|
||||
setScale(frames[0], 1);
|
||||
*/
|
||||
|
||||
$("bigpanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null);
|
||||
$("bigpanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
|
||||
yield;
|
||||
|
||||
SimpleTest.finish();
|
||||
|
@ -221,6 +232,7 @@ function checkPanelPosition(panel)
|
|||
var arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
|
||||
is(arrow.getAttribute("side"), expectedSide, "panel arrow side");
|
||||
is(arrow.hidden, false, "panel hidden");
|
||||
is(arrow.parentNode.pack, expectedPack, "panel arrow pack");
|
||||
|
||||
panel.hidePopup();
|
||||
}
|
||||
|
|
|
@ -315,7 +315,7 @@
|
|||
</xul:box>
|
||||
</content>
|
||||
<implementation>
|
||||
<field name="_fadeTimer"/>
|
||||
<field name="_fadeTimer">null</field>
|
||||
</implementation>
|
||||
<handlers>
|
||||
<handler event="popupshowing">
|
||||
|
@ -383,10 +383,10 @@
|
|||
|
||||
// If the popup is on the left of the anchor.
|
||||
if (smallerTo(popupLeft, anchorLeft, epsilon) && smallerTo(popupRight, anchorRight, epsilon)) {
|
||||
pack = (popupLeft + popupRect.width / 2 < anchorLeft) ? "end" : "start";
|
||||
pack = "end";
|
||||
// If the popup is on the right of the anchor.
|
||||
} else if (smallerTo(anchorLeft, popupLeft, epsilon) && smallerTo(anchorRight, popupRight, epsilon)) {
|
||||
pack = (popupLeft + popupRect.width / 2 > anchorRight) ? "start" : "end";
|
||||
pack = "start"; //(popupLeft + popupRect.width / 2 > anchorRight) ? "start" : "end";
|
||||
// If the popup is not on the right nor on the left.
|
||||
// Basically, that means one is above the other and one is bigger
|
||||
// than the other.
|
||||
|
|
|
@ -127,4 +127,6 @@ ifdef ENABLE_TESTS
|
|||
TOOL_DIRS = test
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -37,7 +37,11 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mozilla/dom/CrashReporterChild.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#if defined(XP_WIN32)
|
||||
#ifdef WIN32_LEAN_AND_MEAN
|
||||
|
@ -112,6 +116,8 @@ using google_breakpad::CrashGenerationServer;
|
|||
using google_breakpad::ClientInfo;
|
||||
using mozilla::Mutex;
|
||||
using mozilla::MutexAutoLock;
|
||||
using mozilla::dom::CrashReporterChild;
|
||||
using mozilla::dom::PCrashReporterChild;
|
||||
|
||||
namespace CrashReporter {
|
||||
|
||||
|
@ -231,6 +237,10 @@ static const char* kSubprocessBlacklist[] = {
|
|||
"URL"
|
||||
};
|
||||
|
||||
// If annotations are attempted before the crash reporter is enabled,
|
||||
// they queue up here.
|
||||
class DelayedNote;
|
||||
nsTArray<nsAutoPtr<DelayedNote> >* gDelayedAnnotations;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
static cpu_type_t pref_cpu_types[2] = {
|
||||
|
@ -801,7 +811,7 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
|
|||
|
||||
bool GetEnabled()
|
||||
{
|
||||
return gExceptionHandler != nsnull && !gExceptionHandler->IsOutOfProcess();
|
||||
return gExceptionHandler != nsnull;
|
||||
}
|
||||
|
||||
bool GetMinidumpPath(nsAString& aPath)
|
||||
|
@ -1095,11 +1105,13 @@ static PLDHashOperator EnumerateEntries(const nsACString& key,
|
|||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
|
||||
// This function is miscompiled with MSVC 2005/2008 when PGO is on.
|
||||
#ifdef _MSC_VER
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
static nsresult
|
||||
EscapeAnnotation(const nsACString& key, const nsACString& data, nsCString& escapedData)
|
||||
{
|
||||
if (!GetEnabled())
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (DoFindInReadable(key, NS_LITERAL_CSTRING("=")) ||
|
||||
DoFindInReadable(key, NS_LITERAL_CSTRING("\n")))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
@ -1107,7 +1119,7 @@ nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
|
|||
if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCString escapedData(data);
|
||||
escapedData = data;
|
||||
|
||||
// escape backslashes
|
||||
ReplaceChar(escapedData, NS_LITERAL_CSTRING("\\"),
|
||||
|
@ -1115,8 +1127,67 @@ nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
|
|||
// escape newlines
|
||||
ReplaceChar(escapedData, NS_LITERAL_CSTRING("\n"),
|
||||
NS_LITERAL_CSTRING("\\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
nsresult rv = crashReporterAPIData_Hash->Put(key, escapedData);
|
||||
class DelayedNote
|
||||
{
|
||||
public:
|
||||
DelayedNote(const nsACString& aKey, const nsACString& aData)
|
||||
: mKey(aKey), mData(aData), mType(Annotation) {}
|
||||
|
||||
DelayedNote(const nsACString& aData)
|
||||
: mData(aData), mType(AppNote) {}
|
||||
|
||||
void Run()
|
||||
{
|
||||
if (mType == Annotation) {
|
||||
AnnotateCrashReport(mKey, mData);
|
||||
} else {
|
||||
AppendAppNotesToCrashReport(mData);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsCString mKey;
|
||||
nsCString mData;
|
||||
enum AnnotationType { Annotation, AppNote } mType;
|
||||
};
|
||||
|
||||
static void
|
||||
EnqueueDelayedNote(DelayedNote* aNote)
|
||||
{
|
||||
if (!gDelayedAnnotations) {
|
||||
gDelayedAnnotations = new nsTArray<nsAutoPtr<DelayedNote> >();
|
||||
}
|
||||
gDelayedAnnotations->AppendElement(aNote);
|
||||
}
|
||||
|
||||
nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
|
||||
{
|
||||
if (!GetEnabled())
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
nsCString escapedData;
|
||||
nsresult rv = EscapeAnnotation(key, data, escapedData);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
PCrashReporterChild* reporter = CrashReporterChild::GetCrashReporter();
|
||||
if (!reporter) {
|
||||
EnqueueDelayedNote(new DelayedNote(key, data));
|
||||
return NS_OK;
|
||||
}
|
||||
if (!reporter->SendAnnotateCrashReport(nsCString(key), escapedData))
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = crashReporterAPIData_Hash->Put(key, escapedData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// now rebuild the file contents
|
||||
|
@ -1135,6 +1206,26 @@ nsresult AppendAppNotesToCrashReport(const nsACString& data)
|
|||
if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
PCrashReporterChild* reporter = CrashReporterChild::GetCrashReporter();
|
||||
if (!reporter) {
|
||||
EnqueueDelayedNote(new DelayedNote(data));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Since we don't go through AnnotateCrashReport in the parent process,
|
||||
// we must ensure that the data is escaped and valid before the parent
|
||||
// sees it.
|
||||
nsCString escapedData;
|
||||
nsresult rv = EscapeAnnotation(NS_LITERAL_CSTRING("Notes"), data, escapedData);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (!reporter->SendAppendAppNotes(escapedData))
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
notesField->Append(data);
|
||||
return AnnotateCrashReport(NS_LITERAL_CSTRING("Notes"), *notesField);
|
||||
}
|
||||
|
@ -1874,7 +1965,7 @@ SetRemoteExceptionHandler(const nsACString& crashPipe)
|
|||
|
||||
gExceptionHandler = new google_breakpad::
|
||||
ExceptionHandler(L"",
|
||||
NULL, // no filter callback
|
||||
FPEFilter,
|
||||
NULL, // no minidump callback
|
||||
NULL, // no callback context
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
|
@ -1925,6 +2016,13 @@ SetRemoteExceptionHandler()
|
|||
true, // install signal handlers
|
||||
kMagicChildCrashReportFd);
|
||||
|
||||
if (gDelayedAnnotations) {
|
||||
for (PRUint32 i = 0; i < gDelayedAnnotations->Length(); i++) {
|
||||
gDelayedAnnotations->ElementAt(i)->Run();
|
||||
}
|
||||
delete gDelayedAnnotations;
|
||||
}
|
||||
|
||||
// we either do remote or nothing, no fallback to regular crash reporting
|
||||
return gExceptionHandler->IsOutOfProcess();
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ relativesrcdir = toolkit/crashreporter/test
|
|||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = crashreporter_test
|
||||
XPCSHELL_TESTS = unit
|
||||
XPCSHELL_TESTS = unit unit_ipc
|
||||
|
||||
LIBRARY_NAME = testcrasher
|
||||
NO_DIST_INSTALL = 1
|
||||
|
@ -95,4 +95,5 @@ endif
|
|||
|
||||
libs:: $(SHARED_LIBRARY) $(EXTRA_JS_MODULES)
|
||||
$(INSTALL) $^ $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/unit/
|
||||
$(INSTALL) $^ $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/unit_ipc/
|
||||
|
||||
|
|
|
@ -2,11 +2,19 @@
|
|||
let cwd = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
|
||||
let crashReporter =
|
||||
Components.classes["@mozilla.org/toolkit/crash-reporter;1"]
|
||||
.getService(Components.interfaces.nsICrashReporter);
|
||||
crashReporter.enabled = true;
|
||||
crashReporter.minidumpPath = cwd;
|
||||
|
||||
// the crash reporter is already enabled in content processes,
|
||||
// and setting the minidump path is not allowed
|
||||
let processType = Components.classes["@mozilla.org/xre/runtime;1"].
|
||||
getService(Components.interfaces.nsIXULRuntime).processType;
|
||||
if (processType == Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||
crashReporter.enabled = true;
|
||||
crashReporter.minidumpPath = cwd;
|
||||
}
|
||||
|
||||
let ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
|
|
@ -65,6 +65,11 @@ function do_crash(setup, callback, canReturnZero)
|
|||
do_check_neq(process.exitValue, 0);
|
||||
}
|
||||
|
||||
handleMinidump(callback);
|
||||
}
|
||||
|
||||
function handleMinidump(callback)
|
||||
{
|
||||
// find minidump
|
||||
let minidump = null;
|
||||
let en = do_get_cwd().directoryEntries;
|
||||
|
@ -101,6 +106,44 @@ function do_crash(setup, callback, canReturnZero)
|
|||
extrafile.remove(false);
|
||||
}
|
||||
|
||||
function do_content_crash(setup, callback)
|
||||
{
|
||||
do_load_child_test_harness();
|
||||
do_test_pending();
|
||||
|
||||
// Setting the minidump path won't work in the child, so we need to do
|
||||
// that here.
|
||||
let crashReporter =
|
||||
Components.classes["@mozilla.org/toolkit/crash-reporter;1"]
|
||||
.getService(Components.interfaces.nsICrashReporter);
|
||||
crashReporter.minidumpPath = do_get_cwd();
|
||||
|
||||
let headfile = do_get_file("../unit/crasher_subprocess_head.js");
|
||||
let tailfile = do_get_file("../unit/crasher_subprocess_tail.js");
|
||||
if (setup) {
|
||||
if (typeof(setup) == "function")
|
||||
// funky, but convenient
|
||||
setup = "("+setup.toSource()+")();";
|
||||
}
|
||||
|
||||
let handleCrash = function() {
|
||||
try {
|
||||
handleMinidump(callback);
|
||||
} catch (x) {
|
||||
do_report_unexpected_exception(x);
|
||||
}
|
||||
do_test_finished();
|
||||
};
|
||||
|
||||
sendCommand("load(\"" + headfile.path.replace(/\\/g, "/") + "\");", function()
|
||||
sendCommand(setup, function()
|
||||
sendCommand("load(\"" + tailfile.path.replace(/\\/g, "/") + "\");",
|
||||
function() do_execute_soon(handleCrash)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Utility functions for parsing .extra files
|
||||
function parseKeyValuePairs(text) {
|
||||
var lines = text.split('\n');
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
load("../unit/head_crashreporter.js");
|
||||
|
||||
function run_test()
|
||||
{
|
||||
if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) {
|
||||
dump("INFO | test_content_annotation.js | Can't test crashreporter in a non-libxul build.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try crashing with a pure virtual call
|
||||
do_content_crash(function() {
|
||||
crashType = CrashTestUtils.CRASH_RUNTIMEABORT;
|
||||
crashReporter.annotateCrashReport("TestKey", "TestValue");
|
||||
crashReporter.appendAppNotesToCrashReport("!!!foo!!!");
|
||||
},
|
||||
function(mdump, extra) {
|
||||
do_check_eq(extra.TestKey, "TestValue");
|
||||
do_check_true('StartupTime' in extra);
|
||||
do_check_true('ProcessType' in extra);
|
||||
do_check_neq(extra.Notes.indexOf("!!!foo!!!"), -1);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
head = head_crashreporter.js
|
||||
tail =
|
||||
|
||||
[test_content_annotation.js]
|
|
@ -361,7 +361,9 @@ XRE_InitChildProcess(int aArgc,
|
|||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
SetupErrorHandling(aArgv[0]);
|
||||
|
||||
#if defined(MOZ_CRASHREPORTER)
|
||||
if (aArgc < 1)
|
||||
return 1;
|
||||
|
@ -392,8 +394,6 @@ XRE_InitChildProcess(int aArgc,
|
|||
gArgv = aArgv;
|
||||
gArgc = aArgc;
|
||||
|
||||
SetupErrorHandling(aArgv[0]);
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK2)
|
||||
g_thread_init(NULL);
|
||||
#endif
|
||||
|
@ -712,16 +712,19 @@ XRE_ShutdownChildProcess()
|
|||
}
|
||||
|
||||
namespace {
|
||||
TestShellParent* gTestShellParent = nsnull;
|
||||
ContentParent* gContentParent; //long-lived, manually refcounted
|
||||
TestShellParent* GetOrCreateTestShellParent()
|
||||
{
|
||||
if (!gTestShellParent) {
|
||||
ContentParent* parent = ContentParent::GetNewOrUsed();
|
||||
NS_ENSURE_TRUE(parent, nsnull);
|
||||
gTestShellParent = parent->CreateTestShell();
|
||||
NS_ENSURE_TRUE(gTestShellParent, nsnull);
|
||||
if (!gContentParent) {
|
||||
NS_ADDREF(gContentParent = ContentParent::GetNewOrUsed());
|
||||
} else if (!gContentParent->IsAlive()) {
|
||||
return nsnull;
|
||||
}
|
||||
return gTestShellParent;
|
||||
TestShellParent* tsp = gContentParent->GetTestShellSingleton();
|
||||
if (!tsp) {
|
||||
tsp = gContentParent->CreateTestShell();
|
||||
}
|
||||
return tsp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,10 +763,16 @@ XRE_GetChildGlobalObject(JSContext* aCx, JSObject** aGlobalP)
|
|||
bool
|
||||
XRE_ShutdownTestShell()
|
||||
{
|
||||
if (!gTestShellParent)
|
||||
return true;
|
||||
return static_cast<ContentParent*>(gTestShellParent->Manager())->
|
||||
DestroyTestShell(gTestShellParent);
|
||||
if (!gContentParent) {
|
||||
return true;
|
||||
}
|
||||
bool ret = true;
|
||||
if (gContentParent->IsAlive()) {
|
||||
ret = gContentParent->DestroyTestShell(
|
||||
gContentParent->GetTestShellSingleton());
|
||||
}
|
||||
NS_RELEASE(gContentParent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MOZ_X11
|
||||
|
|
|
@ -38,9 +38,6 @@
|
|||
|
||||
#include "nsX11ErrorHandler.h"
|
||||
|
||||
#include "mozilla/plugins/PluginProcessChild.h"
|
||||
using mozilla::plugins::PluginProcessChild;
|
||||
|
||||
#include "prenv.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
|
@ -156,15 +153,9 @@ X11Error(Display *display, XErrorEvent *event) {
|
|||
#ifdef MOZ_CRASHREPORTER
|
||||
switch (XRE_GetProcessType()) {
|
||||
case GeckoProcessType_Default:
|
||||
CrashReporter::AppendAppNotesToCrashReport(notes);
|
||||
break;
|
||||
case GeckoProcessType_Plugin:
|
||||
if (CrashReporter::GetEnabled()) {
|
||||
// This is assuming that X operations are performed on the plugin
|
||||
// thread. If plugins are using X on another thread, then we'll need to
|
||||
// handle that differently.
|
||||
PluginProcessChild::AppendNotesToCrashReport(notes);
|
||||
}
|
||||
case GeckoProcessType_Content:
|
||||
CrashReporter::AppendAppNotesToCrashReport(notes);
|
||||
break;
|
||||
default:
|
||||
; // crash report notes not supported.
|
||||
|
|
|
@ -481,23 +481,10 @@ protected:
|
|||
bool mKeyPressDispatched;
|
||||
// Whether keypress event was consumed by web contents or chrome contents.
|
||||
bool mKeyPressHandled;
|
||||
// Whether the key event causes other key events via IME or something.
|
||||
bool mCausedOtherKeyEvents;
|
||||
|
||||
KeyEventState(NSEvent* aNativeKeyEvent) : mKeyEvent(nsnull)
|
||||
KeyEventState() : mKeyEvent(nsnull)
|
||||
{
|
||||
Clear();
|
||||
Set(aNativeKeyEvent);
|
||||
}
|
||||
|
||||
KeyEventState(const KeyEventState &aOther) : mKeyEvent(nsnull)
|
||||
{
|
||||
Clear();
|
||||
mKeyEvent = [aOther.mKeyEvent retain];
|
||||
mKeyDownHandled = aOther.mKeyDownHandled;
|
||||
mKeyPressDispatched = aOther.mKeyPressDispatched;
|
||||
mKeyPressHandled = aOther.mKeyPressHandled;
|
||||
mCausedOtherKeyEvents = aOther.mCausedOtherKeyEvents;
|
||||
}
|
||||
|
||||
~KeyEventState()
|
||||
|
@ -521,18 +508,12 @@ protected:
|
|||
mKeyDownHandled = false;
|
||||
mKeyPressDispatched = false;
|
||||
mKeyPressHandled = false;
|
||||
mCausedOtherKeyEvents = false;
|
||||
}
|
||||
|
||||
bool KeyDownOrPressHandled()
|
||||
{
|
||||
return mKeyDownHandled || mKeyPressHandled;
|
||||
}
|
||||
|
||||
protected:
|
||||
KeyEventState()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -548,46 +529,15 @@ protected:
|
|||
|
||||
~AutoKeyEventStateCleaner()
|
||||
{
|
||||
NS_ASSERTION(mHandler->mCurrentKeyEvents.Length() > 0,
|
||||
"The key event was removed by manually?");
|
||||
mHandler->mCurrentKeyEvents.RemoveElementAt(0);
|
||||
mHandler->mCurrentKeyEvent.Clear();
|
||||
}
|
||||
private:
|
||||
nsRefPtr<TextInputHandlerBase> mHandler;
|
||||
TextInputHandlerBase* mHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
* mCurrentKeyEvents stores all key events which are being processed.
|
||||
* When we call interpretKeyEvents, IME may generate other key events.
|
||||
* mCurrentKeyEvents[0] is the latest key event.
|
||||
*/
|
||||
nsTArray<KeyEventState> mCurrentKeyEvents;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent)
|
||||
{
|
||||
PRUint32 nestCount = mCurrentKeyEvents.Length();
|
||||
for (PRUint32 i = 0; i < nestCount; i++) {
|
||||
// When the key event is caused by another key event, all key events
|
||||
// which are being handled should be marked as "consumed".
|
||||
mCurrentKeyEvents[i].mCausedOtherKeyEvents = true;
|
||||
}
|
||||
KeyEventState keyEventState(aNativeKeyEvent);
|
||||
return mCurrentKeyEvents.InsertElementAt(0, keyEventState);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetCurrentKeyEvent() returns current processing key event.
|
||||
*/
|
||||
KeyEventState* GetCurrentKeyEvent()
|
||||
{
|
||||
if (mCurrentKeyEvents.Length() == 0) {
|
||||
return nsnull;
|
||||
}
|
||||
return &mCurrentKeyEvents[0];
|
||||
}
|
||||
// XXX If keydown event was nested, the key event is overwritten by newer
|
||||
// event. This is wrong behavior. Some IMEs are making such situation.
|
||||
KeyEventState mCurrentKeyEvent;
|
||||
|
||||
/**
|
||||
* IsPrintableChar() checks whether the unicode character is
|
||||
|
@ -1169,8 +1119,7 @@ public:
|
|||
*/
|
||||
bool KeyPressWasHandled()
|
||||
{
|
||||
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
|
||||
return currentKeyEvent && currentKeyEvent->mKeyPressHandled;
|
||||
return mCurrentKeyEvent.mKeyPressHandled;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -997,7 +997,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
|
||||
nsRefPtr<nsChildView> kungFuDeathGrip(mWidget);
|
||||
|
||||
KeyEventState* currentKeyEvent = PushKeyEvent(aNativeEvent);
|
||||
mCurrentKeyEvent.Set(aNativeEvent);
|
||||
AutoKeyEventStateCleaner remover(this);
|
||||
|
||||
BOOL nonDeadKeyPress = [[aNativeEvent characters] length] > 0;
|
||||
|
@ -1015,12 +1015,12 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
}
|
||||
#endif // #ifndef NP_NO_CARBON
|
||||
|
||||
currentKeyEvent->mKeyDownHandled = DispatchEvent(keydownEvent);
|
||||
mCurrentKeyEvent.mKeyDownHandled = DispatchEvent(keydownEvent);
|
||||
if (Destroyed()) {
|
||||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::HandleKeyDownEvent, "
|
||||
"widget was destroyed by keydown event", this));
|
||||
return currentKeyEvent->KeyDownOrPressHandled();
|
||||
return mCurrentKeyEvent.KeyDownOrPressHandled();
|
||||
}
|
||||
|
||||
// The key down event may have shifted the focus, in which
|
||||
|
@ -1030,7 +1030,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::HandleKeyDownEvent, "
|
||||
"view lost focus by keydown event", this));
|
||||
return currentKeyEvent->KeyDownOrPressHandled();
|
||||
return mCurrentKeyEvent.KeyDownOrPressHandled();
|
||||
}
|
||||
|
||||
// If this is the context menu key command, send a context menu key event.
|
||||
|
@ -1052,7 +1052,31 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
Destroyed() ? " and widget was destroyed" : ""));
|
||||
[mView maybeInitContextMenuTracking];
|
||||
// Bail, there is nothing else to do here.
|
||||
return (cmEventHandled || currentKeyEvent->KeyDownOrPressHandled());
|
||||
return (cmEventHandled || mCurrentKeyEvent.KeyDownOrPressHandled());
|
||||
}
|
||||
|
||||
nsKeyEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
|
||||
InitKeyEvent(aNativeEvent, keypressEvent);
|
||||
|
||||
// if this is a non-letter keypress, or the control key is down,
|
||||
// dispatch the keydown to gecko, so that we trap delete,
|
||||
// control-letter combinations etc before Cocoa tries to use
|
||||
// them for keybindings.
|
||||
// XXX This is wrong. IME may be handle the non-letter keypress event as
|
||||
// its owning shortcut key. See bug 477291.
|
||||
if ((!keypressEvent.isChar || keypressEvent.isControl) &&
|
||||
!IsIMEComposing()) {
|
||||
if (mCurrentKeyEvent.mKeyDownHandled) {
|
||||
keypressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
|
||||
}
|
||||
mCurrentKeyEvent.mKeyPressHandled = DispatchEvent(keypressEvent);
|
||||
mCurrentKeyEvent.mKeyPressDispatched = true;
|
||||
if (Destroyed()) {
|
||||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::HandleKeyDownEvent, "
|
||||
"widget was destroyed by keypress event", this));
|
||||
return mCurrentKeyEvent.KeyDownOrPressHandled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1098,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::HandleKeyDownEvent, widget was destroyed",
|
||||
this));
|
||||
return currentKeyEvent->KeyDownOrPressHandled();
|
||||
return mCurrentKeyEvent.KeyDownOrPressHandled();
|
||||
}
|
||||
|
||||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
|
@ -1082,7 +1106,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
"IsIMEComposing()=%s",
|
||||
this, TrueOrFalse(wasComposing), TrueOrFalse(IsIMEComposing())));
|
||||
|
||||
if (!currentKeyEvent->mKeyPressDispatched && nonDeadKeyPress &&
|
||||
if (!mCurrentKeyEvent.mKeyPressDispatched && nonDeadKeyPress &&
|
||||
!wasComposing && !IsIMEComposing()) {
|
||||
nsKeyEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
|
||||
InitKeyEvent(aNativeEvent, keypressEvent);
|
||||
|
@ -1100,11 +1124,10 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
// our default action for this key.
|
||||
if (!(interpretKeyEventsCalled &&
|
||||
IsNormalCharInputtingEvent(keypressEvent))) {
|
||||
if (currentKeyEvent->mKeyDownHandled ||
|
||||
currentKeyEvent->mCausedOtherKeyEvents) {
|
||||
if (mCurrentKeyEvent.mKeyDownHandled) {
|
||||
keypressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
|
||||
}
|
||||
currentKeyEvent->mKeyPressHandled = DispatchEvent(keypressEvent);
|
||||
mCurrentKeyEvent.mKeyPressHandled = DispatchEvent(keypressEvent);
|
||||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::HandleKeyDownEvent, keypress event dispatched",
|
||||
this));
|
||||
|
@ -1116,9 +1139,9 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
|
|||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::HandleKeyDownEvent, "
|
||||
"keydown handled=%s, keypress handled=%s",
|
||||
this, TrueOrFalse(currentKeyEvent->mKeyDownHandled),
|
||||
TrueOrFalse(currentKeyEvent->mKeyPressHandled)));
|
||||
return currentKeyEvent->KeyDownOrPressHandled();
|
||||
this, TrueOrFalse(mCurrentKeyEvent.mKeyDownHandled),
|
||||
TrueOrFalse(mCurrentKeyEvent.mKeyPressHandled)));
|
||||
return mCurrentKeyEvent.KeyDownOrPressHandled();
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
|
||||
}
|
||||
|
@ -1289,17 +1312,13 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
|
|||
return;
|
||||
}
|
||||
|
||||
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
|
||||
|
||||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::InsertText, aAttrString=\"%s\", "
|
||||
"IsIMEComposing()=%s, IgnoreIMEComposition()=%s, "
|
||||
"keyevent=%p, keypressDispatched=%s",
|
||||
this, GetCharacters([aAttrString string]), TrueOrFalse(IsIMEComposing()),
|
||||
TrueOrFalse(IgnoreIMEComposition()),
|
||||
currentKeyEvent ? currentKeyEvent->mKeyEvent : nsnull,
|
||||
currentKeyEvent ?
|
||||
TrueOrFalse(currentKeyEvent->mKeyPressDispatched) : "N/A"));
|
||||
TrueOrFalse(IgnoreIMEComposition()), mCurrentKeyEvent.mKeyEvent,
|
||||
TrueOrFalse(mCurrentKeyEvent.mKeyPressDispatched)));
|
||||
|
||||
if (IgnoreIMEComposition()) {
|
||||
return;
|
||||
|
@ -1318,7 +1337,7 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
|
|||
|
||||
// Don't let the same event be fired twice when hitting
|
||||
// enter/return! (Bug 420502)
|
||||
if (currentKeyEvent && currentKeyEvent->mKeyPressDispatched) {
|
||||
if (mCurrentKeyEvent.mKeyPressDispatched) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1340,8 +1359,8 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
|
|||
EventRecord carbonEvent;
|
||||
#endif // #ifndef NP_NO_CARBON
|
||||
|
||||
if (currentKeyEvent) {
|
||||
NSEvent* keyEvent = currentKeyEvent->mKeyEvent;
|
||||
if (mCurrentKeyEvent.mKeyEvent) {
|
||||
NSEvent* keyEvent = mCurrentKeyEvent.mKeyEvent;
|
||||
|
||||
// XXX The ASCII characters inputting mode of egbridge (Japanese IME)
|
||||
// might send the keyDown event with wrong keyboard layout if other
|
||||
|
@ -1354,7 +1373,7 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
|
|||
}
|
||||
#endif // #ifndef NP_NO_CARBON
|
||||
|
||||
if (currentKeyEvent->mKeyDownHandled) {
|
||||
if (mCurrentKeyEvent.mKeyDownHandled) {
|
||||
keypressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
|
||||
}
|
||||
|
||||
|
@ -1381,9 +1400,9 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
|
|||
|
||||
// Note: mWidget might have become null here. Don't count on it from here on.
|
||||
|
||||
if (currentKeyEvent) {
|
||||
currentKeyEvent->mKeyPressHandled = keyPressHandled;
|
||||
currentKeyEvent->mKeyPressDispatched = true;
|
||||
if (mCurrentKeyEvent.mKeyEvent) {
|
||||
mCurrentKeyEvent.mKeyPressHandled = keyPressHandled;
|
||||
mCurrentKeyEvent.mKeyPressDispatched = true;
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
|
@ -1392,38 +1411,13 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
|
|||
bool
|
||||
TextInputHandler::DoCommandBySelector(const char* aSelector)
|
||||
{
|
||||
nsRefPtr<nsChildView> kungFuDeathGrip(mWidget);
|
||||
|
||||
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
|
||||
|
||||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::DoCommandBySelector, aSelector=\"%s\", "
|
||||
"Destroyed()=%s, keypressHandled=%s, causedOtherKeyEvents=%s",
|
||||
"Destroyed()=%s, keypressHandled=%s",
|
||||
this, aSelector ? aSelector : "", TrueOrFalse(Destroyed()),
|
||||
currentKeyEvent ?
|
||||
TrueOrFalse(currentKeyEvent->mKeyPressHandled) : "N/A",
|
||||
currentKeyEvent ?
|
||||
TrueOrFalse(currentKeyEvent->mCausedOtherKeyEvents) : "N/A"));
|
||||
TrueOrFalse(mCurrentKeyEvent.mKeyPressHandled)));
|
||||
|
||||
if (currentKeyEvent && !currentKeyEvent->mKeyPressDispatched) {
|
||||
nsKeyEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
|
||||
InitKeyEvent(currentKeyEvent->mKeyEvent, keypressEvent);
|
||||
if (currentKeyEvent->mKeyDownHandled ||
|
||||
currentKeyEvent->mCausedOtherKeyEvents) {
|
||||
keypressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
|
||||
}
|
||||
currentKeyEvent->mKeyPressHandled = DispatchEvent(keypressEvent);
|
||||
currentKeyEvent->mKeyPressDispatched = true;
|
||||
PR_LOG(gLog, PR_LOG_ALWAYS,
|
||||
("%p TextInputHandler::DoCommandBySelector, keypress event "
|
||||
"dispatched, Destroyed()=%s, keypressHandled=%s",
|
||||
this, TrueOrFalse(Destroyed()),
|
||||
TrueOrFalse(currentKeyEvent->mKeyPressHandled)));
|
||||
}
|
||||
|
||||
return !Destroyed() && currentKeyEvent &&
|
||||
(currentKeyEvent->mKeyPressHandled ||
|
||||
currentKeyEvent->mCausedOtherKeyEvents);
|
||||
return !Destroyed() && mCurrentKeyEvent.mKeyPressHandled;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -373,17 +373,18 @@ TaskbarPreview::GetWindowHook() {
|
|||
|
||||
void
|
||||
TaskbarPreview::EnableCustomDrawing(HWND aHWND, bool aEnable) {
|
||||
BOOL enabled = aEnable;
|
||||
nsUXThemeData::dwmSetWindowAttributePtr(
|
||||
aHWND,
|
||||
DWMWA_FORCE_ICONIC_REPRESENTATION,
|
||||
&aEnable,
|
||||
sizeof(aEnable));
|
||||
&enabled,
|
||||
sizeof(enabled));
|
||||
|
||||
nsUXThemeData::dwmSetWindowAttributePtr(
|
||||
aHWND,
|
||||
DWMWA_HAS_ICONIC_BITMAP,
|
||||
&aEnable,
|
||||
sizeof(aEnable));
|
||||
&enabled,
|
||||
sizeof(enabled));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -434,6 +434,8 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT
|
|||
static CLIPFORMAT fileDescriptorFlavorA = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORA );
|
||||
static CLIPFORMAT fileDescriptorFlavorW = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORW );
|
||||
static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat( CFSTR_FILECONTENTS );
|
||||
static CLIPFORMAT preferredDropEffect = ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
|
||||
|
||||
switch (stm.tymed) {
|
||||
case TYMED_HGLOBAL:
|
||||
{
|
||||
|
@ -537,9 +539,17 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT
|
|||
// do that in FindPlatformHTML(). For now, return the allocLen. This
|
||||
// case is mostly to ensure we don't try to call strlen on the buffer.
|
||||
*aLen = allocLen;
|
||||
} else if (fe.cfFormat == preferredDropEffect) {
|
||||
// As per the MSDN doc entitled: "Shell Clipboard Formats"
|
||||
// CFSTR_PREFERREDDROPEFFECT should return a DWORD
|
||||
// Reference: http://msdn.microsoft.com/en-us/library/bb776902(v=vs.85).aspx
|
||||
NS_ASSERTION(allocLen == sizeof(DWORD),
|
||||
"CFSTR_PREFERREDDROPEFFECT should return a DWORD");
|
||||
*aLen = allocLen;
|
||||
} else {
|
||||
*aLen = nsCRT::strlen(reinterpret_cast<PRUnichar*>(*aData)) *
|
||||
sizeof(PRUnichar);
|
||||
}
|
||||
else
|
||||
*aLen = nsCRT::strlen(reinterpret_cast<PRUnichar*>(*aData)) * sizeof(PRUnichar);
|
||||
result = NS_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ static POINTL gDragLastPoint;
|
|||
*/
|
||||
nsNativeDragTarget::nsNativeDragTarget(nsIWidget * aWnd)
|
||||
: m_cRef(0),
|
||||
mEffectsAllowed(DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK),
|
||||
mEffectsAllowed(DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK),
|
||||
mEffectsPreferred(DROPEFFECT_NONE),
|
||||
mTookOwnRef(PR_FALSE), mWindow(aWnd), mDropTargetHelper(nsnull)
|
||||
{
|
||||
mHWnd = (HWND)mWindow->GetNativeData(NS_NATIVE_WINDOW);
|
||||
|
@ -127,44 +128,52 @@ void
|
|||
nsNativeDragTarget::GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect,
|
||||
PRUint32 * aGeckoAction)
|
||||
{
|
||||
// If a window is disabled or a modal window is on top of
|
||||
// it (which implies it is disabled), then we should not allow dropping.
|
||||
// If a window is disabled or a modal window is on top of it
|
||||
// (which implies it is disabled), then we should not allow dropping.
|
||||
bool isEnabled;
|
||||
if (NS_SUCCEEDED(mWindow->IsEnabled(&isEnabled)) && !isEnabled) {
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_NONE;
|
||||
return;
|
||||
}
|
||||
// Only a single effect should be specified outgoing for the parameter pdwEffect.
|
||||
// When Shift and Control are pressed, we should specify a LINK effect.
|
||||
else if (!mMovePreferred && (grfKeyState & MK_CONTROL) &&
|
||||
(grfKeyState & MK_SHIFT) && (mEffectsAllowed & DROPEFFECT_LINK)) {
|
||||
*pdwEffect = DROPEFFECT_LINK;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
|
||||
|
||||
// If the user explicitly uses a modifier key, they want the associated action
|
||||
// Shift + Control -> LINK, Shift -> MOVE, Ctrl -> COPY
|
||||
DWORD desiredEffect = DROPEFFECT_NONE;
|
||||
if ((grfKeyState & MK_CONTROL) && (grfKeyState & MK_SHIFT)) {
|
||||
desiredEffect = DROPEFFECT_LINK;
|
||||
} else if (grfKeyState & MK_SHIFT) {
|
||||
desiredEffect = DROPEFFECT_MOVE;
|
||||
} else if (grfKeyState & MK_CONTROL) {
|
||||
desiredEffect = DROPEFFECT_COPY;
|
||||
}
|
||||
// When Shift is pressed we should specify a MOVE effect.
|
||||
else if ((mEffectsAllowed & DROPEFFECT_MOVE) &&
|
||||
(mMovePreferred || (grfKeyState & MK_SHIFT))) {
|
||||
|
||||
// Determine the desired effect from what is allowed and preferred.
|
||||
if (!(desiredEffect &= mEffectsAllowed)) {
|
||||
// No modifier key effect is set which is also allowed, check
|
||||
// the preference of the data.
|
||||
desiredEffect = mEffectsPreferred & mEffectsAllowed;
|
||||
if (!desiredEffect) {
|
||||
// No preference is set, so just fall back to the allowed effect itself
|
||||
desiredEffect = mEffectsAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we should specify the first available effect
|
||||
// from MOVE, COPY, or LINK.
|
||||
if (desiredEffect & DROPEFFECT_MOVE) {
|
||||
*pdwEffect = DROPEFFECT_MOVE;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
|
||||
}
|
||||
// When Control is pressed we should specify a COPY effect.
|
||||
else if ((mEffectsAllowed & DROPEFFECT_COPY) && (grfKeyState & MK_CONTROL)) {
|
||||
} else if (desiredEffect & DROPEFFECT_COPY) {
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
|
||||
}
|
||||
// Otherwise we should specify the first available effect from MOVE, COPY, or LINK.
|
||||
else if (mEffectsAllowed & DROPEFFECT_MOVE) {
|
||||
*pdwEffect = DROPEFFECT_MOVE;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
|
||||
}
|
||||
else if (mEffectsAllowed & DROPEFFECT_COPY) {
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
|
||||
}
|
||||
else if (mEffectsAllowed & DROPEFFECT_LINK) {
|
||||
} else if (desiredEffect & DROPEFFECT_LINK) {
|
||||
*pdwEffect = DROPEFFECT_LINK;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
|
||||
}
|
||||
} else {
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
|
@ -275,15 +284,11 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
|
|||
nsresult loadResult = nsClipboard::GetNativeDataOffClipboard(
|
||||
pIDataSource, 0, ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), nsnull, &tempOutData, &tempDataLen);
|
||||
if (NS_SUCCEEDED(loadResult) && tempOutData) {
|
||||
NS_ASSERTION(tempDataLen == 2, "Expected word size");
|
||||
WORD preferredEffect = *((WORD*)tempOutData);
|
||||
|
||||
// Mask effect coming from function call with effect preferred by the source.
|
||||
mMovePreferred = (preferredEffect & DROPEFFECT_MOVE) != 0;
|
||||
|
||||
mEffectsPreferred = *((DWORD*)tempOutData);
|
||||
nsMemory::Free(tempOutData);
|
||||
} else {
|
||||
mMovePreferred = PR_FALSE;
|
||||
// We have no preference if we can't obtain it
|
||||
mEffectsPreferred = DROPEFFECT_NONE;
|
||||
}
|
||||
|
||||
// Set the native data object into drag service
|
||||
|
|
|
@ -113,7 +113,7 @@ protected:
|
|||
ULONG m_cRef; // reference count
|
||||
HWND mHWnd;
|
||||
DWORD mEffectsAllowed;
|
||||
bool mMovePreferred;
|
||||
DWORD mEffectsPreferred;
|
||||
bool mTookOwnRef;
|
||||
|
||||
// Gecko Stuff
|
||||
|
|
Загрузка…
Ссылка в новой задаче