diff --git a/b2g/components/ActivitiesGlue.js b/b2g/components/ActivitiesGlue.js index c6854572afc..221aecb7143 100644 --- a/b2g/components/ActivitiesGlue.js +++ b/b2g/components/ActivitiesGlue.js @@ -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 }); }); diff --git a/browser/components/downloads/src/DownloadsCommon.jsm b/browser/components/downloads/src/DownloadsCommon.jsm index 6867ceaef41..fd8e6655014 100644 --- a/browser/components/downloads/src/DownloadsCommon.jsm +++ b/browser/components/downloads/src/DownloadsCommon.jsm @@ -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 " diff --git a/content/base/public/nsIMessageManager.idl b/content/base/public/nsIMessageManager.idl index 766f8aacedf..fc8cb671d26 100644 --- a/content/base/public/nsIMessageManager.idl +++ b/content/base/public/nsIMessageManager.idl @@ -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); + }; diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 084e9c95741..b5cc1f171b3 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -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 diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h index b52a1899dc8..f6883f12142 100644 --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -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; diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 4023f9508c0..e2fd1d62c8d 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -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; + } }; diff --git a/content/base/src/nsFrameMessageManager.h b/content/base/src/nsFrameMessageManager.h index ae0825b3ed8..6ca9124372c 100644 --- a/content/base/src/nsFrameMessageManager.h +++ b/content/base/src/nsFrameMessageManager.h @@ -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 >* sPendingSameProcessAsyncMessages; +private: + enum ProcessCheckerType { + PROCESS_CHECKER_PERMISSION, + PROCESS_CHECKER_MANIFEST_URL + }; + nsresult AssertProcessInternal(ProcessCheckerType aType, + const nsAString& aCapability, + bool* aValid); }; void diff --git a/content/base/test/test_messagemanager_assertpermission.html b/content/base/test/test_messagemanager_assertpermission.html index 9a00da1a2a7..5d76cf56348 100644 --- a/content/base/test/test_messagemanager_assertpermission.html +++ b/content/base/test/test_messagemanager_assertpermission.html @@ -2,7 +2,7 @@ - Test for the nsIPermissionChecker part of Message Managers + Test for the nsIProcessChecker part of Message Managers diff --git a/content/html/content/src/HTMLSharedListElement.cpp b/content/html/content/src/HTMLSharedListElement.cpp index 43cb4a2f0f4..cad9ccd01a8 100644 --- a/content/html/content/src/HTMLSharedListElement.cpp +++ b/content/html/content/src/HTMLSharedListElement.cpp @@ -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) diff --git a/content/html/content/src/HTMLSharedListElement.h b/content/html/content/src/HTMLSharedListElement.h index 8fe4b91bdc9..a1a1b2e8c24 100644 --- a/content/html/content/src/HTMLSharedListElement.h +++ b/content/html/content/src/HTMLSharedListElement.h @@ -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(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 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 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 aNodeInfo) + : HTMLSharedListElement(aNodeInfo) + { + } + virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; protected: virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope, bool *aTriedToWrap) MOZ_OVERRIDE; diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index bb6f8326859..c74efe40b84 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -1910,7 +1910,6 @@ NS_NewHTMLElement(already_AddRefed 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) diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index 2fe32b5d353..1e86cea0ceb 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -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; } diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index fd2af330046..530a417448b 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -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; diff --git a/content/html/content/test/forms/test_valueasdate_attribute.html b/content/html/content/test/forms/test_valueasdate_attribute.html index 6a8fb54c176..7fc8d09ffa3 100644 --- a/content/html/content/test/forms/test_valueasdate_attribute.html +++ b/content/html/content/test/forms/test_valueasdate_attribute.html @@ -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(); }); diff --git a/content/media/omx/OmxDecoder.cpp b/content/media/omx/OmxDecoder.cpp index ea33c6dad7a..4e28f0a495f 100644 --- a/content/media/omx/OmxDecoder.cpp +++ b/content/media/omx/OmxDecoder.cpp @@ -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; diff --git a/dom/activities/src/ActivitiesService.jsm b/dom/activities/src/ActivitiesService.jsm index e8bad41a371..8c3ae9c4c57 100644 --- a/dom/activities/src/ActivitiesService.jsm +++ b/dom/activities/src/ActivitiesService.jsm @@ -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 }); diff --git a/dom/alarm/AlarmService.jsm b/dom/alarm/AlarmService.jsm index f9500e9982e..d28152f6f96 100644 --- a/dom/alarm/AlarmService.jsm +++ b/dom/alarm/AlarmService.jsm @@ -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( diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index 88de1c38b47..cfb01e23d1c 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -496,7 +496,6 @@ this.DOMApplicationRegistry = { if (aRunUpdate) { activitiesToRegister.push({ "manifest": aApp.manifestURL, "name": activity, - "title": manifest.name, "icon": manifest.iconURLForSize(128), "description": description }); } diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index fb612c6a362..2bc71830cad 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -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) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 07d121e7a07..82f58217ad8 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -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 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, diff --git a/dom/camera/DOMCameraControl.cpp b/dom/camera/DOMCameraControl.cpp old mode 100755 new mode 100644 diff --git a/dom/camera/GonkCameraControl.cpp b/dom/camera/GonkCameraControl.cpp index 5e25c9e0052..e85562bf642 100644 --- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -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 releaseHardwareResult = new ReleaseHardwareResult(aReleaseHardware->mOnSuccessCb, mWindowId); diff --git a/dom/camera/GonkCameraHwMgr.cpp b/dom/camera/GonkCameraHwMgr.cpp index 36c0fe5ce14..24281e58e20 100644 --- a/dom/camera/GonkCameraHwMgr.cpp +++ b/dom/camera/GonkCameraHwMgr.cpp @@ -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 } diff --git a/dom/camera/GonkCameraHwMgr.h b/dom/camera/GonkCameraHwMgr.h index a028e0082c7..78c09ddadeb 100644 --- a/dom/camera/GonkCameraHwMgr.h +++ b/dom/camera/GonkCameraHwMgr.h @@ -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); /** diff --git a/dom/devicestorage/DeviceStorageRequestParent.cpp b/dom/devicestorage/DeviceStorageRequestParent.cpp index 78076842671..25a6ceb38bf 100644 --- a/dom/devicestorage/DeviceStorageRequestParent.cpp +++ b/dom/devicestorage/DeviceStorageRequestParent.cpp @@ -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 { diff --git a/dom/indexedDB/ipc/IndexedDBParent.cpp b/dom/indexedDB/ipc/IndexedDBParent.cpp index 963c9797b9d..f87de87201b 100644 --- a/dom/indexedDB/ipc/IndexedDBParent.cpp +++ b/dom/indexedDB/ipc/IndexedDBParent.cpp @@ -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" diff --git a/dom/ipc/AppProcessPermissions.cpp b/dom/ipc/AppProcessChecker.cpp similarity index 51% rename from dom/ipc/AppProcessPermissions.cpp rename to dom/ipc/AppProcessChecker.cpp index 25779bede27..9491413afec 100644 --- a/dom/ipc/AppProcessPermissions.cpp +++ b/dom/ipc/AppProcessChecker.cpp @@ -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(aActor); nsCOMPtr 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(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& 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 diff --git a/dom/ipc/AppProcessChecker.h b/dom/ipc/AppProcessChecker.h new file mode 100644 index 00000000000..ddf2ca1910d --- /dev/null +++ b/dom/ipc/AppProcessChecker.h @@ -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 +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 +inline bool +AssertAppProcessManifestURL(T* aActor, + const char* aManifestURL) { + return AssertAppProcess(aActor, + ASSERT_APP_PROCESS_MANIFEST_URL, + aManifestURL); +} + +} // namespace mozilla + +#endif // mozilla_AppProcessChecker_h diff --git a/dom/ipc/AppProcessPermissions.h b/dom/ipc/AppProcessPermissions.h deleted file mode 100644 index 94472d998dd..00000000000 --- a/dom/ipc/AppProcessPermissions.h +++ /dev/null @@ -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 diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 36d27c6a960..3f8ee084065 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -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(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 diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 08ff510f0a4..fb162a9bc14 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -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); diff --git a/dom/ipc/Makefile.in b/dom/ipc/Makefile.in index d4127692fc6..8dca179ca4b 100644 --- a/dom/ipc/Makefile.in +++ b/dom/ipc/Makefile.in @@ -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 \ diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 3aa899aa624..c9a1619971c 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.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; } diff --git a/dom/messages/SystemMessageInternal.js b/dom/messages/SystemMessageInternal.js index 42bd371cf25..ad452a42668 100644 --- a/dom/messages/SystemMessageInternal.js +++ b/dom/messages/SystemMessageInternal.js @@ -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; diff --git a/dom/network/src/TCPSocketParent.cpp b/dom/network/src/TCPSocketParent.cpp index e1d2a88d952..99fceff80a0 100644 --- a/dom/network/src/TCPSocketParent.cpp +++ b/dom/network/src/TCPSocketParent.cpp @@ -8,7 +8,7 @@ #include "nsJSUtils.h" #include "nsIDOMTCPSocket.h" #include "mozilla/unused.h" -#include "mozilla/AppProcessPermissions.h" +#include "mozilla/AppProcessChecker.h" namespace IPC { diff --git a/dom/settings/SettingsManager.js b/dom/settings/SettingsManager.js index 8c3fba78b8a..64f44a295b4 100644 --- a/dom/settings/SettingsManager.js +++ b/dom/settings/SettingsManager.js @@ -4,7 +4,7 @@ "use strict"; -const DEBUG = true; +const DEBUG = false; function debug(s) { if (DEBUG) dump("-*- SettingsManager: " + s + "\n"); } diff --git a/dom/tests/browser/browser_bug396843.js b/dom/tests/browser/browser_bug396843.js index 054f4aa9ffe..085f36533a5 100644 --- a/dom/tests/browser/browser_bug396843.js +++ b/dom/tests/browser/browser_bug396843.js @@ -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") diff --git a/dom/tests/mochitest/bugs/test_bug396843.html b/dom/tests/mochitest/bugs/test_bug396843.html index 55f936ea6c7..bdda2f8bc74 100644 --- a/dom/tests/mochitest/bugs/test_bug396843.html +++ b/dom/tests/mochitest/bugs/test_bug396843.html @@ -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") diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index 535d5b70df6..fb773ed7859 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -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" diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index e68cab25a3d..bc6677c3c70 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -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 native; + rv = nsDOMMultipartFile::NewBlob(getter_AddRefs(native)); + if (NS_FAILED(rv)) { + XPCThrower::Throw(rv, cx); + return false; + } + + nsCOMPtr 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 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 }; diff --git a/js/xpconnect/tests/unit/component-blob.js b/js/xpconnect/tests/unit/component-blob.js new file mode 100644 index 00000000000..e153e01545a --- /dev/null +++ b/js/xpconnect/tests/unit/component-blob.js @@ -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 = "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); diff --git a/js/xpconnect/tests/unit/component-blob.manifest b/js/xpconnect/tests/unit/component-blob.manifest new file mode 100644 index 00000000000..ac264c06d55 --- /dev/null +++ b/js/xpconnect/tests/unit/component-blob.manifest @@ -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} diff --git a/js/xpconnect/tests/unit/test_blob.js b/js/xpconnect/tests/unit/test_blob.js new file mode 100644 index 00000000000..039f45102ef --- /dev/null +++ b/js/xpconnect/tests/unit/test_blob.js @@ -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()); + +} diff --git a/js/xpconnect/tests/unit/xpcshell.ini b/js/xpconnect/tests/unit/xpcshell.ini index d677ef9414d..b7d0bc2d396 100644 --- a/js/xpconnect/tests/unit/xpcshell.ini +++ b/js/xpconnect/tests/unit/xpcshell.ini @@ -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] diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py index 1111c6310a8..88adde9d621 100644 --- a/layout/tools/reftest/runreftestb2g.py +++ b/layout/tools/reftest/runreftestb2g.py @@ -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: diff --git a/parser/htmlparser/public/nsHTMLTagList.h b/parser/htmlparser/public/nsHTMLTagList.h index 525023aa748..898336f05f7 100644 --- a/parser/htmlparser/public/nsHTMLTagList.h +++ b/parser/htmlparser/public/nsHTMLTagList.h @@ -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) diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py index 93f3ace07f1..319fd31cf6f 100644 --- a/testing/mochitest/runtestsb2g.py +++ b/testing/mochitest/runtestsb2g.py @@ -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 diff --git a/widget/windows/nsTextStore.cpp b/widget/windows/nsTextStore.cpp index f529600132f..87dfd50035b 100644 --- a/widget/windows/nsTextStore.cpp +++ b/widget/windows/nsTextStore.cpp @@ -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(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 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( - 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( + 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( - 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( + 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; diff --git a/widget/windows/nsTextStore.h b/widget/windows/nsTextStore.h index 832b87ccc05..b04d819806c 100644 --- a/widget/windows/nsTextStore.h +++ b/widget/windows/nsTextStore.h @@ -11,6 +11,7 @@ #include "nsCOMPtr.h" #include "nsITimer.h" #include "nsIWidget.h" +#include "nsWindowBase.h" #include "mozilla/Attributes.h" #include @@ -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 mWidget; // Document manager for the currently focused editor nsRefPtr mDocumentMgr; // Edit cookie associated with the current editing context @@ -202,8 +210,6 @@ protected: nsRefPtr 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 diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index a88cbf3e027..14ae0ec4b3a 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -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 } diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index 763a5badb02..5fca2e5af4c 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -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); diff --git a/widget/windows/nsWindowBase.h b/widget/windows/nsWindowBase.h new file mode 100644 index 00000000000..38643b63e3a --- /dev/null +++ b/widget/windows/nsWindowBase.h @@ -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(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_