Merge mozilla-central and inbound
This commit is contained in:
3
CLOBBER
3
CLOBBER
@@ -17,4 +17,5 @@
|
||||
#
|
||||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||
#
|
||||
Bug 870180 - CPOWs
|
||||
Bug 889503 - Move Settings API to WebIDL.
|
||||
Requires a clobber due to Bug 890744.
|
||||
|
||||
@@ -6868,7 +6868,7 @@ var gIdentityHandler = {
|
||||
continue;
|
||||
let menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("value", state);
|
||||
menuitem.setAttribute("label", SitePermissions.getStateLabel(state));
|
||||
menuitem.setAttribute("label", SitePermissions.getStateLabel(aPermission, state));
|
||||
menupopup.appendChild(menuitem);
|
||||
}
|
||||
menulist.appendChild(menupopup);
|
||||
|
||||
@@ -134,7 +134,7 @@ function createRow(aPartId) {
|
||||
for (let state of SitePermissions.getAvailableStates(aPartId)) {
|
||||
let radio = document.createElement("radio");
|
||||
radio.setAttribute("id", aPartId + "#" + state);
|
||||
radio.setAttribute("label", SitePermissions.getStateLabel(state));
|
||||
radio.setAttribute("label", SitePermissions.getStateLabel(aPartId, state));
|
||||
radio.setAttribute("command", commandId);
|
||||
radiogroup.appendChild(radio);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ let Cu = Components.utils;
|
||||
|
||||
const appStartup = Services.startup;
|
||||
|
||||
Cu.import("resource://gre/modules/ResetProfile.jsm");
|
||||
|
||||
let defaultToReset = false;
|
||||
|
||||
function restartApp() {
|
||||
@@ -69,7 +71,7 @@ function onLoad() {
|
||||
if (appStartup.automaticSafeModeNecessary) {
|
||||
document.getElementById("autoSafeMode").hidden = false;
|
||||
document.getElementById("safeMode").hidden = true;
|
||||
if (resetSupported()) {
|
||||
if (ResetProfile.resetSupported()) {
|
||||
populateResetPane("resetProfileItems");
|
||||
document.getElementById("resetProfile").hidden = false;
|
||||
} else {
|
||||
@@ -77,7 +79,7 @@ function onLoad() {
|
||||
document.documentElement.getButton("extra1").hidden = true;
|
||||
}
|
||||
} else {
|
||||
if (!resetSupported()) {
|
||||
if (!ResetProfile.resetSupported()) {
|
||||
// Hide the reset button and text if it's not supported.
|
||||
document.documentElement.getButton("extra1").hidden = true;
|
||||
document.getElementById("resetProfileInstead").hidden = true;
|
||||
|
||||
@@ -200,8 +200,24 @@ function checkSocialUI(win) {
|
||||
let active = Social.providers.length > 0 && !win.SocialUI._chromeless &&
|
||||
!PrivateBrowsingUtils.isWindowPrivate(win);
|
||||
|
||||
// some local helpers to avoid log-spew for the many checks made here.
|
||||
let numGoodTests = 0, numTests = 0;
|
||||
function _ok(what, msg) {
|
||||
numTests++;
|
||||
if (!ok)
|
||||
ok(what, msg)
|
||||
else
|
||||
++numGoodTests;
|
||||
}
|
||||
function _is(a, b, msg) {
|
||||
numTests++;
|
||||
if (a != b)
|
||||
is(a, b, msg)
|
||||
else
|
||||
++numGoodTests;
|
||||
}
|
||||
function isbool(a, b, msg) {
|
||||
is(!!a, !!b, msg);
|
||||
_is(!!a, !!b, msg);
|
||||
}
|
||||
isbool(win.SocialSidebar.canShow, enabled, "social sidebar active?");
|
||||
if (enabled)
|
||||
@@ -216,15 +232,15 @@ function checkSocialUI(win) {
|
||||
isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?");
|
||||
if (active) {
|
||||
if (!enabled) {
|
||||
ok(!win.SocialToolbar.button.style.listStyleImage, "toolbar button is default icon");
|
||||
_ok(!win.SocialToolbar.button.style.listStyleImage, "toolbar button is default icon");
|
||||
} else {
|
||||
is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
|
||||
_is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
|
||||
}
|
||||
}
|
||||
// the menus should always have the provider name
|
||||
if (provider) {
|
||||
for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"])
|
||||
is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
|
||||
_is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
|
||||
}
|
||||
|
||||
// and for good measure, check all the social commands.
|
||||
@@ -232,10 +248,12 @@ function checkSocialUI(win) {
|
||||
isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
|
||||
isbool(!doc.getElementById("Social:FocusChat").hidden, enabled && Social.haveLoggedInUser(), "Social:FocusChat visible?");
|
||||
isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
|
||||
is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
|
||||
_is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
|
||||
|
||||
// broadcasters.
|
||||
isbool(!doc.getElementById("socialActiveBroadcaster").hidden, active, "socialActiveBroadcaster hidden?");
|
||||
// and report on overall success of failure of the various checks here.
|
||||
is(numGoodTests, numTests, "The Social UI tests succeeded.")
|
||||
}
|
||||
|
||||
// blocklist testing
|
||||
|
||||
@@ -1180,6 +1180,9 @@ var StartUI = {
|
||||
// of the keyboard transition.
|
||||
ContentAreaObserver.navBarWillBlur();
|
||||
}
|
||||
|
||||
if (aEvent.button == 0)
|
||||
ContextUI.dismissTabs();
|
||||
},
|
||||
|
||||
handleEvent: function handleEvent(aEvent) {
|
||||
|
||||
@@ -89,11 +89,11 @@ this.SitePermissions = {
|
||||
|
||||
/* Removes the saved state of a particular permission for a given URI.
|
||||
*/
|
||||
remove: function (aURI, aPermission) {
|
||||
remove: function (aURI, aPermissionID) {
|
||||
if (!this.isSupportedURI(aURI))
|
||||
return;
|
||||
|
||||
Services.perms.remove(aURI.host, aPermission);
|
||||
Services.perms.remove(aURI.host, aPermissionID);
|
||||
|
||||
if (aPermissionID in gPermissionObject &&
|
||||
gPermissionObject[aPermissionID].onChange)
|
||||
@@ -110,7 +110,14 @@ this.SitePermissions = {
|
||||
/* Returns the localized label for the given permission state, to be used in
|
||||
* a UI for managing permissions.
|
||||
*/
|
||||
getStateLabel: function (aState) {
|
||||
getStateLabel: function (aPermissionID, aState) {
|
||||
if (aPermissionID in gPermissionObject &&
|
||||
gPermissionObject[aPermissionID].getStateLabel) {
|
||||
let label = gPermissionObject[aPermissionID].getStateLabel(aState);
|
||||
if (label)
|
||||
return label;
|
||||
}
|
||||
|
||||
switch (aState) {
|
||||
case this.UNKNOWN:
|
||||
return gStringBundle.GetStringFromName("alwaysAsk");
|
||||
@@ -140,6 +147,11 @@ let gPermissionObject = {
|
||||
* Defaults to UNKNOWN, indicating that the user will be asked each time
|
||||
* a page asks for that permissions.
|
||||
*
|
||||
* - getStateLabel
|
||||
* Called to get the localized label for the given permission state, to be
|
||||
* used in a UI for managing permissions. May return null for states that
|
||||
* should use their default label.
|
||||
*
|
||||
* - onChange
|
||||
* Called when a permission state changes.
|
||||
*
|
||||
@@ -189,8 +201,18 @@ let gPermissionObject = {
|
||||
},
|
||||
|
||||
"indexedDB": {
|
||||
getDefault: function () {
|
||||
return SitePermissions.ALLOW;
|
||||
states: [ SitePermissions.ALLOW, SitePermissions.UNKNOWN, SitePermissions.BLOCK ],
|
||||
getStateLabel: function (aState) {
|
||||
// indexedDB redefines nsIPermissionManager.UNKNOWN_ACTION (the default)
|
||||
// as "allow" and nsIPermissionManager.ALLOW_ACTION as "ask the user."
|
||||
switch (aState) {
|
||||
case SitePermissions.UNKNOWN:
|
||||
return gStringBundle.GetStringFromName("allow");
|
||||
case SitePermissions.ALLOW:
|
||||
return gStringBundle.GetStringFromName("alwaysAsk");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onChange: function (aURI, aState) {
|
||||
if (aState == SitePermissions.ALLOW || aState == SitePermissions.BLOCK)
|
||||
|
||||
@@ -2750,8 +2750,11 @@ nsDocument::SetDocumentURI(nsIURI* aURI)
|
||||
nsIURI* newBase = GetDocBaseURI();
|
||||
|
||||
bool equalBases = false;
|
||||
// Changing just the ref of a URI does not change how relative URIs would
|
||||
// resolve wrt to it, so we can treat the bases as equal as long as they're
|
||||
// equal ignoring the ref.
|
||||
if (oldBase && newBase) {
|
||||
oldBase->Equals(newBase, &equalBases);
|
||||
oldBase->EqualsExceptRef(newBase, &equalBases);
|
||||
}
|
||||
else {
|
||||
equalBases = !oldBase && !newBase;
|
||||
|
||||
@@ -3350,8 +3350,8 @@ nsObjectLoadingContent::TeardownProtoChain()
|
||||
|
||||
bool
|
||||
nsObjectLoadingContent::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
||||
JS::Handle<jsid> aId, unsigned aFlags,
|
||||
JS::MutableHandle<JSObject*> aObjp)
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
// We don't resolve anything; we just try to make sure we're instantiated
|
||||
|
||||
|
||||
@@ -148,8 +148,9 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
void TeardownProtoChain();
|
||||
|
||||
// Helper for WebIDL newResolve
|
||||
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject, JS::Handle<jsid> aId,
|
||||
unsigned aFlags, JS::MutableHandle<JSObject*> aObjp);
|
||||
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
// WebIDL API
|
||||
nsIDocument* GetContentDocument();
|
||||
|
||||
@@ -3296,6 +3296,8 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
|
||||
// gfxContext-over-Azure may modify the DrawTarget's transform, so
|
||||
// save and restore it
|
||||
Matrix matrix = mTarget->GetTransform();
|
||||
double sw = matrix._11 * w;
|
||||
double sh = matrix._22 * h;
|
||||
nsRefPtr<gfxContext> thebes;
|
||||
nsRefPtr<gfxASurface> drawSurf;
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget)) {
|
||||
@@ -3304,7 +3306,7 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
|
||||
matrix._22, matrix._31, matrix._32));
|
||||
} else {
|
||||
drawSurf =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(ceil(w), ceil(h)),
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(ceil(sw), ceil(sh)),
|
||||
gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
if (!drawSurf) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
@@ -3314,6 +3316,7 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
|
||||
drawSurf->SetDeviceOffset(gfxPoint(-floor(x), -floor(y)));
|
||||
thebes = new gfxContext(drawSurf);
|
||||
thebes->Translate(gfxPoint(floor(x), floor(y)));
|
||||
thebes->Scale(matrix._11, matrix._22);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
|
||||
@@ -3333,8 +3336,9 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
|
||||
IntSize(size.width, size.height),
|
||||
img->Stride(),
|
||||
FORMAT_B8G8R8A8);
|
||||
mgfx::Rect rect(0, 0, w, h);
|
||||
mTarget->DrawSurface(data, rect, rect);
|
||||
mgfx::Rect destRect(0, 0, w, h);
|
||||
mgfx::Rect sourceRect(0, 0, sw, sh);
|
||||
mTarget->DrawSurface(data, destRect, sourceRect);
|
||||
mTarget->Flush();
|
||||
} else {
|
||||
mTarget->SetTransform(matrix);
|
||||
|
||||
@@ -176,12 +176,13 @@ AudioContext::CreateBuffer(JSContext* aJSContext, ArrayBuffer& aBuffer,
|
||||
aBuffer.Data(), aBuffer.Length(),
|
||||
contentType);
|
||||
|
||||
WebAudioDecodeJob job(contentType, this);
|
||||
nsRefPtr<WebAudioDecodeJob> job =
|
||||
new WebAudioDecodeJob(contentType, this, aBuffer);
|
||||
|
||||
if (mDecoder.SyncDecodeMedia(contentType.get(),
|
||||
aBuffer.Data(), aBuffer.Length(), job) &&
|
||||
job.mOutput) {
|
||||
nsRefPtr<AudioBuffer> buffer = job.mOutput.forget();
|
||||
aBuffer.Data(), aBuffer.Length(), *job) &&
|
||||
job->mOutput) {
|
||||
nsRefPtr<AudioBuffer> buffer = job->mOutput.forget();
|
||||
if (aMixToMono) {
|
||||
buffer->MixToMono(aJSContext);
|
||||
}
|
||||
@@ -374,8 +375,8 @@ AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
|
||||
if (aFailureCallback.WasPassed()) {
|
||||
failureCallback = &aFailureCallback.Value();
|
||||
}
|
||||
nsAutoPtr<WebAudioDecodeJob> job(
|
||||
new WebAudioDecodeJob(contentType, this,
|
||||
nsRefPtr<WebAudioDecodeJob> job(
|
||||
new WebAudioDecodeJob(contentType, this, aBuffer,
|
||||
&aSuccessCallback, failureCallback));
|
||||
mDecoder.AsyncDecodeMedia(contentType.get(),
|
||||
aBuffer.Data(), aBuffer.Length(), *job);
|
||||
|
||||
@@ -227,7 +227,7 @@ private:
|
||||
nsRefPtr<AudioDestinationNode> mDestination;
|
||||
nsRefPtr<AudioListener> mListener;
|
||||
MediaBufferDecoder mDecoder;
|
||||
nsTArray<nsAutoPtr<WebAudioDecodeJob> > mDecodeJobs;
|
||||
nsTArray<nsRefPtr<WebAudioDecodeJob> > mDecodeJobs;
|
||||
// Two hashsets containing all the PannerNodes and AudioBufferSourceNodes,
|
||||
// to compute the doppler shift, and also to stop AudioBufferSourceNodes.
|
||||
// These are all weak pointers.
|
||||
|
||||
@@ -25,6 +25,29 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebAudioDecodeJob)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutput)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuccessCallback)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFailureCallback)
|
||||
tmp->mArrayBuffer = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebAudioDecodeJob)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutput)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuccessCallback)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFailureCallback)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArrayBuffer)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebAudioDecodeJob, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release)
|
||||
|
||||
using namespace dom;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
@@ -793,6 +816,7 @@ MediaBufferDecoder::Shutdown() {
|
||||
|
||||
WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
|
||||
AudioContext* aContext,
|
||||
const ArrayBuffer& aBuffer,
|
||||
DecodeSuccessCallback* aSuccessCallback,
|
||||
DecodeErrorCallback* aFailureCallback)
|
||||
: mContentType(aContentType)
|
||||
@@ -805,15 +829,21 @@ WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_CTOR(WebAudioDecodeJob);
|
||||
|
||||
mArrayBuffer = aBuffer.Obj();
|
||||
|
||||
MOZ_ASSERT(aSuccessCallback ||
|
||||
(!aSuccessCallback && !aFailureCallback),
|
||||
"If a success callback is not passed, no failure callback should be passed either");
|
||||
|
||||
nsContentUtils::HoldJSObjects(this, NS_CYCLE_COLLECTION_PARTICIPANT(WebAudioDecodeJob));
|
||||
}
|
||||
|
||||
WebAudioDecodeJob::~WebAudioDecodeJob()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_DTOR(WebAudioDecodeJob);
|
||||
mArrayBuffer = nullptr;
|
||||
nsContentUtils::DropJSObjects(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -26,16 +26,20 @@ class DecodeErrorCallback;
|
||||
class DecodeSuccessCallback;
|
||||
}
|
||||
|
||||
struct WebAudioDecodeJob
|
||||
struct WebAudioDecodeJob MOZ_FINAL
|
||||
{
|
||||
// You may omit both the success and failure callback, or you must pass both.
|
||||
// The callbacks are only necessary for asynchronous operation.
|
||||
WebAudioDecodeJob(const nsACString& aContentType,
|
||||
dom::AudioContext* aContext,
|
||||
const dom::ArrayBuffer& aBuffer,
|
||||
dom::DecodeSuccessCallback* aSuccessCallback = nullptr,
|
||||
dom::DecodeErrorCallback* aFailureCallback = nullptr);
|
||||
~WebAudioDecodeJob();
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebAudioDecodeJob)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebAudioDecodeJob)
|
||||
|
||||
enum ErrorCode {
|
||||
NoError,
|
||||
UnknownContent,
|
||||
@@ -52,6 +56,8 @@ struct WebAudioDecodeJob
|
||||
|
||||
bool AllocateBuffer();
|
||||
|
||||
|
||||
JS::Heap<JSObject*> mArrayBuffer;
|
||||
nsCString mContentType;
|
||||
uint32_t mWriteIndex;
|
||||
nsRefPtr<dom::AudioContext> mContext;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,7 @@ class nsIDOMMozConnection;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Geolocation;
|
||||
class systemMessageCallback;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +70,8 @@ class nsIDOMTelephony;
|
||||
// Navigator: Script "navigator" object
|
||||
//*****************************************************************************
|
||||
|
||||
void NS_GetNavigatorAppName(nsAString& aAppName);
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -79,6 +82,15 @@ class BatteryManager;
|
||||
class DesktopNotificationCenter;
|
||||
class SmsManager;
|
||||
class MobileMessageManager;
|
||||
class MozIdleObserver;
|
||||
#ifdef MOZ_GAMEPAD
|
||||
class Gamepad;
|
||||
#endif // MOZ_GAMEPAD
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
class MozDOMGetUserMediaSuccessCallback;
|
||||
class MozDOMGetUserMediaErrorCallback;
|
||||
class MozGetUserMediaDevicesSuccessCallback;
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
|
||||
namespace icc {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
@@ -192,7 +204,7 @@ public:
|
||||
static void Init();
|
||||
|
||||
void Invalidate();
|
||||
nsPIDOMWindow *GetWindow()
|
||||
nsPIDOMWindow *GetWindow() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
@@ -218,8 +230,186 @@ public:
|
||||
|
||||
NS_DECL_NSIDOMNAVIGATORCAMERA
|
||||
|
||||
// WebIDL API
|
||||
void GetAppName(nsString& aAppName)
|
||||
{
|
||||
NS_GetNavigatorAppName(aAppName);
|
||||
}
|
||||
void GetAppVersion(nsString& aAppVersion, ErrorResult& aRv)
|
||||
{
|
||||
aRv = GetAppVersion(aAppVersion);
|
||||
}
|
||||
void GetPlatform(nsString& aPlatform, ErrorResult& aRv)
|
||||
{
|
||||
aRv = GetPlatform(aPlatform);
|
||||
}
|
||||
void GetUserAgent(nsString& aUserAgent, ErrorResult& aRv)
|
||||
{
|
||||
aRv = GetUserAgent(aUserAgent);
|
||||
}
|
||||
// The XPCOM GetProduct is OK
|
||||
// The XPCOM GetLanguage is OK
|
||||
bool OnLine();
|
||||
void RegisterProtocolHandler(const nsAString& aScheme, const nsAString& aURL,
|
||||
const nsAString& aTitle, ErrorResult& rv)
|
||||
{
|
||||
rv = RegisterProtocolHandler(aScheme, aURL, aTitle);
|
||||
}
|
||||
void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
|
||||
const nsAString& aTitle, ErrorResult& rv)
|
||||
{
|
||||
rv = RegisterContentHandler(aMIMEType, aURL, aTitle);
|
||||
}
|
||||
nsMimeTypeArray* GetMimeTypes(ErrorResult& aRv);
|
||||
nsPluginArray* GetPlugins(ErrorResult& aRv);
|
||||
// The XPCOM GetDoNotTrack is ok
|
||||
Geolocation* GetGeolocation(ErrorResult& aRv);
|
||||
battery::BatteryManager* GetBattery(ErrorResult& aRv);
|
||||
void Vibrate(uint32_t aDuration, ErrorResult& aRv);
|
||||
void Vibrate(const nsTArray<uint32_t>& aDuration, ErrorResult& aRv);
|
||||
void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
|
||||
{
|
||||
aRv = GetAppCodeName(aAppCodeName);
|
||||
}
|
||||
void GetOscpu(nsString& aOscpu, ErrorResult& aRv)
|
||||
{
|
||||
aRv = GetOscpu(aOscpu);
|
||||
}
|
||||
// The XPCOM GetVendor is OK
|
||||
// The XPCOM GetVendorSub is OK
|
||||
// The XPCOM GetProductSub is OK
|
||||
bool CookieEnabled();
|
||||
void GetBuildID(nsString& aBuildID, ErrorResult& aRv)
|
||||
{
|
||||
aRv = GetBuildID(aBuildID);
|
||||
}
|
||||
nsIDOMMozPowerManager* GetMozPower(ErrorResult& aRv);
|
||||
bool JavaEnabled(ErrorResult& aRv);
|
||||
bool TaintEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
|
||||
void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
|
||||
already_AddRefed<nsIDOMMozWakeLock> RequestWakeLock(const nsAString &aTopic,
|
||||
ErrorResult& aRv);
|
||||
nsDOMDeviceStorage* GetDeviceStorage(const nsAString& aType,
|
||||
ErrorResult& aRv);
|
||||
void GetDeviceStorages(const nsAString& aType,
|
||||
nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
|
||||
ErrorResult& aRv);
|
||||
DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
|
||||
bool MozIsLocallyAvailable(const nsAString& aURI, bool aWhenOffline,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
bool available = false;
|
||||
aRv = MozIsLocallyAvailable(aURI, aWhenOffline, &available);
|
||||
return available;
|
||||
}
|
||||
nsIDOMMozSmsManager* GetMozSms();
|
||||
nsIDOMMozMobileMessageManager* GetMozMobileMessage();
|
||||
nsIDOMMozConnection* GetMozConnection();
|
||||
nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
|
||||
void MozSetMessageHandler(const nsAString& aType,
|
||||
systemMessageCallback* aCallback,
|
||||
ErrorResult& aRv);
|
||||
bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
|
||||
#ifdef MOZ_B2G_RIL
|
||||
nsIDOMTelephony* GetMozTelephony(ErrorResult& aRv);
|
||||
nsIDOMMozMobileConnection* GetMozMobileConnection(ErrorResult& aRv);
|
||||
nsIDOMMozCellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
|
||||
nsIDOMMozVoicemail* GetMozVoicemail(ErrorResult& aRv);
|
||||
nsIDOMMozIccManager* GetMozIccManager(ErrorResult& aRv);
|
||||
#endif // MOZ_B2G_RIL
|
||||
#ifdef MOZ_GAMEPAD
|
||||
void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
|
||||
#endif // MOZ_GAMEPAD
|
||||
#ifdef MOZ_B2G_BT
|
||||
nsIDOMBluetoothManager* GetMozBluetooth(ErrorResult& aRv);
|
||||
#endif // MOZ_B2G_BT
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
time::TimeManager* GetMozTime(ErrorResult& aRv);
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
|
||||
system::AudioChannelManager* GetMozAudioChannelManager(ErrorResult& aRv);
|
||||
#endif // MOZ_AUDIO_CHANNEL_MANAGER
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
void MozGetUserMedia(nsIMediaStreamOptions* aParams,
|
||||
MozDOMGetUserMediaSuccessCallback* aOnSuccess,
|
||||
MozDOMGetUserMediaErrorCallback* aOnError,
|
||||
ErrorResult& aRv);
|
||||
void MozGetUserMedia(nsIMediaStreamOptions* aParams,
|
||||
nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
|
||||
nsIDOMGetUserMediaErrorCallback* aOnError,
|
||||
ErrorResult& aRv);
|
||||
void MozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback* aOnSuccess,
|
||||
MozDOMGetUserMediaErrorCallback* aOnError,
|
||||
ErrorResult& aRv);
|
||||
void MozGetUserMediaDevices(nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
|
||||
nsIDOMGetUserMediaErrorCallback* aOnError,
|
||||
ErrorResult& aRv);
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
||||
JS::Handle<jsid> aId, JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
// WebIDL helper methods
|
||||
static bool HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */);
|
||||
static bool HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
static bool HasIdleSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
|
||||
static bool HasDesktopNotificationSupport(JSContext* /* unused*/,
|
||||
JSObject* /*unused */)
|
||||
{
|
||||
return HasDesktopNotificationSupport();
|
||||
}
|
||||
static bool HasSmsSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
static bool HasMobileMessageSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasCameraSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
#ifdef MOZ_B2G_RIL
|
||||
static bool HasTelephonySupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasMobileConnectionSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasCellBroadcastSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasVoicemailSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasIccManagerSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_RIL
|
||||
#ifdef MOZ_B2G_BT
|
||||
static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_BT
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
static bool HasUserMediaSupport(JSContext* /* unused */,
|
||||
JSObject* /* unused */);
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return GetWindow();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx,
|
||||
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
bool CheckPermission(const char* type);
|
||||
static bool CheckPermission(nsPIDOMWindow* aWindow, const char* aType);
|
||||
static bool HasMobileMessageSupport(nsPIDOMWindow* aWindow);
|
||||
// GetWindowFromGlobal returns the inner window for this global, if
|
||||
// any, else null.
|
||||
static already_AddRefed<nsPIDOMWindow> GetWindowFromGlobal(JSObject* aGlobal);
|
||||
|
||||
// Methods to common up the XPCOM and WebIDL implementations of
|
||||
// Add/RemoveIdleObserver.
|
||||
void AddIdleObserver(nsIIdleObserver& aIdleObserver);
|
||||
void RemoveIdleObserver(nsIIdleObserver& aIdleObserver);
|
||||
|
||||
nsRefPtr<nsMimeTypeArray> mMimeTypes;
|
||||
nsRefPtr<nsPluginArray> mPlugins;
|
||||
@@ -258,6 +448,5 @@ private:
|
||||
nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
|
||||
nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
|
||||
nsresult NS_GetNavigatorAppVersion(nsAString& aAppVersion);
|
||||
nsresult NS_GetNavigatorAppName(nsAString& aAppName);
|
||||
|
||||
#endif // mozilla_dom_Navigator_h
|
||||
|
||||
@@ -129,7 +129,6 @@
|
||||
#include "nsIXSLTProcessorPrivate.h"
|
||||
|
||||
#include "nsXMLHttpRequest.h"
|
||||
#include "nsIDOMSettingsManager.h"
|
||||
#include "nsIDOMContactManager.h"
|
||||
#include "nsIDOMPermissionSettings.h"
|
||||
#include "nsIDOMApplicationRegistry.h"
|
||||
@@ -4660,101 +4659,24 @@ nsNavigatorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, aObj);
|
||||
JS::Rooted<jsid> id(cx, aId);
|
||||
if (!JSID_IS_STRING(id)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsScriptNameSpaceManager *nameSpaceManager =
|
||||
nsJSRuntime::GetNameSpaceManager();
|
||||
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsDependentJSString name(id);
|
||||
|
||||
const nsGlobalNameStruct* name_struct =
|
||||
nameSpaceManager->LookupNavigatorName(name);
|
||||
if (!name_struct) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
|
||||
mozilla::dom::ConstructNavigatorProperty construct = name_struct->mConstructNavigatorProperty;
|
||||
MOZ_ASSERT(construct);
|
||||
|
||||
JS::Rooted<JSObject*> naviObj(cx, js::CheckedUnwrap(obj, /* stopAtOuter = */ false));
|
||||
NS_ENSURE_TRUE(naviObj, NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
||||
JS::Rooted<JSObject*> domObject(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, naviObj);
|
||||
|
||||
// Check whether our constructor is enabled after we unwrap Xrays, since
|
||||
// we don't want to define an interface on the Xray if it's disabled in
|
||||
// the target global, even if it's enabled in the Xray's global.
|
||||
if (name_struct->mConstructorEnabled &&
|
||||
!(*name_struct->mConstructorEnabled)(cx, naviObj)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
domObject = construct(cx, naviObj);
|
||||
if (!domObject) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JS_WrapObject(cx, domObject.address()) ||
|
||||
!JS_DefinePropertyById(cx, obj, id,
|
||||
JS::ObjectValue(*domObject),
|
||||
nullptr, nullptr, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*_retval = true;
|
||||
*objp = obj;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
|
||||
"unexpected type");
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsISupports> native(do_CreateInstance(name_struct->mCID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JS::Rooted<JS::Value> prop_val(cx, JS::UndefinedValue()); // Property value.
|
||||
|
||||
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
|
||||
|
||||
if (gpi) {
|
||||
nsCOMPtr<nsIDOMNavigator> navigator = do_QueryWrappedNative(wrapper);
|
||||
nsIDOMWindow *window = static_cast<Navigator*>(navigator.get())->GetWindow();
|
||||
NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
|
||||
|
||||
rv = gpi->Init(window, prop_val.address());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
JS::Rooted<JS::Value> value(cx, JS::UndefinedValue());
|
||||
if (!static_cast<Navigator*>(navigator.get())->DoNewResolve(cx, obj, id,
|
||||
&value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) {
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
rv = WrapNative(cx, obj, native, true, prop_val.address(),
|
||||
getter_AddRefs(holder));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!value.isUndefined()) {
|
||||
if (!JS_DefinePropertyById(cx, obj, id, value, JS_PropertyStub,
|
||||
JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!JS_WrapValue(cx, prop_val.address())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
*objp = obj;
|
||||
}
|
||||
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val,
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_ENUMERATE);
|
||||
|
||||
*_retval = true;
|
||||
*objp = obj;
|
||||
|
||||
return ok ? NS_OK : NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -1702,17 +1702,30 @@ addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
|
||||
addExternalIface('LockedFile')
|
||||
addExternalIface('MediaList')
|
||||
addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
|
||||
addExternalIface('MozBluetoothManager', nativeType='nsIDOMBluetoothManager')
|
||||
addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
|
||||
addExternalIface('MozCellBroadcast')
|
||||
addExternalIface('MozConnection', headerFile='nsIDOMConnection.h')
|
||||
addExternalIface('MozControllers', nativeType='nsIControllers')
|
||||
addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
|
||||
addExternalIface('MozIccManager', headerFile='nsIDOMIccManager.h')
|
||||
addExternalIface('MozMediaStreamOptions', nativeType='nsIMediaStreamOptions',
|
||||
headerFile='nsIDOMNavigatorUserMedia.h')
|
||||
addExternalIface('MozMobileConnection', headerFile='nsIDOMMobileConnection.h')
|
||||
addExternalIface('MozMobileMessageManager', headerFile='nsIDOMMobileMessageManager.h')
|
||||
addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
|
||||
addExternalIface('MozPowerManager', headerFile='nsIDOMPowerManager.h')
|
||||
addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
|
||||
notflattened=True)
|
||||
addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
|
||||
addExternalIface('MozSmsManager', headerFile='nsIDOMSmsManager.h')
|
||||
addExternalIface('MozTelephony', nativeType='nsIDOMTelephony')
|
||||
addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
|
||||
notflattened=True)
|
||||
addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
|
||||
headerFile='nsITreeColumns.h')
|
||||
addExternalIface('MozVoicemail')
|
||||
addExternalIface('MozWakeLock', headerFile='nsIDOMWakeLock.h')
|
||||
addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
|
||||
addExternalIface('nsIControllers', nativeType='nsIControllers')
|
||||
addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
|
||||
|
||||
@@ -85,6 +85,9 @@ class CGNativePropertyHooks(CGThing):
|
||||
if self.descriptor.concrete and self.descriptor.proxy:
|
||||
resolveOwnProperty = "ResolveOwnProperty"
|
||||
enumerateOwnProperties = "EnumerateOwnProperties"
|
||||
elif self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
|
||||
resolveOwnProperty = "ResolveOwnPropertyViaNewresolve"
|
||||
enumerateOwnProperties = "nullptr"
|
||||
else:
|
||||
resolveOwnProperty = "nullptr"
|
||||
enumerateOwnProperties = "nullptr"
|
||||
@@ -3732,7 +3735,7 @@ def convertConstIDLValueToJSVal(value):
|
||||
return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
|
||||
if tag in [IDLType.Tags.float, IDLType.Tags.double]:
|
||||
return "DOUBLE_TO_JSVAL(%s)" % (value.value)
|
||||
raise TypeError("Const value of unhandled type: " + value.type)
|
||||
raise TypeError("Const value of unhandled type: %s" % value.type)
|
||||
|
||||
class CGArgumentConverter(CGThing):
|
||||
"""
|
||||
@@ -5130,8 +5133,9 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
|
||||
"""
|
||||
def __init__(self, descriptor, name, args, unwrapFailureCode=None,
|
||||
getThisObj="args.computeThis(cx).toObjectOrNull()",
|
||||
callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);"):
|
||||
CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args)
|
||||
callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);",
|
||||
returnType="JSBool"):
|
||||
CGAbstractStaticMethod.__init__(self, descriptor, name, returnType, args)
|
||||
|
||||
if unwrapFailureCode is None:
|
||||
self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");' % descriptor.interface.identifier.name
|
||||
@@ -5145,13 +5149,14 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
|
||||
# we're someone's consequential interface. But for this-unwrapping, we
|
||||
# know that we're the real deal. So fake a descriptor here for
|
||||
# consumption by CastableObjectUnwrapper.
|
||||
getThis = CGGeneric("""%s
|
||||
JS::RootedObject obj(cx, %s);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
%s* self;""" % (self.callArgs, self.getThisObj, self.descriptor.nativeType))
|
||||
getThis = CGList([
|
||||
CGGeneric(self.callArgs) if self.callArgs != "" else None,
|
||||
CGGeneric("JS::RootedObject obj(cx, %s);\n"
|
||||
"if (!obj) {\n"
|
||||
" return false;\n"
|
||||
"}" % self.getThisObj) if self.getThisObj else None,
|
||||
CGGeneric("%s* self;" % self.descriptor.nativeType)
|
||||
], "\n")
|
||||
unwrapThis = CGGeneric(
|
||||
str(CastableObjectUnwrapper(
|
||||
self.descriptor,
|
||||
@@ -5265,13 +5270,13 @@ class CGNewResolveHook(CGAbstractBindingMethod):
|
||||
"""
|
||||
def __init__(self, descriptor):
|
||||
self._needNewResolve = descriptor.interface.getExtendedAttribute("NeedNewResolve")
|
||||
args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'obj_'),
|
||||
args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'obj'),
|
||||
Argument('JS::Handle<jsid>', 'id'), Argument('unsigned', 'flags'),
|
||||
Argument('JS::MutableHandle<JSObject*>', 'objp')]
|
||||
# Our "self" is actually the callee in this case, not the thisval.
|
||||
CGAbstractBindingMethod.__init__(
|
||||
self, descriptor, NEWRESOLVE_HOOK_NAME,
|
||||
args, getThisObj="obj_", callArgs="")
|
||||
args, getThisObj="", callArgs="")
|
||||
|
||||
def define(self):
|
||||
if not self._needNewResolve:
|
||||
@@ -5279,7 +5284,19 @@ class CGNewResolveHook(CGAbstractBindingMethod):
|
||||
return CGAbstractBindingMethod.define(self)
|
||||
|
||||
def generate_code(self):
|
||||
return CGIndenter(CGGeneric("return self->DoNewResolve(cx, obj, id, flags, objp);"))
|
||||
return CGIndenter(CGGeneric(
|
||||
"JS::Rooted<JS::Value> value(cx);\n"
|
||||
"if (!self->DoNewResolve(cx, obj, id, &value)) {\n"
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
"if (value.isUndefined()) {\n"
|
||||
" return true;\n"
|
||||
"}\n"
|
||||
"if (!JS_DefinePropertyById(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE)) {\n"
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
"objp.set(obj);\n"
|
||||
"return true;"))
|
||||
|
||||
class CppKeywords():
|
||||
"""
|
||||
@@ -6629,7 +6646,7 @@ class CGClass(CGThing):
|
||||
result = result + memberString
|
||||
return result
|
||||
|
||||
class CGResolveOwnProperty(CGAbstractMethod):
|
||||
class CGResolveOwnProperty(CGAbstractStaticMethod):
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'wrapper'),
|
||||
@@ -6637,18 +6654,47 @@ class CGResolveOwnProperty(CGAbstractMethod):
|
||||
Argument('JS::Handle<jsid>', 'id'),
|
||||
Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
|
||||
]
|
||||
CGAbstractMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args)
|
||||
CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
|
||||
"bool", args)
|
||||
def definition_body(self):
|
||||
return """ return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc, flags);
|
||||
"""
|
||||
|
||||
class CGEnumerateOwnProperties(CGAbstractMethod):
|
||||
class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod):
|
||||
"""
|
||||
An implementation of Xray ResolveOwnProperty stuff for things that have a
|
||||
newresolve hook.
|
||||
"""
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'wrapper'),
|
||||
Argument('JS::Handle<JSObject*>', 'obj'),
|
||||
Argument('JS::Handle<jsid>', 'id'),
|
||||
Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
|
||||
]
|
||||
CGAbstractBindingMethod.__init__(self, descriptor,
|
||||
"ResolveOwnPropertyViaNewresolve",
|
||||
args, getThisObj="",
|
||||
callArgs="", returnType="bool")
|
||||
def generate_code(self):
|
||||
return CGIndenter(CGGeneric(
|
||||
"JS::Rooted<JS::Value> value(cx);\n"
|
||||
"if (!self->DoNewResolve(cx, obj, id, &value)) {\n"
|
||||
" return false;\n"
|
||||
"}\n"
|
||||
"if (!value.isUndefined()) {\n"
|
||||
" FillPropertyDescriptor(desc, wrapper, value, /* readonly = */ false);\n"
|
||||
"}\n"
|
||||
"return true;"))
|
||||
|
||||
class CGEnumerateOwnProperties(CGAbstractStaticMethod):
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'wrapper'),
|
||||
Argument('JS::Handle<JSObject*>', 'obj'),
|
||||
Argument('JS::AutoIdVector&', 'props')]
|
||||
CGAbstractMethod.__init__(self, descriptor, "EnumerateOwnProperties", "bool", args)
|
||||
CGAbstractStaticMethod.__init__(self, descriptor,
|
||||
"EnumerateOwnProperties", "bool", args)
|
||||
def definition_body(self):
|
||||
return """ return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
|
||||
"""
|
||||
@@ -7606,6 +7652,16 @@ class CGDescriptor(CGThing):
|
||||
cgThings.append(CGGeneric(define=str(properties)))
|
||||
cgThings.append(CGNativeProperties(descriptor, properties))
|
||||
|
||||
# Set up our Xray callbacks as needed. Note that we don't need to do
|
||||
# it in workers.
|
||||
if not descriptor.workers and descriptor.concrete and descriptor.proxy:
|
||||
cgThings.append(CGResolveOwnProperty(descriptor))
|
||||
cgThings.append(CGEnumerateOwnProperties(descriptor))
|
||||
elif descriptor.interface.getExtendedAttribute("NeedNewResolve"):
|
||||
cgThings.append(CGResolveOwnPropertyViaNewresolve(descriptor))
|
||||
|
||||
# Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
|
||||
# done, set up our NativePropertyHooks.
|
||||
cgThings.append(CGNativePropertyHooks(descriptor, properties))
|
||||
|
||||
if descriptor.interface.hasInterfaceObject():
|
||||
@@ -7629,12 +7685,6 @@ class CGDescriptor(CGThing):
|
||||
if descriptor.interface.hasInterfaceObject():
|
||||
cgThings.append(CGGetConstructorObjectMethod(descriptor))
|
||||
|
||||
# Set up our Xray callbacks as needed. Note that we don't need to do
|
||||
# it in workers.
|
||||
if not descriptor.workers and descriptor.concrete and descriptor.proxy:
|
||||
cgThings.append(CGResolveOwnProperty(descriptor))
|
||||
cgThings.append(CGEnumerateOwnProperties(descriptor))
|
||||
|
||||
if descriptor.interface.hasInterfaceObject():
|
||||
cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ include $(topsrcdir)/dom/dom-config.mk
|
||||
include $(topsrcdir)/dom/webidl/WebIDL.mk
|
||||
|
||||
binding_include_path := mozilla/dom
|
||||
all_webidl_files = $(webidl_files) $(generated_webidl_files)
|
||||
all_webidl_files = $(webidl_files) $(generated_webidl_files) $(preprocessed_webidl_files)
|
||||
# Set exported_binding_headers before adding the test IDL to the mix
|
||||
exported_binding_headers := $(subst .webidl,Binding.h,$(all_webidl_files))
|
||||
# Set linked_binding_cpp_files before adding the test IDL to the mix
|
||||
@@ -142,6 +142,23 @@ $(webidl_files): %: $(webidl_base)/%
|
||||
$(test_webidl_files): %: $(srcdir)/test/%
|
||||
$(INSTALL) $(IFLAGS1) $(srcdir)/test/$* .
|
||||
|
||||
# We can't easily use PP_TARGETS here because it insists on outputting targets
|
||||
# that look like "$(CURDIR)/foo" whereas we want our target to just be "foo".
|
||||
# Make sure to include $(GLOBAL_DEPS) so we pick up changes to what symbols are
|
||||
# defined. Also make sure to remove $@ before writing to it, because otherwise
|
||||
# if a file goes from non-preprocessed to preprocessed we can end up writing to
|
||||
# a symlink, which will clobber files in the srcdir, which is bad.
|
||||
$(preprocessed_webidl_files): %: $(webidl_base)/% $(GLOBAL_DEPS)
|
||||
$(RM) $@
|
||||
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
|
||||
$(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(webidl_base)/$* -o $@
|
||||
|
||||
# Make is dumb and can get confused between "foo" and "$(CURDIR)/foo". Make
|
||||
# sure that the latter depends on the former, since the latter gets used in .pp
|
||||
# files.
|
||||
all_webidl_files_absolute = $(addprefix $(CURDIR)/,$(all_webidl_files))
|
||||
$(all_webidl_files_absolute): $(CURDIR)/%: %
|
||||
|
||||
$(binding_header_files): .BindingGen
|
||||
|
||||
$(binding_cpp_files): .BindingGen
|
||||
|
||||
@@ -168,30 +168,23 @@ BluetoothManager::Create(nsPIDOMWindow* aWindow)
|
||||
return manager.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
|
||||
nsIDOMBluetoothManager** aBluetoothManager)
|
||||
// static
|
||||
bool
|
||||
BluetoothManager::CheckPermission(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(aWindow, "Null pointer!");
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permMgr, NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
uint32_t permission;
|
||||
nsresult rv =
|
||||
permMgr->TestPermissionFromWindow(aWindow, "bluetooth",
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsRefPtr<BluetoothManager> bluetoothManager;
|
||||
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION) {
|
||||
bluetoothManager = BluetoothManager::Create(aWindow);
|
||||
}
|
||||
|
||||
bluetoothManager.forget(aBluetoothManager);
|
||||
return NS_OK;
|
||||
return permission == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -29,8 +29,10 @@ public:
|
||||
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
// Never returns null
|
||||
static already_AddRefed<BluetoothManager>
|
||||
Create(nsPIDOMWindow* aWindow);
|
||||
static bool CheckPermission(nsPIDOMWindow* aWindow);
|
||||
void Notify(const BluetoothSignal& aData);
|
||||
virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE;
|
||||
private:
|
||||
@@ -40,7 +42,4 @@ private:
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
nsresult NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
|
||||
nsIDOMBluetoothManager** aBluetoothManager);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -71,21 +71,27 @@ nsDOMCameraManager::~nsDOMCameraManager()
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
}
|
||||
|
||||
// static creator
|
||||
already_AddRefed<nsDOMCameraManager>
|
||||
nsDOMCameraManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
|
||||
bool
|
||||
nsDOMCameraManager::CheckPermission(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permMgr, nullptr);
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
permMgr->TestPermissionFromWindow(aWindow, "camera", &permission);
|
||||
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||
NS_WARNING("No permission to access camera");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static creator
|
||||
already_AddRefed<nsDOMCameraManager>
|
||||
nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
// Initialize the shared active window tracker
|
||||
if (!sActiveWindowsInitialized) {
|
||||
sActiveWindows.Init();
|
||||
|
||||
@@ -45,8 +45,9 @@ public:
|
||||
nsIObserver)
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static bool CheckPermission(nsPIDOMWindow* aWindow);
|
||||
static already_AddRefed<nsDOMCameraManager>
|
||||
CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow);
|
||||
CreateInstance(nsPIDOMWindow* aWindow);
|
||||
static bool IsWindowStillActive(uint64_t aWindowId);
|
||||
|
||||
void Register(mozilla::nsDOMCameraControl* aDOMCameraControl);
|
||||
|
||||
@@ -6,13 +6,28 @@ MARIONETTE_TIMEOUT = 30000;
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
SpecialPowers.addPermission("settings-write", true, document);
|
||||
|
||||
let icc = navigator.mozIccManager;
|
||||
ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor);
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let icc;
|
||||
ifr.onload = function() {
|
||||
icc = ifr.contentWindow.navigator.mozIccManager;
|
||||
|
||||
ok(icc instanceof ifr.contentWindow.MozIccManager,
|
||||
"icc is instanceof " + icc.constructor);
|
||||
|
||||
is(icc.cardState, "ready");
|
||||
|
||||
// Enable Airplane mode, expect got cardstatechange to null
|
||||
testCardStateChange(true, null,
|
||||
// Disable Airplane mode, expect got cardstatechange to 'ready'
|
||||
testCardStateChange.bind(window, false, "ready", cleanUp)
|
||||
);
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
function setAirplaneModeEnabled(enabled) {
|
||||
let settings = window.navigator.mozSettings;
|
||||
let settings = ifr.contentWindow.navigator.mozSettings;
|
||||
let setLock = settings.createLock();
|
||||
let obj = {
|
||||
"ril.radio.disabled": enabled
|
||||
@@ -53,9 +68,3 @@ function cleanUp() {
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
// Enable Airplane mode, expect got cardstatechange to null
|
||||
testCardStateChange(true, null,
|
||||
// Disable Airplane mode, expect got cardstatechange to 'ready'
|
||||
testCardStateChange.bind(this, false, "ready", cleanUp)
|
||||
);
|
||||
@@ -5,10 +5,43 @@ MARIONETTE_TIMEOUT = 30000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let icc = navigator.mozIccManager;
|
||||
ok(icc instanceof MozIccManager,
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let icc;
|
||||
let iccInfo;
|
||||
ifr.onload = function() {
|
||||
icc = ifr.contentWindow.navigator.mozIccManager;
|
||||
ok(icc instanceof ifr.contentWindow.MozIccManager,
|
||||
"icc is instanceof " + icc.constructor);
|
||||
|
||||
iccInfo = icc.iccInfo;
|
||||
|
||||
// The emulator's hard coded iccid value.
|
||||
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
|
||||
is(iccInfo.iccid, 89014103211118510720);
|
||||
|
||||
// The emulator's hard coded mcc and mnc codes.
|
||||
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
|
||||
is(iccInfo.mcc, 310);
|
||||
is(iccInfo.mnc, 260);
|
||||
is(iccInfo.spn, "Android");
|
||||
// Phone number is hardcoded in MSISDN
|
||||
// See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io()
|
||||
is(iccInfo.msisdn, "15555215554");
|
||||
|
||||
testDisplayConditionChange(testSPN, [
|
||||
// [MCC, MNC, isDisplayNetworkNameRequired, isDisplaySpnRequired]
|
||||
[123, 456, false, true], // Not in HPLMN.
|
||||
[234, 136, true, true], // Not in HPLMN, but in PLMN specified in SPDI.
|
||||
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
|
||||
[466, 92, true, true], // Not in HPLMN, but in another PLMN specified in SPDI.
|
||||
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
|
||||
[310, 260, true, true], // inside HPLMN.
|
||||
], finalize);
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
let emulatorCmdPendingCount = 0;
|
||||
function sendEmulatorCommand(cmd, callback) {
|
||||
emulatorCmdPendingCount++;
|
||||
@@ -39,21 +72,6 @@ function finalize() {
|
||||
finish();
|
||||
}
|
||||
|
||||
let iccInfo = icc.iccInfo;
|
||||
|
||||
// The emulator's hard coded iccid value.
|
||||
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
|
||||
is(iccInfo.iccid, 89014103211118510720);
|
||||
|
||||
// The emulator's hard coded mcc and mnc codes.
|
||||
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
|
||||
is(iccInfo.mcc, 310);
|
||||
is(iccInfo.mnc, 260);
|
||||
is(iccInfo.spn, "Android");
|
||||
// Phone number is hardcoded in MSISDN
|
||||
// See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io()
|
||||
is(iccInfo.msisdn, "15555215554");
|
||||
|
||||
// Test display condition change.
|
||||
function testDisplayConditionChange(func, caseArray, oncomplete) {
|
||||
(function do_call(index) {
|
||||
@@ -75,13 +93,3 @@ function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired,
|
||||
});
|
||||
setEmulatorMccMnc(mcc, mnc);
|
||||
}
|
||||
|
||||
testDisplayConditionChange(testSPN, [
|
||||
// [MCC, MNC, isDisplayNetworkNameRequired, isDisplaySpnRequired]
|
||||
[123, 456, false, true], // Not in HPLMN.
|
||||
[234, 136, true, true], // Not in HPLMN, but in PLMN specified in SPDI.
|
||||
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
|
||||
[466, 92, true, true], // Not in HPLMN, but in another PLMN specified in SPDI.
|
||||
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
|
||||
[310, 260, true, true], // inside HPLMN.
|
||||
], finalize);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMMozSettingsEvent.idl',
|
||||
'nsIDOMSettingsManager.idl',
|
||||
'nsISettingsService.idl',
|
||||
]
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "domstubs.idl"
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
|
||||
interface nsIDOMDOMRequest;
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, uuid(ef95ddd0-6308-11e1-b86c-0800200c9a66)]
|
||||
interface nsIDOMSettingsLock : nsISupports
|
||||
{
|
||||
// Whether this lock is invalid
|
||||
readonly attribute boolean closed;
|
||||
|
||||
// Contains a JSON object with name/value pairs to be set.
|
||||
nsIDOMDOMRequest set(in nsIVariant settings);
|
||||
|
||||
// result contains the value of the setting.
|
||||
nsIDOMDOMRequest get(in jsval name);
|
||||
|
||||
nsIDOMDOMRequest clear();
|
||||
};
|
||||
|
||||
[scriptable, uuid(c40b1c70-00fb-11e2-a21f-0800200c9a66)]
|
||||
interface nsIDOMSettingsManager : nsISupports
|
||||
{
|
||||
nsIDOMSettingsLock createLock();
|
||||
|
||||
void addObserver(in DOMString name, in jsval callback);
|
||||
void removeObserver(in DOMString name, in jsval callback);
|
||||
|
||||
attribute nsIDOMEventListener onsettingchange;
|
||||
};
|
||||
@@ -78,7 +78,12 @@ const BrowserElementIsPreloaded = true;
|
||||
Cc["@mozilla.org/contentsecuritypolicy;1"].createInstance(Ci["nsIContentSecurityPolicy"]);
|
||||
|
||||
/* Applications Specific Helper */
|
||||
Cc["@mozilla.org/settingsManager;1"].getService(Ci["nsIDOMSettingsManager"]);
|
||||
try {
|
||||
// May throw if we don't have the settings permission
|
||||
navigator.mozSettings;
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("dom.sysmsg.enabled")) {
|
||||
Cc["@mozilla.org/system-message-manager;1"].getService(Ci["nsIDOMNavigatorSystemMessages"]);
|
||||
|
||||
@@ -1095,9 +1095,9 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
|
||||
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
if (mCameraManager == nullptr) {
|
||||
mCameraManager = nsDOMCameraManager::CheckPermissionAndCreateInstance(aWindow);
|
||||
if (!mCameraManager) {
|
||||
aPrivileged = false;
|
||||
aPrivileged = nsDOMCameraManager::CheckPermission(aWindow);
|
||||
if (aPrivileged) {
|
||||
mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=802982
|
||||
function boom()
|
||||
{
|
||||
for (var j = 0; j < 100; ++j) {
|
||||
navigator.mozGetUserMedia({}, {}, {});
|
||||
navigator.mozGetUserMedia({}, function(){}, function(){});
|
||||
}
|
||||
finish(); // we're not waiting for success/error callbacks here
|
||||
}
|
||||
|
||||
@@ -26,26 +26,26 @@ var exceptionTests = [
|
||||
// Each test here verifies that a caller is required to have all
|
||||
// three arguments in order to call mozGetUserMedia
|
||||
{ params: undefined,
|
||||
error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
|
||||
error: "Not enough arguments to Navigator.mozGetUserMedia.",
|
||||
message: "no arguments specified" },
|
||||
{ params: [{video: true, fake: true}],
|
||||
error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
|
||||
error: "Not enough arguments to Navigator.mozGetUserMedia.",
|
||||
message: "one argument specified" },
|
||||
{ params: [{video: true, fake: true}, unexpectedCall],
|
||||
error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
|
||||
error: "Not enough arguments to Navigator.mozGetUserMedia.",
|
||||
message: "two arguments specified" },
|
||||
|
||||
// Each test here verifies that providing an incorret object
|
||||
// type to any mozGetUserMedia parameter should throw
|
||||
// the correct exception specified
|
||||
{ params: [1, unexpectedCall, unexpectedCall],
|
||||
error: Cr.NS_ERROR_XPC_BAD_CONVERT_JS,
|
||||
error: "Argument 1 of Navigator.mozGetUserMedia is not an object.",
|
||||
message: "wrong object type as first parameter" },
|
||||
{ params: [{video: true, fake: true}, 1, unexpectedCall],
|
||||
error: Cr.NS_ERROR_XPC_BAD_CONVERT_JS,
|
||||
error: "Argument 2 of Navigator.mozGetUserMedia is not an object.",
|
||||
message: "wrong object type as second parameter" },
|
||||
{ params: [{video: true, fake: true}, unexpectedCall, 1],
|
||||
error: Cr.NS_ERROR_XPC_BAD_CONVERT_JS,
|
||||
error: "Argument 3 of Navigator.mozGetUserMedia is not an object.",
|
||||
message: "wrong object type as third parameter" }
|
||||
];
|
||||
|
||||
@@ -71,7 +71,7 @@ runTest(function () {
|
||||
try {
|
||||
navigator.mozGetUserMedia.apply(navigator, test.params);
|
||||
} catch (e) {
|
||||
exception = (e.result === test.error);
|
||||
exception = (e.message === test.error);
|
||||
}
|
||||
ok(exception, "Exception for " + test.message);
|
||||
});
|
||||
|
||||
@@ -54,41 +54,49 @@ NS_IMPL_EVENT_HANDLER(SmsManager, failed)
|
||||
NS_IMPL_EVENT_HANDLER(SmsManager, deliverysuccess)
|
||||
NS_IMPL_EVENT_HANDLER(SmsManager, deliveryerror)
|
||||
|
||||
/* static */already_AddRefed<SmsManager>
|
||||
SmsManager::CreateInstanceIfAllowed(nsPIDOMWindow* aWindow)
|
||||
/* static */
|
||||
bool
|
||||
SmsManager::CreationIsAllowed(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(aWindow, "Null pointer!");
|
||||
|
||||
#ifndef MOZ_WEBSMS_BACKEND
|
||||
return nullptr;
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// First of all, the general pref has to be turned on.
|
||||
bool enabled = false;
|
||||
Preferences::GetBool("dom.sms.enabled", &enabled);
|
||||
NS_ENSURE_TRUE(enabled, nullptr);
|
||||
NS_ENSURE_TRUE(enabled, false);
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permMgr, nullptr);
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
permMgr->TestPermissionFromWindow(aWindow, "sms", &permission);
|
||||
|
||||
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the Sms Service:
|
||||
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(smsService, nullptr);
|
||||
NS_ENSURE_TRUE(smsService, false);
|
||||
|
||||
bool result = false;
|
||||
smsService->HasSupport(&result);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<SmsManager>
|
||||
SmsManager::CreateInstance(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
nsRefPtr<SmsManager> smsMgr = new SmsManager();
|
||||
smsMgr->Init(aWindow);
|
||||
|
||||
|
||||
@@ -27,7 +27,10 @@ public:
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
static already_AddRefed<SmsManager>
|
||||
CreateInstanceIfAllowed(nsPIDOMWindow *aWindow);
|
||||
CreateInstance(nsPIDOMWindow *aWindow);
|
||||
|
||||
static bool
|
||||
CreationIsAllowed(nsPIDOMWindow *aWindow);
|
||||
|
||||
void Init(nsPIDOMWindow *aWindow);
|
||||
void Shutdown();
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
/** Test for WebSMS **/
|
||||
|
||||
function checkSmsDisabled() {
|
||||
ok('mozSms' in frames[0].navigator, "navigator.mozSms should exist");
|
||||
is(frames[0].navigator.mozSms, null, "navigator.mozSms should return null");
|
||||
ok(!('mozSms' in frames[0].navigator), "navigator.mozSms should not exist");
|
||||
ok(frames[0].navigator.mozSms === undefined,
|
||||
"navigator.mozSms should return undefined");
|
||||
}
|
||||
|
||||
function checkSmsEnabled() {
|
||||
|
||||
@@ -5,10 +5,20 @@ MARIONETTE_TIMEOUT = 60000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let connection = navigator.mozMobileConnection;
|
||||
ok(connection instanceof MozMobileConnection,
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let connection;
|
||||
ifr.onload = function() {
|
||||
connection = ifr.contentWindow.navigator.mozMobileConnection;
|
||||
|
||||
ok(connection instanceof ifr.contentWindow.MozMobileConnection,
|
||||
"connection is instanceof " + connection.constructor);
|
||||
|
||||
testGetCallBarringOption();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
function testGetCallBarringOption() {
|
||||
let option = {'program': 0, 'password': '', 'serviceClass': 0};
|
||||
let request = connection.getCallBarringOption(option);
|
||||
@@ -27,5 +37,3 @@ function cleanUp() {
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
finish();
|
||||
}
|
||||
|
||||
testGetCallBarringOption();
|
||||
|
||||
@@ -5,10 +5,20 @@ MARIONETTE_TIMEOUT = 60000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let connection = navigator.mozMobileConnection;
|
||||
ok(connection instanceof MozMobileConnection,
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let connection;
|
||||
ifr.onload = function() {
|
||||
connection = ifr.contentWindow.navigator.mozMobileConnection;
|
||||
|
||||
ok(connection instanceof ifr.contentWindow.MozMobileConnection,
|
||||
"connection is instanceof " + connection.constructor);
|
||||
|
||||
nextTest();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
let caseId = 0;
|
||||
let options = [
|
||||
buildOption(5, true, '0000', 0), // invalid program.
|
||||
@@ -61,5 +71,3 @@ function cleanUp() {
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
finish();
|
||||
}
|
||||
|
||||
nextTest();
|
||||
|
||||
@@ -5,7 +5,18 @@ MARIONETTE_TIMEOUT = 20000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let mobileConnection = navigator.mozMobileConnection;
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let mobileConnection;
|
||||
ifr.onload = function() {
|
||||
mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
|
||||
|
||||
// Start the test
|
||||
verifyInitialState();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
let emulatorStartLac = 0;
|
||||
let emulatorStartCid = 0;
|
||||
|
||||
@@ -114,6 +125,3 @@ function cleanUp() {
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
finish();
|
||||
}
|
||||
|
||||
// Start the test
|
||||
verifyInitialState();
|
||||
|
||||
@@ -5,7 +5,17 @@ MARIONETTE_TIMEOUT = 30000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let mobileConnection = navigator.mozMobileConnection;
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let mobileConnection;
|
||||
ifr.onload = function() {
|
||||
mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
|
||||
|
||||
// Start the test
|
||||
verifyInitialState();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
function verifyInitialState() {
|
||||
log("Verifying initial state.");
|
||||
@@ -116,6 +126,3 @@ function cleanUp() {
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
finish();
|
||||
}
|
||||
|
||||
// Start the test
|
||||
verifyInitialState();
|
||||
|
||||
@@ -5,7 +5,16 @@ MARIONETTE_TIMEOUT = 20000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let mobileConnection = navigator.mozMobileConnection;
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let mobileConnection;
|
||||
ifr.onload = function() {
|
||||
mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
|
||||
|
||||
tasks.run();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
let tasks = {
|
||||
// List of test functions. Each of them should call |tasks.next()| when
|
||||
@@ -43,7 +52,7 @@ let tasks = {
|
||||
tasks.push(function verifyInitialState() {
|
||||
log("Verifying initial state.");
|
||||
|
||||
ok(mobileConnection instanceof MozMobileConnection,
|
||||
ok(mobileConnection instanceof ifr.contentWindow.MozMobileConnection,
|
||||
"mobileConnection is instanceof " + mobileConnection.constructor);
|
||||
|
||||
tasks.next();
|
||||
@@ -77,5 +86,3 @@ tasks.push(function cleanUp() {
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
finish();
|
||||
});
|
||||
|
||||
tasks.run();
|
||||
|
||||
@@ -8,16 +8,29 @@ SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
const OPERATOR_HOME = 0;
|
||||
const OPERATOR_ROAMING = 1;
|
||||
|
||||
let connection = navigator.mozMobileConnection;
|
||||
ok(connection instanceof MozMobileConnection,
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let connection;
|
||||
let voice;
|
||||
let network;
|
||||
ifr.onload = function() {
|
||||
connection = ifr.contentWindow.navigator.mozMobileConnection;
|
||||
ok(connection instanceof ifr.contentWindow.MozMobileConnection,
|
||||
"connection is instanceof " + connection.constructor);
|
||||
|
||||
let voice = connection.voice;
|
||||
voice = connection.voice;
|
||||
ok(voice, "voice connection valid");
|
||||
|
||||
let network = voice.network;
|
||||
network = voice.network;
|
||||
ok(network, "voice network info valid");
|
||||
|
||||
waitFor(testMobileOperatorNames, function () {
|
||||
return voice.connected;
|
||||
});
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
let emulatorCmdPendingCount = 0;
|
||||
function sendEmulatorCommand(cmd, callback) {
|
||||
emulatorCmdPendingCount++;
|
||||
@@ -203,7 +216,3 @@ function cleanUp() {
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
finish();
|
||||
}
|
||||
|
||||
waitFor(testMobileOperatorNames, function () {
|
||||
return voice.connected;
|
||||
});
|
||||
|
||||
@@ -5,9 +5,17 @@ MARIONETTE_TIMEOUT = 30000;
|
||||
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let connection = navigator.mozMobileConnection;
|
||||
ok(connection instanceof MozMobileConnection,
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let connection;
|
||||
ifr.onload = function() {
|
||||
connection = ifr.contentWindow.navigator.mozMobileConnection;
|
||||
ok(connection instanceof ifr.contentWindow.MozMobileConnection,
|
||||
"connection is instanceof " + connection.constructor);
|
||||
testConnectionInfo();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
let emulatorCmdPendingCount = 0;
|
||||
function setEmulatorVoiceState(state) {
|
||||
@@ -149,5 +157,3 @@ function cleanUp() {
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
finish();
|
||||
}
|
||||
|
||||
testConnectionInfo();
|
||||
|
||||
@@ -25,7 +25,7 @@ var gData = [
|
||||
{
|
||||
perm: ["settings"],
|
||||
obj: 'mozSettings',
|
||||
idl: 'nsIDOMSettingsManager',
|
||||
webidl: 'SettingsManager',
|
||||
settings: [["dom.mozSettings.enabled", true]],
|
||||
}
|
||||
]
|
||||
|
||||
@@ -179,22 +179,26 @@ PowerManager::SetCpuSleepAllowed(bool aAllowed)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<PowerManager>
|
||||
PowerManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
|
||||
bool
|
||||
PowerManager::CheckPermission(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permMgr, nullptr);
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
permMgr->TestPermissionFromWindow(aWindow, "power", &permission);
|
||||
|
||||
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||
return nullptr;
|
||||
return permission == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
already_AddRefed<PowerManager>
|
||||
PowerManager::CreateInstance(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
nsRefPtr<PowerManager> powerManager = new PowerManager();
|
||||
powerManager->Init(aWindow);
|
||||
if (NS_FAILED(powerManager->Init(aWindow))) {
|
||||
powerManager = nullptr;
|
||||
}
|
||||
|
||||
return powerManager.forget();
|
||||
}
|
||||
|
||||
@@ -33,8 +33,9 @@ public:
|
||||
nsresult Init(nsIDOMWindow *aWindow);
|
||||
nsresult Shutdown();
|
||||
|
||||
static already_AddRefed<PowerManager>
|
||||
CheckPermissionAndCreateInstance(nsPIDOMWindow*);
|
||||
static bool CheckPermission(nsPIDOMWindow*);
|
||||
|
||||
static already_AddRefed<PowerManager> CreateInstance(nsPIDOMWindow*);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -23,13 +23,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
const nsIClassInfo = Ci.nsIClassInfo;
|
||||
const SETTINGSLOCK_CONTRACTID = "@mozilla.org/settingsLock;1";
|
||||
const SETTINGSLOCK_CID = Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}");
|
||||
const nsIDOMSettingsLock = Ci.nsIDOMSettingsLock;
|
||||
|
||||
function SettingsLock(aSettingsManager)
|
||||
{
|
||||
function SettingsLock(aSettingsManager) {
|
||||
this._open = true;
|
||||
this._isBusy = false;
|
||||
this._requests = new Queue();
|
||||
@@ -38,7 +32,6 @@ function SettingsLock(aSettingsManager)
|
||||
}
|
||||
|
||||
SettingsLock.prototype = {
|
||||
|
||||
get closed() {
|
||||
return !this._open;
|
||||
},
|
||||
@@ -217,8 +210,7 @@ SettingsLock.prototype = {
|
||||
|
||||
set: function set(aSettings) {
|
||||
if (!this._open) {
|
||||
dump("Settings lock not open!\n");
|
||||
throw Components.results.NS_ERROR_ABORT;
|
||||
throw "Settings lock not open";
|
||||
}
|
||||
|
||||
if (this._settingsManager.hasWritePrivileges) {
|
||||
@@ -230,14 +222,13 @@ SettingsLock.prototype = {
|
||||
return req;
|
||||
} else {
|
||||
if (DEBUG) debug("set not allowed");
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
throw "No permission to call set";
|
||||
}
|
||||
},
|
||||
|
||||
clear: function clear() {
|
||||
if (!this._open) {
|
||||
dump("Settings lock not open!\n");
|
||||
throw Components.results.NS_ERROR_ABORT;
|
||||
throw "Settings lock not open";
|
||||
}
|
||||
|
||||
if (this._settingsManager.hasWritePrivileges) {
|
||||
@@ -247,28 +238,18 @@ SettingsLock.prototype = {
|
||||
return req;
|
||||
} else {
|
||||
if (DEBUG) debug("clear not allowed");
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
throw "No permission to call clear";
|
||||
}
|
||||
},
|
||||
|
||||
classID : SETTINGSLOCK_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsLock]),
|
||||
|
||||
classInfo : XPCOMUtils.generateCI({classID: SETTINGSLOCK_CID,
|
||||
contractID: SETTINGSLOCK_CONTRACTID,
|
||||
classDescription: "SettingsLock",
|
||||
interfaces: [nsIDOMSettingsLock],
|
||||
flags: nsIClassInfo.DOM_OBJECT})
|
||||
classID: Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}"),
|
||||
contractID: "@mozilla.org/settingsLock;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
|
||||
};
|
||||
|
||||
const SETTINGSMANAGER_CONTRACTID = "@mozilla.org/settingsManager;1";
|
||||
const SETTINGSMANAGER_CID = Components.ID("{c40b1c70-00fb-11e2-a21f-0800200c9a66}");
|
||||
const nsIDOMSettingsManager = Ci.nsIDOMSettingsManager;
|
||||
|
||||
let myGlobal = this;
|
||||
|
||||
function SettingsManager()
|
||||
{
|
||||
function SettingsManager() {
|
||||
this._locks = new Queue();
|
||||
if (!("indexedDB" in myGlobal)) {
|
||||
let idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
|
||||
@@ -279,7 +260,6 @@ function SettingsManager()
|
||||
}
|
||||
|
||||
SettingsManager.prototype = {
|
||||
_onsettingchange: null,
|
||||
_callbacks: null,
|
||||
|
||||
_wrap: function _wrap(obj) {
|
||||
@@ -293,19 +273,12 @@ SettingsManager.prototype = {
|
||||
Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
set onsettingchange(aCallback) {
|
||||
if (this.hasReadPrivileges) {
|
||||
if (!this._onsettingchange) {
|
||||
cpmm.sendAsyncMessage("Settings:RegisterForMessages");
|
||||
}
|
||||
this._onsettingchange = aCallback;
|
||||
} else {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
set onsettingchange(aHandler) {
|
||||
this.__DOM_IMPL__.setEventHandler("onsettingchange", aHandler);
|
||||
},
|
||||
|
||||
get onsettingchange() {
|
||||
return this._onsettingchange;
|
||||
return this.__DOM_IMPL__.getEventHandler("onsettingchange");
|
||||
},
|
||||
|
||||
createLock: function() {
|
||||
@@ -326,22 +299,19 @@ SettingsManager.prototype = {
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "Settings:Change:Return:OK":
|
||||
if (this._onsettingchange || this._callbacks) {
|
||||
if (DEBUG) debug('data:' + msg.key + ':' + msg.value + '\n');
|
||||
|
||||
if (this._onsettingchange) {
|
||||
let event = new this._window.MozSettingsEvent("settingchanged", this._wrap({
|
||||
let event = new this._window.MozSettingsEvent("settingchange", this._wrap({
|
||||
settingName: msg.key,
|
||||
settingValue: msg.value
|
||||
}));
|
||||
this._onsettingchange.handleEvent(event);
|
||||
}
|
||||
this.__DOM_IMPL__.dispatchEvent(event);
|
||||
|
||||
if (this._callbacks && this._callbacks[msg.key]) {
|
||||
if (DEBUG) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length);
|
||||
this._callbacks[msg.key].forEach(function(cb) {
|
||||
cb(this._wrap({settingName: msg.key, settingValue: msg.value}));
|
||||
}.bind(this));
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) debug("no observers stored!");
|
||||
}
|
||||
@@ -390,9 +360,12 @@ SettingsManager.prototype = {
|
||||
this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
this.hasWritePrivileges = writePerm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
||||
if (this.hasReadPrivileges) {
|
||||
cpmm.sendAsyncMessage("Settings:RegisterForMessages");
|
||||
}
|
||||
|
||||
if (!this.hasReadPrivileges && !this.hasWritePrivileges) {
|
||||
Cu.reportError("NO SETTINGS PERMISSION FOR: " + aWindow.document.nodePrincipal.origin + "\n");
|
||||
return null;
|
||||
throw "NO SETTINGS PERMISSION FOR: " + aWindow.document.nodePrincipal.origin + "\n";
|
||||
}
|
||||
},
|
||||
|
||||
@@ -406,20 +379,15 @@ SettingsManager.prototype = {
|
||||
this._requests = null;
|
||||
this._window = null;
|
||||
this._innerWindowID = null;
|
||||
this._onsettingchange = null;
|
||||
this._settingsDB.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
classID : SETTINGSMANAGER_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsManager, Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
|
||||
classInfo : XPCOMUtils.generateCI({classID: SETTINGSMANAGER_CID,
|
||||
contractID: SETTINGSMANAGER_CONTRACTID,
|
||||
classDescription: "SettingsManager",
|
||||
interfaces: [nsIDOMSettingsManager],
|
||||
flags: nsIClassInfo.DOM_OBJECT})
|
||||
}
|
||||
classID: Components.ID("{c40b1c70-00fb-11e2-a21f-0800200c9a66}"),
|
||||
contractID: "@mozilla.org/settingsManager;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock])
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
component {c40b1c70-00fb-11e2-a21f-0800200c9a66} SettingsManager.js
|
||||
contract @mozilla.org/settingsManager;1 {c40b1c70-00fb-11e2-a21f-0800200c9a66}
|
||||
category JavaScript-navigator-property mozSettings @mozilla.org/settingsManager;1
|
||||
|
||||
component {60c9357c-3ae0-4222-8f55-da01428470d5} SettingsManager.js
|
||||
contract @mozilla.org/settingsLock;1 {60c9357c-3ae0-4222-8f55-da01428470d5}
|
||||
|
||||
@@ -64,11 +64,12 @@ let steps = [
|
||||
req.onerror = onFailure("Deleting database");
|
||||
},
|
||||
function() {
|
||||
mozSettings.addObserver("test1", function(e) {
|
||||
function obs(e) {
|
||||
checkBlob(e.settingValue);
|
||||
mozSettings.removeObserver("test1", this);
|
||||
mozSettings.removeObserver("test1", obs);
|
||||
next();
|
||||
});
|
||||
}
|
||||
mozSettings.addObserver("test1", obs);
|
||||
next();
|
||||
},
|
||||
function() {
|
||||
|
||||
@@ -117,29 +117,47 @@ Telephony::~Telephony()
|
||||
|
||||
// static
|
||||
already_AddRefed<Telephony>
|
||||
Telephony::Create(nsPIDOMWindow* aOwner, nsITelephonyProvider* aProvider)
|
||||
Telephony::Create(nsPIDOMWindow* aOwner, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(aOwner, "Null owner!");
|
||||
NS_ASSERTION(aProvider, "Null provider!");
|
||||
|
||||
nsCOMPtr<nsITelephonyProvider> ril =
|
||||
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
||||
if (!ril) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
|
||||
NS_ENSURE_TRUE(sgo, nullptr);
|
||||
if (!sgo) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(scriptContext, nullptr);
|
||||
if (!scriptContext) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<Telephony> telephony = new Telephony();
|
||||
|
||||
telephony->BindToOwner(aOwner);
|
||||
|
||||
telephony->mProvider = aProvider;
|
||||
telephony->mProvider = ril;
|
||||
telephony->mListener = new Listener(telephony);
|
||||
|
||||
nsresult rv = aProvider->EnumerateCalls(telephony->mListener);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
nsresult rv = ril->EnumerateCalls(telephony->mListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rv = aProvider->RegisterTelephonyMsg(telephony->mListener);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
rv = ril->RegisterTelephonyMsg(telephony->mListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return telephony.forget();
|
||||
}
|
||||
@@ -574,36 +592,24 @@ Telephony::EnqueueEnumerationAck()
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony)
|
||||
/* static */
|
||||
bool
|
||||
Telephony::CheckPermission(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(aWindow, "Null pointer!");
|
||||
|
||||
nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
|
||||
aWindow :
|
||||
aWindow->GetCurrentInnerWindow();
|
||||
MOZ_ASSERT(aWindow && aWindow->IsInnerWindow());
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(permMgr, NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
uint32_t permission;
|
||||
nsresult rv =
|
||||
permMgr->TestPermissionFromWindow(aWindow, "telephony", &permission);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||
*aTelephony = nullptr;
|
||||
return NS_OK;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITelephonyProvider> ril =
|
||||
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(ril, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsRefPtr<Telephony> telephony = Telephony::Create(innerWindow, ril);
|
||||
NS_ENSURE_TRUE(telephony, NS_ERROR_UNEXPECTED);
|
||||
|
||||
telephony.forget(aTelephony);
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#define mozilla_dom_telephony_telephony_h__
|
||||
|
||||
#include "TelephonyCommon.h"
|
||||
// Need to include TelephonyCall.h because we have inline methods that
|
||||
// assume they see the definition of TelephonyCall.
|
||||
#include "TelephonyCall.h"
|
||||
|
||||
#include "nsIDOMTelephony.h"
|
||||
#include "nsIDOMTelephonyCall.h"
|
||||
@@ -56,7 +59,9 @@ public:
|
||||
nsDOMEventTargetHelper)
|
||||
|
||||
static already_AddRefed<Telephony>
|
||||
Create(nsPIDOMWindow* aOwner, nsITelephonyProvider* aProvider);
|
||||
Create(nsPIDOMWindow* aOwner, ErrorResult& aRv);
|
||||
|
||||
static bool CheckPermission(nsPIDOMWindow* aOwner);
|
||||
|
||||
nsISupports*
|
||||
ToISupports()
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* 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_dom_telephony_telephonyfactory_h__
|
||||
#define mozilla_dom_telephony_telephonyfactory_h__
|
||||
|
||||
#include "nsIDOMTelephony.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
// Implemented in Telephony.cpp.
|
||||
|
||||
nsresult
|
||||
NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony);
|
||||
|
||||
#endif // mozilla_dom_telephony_telephonyfactory_h__
|
||||
@@ -8,10 +8,19 @@ const KEY = "ril.radio.disabled";
|
||||
SpecialPowers.addPermission("telephony", true, document);
|
||||
SpecialPowers.addPermission("settings-write", true, document);
|
||||
|
||||
let settings = window.navigator.mozSettings;
|
||||
let telephony = window.navigator.mozTelephony;
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator
|
||||
let ifr = document.createElement("iframe");
|
||||
let settings;
|
||||
let telephony;
|
||||
let number = "112";
|
||||
let outgoing;
|
||||
ifr.onload = function() {
|
||||
settings = ifr.contentWindow.navigator.mozSettings;
|
||||
telephony = ifr.contentWindow.navigator.mozTelephony;
|
||||
getExistingCalls();
|
||||
};
|
||||
document.body.appendChild(ifr);
|
||||
|
||||
function getExistingCalls() {
|
||||
runEmulatorCmd("gsm list", function(result) {
|
||||
@@ -155,5 +164,3 @@ function cleanUp() {
|
||||
SpecialPowers.removePermission("settings-write", document);
|
||||
finish();
|
||||
}
|
||||
|
||||
getExistingCalls();
|
||||
|
||||
@@ -17,23 +17,28 @@ var idleObserver = {
|
||||
onactive: null
|
||||
};
|
||||
|
||||
function doAddIdleObserver(obs) {
|
||||
var i = document.createElement("iframe");
|
||||
document.body.appendChild(i);
|
||||
var added = false;
|
||||
try {
|
||||
i.contentWindow.navigator.addIdleObserver(obs);
|
||||
added = true;
|
||||
} catch (e) { }
|
||||
i.remove();
|
||||
return added;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// addIdleObserver checks whether time is > 0.
|
||||
this.idleObserver.time = 100;
|
||||
|
||||
var added = false;
|
||||
try {
|
||||
navigator.addIdleObserver(this.idleObserver);
|
||||
added = true;
|
||||
} catch (e) { }
|
||||
var added = doAddIdleObserver(this.idleObserver, false);
|
||||
ok(!added, "Should not be able to add idle observer without permission");
|
||||
|
||||
SpecialPowers.addPermission("idle", true, document);
|
||||
added = false;
|
||||
try {
|
||||
navigator.addIdleObserver(this.idleObserver);
|
||||
added = true;
|
||||
} catch (e) { }
|
||||
|
||||
added = doAddIdleObserver(this.idleObserver, true);
|
||||
ok(added, "Should be able to add idle observer with permission.");
|
||||
|
||||
SimpleTest.finish();
|
||||
|
||||
@@ -35,12 +35,12 @@ function expectSuccess(param) {
|
||||
}
|
||||
|
||||
function testFailures() {
|
||||
expectFailure(null);
|
||||
expectFailure(undefined);
|
||||
expectSuccess(null);
|
||||
expectSuccess(undefined);
|
||||
expectFailure(-1);
|
||||
expectFailure('a');
|
||||
expectSuccess('a');
|
||||
expectFailure([100, -1]);
|
||||
expectFailure([100, 'a']);
|
||||
expectSuccess([100, 'a']);
|
||||
|
||||
var maxVibrateMs = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_ms');
|
||||
var maxVibrateListLen = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_list_len');
|
||||
|
||||
353
dom/webidl/Navigator.webidl
Normal file
353
dom/webidl/Navigator.webidl
Normal file
@@ -0,0 +1,353 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
|
||||
* http://www.w3.org/TR/tracking-dnt/
|
||||
* http://www.w3.org/TR/geolocation-API/#geolocation_interface
|
||||
* http://www.w3.org/TR/battery-status/#navigatorbattery-interface
|
||||
* http://www.w3.org/TR/vibration/#vibration-interface
|
||||
* http://www.w3.org/2012/sysapps/runtime/#extension-to-the-navigator-interface-1
|
||||
* https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension
|
||||
*
|
||||
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
|
||||
* Opera Software ASA. You are granted a license to use, reproduce
|
||||
* and create derivative works of this document.
|
||||
*/
|
||||
|
||||
interface MozPowerManager;
|
||||
interface MozWakeLock;
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
|
||||
[HeaderFile="Navigator.h", NeedNewResolve]
|
||||
interface Navigator {
|
||||
// objects implementing this interface also implement the interfaces given below
|
||||
};
|
||||
Navigator implements NavigatorID;
|
||||
Navigator implements NavigatorLanguage;
|
||||
Navigator implements NavigatorOnLine;
|
||||
Navigator implements NavigatorContentUtils;
|
||||
Navigator implements NavigatorStorageUtils;
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorID {
|
||||
readonly attribute DOMString appName;
|
||||
[Throws]
|
||||
readonly attribute DOMString appVersion;
|
||||
[Throws]
|
||||
readonly attribute DOMString platform;
|
||||
[Throws]
|
||||
readonly attribute DOMString userAgent;
|
||||
|
||||
// Spec has this as a const, but that's wrong because it should not
|
||||
// be on the interface object.
|
||||
//const DOMString product = "Gecko"; // for historical reasons
|
||||
readonly attribute DOMString product;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorLanguage {
|
||||
readonly attribute DOMString? language;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorOnLine {
|
||||
readonly attribute boolean onLine;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorContentUtils {
|
||||
// content handler registration
|
||||
[Throws]
|
||||
void registerProtocolHandler(DOMString scheme, DOMString url, DOMString title);
|
||||
[Throws]
|
||||
void registerContentHandler(DOMString mimeType, DOMString url, DOMString title);
|
||||
// NOT IMPLEMENTED
|
||||
//DOMString isProtocolHandlerRegistered(DOMString scheme, DOMString url);
|
||||
//DOMString isContentHandlerRegistered(DOMString mimeType, DOMString url);
|
||||
//void unregisterProtocolHandler(DOMString scheme, DOMString url);
|
||||
//void unregisterContentHandler(DOMString mimeType, DOMString url);
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorStorageUtils {
|
||||
// NOT IMPLEMENTED
|
||||
//void yieldForStorageUpdates();
|
||||
};
|
||||
|
||||
// Things that definitely need to be in the spec and and are not for some
|
||||
// reason. See https://www.w3.org/Bugs/Public/show_bug.cgi?id=22406
|
||||
partial interface Navigator {
|
||||
[Throws]
|
||||
readonly attribute MimeTypeArray mimeTypes;
|
||||
[Throws]
|
||||
readonly attribute PluginArray plugins;
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/tracking-dnt/ sort of
|
||||
partial interface Navigator {
|
||||
readonly attribute DOMString doNotTrack;
|
||||
};
|
||||
|
||||
// http://www.w3.org/TR/geolocation-API/#geolocation_interface
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorGeolocation {
|
||||
// XXXbz This should perhaps be controleld by the "geo.enabled" pref, instead
|
||||
// of checking it in the C++. Let's not for now to reduce risk.
|
||||
// Also, we violate the spec as a result, since we can return null. See bug
|
||||
// 884921.
|
||||
[Throws]
|
||||
readonly attribute Geolocation? geolocation;
|
||||
};
|
||||
Navigator implements NavigatorGeolocation;
|
||||
|
||||
// http://www.w3.org/TR/battery-status/#navigatorbattery-interface
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorBattery {
|
||||
// XXXbz Per spec this should be non-nullable, but we return null in
|
||||
// torn-down windows. See bug 884925.
|
||||
[Throws, Func="Navigator::HasBatterySupport"]
|
||||
readonly attribute BatteryManager? battery;
|
||||
};
|
||||
Navigator implements NavigatorBattery;
|
||||
|
||||
// http://www.w3.org/TR/vibration/#vibration-interface
|
||||
partial interface Navigator {
|
||||
// We don't support sequences in unions yet
|
||||
//boolean vibrate ((unsigned long or sequence<unsigned long>) pattern);
|
||||
// XXXbz also, per spec we should be returning a boolean, and we just don't.
|
||||
// See bug 884935.
|
||||
[Throws]
|
||||
void vibrate(unsigned long duration);
|
||||
[Throws]
|
||||
void vibrate(sequence<unsigned long> pattern);
|
||||
};
|
||||
|
||||
// Mozilla-specific extensions
|
||||
|
||||
callback interface MozIdleObserver {
|
||||
// Time is in seconds and is read only when idle observers are added
|
||||
// and removed.
|
||||
readonly attribute unsigned long time;
|
||||
void onidle();
|
||||
void onactive();
|
||||
};
|
||||
|
||||
// nsIDOMNavigator
|
||||
partial interface Navigator {
|
||||
// WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla").
|
||||
[Throws]
|
||||
readonly attribute DOMString appCodeName;
|
||||
[Throws]
|
||||
readonly attribute DOMString oscpu;
|
||||
// WebKit/Blink support this; Trident/Presto do not.
|
||||
readonly attribute DOMString vendor;
|
||||
// WebKit/Blink supports this (hardcoded ""); Trident/Presto do not.
|
||||
readonly attribute DOMString vendorSub;
|
||||
// WebKit/Blink supports this (hardcoded "20030107"); Trident/Presto don't
|
||||
readonly attribute DOMString productSub;
|
||||
// WebKit/Blink/Trident/Presto support this.
|
||||
readonly attribute boolean cookieEnabled;
|
||||
[Throws]
|
||||
readonly attribute DOMString buildID;
|
||||
[Throws, Func="Navigator::HasPowerSupport"]
|
||||
readonly attribute MozPowerManager mozPower;
|
||||
|
||||
// WebKit/Blink/Trident/Presto support this.
|
||||
[Throws]
|
||||
boolean javaEnabled();
|
||||
// Everyone but WebKit/Blink supports this. See bug 679971.
|
||||
boolean taintEnabled();
|
||||
|
||||
/**
|
||||
* Navigator requests to add an idle observer to the existing window.
|
||||
*/
|
||||
[Throws, Func="Navigator::HasIdleSupport"]
|
||||
void addIdleObserver(MozIdleObserver aIdleObserver);
|
||||
|
||||
/**
|
||||
* Navigator requests to remove an idle observer from the existing window.
|
||||
*/
|
||||
[Throws, Func="Navigator::HasIdleSupport"]
|
||||
void removeIdleObserver(MozIdleObserver aIdleObserver);
|
||||
|
||||
/**
|
||||
* Request a wake lock for a resource.
|
||||
*
|
||||
* A page holds a wake lock to request that a resource not be turned
|
||||
* off (or otherwise made unavailable).
|
||||
*
|
||||
* The topic is the name of a resource that might be made unavailable for
|
||||
* various reasons. For example, on a mobile device the power manager might
|
||||
* decide to turn off the screen after a period of idle time to save power.
|
||||
*
|
||||
* The resource manager checks the lock state of a topic before turning off
|
||||
* the associated resource. For example, a page could hold a lock on the
|
||||
* "screen" topic to prevent the screensaver from appearing or the screen
|
||||
* from turning off.
|
||||
*
|
||||
* The resource manager defines what each topic means and sets policy. For
|
||||
* example, the resource manager might decide to ignore 'screen' wake locks
|
||||
* held by pages which are not visible.
|
||||
*
|
||||
* One topic can be locked multiple times; it is considered released only when
|
||||
* all locks on the topic have been released.
|
||||
*
|
||||
* The returned nsIDOMMozWakeLock object is a token of the lock. You can
|
||||
* unlock the lock via the object's |unlock| method. The lock is released
|
||||
* automatically when its associated window is unloaded.
|
||||
*
|
||||
* @param aTopic resource name
|
||||
*/
|
||||
[Throws, Func="Navigator::HasWakeLockSupport"]
|
||||
MozWakeLock requestWakeLock(DOMString aTopic);
|
||||
};
|
||||
|
||||
// nsIDOMNavigatorDeviceStorage
|
||||
partial interface Navigator {
|
||||
[Throws, Pref="device.storage.enabled"]
|
||||
DeviceStorage? getDeviceStorage(DOMString type);
|
||||
[Throws, Pref="device.storage.enabled"]
|
||||
sequence<DeviceStorage> getDeviceStorages(DOMString type);
|
||||
};
|
||||
|
||||
// nsIDOMNavigatorDesktopNotification
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasDesktopNotificationSupport"]
|
||||
readonly attribute DesktopNotificationCenter mozNotification;
|
||||
};
|
||||
|
||||
// nsIDOMClientInformation
|
||||
partial interface Navigator {
|
||||
[Throws]
|
||||
boolean mozIsLocallyAvailable(DOMString uri, boolean whenOffline);
|
||||
};
|
||||
|
||||
// nsIDOMMozNavigatorSms
|
||||
interface MozSmsManager;
|
||||
partial interface Navigator {
|
||||
[Func="Navigator::HasSmsSupport"]
|
||||
readonly attribute MozSmsManager? mozSms;
|
||||
};
|
||||
|
||||
// nsIDOMMozNavigatorMobileMessage
|
||||
interface MozMobileMessageManager;
|
||||
partial interface Navigator {
|
||||
[Func="Navigator::HasMobileMessageSupport"]
|
||||
readonly attribute MozMobileMessageManager? mozMobileMessage;
|
||||
};
|
||||
|
||||
// nsIDOMMozNavigatorNetwork
|
||||
interface MozConnection;
|
||||
partial interface Navigator {
|
||||
readonly attribute MozConnection? mozConnection;
|
||||
};
|
||||
|
||||
// nsIDOMNavigatorCamera
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasCameraSupport"]
|
||||
readonly attribute CameraManager mozCameras;
|
||||
};
|
||||
|
||||
// nsIDOMNavigatorSystemMessages and sort of maybe
|
||||
// http://www.w3.org/2012/sysapps/runtime/#extension-to-the-navigator-interface-1
|
||||
callback systemMessageCallback = void (optional object message);
|
||||
partial interface Navigator {
|
||||
[Throws, Pref="dom.sysmsg.enabled"]
|
||||
void mozSetMessageHandler (DOMString type, systemMessageCallback? callback);
|
||||
[Throws, Pref="dom.sysmsg.enabled"]
|
||||
boolean mozHasPendingMessage (DOMString type);
|
||||
};
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
interface MozTelephony;
|
||||
// nsIDOMNavigatorTelephony
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasTelephonySupport"]
|
||||
readonly attribute MozTelephony? mozTelephony;
|
||||
};
|
||||
|
||||
// nsIMozNavigatorMobileConnection
|
||||
interface MozMobileConnection;
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasMobileConnectionSupport"]
|
||||
readonly attribute MozMobileConnection mozMobileConnection;
|
||||
};
|
||||
|
||||
// nsIMozNavigatorCellBroadcast
|
||||
interface MozCellBroadcast;
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasCellBroadcastSupport"]
|
||||
readonly attribute MozCellBroadcast mozCellBroadcast;
|
||||
};
|
||||
|
||||
// nsIMozNavigatorVoicemail
|
||||
interface MozVoicemail;
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasVoicemailSupport"]
|
||||
readonly attribute MozVoicemail mozVoicemail;
|
||||
};
|
||||
|
||||
// nsIMozNavigatorIccManager
|
||||
interface MozIccManager;
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasIccManagerSupport"]
|
||||
readonly attribute MozIccManager? mozIccManager;
|
||||
};
|
||||
#endif // MOZ_B2G_RIL
|
||||
|
||||
#ifdef MOZ_GAMEPAD
|
||||
// https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension
|
||||
partial interface Navigator {
|
||||
[Throws, Pref="dom.gamepad.enabled"]
|
||||
sequence<Gamepad?> getGamepads();
|
||||
};
|
||||
#endif // MOZ_GAMEPAD
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
// nsIDOMNavigatorBluetooth
|
||||
interface MozBluetoothManager;
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasBluetoothSupport"]
|
||||
readonly attribute MozBluetoothManager mozBluetooth;
|
||||
};
|
||||
#endif // MOZ_B2G_BT
|
||||
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
// nsIDOMMozNavigatorTime
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasTimeSupport"]
|
||||
readonly attribute MozTimeManager mozTime;
|
||||
};
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
|
||||
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
|
||||
// nsIMozNavigatorAudioChannelManager
|
||||
partial interface Navigator {
|
||||
[Throws]
|
||||
readonly attribute AudioChannelManager mozAudioChannelManager;
|
||||
};
|
||||
#endif // MOZ_AUDIO_CHANNEL_MANAGER
|
||||
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
// nsIDOMNavigatorUserMedia
|
||||
callback MozDOMGetUserMediaSuccessCallback = void (nsISupports? value);
|
||||
callback MozDOMGetUserMediaErrorCallback = void (DOMString error);
|
||||
interface MozMediaStreamOptions;
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasUserMediaSupport"]
|
||||
void mozGetUserMedia(MozMediaStreamOptions? params,
|
||||
MozDOMGetUserMediaSuccessCallback? onsuccess,
|
||||
MozDOMGetUserMediaErrorCallback? onerror);
|
||||
};
|
||||
|
||||
// nsINavigatorUserMedia
|
||||
callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices);
|
||||
partial interface Navigator {
|
||||
[Throws, ChromeOnly]
|
||||
void mozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback? onsuccess,
|
||||
MozDOMGetUserMediaErrorCallback? onerror);
|
||||
};
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
39
dom/webidl/SettingsManager.webidl
Normal file
39
dom/webidl/SettingsManager.webidl
Normal file
@@ -0,0 +1,39 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; 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/.
|
||||
*/
|
||||
|
||||
[JSImplementation="@mozilla.org/settingsLock;1",
|
||||
Pref="dom.mozSettings.enabled"]
|
||||
interface SettingsLock {
|
||||
// Whether this lock is invalid
|
||||
readonly attribute boolean closed;
|
||||
|
||||
// Contains a JSON object with name/value pairs to be set.
|
||||
DOMRequest set(object settings);
|
||||
|
||||
// Result contains the value of the setting.
|
||||
DOMRequest get(DOMString name);
|
||||
|
||||
DOMRequest clear();
|
||||
};
|
||||
|
||||
dictionary SettingChange {
|
||||
DOMString settingName;
|
||||
DOMString settingValue;
|
||||
};
|
||||
|
||||
callback SettingChangeCallback = void (SettingChange setting);
|
||||
|
||||
[JSImplementation="@mozilla.org/settingsManager;1",
|
||||
NavigatorProperty="mozSettings",
|
||||
Pref="dom.mozSettings.enabled"]
|
||||
interface SettingsManager : EventTarget {
|
||||
SettingsLock createLock();
|
||||
|
||||
void addObserver(DOMString name, SettingChangeCallback callback);
|
||||
void removeObserver(DOMString name, SettingChangeCallback callback);
|
||||
|
||||
attribute EventHandler onsettingchange;
|
||||
};
|
||||
@@ -8,6 +8,10 @@ generated_webidl_files = \
|
||||
CSS2Properties.webidl \
|
||||
$(NULL)
|
||||
|
||||
preprocessed_webidl_files = \
|
||||
Navigator.webidl \
|
||||
$(NULL)
|
||||
|
||||
webidl_files = \
|
||||
AnalyserNode.webidl \
|
||||
AnimationEvent.webidl \
|
||||
@@ -227,6 +231,7 @@ webidl_files = \
|
||||
Screen.webidl \
|
||||
ScriptProcessorNode.webidl \
|
||||
ScrollAreaEvent.webidl \
|
||||
SettingsManager.webidl \
|
||||
SimpleGestureEvent.webidl \
|
||||
SourceBuffer.webidl \
|
||||
SourceBufferList.webidl \
|
||||
|
||||
@@ -1158,8 +1158,8 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
}
|
||||
else {
|
||||
if (!mNavigatorStringsLoaded) {
|
||||
if (NS_FAILED(NS_GetNavigatorAppName(mNavigatorStrings.mAppName)) ||
|
||||
NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorStrings.mAppVersion)) ||
|
||||
NS_GetNavigatorAppName(mNavigatorStrings.mAppName);
|
||||
if (NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorStrings.mAppVersion)) ||
|
||||
NS_FAILED(NS_GetNavigatorPlatform(mNavigatorStrings.mPlatform)) ||
|
||||
NS_FAILED(NS_GetNavigatorUserAgent(mNavigatorStrings.mUserAgent))) {
|
||||
JS_ReportError(aCx, "Failed to load navigator strings!");
|
||||
|
||||
@@ -35,7 +35,8 @@ Tests of DOM Worker Navigator
|
||||
return;
|
||||
}
|
||||
|
||||
is(navigator[args.name], args.value, "Mismatched navigator string!");
|
||||
is(navigator[args.name], args.value,
|
||||
"Mismatched navigator string for " + args.name + "!");
|
||||
};
|
||||
|
||||
worker.onerror = function(event) {
|
||||
|
||||
@@ -61,6 +61,7 @@ VPATH += \
|
||||
|
||||
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
|
||||
OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(CAIRO_FT_CFLAGS)
|
||||
DEFINES += -DSK_FONTHOST_CAIRO_STANDALONE=0
|
||||
endif
|
||||
|
||||
ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
|
||||
|
||||
@@ -222,8 +222,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
'ashmem.cpp',
|
||||
'SkDebug_android.cpp',
|
||||
'SkFontHost_cairo.cpp',
|
||||
'SkFontHost_linux.cpp',
|
||||
'SkFontHost_FreeType_common.cpp',
|
||||
'SkFontHost_FreeType.cpp',
|
||||
'SkImageRef_ashmem.cpp',
|
||||
'SkOSFile.cpp',
|
||||
'SkTime_Unix.cpp',
|
||||
'SkThread_pthread.cpp',
|
||||
'SkThreadUtils_pthread.cpp',
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#ifndef SK_FONTHOST_CAIRO_STANDALONE
|
||||
#define SK_FONTHOST_CAIRO_STANDALONE 1
|
||||
#endif
|
||||
|
||||
static cairo_user_data_key_t kSkTypefaceKey;
|
||||
|
||||
class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
|
||||
@@ -138,6 +142,7 @@ SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypefac
|
||||
return typeface;
|
||||
}
|
||||
|
||||
#if SK_FONTHOST_CAIRO_STANDALONE
|
||||
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
|
||||
const char famillyName[],
|
||||
SkTypeface::Style style)
|
||||
@@ -157,6 +162,7 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*)
|
||||
SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -355,10 +361,12 @@ SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_FONTHOST_CAIRO_STANDALONE
|
||||
#include "SkFontMgr.h"
|
||||
|
||||
SkFontMgr* SkFontMgr::Factory() {
|
||||
// todo
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -19,8 +19,12 @@
|
||||
#include "SkTSearch.h"
|
||||
|
||||
#ifndef SK_FONT_FILE_PREFIX
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
#define SK_FONT_FILE_PREFIX "/fonts/"
|
||||
#else
|
||||
#define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/"
|
||||
#endif
|
||||
#endif
|
||||
#ifndef SK_FONT_FILE_DIR_SEPERATOR
|
||||
#define SK_FONT_FILE_DIR_SEPERATOR "/"
|
||||
#endif
|
||||
@@ -419,7 +423,13 @@ static void load_system_fonts() {
|
||||
return;
|
||||
}
|
||||
|
||||
SkString baseDirectory(SK_FONT_FILE_PREFIX);
|
||||
SkString baseDirectory;
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
baseDirectory.set(getenv("ANDROID_ROOT"));
|
||||
#endif
|
||||
|
||||
baseDirectory.append(SK_FONT_FILE_PREFIX);
|
||||
|
||||
unsigned int count = 0;
|
||||
load_directory_fonts(baseDirectory, &count);
|
||||
|
||||
|
||||
@@ -205,8 +205,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
|
||||
canLazilyParse ? &syntaxParser.ref() : NULL, NULL);
|
||||
parser.sct = sct;
|
||||
|
||||
GlobalSharedContext globalsc(cx, scopeChain,
|
||||
options.strictOption, options.extraWarningsOption);
|
||||
Directives directives(options.strictOption);
|
||||
GlobalSharedContext globalsc(cx, scopeChain, directives, options.extraWarningsOption);
|
||||
|
||||
bool savedCallerFun =
|
||||
options.compileAndGo &&
|
||||
@@ -240,7 +240,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
|
||||
// reset when this occurs.
|
||||
Maybe<ParseContext<FullParseHandler> > pc;
|
||||
|
||||
pc.construct(&parser, (GenericParseContext *) NULL, &globalsc, staticLevel, /* bodyid = */ 0);
|
||||
pc.construct(&parser, (GenericParseContext *) NULL, &globalsc, (Directives *) NULL,
|
||||
staticLevel, /* bodyid = */ 0);
|
||||
if (!pc.ref().init())
|
||||
return NULL;
|
||||
|
||||
@@ -267,7 +268,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
|
||||
* wishes to decompile it while it's running.
|
||||
*/
|
||||
JSFunction *fun = evalCaller->functionOrCallerFunction();
|
||||
ObjectBox *funbox = parser.newFunctionBox(fun, pc.addr(), fun->strict());
|
||||
Directives directives(/* strict = */ fun->strict());
|
||||
ObjectBox *funbox = parser.newFunctionBox(fun, pc.addr(), directives);
|
||||
if (!funbox)
|
||||
return NULL;
|
||||
bce.objectList.add(funbox);
|
||||
@@ -305,7 +307,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
|
||||
|
||||
pc.destroy();
|
||||
pc.construct(&parser, (GenericParseContext *) NULL, &globalsc,
|
||||
staticLevel, /* bodyid = */ 0);
|
||||
(Directives *) NULL, staticLevel, /* bodyid = */ 0);
|
||||
if (!pc.ref().init())
|
||||
return NULL;
|
||||
JS_ASSERT(parser.pc == pc.addr());
|
||||
@@ -462,16 +464,19 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
|
||||
|
||||
fun->setArgCount(formals.length());
|
||||
|
||||
// If the context is strict, immediately parse the body in strict
|
||||
// mode. Otherwise, we parse it normally. If we see a "use strict"
|
||||
// directive, we backup and reparse it as strict.
|
||||
ParseNode *fn;
|
||||
// Speculatively parse using the default directives implied by the context.
|
||||
// If a directive is encountered (e.g., "use strict") that changes how the
|
||||
// function should have been parsed, we backup and reparse with the new set
|
||||
// of directives.
|
||||
Directives directives(options.strictOption);
|
||||
|
||||
TokenStream::Position start(parser.keepAtoms);
|
||||
parser.tokenStream.tell(&start);
|
||||
bool strict = options.strictOption;
|
||||
bool becameStrict;
|
||||
|
||||
ParseNode *fn;
|
||||
while (true) {
|
||||
fn = parser.standaloneFunctionBody(fun, formals, strict, &becameStrict);
|
||||
Directives newDirectives = directives;
|
||||
fn = parser.standaloneFunctionBody(fun, formals, directives, &newDirectives);
|
||||
if (fn)
|
||||
break;
|
||||
|
||||
@@ -481,10 +486,12 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
|
||||
// the parse.
|
||||
parser.clearAbortedSyntaxParse();
|
||||
} else {
|
||||
// If the function became strict, reparse in strict mode.
|
||||
if (strict || !becameStrict || parser.tokenStream.hadError())
|
||||
if (parser.tokenStream.hadError() || directives == newDirectives)
|
||||
return false;
|
||||
strict = true;
|
||||
|
||||
// Assignment must be monotonic to prevent reparsing iloops
|
||||
JS_ASSERT_IF(directives.strict(), newDirectives.strict());
|
||||
directives = newDirectives;
|
||||
}
|
||||
|
||||
parser.tokenStream.seek(start);
|
||||
|
||||
@@ -384,7 +384,8 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
|
||||
MOZ_ASSUME_UNREACHABLE("module nodes cannot be cloned");
|
||||
}
|
||||
NULLCHECK(pn->pn_funbox =
|
||||
newFunctionBox(opn->pn_funbox->function(), pc, opn->pn_funbox->strict));
|
||||
newFunctionBox(opn->pn_funbox->function(), pc,
|
||||
Directives(/* strict = */ opn->pn_funbox->strict)));
|
||||
NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body));
|
||||
pn->pn_cookie = opn->pn_cookie;
|
||||
pn->pn_dflags = opn->pn_dflags;
|
||||
|
||||
@@ -453,9 +453,10 @@ Parser<ParseHandler>::newObjectBox(JSObject *obj)
|
||||
|
||||
template <typename ParseHandler>
|
||||
FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
|
||||
ParseContext<ParseHandler> *outerpc, bool strict, bool extraWarnings)
|
||||
ParseContext<ParseHandler> *outerpc, Directives directives,
|
||||
bool extraWarnings)
|
||||
: ObjectBox(fun, traceListHead),
|
||||
SharedContext(cx, strict, extraWarnings),
|
||||
SharedContext(cx, directives, extraWarnings),
|
||||
bindings(),
|
||||
bufStart(0),
|
||||
bufEnd(0),
|
||||
@@ -516,8 +517,8 @@ FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunct
|
||||
|
||||
template <typename ParseHandler>
|
||||
FunctionBox *
|
||||
Parser<ParseHandler>::newFunctionBox(JSFunction *fun,
|
||||
ParseContext<ParseHandler> *outerpc, bool strict)
|
||||
Parser<ParseHandler>::newFunctionBox(JSFunction *fun, ParseContext<ParseHandler> *outerpc,
|
||||
Directives inheritedDirectives)
|
||||
{
|
||||
JS_ASSERT(fun && !IsPoisonedPtr(fun));
|
||||
|
||||
@@ -530,7 +531,7 @@ Parser<ParseHandler>::newFunctionBox(JSFunction *fun,
|
||||
*/
|
||||
FunctionBox *funbox =
|
||||
alloc.new_<FunctionBox>(context, traceListHead, fun, outerpc,
|
||||
strict, options().extraWarningsOption);
|
||||
inheritedDirectives, options().extraWarningsOption);
|
||||
if (!funbox) {
|
||||
js_ReportOutOfMemory(context);
|
||||
return NULL;
|
||||
@@ -544,7 +545,7 @@ Parser<ParseHandler>::newFunctionBox(JSFunction *fun,
|
||||
ModuleBox::ModuleBox(ExclusiveContext *cx, ObjectBox *traceListHead, Module *module,
|
||||
ParseContext<FullParseHandler> *pc, bool extraWarnings)
|
||||
: ObjectBox(module, traceListHead),
|
||||
SharedContext(cx, true, extraWarnings)
|
||||
SharedContext(cx, Directives(/* strict = */ true), extraWarnings)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -602,9 +603,11 @@ Parser<ParseHandler>::parse(JSObject *chain)
|
||||
* an object lock before it finishes generating bytecode into a script
|
||||
* protected from the GC by a root or a stack frame reference.
|
||||
*/
|
||||
GlobalSharedContext globalsc(context, chain,
|
||||
options().strictOption, options().extraWarningsOption);
|
||||
ParseContext<ParseHandler> globalpc(this, NULL, &globalsc, /* staticLevel = */ 0, /* bodyid = */ 0);
|
||||
Directives directives(options().strictOption);
|
||||
GlobalSharedContext globalsc(context, chain, directives, options().extraWarningsOption);
|
||||
ParseContext<ParseHandler> globalpc(this, /* parent = */ NULL, &globalsc,
|
||||
/* newDirectives = */ NULL, /* staticLevel = */ 0,
|
||||
/* bodyid = */ 0);
|
||||
if (!globalpc.init())
|
||||
return null();
|
||||
|
||||
@@ -843,11 +846,9 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName *name, Node pn)
|
||||
template <>
|
||||
ParseNode *
|
||||
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
|
||||
bool strict, bool *becameStrict)
|
||||
Directives inheritedDirectives,
|
||||
Directives *newDirectives)
|
||||
{
|
||||
if (becameStrict)
|
||||
*becameStrict = false;
|
||||
|
||||
Node fn = handler.newFunctionDefinition();
|
||||
if (!fn)
|
||||
return null();
|
||||
@@ -859,12 +860,13 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
|
||||
argsbody->makeEmpty();
|
||||
fn->pn_body = argsbody;
|
||||
|
||||
FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, strict);
|
||||
FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, inheritedDirectives);
|
||||
if (!funbox)
|
||||
return null();
|
||||
handler.setFunctionBox(fn, funbox);
|
||||
|
||||
ParseContext<FullParseHandler> funpc(this, pc, funbox, /* staticLevel = */ 0, /* bodyid = */ 0);
|
||||
ParseContext<FullParseHandler> funpc(this, pc, funbox, newDirectives,
|
||||
/* staticLevel = */ 0, /* bodyid = */ 0);
|
||||
if (!funpc.init())
|
||||
return null();
|
||||
|
||||
@@ -874,11 +876,8 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
|
||||
}
|
||||
|
||||
ParseNode *pn = functionBody(Statement, StatementListBody);
|
||||
if (!pn) {
|
||||
if (becameStrict && pc->funBecameStrict)
|
||||
*becameStrict = true;
|
||||
if (!pn)
|
||||
return null();
|
||||
}
|
||||
|
||||
if (!tokenStream.matchToken(TOK_EOF)) {
|
||||
report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
|
||||
@@ -1798,7 +1797,7 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
||||
// so we can skip over them after accounting for their free variables.
|
||||
if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
|
||||
JSFunction *fun = handler.nextLazyInnerFunction();
|
||||
FunctionBox *funbox = newFunctionBox(fun, pc, /* strict = */ false);
|
||||
FunctionBox *funbox = newFunctionBox(fun, pc, Directives(/* strict = */ false));
|
||||
if (!funbox)
|
||||
return false;
|
||||
handler.setFunctionBox(pn, funbox);
|
||||
@@ -1933,27 +1932,29 @@ Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream:
|
||||
if (!fun)
|
||||
return null();
|
||||
|
||||
// If the outer scope is strict, immediately parse the function in strict
|
||||
// mode. Otherwise, we parse it normally. If we see a "use strict"
|
||||
// directive, we backup and reparse it as strict.
|
||||
bool initiallyStrict = pc->sc->strict;
|
||||
bool becameStrict;
|
||||
if (!functionArgsAndBody(pn, fun, type, kind, initiallyStrict,
|
||||
&becameStrict))
|
||||
{
|
||||
if (initiallyStrict || !becameStrict || tokenStream.hadError())
|
||||
// Speculatively parse using the directives of the parent parsing context.
|
||||
// If a directive is encountered (e.g., "use strict") that changes how the
|
||||
// function should have been parsed, we backup and reparse with the new set
|
||||
// of directives.
|
||||
Directives directives(pc);
|
||||
Directives newDirectives = directives;
|
||||
|
||||
while (true) {
|
||||
if (functionArgsAndBody(pn, fun, type, kind, directives, &newDirectives))
|
||||
break;
|
||||
if (tokenStream.hadError() || directives == newDirectives)
|
||||
return null();
|
||||
|
||||
// Reparse the function in strict mode.
|
||||
// Assignment must be monotonic to prevent reparsing iloops
|
||||
JS_ASSERT_IF(directives.strict(), newDirectives.strict());
|
||||
directives = newDirectives;
|
||||
|
||||
tokenStream.seek(start);
|
||||
if (funName && tokenStream.getToken() == TOK_ERROR)
|
||||
return null();
|
||||
|
||||
// functionArgsAndBody may have already set pn->pn_body before failing.
|
||||
handler.setFunctionBody(pn, null());
|
||||
|
||||
if (!functionArgsAndBody(pn, fun, type, kind, true))
|
||||
return null();
|
||||
}
|
||||
|
||||
return pn;
|
||||
@@ -2054,14 +2055,13 @@ template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
||||
FunctionType type, FunctionSyntaxKind kind,
|
||||
bool strict, bool *becameStrict)
|
||||
Directives inheritedDirectives,
|
||||
Directives *newDirectives)
|
||||
{
|
||||
if (becameStrict)
|
||||
*becameStrict = false;
|
||||
ParseContext<FullParseHandler> *outerpc = pc;
|
||||
|
||||
// Create box for fun->object early to protect against last-ditch GC.
|
||||
FunctionBox *funbox = newFunctionBox(fun, pc, strict);
|
||||
FunctionBox *funbox = newFunctionBox(fun, pc, inheritedDirectives);
|
||||
if (!funbox)
|
||||
return false;
|
||||
|
||||
@@ -2077,13 +2077,13 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
||||
tokenStream.tell(&position);
|
||||
parser->tokenStream.seek(position, tokenStream);
|
||||
|
||||
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, funbox,
|
||||
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, funbox, newDirectives,
|
||||
outerpc->staticLevel + 1, outerpc->blockidGen);
|
||||
if (!funpc.init())
|
||||
return false;
|
||||
|
||||
if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
|
||||
fun, type, kind, becameStrict))
|
||||
fun, type, kind, newDirectives))
|
||||
{
|
||||
if (parser->hadAbortedSyntaxParse()) {
|
||||
// Try again with a full parse.
|
||||
@@ -2111,12 +2111,12 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
||||
} while (false);
|
||||
|
||||
// Continue doing a full parse for this inner function.
|
||||
ParseContext<FullParseHandler> funpc(this, pc, funbox,
|
||||
ParseContext<FullParseHandler> funpc(this, pc, funbox, newDirectives,
|
||||
outerpc->staticLevel + 1, outerpc->blockidGen);
|
||||
if (!funpc.init())
|
||||
return false;
|
||||
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, becameStrict))
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
|
||||
return false;
|
||||
|
||||
if (!leaveFunction(pn, outerpc, kind))
|
||||
@@ -2138,24 +2138,23 @@ template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
|
||||
FunctionType type, FunctionSyntaxKind kind,
|
||||
bool strict, bool *becameStrict)
|
||||
Directives inheritedDirectives,
|
||||
Directives *newDirectives)
|
||||
{
|
||||
if (becameStrict)
|
||||
*becameStrict = false;
|
||||
ParseContext<SyntaxParseHandler> *outerpc = pc;
|
||||
|
||||
// Create box for fun->object early to protect against last-ditch GC.
|
||||
FunctionBox *funbox = newFunctionBox(fun, pc, strict);
|
||||
FunctionBox *funbox = newFunctionBox(fun, pc, inheritedDirectives);
|
||||
if (!funbox)
|
||||
return false;
|
||||
|
||||
// Initialize early for possible flags mutation via destructuringExpr.
|
||||
ParseContext<SyntaxParseHandler> funpc(this, pc, funbox,
|
||||
ParseContext<SyntaxParseHandler> funpc(this, pc, funbox, newDirectives,
|
||||
outerpc->staticLevel + 1, outerpc->blockidGen);
|
||||
if (!funpc.init())
|
||||
return false;
|
||||
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, becameStrict))
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
|
||||
return false;
|
||||
|
||||
if (!leaveFunction(pn, outerpc, kind))
|
||||
@@ -2177,17 +2176,23 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, strict);
|
||||
Directives directives(/* strict = */ strict);
|
||||
FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, directives);
|
||||
if (!funbox)
|
||||
return null();
|
||||
handler.setFunctionBox(pn, funbox);
|
||||
|
||||
ParseContext<FullParseHandler> funpc(this, NULL, funbox, staticLevel, 0);
|
||||
Directives newDirectives = directives;
|
||||
ParseContext<FullParseHandler> funpc(this, /* parent = */ NULL, funbox,
|
||||
&newDirectives, staticLevel, /* bodyid = */ 0);
|
||||
if (!funpc.init())
|
||||
return null();
|
||||
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement, NULL))
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement, &newDirectives)) {
|
||||
JS_ASSERT(directives == newDirectives);
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
if (fun->isNamedLambda()) {
|
||||
if (AtomDefnPtr p = pc->lexdeps->lookup(fun->name())) {
|
||||
@@ -2208,7 +2213,8 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
|
||||
FunctionSyntaxKind kind, bool *becameStrict)
|
||||
FunctionSyntaxKind kind,
|
||||
Directives *newDirectives)
|
||||
{
|
||||
// Given a properly initialized parse context, try to parse an actual
|
||||
// function without concern for conversion to strict mode, use of lazy
|
||||
@@ -2254,12 +2260,8 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, Fu
|
||||
}
|
||||
|
||||
Node body = functionBody(kind, bodyType);
|
||||
if (!body) {
|
||||
// Notify the caller if this function was discovered to be strict.
|
||||
if (becameStrict && pc->funBecameStrict)
|
||||
*becameStrict = true;
|
||||
if (!body)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!yieldGuard.empty() && !yieldGuard.ref().checkValidBody(body, JSMSG_YIELD_IN_ARROW))
|
||||
return false;
|
||||
@@ -2312,7 +2314,8 @@ Parser<FullParseHandler>::moduleDecl()
|
||||
return NULL;
|
||||
pn->pn_modulebox = modulebox;
|
||||
|
||||
ParseContext<FullParseHandler> modulepc(this, pc, modulebox, pc->staticLevel + 1, pc->blockidGen);
|
||||
ParseContext<FullParseHandler> modulepc(this, pc, modulebox, /* newDirectives = */ NULL,
|
||||
pc->staticLevel + 1, pc->blockidGen);
|
||||
if (!modulepc.init())
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_MODULE);
|
||||
@@ -2441,7 +2444,7 @@ Parser<ParseHandler>::maybeParseDirective(Node pn, bool *cont)
|
||||
if (!pc->sc->strict) {
|
||||
if (pc->sc->isFunctionBox()) {
|
||||
// Request that this function be reparsed as strict.
|
||||
pc->funBecameStrict = true;
|
||||
pc->newDirectives->setStrict();
|
||||
return false;
|
||||
} else {
|
||||
// We don't reparse global scopes, so we keep track of the
|
||||
@@ -5984,11 +5987,12 @@ Parser<FullParseHandler>::generatorExpr(ParseNode *kid)
|
||||
return null();
|
||||
|
||||
/* Create box for fun->object early to protect against last-ditch GC. */
|
||||
FunctionBox *genFunbox = newFunctionBox(fun, outerpc, outerpc->sc->strict);
|
||||
Directives directives(/* strict = */ outerpc->sc->strict);
|
||||
FunctionBox *genFunbox = newFunctionBox(fun, outerpc, directives);
|
||||
if (!genFunbox)
|
||||
return null();
|
||||
|
||||
ParseContext<FullParseHandler> genpc(this, outerpc, genFunbox,
|
||||
ParseContext<FullParseHandler> genpc(this, outerpc, genFunbox, /* newDirectives = */ NULL,
|
||||
outerpc->staticLevel + 1, outerpc->blockidGen);
|
||||
if (!genpc.init())
|
||||
return null();
|
||||
|
||||
@@ -214,6 +214,13 @@ struct ParseContext : public GenericParseContext
|
||||
// All inner functions in this context. Only filled in when parsing syntax.
|
||||
AutoFunctionVector innerFunctions;
|
||||
|
||||
// In a function context, points to a Directive struct that can be updated
|
||||
// to reflect new directives encountered in the Directive Prologue that
|
||||
// require reparsing the function. In global/module/generator-tail contexts,
|
||||
// we don't need to reparse when encountering a DirectivePrologue so this
|
||||
// pointer may be NULL.
|
||||
Directives *newDirectives;
|
||||
|
||||
// Set when parsing a declaration-like destructuring pattern. This flag
|
||||
// causes PrimaryExpr to create PN_NAME parse nodes for variable references
|
||||
// which are not hooked into any definition's use chain, added to any tree
|
||||
@@ -225,12 +232,9 @@ struct ParseContext : public GenericParseContext
|
||||
// they need to be treated differently.
|
||||
bool inDeclDestructuring:1;
|
||||
|
||||
// True if we are in a function, saw a "use strict" directive, and weren't
|
||||
// strict before.
|
||||
bool funBecameStrict:1;
|
||||
|
||||
ParseContext(Parser<ParseHandler> *prs, GenericParseContext *parent,
|
||||
SharedContext *sc, unsigned staticLevel, uint32_t bodyid)
|
||||
SharedContext *sc, Directives *newDirectives,
|
||||
unsigned staticLevel, uint32_t bodyid)
|
||||
: GenericParseContext(parent, sc),
|
||||
bodyid(0), // initialized in init()
|
||||
blockidGen(bodyid), // used to set |bodyid| and subsequently incremented in init()
|
||||
@@ -250,8 +254,8 @@ struct ParseContext : public GenericParseContext
|
||||
lexdeps(prs->context),
|
||||
funcStmts(NULL),
|
||||
innerFunctions(prs->context),
|
||||
inDeclDestructuring(false),
|
||||
funBecameStrict(false)
|
||||
newDirectives(newDirectives),
|
||||
inDeclDestructuring(false)
|
||||
{
|
||||
prs->pc = this;
|
||||
}
|
||||
@@ -288,6 +292,12 @@ struct ParseContext : public GenericParseContext
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ParseHandler>
|
||||
inline
|
||||
Directives::Directives(ParseContext<ParseHandler> *parent)
|
||||
: strict_(parent->sc->strict)
|
||||
{}
|
||||
|
||||
template <typename ParseHandler>
|
||||
struct BindData;
|
||||
|
||||
@@ -369,7 +379,8 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
||||
*/
|
||||
ObjectBox *newObjectBox(JSObject *obj);
|
||||
ModuleBox *newModuleBox(Module *module, ParseContext<ParseHandler> *pc);
|
||||
FunctionBox *newFunctionBox(JSFunction *fun, ParseContext<ParseHandler> *pc, bool strict);
|
||||
FunctionBox *newFunctionBox(JSFunction *fun, ParseContext<ParseHandler> *pc,
|
||||
Directives directives);
|
||||
|
||||
/*
|
||||
* Create a new function object given parse context (pc) and a name (which
|
||||
@@ -402,7 +413,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
||||
|
||||
// Parse a function, given only its body. Used for the Function constructor.
|
||||
Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
|
||||
bool strict, bool *becameStrict);
|
||||
Directives inheritedDirectives, Directives *newDirectives);
|
||||
|
||||
// Parse a function, given only its arguments and body. Used for lazily
|
||||
// parsed functions.
|
||||
@@ -416,7 +427,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
||||
Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type);
|
||||
|
||||
bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
|
||||
FunctionSyntaxKind kind, bool *becameStrict);
|
||||
FunctionSyntaxKind kind, Directives *newDirectives);
|
||||
|
||||
virtual bool strictMode() { return pc->sc->strict; }
|
||||
|
||||
@@ -487,7 +498,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
||||
FunctionType type, FunctionSyntaxKind kind);
|
||||
bool functionArgsAndBody(Node pn, HandleFunction fun,
|
||||
FunctionType type, FunctionSyntaxKind kind,
|
||||
bool strict, bool *becameStrict = NULL);
|
||||
Directives inheritedDirectives, Directives *newDirectives);
|
||||
|
||||
Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);
|
||||
|
||||
|
||||
@@ -140,6 +140,30 @@ class FunctionContextFlags
|
||||
|
||||
class GlobalSharedContext;
|
||||
|
||||
// List of directives that may be encountered in a Directive Prologue (ES5 15.1).
|
||||
class Directives
|
||||
{
|
||||
bool strict_;
|
||||
|
||||
public:
|
||||
explicit Directives(bool strict) : strict_(strict) {}
|
||||
template <typename ParseHandler> explicit Directives(ParseContext<ParseHandler> *parent);
|
||||
|
||||
void setStrict() { strict_ = true; }
|
||||
bool strict() const { return strict_; }
|
||||
|
||||
Directives &operator=(Directives rhs) {
|
||||
strict_ = rhs.strict_;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const Directives &rhs) const {
|
||||
return strict_ == rhs.strict_;
|
||||
}
|
||||
bool operator!=(const Directives &rhs) const {
|
||||
return strict_ != rhs.strict_;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The struct SharedContext is part of the current parser context (see
|
||||
* ParseContext). It stores information that is reused between the parser and
|
||||
@@ -156,10 +180,10 @@ class SharedContext
|
||||
|
||||
// If it's function code, funbox must be non-NULL and scopeChain must be NULL.
|
||||
// If it's global code, funbox must be NULL.
|
||||
SharedContext(ExclusiveContext *cx, bool strict, bool extraWarnings)
|
||||
SharedContext(ExclusiveContext *cx, Directives directives, bool extraWarnings)
|
||||
: context(cx),
|
||||
anyCxFlags(),
|
||||
strict(strict),
|
||||
strict(directives.strict()),
|
||||
extraWarnings(extraWarnings)
|
||||
{}
|
||||
|
||||
@@ -192,8 +216,8 @@ class GlobalSharedContext : public SharedContext
|
||||
|
||||
public:
|
||||
GlobalSharedContext(ExclusiveContext *cx, JSObject *scopeChain,
|
||||
bool strict, bool extraWarnings)
|
||||
: SharedContext(cx, strict, extraWarnings),
|
||||
Directives directives, bool extraWarnings)
|
||||
: SharedContext(cx, directives, extraWarnings),
|
||||
scopeChain_(cx, scopeChain)
|
||||
{}
|
||||
|
||||
@@ -249,8 +273,8 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
|
||||
template <typename ParseHandler>
|
||||
FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
|
||||
ParseContext<ParseHandler> *pc,
|
||||
bool strict, bool extraWarnings);
|
||||
ParseContext<ParseHandler> *pc, Directives directives,
|
||||
bool extraWarnings);
|
||||
|
||||
ObjectBox *toObjectBox() { return this; }
|
||||
JSFunction *function() const { return &object->as<JSFunction>(); }
|
||||
|
||||
@@ -966,7 +966,14 @@ TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
|
||||
uint32_t i;
|
||||
if (js_IdIsIndex(id, &i))
|
||||
return;
|
||||
MarkTypeObjectUnknownProperties(cx, obj->type());
|
||||
|
||||
// But if we don't have too many properties yet, don't do anything. The
|
||||
// idea here is that normal object initialization should not trigger
|
||||
// deoptimization in most cases, while actual usage as a hashmap should.
|
||||
TypeObject* type = obj->type();
|
||||
if (type->getPropertyCount() < 8)
|
||||
return;
|
||||
MarkTypeObjectUnknownProperties(cx, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,13 +221,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=668855
|
||||
|
||||
let dummy_test_map = new WeakMap;
|
||||
|
||||
let navi_fail = false;
|
||||
let rule_fail = false;
|
||||
let got_rule = false;
|
||||
try {
|
||||
dummy_test_map.set(window.navigator, 1);
|
||||
var rule = document.styleSheets[0].cssRules[0];
|
||||
got_rule = true;
|
||||
dummy_test_map.set(rule, 1);
|
||||
} catch (e) {
|
||||
navi_fail = true;
|
||||
rule_fail = true;
|
||||
}
|
||||
ok(navi_fail, "Using window.navigator as a weak map key should produce an exception because it can't be wrapper preserved.");
|
||||
ok(got_rule, "Got the CSS rule");
|
||||
ok(rule_fail, "Using a CSS rule as a weak map key should produce an exception because it can't be wrapper preserved.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="data:text/css,div {}">
|
||||
<title>Test Cross-Compartment DOM WeakMaps</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -16,13 +16,13 @@ function setup() {
|
||||
|
||||
my_map.set(item, "success_string");
|
||||
|
||||
var navi_fail = false;
|
||||
var rule_fail = false;
|
||||
try {
|
||||
my_map.set(window.frames[0].navigator, 1);
|
||||
my_map.set(window.frames[0].document.styleSheets[0].cssRules[0], 1);
|
||||
} catch (e) {
|
||||
navi_fail = true;
|
||||
rule_fail = true;
|
||||
}
|
||||
ok(navi_fail, "Using window.navigator as a weak map key across compartments should produce an exception because it can't be wrapper preserved.");
|
||||
ok(rule_fail, "Using rule as a weak map key across compartments should produce an exception because it can't be wrapper preserved.");
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
|
||||
@@ -333,8 +333,7 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
aBottomMarginResult.Zero();
|
||||
}
|
||||
|
||||
nscoord x = mX;
|
||||
nscoord y = mY;
|
||||
nsPoint position(mX, mY);
|
||||
nscoord backupContainingBlockAdvance = 0;
|
||||
|
||||
// Check whether the block's bottom margin collapses with its top
|
||||
@@ -358,7 +357,7 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
printf(": ");
|
||||
nsFrame::ListTag(stdout, mFrame);
|
||||
printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n",
|
||||
y, mSpace.y);
|
||||
position.y, mSpace.y);
|
||||
#endif
|
||||
// Section 8.3.1 of CSS 2.1 says that blocks with adjoining
|
||||
// top/bottom margins whose top margin collapses with their
|
||||
@@ -385,7 +384,7 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
// even if there's some sort of integer overflow that makes y +
|
||||
// mMetrics.height appear to go beyond the available height.
|
||||
if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) {
|
||||
nscoord yMost = y - backupContainingBlockAdvance + mMetrics.height;
|
||||
nscoord yMost = position.y - backupContainingBlockAdvance + mMetrics.height;
|
||||
if (yMost > mSpace.YMost()) {
|
||||
// didn't fit, we must acquit.
|
||||
mFrame->DidReflow(mPresContext, &aReflowState, nsDidReflowStatus::FINISHED);
|
||||
@@ -393,20 +392,16 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
}
|
||||
|
||||
aInFlowBounds = nsRect(x, y - backupContainingBlockAdvance,
|
||||
aInFlowBounds = nsRect(position.x, position.y - backupContainingBlockAdvance,
|
||||
mMetrics.width, mMetrics.height);
|
||||
|
||||
// Apply CSS relative positioning
|
||||
const nsStyleDisplay* styleDisp = mFrame->StyleDisplay();
|
||||
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
|
||||
x += aReflowState.mComputedOffsets.left;
|
||||
y += aReflowState.mComputedOffsets.top;
|
||||
}
|
||||
aReflowState.ApplyRelativePositioning(&position);
|
||||
|
||||
// Now place the frame and complete the reflow process
|
||||
nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState, mMetrics, x, y, 0);
|
||||
nsContainerFrame::FinishReflowChild(mFrame, mPresContext, &aReflowState,
|
||||
mMetrics, position.x, position.y, 0);
|
||||
|
||||
aOverflowAreas = mMetrics.mOverflowAreas + nsPoint(x, y);
|
||||
aOverflowAreas = mMetrics.mOverflowAreas + position;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -476,12 +476,8 @@ nsCanvasFrame::Reflow(nsPresContext* aPresContext,
|
||||
|
||||
nsPoint kidPt(kidReflowState.mComputedMargin.left,
|
||||
kidReflowState.mComputedMargin.top);
|
||||
// Apply CSS relative positioning
|
||||
const nsStyleDisplay* styleDisp = kidFrame->StyleDisplay();
|
||||
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
|
||||
kidPt += nsPoint(kidReflowState.mComputedOffsets.left,
|
||||
kidReflowState.mComputedOffsets.top);
|
||||
}
|
||||
|
||||
kidReflowState.ApplyRelativePositioning(&kidPt);
|
||||
|
||||
// Reflow the frame
|
||||
ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
|
||||
|
||||
@@ -2400,12 +2400,7 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
"We gave flex item unconstrained available height, so it "
|
||||
"should be complete");
|
||||
|
||||
// Apply CSS relative positioning
|
||||
const nsStyleDisplay* styleDisp = curItem.Frame()->StyleDisplay();
|
||||
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
|
||||
physicalPosn.x += childReflowState.mComputedOffsets.left;
|
||||
physicalPosn.y += childReflowState.mComputedOffsets.top;
|
||||
}
|
||||
childReflowState.ApplyRelativePositioning(&physicalPosn);
|
||||
|
||||
rv = FinishReflowChild(curItem.Frame(), aPresContext,
|
||||
&childReflowState, childDesiredSize,
|
||||
|
||||
@@ -2934,10 +2934,6 @@ void nsGfxScrollFrameInner::CurPosAttributeChanged(nsIContent* aContent)
|
||||
(mVScrollbarBox && mVScrollbarBox->GetContent() == aContent),
|
||||
"unexpected child");
|
||||
|
||||
if (mScrollbarActivity) {
|
||||
mScrollbarActivity->ActivityOccurred();
|
||||
}
|
||||
|
||||
// Attribute changes on the scrollbars happen in one of three ways:
|
||||
// 1) The scrollbar changed the attribute in response to some user event
|
||||
// 2) We changed the attribute in response to a ScrollPositionDidChange
|
||||
@@ -2970,6 +2966,10 @@ void nsGfxScrollFrameInner::CurPosAttributeChanged(nsIContent* aContent)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mScrollbarActivity) {
|
||||
mScrollbarActivity->ActivityOccurred();
|
||||
}
|
||||
|
||||
bool isSmooth = aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::smooth);
|
||||
if (isSmooth) {
|
||||
// Make sure an attribute-setting callback occurs even if the view
|
||||
|
||||
@@ -838,6 +838,16 @@ nsHTMLReflowState::ComputeRelativeOffsets(uint8_t aCBDirection,
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsHTMLReflowState::ApplyRelativePositioning(const nsStyleDisplay* aDisplay,
|
||||
const nsMargin &aComputedOffsets,
|
||||
nsPoint* aPosition)
|
||||
{
|
||||
if (NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) {
|
||||
*aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top);
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame,
|
||||
nscoord& aCBLeftEdge,
|
||||
|
||||
@@ -533,6 +533,15 @@ public:
|
||||
nscoord aContainingBlockHeight,
|
||||
nsMargin& aComputedOffsets);
|
||||
|
||||
// If a relatively positioned element, adjust the position appropriately.
|
||||
static void ApplyRelativePositioning(const nsStyleDisplay* aDisplay,
|
||||
const nsMargin& aComputedOffsets,
|
||||
nsPoint* aPosition);
|
||||
|
||||
void ApplyRelativePositioning(nsPoint* aPosition) const {
|
||||
ApplyRelativePositioning(mStyleDisplay, mComputedOffsets, aPosition);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Reflow trace methods. Defined in nsFrame.cpp so they have access
|
||||
// to the display-reflow infrastructure.
|
||||
|
||||
@@ -2628,8 +2628,9 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflo
|
||||
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
||||
// right and bottom are handled by
|
||||
// nsHTMLReflowState::ComputeRelativeOffsets
|
||||
nsPoint change(pfd->mOffsets.left, pfd->mOffsets.top);
|
||||
origin += change;
|
||||
nsHTMLReflowState::ApplyRelativePositioning(pfd->mFrame->StyleDisplay(),
|
||||
pfd->mOffsets,
|
||||
&origin);
|
||||
frame->SetPosition(origin);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,9 @@ LOCAL_INCLUDES += \
|
||||
-I$(srcdir)/../../content/xul/document/src \
|
||||
$(NULL)
|
||||
|
||||
nsStyleStructList.h : $(srcdir)/generate-stylestructlist.py
|
||||
$(PYTHON) $< > $@
|
||||
|
||||
_FILES = \
|
||||
contenteditable.css \
|
||||
designmode.css \
|
||||
@@ -42,7 +45,10 @@ _FILES = \
|
||||
TopLevelVideoDocument.css \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE += $(addprefix $(DIST)/bin/res/,$(_FILES))
|
||||
GARBAGE += \
|
||||
$(addprefix $(DIST)/bin/res/,$(_FILES)) \
|
||||
nsStyleStructList.h \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_FILES)
|
||||
$(INSTALL) $^ $(DIST)/bin/res
|
||||
|
||||
169
layout/style/generate-stylestructlist.py
Normal file
169
layout/style/generate-stylestructlist.py
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# 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/.
|
||||
|
||||
# This script generates nsStyleStructList.h, which contains macro invocations
|
||||
# that can be used for three things:
|
||||
#
|
||||
# 1. To generate code for each inherited style struct.
|
||||
# 2. To generate code for each reset style struct.
|
||||
# 3. To generate a tree of nested if statements that can be used to run
|
||||
# some code on each style struct.
|
||||
#
|
||||
# As an example, if we assume that we have only four style structs, the
|
||||
# generated tree of nested if statements looks like this:
|
||||
#
|
||||
# if (STYLE_STRUCT_TEST < 4) {
|
||||
# if (STYLE_STRUCT_TEST < 2) {
|
||||
# if (STYLE_STRUCT_TEST == 0) {
|
||||
# ... code for style struct with id 0 ...
|
||||
# } else {
|
||||
# ... code for style struct with id 1 ...
|
||||
# }
|
||||
# } else {
|
||||
# if (STYLE_STRUCT_TEST == 2) {
|
||||
# ... code for style struct with id 2 ...
|
||||
# } else {
|
||||
# ... code for style struct with id 3 ...
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# The TOPLEVELBRANCHES variable controls how widely we branch on the outermost
|
||||
# if statement. In the example above, it splits the search space in 2, but with
|
||||
# a larger number of style structs to test -- particularly when the number is
|
||||
# closer to one power of two than the next higher one -- the average number of
|
||||
# comparisons can be reduced by splitting the top level check into more than 2.
|
||||
|
||||
import math
|
||||
|
||||
# List of style structs and their corresponding Check callback functions,
|
||||
# if any.
|
||||
STYLE_STRUCTS = [("INHERITED",) + x for x in [
|
||||
# Inherited style structs.
|
||||
("Font", "CheckFontCallback"),
|
||||
("Color", "CheckColorCallback"),
|
||||
("List", "nullptr"),
|
||||
("Text", "CheckTextCallback"),
|
||||
("Visibility", "nullptr"),
|
||||
("Quotes", "nullptr"),
|
||||
("UserInterface", "nullptr"),
|
||||
("TableBorder", "nullptr"),
|
||||
("SVG", "nullptr"),
|
||||
]] + [("RESET",) + x for x in [
|
||||
# Reset style structs.
|
||||
("Background", "nullptr"),
|
||||
("Position", "nullptr"),
|
||||
("TextReset", "nullptr"),
|
||||
("Display", "nullptr"),
|
||||
("Content", "nullptr"),
|
||||
("UIReset", "nullptr"),
|
||||
("Table", "nullptr"),
|
||||
("Margin", "nullptr"),
|
||||
("Padding", "nullptr"),
|
||||
("Border", "nullptr"),
|
||||
("Outline", "nullptr"),
|
||||
("XUL", "nullptr"),
|
||||
("SVGReset", "nullptr"),
|
||||
("Column", "nullptr"),
|
||||
]]
|
||||
|
||||
# How widely to branch on the outermost if statement.
|
||||
TOPLEVELBRANCHES = 4
|
||||
|
||||
|
||||
# ---- Generate nsStyleStructList.h ----
|
||||
|
||||
count = len(STYLE_STRUCTS)
|
||||
|
||||
def nextPowerOf2(x):
|
||||
return int(pow(2, math.ceil(math.log(x, 2))))
|
||||
|
||||
def printEntry(i):
|
||||
print "STYLE_STRUCT_%s(%s, %s)" % STYLE_STRUCTS[i]
|
||||
|
||||
def printTestTree(min, max, depth, branches):
|
||||
indent = " " * depth
|
||||
if min == count - 1 and max >= count:
|
||||
print " STYLE_STRUCT_TEST_CODE(%sNS_ASSERTION(STYLE_STRUCT_TEST == %d, \"out of range\");)" % (indent, min)
|
||||
printEntry(min)
|
||||
elif max - min == 2:
|
||||
print " STYLE_STRUCT_TEST_CODE(%sif (STYLE_STRUCT_TEST == %d) {)" % (indent, min)
|
||||
printEntry(min)
|
||||
print " STYLE_STRUCT_TEST_CODE(%s} else {)" % indent
|
||||
printEntry(min + 1)
|
||||
print " STYLE_STRUCT_TEST_CODE(%s})" % indent
|
||||
elif min < count:
|
||||
mid = min + (max - min) / branches
|
||||
print " STYLE_STRUCT_TEST_CODE(%sif (STYLE_STRUCT_TEST < %d) {)" % (indent, mid)
|
||||
printTestTree(min, mid, depth + 1, 2)
|
||||
for branch in range(1, branches):
|
||||
lo = min + branch * (max - min) / branches
|
||||
hi = min + (branch + 1) * (max - min) / branches
|
||||
if lo >= count:
|
||||
break
|
||||
if branch == branches - 1 or hi >= count:
|
||||
print " STYLE_STRUCT_TEST_CODE(%s} else {)" % indent
|
||||
else:
|
||||
print " STYLE_STRUCT_TEST_CODE(%s} else if (STYLE_STRUCT_TEST < %d) {)" % (indent, hi)
|
||||
printTestTree(lo, hi, depth + 1, 2)
|
||||
print " STYLE_STRUCT_TEST_CODE(%s})" % indent
|
||||
|
||||
HEADER = """/* THIS FILE IS AUTOGENERATED BY generate-stylestructlist.py - DO NOT EDIT */
|
||||
|
||||
// IWYU pragma: private, include "nsStyleStructFwd.h"
|
||||
|
||||
/*
|
||||
* list of structs that contain the data provided by nsStyleContext, the
|
||||
* internal API for computed style data for an element
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is intended to be used by different parts of the code, with
|
||||
* the STYLE_STRUCT macro (or the STYLE_STRUCT_INHERITED and
|
||||
* STYLE_STRUCT_RESET pair of macros) defined in different ways.
|
||||
*/
|
||||
|
||||
#ifndef STYLE_STRUCT_INHERITED
|
||||
#define STYLE_STRUCT_INHERITED(name, checkdata_cb) \\
|
||||
STYLE_STRUCT(name, checkdata_cb)
|
||||
#define UNDEF_STYLE_STRUCT_INHERITED
|
||||
#endif
|
||||
|
||||
#ifndef STYLE_STRUCT_RESET
|
||||
#define STYLE_STRUCT_RESET(name, checkdata_cb) \\
|
||||
STYLE_STRUCT(name, checkdata_cb)
|
||||
#define UNDEF_STYLE_STRUCT_RESET
|
||||
#endif
|
||||
|
||||
#ifdef STYLE_STRUCT_TEST
|
||||
#define STYLE_STRUCT_TEST_CODE(c) c
|
||||
#else
|
||||
#define STYLE_STRUCT_TEST_CODE(c)
|
||||
#endif
|
||||
|
||||
// The inherited structs are listed before the Reset structs.
|
||||
// nsStyleStructID assumes this is the case, and callers other than
|
||||
// nsStyleStructFwd.h that want the structs in id-order just define
|
||||
// STYLE_STRUCT rather than including the file twice.
|
||||
|
||||
"""
|
||||
FOOTER = """
|
||||
#ifdef UNDEF_STYLE_STRUCT_INHERITED
|
||||
#undef STYLE_STRUCT_INHERITED
|
||||
#undef UNDEF_STYLE_STRUCT_INHERITED
|
||||
#endif
|
||||
|
||||
#ifdef UNDEF_STYLE_STRUCT_RESET
|
||||
#undef STYLE_STRUCT_RESET
|
||||
#undef UNDEF_STYLE_STRUCT_RESET
|
||||
#endif
|
||||
|
||||
#undef STYLE_STRUCT_TEST_CODE
|
||||
"""
|
||||
|
||||
print HEADER
|
||||
printTestTree(0, nextPowerOf2(count), 0, TOPLEVELBRANCHES)
|
||||
print FOOTER
|
||||
@@ -1,138 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
// vim:cindent:ts=8:et:sw=4:
|
||||
/* 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/. */
|
||||
|
||||
// IWYU pragma: private, include "nsStyleStructFwd.h"
|
||||
|
||||
/*
|
||||
* list of structs that contain the data provided by nsStyleContext, the
|
||||
* internal API for computed style data for an element
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is intended to be used by different parts of the code, with
|
||||
* the STYLE_STRUCT macro (or the STYLE_STRUCT_INHERITED and
|
||||
* STYLE_STRUCT_RESET pair of macros) defined in different ways.
|
||||
*/
|
||||
|
||||
#ifndef STYLE_STRUCT_INHERITED
|
||||
#define STYLE_STRUCT_INHERITED(name, checkdata_cb) \
|
||||
STYLE_STRUCT(name, checkdata_cb)
|
||||
#define UNDEF_STYLE_STRUCT_INHERITED
|
||||
#endif
|
||||
|
||||
#ifndef STYLE_STRUCT_RESET
|
||||
#define STYLE_STRUCT_RESET(name, checkdata_cb) \
|
||||
STYLE_STRUCT(name, checkdata_cb)
|
||||
#define UNDEF_STYLE_STRUCT_RESET
|
||||
#endif
|
||||
|
||||
#ifdef STYLE_STRUCT_TEST
|
||||
#define STYLE_STRUCT_TEST_CODE(c) c
|
||||
#else
|
||||
#define STYLE_STRUCT_TEST_CODE(c)
|
||||
#endif
|
||||
|
||||
// The inherited structs must be listed before the Reset structs.
|
||||
// nsStyleStructID assumes this is the case, and callers other than
|
||||
// nsStyleStructFwd.h that want the structs in id-order just define
|
||||
// STYLE_STRUCT rather than including the file twice.
|
||||
|
||||
STYLE_STRUCT_TEST_CODE(if (STYLE_STRUCT_TEST < 8) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST < 4) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST < 2) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 0) {)
|
||||
STYLE_STRUCT_INHERITED(Font, CheckFontCallback)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_INHERITED(Color, CheckColorCallback)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 2) {)
|
||||
STYLE_STRUCT_INHERITED(List, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_INHERITED(Text, CheckTextCallback)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST < 6) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 4) {)
|
||||
STYLE_STRUCT_INHERITED(Visibility, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_INHERITED(Quotes, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 6) {)
|
||||
STYLE_STRUCT_INHERITED(UserInterface, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_INHERITED(TableBorder, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE(} else if (STYLE_STRUCT_TEST < 16) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST < 12) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST < 10) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 8) {)
|
||||
STYLE_STRUCT_INHERITED(SVG, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_RESET(Background, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 10) {)
|
||||
STYLE_STRUCT_RESET(Position, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_RESET(TextReset, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST < 14) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 12) {)
|
||||
STYLE_STRUCT_RESET(Display, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_RESET(Content, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 14) {)
|
||||
STYLE_STRUCT_RESET(UIReset, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_RESET(Table, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE(} else if (STYLE_STRUCT_TEST < 20) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST < 18) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 16) {)
|
||||
STYLE_STRUCT_RESET(Margin, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_RESET(Padding, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 18) {)
|
||||
STYLE_STRUCT_RESET(Border, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_RESET(Outline, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE(} else if (STYLE_STRUCT_TEST < 22) {)
|
||||
STYLE_STRUCT_TEST_CODE( if (STYLE_STRUCT_TEST == 20) {)
|
||||
STYLE_STRUCT_RESET(XUL, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( } else {)
|
||||
STYLE_STRUCT_RESET(SVGReset, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE( })
|
||||
STYLE_STRUCT_TEST_CODE(} else {)
|
||||
STYLE_STRUCT_TEST_CODE( NS_ASSERTION(STYLE_STRUCT_TEST == 22, "out of range");)
|
||||
STYLE_STRUCT_RESET(Column, nullptr)
|
||||
STYLE_STRUCT_TEST_CODE(})
|
||||
|
||||
#ifdef UNDEF_STYLE_STRUCT_INHERITED
|
||||
#undef STYLE_STRUCT_INHERITED
|
||||
#undef UNDEF_STYLE_STRUCT_INHERITED
|
||||
#endif
|
||||
|
||||
#ifdef UNDEF_STYLE_STRUCT_RESET
|
||||
#undef STYLE_STRUCT_RESET
|
||||
#undef UNDEF_STYLE_STRUCT_RESET
|
||||
#endif
|
||||
|
||||
#undef STYLE_STRUCT_TEST_CODE
|
||||
@@ -113,7 +113,6 @@ abstract public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
private Vector<MenuItemInfo> mAddonMenuItemsCache;
|
||||
private ButtonToast mToast;
|
||||
private PropertyAnimator mMainLayoutAnimator;
|
||||
|
||||
private static final Interpolator sTabsInterpolator = new Interpolator() {
|
||||
@@ -395,15 +394,6 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browser_toolbar);
|
||||
|
||||
mToast = new ButtonToast(findViewById(R.id.toast), new ButtonToast.ToastListener() {
|
||||
@Override
|
||||
public void onButtonClicked(CharSequence token) {
|
||||
if (ADD_SHORTCUT_TOAST.equals(token)) {
|
||||
showBookmarkDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
((GeckoApp.MainLayout) mMainLayout).setTouchEventInterceptor(new HideTabsTouchListener());
|
||||
((GeckoApp.MainLayout) mMainLayout).setMotionEventInterceptor(new MotionEventInterceptor() {
|
||||
@Override
|
||||
@@ -815,7 +805,7 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
// If the page has shrunk so that the toolbar no longer scrolls, make
|
||||
// sure the toolbar is visible.
|
||||
if (aMetrics.getPageHeight() < aMetrics.getHeight()) {
|
||||
if (aMetrics.getPageHeight() <= aMetrics.getHeight()) {
|
||||
if (mDynamicToolbarCanScroll) {
|
||||
mDynamicToolbarCanScroll = false;
|
||||
if (!mBrowserToolbar.isVisible()) {
|
||||
@@ -1449,34 +1439,20 @@ abstract public class BrowserApp extends GeckoApp
|
||||
});
|
||||
|
||||
if (info.icon != null) {
|
||||
if (info.icon.startsWith("data")) {
|
||||
BitmapDrawable drawable = new BitmapDrawable(BitmapUtils.getBitmapFromDataURI(info.icon));
|
||||
item.setIcon(drawable);
|
||||
}
|
||||
else if (info.icon.startsWith("jar:") || info.icon.startsWith("file://")) {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
BitmapUtils.getDrawable(this, info.icon, new BitmapUtils.BitmapLoader() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
URL url = new URL(info.icon);
|
||||
InputStream is = (InputStream) url.getContent();
|
||||
try {
|
||||
Drawable drawable = Drawable.createFromStream(is, "src");
|
||||
item.setIcon(drawable);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(LOGTAG, "Unable to set icon", e);
|
||||
public void onBitmapFound(Drawable d) {
|
||||
if (d == null) {
|
||||
item.setIcon(R.drawable.ic_menu_addons_filler);
|
||||
return;
|
||||
}
|
||||
|
||||
item.setIcon(d);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
item.setIcon(R.drawable.ic_menu_addons_filler);
|
||||
}
|
||||
} else {
|
||||
item.setIcon(R.drawable.ic_menu_addons_filler);
|
||||
}
|
||||
|
||||
item.setCheckable(info.checkable);
|
||||
item.setChecked(info.checked);
|
||||
@@ -1701,8 +1677,16 @@ abstract public class BrowserApp extends GeckoApp
|
||||
mToast.show(false,
|
||||
getResources().getString(R.string.bookmark_added),
|
||||
getResources().getString(R.string.bookmark_options),
|
||||
0,
|
||||
ADD_SHORTCUT_TOAST);
|
||||
null,
|
||||
new ButtonToast.ToastListener() {
|
||||
@Override
|
||||
public void onButtonClicked() {
|
||||
showBookmarkDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToastHidden(ButtonToast.ReasonHidden reason) { }
|
||||
});
|
||||
item.setIcon(R.drawable.ic_menu_bookmark_remove);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.menu.GeckoMenu;
|
||||
import org.mozilla.gecko.menu.MenuPopup;
|
||||
import org.mozilla.gecko.PageActionLayout;
|
||||
import org.mozilla.gecko.PrefsHelper;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UiAsyncTask;
|
||||
|
||||
import org.mozilla.gecko.PrefsHelper;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
@@ -63,14 +63,14 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.RelativeLayout.LayoutParams;
|
||||
import android.widget.ViewSwitcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BrowserToolbar extends GeckoRelativeLayout
|
||||
implements Tabs.OnTabsChangedListener,
|
||||
GeckoMenu.ActionItemBarPresenter,
|
||||
Animation.AnimationListener {
|
||||
Animation.AnimationListener,
|
||||
GeckoEventListener {
|
||||
private static final String LOGTAG = "GeckoToolbar";
|
||||
public static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode";
|
||||
private LayoutParams mAwesomeBarParams;
|
||||
@@ -88,7 +88,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
public ImageButton mFavicon;
|
||||
public ImageButton mStop;
|
||||
public ImageButton mSiteSecurity;
|
||||
public ImageButton mReader;
|
||||
public PageActionLayout mPageActionLayout;
|
||||
private AnimationDrawable mProgressSpinner;
|
||||
private TabCounter mTabsCounter;
|
||||
private ImageView mShadow;
|
||||
@@ -183,6 +183,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
mDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext));
|
||||
mPrivateDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext_private));
|
||||
|
||||
registerEventListener("Reader:Click");
|
||||
registerEventListener("Reader:LongClick");
|
||||
|
||||
mShowSiteSecurity = false;
|
||||
mShowReader = false;
|
||||
|
||||
@@ -221,8 +224,8 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
mProgressSpinner = (AnimationDrawable) res.getDrawable(R.drawable.progress_spinner);
|
||||
|
||||
mStop = (ImageButton) findViewById(R.id.stop);
|
||||
mReader = (ImageButton) findViewById(R.id.reader);
|
||||
mShadow = (ImageView) findViewById(R.id.shadow);
|
||||
mPageActionLayout = (PageActionLayout) findViewById(R.id.page_action_layout);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
mShadow.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
@@ -237,9 +240,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
// order appropriately.
|
||||
if (HardwareUtils.isTablet()) {
|
||||
mFocusOrder = Arrays.asList(mTabs, mBack, mForward, this,
|
||||
mSiteSecurity, mReader, mStop, mActionItemBar, mMenu);
|
||||
mSiteSecurity, mPageActionLayout, mStop, mActionItemBar, mMenu);
|
||||
} else {
|
||||
mFocusOrder = Arrays.asList(this, mSiteSecurity, mReader, mStop,
|
||||
mFocusOrder = Arrays.asList(this, mSiteSecurity, mPageActionLayout, mStop,
|
||||
mTabs, mMenu);
|
||||
}
|
||||
}
|
||||
@@ -353,28 +356,6 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
}
|
||||
});
|
||||
|
||||
mReader.setOnClickListener(new Button.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
tab.toggleReaderMode();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mReader.setOnLongClickListener(new Button.OnLongClickListener() {
|
||||
public boolean onLongClick(View v) {
|
||||
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
tab.addToReadingList();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mShadow.setOnClickListener(new Button.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@@ -474,7 +455,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
if (showProgress && tab.getState() == Tab.STATE_LOADING)
|
||||
setProgressVisibility(true);
|
||||
setSecurityMode(tab.getSecurityMode());
|
||||
setReaderMode(tab.getReaderEnabled());
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
break;
|
||||
case STOP:
|
||||
@@ -519,7 +500,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
break;
|
||||
case READER_ENABLED:
|
||||
if (Tabs.getInstance().isSelectedTab(tab)) {
|
||||
setReaderMode(tab.getReaderEnabled());
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -537,7 +518,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
mFavicon.setNextFocusDownId(nextId);
|
||||
mStop.setNextFocusDownId(nextId);
|
||||
mSiteSecurity.setNextFocusDownId(nextId);
|
||||
mReader.setNextFocusDownId(nextId);
|
||||
mPageActionLayout.setNextFocusDownId(nextId);
|
||||
mMenu.setNextFocusDownId(nextId);
|
||||
}
|
||||
|
||||
@@ -613,7 +594,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
ViewHelper.setTranslationX(mMenuIcon, curveTranslation);
|
||||
}
|
||||
|
||||
ViewHelper.setAlpha(mReader, 0);
|
||||
ViewHelper.setAlpha(mPageActionLayout, 0);
|
||||
ViewHelper.setAlpha(mStop, 0);
|
||||
}
|
||||
|
||||
@@ -661,7 +642,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
|
||||
// Fade toolbar buttons (reader, stop) after the entry
|
||||
// is schrunk back to its original size.
|
||||
buttonsAnimator.attach(mReader,
|
||||
buttonsAnimator.attach(mPageActionLayout,
|
||||
PropertyAnimator.Property.ALPHA,
|
||||
1);
|
||||
buttonsAnimator.attach(mStop,
|
||||
@@ -708,7 +689,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
setSelected(true);
|
||||
|
||||
// Hide stop/reader buttons immediately
|
||||
ViewHelper.setAlpha(mReader, 0);
|
||||
ViewHelper.setAlpha(mPageActionLayout, 0);
|
||||
ViewHelper.setAlpha(mStop, 0);
|
||||
|
||||
// Slide the right side elements of the toolbar
|
||||
@@ -827,22 +808,16 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
// Handle the viewing mode page actions
|
||||
setSiteSecurityVisibility(mShowSiteSecurity && !isLoading);
|
||||
|
||||
// Handle the readerMode image and visibility: We show the reader mode button if 1) you can
|
||||
// enter reader mode for current page or 2) if you're already in reader mode,
|
||||
// in which case we show the reader mode "close" (reader_active) icon.
|
||||
boolean inReaderMode = false;
|
||||
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null)
|
||||
inReaderMode = ReaderModeUtils.isAboutReader(tab.getURL());
|
||||
mReader.setImageResource(inReaderMode ? R.drawable.reader_active : R.drawable.reader);
|
||||
|
||||
mReader.setVisibility(!isLoading && (mShowReader || inReaderMode) ? View.VISIBLE : View.GONE);
|
||||
|
||||
mPageActionLayout.setVisibility(!isLoading ? View.VISIBLE : View.GONE);
|
||||
// We want title to fill the whole space available for it when there are icons
|
||||
// being shown on the right side of the toolbar as the icons already have some
|
||||
// padding in them. This is just to avoid wasting space when icons are shown.
|
||||
mTitle.setPadding(0, 0, (!isLoading && !(mShowReader || inReaderMode) ? mTitlePadding : 0), 0);
|
||||
|
||||
updateFocusOrder();
|
||||
}
|
||||
|
||||
@@ -997,11 +972,6 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
|
||||
private void setReaderMode(boolean showReader) {
|
||||
mShowReader = showReader;
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
|
||||
public void prepareTabsAnimation(PropertyAnimator animator, boolean tabsAreShown) {
|
||||
if (!tabsAreShown) {
|
||||
PropertyAnimator buttonsAnimator =
|
||||
@@ -1162,7 +1132,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
setFavicon(tab.getFavicon());
|
||||
setProgressVisibility(tab.getState() == Tab.STATE_LOADING);
|
||||
setSecurityMode(tab.getSecurityMode());
|
||||
setReaderMode(tab.getReaderEnabled());
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
setShadowVisibility(true);
|
||||
updateBackButton(tab.canDoBack());
|
||||
updateForwardButton(tab.canDoForward());
|
||||
@@ -1189,6 +1159,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
mPrefObserverId = null;
|
||||
}
|
||||
Tabs.unregisterOnTabsChangedListener(this);
|
||||
|
||||
unregisterEventListener("Reader:Click");
|
||||
unregisterEventListener("Reader:LongClick");
|
||||
}
|
||||
|
||||
public boolean openOptionsMenu() {
|
||||
@@ -1225,4 +1198,27 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void registerEventListener(String event) {
|
||||
GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
|
||||
}
|
||||
|
||||
protected void unregisterEventListener(String event) {
|
||||
GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
if (event.equals("Reader:Click")) {
|
||||
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
tab.toggleReaderMode();
|
||||
}
|
||||
} else if (event.equals("Reader:LongClick")) {
|
||||
Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
tab.addToReadingList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.mozilla.gecko.util.GeckoEventResponder;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UiAsyncTask;
|
||||
import org.mozilla.gecko.widget.ButtonToast;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@@ -44,6 +45,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.Sensor;
|
||||
@@ -187,6 +189,7 @@ abstract public class GeckoApp
|
||||
protected DoorHangerPopup mDoorHangerPopup;
|
||||
protected FormAssistPopup mFormAssistPopup;
|
||||
protected TabsPanel mTabsPanel;
|
||||
protected ButtonToast mToast;
|
||||
|
||||
// Handles notification messages from javascript
|
||||
protected NotificationHelper mNotificationHelper;
|
||||
@@ -545,8 +548,16 @@ abstract public class GeckoApp
|
||||
try {
|
||||
if (event.equals("Toast:Show")) {
|
||||
final String msg = message.getString("message");
|
||||
final JSONObject button = message.optJSONObject("button");
|
||||
if (button != null) {
|
||||
final String label = button.optString("label");
|
||||
final String icon = button.optString("icon");
|
||||
final String id = button.optString("id");
|
||||
showButtonToast(msg, label, icon, id);
|
||||
} else {
|
||||
final String duration = message.getString("duration");
|
||||
handleShowToast(msg, duration);
|
||||
showNormalToast(msg, duration);
|
||||
}
|
||||
} else if (event.equals("log")) {
|
||||
// generic log listener
|
||||
final String msg = message.getString("msg");
|
||||
@@ -810,20 +821,42 @@ abstract public class GeckoApp
|
||||
});
|
||||
}
|
||||
|
||||
void handleShowToast(final String message, final String duration) {
|
||||
public void showNormalToast(final String message, final String duration) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast toast;
|
||||
if (duration.equals("long"))
|
||||
if (duration.equals("long")) {
|
||||
toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_LONG);
|
||||
else
|
||||
} else {
|
||||
toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_SHORT);
|
||||
}
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void showButtonToast(final String message, final String buttonText,
|
||||
final String buttonIcon, final String buttonId) {
|
||||
BitmapUtils.getDrawable(GeckoApp.this, buttonIcon, new BitmapUtils.BitmapLoader() {
|
||||
public void onBitmapFound(Drawable d) {
|
||||
mToast.show(false, message, buttonText, d, new ButtonToast.ToastListener() {
|
||||
@Override
|
||||
public void onButtonClicked() {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Toast:Click", buttonId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToastHidden(ButtonToast.ReasonHidden reason) {
|
||||
if (reason == ButtonToast.ReasonHidden.TIMEOUT) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Toast:Hidden", buttonId));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addFullScreenPluginView(View view) {
|
||||
if (mFullScreenPluginView != null) {
|
||||
Log.w(LOGTAG, "Already have a fullscreen plugin view");
|
||||
@@ -1278,6 +1311,7 @@ abstract public class GeckoApp
|
||||
// Set up tabs panel.
|
||||
mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel);
|
||||
mNotificationHelper = new NotificationHelper(this);
|
||||
mToast = new ButtonToast(findViewById(R.id.toast));
|
||||
|
||||
// Check if the last run was exited due to a normal kill while
|
||||
// we were in the background, or a more harsh kill while we were
|
||||
|
||||
@@ -129,6 +129,7 @@ FENNEC_JAVA_FILES = \
|
||||
NotificationService.java \
|
||||
NSSBridge.java \
|
||||
OrderedBroadcastHelper.java \
|
||||
PageActionLayout.java \
|
||||
PrefsHelper.java \
|
||||
PrivateDataPreference.java \
|
||||
PrivateTab.java \
|
||||
@@ -641,6 +642,7 @@ RES_DRAWABLE_MDPI = \
|
||||
res/drawable-mdpi/ic_menu_new_tab.png \
|
||||
res/drawable-mdpi/ic_menu_reload.png \
|
||||
res/drawable-mdpi/ic_status_logo.png \
|
||||
res/drawable-mdpi/icon_pageaction.png \
|
||||
res/drawable-mdpi/progress_spinner_1.png \
|
||||
res/drawable-mdpi/progress_spinner_2.png \
|
||||
res/drawable-mdpi/progress_spinner_3.png \
|
||||
@@ -763,6 +765,7 @@ RES_DRAWABLE_HDPI = \
|
||||
res/drawable-hdpi/ic_menu_new_tab.png \
|
||||
res/drawable-hdpi/ic_menu_reload.png \
|
||||
res/drawable-hdpi/ic_status_logo.png \
|
||||
res/drawable-hdpi/icon_pageaction.png \
|
||||
res/drawable-hdpi/tab_indicator_divider.9.png \
|
||||
res/drawable-hdpi/tab_indicator_selected.9.png \
|
||||
res/drawable-hdpi/tab_indicator_selected_focused.9.png \
|
||||
@@ -861,6 +864,7 @@ RES_DRAWABLE_XHDPI = \
|
||||
res/drawable-xhdpi/ic_menu_new_tab.png \
|
||||
res/drawable-xhdpi/ic_menu_reload.png \
|
||||
res/drawable-xhdpi/ic_status_logo.png \
|
||||
res/drawable-xhdpi/icon_pageaction.png \
|
||||
res/drawable-xhdpi/spinner_default.9.png \
|
||||
res/drawable-xhdpi/spinner_focused.9.png \
|
||||
res/drawable-xhdpi/spinner_pressed.9.png \
|
||||
|
||||
315
mobile/android/base/PageActionLayout.java
Normal file
315
mobile/android/base/PageActionLayout.java
Normal file
@@ -0,0 +1,315 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.widget.GeckoPopupMenu;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class PageActionLayout extends LinearLayout implements GeckoEventListener,
|
||||
View.OnClickListener,
|
||||
View.OnLongClickListener {
|
||||
private final String LOGTAG = "GeckoPageActionLayout";
|
||||
private final String MENU_BUTTON_KEY = "MENU_BUTTON_KEY";
|
||||
private final int DEFAULT_PAGE_ACTIONS_SHOWN = 2;
|
||||
|
||||
private LinkedHashMap<String, PageAction> mPageActionList;
|
||||
private GeckoPopupMenu mPageActionsMenu;
|
||||
private Context mContext;
|
||||
private LinearLayout mLayout;
|
||||
|
||||
// By default it's two, can be changed by calling setNumberShown(int)
|
||||
private int mMaxVisiblePageActions;
|
||||
|
||||
public PageActionLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
mLayout = this;
|
||||
|
||||
mPageActionList = new LinkedHashMap<String, PageAction>();
|
||||
setNumberShown(DEFAULT_PAGE_ACTIONS_SHOWN);
|
||||
|
||||
registerEventListener("PageActions:Add");
|
||||
registerEventListener("PageActions:Remove");
|
||||
}
|
||||
|
||||
public void setNumberShown(int count) {
|
||||
mMaxVisiblePageActions = count;
|
||||
|
||||
for(int index = 0; index < count; index++) {
|
||||
if ((this.getChildCount() - 1) < index) {
|
||||
mLayout.addView(createImageButton());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
unregisterEventListener("PageActions:Add");
|
||||
unregisterEventListener("PageActions:Remove");
|
||||
}
|
||||
|
||||
protected void registerEventListener(String event) {
|
||||
GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
|
||||
}
|
||||
|
||||
protected void unregisterEventListener(String event) {
|
||||
GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
try {
|
||||
if (event.equals("PageActions:Add")) {
|
||||
final String id = message.getString("id");
|
||||
final String title = message.getString("title");
|
||||
final String imageURL = message.optString("icon");
|
||||
|
||||
addPageAction(id, title, imageURL, new OnPageActionClickListeners() {
|
||||
@Override
|
||||
public void onClick(String id) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("PageActions:Clicked", id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(String id) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("PageActions:LongClicked", id));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else if (event.equals("PageActions:Remove")) {
|
||||
final String id = message.getString("id");
|
||||
|
||||
removePageAction(id);
|
||||
}
|
||||
} catch(JSONException ex) {
|
||||
Log.e(LOGTAG, "Error deocding", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPageAction(final String id, final String title, final String imageData, final OnPageActionClickListeners mOnPageActionClickListeners) {
|
||||
final PageAction pageAction = new PageAction(id, title, null, mOnPageActionClickListeners);
|
||||
mPageActionList.put(id, pageAction);
|
||||
|
||||
BitmapUtils.getDrawable(mContext, imageData, new BitmapUtils.BitmapLoader() {
|
||||
@Override
|
||||
public void onBitmapFound(final Drawable d) {
|
||||
if (mPageActionList.containsKey(id)) {
|
||||
pageAction.setDrawable(d);
|
||||
refreshPageActionIcons();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removePageAction(String id) {
|
||||
mPageActionList.remove(id);
|
||||
refreshPageActionIcons();
|
||||
}
|
||||
|
||||
private ImageButton createImageButton() {
|
||||
ImageButton imageButton = new ImageButton(mContext, null, R.style.AddressBar_ImageButton_Icon);
|
||||
imageButton.setLayoutParams(new LayoutParams(mContext.getResources().getDimensionPixelSize(R.dimen.page_action_button_width), LayoutParams.MATCH_PARENT));
|
||||
imageButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||
imageButton.setOnClickListener(this);
|
||||
imageButton.setOnLongClickListener(this);
|
||||
return imageButton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String buttonClickedId = (String)v.getTag();
|
||||
if (buttonClickedId != null) {
|
||||
if (buttonClickedId.equals(MENU_BUTTON_KEY)) {
|
||||
showMenu(v, mPageActionList.size() - mMaxVisiblePageActions + 1);
|
||||
} else {
|
||||
mPageActionList.get(buttonClickedId).onClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
String buttonClickedId = (String)v.getTag();
|
||||
if (buttonClickedId.equals(MENU_BUTTON_KEY)) {
|
||||
showMenu(v, mPageActionList.size() - mMaxVisiblePageActions + 1);
|
||||
return true;
|
||||
} else {
|
||||
return mPageActionList.get(buttonClickedId).onLongClick();
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshPageActionIcons() {
|
||||
final Resources resources = mContext.getResources();
|
||||
for(int index = 0; index < this.getChildCount(); index++) {
|
||||
final ImageButton v = (ImageButton)this.getChildAt(index);
|
||||
final PageAction pageAction = getPageActionForViewAt(index);
|
||||
|
||||
if (index == (this.getChildCount() - 1)) {
|
||||
String id = (pageAction != null) ? pageAction.getID() : null;
|
||||
v.setTag((mPageActionList.size() > mMaxVisiblePageActions) ? MENU_BUTTON_KEY : id);
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run () {
|
||||
// If there are more pageactions then buttons, set the menu icon. Otherwise set the page action's icon if there is a page action.
|
||||
Drawable d = (pageAction != null) ? pageAction.getDrawable() : null;
|
||||
v.setImageDrawable((mPageActionList.size() > mMaxVisiblePageActions) ? resources.getDrawable(R.drawable.icon_pageaction) : d);
|
||||
v.setVisibility((pageAction != null) ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
v.setTag((pageAction != null) ? pageAction.getID() : null);
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run () {
|
||||
v.setImageDrawable((pageAction != null) ? pageAction.getDrawable() : null);
|
||||
v.setVisibility((pageAction != null) ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PageAction getPageActionForViewAt(int index) {
|
||||
/**
|
||||
* We show the user the most recent pageaction added since this keeps the user aware of any new page actions being added
|
||||
* Also, the order of the pageAction is important i.e. if a page action is added, instead of shifting the pagactions to the
|
||||
* left to make space for the new one, it would be more visually appealing to have the pageaction appear in the blank space.
|
||||
*
|
||||
* buttonIndex is needed for this reason because every new View added to PageActionLayout gets added to the right of its neighbouring View.
|
||||
* Hence the button on the very leftmost has the index 0. We want our pageactions to start from the rightmost
|
||||
* and hence we maintain the insertion order of the child Views which is essentially the reverse of their index
|
||||
*/
|
||||
|
||||
int buttonIndex = (this.getChildCount() - 1) - index;
|
||||
int totalVisibleButtons = ((mPageActionList.size() < this.getChildCount()) ? mPageActionList.size() : this.getChildCount());
|
||||
|
||||
if (mPageActionList.size() > buttonIndex) {
|
||||
// Return the pageactions starting from the end of the list for the number of visible pageactions.
|
||||
return getPageActionAt((mPageActionList.size() - totalVisibleButtons) + buttonIndex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private PageAction getPageActionAt(int index) {
|
||||
int count = 0;
|
||||
for(PageAction pageAction : mPageActionList.values()) {
|
||||
if (count == index) {
|
||||
return pageAction;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void showMenu(View mPageActionButton, int toShow) {
|
||||
if (mPageActionsMenu == null) {
|
||||
mPageActionsMenu = new GeckoPopupMenu(mPageActionButton.getContext(), mPageActionButton);
|
||||
mPageActionsMenu.inflate(0);
|
||||
mPageActionsMenu.setOnMenuItemClickListener(new GeckoPopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
for(PageAction pageAction : mPageActionList.values()) {
|
||||
if (pageAction.key() == item.getItemId()) {
|
||||
pageAction.onClick();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
Menu menu = mPageActionsMenu.getMenu();
|
||||
menu.clear();
|
||||
|
||||
int count = 0;
|
||||
for(PageAction pageAction : mPageActionList.values()) {
|
||||
if (count < toShow) {
|
||||
MenuItem item = menu.add(Menu.NONE, pageAction.key(), Menu.NONE, pageAction.getTitle());
|
||||
item.setIcon(pageAction.getDrawable());
|
||||
}
|
||||
count++;
|
||||
}
|
||||
mPageActionsMenu.show();
|
||||
}
|
||||
|
||||
public static interface OnPageActionClickListeners {
|
||||
public void onClick(String id);
|
||||
public boolean onLongClick(String id);
|
||||
}
|
||||
|
||||
private static class PageAction {
|
||||
private OnPageActionClickListeners mOnPageActionClickListeners;
|
||||
private Drawable mDrawable;
|
||||
private String mTitle;
|
||||
private String mId;
|
||||
private int key;
|
||||
|
||||
public PageAction(String id, String title, Drawable image, OnPageActionClickListeners mOnPageActionClickListeners) {
|
||||
this.mId = id;
|
||||
this.mTitle = title;
|
||||
this.mDrawable = image;
|
||||
this.mOnPageActionClickListeners = mOnPageActionClickListeners;
|
||||
|
||||
this.key = UUID.fromString(mId.subSequence(1, mId.length() - 2).toString()).hashCode();
|
||||
}
|
||||
|
||||
public Drawable getDrawable() {
|
||||
return mDrawable;
|
||||
}
|
||||
|
||||
public void setDrawable(Drawable d) {
|
||||
this.mDrawable = d;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public int key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void onClick() {
|
||||
if (mOnPageActionClickListeners != null) {
|
||||
mOnPageActionClickListeners.onClick(mId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onLongClick() {
|
||||
if (mOnPageActionClickListeners != null) {
|
||||
return mOnPageActionClickListeners.onLongClick(mId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,22 @@
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.GeckoJarReader;
|
||||
import org.mozilla.gecko.util.UiAsyncTask;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
@@ -27,6 +35,70 @@ public final class BitmapUtils {
|
||||
|
||||
private BitmapUtils() {}
|
||||
|
||||
public interface BitmapLoader {
|
||||
public void onBitmapFound(Drawable d);
|
||||
}
|
||||
|
||||
/* Given a string url, returns a drawable for the bitmap. Should work with data, file, jar,
|
||||
* or chrome (converted to jar:jar) urls. Results are sent to the passed in BitmapLoader object.
|
||||
* Can return null if a Drawable couldn't be created.
|
||||
* Results are always posted on the UI thread.
|
||||
* TODO: Support for http(s) and drawable urls.
|
||||
*/
|
||||
public static void getDrawable(final Context context, final String data, final BitmapLoader loader) {
|
||||
if (TextUtils.isEmpty(data)) {
|
||||
postResultToUiThread(null, loader);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.startsWith("data")) {
|
||||
BitmapDrawable d = new BitmapDrawable(getBitmapFromDataURI(data));
|
||||
postResultToUiThread(d, loader);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.startsWith("jar:") && !data.startsWith("file://")) {
|
||||
postResultToUiThread(null, loader);
|
||||
return;
|
||||
}
|
||||
|
||||
(new UiAsyncTask<Void, Void, Drawable>(ThreadUtils.getBackgroundHandler()) {
|
||||
@Override
|
||||
public Drawable doInBackground(Void... params) {
|
||||
try {
|
||||
if (data.startsWith("jar:jar")) {
|
||||
return GeckoJarReader.getBitmapDrawable(context.getResources(), data);
|
||||
}
|
||||
|
||||
URL url = new URL(data);
|
||||
InputStream is = (InputStream) url.getContent();
|
||||
try {
|
||||
return Drawable.createFromStream(is, "src");
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(LOGTAG, "Unable to set icon", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute(Drawable drawable) {
|
||||
postResultToUiThread(drawable, loader);
|
||||
}
|
||||
}).execute();
|
||||
}
|
||||
|
||||
private static void postResultToUiThread(final Drawable d, final BitmapLoader loader) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
loader.onBitmapFound(d);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Bitmap decodeByteArray(byte[] bytes) {
|
||||
return decodeByteArray(bytes, null);
|
||||
}
|
||||
|
||||
@@ -854,6 +854,21 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
viewportMetricsChanged(true);
|
||||
}
|
||||
|
||||
/** Implementation of PanZoomTarget
|
||||
* Notification that a subdocument has been scrolled by a certain amount.
|
||||
* This is used here to make sure that the margins are still accessible
|
||||
* during subdocument scrolling.
|
||||
*
|
||||
* You must hold the monitor while calling this.
|
||||
*/
|
||||
@Override
|
||||
public void onSubdocumentScrollBy(float dx, float dy) {
|
||||
ImmutableViewportMetrics newMarginsMetrics =
|
||||
mMarginsAnimator.scrollBy(mViewportMetrics, dx, dy);
|
||||
mViewportMetrics = mViewportMetrics.setMarginsFrom(newMarginsMetrics);
|
||||
viewportMetricsChanged(true);
|
||||
}
|
||||
|
||||
/** Implementation of PanZoomTarget */
|
||||
@Override
|
||||
public void panZoomStopped() {
|
||||
|
||||
@@ -806,7 +806,11 @@ class JavaPanZoomController
|
||||
if (FloatUtils.fuzzyEquals(displacement.x, 0.0f) && FloatUtils.fuzzyEquals(displacement.y, 0.0f)) {
|
||||
return;
|
||||
}
|
||||
if (! mSubscroller.scrollBy(displacement)) {
|
||||
if (mSubscroller.scrollBy(displacement)) {
|
||||
synchronized (mTarget.getLock()) {
|
||||
mTarget.onSubdocumentScrollBy(displacement.x, displacement.y);
|
||||
}
|
||||
} else {
|
||||
synchronized (mTarget.getLock()) {
|
||||
scrollBy(displacement.x, displacement.y);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public interface PanZoomTarget {
|
||||
public void setAnimationTarget(ImmutableViewportMetrics viewport);
|
||||
public void setViewportMetrics(ImmutableViewportMetrics viewport);
|
||||
public void scrollBy(float dx, float dy);
|
||||
public void onSubdocumentScrollBy(float dx, float dy);
|
||||
public void panZoomStopped();
|
||||
/** This triggers an (asynchronous) viewport update/redraw. */
|
||||
public void forceRedraw(DisplayPortMetrics displayPort);
|
||||
|
||||
@@ -105,7 +105,7 @@ public class MenuPopup extends PopupWindow {
|
||||
((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mPopupWidth - anchor.getWidth() + arrowOffset;
|
||||
} else {
|
||||
// right align
|
||||
((LayoutParams) mArrowTop.getLayoutParams()).rightMargin = mArrowMargin;
|
||||
((LayoutParams) mArrowTop.getLayoutParams()).rightMargin = screenWidth - anchorLocation[0] - anchor.getWidth()/2 - arrowWidth/2;
|
||||
((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mArrowMargin;
|
||||
}
|
||||
|
||||
|
||||
BIN
mobile/android/base/resources/drawable-hdpi/icon_pageaction.png
Normal file
BIN
mobile/android/base/resources/drawable-hdpi/icon_pageaction.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 187 B |
BIN
mobile/android/base/resources/drawable-mdpi/icon_pageaction.png
Normal file
BIN
mobile/android/base/resources/drawable-mdpi/icon_pageaction.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 B |
BIN
mobile/android/base/resources/drawable-xhdpi/icon_pageaction.png
Normal file
BIN
mobile/android/base/resources/drawable-xhdpi/icon_pageaction.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 289 B |
@@ -103,11 +103,12 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
gecko:autoUpdateTheme="false"/>
|
||||
|
||||
<ImageButton android:id="@+id/reader"
|
||||
style="@style/AddressBar.ImageButton.Icon"
|
||||
android:src="@drawable/reader"
|
||||
android:contentDescription="@string/reader"
|
||||
android:visibility="gone"/>
|
||||
<org.mozilla.gecko.PageActionLayout android:id="@+id/page_action_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginRight="@dimen/browser_toolbar_button_padding"
|
||||
android:visibility="gone"
|
||||
android:orientation="horizontal"/>
|
||||
|
||||
<ImageButton android:id="@+id/stop"
|
||||
style="@style/AddressBar.ImageButton.Icon"
|
||||
|
||||
@@ -129,11 +129,12 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
gecko:autoUpdateTheme="false"/>
|
||||
|
||||
<ImageButton android:id="@+id/reader"
|
||||
style="@style/AddressBar.ImageButton.Icon"
|
||||
android:src="@drawable/reader"
|
||||
android:contentDescription="@string/reader"
|
||||
android:visibility="gone"/>
|
||||
<org.mozilla.gecko.PageActionLayout android:id="@+id/page_action_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginRight="12dp"
|
||||
android:visibility="gone"
|
||||
android:orientation="horizontal"/>
|
||||
|
||||
<ImageButton android:id="@+id/stop"
|
||||
style="@style/AddressBar.ImageButton.Icon"
|
||||
|
||||
@@ -76,4 +76,8 @@
|
||||
<dimen name="validation_message_margin_top">6dp</dimen>
|
||||
<dimen name="forward_default_offset">-13dip</dimen>
|
||||
<dimen name="addressbar_offset_left">32dp</dimen>
|
||||
|
||||
<!-- PageActionButtons dimensions -->
|
||||
<dimen name="page_action_button_width">32dp</dimen>
|
||||
<dimen name="toast_button_padding">8dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -506,7 +506,7 @@
|
||||
<item name="android:textAppearance">?android:textAppearanceSmall</item>
|
||||
<item name="android:paddingTop">0dp</item>
|
||||
<item name="android:paddingBottom">0dp</item>
|
||||
<item name="android:paddingLeft">8dp</item>
|
||||
<item name="android:paddingLeft">@dimen/toast_button_padding</item>
|
||||
<item name="android:paddingRight">0dp</item>
|
||||
<item name="android:layout_marginTop">0dp</item>
|
||||
<item name="android:layout_marginBottom">0dp</item>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user