mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
commit
1ee741e692
@ -24,7 +24,7 @@ ActivitiesDialog.prototype = {
|
||||
|
||||
let choices = [];
|
||||
activity.list.forEach(function(item) {
|
||||
choices.push({ title: item.title, icon: item.icon });
|
||||
choices.push({ manifest: item.manifest, icon: item.icon });
|
||||
});
|
||||
|
||||
|
||||
|
@ -773,6 +773,11 @@ DownloadsDataCtor.prototype = {
|
||||
ensurePersistentDataLoaded:
|
||||
function DD_ensurePersistentDataLoaded(aActiveOnly)
|
||||
{
|
||||
if (this == PrivateDownloadsData) {
|
||||
Cu.reportError("ensurePersistentDataLoaded should not be called on PrivateDownloadsData");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._pendingStatement) {
|
||||
// We are already in the process of reloading all downloads.
|
||||
return;
|
||||
@ -787,9 +792,7 @@ DownloadsDataCtor.prototype = {
|
||||
|
||||
// Reload the list using the Download Manager service. The list is
|
||||
// returned in no particular order.
|
||||
let downloads = this._isPrivate ?
|
||||
Services.downloads.activePrivateDownloads :
|
||||
Services.downloads.activeDownloads;
|
||||
let downloads = Services.downloads.activeDownloads;
|
||||
while (downloads.hasMoreElements()) {
|
||||
let download = downloads.getNext().QueryInterface(Ci.nsIDownload);
|
||||
this._getOrAddDataItem(download, true);
|
||||
@ -807,9 +810,7 @@ DownloadsDataCtor.prototype = {
|
||||
// columns are read in the _initFromDataRow method of DownloadsDataItem.
|
||||
// Order by descending download identifier so that the most recent
|
||||
// downloads are notified first to the listening views.
|
||||
let dbConnection = this._isPrivate ?
|
||||
Services.downloads.privateDBConnection :
|
||||
Services.downloads.DBConnection;
|
||||
let dbConnection = Services.downloads.DBConnection;
|
||||
let statement = dbConnection.createAsyncStatement(
|
||||
"SELECT guid, target, name, source, referrer, state, "
|
||||
+ "startTime, endTime, currBytes, maxBytes "
|
||||
|
@ -336,8 +336,8 @@ interface nsIFrameScriptLoader : nsISupports
|
||||
void removeDelayedFrameScript(in AString aURL);
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(5f552699-01a2-4f17-833b-ddb3fa0d98b2)]
|
||||
interface nsIPermissionChecker : nsISupports
|
||||
[scriptable, builtinclass, uuid(e2ccdade-4c16-11e2-9ae0-23151c6d6e1d)]
|
||||
interface nsIProcessChecker : nsISupports
|
||||
{
|
||||
|
||||
/**
|
||||
@ -361,4 +361,25 @@ interface nsIPermissionChecker : nsISupports
|
||||
*/
|
||||
boolean assertPermission(in DOMString aPermission);
|
||||
|
||||
/**
|
||||
* Return true iff the "remote" process has |aManifestURL|. This is
|
||||
* intended to be used by JS implementations of cross-process DOM
|
||||
* APIs, like so
|
||||
*
|
||||
* recvFooRequest: function(message) {
|
||||
* if (!message.target.assertContainApp("foo")) {
|
||||
* return false;
|
||||
* }
|
||||
* // service foo request
|
||||
*
|
||||
* This interface only returns meaningful data when our content is
|
||||
* in a separate process. If it shares the same OS process as us,
|
||||
* then applying this manifest URL check doesn't add any security,
|
||||
* though it doesn't hurt anything either.
|
||||
*
|
||||
* Note: If the remote content process does *not* contain |aManifestURL|,
|
||||
* it will be killed as a precaution.
|
||||
*/
|
||||
boolean assertContainApp(in DOMString aManifestURL);
|
||||
|
||||
};
|
||||
|
@ -77,7 +77,7 @@
|
||||
|
||||
#include "Layers.h"
|
||||
|
||||
#include "AppProcessPermissions.h"
|
||||
#include "AppProcessChecker.h"
|
||||
#include "ContentParent.h"
|
||||
#include "TabParent.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
@ -2314,6 +2314,13 @@ nsFrameLoader::CheckPermission(const nsAString& aPermission)
|
||||
NS_ConvertUTF16toUTF8(aPermission).get());
|
||||
}
|
||||
|
||||
bool
|
||||
nsFrameLoader::CheckManifestURL(const nsAString& aManifestURL)
|
||||
{
|
||||
return AssertAppProcessManifestURL(GetRemoteBrowser(),
|
||||
NS_ConvertUTF16toUTF8(aManifestURL).get());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::GetMessageManager(nsIMessageSender** aManager)
|
||||
{
|
||||
@ -2550,6 +2557,12 @@ nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
|
||||
void
|
||||
nsFrameLoader::ResetPermissionManagerStatus()
|
||||
{
|
||||
// The resetting of the permissions status can run only
|
||||
// in the main process.
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Finding the new app Id:
|
||||
// . first we check if the owner is an app frame
|
||||
// . second, we check if the owner is a browser frame
|
||||
|
@ -189,7 +189,7 @@ public:
|
||||
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
|
||||
const mozilla::dom::StructuredCloneData& aData);
|
||||
virtual bool CheckPermission(const nsAString& aPermission);
|
||||
|
||||
virtual bool CheckManifestURL(const nsAString& aManifestURL);
|
||||
|
||||
/**
|
||||
* Called from the layout frame associated with this frame loader;
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "nsFrameMessageManager.h"
|
||||
|
||||
#include "AppProcessPermissions.h"
|
||||
#include "AppProcessChecker.h"
|
||||
#include "ContentChild.h"
|
||||
#include "ContentParent.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -107,8 +107,8 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFrameScriptLoader,
|
||||
mChrome && !mIsProcessManager)
|
||||
|
||||
/* Message senders in the chrome process support nsIPermissionChecker. */
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPermissionChecker,
|
||||
/* Message senders in the chrome process support nsIProcessChecker. */
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIProcessChecker,
|
||||
mChrome && !mIsBroadcaster)
|
||||
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageBroadcaster,
|
||||
@ -423,12 +423,14 @@ nsFrameMessageManager::Atob(const nsAString& aAsciiString,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIPermissionChecker
|
||||
// nsIProcessChecker
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::AssertPermission(const nsAString& aPermission, bool* aHasPermission)
|
||||
nsresult
|
||||
nsFrameMessageManager::AssertProcessInternal(ProcessCheckerType aType,
|
||||
const nsAString& aCapability,
|
||||
bool* aValid)
|
||||
{
|
||||
*aHasPermission = false;
|
||||
*aValid = false;
|
||||
|
||||
// This API is only supported for message senders in the chrome process.
|
||||
if (!mChrome || mIsBroadcaster) {
|
||||
@ -437,10 +439,37 @@ nsFrameMessageManager::AssertPermission(const nsAString& aPermission, bool* aHas
|
||||
if (!mCallback) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
*aHasPermission = mCallback->CheckPermission(aPermission);
|
||||
switch (aType) {
|
||||
case PROCESS_CHECKER_PERMISSION:
|
||||
*aValid = mCallback->CheckPermission(aCapability);
|
||||
break;
|
||||
case PROCESS_CHECKER_MANIFEST_URL:
|
||||
*aValid = mCallback->CheckManifestURL(aCapability);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::AssertPermission(const nsAString& aPermission,
|
||||
bool* aHasPermission)
|
||||
{
|
||||
return AssertProcessInternal(PROCESS_CHECKER_PERMISSION,
|
||||
aPermission,
|
||||
aHasPermission);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::AssertContainApp(const nsAString& aManifestURL,
|
||||
bool* aHasManifestURL)
|
||||
{
|
||||
return AssertProcessInternal(PROCESS_CHECKER_MANIFEST_URL,
|
||||
aManifestURL,
|
||||
aHasManifestURL);
|
||||
}
|
||||
|
||||
class MMListenerRemover
|
||||
{
|
||||
public:
|
||||
@ -1100,6 +1129,11 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckManifestURL(const nsAString& aManifestURL)
|
||||
{
|
||||
// In a single-process scenario, the child always has all capabilities.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -66,6 +66,11 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool CheckManifestURL(const nsAString& aManifestURL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
@ -86,7 +91,7 @@ struct nsMessageListenerInfo
|
||||
class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
|
||||
public nsIMessageBroadcaster,
|
||||
public nsIFrameScriptLoader,
|
||||
public nsIPermissionChecker
|
||||
public nsIProcessChecker
|
||||
{
|
||||
typedef mozilla::dom::StructuredCloneData StructuredCloneData;
|
||||
public:
|
||||
@ -152,7 +157,7 @@ public:
|
||||
NS_DECL_NSISYNCMESSAGESENDER
|
||||
NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
|
||||
NS_DECL_NSIFRAMESCRIPTLOADER
|
||||
NS_DECL_NSIPERMISSIONCHECKER
|
||||
NS_DECL_NSIPROCESSCHECKER
|
||||
|
||||
static nsFrameMessageManager*
|
||||
NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
|
||||
@ -226,6 +231,14 @@ public:
|
||||
static nsFrameMessageManager* sChildProcessManager;
|
||||
static nsFrameMessageManager* sSameProcessParentManager;
|
||||
static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
|
||||
private:
|
||||
enum ProcessCheckerType {
|
||||
PROCESS_CHECKER_PERMISSION,
|
||||
PROCESS_CHECKER_MANIFEST_URL
|
||||
};
|
||||
nsresult AssertProcessInternal(ProcessCheckerType aType,
|
||||
const nsAString& aCapability,
|
||||
bool* aValid);
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for the nsIPermissionChecker part of Message Managers</title>
|
||||
<title>Test for the nsIProcessChecker part of Message Managers</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
@ -16,7 +16,9 @@
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(SharedList)
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(OList)
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(DList)
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(UList)
|
||||
DOMCI_DATA(HTMLOListElement, mozilla::dom::HTMLSharedListElement)
|
||||
DOMCI_DATA(HTMLDListElement, mozilla::dom::HTMLSharedListElement)
|
||||
DOMCI_DATA(HTMLUListElement, mozilla::dom::HTMLSharedListElement)
|
||||
@ -62,7 +64,9 @@ NS_INTERFACE_TABLE_HEAD(HTMLSharedListElement)
|
||||
NS_HTML_CONTENT_INTERFACE_MAP_END
|
||||
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLSharedListElement)
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLOListElement)
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLDListElement)
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLUListElement)
|
||||
|
||||
|
||||
NS_IMPL_BOOL_ATTR(HTMLSharedListElement, Compact, compact)
|
||||
|
@ -55,7 +55,6 @@ public:
|
||||
nsAttrValue& aResult);
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
virtual nsXPCClassInfo* GetClassInfo()
|
||||
{
|
||||
return static_cast<nsXPCClassInfo*>(GetClassInfoInternal());
|
||||
@ -99,10 +98,20 @@ public:
|
||||
{
|
||||
SetHTMLBoolAttr(nsGkAtoms::compact, aCompact, rv);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
|
||||
bool *aTriedToWrap) MOZ_OVERRIDE = 0;
|
||||
};
|
||||
|
||||
class HTMLDListElement MOZ_FINAL : public HTMLSharedListElement
|
||||
{
|
||||
public:
|
||||
HTMLDListElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
: HTMLSharedListElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
protected:
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
|
||||
bool *aTriedToWrap) MOZ_OVERRIDE;
|
||||
@ -110,6 +119,12 @@ protected:
|
||||
|
||||
class HTMLOListElement MOZ_FINAL : public HTMLSharedListElement
|
||||
{
|
||||
public:
|
||||
HTMLOListElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
: HTMLSharedListElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
protected:
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
|
||||
bool *aTriedToWrap) MOZ_OVERRIDE;
|
||||
@ -117,6 +132,12 @@ protected:
|
||||
|
||||
class HTMLUListElement MOZ_FINAL : public HTMLSharedListElement
|
||||
{
|
||||
public:
|
||||
HTMLUListElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
: HTMLSharedListElement(aNodeInfo)
|
||||
{
|
||||
}
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
protected:
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
|
||||
bool *aTriedToWrap) MOZ_OVERRIDE;
|
||||
|
@ -1910,7 +1910,6 @@ NS_NewHTMLElement(already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
|
||||
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Shared)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedList)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(SharedObject)
|
||||
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Anchor)
|
||||
@ -1925,6 +1924,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Canvas)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Mod)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(DataList)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Div)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(DList)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(FieldSet)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Font)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Form)
|
||||
@ -1947,6 +1947,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(MenuItem)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Meta)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Meter)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Object)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(OList)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(OptGroup)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Option)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Output)
|
||||
@ -1971,6 +1972,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(TextArea)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Tfoot)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Thead)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Title)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(UList)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Unknown)
|
||||
#if defined(MOZ_MEDIA)
|
||||
NS_DECLARE_NS_NEW_HTML_ELEMENT(Video)
|
||||
|
@ -1076,7 +1076,7 @@ nsHTMLInputElement::ConvertStringToNumber(nsAString& aValue,
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
case NS_FORM_INPUT_DATE:
|
||||
{
|
||||
@ -1091,32 +1091,40 @@ nsHTMLInputElement::ConvertStringToNumber(nsAString& aValue,
|
||||
}
|
||||
|
||||
JSObject* date = JS_NewDateObjectMsec(ctx, 0);
|
||||
if (!date) {
|
||||
JS_ClearPendingException(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
jsval rval;
|
||||
jsval fullYear[3];
|
||||
fullYear[0].setInt32(year);
|
||||
fullYear[1].setInt32(month-1);
|
||||
fullYear[2].setInt32(day);
|
||||
if (!JS::Call(ctx, date, "setUTCFullYear", 3, fullYear, &rval)) {
|
||||
JS_ClearPendingException(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
jsval timestamp;
|
||||
if (!JS::Call(ctx, date, "getTime", 0, nullptr, ×tamp)) {
|
||||
JS_ClearPendingException(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!timestamp.isNumber()) {
|
||||
if (!timestamp.isNumber() || MOZ_DOUBLE_IS_NaN(timestamp.toNumber())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aResultValue = timestamp.toNumber();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
MOZ_NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
double
|
||||
@ -1242,6 +1250,7 @@ nsHTMLInputElement::ConvertNumberToString(double aValue,
|
||||
|
||||
JSObject* date = JS_NewDateObjectMsec(ctx, aValue);
|
||||
if (!date) {
|
||||
JS_ClearPendingException(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1249,6 +1258,14 @@ nsHTMLInputElement::ConvertNumberToString(double aValue,
|
||||
if (!JS::Call(ctx, date, "getUTCFullYear", 0, nullptr, &year) ||
|
||||
!JS::Call(ctx, date, "getUTCMonth", 0, nullptr, &month) ||
|
||||
!JS::Call(ctx, date, "getUTCDate", 0, nullptr, &day)) {
|
||||
JS_ClearPendingException(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!year.isNumber() || !month.isNumber() || !day.isNumber() ||
|
||||
MOZ_DOUBLE_IS_NaN(year.toNumber()) ||
|
||||
MOZ_DOUBLE_IS_NaN(month.toNumber()) ||
|
||||
MOZ_DOUBLE_IS_NaN(day.toNumber())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1280,12 +1297,19 @@ nsHTMLInputElement::GetValueAsDate(JSContext* aCtx, jsval* aDate)
|
||||
}
|
||||
|
||||
JSObject* date = JS_NewDateObjectMsec(aCtx, 0);
|
||||
if (!date) {
|
||||
JS_ClearPendingException(aCtx);
|
||||
aDate->setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
jsval rval;
|
||||
jsval fullYear[3];
|
||||
fullYear[0].setInt32(year);
|
||||
fullYear[1].setInt32(month-1);
|
||||
fullYear[2].setInt32(day);
|
||||
if(!JS::Call(aCtx, date, "setUTCFullYear", 3, fullYear, &rval)) {
|
||||
JS_ClearPendingException(aCtx);
|
||||
aDate->setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1301,15 +1325,22 @@ nsHTMLInputElement::SetValueAsDate(JSContext* aCtx, const jsval& aDate)
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
if (aDate.isNullOrUndefined()) {
|
||||
return SetValue(EmptyString());
|
||||
}
|
||||
|
||||
// TODO: return TypeError when HTMLInputElement is converted to WebIDL, see
|
||||
// bug 826302.
|
||||
if (!aDate.isObject() || !JS_ObjectIsDate(aCtx, &aDate.toObject())) {
|
||||
SetValue(EmptyString());
|
||||
return NS_OK;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JSObject& date = aDate.toObject();
|
||||
jsval timestamp;
|
||||
bool ret = JS::Call(aCtx, &date, "getTime", 0, nullptr, ×tamp);
|
||||
if (!ret || !timestamp.isNumber() || MOZ_DOUBLE_IS_NaN(timestamp.toNumber())) {
|
||||
if (!JS::Call(aCtx, &date, "getTime", 0, nullptr, ×tamp) ||
|
||||
!timestamp.isNumber() || MOZ_DOUBLE_IS_NaN(timestamp.toNumber())) {
|
||||
JS_ClearPendingException(aCtx);
|
||||
SetValue(EmptyString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3570,9 +3570,10 @@ void nsHTMLMediaElement::UpdateAudioChannelPlayingState()
|
||||
// The nsHTMLMediaElement is registered to the AudioChannelService only on B2G.
|
||||
#ifdef MOZ_B2G
|
||||
bool playingThroughTheAudioChannel =
|
||||
(mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
|
||||
!mPaused &&
|
||||
!IsPlaybackEnded());
|
||||
(!mPaused &&
|
||||
(HasAttr(kNameSpaceID_None, nsGkAtoms::loop) ||
|
||||
mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
|
||||
!IsPlaybackEnded()));
|
||||
if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
|
||||
mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;
|
||||
|
||||
|
@ -176,6 +176,9 @@ function checkSet()
|
||||
// the corresponding date string is the empty string
|
||||
[ -62135596800001, "" ],
|
||||
// Invalid dates.
|
||||
// We set the value to something different than the empty string because
|
||||
// NaN should set the value to the empty string.
|
||||
[ 86400000, "1970-01-02" ],
|
||||
[ NaN, "" ],
|
||||
];
|
||||
|
||||
@ -186,9 +189,61 @@ function checkSet()
|
||||
+ data[1]);
|
||||
}
|
||||
|
||||
element.value = "test";
|
||||
element.valueAsDate = null;
|
||||
is(element.value, "", "valueAsDate should set the value to the empty string");
|
||||
|
||||
element.value = "test";
|
||||
element.valueAsDate = undefined;
|
||||
is(element.value, "", "valueAsDate should set the value to the empty string");
|
||||
|
||||
var illegalValues = [
|
||||
"foobar", 42, {}, function() { return 42; }, function() { return Date(); }
|
||||
];
|
||||
|
||||
for (value of illegalValues) {
|
||||
try {
|
||||
var caught = false;
|
||||
element.valueAsDate = value;
|
||||
} catch(e) {
|
||||
caught = true;
|
||||
}
|
||||
ok(caught, "Assigning " + value + " to .valueAsDate should throw");
|
||||
}
|
||||
}
|
||||
|
||||
function checkWithBustedPrototype()
|
||||
{
|
||||
var element = document.createElement('input');
|
||||
element.type = 'date';
|
||||
|
||||
var witnessDate = new Date();
|
||||
|
||||
Date.prototype.getUTCFullYear = function() { return {}; };
|
||||
Date.prototype.getUTCMonth = function() { return {}; };
|
||||
Date.prototype.getUTCDate = function() { return {}; };
|
||||
Date.prototype.getTime = function() { return {}; };
|
||||
Date.prototype.setUTCFullYear = function(y,m,d) { };
|
||||
|
||||
element.valueAsDate = new Date();
|
||||
|
||||
todo_isnot(element.valueAsDate, null, ".valueAsDate should not return null");
|
||||
// TODO: check the Date object value (UTCFullYear, UTCMonth and UTCDate)
|
||||
// when .valueAsDate will stop returning null.
|
||||
|
||||
// Same test as above but using NaN instead of {}.
|
||||
|
||||
Date.prototype.getUTCFullYear = function() { return NaN; };
|
||||
Date.prototype.getUTCMonth = function() { return NaN; };
|
||||
Date.prototype.getUTCDate = function() { return NaN; };
|
||||
Date.prototype.getTime = function() { return NaN; };
|
||||
Date.prototype.setUTCFullYear = function(y,m,d) { };
|
||||
|
||||
element.valueAsDate = new Date();
|
||||
|
||||
todo_isnot(element.valueAsDate, null, ".valueAsDate should not return null");
|
||||
// TODO: check the Date object value (UTCFullYear, UTCMonth and UTCDate)
|
||||
// when .valueAsDate will stop returning null.
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
@ -196,6 +251,7 @@ SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function(
|
||||
checkAvailability();
|
||||
checkGet();
|
||||
checkSet();
|
||||
checkWithBustedPrototype();
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
@ -573,10 +573,6 @@ bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
if (!mAudioBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mAudioMetadataRead && aSeekTimeUs == -1) {
|
||||
// Use the data read into the buffer during metadata time
|
||||
err = OK;
|
||||
@ -595,7 +591,7 @@ bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
|
||||
|
||||
aSeekTimeUs = -1;
|
||||
|
||||
if (err == OK && mAudioBuffer->range_length() != 0) {
|
||||
if (err == OK && mAudioBuffer && mAudioBuffer->range_length() != 0) {
|
||||
int64_t timeUs;
|
||||
if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs))
|
||||
return false;
|
||||
|
@ -52,7 +52,6 @@ ActivitiesDb.prototype = {
|
||||
* id: String
|
||||
* manifest: String
|
||||
* name: String
|
||||
* title: String
|
||||
* icon: String
|
||||
* description: jsval
|
||||
* }
|
||||
@ -94,7 +93,6 @@ ActivitiesDb.prototype = {
|
||||
let object = {
|
||||
manifest: aObject.manifest,
|
||||
name: aObject.name,
|
||||
title: aObject.title || "",
|
||||
icon: aObject.icon || "",
|
||||
description: aObject.description
|
||||
};
|
||||
@ -140,7 +138,6 @@ ActivitiesDb.prototype = {
|
||||
|
||||
txn.result.options.push({
|
||||
manifest: result.manifest,
|
||||
title: result.title,
|
||||
icon: result.icon,
|
||||
description: result.description
|
||||
});
|
||||
|
@ -83,19 +83,23 @@ this.AlarmService = {
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
debug("receiveMessage(): " + aMessage.name);
|
||||
let json = aMessage.json;
|
||||
|
||||
// To prevent hacked child processes from sending commands to parent
|
||||
// to schedule alarms, we need to check their installed permissions.
|
||||
// To prevent the hacked child process from sending commands to parent
|
||||
// to schedule alarms, we need to check its permission and manifest URL.
|
||||
if (["AlarmsManager:GetAll", "AlarmsManager:Add", "AlarmsManager:Remove"]
|
||||
.indexOf(aMessage.name) != -1) {
|
||||
if (!aMessage.target.assertPermission("alarms")) {
|
||||
debug("Got message from a child process with no 'alarms' permission.");
|
||||
return null;
|
||||
}
|
||||
if (!aMessage.target.assertContainApp(json.manifestURL)) {
|
||||
debug("Got message from a child process containing illegal manifest URL.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let mm = aMessage.target.QueryInterface(Ci.nsIMessageSender);
|
||||
let json = aMessage.json;
|
||||
switch (aMessage.name) {
|
||||
case "AlarmsManager:GetAll":
|
||||
this._db.getAll(
|
||||
|
@ -496,7 +496,6 @@ this.DOMApplicationRegistry = {
|
||||
if (aRunUpdate) {
|
||||
activitiesToRegister.push({ "manifest": aApp.manifestURL,
|
||||
"name": activity,
|
||||
"title": manifest.name,
|
||||
"icon": manifest.iconURLForSize(128),
|
||||
"description": description });
|
||||
}
|
||||
|
@ -3810,7 +3810,7 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIPermissionChecker)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIProcessChecker)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
|
||||
|
@ -1965,6 +1965,107 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, JSObject* aScope,
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJSContext::CallEventHandler(nsISupports* aTarget, JSObject* aScope,
|
||||
JSObject* aHandler, nsIArray* aargv,
|
||||
nsIVariant** arv)
|
||||
{
|
||||
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!mScriptsEnabled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SAMPLE_LABEL("JS", "CallEventHandler");
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
xpc_UnmarkGrayObject(aScope);
|
||||
xpc_UnmarkGrayObject(aHandler);
|
||||
|
||||
XPCAutoRequest ar(mContext);
|
||||
JSObject* target = nullptr;
|
||||
nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JS::AutoObjectRooter targetVal(mContext, target);
|
||||
jsval rval = JSVAL_VOID;
|
||||
|
||||
// This one's a lot easier than EvaluateString because we don't have to
|
||||
// hassle with principals: they're already compiled into the JS function.
|
||||
// xxxmarkh - this comment is no longer true - principals are not used at
|
||||
// all now, and never were in some cases.
|
||||
|
||||
nsCxPusher pusher;
|
||||
if (!pusher.Push(mContext, true))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// check if the event handler can be run on the object in question
|
||||
rv = sSecurityManager->CheckFunctionAccess(mContext, aHandler, target);
|
||||
|
||||
nsJSContext::TerminationFuncHolder holder(this);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Convert args to jsvals.
|
||||
uint32_t argc = 0;
|
||||
jsval *argv = nullptr;
|
||||
|
||||
JSObject *funobj = aHandler;
|
||||
jsval funval = OBJECT_TO_JSVAL(funobj);
|
||||
JSAutoCompartment ac(mContext, funobj);
|
||||
if (!JS_WrapObject(mContext, &target)) {
|
||||
ReportPendingException();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
Maybe<nsRootedJSValueArray> tempStorage;
|
||||
|
||||
// Use |target| as the scope for wrapping the arguments, since aScope is
|
||||
// the safe scope in many cases, which isn't very useful. Wrapping aTarget
|
||||
// was OK because those typically have PreCreate methods that give them the
|
||||
// right scope anyway, and we want to make sure that the arguments end up
|
||||
// in the same scope as aTarget.
|
||||
rv = ConvertSupportsTojsvals(aargv, target, &argc, &argv, tempStorage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (uint32_t i = 0; i < argc; i++) {
|
||||
if (!JSVAL_IS_PRIMITIVE(argv[i])) {
|
||||
xpc_UnmarkGrayObject(JSVAL_TO_OBJECT(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
++mExecuteDepth;
|
||||
bool ok = ::JS_CallFunctionValue(mContext, target,
|
||||
funval, argc, argv, &rval);
|
||||
--mExecuteDepth;
|
||||
|
||||
if (!ok) {
|
||||
// Don't pass back results from failed calls.
|
||||
rval = JSVAL_VOID;
|
||||
|
||||
// Tell the caller that the handler threw an error.
|
||||
rv = NS_ERROR_FAILURE;
|
||||
} else if (rval == JSVAL_NULL) {
|
||||
*arv = nullptr;
|
||||
} else if (!JS_WrapValue(mContext, &rval)) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
} else {
|
||||
rv = nsContentUtils::XPConnect()->JSToVariant(mContext, rval, arv);
|
||||
}
|
||||
|
||||
// Tell XPConnect about any pending exceptions. This is needed
|
||||
// to avoid dropping JS exceptions in case we got here through
|
||||
// nested calls through XPConnect.
|
||||
if (NS_FAILED(rv))
|
||||
ReportPendingException();
|
||||
}
|
||||
|
||||
pusher.Pop();
|
||||
|
||||
// ScriptEvaluated needs to come after we pop the stack
|
||||
ScriptEvaluated(true);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, JSObject* aScope,
|
||||
JSObject* aHandler,
|
||||
|
0
dom/camera/DOMCameraControl.cpp
Executable file → Normal file
0
dom/camera/DOMCameraControl.cpp
Executable file → Normal file
@ -282,6 +282,7 @@ nsGonkCameraControl::Init()
|
||||
nsGonkCameraControl::~nsGonkCameraControl()
|
||||
{
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p, mHwHandle = %d\n", __func__, __LINE__, this, mHwHandle);
|
||||
|
||||
ReleaseHardwareImpl(nullptr);
|
||||
if (mRwLock) {
|
||||
PRRWLock* lock = mRwLock;
|
||||
@ -1331,7 +1332,7 @@ nsGonkCameraControl::ReleaseHardwareImpl(ReleaseHardwareTask* aReleaseHardware)
|
||||
StopPreviewInternal(true /* forced */);
|
||||
|
||||
// release the hardware handle
|
||||
GonkCameraHardware::ReleaseHandle(mHwHandle);
|
||||
GonkCameraHardware::ReleaseHandle(mHwHandle, true /* unregister */);
|
||||
|
||||
if (aReleaseHardware && aReleaseHardware->mOnSuccessCb) {
|
||||
nsCOMPtr<nsIRunnable> releaseHardwareResult = new ReleaseHardwareResult(aReleaseHardware->mOnSuccessCb, mWindowId);
|
||||
|
@ -234,7 +234,8 @@ GonkCameraHardware* GonkCameraHardware::sHw = nullptr;
|
||||
uint32_t GonkCameraHardware::sHwHandle = 0;
|
||||
|
||||
void
|
||||
GonkCameraHardware::ReleaseHandle(uint32_t aHwHandle)
|
||||
GonkCameraHardware::ReleaseHandle(uint32_t aHwHandle,
|
||||
bool aUnregisterTarget = false)
|
||||
{
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
DOM_CAMERA_LOGI("%s: aHwHandle = %d, hw = %p (sHwHandle = %d)\n", __func__, aHwHandle, (void*)hw, sHwHandle);
|
||||
@ -253,6 +254,9 @@ GonkCameraHardware::ReleaseHandle(uint32_t aHwHandle)
|
||||
window->abandon();
|
||||
}
|
||||
DOM_CAMERA_LOGT("%s: after: sHwHandle = %d\n", __func__, sHwHandle);
|
||||
if (aUnregisterTarget) {
|
||||
hw->mTarget = nullptr;
|
||||
}
|
||||
delete hw; // destroy the camera hardware instance
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ protected:
|
||||
public:
|
||||
virtual void OnNewFrame() MOZ_OVERRIDE;
|
||||
|
||||
static void ReleaseHandle(uint32_t aHwHandle);
|
||||
static void ReleaseHandle(uint32_t aHwHandle, bool aUnregisterTarget);
|
||||
static uint32_t GetHandle(GonkCamera* aTarget, uint32_t aCamera);
|
||||
|
||||
/**
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
#include "ContentParent.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "AppProcessPermissions.h"
|
||||
#include "AppProcessChecker.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
||||
#include "mozilla/AppProcessPermissions.h"
|
||||
#include "mozilla/AppProcessChecker.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
@ -5,7 +5,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AppProcessPermissions.h"
|
||||
#include "AppProcessChecker.h"
|
||||
#include "ContentParent.h"
|
||||
#include "mozIApplication.h"
|
||||
#include "mozilla/hal_sandbox/PHalParent.h"
|
||||
@ -19,41 +19,59 @@ using namespace mozilla::services;
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
AssertAppProcessPermission(PBrowserParent* aActor, const char* aPermission)
|
||||
AssertAppProcess(PBrowserParent* aActor,
|
||||
AssertAppProcessType aType,
|
||||
const char* aCapability)
|
||||
{
|
||||
if (!aActor) {
|
||||
NS_WARNING("Testing permissions for null actor");
|
||||
NS_WARNING("Testing process capability for null actor");
|
||||
return false;
|
||||
}
|
||||
|
||||
TabParent* tab = static_cast<TabParent*>(aActor);
|
||||
nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
|
||||
bool hasPermission = false;
|
||||
bool aValid = false;
|
||||
|
||||
// isBrowser frames inherit their app descriptor to identify their
|
||||
// data storage, but they don't inherit the permissions associated
|
||||
// data storage, but they don't inherit the capability associated
|
||||
// with that descriptor.
|
||||
if (app && !tab->IsBrowserElement()) {
|
||||
if (!NS_SUCCEEDED(app->HasPermission(aPermission, &hasPermission))) {
|
||||
hasPermission = false;
|
||||
switch (aType) {
|
||||
case ASSERT_APP_PROCESS_PERMISSION:
|
||||
if (!NS_SUCCEEDED(app->HasPermission(aCapability, &aValid))) {
|
||||
aValid = false;
|
||||
}
|
||||
break;
|
||||
case ASSERT_APP_PROCESS_MANIFEST_URL: {
|
||||
nsAutoString manifestURL;
|
||||
if (NS_SUCCEEDED(app->GetManifestURL(manifestURL)) &&
|
||||
manifestURL.EqualsASCII(aCapability)) {
|
||||
aValid = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPermission) {
|
||||
printf_stderr("Security problem: Content process does not have `%s' permission. It will be killed.\n", aPermission);
|
||||
if (!aValid) {
|
||||
printf_stderr("Security problem: Content process does not have `%s'. It will be killed.\n", aCapability);
|
||||
ContentParent* process = static_cast<ContentParent*>(aActor->Manager());
|
||||
process->KillHard();
|
||||
}
|
||||
return hasPermission;
|
||||
return aValid;
|
||||
}
|
||||
|
||||
bool
|
||||
AssertAppProcessPermission(PContentParent* aActor, const char* aPermission)
|
||||
AssertAppProcess(PContentParent* aActor,
|
||||
AssertAppProcessType aType,
|
||||
const char* aCapability)
|
||||
{
|
||||
const InfallibleTArray<PBrowserParent*>& browsers =
|
||||
aActor->ManagedPBrowserParent();
|
||||
for (uint32_t i = 0; i < browsers.Length(); ++i) {
|
||||
if (AssertAppProcessPermission(browsers[i], aPermission)) {
|
||||
if (AssertAppProcess(browsers[i], aType, aCapability)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -61,9 +79,11 @@ AssertAppProcessPermission(PContentParent* aActor, const char* aPermission)
|
||||
}
|
||||
|
||||
bool
|
||||
AssertAppProcessPermission(PHalParent* aActor, const char* aPermission)
|
||||
AssertAppProcess(PHalParent* aActor,
|
||||
AssertAppProcessType aType,
|
||||
const char* aCapability)
|
||||
{
|
||||
return AssertAppProcessPermission(aActor->Manager(), aPermission);
|
||||
return AssertAppProcess(aActor->Manager(), aType, aCapability);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
86
dom/ipc/AppProcessChecker.h
Normal file
86
dom/ipc/AppProcessChecker.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_AppProcessChecker_h
|
||||
#define mozilla_AppProcessChecker_h
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class PBrowserParent;
|
||||
class PContentParent;
|
||||
}
|
||||
|
||||
namespace hal_sandbox {
|
||||
class PHalParent;
|
||||
}
|
||||
|
||||
enum AssertAppProcessType {
|
||||
ASSERT_APP_PROCESS_PERMISSION,
|
||||
ASSERT_APP_PROCESS_MANIFEST_URL
|
||||
};
|
||||
|
||||
/**
|
||||
* Return true iff the specified browser has the specified capability.
|
||||
* If this returns false, the browser didn't have the capability and
|
||||
* will be killed.
|
||||
*/
|
||||
bool
|
||||
AssertAppProcess(mozilla::dom::PBrowserParent* aActor,
|
||||
AssertAppProcessType aType,
|
||||
const char* aCapability);
|
||||
|
||||
/**
|
||||
* Return true iff any of the PBrowsers loaded in this content process
|
||||
* has the specified capability. If this returns false, the process
|
||||
* didn't have the capability and will be killed.
|
||||
*/
|
||||
bool
|
||||
AssertAppProcess(mozilla::dom::PContentParent* aActor,
|
||||
AssertAppProcessType aType,
|
||||
const char* aCapability);
|
||||
|
||||
bool
|
||||
AssertAppProcess(mozilla::hal_sandbox::PHalParent* aActor,
|
||||
AssertAppProcessType aType,
|
||||
const char* aCapability);
|
||||
|
||||
// NB: when adding capability checks for other IPDL actors, please add
|
||||
// them to this file and have them delegate to the two functions above
|
||||
// as appropriate. For example,
|
||||
//
|
||||
// bool AppProcessHasCapability(PNeckoParent* aActor, AssertAppProcessType aType) {
|
||||
// return AssertAppProcess(aActor->Manager(), aType);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Inline function for asserting the process's permission.
|
||||
*/
|
||||
template<typename T>
|
||||
inline bool
|
||||
AssertAppProcessPermission(T* aActor,
|
||||
const char* aPermission) {
|
||||
return AssertAppProcess(aActor,
|
||||
ASSERT_APP_PROCESS_PERMISSION,
|
||||
aPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline function for asserting the process's manifest URL.
|
||||
*/
|
||||
template<typename T>
|
||||
inline bool
|
||||
AssertAppProcessManifestURL(T* aActor,
|
||||
const char* aManifestURL) {
|
||||
return AssertAppProcess(aActor,
|
||||
ASSERT_APP_PROCESS_MANIFEST_URL,
|
||||
aManifestURL);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_AppProcessChecker_h
|
@ -1,54 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_AppProcessPermissions_h
|
||||
#define mozilla_AppProcessPermissions_h
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class PBrowserParent;
|
||||
class PContentParent;
|
||||
}
|
||||
|
||||
namespace hal_sandbox {
|
||||
class PHalParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true iff the specified browser has the specified capability.
|
||||
* If this returns false, the browser didn't have the permission and
|
||||
* will be killed.
|
||||
*/
|
||||
bool
|
||||
AssertAppProcessPermission(mozilla::dom::PBrowserParent* aActor,
|
||||
const char* aPermission);
|
||||
|
||||
/**
|
||||
* Return true iff any of the PBrowsers loaded in this content process
|
||||
* has the specified capability. If this returns false, the process
|
||||
* didn't have the permission and will be killed.
|
||||
*/
|
||||
bool
|
||||
AssertAppProcessPermission(mozilla::dom::PContentParent* aActor,
|
||||
const char* aPermission);
|
||||
|
||||
bool
|
||||
AssertAppProcessPermission(mozilla::hal_sandbox::PHalParent* aActor,
|
||||
const char* aPermission);
|
||||
|
||||
// NB: when adding capability checks for other IPDL actors, please add
|
||||
// them to this file and have them delegate to the two functions above
|
||||
// as appropriate. For example,
|
||||
//
|
||||
// bool AppProcessHasCapability(PNeckoParent* aActor) {
|
||||
// return AssertAppProcessPermission(aActor->Manager());
|
||||
// }
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_AppProcessPermissions_h
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "chrome/common/process_watcher.h"
|
||||
|
||||
#include "AppProcessPermissions.h"
|
||||
#include "AppProcessChecker.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "CrashReporterParent.h"
|
||||
#include "IHistory.h"
|
||||
@ -712,8 +712,17 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
CrashReporterParent* crashReporter =
|
||||
static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
|
||||
|
||||
crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("URL"),
|
||||
NS_ConvertUTF16toUTF8(mAppManifestURL));
|
||||
// If we're an app process, always stomp the latest URI
|
||||
// loaded in the child process with our manifest URL. We
|
||||
// would rather associate the crashes with apps than
|
||||
// random child windows loaded in them.
|
||||
//
|
||||
// XXX would be nice if we could get both ...
|
||||
if (!mAppManifestURL.IsEmpty()) {
|
||||
crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("URL"),
|
||||
NS_ConvertUTF16toUTF8(mAppManifestURL));
|
||||
}
|
||||
|
||||
crashReporter->GenerateCrashReport(this, NULL);
|
||||
|
||||
nsAutoString dumpID(crashReporter->ChildDumpID());
|
||||
@ -2147,6 +2156,11 @@ ContentParent::CheckPermission(const nsAString& aPermission)
|
||||
return AssertAppProcessPermission(this, NS_ConvertUTF16toUTF8(aPermission).get());
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::CheckManifestURL(const nsAString& aManifestURL)
|
||||
{
|
||||
return AssertAppProcessManifestURL(this, NS_ConvertUTF16toUTF8(aManifestURL).get());
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -102,6 +102,7 @@ public:
|
||||
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
|
||||
const mozilla::dom::StructuredCloneData& aData);
|
||||
virtual bool CheckPermission(const nsAString& aPermission);
|
||||
virtual bool CheckManifestURL(const nsAString& aManifestURL);
|
||||
|
||||
/** Notify that a tab was destroyed during normal operation. */
|
||||
void NotifyTabDestroyed(PBrowserParent* aTab);
|
||||
|
@ -31,7 +31,7 @@ EXPORTS_NAMESPACES = \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_mozilla = \
|
||||
AppProcessPermissions.h \
|
||||
AppProcessChecker.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_mozilla/dom = \
|
||||
@ -55,7 +55,7 @@ EXPORTS_mozilla/dom/ipc = \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
AppProcessPermissions.cpp \
|
||||
AppProcessChecker.cpp \
|
||||
Blob.cpp \
|
||||
ContentProcess.cpp \
|
||||
ContentParent.cpp \
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsEmbedCID.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
@ -1089,6 +1090,10 @@ TabChild::RecvLoadURL(const nsCString& uri)
|
||||
NS_WARNING("mWebNav->LoadURI failed. Eating exception, what else can I do?");
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), uri);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -168,6 +168,20 @@ SystemMessageInternal.prototype = {
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
|
||||
// To prevent the hacked child process from sending commands to parent
|
||||
// to manage system messages, we need to check its manifest URL.
|
||||
if (["SystemMessageManager:Register",
|
||||
"SystemMessageManager:Unregister",
|
||||
"SystemMessageManager:GetPendingMessages",
|
||||
"SystemMessageManager:HasPendingMessages",
|
||||
"SystemMessageManager:Message:Return:OK"].indexOf(aMessage.name) != -1) {
|
||||
if (!aMessage.target.assertContainApp(msg.manifest)) {
|
||||
debug("Got message from a child process containing illegal manifest URL.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
switch(aMessage.name) {
|
||||
case "SystemMessageManager:AskReadyToRegister":
|
||||
return true;
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsIDOMTCPSocket.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/AppProcessPermissions.h"
|
||||
#include "mozilla/AppProcessChecker.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const DEBUG = true;
|
||||
const DEBUG = false;
|
||||
function debug(s) {
|
||||
if (DEBUG) dump("-*- SettingsManager: " + s + "\n");
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ function test() {
|
||||
HTML_TAG("dfn", "Span")
|
||||
HTML_TAG("dir", "Shared")
|
||||
HTML_TAG("div", "Div")
|
||||
HTML_TAG("dl", "SharedList")
|
||||
HTML_TAG("dl", "DList")
|
||||
HTML_TAG("dt", "Span")
|
||||
HTML_TAG("em", "Span")
|
||||
HTML_TAG("embed", "SharedObject")
|
||||
@ -84,7 +84,7 @@ function test() {
|
||||
HTML_TAG("noframes", "Div")
|
||||
HTML_TAG("noscript", "Div")
|
||||
HTML_TAG("object", "Object")
|
||||
HTML_TAG("ol", "SharedList")
|
||||
HTML_TAG("ol", "OList")
|
||||
HTML_TAG("optgroup", "OptGroup")
|
||||
HTML_TAG("option", "Option")
|
||||
HTML_TAG("p", "Paragraph")
|
||||
@ -115,7 +115,7 @@ function test() {
|
||||
HTML_TAG("tr", "TableRow")
|
||||
HTML_TAG("tt", "Span")
|
||||
HTML_TAG("u", "Span")
|
||||
HTML_TAG("ul", "SharedList")
|
||||
HTML_TAG("ul", "UList")
|
||||
HTML_TAG("var", "Span")
|
||||
HTML_TAG("wbr", "Shared")
|
||||
HTML_TAG("xmp", "Span")
|
||||
|
@ -60,7 +60,7 @@ HTML_TAG("del", "Mod")
|
||||
HTML_TAG("dfn", "Span")
|
||||
HTML_TAG("dir", "Shared")
|
||||
HTML_TAG("div", "Div")
|
||||
HTML_TAG("dl", "SharedList")
|
||||
HTML_TAG("dl", "DList")
|
||||
HTML_TAG("dt", "Span")
|
||||
HTML_TAG("em", "Span")
|
||||
HTML_TAG("embed", "SharedObject")
|
||||
@ -102,7 +102,7 @@ HTML_TAG("noembed", "Div")
|
||||
HTML_TAG("noframes", "Div")
|
||||
HTML_TAG("noscript", "Div")
|
||||
HTML_TAG("object", "Object")
|
||||
HTML_TAG("ol", "SharedList")
|
||||
HTML_TAG("ol", "OList")
|
||||
HTML_TAG("optgroup", "OptGroup")
|
||||
HTML_TAG("option", "Option")
|
||||
HTML_TAG("p", "Paragraph")
|
||||
@ -133,7 +133,7 @@ HTML_TAG("title", "Title")
|
||||
HTML_TAG("tr", "TableRow")
|
||||
HTML_TAG("tt", "Span")
|
||||
HTML_TAG("u", "Span")
|
||||
HTML_TAG("ul", "SharedList")
|
||||
HTML_TAG("ul", "UList")
|
||||
HTML_TAG("var", "Span")
|
||||
HTML_TAG("wbr", "Shared")
|
||||
HTML_TAG("xmp", "Span")
|
||||
|
@ -5,7 +5,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Hal.h"
|
||||
#include "mozilla/AppProcessPermissions.h"
|
||||
#include "mozilla/AppProcessChecker.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/hal_sandbox/PHalChild.h"
|
||||
#include "mozilla/hal_sandbox/PHalParent.h"
|
||||
|
@ -282,12 +282,56 @@ File(JSContext *cx, unsigned argc, jsval *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
Blob(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> native;
|
||||
rv = nsDOMMultipartFile::NewBlob(getter_AddRefs(native));
|
||||
if (NS_FAILED(rv)) {
|
||||
XPCThrower::Throw(rv, cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIJSNativeInitializer> initializer = do_QueryInterface(native);
|
||||
NS_ASSERTION(initializer, "what?");
|
||||
|
||||
rv = initializer->Initialize(nullptr, cx, nullptr, argc, JS_ARGV(cx, vp));
|
||||
if (NS_FAILED(rv)) {
|
||||
XPCThrower::Throw(rv, cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsXPConnect* xpc = nsXPConnect::GetXPConnect();
|
||||
if (!xpc) {
|
||||
XPCThrower::Throw(NS_ERROR_UNEXPECTED, cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject* glob = JS_GetGlobalForScopeChain(cx);
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
jsval retval;
|
||||
rv = xpc->WrapNativeToJSVal(cx, glob, native, nullptr,
|
||||
&NS_GET_IID(nsISupports),
|
||||
true, &retval, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
XPCThrower::Throw(rv, cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_SET_RVAL(cx, vp, retval);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSFunctionSpec gGlobalFun[] = {
|
||||
JS_FS("dump", Dump, 1,0),
|
||||
JS_FS("debug", Debug, 1,0),
|
||||
JS_FS("atob", Atob, 1,0),
|
||||
JS_FS("btoa", Btoa, 1,0),
|
||||
JS_FS("File", File, 1,JSFUN_CONSTRUCTOR),
|
||||
JS_FS("Blob", Blob, 2,JSFUN_CONSTRUCTOR),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
85
js/xpconnect/tests/unit/component-blob.js
Normal file
85
js/xpconnect/tests/unit/component-blob.js
Normal file
@ -0,0 +1,85 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
function do_check_true(cond, text) {
|
||||
// we don't have the test harness' utilities in this scope, so we need this
|
||||
// little helper. In the failure case, the exception is propagated to the
|
||||
// caller in the main run_test() function, and the test fails.
|
||||
if (!cond)
|
||||
throw "Failed check: " + text;
|
||||
}
|
||||
|
||||
function BlobComponent() {
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
BlobComponent.prototype =
|
||||
{
|
||||
doTest: function() {
|
||||
// throw if anything goes wrong
|
||||
let testContent = "<a id=\"a\"><b id=\"b\">hey!<\/b><\/a>";
|
||||
// should be able to construct a file
|
||||
var f1 = Blob([testContent], {"type" : "text/xml"});
|
||||
// with either constructor syntax
|
||||
var f2 = new Blob([testContent], {"type" : "text/xml"});
|
||||
|
||||
// do some tests
|
||||
do_check_true(f1 instanceof Ci.nsIDOMBlob, "Should be a DOM Blob");
|
||||
do_check_true(f2 instanceof Ci.nsIDOMBlob, "Should be a DOM Blob");
|
||||
|
||||
do_check_true(!(f1 instanceof Ci.nsIDOMFile), "Should not be a DOM File");
|
||||
do_check_true(!(f2 instanceof Ci.nsIDOMFile), "Should not be a DOM File");
|
||||
|
||||
do_check_true(f1.type == "text/xml", "Wrong type");
|
||||
do_check_true(f2.type == "text/xml", "Wrong type");
|
||||
|
||||
do_check_true(f1.size == testContent.length, "Wrong content size");
|
||||
do_check_true(f2.size == testContent.length, "Wrong content size");
|
||||
|
||||
var f3 = new Blob();
|
||||
do_check_true(f3.size == 0, "Wrong size");
|
||||
do_check_true(f3.type == "", "Wrong type");
|
||||
|
||||
var threw = false;
|
||||
try {
|
||||
// Needs a valid ctor argument
|
||||
var f3 = Blob(Date(132131532));
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
do_check_true(threw, "Passing a random object should fail");
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// nsIClassInfo + information for XPCOM registration code in XPCOMUtils.jsm
|
||||
classDescription: "Blob in components scope code",
|
||||
classID: Components.ID("{06215993-a3c2-41e3-bdfd-0a3a2cc0b65c}"),
|
||||
contractID: "@mozilla.org/tests/component-blob;1",
|
||||
|
||||
// nsIClassInfo
|
||||
implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
|
||||
flags: 0,
|
||||
|
||||
getInterfaces: function getInterfaces(aCount) {
|
||||
var interfaces = [Components.interfaces.nsIClassInfo];
|
||||
aCount.value = interfaces.length;
|
||||
return interfaces;
|
||||
},
|
||||
|
||||
getHelperForLanguage: function getHelperForLanguage(aLanguage) {
|
||||
return null;
|
||||
},
|
||||
|
||||
// nsISupports
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIClassInfo])
|
||||
};
|
||||
|
||||
var gComponentsArray = [BlobComponent];
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(gComponentsArray);
|
2
js/xpconnect/tests/unit/component-blob.manifest
Normal file
2
js/xpconnect/tests/unit/component-blob.manifest
Normal file
@ -0,0 +1,2 @@
|
||||
component {06215993-a3c2-41e3-bdfd-0a3a2cc0b65c} component-blob.js
|
||||
contract @mozilla.org/tests/component-blob;1 {06215993-a3c2-41e3-bdfd-0a3a2cc0b65c}
|
16
js/xpconnect/tests/unit/test_blob.js
Normal file
16
js/xpconnect/tests/unit/test_blob.js
Normal file
@ -0,0 +1,16 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function run_test() {
|
||||
do_load_manifest("component-blob.manifest");
|
||||
const contractID = "@mozilla.org/tests/component-blob;1";
|
||||
do_check_true(contractID in Components.classes);
|
||||
var foo = Components.classes[contractID]
|
||||
.createInstance(Components.interfaces.nsIClassInfo);
|
||||
do_check_true(Boolean(foo));
|
||||
do_check_true(foo.contractID == contractID);
|
||||
do_check_true(!!foo.wrappedJSObject);
|
||||
do_check_true(foo.wrappedJSObject.doTest());
|
||||
|
||||
}
|
@ -15,6 +15,7 @@ tail =
|
||||
[test_bug780370.js]
|
||||
[test_bug_442086.js]
|
||||
[test_file.js]
|
||||
[test_blob.js]
|
||||
[test_import.js]
|
||||
[test_import_fail.js]
|
||||
[test_js_weak_references.js]
|
||||
|
@ -109,6 +109,10 @@ class B2GOptions(ReftestOptions):
|
||||
type="string", dest="logcat_dir",
|
||||
help="directory to store logcat dump files")
|
||||
defaults["logcat_dir"] = None
|
||||
self.add_option('--busybox', action='store',
|
||||
type='string', dest='busybox',
|
||||
help="Path to busybox binary to install on device")
|
||||
defaults['busybox'] = None
|
||||
defaults["remoteTestRoot"] = "/data/local/tests"
|
||||
defaults["logFile"] = "reftest.log"
|
||||
defaults["autorun"] = True
|
||||
@ -484,6 +488,8 @@ def main(args=sys.argv[1:]):
|
||||
kwargs['gecko_path'] = options.geckoPath
|
||||
if options.logcat_dir:
|
||||
kwargs['logcat_dir'] = options.logcat_dir
|
||||
if options.busybox:
|
||||
kwargs['busybox'] = options.busybox
|
||||
if options.emulator_res:
|
||||
kwargs['emulator_res'] = options.emulator_res
|
||||
if options.b2gPath:
|
||||
|
@ -70,7 +70,7 @@ HTML_TAG(del, Mod)
|
||||
HTML_HTMLELEMENT_TAG(dfn)
|
||||
HTML_TAG(dir, Shared)
|
||||
HTML_TAG(div, Div)
|
||||
HTML_TAG(dl, SharedList)
|
||||
HTML_TAG(dl, DList)
|
||||
HTML_HTMLELEMENT_TAG(dt)
|
||||
HTML_HTMLELEMENT_TAG(em)
|
||||
HTML_TAG(embed, SharedObject)
|
||||
@ -120,7 +120,7 @@ HTML_HTMLELEMENT_TAG(noembed)
|
||||
HTML_HTMLELEMENT_TAG(noframes)
|
||||
HTML_HTMLELEMENT_TAG(noscript)
|
||||
HTML_TAG(object, Object)
|
||||
HTML_TAG(ol, SharedList)
|
||||
HTML_TAG(ol, OList)
|
||||
HTML_TAG(optgroup, OptGroup)
|
||||
HTML_TAG(option, Option)
|
||||
HTML_TAG(output, Output)
|
||||
@ -156,7 +156,7 @@ HTML_TAG(title, Title)
|
||||
HTML_TAG(tr, TableRow)
|
||||
HTML_HTMLELEMENT_TAG(tt)
|
||||
HTML_HTMLELEMENT_TAG(u)
|
||||
HTML_TAG(ul, SharedList)
|
||||
HTML_TAG(ul, UList)
|
||||
HTML_HTMLELEMENT_TAG(var)
|
||||
#if defined(MOZ_MEDIA)
|
||||
HTML_TAG(video, Video)
|
||||
|
@ -102,6 +102,10 @@ class B2GOptions(MochitestOptions):
|
||||
type="string", dest="logcat_dir",
|
||||
help="directory to store logcat dump files")
|
||||
defaults["logcat_dir"] = None
|
||||
self.add_option('--busybox', action='store',
|
||||
type='string', dest='busybox',
|
||||
help="Path to busybox binary to install on device")
|
||||
defaults['busybox'] = None
|
||||
|
||||
defaults["remoteTestRoot"] = "/data/local/tests"
|
||||
defaults["logFile"] = "mochitest.log"
|
||||
@ -482,6 +486,8 @@ def main():
|
||||
kwargs['gecko_path'] = options.geckoPath
|
||||
if options.logcat_dir:
|
||||
kwargs['logcat_dir'] = options.logcat_dir
|
||||
if options.busybox:
|
||||
kwargs['busybox'] = options.busybox
|
||||
# needless to say sdcard is only valid if using an emulator
|
||||
if options.sdcard:
|
||||
kwargs['sdcard'] = options.sdcard
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include "nscore.h"
|
||||
#include "nsTextStore.h"
|
||||
#include "nsWindow.h"
|
||||
#ifdef MOZ_METRO
|
||||
#include "winrt/MetroWidget.h"
|
||||
#endif
|
||||
#include "nsPrintfCString.h"
|
||||
#include "WinUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -339,7 +342,6 @@ nsTextStore::nsTextStore()
|
||||
mRefCnt = 1;
|
||||
mEditCookie = 0;
|
||||
mSinkMask = 0;
|
||||
mWindow = nullptr;
|
||||
mLock = 0;
|
||||
mLockQueued = 0;
|
||||
mTextChange.acpStart = INT32_MAX;
|
||||
@ -351,8 +353,8 @@ nsTextStore::~nsTextStore()
|
||||
{
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore instance is destroyed, "
|
||||
"mWindow=0x%p, mDocumentMgr=0x%p, mContext=0x%p",
|
||||
this, mWindow, mDocumentMgr.get(), mContext.get()));
|
||||
"mWidget=0x%p, mDocumentMgr=0x%p, mContext=0x%p",
|
||||
this, mWidget, mDocumentMgr, mContext));
|
||||
|
||||
if (mCompositionTimer) {
|
||||
mCompositionTimer->Cancel();
|
||||
@ -362,12 +364,12 @@ nsTextStore::~nsTextStore()
|
||||
}
|
||||
|
||||
bool
|
||||
nsTextStore::Create(nsWindow* aWindow,
|
||||
nsTextStore::Create(nsWindowBase* aWidget,
|
||||
IMEState::Enabled aIMEEnabled)
|
||||
{
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::Create(aWindow=0x%p, aIMEEnabled=%s)",
|
||||
this, aWindow, GetIMEEnabledName(aIMEEnabled)));
|
||||
("TSF: 0x%p nsTextStore::Create(aWidget=0x%p, aIMEEnabled=%s)",
|
||||
this, aWidget, GetIMEEnabledName(aIMEEnabled)));
|
||||
|
||||
if (mDocumentMgr) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
@ -385,7 +387,8 @@ nsTextStore::Create(nsWindow* aWindow,
|
||||
"(0x%08X)", this, hr));
|
||||
return false;
|
||||
}
|
||||
mWindow = aWindow;
|
||||
mWidget = aWidget;
|
||||
|
||||
// Create context and add it to document manager
|
||||
hr = mDocumentMgr->CreateContext(sTsfClientId, 0,
|
||||
static_cast<ITextStoreACP*>(this),
|
||||
@ -425,13 +428,13 @@ nsTextStore::Destroy(void)
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::Destroy()", this));
|
||||
|
||||
if (mWindow) {
|
||||
if (mWidget) {
|
||||
// When blurred, Tablet Input Panel posts "blur" messages
|
||||
// and try to insert text when the message is retrieved later.
|
||||
// But by that time the text store is already destroyed,
|
||||
// so try to get the message early
|
||||
MSG msg;
|
||||
if (::PeekMessageW(&msg, mWindow->GetWindowHandle(),
|
||||
if (::PeekMessageW(&msg, mWidget->GetWindowHandle(),
|
||||
sFlushTIPInputMessage, sFlushTIPInputMessage,
|
||||
PM_REMOVE)) {
|
||||
::DispatchMessageW(&msg);
|
||||
@ -443,7 +446,7 @@ nsTextStore::Destroy(void)
|
||||
mDocumentMgr = NULL;
|
||||
}
|
||||
mSink = NULL;
|
||||
mWindow = NULL;
|
||||
mWidget = nullptr;
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::Destroy() succeeded", this));
|
||||
@ -756,9 +759,9 @@ nsTextStore::GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP)
|
||||
"try to get normal selection...", this));
|
||||
|
||||
// Construct and initialize an event to get selection info
|
||||
nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
if (!event.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetSelectionInternal() FAILED to "
|
||||
@ -1087,8 +1090,8 @@ nsTextStore::SendTextEventForCompositionString()
|
||||
}
|
||||
|
||||
// Use NS_TEXT_TEXT to set composition string
|
||||
nsTextEvent event(true, NS_TEXT_TEXT, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
nsTextEvent event(true, NS_TEXT_TEXT, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
|
||||
nsRefPtr<ITfRange> composingRange;
|
||||
hr = mCompositionView->GetRange(getter_AddRefs(composingRange));
|
||||
@ -1218,18 +1221,18 @@ nsTextStore::SendTextEventForCompositionString()
|
||||
("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() "
|
||||
"dispatching compositionupdate event...", this));
|
||||
nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE,
|
||||
mWindow);
|
||||
mWindow->InitEvent(compositionUpdate);
|
||||
mWidget);
|
||||
mWidget->InitEvent(compositionUpdate);
|
||||
compositionUpdate.data = mCompositionString;
|
||||
mLastDispatchedCompositionString = mCompositionString;
|
||||
mWindow->DispatchWindowEvent(&compositionUpdate);
|
||||
mWidget->DispatchWindowEvent(&compositionUpdate);
|
||||
}
|
||||
|
||||
if (mWindow && !mWindow->Destroyed()) {
|
||||
if (mWidget && !mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() "
|
||||
"dispatching text event...", this));
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
}
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
@ -1282,12 +1285,12 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection,
|
||||
}
|
||||
return S_OK;
|
||||
} else {
|
||||
nsSelectionEvent event(true, NS_SELECTION_SET, mWindow);
|
||||
nsSelectionEvent event(true, NS_SELECTION_SET, mWidget);
|
||||
event.mOffset = pSelection->acpStart;
|
||||
event.mLength = uint32_t(pSelection->acpEnd - pSelection->acpStart);
|
||||
event.mReversed = pSelection->style.ase == TS_AE_START;
|
||||
mWindow->InitEvent(event);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
mWidget->InitEvent(event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
if (!event.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to "
|
||||
@ -1415,10 +1418,10 @@ nsTextStore::GetText(LONG acpStart,
|
||||
}
|
||||
}
|
||||
// Send NS_QUERY_TEXT_CONTENT to get text content
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
event.InitForQueryTextContent(uint32_t(acpStart), length);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
if (!event.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetText() FAILED due to "
|
||||
@ -1693,11 +1696,11 @@ nsTextStore::GetEndACP(LONG *pacp)
|
||||
}
|
||||
|
||||
// Flattened text is retrieved and its length returned
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
// Return entire text
|
||||
event.InitForQueryTextContent(0, INT32_MAX);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
if (!event.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to "
|
||||
@ -1801,10 +1804,10 @@ nsTextStore::GetTextExt(TsViewCookie vcView,
|
||||
}
|
||||
|
||||
// use NS_QUERY_TEXT_RECT to get rect in system, screen coordinates
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
event.InitForQueryTextRect(acpStart, acpEnd - acpStart);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
if (!event.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to "
|
||||
@ -1817,19 +1820,21 @@ nsTextStore::GetTextExt(TsViewCookie vcView,
|
||||
if (event.mReply.mRect.height <= 0)
|
||||
event.mReply.mRect.height = 1;
|
||||
|
||||
// convert to unclipped screen rect
|
||||
nsWindow* refWindow = static_cast<nsWindow*>(
|
||||
event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow);
|
||||
// Result rect is in top level widget coordinates
|
||||
refWindow = refWindow->GetTopLevelWindow(false);
|
||||
if (!refWindow) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to "
|
||||
"no top level window", this));
|
||||
return E_FAIL;
|
||||
}
|
||||
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
|
||||
// convert to unclipped screen rect
|
||||
nsWindow* refWindow = static_cast<nsWindow*>(
|
||||
event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWidget);
|
||||
// Result rect is in top level widget coordinates
|
||||
refWindow = refWindow->GetTopLevelWindow(false);
|
||||
if (!refWindow) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to "
|
||||
"no top level window", this));
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
}
|
||||
|
||||
// get bounding screen rect to test for clipping
|
||||
if (!GetScreenExtInternal(*prc)) {
|
||||
@ -1902,9 +1907,9 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt)
|
||||
("TSF: 0x%p nsTextStore::GetScreenExtInternal()", this));
|
||||
|
||||
// use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates
|
||||
nsQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
nsQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
if (!event.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to "
|
||||
@ -1912,35 +1917,50 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt)
|
||||
return false;
|
||||
}
|
||||
|
||||
nsWindow* refWindow = static_cast<nsWindow*>(
|
||||
event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow);
|
||||
// Result rect is in top level widget coordinates
|
||||
refWindow = refWindow->GetTopLevelWindow(false);
|
||||
if (!refWindow) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to "
|
||||
"no top level window", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIntRect boundRect;
|
||||
if (NS_FAILED(refWindow->GetClientBounds(boundRect))) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to "
|
||||
"failed to get the client bounds", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
boundRect.MoveTo(0, 0);
|
||||
|
||||
// Clip frame rect to window rect
|
||||
boundRect.IntersectRect(event.mReply.mRect, boundRect);
|
||||
if (!boundRect.IsEmpty()) {
|
||||
boundRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
|
||||
nsIntRect boundRect;
|
||||
if (NS_FAILED(mWidget->GetClientBounds(boundRect))) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to "
|
||||
"failed to get the client bounds", this));
|
||||
return false;
|
||||
}
|
||||
::SetRect(&aScreenExt, boundRect.x, boundRect.y,
|
||||
boundRect.XMost(), boundRect.YMost());
|
||||
} else {
|
||||
::SetRectEmpty(&aScreenExt);
|
||||
NS_ASSERTION(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop,
|
||||
"environment isn't WindowsEnvironmentType_Desktop!");
|
||||
nsWindow* refWindow = static_cast<nsWindow*>(
|
||||
event.mReply.mFocusedWidget ?
|
||||
event.mReply.mFocusedWidget : mWidget);
|
||||
// Result rect is in top level widget coordinates
|
||||
refWindow = refWindow->GetTopLevelWindow(false);
|
||||
if (!refWindow) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to "
|
||||
"no top level window", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIntRect boundRect;
|
||||
if (NS_FAILED(refWindow->GetClientBounds(boundRect))) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to "
|
||||
"failed to get the client bounds", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
boundRect.MoveTo(0, 0);
|
||||
|
||||
// Clip frame rect to window rect
|
||||
boundRect.IntersectRect(event.mReply.mRect, boundRect);
|
||||
if (!boundRect.IsEmpty()) {
|
||||
boundRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
::SetRect(&aScreenExt, boundRect.x, boundRect.y,
|
||||
boundRect.XMost(), boundRect.YMost());
|
||||
} else {
|
||||
::SetRectEmpty(&aScreenExt);
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
@ -1956,8 +1976,9 @@ nsTextStore::GetWnd(TsViewCookie vcView,
|
||||
HWND *phwnd)
|
||||
{
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), mWindow=0x%p",
|
||||
this, vcView, phwnd, mWindow));
|
||||
("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), "
|
||||
"mWidget=0x%p",
|
||||
this, vcView, phwnd, mWidget));
|
||||
|
||||
if (vcView != TEXTSTORE_DEFAULT_VIEW) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
@ -1973,7 +1994,7 @@ nsTextStore::GetWnd(TsViewCookie vcView,
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*phwnd = mWindow->GetWindowHandle();
|
||||
*phwnd = mWidget->GetWindowHandle();
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::GetWnd() succeeded: *phwnd=0x%p",
|
||||
@ -2135,10 +2156,11 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a compositionstart event...", this));
|
||||
nsCompositionEvent compStartEvent(true, NS_COMPOSITION_START, mWindow);
|
||||
mWindow->InitEvent(compStartEvent);
|
||||
mWindow->DispatchWindowEvent(&compStartEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
nsCompositionEvent compStartEvent(true, NS_COMPOSITION_START,
|
||||
mWidget);
|
||||
mWidget->InitEvent(compStartEvent);
|
||||
mWidget->DispatchWindowEvent(&compStartEvent);
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to the widget destroyed by compositionstart event", this));
|
||||
@ -2149,10 +2171,11 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a compositionupdate event...", this));
|
||||
nsCompositionEvent compUpdateEvent(true, NS_COMPOSITION_UPDATE, mWindow);
|
||||
nsCompositionEvent compUpdateEvent(true, NS_COMPOSITION_UPDATE,
|
||||
mWidget);
|
||||
compUpdateEvent.data = aInsertStr;
|
||||
mWindow->DispatchWindowEvent(&compUpdateEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
mWidget->DispatchWindowEvent(&compUpdateEvent);
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"FAILED due to the widget destroyed by compositionupdate event",
|
||||
@ -2164,13 +2187,13 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a text event...", this));
|
||||
nsTextEvent textEvent(true, NS_TEXT_TEXT, mWindow);
|
||||
mWindow->InitEvent(textEvent);
|
||||
nsTextEvent textEvent(true, NS_TEXT_TEXT, mWidget);
|
||||
mWidget->InitEvent(textEvent);
|
||||
textEvent.theText = aInsertStr;
|
||||
textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
|
||||
NS_LITERAL_STRING("\n"));
|
||||
mWindow->DispatchWindowEvent(&textEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
mWidget->DispatchWindowEvent(&textEvent);
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to the widget destroyed by text event", this));
|
||||
@ -2180,10 +2203,10 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() "
|
||||
"dispatching a compositionend event...", this));
|
||||
nsCompositionEvent compEndEvent(true, NS_COMPOSITION_END, mWindow);
|
||||
nsCompositionEvent compEndEvent(true, NS_COMPOSITION_END, mWidget);
|
||||
compEndEvent.data = aInsertStr;
|
||||
mWindow->DispatchWindowEvent(&compEndEvent);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
mWidget->DispatchWindowEvent(&compEndEvent);
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED "
|
||||
"due to the widget destroyed by compositionend event", this));
|
||||
@ -2209,9 +2232,9 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr,
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() succeeded: "
|
||||
"mWindow=0x%p, mWindow->Destroyed()=%s, aTextChange={ acpStart=%ld, "
|
||||
"mWidget=0x%p, mWidget->Destroyed()=%s, aTextChange={ acpStart=%ld, "
|
||||
"acpOldEnd=%ld, acpNewEnd=%ld }",
|
||||
this, mWindow, GetBoolName(mWindow ? mWindow->Destroyed() : true),
|
||||
this, mWidget, GetBoolName(mWidget ? mWidget->Destroyed() : true),
|
||||
aTextChange ? aTextChange->acpStart : 0,
|
||||
aTextChange ? aTextChange->acpOldEnd : 0,
|
||||
aTextChange ? aTextChange->acpNewEnd : 0));
|
||||
@ -2264,12 +2287,12 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
|
||||
"dispatching selectionset event..."));
|
||||
|
||||
// Select composition range so the new composition replaces the range
|
||||
nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWindow);
|
||||
mWindow->InitEvent(selEvent);
|
||||
nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWidget);
|
||||
mWidget->InitEvent(selEvent);
|
||||
selEvent.mOffset = uint32_t(mCompositionStart);
|
||||
selEvent.mLength = uint32_t(mCompositionLength);
|
||||
selEvent.mReversed = false;
|
||||
mWindow->DispatchWindowEvent(&selEvent);
|
||||
mWidget->DispatchWindowEvent(&selEvent);
|
||||
if (!selEvent.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due "
|
||||
@ -2278,9 +2301,9 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
|
||||
}
|
||||
|
||||
// Set up composition
|
||||
nsQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, mWindow);
|
||||
mWindow->InitEvent(queryEvent);
|
||||
mWindow->DispatchWindowEvent(&queryEvent);
|
||||
nsQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, mWidget);
|
||||
mWidget->InitEvent(queryEvent);
|
||||
mWidget->DispatchWindowEvent(&queryEvent);
|
||||
if (!queryEvent.mSucceeded) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
|
||||
("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due "
|
||||
@ -2299,9 +2322,9 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
|
||||
mCompositionSelection.style.ase = TS_AE_END;
|
||||
mCompositionSelection.style.fInterimChar = FALSE;
|
||||
}
|
||||
nsCompositionEvent event(true, NS_COMPOSITION_START, mWindow);
|
||||
mWindow->InitEvent(event);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
nsCompositionEvent event(true, NS_COMPOSITION_START, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: 0x%p nsTextStore::OnStartCompositionInternal() succeeded: "
|
||||
@ -2476,12 +2499,12 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
|
||||
("TSF: 0x%p nsTextStore::OnEndComposition(), "
|
||||
"dispatching compositionupdate event...", this));
|
||||
nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE,
|
||||
mWindow);
|
||||
mWindow->InitEvent(compositionUpdate);
|
||||
mWidget);
|
||||
mWidget->InitEvent(compositionUpdate);
|
||||
compositionUpdate.data = mCompositionString;
|
||||
mLastDispatchedCompositionString = mCompositionString;
|
||||
mWindow->DispatchWindowEvent(&compositionUpdate);
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
mWidget->DispatchWindowEvent(&compositionUpdate);
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::OnEndComposition(), "
|
||||
"succeeded, but the widget has gone", this));
|
||||
@ -2494,14 +2517,14 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
|
||||
"dispatching text event...", this));
|
||||
|
||||
// Use NS_TEXT_TEXT to commit composition string
|
||||
nsTextEvent textEvent(true, NS_TEXT_TEXT, mWindow);
|
||||
mWindow->InitEvent(textEvent);
|
||||
nsTextEvent textEvent(true, NS_TEXT_TEXT, mWidget);
|
||||
mWidget->InitEvent(textEvent);
|
||||
textEvent.theText = mCompositionString;
|
||||
textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
|
||||
NS_LITERAL_STRING("\n"));
|
||||
mWindow->DispatchWindowEvent(&textEvent);
|
||||
mWidget->DispatchWindowEvent(&textEvent);
|
||||
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::OnEndComposition(), "
|
||||
"succeeded, but the widget has gone", this));
|
||||
@ -2512,12 +2535,12 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
|
||||
("TSF: 0x%p nsTextStore::OnEndComposition(), "
|
||||
"dispatching compositionend event...", this));
|
||||
|
||||
nsCompositionEvent event(true, NS_COMPOSITION_END, mWindow);
|
||||
nsCompositionEvent event(true, NS_COMPOSITION_END, mWidget);
|
||||
event.data = mLastDispatchedCompositionString;
|
||||
mWindow->InitEvent(event);
|
||||
mWindow->DispatchWindowEvent(&event);
|
||||
mWidget->InitEvent(event);
|
||||
mWidget->DispatchWindowEvent(&event);
|
||||
|
||||
if (!mWindow || mWindow->Destroyed()) {
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
|
||||
("TSF: 0x%p nsTextStore::OnEndComposition(), "
|
||||
"succeeded, but the widget has gone", this));
|
||||
@ -2538,22 +2561,24 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsTextStore::OnFocusChange(bool aFocus,
|
||||
nsWindow* aWindow,
|
||||
nsTextStore::OnFocusChange(bool aGotFocus,
|
||||
nsWindowBase* aFocusedWidget,
|
||||
IMEState::Enabled aIMEEnabled)
|
||||
{
|
||||
PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
|
||||
("TSF: nsTextStore::OnFocusChange(aFocus=%s, aWindow=0x%p, "
|
||||
"aIMEEnabled=%s), sTsfThreadMgr=0x%p, sTsfTextStore=0x%p",
|
||||
GetBoolName(aFocus), aWindow, GetIMEEnabledName(aIMEEnabled),
|
||||
sTsfThreadMgr, sTsfTextStore));
|
||||
("TSF: nsTextStore::OnFocusChange(aGotFocus=%s, "
|
||||
"aFocusedWidget=0x%p, aIMEEnabled=%s), sTsfThreadMgr=0x%p, "
|
||||
"sTsfTextStore=0x%p",
|
||||
GetBoolName(aGotFocus), aFocusedWidget,
|
||||
GetIMEEnabledName(aIMEEnabled), sTsfThreadMgr, sTsfTextStore));
|
||||
|
||||
// no change notifications if TSF is disabled
|
||||
if (!sTsfThreadMgr || !sTsfTextStore)
|
||||
if (!sTsfThreadMgr || !sTsfTextStore) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (aFocus) {
|
||||
bool bRet = sTsfTextStore->Create(aWindow, aIMEEnabled);
|
||||
if (aGotFocus) {
|
||||
bool bRet = sTsfTextStore->Create(aFocusedWidget, aIMEEnabled);
|
||||
NS_ENSURE_TRUE(bRet, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(sTsfTextStore->mDocumentMgr, NS_ERROR_FAILURE);
|
||||
HRESULT hr = sTsfThreadMgr->SetFocus(sTsfTextStore->mDocumentMgr);
|
||||
@ -2594,7 +2619,7 @@ nsTextStore::OnTextChangeInternal(uint32_t aStart,
|
||||
mTextChange.acpStart = NS_MIN(mTextChange.acpStart, LONG(aStart));
|
||||
mTextChange.acpOldEnd = NS_MAX(mTextChange.acpOldEnd, LONG(aOldEnd));
|
||||
mTextChange.acpNewEnd = NS_MAX(mTextChange.acpNewEnd, LONG(aNewEnd));
|
||||
::PostMessageW(mWindow->GetWindowHandle(),
|
||||
::PostMessageW(mWidget->GetWindowHandle(),
|
||||
WM_USER_TSF_TEXTCHANGE, 0, 0);
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsWindowBase.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include <msctf.h>
|
||||
@ -22,6 +23,9 @@ struct ITfDisplayAttributeMgr;
|
||||
struct ITfCategoryMgr;
|
||||
class nsWindow;
|
||||
class nsTextEvent;
|
||||
#ifdef MOZ_METRO
|
||||
class MetroWidget;
|
||||
#endif
|
||||
|
||||
// It doesn't work well when we notify TSF of text change
|
||||
// during a mutation observer call because things get broken.
|
||||
@ -100,8 +104,9 @@ public:
|
||||
sTsfTextStore->SetInputContextInternal(aContext.mIMEState.mEnabled);
|
||||
}
|
||||
|
||||
static nsresult OnFocusChange(bool, nsWindow*, IMEState::Enabled);
|
||||
|
||||
static nsresult OnFocusChange(bool aGotFocus,
|
||||
nsWindowBase* aFocusedWidget,
|
||||
IMEState::Enabled aIMEEnabled);
|
||||
static nsresult OnTextChange(uint32_t aStart,
|
||||
uint32_t aOldEnd,
|
||||
uint32_t aNewEnd)
|
||||
@ -154,7 +159,8 @@ protected:
|
||||
nsTextStore();
|
||||
~nsTextStore();
|
||||
|
||||
bool Create(nsWindow*, IMEState::Enabled);
|
||||
bool Create(nsWindowBase* aWidget,
|
||||
IMEState::Enabled aIMEEnabled);
|
||||
bool Destroy(void);
|
||||
|
||||
bool IsReadLock(DWORD aLock) const
|
||||
@ -192,6 +198,8 @@ protected:
|
||||
HRESULT SaveTextEvent(const nsTextEvent* aEvent);
|
||||
nsresult OnCompositionTimer();
|
||||
|
||||
// Holds the pointer to our current win32 or metro widget
|
||||
nsRefPtr<nsWindowBase> mWidget;
|
||||
// Document manager for the currently focused editor
|
||||
nsRefPtr<ITfDocumentMgr> mDocumentMgr;
|
||||
// Edit cookie associated with the current editing context
|
||||
@ -202,8 +210,6 @@ protected:
|
||||
nsRefPtr<ITextStoreACPSink> mSink;
|
||||
// TS_AS_* mask of what events to notify
|
||||
DWORD mSinkMask;
|
||||
// Window containing the focused editor
|
||||
nsWindow* mWindow;
|
||||
// 0 if not locked, otherwise TS_LF_* indicating the current lock
|
||||
DWORD mLock;
|
||||
// 0 if no lock is queued, otherwise TS_LF_* indicating the queue lock
|
||||
|
@ -302,7 +302,7 @@ static const int32_t kResizableBorderMinSize = 3;
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
nsWindow::nsWindow() : nsBaseWidget()
|
||||
nsWindow::nsWindow() : nsWindowBase()
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gWindowsLog) {
|
||||
@ -5046,7 +5046,9 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
|
||||
case WM_APPCOMMAND:
|
||||
{
|
||||
uint32_t appCommand = GET_APPCOMMAND_LPARAM(lParam);
|
||||
|
||||
uint32_t contentCommandMessage = NS_EVENT_NULL;
|
||||
// XXX After we implement KeyboardEvent.key, we should dispatch the
|
||||
// key event if (GET_DEVICE_LPARAM(lParam) == FAPPCOMMAND_KEY) is.
|
||||
switch (appCommand)
|
||||
{
|
||||
case APPCOMMAND_BROWSER_BACKWARD:
|
||||
@ -5075,6 +5077,31 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
|
||||
// Use content command for following commands:
|
||||
case APPCOMMAND_COPY:
|
||||
contentCommandMessage = NS_CONTENT_COMMAND_COPY;
|
||||
break;
|
||||
case APPCOMMAND_CUT:
|
||||
contentCommandMessage = NS_CONTENT_COMMAND_CUT;
|
||||
break;
|
||||
case APPCOMMAND_PASTE:
|
||||
contentCommandMessage = NS_CONTENT_COMMAND_PASTE;
|
||||
break;
|
||||
case APPCOMMAND_REDO:
|
||||
contentCommandMessage = NS_CONTENT_COMMAND_REDO;
|
||||
break;
|
||||
case APPCOMMAND_UNDO:
|
||||
contentCommandMessage = NS_CONTENT_COMMAND_UNDO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (contentCommandMessage) {
|
||||
nsContentCommandEvent contentCommand(true, contentCommandMessage, this);
|
||||
DispatchWindowEvent(&contentCommand);
|
||||
// tell the driver that we handled the event
|
||||
*aRetValue = 1;
|
||||
result = true;
|
||||
}
|
||||
// default = false - tell the driver that the event was not handled
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsBaseWidget.h"
|
||||
#include "nsWindowBase.h"
|
||||
#include "nsdefs.h"
|
||||
#include "nsIdleService.h"
|
||||
#include "nsToolkit.h"
|
||||
@ -64,7 +65,7 @@ class ModifierKeyState;
|
||||
* Native WIN32 window wrapper.
|
||||
*/
|
||||
|
||||
class nsWindow : public nsBaseWidget
|
||||
class nsWindow : public nsWindowBase
|
||||
{
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
typedef mozilla::TimeDuration TimeDuration;
|
||||
@ -79,9 +80,11 @@ public:
|
||||
|
||||
friend class nsWindowGfx;
|
||||
|
||||
/**
|
||||
* nsIWidget interface
|
||||
*/
|
||||
// nsWindowBase
|
||||
virtual void InitEvent(nsGUIEvent& aEvent, nsIntPoint* aPoint = nullptr) MOZ_OVERRIDE;
|
||||
virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE;
|
||||
|
||||
// nsIWidget interface
|
||||
NS_IMETHOD Create(nsIWidget *aParent,
|
||||
nsNativeWidget aNativeParent,
|
||||
const nsIntRect &aRect,
|
||||
@ -186,13 +189,11 @@ public:
|
||||
/**
|
||||
* Event helpers
|
||||
*/
|
||||
void InitEvent(nsGUIEvent& event, nsIntPoint* aPoint = nullptr);
|
||||
virtual bool DispatchMouseEvent(uint32_t aEventType, WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
bool aIsContextMenuKey = false,
|
||||
int16_t aButton = nsMouseEvent::eLeftButton,
|
||||
uint16_t aInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE);
|
||||
virtual bool DispatchWindowEvent(nsGUIEvent* event);
|
||||
virtual bool DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus);
|
||||
void InitKeyEvent(nsKeyEvent& aKeyEvent,
|
||||
const NativeKey& aNativeKey,
|
||||
@ -215,7 +216,6 @@ public:
|
||||
* Window utilities
|
||||
*/
|
||||
nsWindow* GetTopLevelWindow(bool aStopOnDialogOrPopup);
|
||||
HWND GetWindowHandle() { return mWnd; }
|
||||
WNDPROC GetPrevWindowProc() { return mPrevWndProc; }
|
||||
WindowHook& GetWindowHook() { return mWindowHook; }
|
||||
nsWindow* GetParentWindow(bool aIncludeOwner);
|
||||
|
37
widget/windows/nsWindowBase.h
Normal file
37
widget/windows/nsWindowBase.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsWindowBase_h_
|
||||
#define nsWindowBase_h_
|
||||
|
||||
#include "nsBaseWidget.h"
|
||||
|
||||
/*
|
||||
* nsWindowBase - Base class of common methods other classes need to access
|
||||
* in both win32 and winrt window classes.
|
||||
*/
|
||||
|
||||
class nsWindowBase : public nsBaseWidget
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Return the HWND or null for this widget.
|
||||
*/
|
||||
virtual HWND GetWindowHandle() MOZ_FINAL {
|
||||
return static_cast<HWND>(GetNativeData(NS_NATIVE_WINDOW));
|
||||
}
|
||||
|
||||
/*
|
||||
* Init a standard gecko event for this widget.
|
||||
*/
|
||||
virtual void InitEvent(nsGUIEvent& aEvent, nsIntPoint* aPoint = nullptr) = 0;
|
||||
|
||||
/*
|
||||
* Dispatch a gecko event for this widget.
|
||||
*/
|
||||
virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) = 0;
|
||||
};
|
||||
|
||||
#endif // nsWindowBase_h_
|
Loading…
Reference in New Issue
Block a user