Merge mozilla-central and inbound

This commit is contained in:
Ed Morley
2013-07-16 10:02:20 +01:00
108 changed files with 3230 additions and 1092 deletions

View File

@@ -17,4 +17,5 @@
# #
# Modifying this file will now automatically clobber the buildbot machines \o/ # 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.

View File

@@ -6868,7 +6868,7 @@ var gIdentityHandler = {
continue; continue;
let menuitem = document.createElement("menuitem"); let menuitem = document.createElement("menuitem");
menuitem.setAttribute("value", state); menuitem.setAttribute("value", state);
menuitem.setAttribute("label", SitePermissions.getStateLabel(state)); menuitem.setAttribute("label", SitePermissions.getStateLabel(aPermission, state));
menupopup.appendChild(menuitem); menupopup.appendChild(menuitem);
} }
menulist.appendChild(menupopup); menulist.appendChild(menupopup);

View File

@@ -134,7 +134,7 @@ function createRow(aPartId) {
for (let state of SitePermissions.getAvailableStates(aPartId)) { for (let state of SitePermissions.getAvailableStates(aPartId)) {
let radio = document.createElement("radio"); let radio = document.createElement("radio");
radio.setAttribute("id", aPartId + "#" + state); radio.setAttribute("id", aPartId + "#" + state);
radio.setAttribute("label", SitePermissions.getStateLabel(state)); radio.setAttribute("label", SitePermissions.getStateLabel(aPartId, state));
radio.setAttribute("command", commandId); radio.setAttribute("command", commandId);
radiogroup.appendChild(radio); radiogroup.appendChild(radio);
} }

View File

@@ -9,6 +9,8 @@ let Cu = Components.utils;
const appStartup = Services.startup; const appStartup = Services.startup;
Cu.import("resource://gre/modules/ResetProfile.jsm");
let defaultToReset = false; let defaultToReset = false;
function restartApp() { function restartApp() {
@@ -69,7 +71,7 @@ function onLoad() {
if (appStartup.automaticSafeModeNecessary) { if (appStartup.automaticSafeModeNecessary) {
document.getElementById("autoSafeMode").hidden = false; document.getElementById("autoSafeMode").hidden = false;
document.getElementById("safeMode").hidden = true; document.getElementById("safeMode").hidden = true;
if (resetSupported()) { if (ResetProfile.resetSupported()) {
populateResetPane("resetProfileItems"); populateResetPane("resetProfileItems");
document.getElementById("resetProfile").hidden = false; document.getElementById("resetProfile").hidden = false;
} else { } else {
@@ -77,7 +79,7 @@ function onLoad() {
document.documentElement.getButton("extra1").hidden = true; document.documentElement.getButton("extra1").hidden = true;
} }
} else { } else {
if (!resetSupported()) { if (!ResetProfile.resetSupported()) {
// Hide the reset button and text if it's not supported. // Hide the reset button and text if it's not supported.
document.documentElement.getButton("extra1").hidden = true; document.documentElement.getButton("extra1").hidden = true;
document.getElementById("resetProfileInstead").hidden = true; document.getElementById("resetProfileInstead").hidden = true;

View File

@@ -200,8 +200,24 @@ function checkSocialUI(win) {
let active = Social.providers.length > 0 && !win.SocialUI._chromeless && let active = Social.providers.length > 0 && !win.SocialUI._chromeless &&
!PrivateBrowsingUtils.isWindowPrivate(win); !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) { function isbool(a, b, msg) {
is(!!a, !!b, msg); _is(!!a, !!b, msg);
} }
isbool(win.SocialSidebar.canShow, enabled, "social sidebar active?"); isbool(win.SocialSidebar.canShow, enabled, "social sidebar active?");
if (enabled) if (enabled)
@@ -216,15 +232,15 @@ function checkSocialUI(win) {
isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?"); isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?");
if (active) { if (active) {
if (!enabled) { 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 { } 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 // the menus should always have the provider name
if (provider) { if (provider) {
for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"]) 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. // 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:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
isbool(!doc.getElementById("Social:FocusChat").hidden, enabled && Social.haveLoggedInUser(), "Social:FocusChat 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?"); 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. // broadcasters.
isbool(!doc.getElementById("socialActiveBroadcaster").hidden, active, "socialActiveBroadcaster hidden?"); 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 // blocklist testing

View File

@@ -1180,6 +1180,9 @@ var StartUI = {
// of the keyboard transition. // of the keyboard transition.
ContentAreaObserver.navBarWillBlur(); ContentAreaObserver.navBarWillBlur();
} }
if (aEvent.button == 0)
ContextUI.dismissTabs();
}, },
handleEvent: function handleEvent(aEvent) { handleEvent: function handleEvent(aEvent) {

View File

@@ -89,11 +89,11 @@ this.SitePermissions = {
/* Removes the saved state of a particular permission for a given URI. /* Removes the saved state of a particular permission for a given URI.
*/ */
remove: function (aURI, aPermission) { remove: function (aURI, aPermissionID) {
if (!this.isSupportedURI(aURI)) if (!this.isSupportedURI(aURI))
return; return;
Services.perms.remove(aURI.host, aPermission); Services.perms.remove(aURI.host, aPermissionID);
if (aPermissionID in gPermissionObject && if (aPermissionID in gPermissionObject &&
gPermissionObject[aPermissionID].onChange) gPermissionObject[aPermissionID].onChange)
@@ -110,7 +110,14 @@ this.SitePermissions = {
/* Returns the localized label for the given permission state, to be used in /* Returns the localized label for the given permission state, to be used in
* a UI for managing permissions. * 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) { switch (aState) {
case this.UNKNOWN: case this.UNKNOWN:
return gStringBundle.GetStringFromName("alwaysAsk"); return gStringBundle.GetStringFromName("alwaysAsk");
@@ -140,6 +147,11 @@ let gPermissionObject = {
* Defaults to UNKNOWN, indicating that the user will be asked each time * Defaults to UNKNOWN, indicating that the user will be asked each time
* a page asks for that permissions. * 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 * - onChange
* Called when a permission state changes. * Called when a permission state changes.
* *
@@ -189,8 +201,18 @@ let gPermissionObject = {
}, },
"indexedDB": { "indexedDB": {
getDefault: function () { states: [ SitePermissions.ALLOW, SitePermissions.UNKNOWN, SitePermissions.BLOCK ],
return SitePermissions.ALLOW; 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) { onChange: function (aURI, aState) {
if (aState == SitePermissions.ALLOW || aState == SitePermissions.BLOCK) if (aState == SitePermissions.ALLOW || aState == SitePermissions.BLOCK)

View File

@@ -2750,8 +2750,11 @@ nsDocument::SetDocumentURI(nsIURI* aURI)
nsIURI* newBase = GetDocBaseURI(); nsIURI* newBase = GetDocBaseURI();
bool equalBases = false; 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) { if (oldBase && newBase) {
oldBase->Equals(newBase, &equalBases); oldBase->EqualsExceptRef(newBase, &equalBases);
} }
else { else {
equalBases = !oldBase && !newBase; equalBases = !oldBase && !newBase;

View File

@@ -3350,8 +3350,8 @@ nsObjectLoadingContent::TeardownProtoChain()
bool bool
nsObjectLoadingContent::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject, nsObjectLoadingContent::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
JS::Handle<jsid> aId, unsigned aFlags, JS::Handle<jsid> aId,
JS::MutableHandle<JSObject*> aObjp) JS::MutableHandle<JS::Value> aValue)
{ {
// We don't resolve anything; we just try to make sure we're instantiated // We don't resolve anything; we just try to make sure we're instantiated

View File

@@ -148,8 +148,9 @@ class nsObjectLoadingContent : public nsImageLoadingContent
void TeardownProtoChain(); void TeardownProtoChain();
// Helper for WebIDL newResolve // Helper for WebIDL newResolve
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject, JS::Handle<jsid> aId, bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
unsigned aFlags, JS::MutableHandle<JSObject*> aObjp); JS::Handle<jsid> aId,
JS::MutableHandle<JS::Value> aValue);
// WebIDL API // WebIDL API
nsIDocument* GetContentDocument(); nsIDocument* GetContentDocument();

View File

@@ -3296,6 +3296,8 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
// gfxContext-over-Azure may modify the DrawTarget's transform, so // gfxContext-over-Azure may modify the DrawTarget's transform, so
// save and restore it // save and restore it
Matrix matrix = mTarget->GetTransform(); Matrix matrix = mTarget->GetTransform();
double sw = matrix._11 * w;
double sh = matrix._22 * h;
nsRefPtr<gfxContext> thebes; nsRefPtr<gfxContext> thebes;
nsRefPtr<gfxASurface> drawSurf; nsRefPtr<gfxASurface> drawSurf;
if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget)) { if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget)) {
@@ -3304,7 +3306,7 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
matrix._22, matrix._31, matrix._32)); matrix._22, matrix._31, matrix._32));
} else { } else {
drawSurf = drawSurf =
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(ceil(w), ceil(h)), gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(ceil(sw), ceil(sh)),
gfxASurface::CONTENT_COLOR_ALPHA); gfxASurface::CONTENT_COLOR_ALPHA);
if (!drawSurf) { if (!drawSurf) {
error.Throw(NS_ERROR_FAILURE); error.Throw(NS_ERROR_FAILURE);
@@ -3314,6 +3316,7 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
drawSurf->SetDeviceOffset(gfxPoint(-floor(x), -floor(y))); drawSurf->SetDeviceOffset(gfxPoint(-floor(x), -floor(y)));
thebes = new gfxContext(drawSurf); thebes = new gfxContext(drawSurf);
thebes->Translate(gfxPoint(floor(x), floor(y))); thebes->Translate(gfxPoint(floor(x), floor(y)));
thebes->Scale(matrix._11, matrix._22);
} }
nsCOMPtr<nsIPresShell> shell = presContext->PresShell(); nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
@@ -3333,8 +3336,9 @@ CanvasRenderingContext2D::DrawWindow(nsIDOMWindow* window, double x,
IntSize(size.width, size.height), IntSize(size.width, size.height),
img->Stride(), img->Stride(),
FORMAT_B8G8R8A8); FORMAT_B8G8R8A8);
mgfx::Rect rect(0, 0, w, h); mgfx::Rect destRect(0, 0, w, h);
mTarget->DrawSurface(data, rect, rect); mgfx::Rect sourceRect(0, 0, sw, sh);
mTarget->DrawSurface(data, destRect, sourceRect);
mTarget->Flush(); mTarget->Flush();
} else { } else {
mTarget->SetTransform(matrix); mTarget->SetTransform(matrix);

View File

@@ -176,12 +176,13 @@ AudioContext::CreateBuffer(JSContext* aJSContext, ArrayBuffer& aBuffer,
aBuffer.Data(), aBuffer.Length(), aBuffer.Data(), aBuffer.Length(),
contentType); contentType);
WebAudioDecodeJob job(contentType, this); nsRefPtr<WebAudioDecodeJob> job =
new WebAudioDecodeJob(contentType, this, aBuffer);
if (mDecoder.SyncDecodeMedia(contentType.get(), if (mDecoder.SyncDecodeMedia(contentType.get(),
aBuffer.Data(), aBuffer.Length(), job) && aBuffer.Data(), aBuffer.Length(), *job) &&
job.mOutput) { job->mOutput) {
nsRefPtr<AudioBuffer> buffer = job.mOutput.forget(); nsRefPtr<AudioBuffer> buffer = job->mOutput.forget();
if (aMixToMono) { if (aMixToMono) {
buffer->MixToMono(aJSContext); buffer->MixToMono(aJSContext);
} }
@@ -374,8 +375,8 @@ AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
if (aFailureCallback.WasPassed()) { if (aFailureCallback.WasPassed()) {
failureCallback = &aFailureCallback.Value(); failureCallback = &aFailureCallback.Value();
} }
nsAutoPtr<WebAudioDecodeJob> job( nsRefPtr<WebAudioDecodeJob> job(
new WebAudioDecodeJob(contentType, this, new WebAudioDecodeJob(contentType, this, aBuffer,
&aSuccessCallback, failureCallback)); &aSuccessCallback, failureCallback));
mDecoder.AsyncDecodeMedia(contentType.get(), mDecoder.AsyncDecodeMedia(contentType.get(),
aBuffer.Data(), aBuffer.Length(), *job); aBuffer.Data(), aBuffer.Length(), *job);

View File

@@ -227,7 +227,7 @@ private:
nsRefPtr<AudioDestinationNode> mDestination; nsRefPtr<AudioDestinationNode> mDestination;
nsRefPtr<AudioListener> mListener; nsRefPtr<AudioListener> mListener;
MediaBufferDecoder mDecoder; MediaBufferDecoder mDecoder;
nsTArray<nsAutoPtr<WebAudioDecodeJob> > mDecodeJobs; nsTArray<nsRefPtr<WebAudioDecodeJob> > mDecodeJobs;
// Two hashsets containing all the PannerNodes and AudioBufferSourceNodes, // Two hashsets containing all the PannerNodes and AudioBufferSourceNodes,
// to compute the doppler shift, and also to stop AudioBufferSourceNodes. // to compute the doppler shift, and also to stop AudioBufferSourceNodes.
// These are all weak pointers. // These are all weak pointers.

View File

@@ -25,6 +25,29 @@
namespace mozilla { 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; using namespace dom;
#ifdef PR_LOGGING #ifdef PR_LOGGING
@@ -793,6 +816,7 @@ MediaBufferDecoder::Shutdown() {
WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType, WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
AudioContext* aContext, AudioContext* aContext,
const ArrayBuffer& aBuffer,
DecodeSuccessCallback* aSuccessCallback, DecodeSuccessCallback* aSuccessCallback,
DecodeErrorCallback* aFailureCallback) DecodeErrorCallback* aFailureCallback)
: mContentType(aContentType) : mContentType(aContentType)
@@ -805,15 +829,21 @@ WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(WebAudioDecodeJob); MOZ_COUNT_CTOR(WebAudioDecodeJob);
mArrayBuffer = aBuffer.Obj();
MOZ_ASSERT(aSuccessCallback || MOZ_ASSERT(aSuccessCallback ||
(!aSuccessCallback && !aFailureCallback), (!aSuccessCallback && !aFailureCallback),
"If a success callback is not passed, no failure callback should be passed either"); "If a success callback is not passed, no failure callback should be passed either");
nsContentUtils::HoldJSObjects(this, NS_CYCLE_COLLECTION_PARTICIPANT(WebAudioDecodeJob));
} }
WebAudioDecodeJob::~WebAudioDecodeJob() WebAudioDecodeJob::~WebAudioDecodeJob()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_DTOR(WebAudioDecodeJob); MOZ_COUNT_DTOR(WebAudioDecodeJob);
mArrayBuffer = nullptr;
nsContentUtils::DropJSObjects(this);
} }
void void

View File

@@ -26,16 +26,20 @@ class DecodeErrorCallback;
class DecodeSuccessCallback; class DecodeSuccessCallback;
} }
struct WebAudioDecodeJob struct WebAudioDecodeJob MOZ_FINAL
{ {
// You may omit both the success and failure callback, or you must pass both. // You may omit both the success and failure callback, or you must pass both.
// The callbacks are only necessary for asynchronous operation. // The callbacks are only necessary for asynchronous operation.
WebAudioDecodeJob(const nsACString& aContentType, WebAudioDecodeJob(const nsACString& aContentType,
dom::AudioContext* aContext, dom::AudioContext* aContext,
const dom::ArrayBuffer& aBuffer,
dom::DecodeSuccessCallback* aSuccessCallback = nullptr, dom::DecodeSuccessCallback* aSuccessCallback = nullptr,
dom::DecodeErrorCallback* aFailureCallback = nullptr); dom::DecodeErrorCallback* aFailureCallback = nullptr);
~WebAudioDecodeJob(); ~WebAudioDecodeJob();
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebAudioDecodeJob)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebAudioDecodeJob)
enum ErrorCode { enum ErrorCode {
NoError, NoError,
UnknownContent, UnknownContent,
@@ -52,6 +56,8 @@ struct WebAudioDecodeJob
bool AllocateBuffer(); bool AllocateBuffer();
JS::Heap<JSObject*> mArrayBuffer;
nsCString mContentType; nsCString mContentType;
uint32_t mWriteIndex; uint32_t mWriteIndex;
nsRefPtr<dom::AudioContext> mContext; nsRefPtr<dom::AudioContext> mContext;

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,7 @@ class nsIDOMMozConnection;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class Geolocation; class Geolocation;
class systemMessageCallback;
} }
} }
@@ -69,6 +70,8 @@ class nsIDOMTelephony;
// Navigator: Script "navigator" object // Navigator: Script "navigator" object
//***************************************************************************** //*****************************************************************************
void NS_GetNavigatorAppName(nsAString& aAppName);
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@@ -79,6 +82,15 @@ class BatteryManager;
class DesktopNotificationCenter; class DesktopNotificationCenter;
class SmsManager; class SmsManager;
class MobileMessageManager; 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 { namespace icc {
#ifdef MOZ_B2G_RIL #ifdef MOZ_B2G_RIL
@@ -192,7 +204,7 @@ public:
static void Init(); static void Init();
void Invalidate(); void Invalidate();
nsPIDOMWindow *GetWindow() nsPIDOMWindow *GetWindow() const
{ {
return mWindow; return mWindow;
} }
@@ -218,8 +230,186 @@ public:
NS_DECL_NSIDOMNAVIGATORCAMERA 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: private:
bool CheckPermission(const char* type); 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<nsMimeTypeArray> mMimeTypes;
nsRefPtr<nsPluginArray> mPlugins; nsRefPtr<nsPluginArray> mPlugins;
@@ -258,6 +448,5 @@ private:
nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent); nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
nsresult NS_GetNavigatorPlatform(nsAString& aPlatform); nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
nsresult NS_GetNavigatorAppVersion(nsAString& aAppVersion); nsresult NS_GetNavigatorAppVersion(nsAString& aAppVersion);
nsresult NS_GetNavigatorAppName(nsAString& aAppName);
#endif // mozilla_dom_Navigator_h #endif // mozilla_dom_Navigator_h

View File

@@ -129,7 +129,6 @@
#include "nsIXSLTProcessorPrivate.h" #include "nsIXSLTProcessorPrivate.h"
#include "nsXMLHttpRequest.h" #include "nsXMLHttpRequest.h"
#include "nsIDOMSettingsManager.h"
#include "nsIDOMContactManager.h" #include "nsIDOMContactManager.h"
#include "nsIDOMPermissionSettings.h" #include "nsIDOMPermissionSettings.h"
#include "nsIDOMApplicationRegistry.h" #include "nsIDOMApplicationRegistry.h"
@@ -4660,101 +4659,24 @@ nsNavigatorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
{ {
JS::Rooted<JSObject*> obj(cx, aObj); JS::Rooted<JSObject*> obj(cx, aObj);
JS::Rooted<jsid> id(cx, aId); JS::Rooted<jsid> id(cx, aId);
if (!JSID_IS_STRING(id)) { nsCOMPtr<nsIDOMNavigator> navigator = do_QueryWrappedNative(wrapper);
return NS_OK; JS::Rooted<JS::Value> value(cx, JS::UndefinedValue());
if (!static_cast<Navigator*>(navigator.get())->DoNewResolve(cx, obj, id,
&value)) {
return NS_ERROR_FAILURE;
} }
nsScriptNameSpaceManager *nameSpaceManager = if (!value.isUndefined()) {
nsJSRuntime::GetNameSpaceManager(); if (!JS_DefinePropertyById(cx, obj, id, value, JS_PropertyStub,
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
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; return NS_ERROR_FAILURE;
} }
*_retval = true;
*objp = obj; *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);
}
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 (!JS_WrapValue(cx, prop_val.address())) {
return NS_ERROR_UNEXPECTED;
}
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val,
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE);
*_retval = true; *_retval = true;
*objp = obj; return NS_OK;
return ok ? NS_OK : NS_ERROR_FAILURE;
} }
// static // static

View File

@@ -1702,17 +1702,30 @@ addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
addExternalIface('LockedFile') addExternalIface('LockedFile')
addExternalIface('MediaList') addExternalIface('MediaList')
addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True) addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
addExternalIface('MozBluetoothManager', nativeType='nsIDOMBluetoothManager')
addExternalIface('MozBoxObject', nativeType='nsIBoxObject') addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
addExternalIface('MozCellBroadcast')
addExternalIface('MozConnection', headerFile='nsIDOMConnection.h')
addExternalIface('MozControllers', nativeType='nsIControllers') addExternalIface('MozControllers', nativeType='nsIControllers')
addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True) 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('MozObserver', nativeType='nsIObserver', notflattened=True)
addExternalIface('MozPowerManager', headerFile='nsIDOMPowerManager.h')
addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource', addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
notflattened=True) notflattened=True)
addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True) addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
addExternalIface('MozSmsManager', headerFile='nsIDOMSmsManager.h')
addExternalIface('MozTelephony', nativeType='nsIDOMTelephony')
addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject', addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
notflattened=True) notflattened=True)
addExternalIface('MozTreeColumn', nativeType='nsITreeColumn', addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
headerFile='nsITreeColumns.h') headerFile='nsITreeColumns.h')
addExternalIface('MozVoicemail')
addExternalIface('MozWakeLock', headerFile='nsIDOMWakeLock.h')
addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder') addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
addExternalIface('nsIControllers', nativeType='nsIControllers') addExternalIface('nsIControllers', nativeType='nsIControllers')
addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback', addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',

View File

@@ -85,6 +85,9 @@ class CGNativePropertyHooks(CGThing):
if self.descriptor.concrete and self.descriptor.proxy: if self.descriptor.concrete and self.descriptor.proxy:
resolveOwnProperty = "ResolveOwnProperty" resolveOwnProperty = "ResolveOwnProperty"
enumerateOwnProperties = "EnumerateOwnProperties" enumerateOwnProperties = "EnumerateOwnProperties"
elif self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
resolveOwnProperty = "ResolveOwnPropertyViaNewresolve"
enumerateOwnProperties = "nullptr"
else: else:
resolveOwnProperty = "nullptr" resolveOwnProperty = "nullptr"
enumerateOwnProperties = "nullptr" enumerateOwnProperties = "nullptr"
@@ -3732,7 +3735,7 @@ def convertConstIDLValueToJSVal(value):
return "JSVAL_TRUE" if value.value else "JSVAL_FALSE" return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
if tag in [IDLType.Tags.float, IDLType.Tags.double]: if tag in [IDLType.Tags.float, IDLType.Tags.double]:
return "DOUBLE_TO_JSVAL(%s)" % (value.value) 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): class CGArgumentConverter(CGThing):
""" """
@@ -5130,8 +5133,9 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
""" """
def __init__(self, descriptor, name, args, unwrapFailureCode=None, def __init__(self, descriptor, name, args, unwrapFailureCode=None,
getThisObj="args.computeThis(cx).toObjectOrNull()", getThisObj="args.computeThis(cx).toObjectOrNull()",
callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);"): callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);",
CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args) returnType="JSBool"):
CGAbstractStaticMethod.__init__(self, descriptor, name, returnType, args)
if unwrapFailureCode is None: if unwrapFailureCode is None:
self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");' % descriptor.interface.identifier.name 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 # we're someone's consequential interface. But for this-unwrapping, we
# know that we're the real deal. So fake a descriptor here for # know that we're the real deal. So fake a descriptor here for
# consumption by CastableObjectUnwrapper. # consumption by CastableObjectUnwrapper.
getThis = CGGeneric("""%s getThis = CGList([
JS::RootedObject obj(cx, %s); CGGeneric(self.callArgs) if self.callArgs != "" else None,
if (!obj) { CGGeneric("JS::RootedObject obj(cx, %s);\n"
return false; "if (!obj) {\n"
} " return false;\n"
"}" % self.getThisObj) if self.getThisObj else None,
%s* self;""" % (self.callArgs, self.getThisObj, self.descriptor.nativeType)) CGGeneric("%s* self;" % self.descriptor.nativeType)
], "\n")
unwrapThis = CGGeneric( unwrapThis = CGGeneric(
str(CastableObjectUnwrapper( str(CastableObjectUnwrapper(
self.descriptor, self.descriptor,
@@ -5265,13 +5270,13 @@ class CGNewResolveHook(CGAbstractBindingMethod):
""" """
def __init__(self, descriptor): def __init__(self, descriptor):
self._needNewResolve = descriptor.interface.getExtendedAttribute("NeedNewResolve") 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::Handle<jsid>', 'id'), Argument('unsigned', 'flags'),
Argument('JS::MutableHandle<JSObject*>', 'objp')] Argument('JS::MutableHandle<JSObject*>', 'objp')]
# Our "self" is actually the callee in this case, not the thisval. # Our "self" is actually the callee in this case, not the thisval.
CGAbstractBindingMethod.__init__( CGAbstractBindingMethod.__init__(
self, descriptor, NEWRESOLVE_HOOK_NAME, self, descriptor, NEWRESOLVE_HOOK_NAME,
args, getThisObj="obj_", callArgs="") args, getThisObj="", callArgs="")
def define(self): def define(self):
if not self._needNewResolve: if not self._needNewResolve:
@@ -5279,7 +5284,19 @@ class CGNewResolveHook(CGAbstractBindingMethod):
return CGAbstractBindingMethod.define(self) return CGAbstractBindingMethod.define(self)
def generate_code(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(): class CppKeywords():
""" """
@@ -6629,7 +6646,7 @@ class CGClass(CGThing):
result = result + memberString result = result + memberString
return result return result
class CGResolveOwnProperty(CGAbstractMethod): class CGResolveOwnProperty(CGAbstractStaticMethod):
def __init__(self, descriptor): def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'), args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'wrapper'), Argument('JS::Handle<JSObject*>', 'wrapper'),
@@ -6637,18 +6654,47 @@ class CGResolveOwnProperty(CGAbstractMethod):
Argument('JS::Handle<jsid>', 'id'), Argument('JS::Handle<jsid>', 'id'),
Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'), Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
] ]
CGAbstractMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args) CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
"bool", args)
def definition_body(self): def definition_body(self):
return """ return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc, flags); 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): def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'), args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'wrapper'), Argument('JS::Handle<JSObject*>', 'wrapper'),
Argument('JS::Handle<JSObject*>', 'obj'), Argument('JS::Handle<JSObject*>', 'obj'),
Argument('JS::AutoIdVector&', 'props')] Argument('JS::AutoIdVector&', 'props')]
CGAbstractMethod.__init__(self, descriptor, "EnumerateOwnProperties", "bool", args) CGAbstractStaticMethod.__init__(self, descriptor,
"EnumerateOwnProperties", "bool", args)
def definition_body(self): def definition_body(self):
return """ return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props); return """ return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
""" """
@@ -7606,6 +7652,16 @@ class CGDescriptor(CGThing):
cgThings.append(CGGeneric(define=str(properties))) cgThings.append(CGGeneric(define=str(properties)))
cgThings.append(CGNativeProperties(descriptor, 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)) cgThings.append(CGNativePropertyHooks(descriptor, properties))
if descriptor.interface.hasInterfaceObject(): if descriptor.interface.hasInterfaceObject():
@@ -7629,12 +7685,6 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasInterfaceObject(): if descriptor.interface.hasInterfaceObject():
cgThings.append(CGGetConstructorObjectMethod(descriptor)) 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(): if descriptor.interface.hasInterfaceObject():
cgThings.append(CGDefineDOMInterfaceMethod(descriptor)) cgThings.append(CGDefineDOMInterfaceMethod(descriptor))

View File

@@ -22,7 +22,7 @@ include $(topsrcdir)/dom/dom-config.mk
include $(topsrcdir)/dom/webidl/WebIDL.mk include $(topsrcdir)/dom/webidl/WebIDL.mk
binding_include_path := mozilla/dom 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 # Set exported_binding_headers before adding the test IDL to the mix
exported_binding_headers := $(subst .webidl,Binding.h,$(all_webidl_files)) exported_binding_headers := $(subst .webidl,Binding.h,$(all_webidl_files))
# Set linked_binding_cpp_files before adding the test IDL to the mix # 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/% $(test_webidl_files): %: $(srcdir)/test/%
$(INSTALL) $(IFLAGS1) $(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_header_files): .BindingGen
$(binding_cpp_files): .BindingGen $(binding_cpp_files): .BindingGen

View File

@@ -168,30 +168,23 @@ BluetoothManager::Create(nsPIDOMWindow* aWindow)
return manager.forget(); return manager.forget();
} }
nsresult // static
NS_NewBluetoothManager(nsPIDOMWindow* aWindow, bool
nsIDOMBluetoothManager** aBluetoothManager) BluetoothManager::CheckPermission(nsPIDOMWindow* aWindow)
{ {
NS_ASSERTION(aWindow, "Null pointer!"); NS_ASSERTION(aWindow, "Null pointer!");
nsCOMPtr<nsIPermissionManager> permMgr = nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
NS_ENSURE_TRUE(permMgr, NS_ERROR_UNEXPECTED); NS_ENSURE_TRUE(permMgr, false);
uint32_t permission; uint32_t permission;
nsresult rv = nsresult rv =
permMgr->TestPermissionFromWindow(aWindow, "bluetooth", permMgr->TestPermissionFromWindow(aWindow, "bluetooth",
&permission); &permission);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, false);
nsRefPtr<BluetoothManager> bluetoothManager; return permission == nsIPermissionManager::ALLOW_ACTION;
if (permission == nsIPermissionManager::ALLOW_ACTION) {
bluetoothManager = BluetoothManager::Create(aWindow);
}
bluetoothManager.forget(aBluetoothManager);
return NS_OK;
} }
void void

View File

@@ -29,8 +29,10 @@ public:
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper) NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
// Never returns null
static already_AddRefed<BluetoothManager> static already_AddRefed<BluetoothManager>
Create(nsPIDOMWindow* aWindow); Create(nsPIDOMWindow* aWindow);
static bool CheckPermission(nsPIDOMWindow* aWindow);
void Notify(const BluetoothSignal& aData); void Notify(const BluetoothSignal& aData);
virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE; virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE;
private: private:
@@ -40,7 +42,4 @@ private:
END_BLUETOOTH_NAMESPACE END_BLUETOOTH_NAMESPACE
nsresult NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
nsIDOMBluetoothManager** aBluetoothManager);
#endif #endif

View File

@@ -71,21 +71,27 @@ nsDOMCameraManager::~nsDOMCameraManager()
obs->RemoveObserver(this, "xpcom-shutdown"); obs->RemoveObserver(this, "xpcom-shutdown");
} }
// static creator bool
already_AddRefed<nsDOMCameraManager> nsDOMCameraManager::CheckPermission(nsPIDOMWindow* aWindow)
nsDOMCameraManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
{ {
nsCOMPtr<nsIPermissionManager> permMgr = nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
NS_ENSURE_TRUE(permMgr, nullptr); NS_ENSURE_TRUE(permMgr, false);
uint32_t permission = nsIPermissionManager::DENY_ACTION; uint32_t permission = nsIPermissionManager::DENY_ACTION;
permMgr->TestPermissionFromWindow(aWindow, "camera", &permission); permMgr->TestPermissionFromWindow(aWindow, "camera", &permission);
if (permission != nsIPermissionManager::ALLOW_ACTION) { if (permission != nsIPermissionManager::ALLOW_ACTION) {
NS_WARNING("No permission to access camera"); 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 // Initialize the shared active window tracker
if (!sActiveWindowsInitialized) { if (!sActiveWindowsInitialized) {
sActiveWindows.Init(); sActiveWindows.Init();

View File

@@ -45,8 +45,9 @@ public:
nsIObserver) nsIObserver)
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
static bool CheckPermission(nsPIDOMWindow* aWindow);
static already_AddRefed<nsDOMCameraManager> static already_AddRefed<nsDOMCameraManager>
CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow); CreateInstance(nsPIDOMWindow* aWindow);
static bool IsWindowStillActive(uint64_t aWindowId); static bool IsWindowStillActive(uint64_t aWindowId);
void Register(mozilla::nsDOMCameraControl* aDOMCameraControl); void Register(mozilla::nsDOMCameraControl* aDOMCameraControl);

View File

@@ -6,13 +6,28 @@ MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document); SpecialPowers.addPermission("mobileconnection", true, document);
SpecialPowers.addPermission("settings-write", true, document); SpecialPowers.addPermission("settings-write", true, document);
let icc = navigator.mozIccManager; // Permission changes can't change existing Navigator.prototype
ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor); // objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let icc;
ifr.onload = function() {
icc = ifr.contentWindow.navigator.mozIccManager;
is(icc.cardState, "ready"); 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) { function setAirplaneModeEnabled(enabled) {
let settings = window.navigator.mozSettings; let settings = ifr.contentWindow.navigator.mozSettings;
let setLock = settings.createLock(); let setLock = settings.createLock();
let obj = { let obj = {
"ril.radio.disabled": enabled "ril.radio.disabled": enabled
@@ -53,9 +68,3 @@ function cleanUp() {
finish(); 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)
);

View File

@@ -5,9 +5,42 @@ MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document); SpecialPowers.addPermission("mobileconnection", true, document);
let icc = navigator.mozIccManager; // Permission changes can't change existing Navigator.prototype
ok(icc instanceof MozIccManager, // objects, so grab our objects from a new Navigator
"icc is instanceof " + icc.constructor); 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; let emulatorCmdPendingCount = 0;
function sendEmulatorCommand(cmd, callback) { function sendEmulatorCommand(cmd, callback) {
@@ -39,21 +72,6 @@ function finalize() {
finish(); 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. // Test display condition change.
function testDisplayConditionChange(func, caseArray, oncomplete) { function testDisplayConditionChange(func, caseArray, oncomplete) {
(function do_call(index) { (function do_call(index) {
@@ -75,13 +93,3 @@ function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired,
}); });
setEmulatorMccMnc(mcc, mnc); 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);

View File

@@ -6,7 +6,6 @@
XPIDL_SOURCES += [ XPIDL_SOURCES += [
'nsIDOMMozSettingsEvent.idl', 'nsIDOMMozSettingsEvent.idl',
'nsIDOMSettingsManager.idl',
'nsISettingsService.idl', 'nsISettingsService.idl',
] ]

View File

@@ -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;
};

View File

@@ -78,7 +78,12 @@ const BrowserElementIsPreloaded = true;
Cc["@mozilla.org/contentsecuritypolicy;1"].createInstance(Ci["nsIContentSecurityPolicy"]); Cc["@mozilla.org/contentsecuritypolicy;1"].createInstance(Ci["nsIContentSecurityPolicy"]);
/* Applications Specific Helper */ /* 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 { try {
if (Services.prefs.getBoolPref("dom.sysmsg.enabled")) { if (Services.prefs.getBoolPref("dom.sysmsg.enabled")) {
Cc["@mozilla.org/system-message-manager;1"].getService(Ci["nsIDOMNavigatorSystemMessages"]); Cc["@mozilla.org/system-message-manager;1"].getService(Ci["nsIDOMNavigatorSystemMessages"]);

View File

@@ -1095,9 +1095,9 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
#ifdef MOZ_B2G_CAMERA #ifdef MOZ_B2G_CAMERA
if (mCameraManager == nullptr) { if (mCameraManager == nullptr) {
mCameraManager = nsDOMCameraManager::CheckPermissionAndCreateInstance(aWindow); aPrivileged = nsDOMCameraManager::CheckPermission(aWindow);
if (!mCameraManager) { if (aPrivileged) {
aPrivileged = false; mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
} }
} }
#endif #endif

View File

@@ -15,7 +15,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=802982
function boom() function boom()
{ {
for (var j = 0; j < 100; ++j) { for (var j = 0; j < 100; ++j) {
navigator.mozGetUserMedia({}, {}, {}); navigator.mozGetUserMedia({}, function(){}, function(){});
} }
finish(); // we're not waiting for success/error callbacks here finish(); // we're not waiting for success/error callbacks here
} }

View File

@@ -26,26 +26,26 @@ var exceptionTests = [
// Each test here verifies that a caller is required to have all // Each test here verifies that a caller is required to have all
// three arguments in order to call mozGetUserMedia // three arguments in order to call mozGetUserMedia
{ params: undefined, { params: undefined,
error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS, error: "Not enough arguments to Navigator.mozGetUserMedia.",
message: "no arguments specified" }, message: "no arguments specified" },
{ params: [{video: true, fake: true}], { params: [{video: true, fake: true}],
error: Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS, error: "Not enough arguments to Navigator.mozGetUserMedia.",
message: "one argument specified" }, message: "one argument specified" },
{ params: [{video: true, fake: true}, unexpectedCall], { 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" }, message: "two arguments specified" },
// Each test here verifies that providing an incorret object // Each test here verifies that providing an incorret object
// type to any mozGetUserMedia parameter should throw // type to any mozGetUserMedia parameter should throw
// the correct exception specified // the correct exception specified
{ params: [1, unexpectedCall, unexpectedCall], { 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" }, message: "wrong object type as first parameter" },
{ params: [{video: true, fake: true}, 1, unexpectedCall], { 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" }, message: "wrong object type as second parameter" },
{ params: [{video: true, fake: true}, unexpectedCall, 1], { 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" } message: "wrong object type as third parameter" }
]; ];
@@ -71,7 +71,7 @@ runTest(function () {
try { try {
navigator.mozGetUserMedia.apply(navigator, test.params); navigator.mozGetUserMedia.apply(navigator, test.params);
} catch (e) { } catch (e) {
exception = (e.result === test.error); exception = (e.message === test.error);
} }
ok(exception, "Exception for " + test.message); ok(exception, "Exception for " + test.message);
}); });

View File

@@ -54,41 +54,49 @@ NS_IMPL_EVENT_HANDLER(SmsManager, failed)
NS_IMPL_EVENT_HANDLER(SmsManager, deliverysuccess) NS_IMPL_EVENT_HANDLER(SmsManager, deliverysuccess)
NS_IMPL_EVENT_HANDLER(SmsManager, deliveryerror) NS_IMPL_EVENT_HANDLER(SmsManager, deliveryerror)
/* static */already_AddRefed<SmsManager> /* static */
SmsManager::CreateInstanceIfAllowed(nsPIDOMWindow* aWindow) bool
SmsManager::CreationIsAllowed(nsPIDOMWindow* aWindow)
{ {
NS_ASSERTION(aWindow, "Null pointer!"); NS_ASSERTION(aWindow, "Null pointer!");
#ifndef MOZ_WEBSMS_BACKEND #ifndef MOZ_WEBSMS_BACKEND
return nullptr; return false;
#endif #endif
// First of all, the general pref has to be turned on. // First of all, the general pref has to be turned on.
bool enabled = false; bool enabled = false;
Preferences::GetBool("dom.sms.enabled", &enabled); Preferences::GetBool("dom.sms.enabled", &enabled);
NS_ENSURE_TRUE(enabled, nullptr); NS_ENSURE_TRUE(enabled, false);
nsCOMPtr<nsIPermissionManager> permMgr = nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
NS_ENSURE_TRUE(permMgr, nullptr); NS_ENSURE_TRUE(permMgr, false);
uint32_t permission = nsIPermissionManager::DENY_ACTION; uint32_t permission = nsIPermissionManager::DENY_ACTION;
permMgr->TestPermissionFromWindow(aWindow, "sms", &permission); permMgr->TestPermissionFromWindow(aWindow, "sms", &permission);
if (permission != nsIPermissionManager::ALLOW_ACTION) { if (permission != nsIPermissionManager::ALLOW_ACTION) {
return nullptr; return false;
} }
// Check the Sms Service: // Check the Sms Service:
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID); nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, nullptr); NS_ENSURE_TRUE(smsService, false);
bool result = false; bool result = false;
smsService->HasSupport(&result); smsService->HasSupport(&result);
if (!result) { if (!result) {
return nullptr; return false;
} }
return true;
}
// static
already_AddRefed<SmsManager>
SmsManager::CreateInstance(nsPIDOMWindow* aWindow)
{
nsRefPtr<SmsManager> smsMgr = new SmsManager(); nsRefPtr<SmsManager> smsMgr = new SmsManager();
smsMgr->Init(aWindow); smsMgr->Init(aWindow);

View File

@@ -27,7 +27,10 @@ public:
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper) NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
static already_AddRefed<SmsManager> static already_AddRefed<SmsManager>
CreateInstanceIfAllowed(nsPIDOMWindow *aWindow); CreateInstance(nsPIDOMWindow *aWindow);
static bool
CreationIsAllowed(nsPIDOMWindow *aWindow);
void Init(nsPIDOMWindow *aWindow); void Init(nsPIDOMWindow *aWindow);
void Shutdown(); void Shutdown();

View File

@@ -16,8 +16,9 @@
/** Test for WebSMS **/ /** Test for WebSMS **/
function checkSmsDisabled() { function checkSmsDisabled() {
ok('mozSms' in frames[0].navigator, "navigator.mozSms should exist"); ok(!('mozSms' in frames[0].navigator), "navigator.mozSms should not exist");
is(frames[0].navigator.mozSms, null, "navigator.mozSms should return null"); ok(frames[0].navigator.mozSms === undefined,
"navigator.mozSms should return undefined");
} }
function checkSmsEnabled() { function checkSmsEnabled() {

View File

@@ -5,9 +5,19 @@ MARIONETTE_TIMEOUT = 60000;
SpecialPowers.addPermission("mobileconnection", true, document); SpecialPowers.addPermission("mobileconnection", true, document);
let connection = navigator.mozMobileConnection; // Permission changes can't change existing Navigator.prototype
ok(connection instanceof MozMobileConnection, // objects, so grab our objects from a new Navigator
"connection is instanceof " + connection.constructor); 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() { function testGetCallBarringOption() {
let option = {'program': 0, 'password': '', 'serviceClass': 0}; let option = {'program': 0, 'password': '', 'serviceClass': 0};
@@ -27,5 +37,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document); SpecialPowers.removePermission("mobileconnection", document);
finish(); finish();
} }
testGetCallBarringOption();

View File

@@ -5,9 +5,19 @@ MARIONETTE_TIMEOUT = 60000;
SpecialPowers.addPermission("mobileconnection", true, document); SpecialPowers.addPermission("mobileconnection", true, document);
let connection = navigator.mozMobileConnection; // Permission changes can't change existing Navigator.prototype
ok(connection instanceof MozMobileConnection, // objects, so grab our objects from a new Navigator
"connection is instanceof " + connection.constructor); 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 caseId = 0;
let options = [ let options = [
@@ -61,5 +71,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document); SpecialPowers.removePermission("mobileconnection", document);
finish(); finish();
} }
nextTest();

View File

@@ -5,7 +5,18 @@ MARIONETTE_TIMEOUT = 20000;
SpecialPowers.addPermission("mobileconnection", true, document); 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 emulatorStartLac = 0;
let emulatorStartCid = 0; let emulatorStartCid = 0;
@@ -114,6 +125,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document); SpecialPowers.removePermission("mobileconnection", document);
finish(); finish();
} }
// Start the test
verifyInitialState();

View File

@@ -5,7 +5,17 @@ MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document); 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() { function verifyInitialState() {
log("Verifying initial state."); log("Verifying initial state.");
@@ -116,6 +126,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document); SpecialPowers.removePermission("mobileconnection", document);
finish(); finish();
} }
// Start the test
verifyInitialState();

View File

@@ -5,7 +5,16 @@ MARIONETTE_TIMEOUT = 20000;
SpecialPowers.addPermission("mobileconnection", true, document); 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 = { let tasks = {
// List of test functions. Each of them should call |tasks.next()| when // List of test functions. Each of them should call |tasks.next()| when
@@ -43,7 +52,7 @@ let tasks = {
tasks.push(function verifyInitialState() { tasks.push(function verifyInitialState() {
log("Verifying initial state."); log("Verifying initial state.");
ok(mobileConnection instanceof MozMobileConnection, ok(mobileConnection instanceof ifr.contentWindow.MozMobileConnection,
"mobileConnection is instanceof " + mobileConnection.constructor); "mobileConnection is instanceof " + mobileConnection.constructor);
tasks.next(); tasks.next();
@@ -77,5 +86,3 @@ tasks.push(function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document); SpecialPowers.removePermission("mobileconnection", document);
finish(); finish();
}); });
tasks.run();

View File

@@ -8,15 +8,28 @@ SpecialPowers.addPermission("mobileconnection", true, document);
const OPERATOR_HOME = 0; const OPERATOR_HOME = 0;
const OPERATOR_ROAMING = 1; const OPERATOR_ROAMING = 1;
let connection = navigator.mozMobileConnection; // Permission changes can't change existing Navigator.prototype
ok(connection instanceof MozMobileConnection, // objects, so grab our objects from a new Navigator
"connection is instanceof " + connection.constructor); 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"); ok(voice, "voice connection valid");
let network = voice.network; network = voice.network;
ok(network, "voice network info valid"); ok(network, "voice network info valid");
waitFor(testMobileOperatorNames, function () {
return voice.connected;
});
};
document.body.appendChild(ifr);
let emulatorCmdPendingCount = 0; let emulatorCmdPendingCount = 0;
function sendEmulatorCommand(cmd, callback) { function sendEmulatorCommand(cmd, callback) {
@@ -203,7 +216,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document); SpecialPowers.removePermission("mobileconnection", document);
finish(); finish();
} }
waitFor(testMobileOperatorNames, function () {
return voice.connected;
});

View File

@@ -5,9 +5,17 @@ MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document); SpecialPowers.addPermission("mobileconnection", true, document);
let connection = navigator.mozMobileConnection; // Permission changes can't change existing Navigator.prototype
ok(connection instanceof MozMobileConnection, // objects, so grab our objects from a new Navigator
"connection is instanceof " + connection.constructor); 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; let emulatorCmdPendingCount = 0;
function setEmulatorVoiceState(state) { function setEmulatorVoiceState(state) {
@@ -149,5 +157,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document); SpecialPowers.removePermission("mobileconnection", document);
finish(); finish();
} }
testConnectionInfo();

View File

@@ -25,7 +25,7 @@ var gData = [
{ {
perm: ["settings"], perm: ["settings"],
obj: 'mozSettings', obj: 'mozSettings',
idl: 'nsIDOMSettingsManager', webidl: 'SettingsManager',
settings: [["dom.mozSettings.enabled", true]], settings: [["dom.mozSettings.enabled", true]],
} }
] ]

View File

@@ -179,22 +179,26 @@ PowerManager::SetCpuSleepAllowed(bool aAllowed)
return NS_OK; return NS_OK;
} }
already_AddRefed<PowerManager> bool
PowerManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow) PowerManager::CheckPermission(nsPIDOMWindow* aWindow)
{ {
nsCOMPtr<nsIPermissionManager> permMgr = nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
NS_ENSURE_TRUE(permMgr, nullptr); NS_ENSURE_TRUE(permMgr, false);
uint32_t permission = nsIPermissionManager::DENY_ACTION; uint32_t permission = nsIPermissionManager::DENY_ACTION;
permMgr->TestPermissionFromWindow(aWindow, "power", &permission); permMgr->TestPermissionFromWindow(aWindow, "power", &permission);
if (permission != nsIPermissionManager::ALLOW_ACTION) { return permission == nsIPermissionManager::ALLOW_ACTION;
return nullptr; }
}
already_AddRefed<PowerManager>
PowerManager::CreateInstance(nsPIDOMWindow* aWindow)
{
nsRefPtr<PowerManager> powerManager = new PowerManager(); nsRefPtr<PowerManager> powerManager = new PowerManager();
powerManager->Init(aWindow); if (NS_FAILED(powerManager->Init(aWindow))) {
powerManager = nullptr;
}
return powerManager.forget(); return powerManager.forget();
} }

View File

@@ -33,8 +33,9 @@ public:
nsresult Init(nsIDOMWindow *aWindow); nsresult Init(nsIDOMWindow *aWindow);
nsresult Shutdown(); nsresult Shutdown();
static already_AddRefed<PowerManager> static bool CheckPermission(nsPIDOMWindow*);
CheckPermissionAndCreateInstance(nsPIDOMWindow*);
static already_AddRefed<PowerManager> CreateInstance(nsPIDOMWindow*);
private: private:

View File

@@ -23,13 +23,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1", "@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender"); "nsIMessageSender");
const nsIClassInfo = Ci.nsIClassInfo; function SettingsLock(aSettingsManager) {
const SETTINGSLOCK_CONTRACTID = "@mozilla.org/settingsLock;1";
const SETTINGSLOCK_CID = Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}");
const nsIDOMSettingsLock = Ci.nsIDOMSettingsLock;
function SettingsLock(aSettingsManager)
{
this._open = true; this._open = true;
this._isBusy = false; this._isBusy = false;
this._requests = new Queue(); this._requests = new Queue();
@@ -38,7 +32,6 @@ function SettingsLock(aSettingsManager)
} }
SettingsLock.prototype = { SettingsLock.prototype = {
get closed() { get closed() {
return !this._open; return !this._open;
}, },
@@ -217,8 +210,7 @@ SettingsLock.prototype = {
set: function set(aSettings) { set: function set(aSettings) {
if (!this._open) { if (!this._open) {
dump("Settings lock not open!\n"); throw "Settings lock not open";
throw Components.results.NS_ERROR_ABORT;
} }
if (this._settingsManager.hasWritePrivileges) { if (this._settingsManager.hasWritePrivileges) {
@@ -230,14 +222,13 @@ SettingsLock.prototype = {
return req; return req;
} else { } else {
if (DEBUG) debug("set not allowed"); if (DEBUG) debug("set not allowed");
throw Components.results.NS_ERROR_NOT_IMPLEMENTED; throw "No permission to call set";
} }
}, },
clear: function clear() { clear: function clear() {
if (!this._open) { if (!this._open) {
dump("Settings lock not open!\n"); throw "Settings lock not open";
throw Components.results.NS_ERROR_ABORT;
} }
if (this._settingsManager.hasWritePrivileges) { if (this._settingsManager.hasWritePrivileges) {
@@ -247,28 +238,18 @@ SettingsLock.prototype = {
return req; return req;
} else { } else {
if (DEBUG) debug("clear not allowed"); if (DEBUG) debug("clear not allowed");
throw Components.results.NS_ERROR_NOT_IMPLEMENTED; throw "No permission to call clear";
} }
}, },
classID : SETTINGSLOCK_CID, classID: Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}"),
QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsLock]), contractID: "@mozilla.org/settingsLock;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
classInfo : XPCOMUtils.generateCI({classID: SETTINGSLOCK_CID,
contractID: SETTINGSLOCK_CONTRACTID,
classDescription: "SettingsLock",
interfaces: [nsIDOMSettingsLock],
flags: nsIClassInfo.DOM_OBJECT})
}; };
const SETTINGSMANAGER_CONTRACTID = "@mozilla.org/settingsManager;1";
const SETTINGSMANAGER_CID = Components.ID("{c40b1c70-00fb-11e2-a21f-0800200c9a66}");
const nsIDOMSettingsManager = Ci.nsIDOMSettingsManager;
let myGlobal = this; let myGlobal = this;
function SettingsManager() function SettingsManager() {
{
this._locks = new Queue(); this._locks = new Queue();
if (!("indexedDB" in myGlobal)) { if (!("indexedDB" in myGlobal)) {
let idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager); let idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
@@ -279,7 +260,6 @@ function SettingsManager()
} }
SettingsManager.prototype = { SettingsManager.prototype = {
_onsettingchange: null,
_callbacks: null, _callbacks: null,
_wrap: function _wrap(obj) { _wrap: function _wrap(obj) {
@@ -293,19 +273,12 @@ SettingsManager.prototype = {
Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL); Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
}, },
set onsettingchange(aCallback) { set onsettingchange(aHandler) {
if (this.hasReadPrivileges) { this.__DOM_IMPL__.setEventHandler("onsettingchange", aHandler);
if (!this._onsettingchange) {
cpmm.sendAsyncMessage("Settings:RegisterForMessages");
}
this._onsettingchange = aCallback;
} else {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
}, },
get onsettingchange() { get onsettingchange() {
return this._onsettingchange; return this.__DOM_IMPL__.getEventHandler("onsettingchange");
}, },
createLock: function() { createLock: function() {
@@ -326,22 +299,19 @@ SettingsManager.prototype = {
switch (aMessage.name) { switch (aMessage.name) {
case "Settings:Change:Return:OK": case "Settings:Change:Return:OK":
if (this._onsettingchange || this._callbacks) { if (DEBUG) debug('data:' + msg.key + ':' + msg.value + '\n');
if (DEBUG) debug('data:' + msg.key + ':' + msg.value + '\n');
if (this._onsettingchange) { let event = new this._window.MozSettingsEvent("settingchange", this._wrap({
let event = new this._window.MozSettingsEvent("settingchanged", this._wrap({ settingName: msg.key,
settingName: msg.key, settingValue: msg.value
settingValue: msg.value }));
})); this.__DOM_IMPL__.dispatchEvent(event);
this._onsettingchange.handleEvent(event);
} if (this._callbacks && this._callbacks[msg.key]) {
if (this._callbacks && this._callbacks[msg.key]) { if (DEBUG) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length);
if (DEBUG) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length); this._callbacks[msg.key].forEach(function(cb) {
this._callbacks[msg.key].forEach(function(cb) { cb(this._wrap({settingName: msg.key, settingValue: msg.value}));
cb(this._wrap({settingName: msg.key, settingValue: msg.value})); }.bind(this));
}.bind(this));
}
} else { } else {
if (DEBUG) debug("no observers stored!"); if (DEBUG) debug("no observers stored!");
} }
@@ -390,9 +360,12 @@ SettingsManager.prototype = {
this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION; this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
this.hasWritePrivileges = writePerm == Ci.nsIPermissionManager.ALLOW_ACTION; this.hasWritePrivileges = writePerm == Ci.nsIPermissionManager.ALLOW_ACTION;
if (this.hasReadPrivileges) {
cpmm.sendAsyncMessage("Settings:RegisterForMessages");
}
if (!this.hasReadPrivileges && !this.hasWritePrivileges) { if (!this.hasReadPrivileges && !this.hasWritePrivileges) {
Cu.reportError("NO SETTINGS PERMISSION FOR: " + aWindow.document.nodePrincipal.origin + "\n"); throw "NO SETTINGS PERMISSION FOR: " + aWindow.document.nodePrincipal.origin + "\n";
return null;
} }
}, },
@@ -406,20 +379,15 @@ SettingsManager.prototype = {
this._requests = null; this._requests = null;
this._window = null; this._window = null;
this._innerWindowID = null; this._innerWindowID = null;
this._onsettingchange = null;
this._settingsDB.close(); this._settingsDB.close();
} }
} }
}, },
classID : SETTINGSMANAGER_CID, classID: Components.ID("{c40b1c70-00fb-11e2-a21f-0800200c9a66}"),
QueryInterface : XPCOMUtils.generateQI([nsIDOMSettingsManager, Ci.nsIDOMGlobalPropertyInitializer]), contractID: "@mozilla.org/settingsManager;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
classInfo : XPCOMUtils.generateCI({classID: SETTINGSMANAGER_CID, Ci.nsIDOMGlobalPropertyInitializer]),
contractID: SETTINGSMANAGER_CONTRACTID, };
classDescription: "SettingsManager",
interfaces: [nsIDOMSettingsManager],
flags: nsIClassInfo.DOM_OBJECT})
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock]) this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock])

View File

@@ -1,6 +1,5 @@
component {c40b1c70-00fb-11e2-a21f-0800200c9a66} SettingsManager.js component {c40b1c70-00fb-11e2-a21f-0800200c9a66} SettingsManager.js
contract @mozilla.org/settingsManager;1 {c40b1c70-00fb-11e2-a21f-0800200c9a66} 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 component {60c9357c-3ae0-4222-8f55-da01428470d5} SettingsManager.js
contract @mozilla.org/settingsLock;1 {60c9357c-3ae0-4222-8f55-da01428470d5} contract @mozilla.org/settingsLock;1 {60c9357c-3ae0-4222-8f55-da01428470d5}

View File

@@ -64,11 +64,12 @@ let steps = [
req.onerror = onFailure("Deleting database"); req.onerror = onFailure("Deleting database");
}, },
function() { function() {
mozSettings.addObserver("test1", function(e) { function obs(e) {
checkBlob(e.settingValue); checkBlob(e.settingValue);
mozSettings.removeObserver("test1", this); mozSettings.removeObserver("test1", obs);
next(); next();
}); }
mozSettings.addObserver("test1", obs);
next(); next();
}, },
function() { function() {

View File

@@ -117,29 +117,47 @@ Telephony::~Telephony()
// static // static
already_AddRefed<Telephony> already_AddRefed<Telephony>
Telephony::Create(nsPIDOMWindow* aOwner, nsITelephonyProvider* aProvider) Telephony::Create(nsPIDOMWindow* aOwner, ErrorResult& aRv)
{ {
NS_ASSERTION(aOwner, "Null owner!"); 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); 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(); nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
NS_ENSURE_TRUE(scriptContext, nullptr); if (!scriptContext) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Telephony> telephony = new Telephony(); nsRefPtr<Telephony> telephony = new Telephony();
telephony->BindToOwner(aOwner); telephony->BindToOwner(aOwner);
telephony->mProvider = aProvider; telephony->mProvider = ril;
telephony->mListener = new Listener(telephony); telephony->mListener = new Listener(telephony);
nsresult rv = aProvider->EnumerateCalls(telephony->mListener); nsresult rv = ril->EnumerateCalls(telephony->mListener);
NS_ENSURE_SUCCESS(rv, nullptr); if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
rv = aProvider->RegisterTelephonyMsg(telephony->mListener); rv = ril->RegisterTelephonyMsg(telephony->mListener);
NS_ENSURE_SUCCESS(rv, nullptr); if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
return telephony.forget(); return telephony.forget();
} }
@@ -574,36 +592,24 @@ Telephony::EnqueueEnumerationAck()
} }
} }
nsresult /* static */
NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony) bool
Telephony::CheckPermission(nsPIDOMWindow* aWindow)
{ {
NS_ASSERTION(aWindow, "Null pointer!"); MOZ_ASSERT(aWindow && aWindow->IsInnerWindow());
nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
aWindow :
aWindow->GetCurrentInnerWindow();
nsCOMPtr<nsIPermissionManager> permMgr = nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
NS_ENSURE_TRUE(permMgr, NS_ERROR_UNEXPECTED); NS_ENSURE_TRUE(permMgr, false);
uint32_t permission; uint32_t permission;
nsresult rv = nsresult rv =
permMgr->TestPermissionFromWindow(aWindow, "telephony", &permission); permMgr->TestPermissionFromWindow(aWindow, "telephony", &permission);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, false);
if (permission != nsIPermissionManager::ALLOW_ACTION) { if (permission != nsIPermissionManager::ALLOW_ACTION) {
*aTelephony = nullptr; return false;
return NS_OK;
} }
nsCOMPtr<nsITelephonyProvider> ril = return true;
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;
} }

View File

@@ -8,6 +8,9 @@
#define mozilla_dom_telephony_telephony_h__ #define mozilla_dom_telephony_telephony_h__
#include "TelephonyCommon.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 "nsIDOMTelephony.h"
#include "nsIDOMTelephonyCall.h" #include "nsIDOMTelephonyCall.h"
@@ -56,7 +59,9 @@ public:
nsDOMEventTargetHelper) nsDOMEventTargetHelper)
static already_AddRefed<Telephony> static already_AddRefed<Telephony>
Create(nsPIDOMWindow* aOwner, nsITelephonyProvider* aProvider); Create(nsPIDOMWindow* aOwner, ErrorResult& aRv);
static bool CheckPermission(nsPIDOMWindow* aOwner);
nsISupports* nsISupports*
ToISupports() ToISupports()

View File

@@ -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__

View File

@@ -8,10 +8,19 @@ const KEY = "ril.radio.disabled";
SpecialPowers.addPermission("telephony", true, document); SpecialPowers.addPermission("telephony", true, document);
SpecialPowers.addPermission("settings-write", true, document); SpecialPowers.addPermission("settings-write", true, document);
let settings = window.navigator.mozSettings; // Permission changes can't change existing Navigator.prototype
let telephony = window.navigator.mozTelephony; // objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let settings;
let telephony;
let number = "112"; let number = "112";
let outgoing; let outgoing;
ifr.onload = function() {
settings = ifr.contentWindow.navigator.mozSettings;
telephony = ifr.contentWindow.navigator.mozTelephony;
getExistingCalls();
};
document.body.appendChild(ifr);
function getExistingCalls() { function getExistingCalls() {
runEmulatorCmd("gsm list", function(result) { runEmulatorCmd("gsm list", function(result) {
@@ -155,5 +164,3 @@ function cleanUp() {
SpecialPowers.removePermission("settings-write", document); SpecialPowers.removePermission("settings-write", document);
finish(); finish();
} }
getExistingCalls();

View File

@@ -17,23 +17,28 @@ var idleObserver = {
onactive: null 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() { function run_test() {
// addIdleObserver checks whether time is > 0. // addIdleObserver checks whether time is > 0.
this.idleObserver.time = 100; this.idleObserver.time = 100;
var added = false; var added = doAddIdleObserver(this.idleObserver, false);
try {
navigator.addIdleObserver(this.idleObserver);
added = true;
} catch (e) { }
ok(!added, "Should not be able to add idle observer without permission"); ok(!added, "Should not be able to add idle observer without permission");
SpecialPowers.addPermission("idle", true, document); SpecialPowers.addPermission("idle", true, document);
added = false;
try { added = doAddIdleObserver(this.idleObserver, true);
navigator.addIdleObserver(this.idleObserver);
added = true;
} catch (e) { }
ok(added, "Should be able to add idle observer with permission."); ok(added, "Should be able to add idle observer with permission.");
SimpleTest.finish(); SimpleTest.finish();

View File

@@ -35,12 +35,12 @@ function expectSuccess(param) {
} }
function testFailures() { function testFailures() {
expectFailure(null); expectSuccess(null);
expectFailure(undefined); expectSuccess(undefined);
expectFailure(-1); expectFailure(-1);
expectFailure('a'); expectSuccess('a');
expectFailure([100, -1]); expectFailure([100, -1]);
expectFailure([100, 'a']); expectSuccess([100, 'a']);
var maxVibrateMs = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_ms'); var maxVibrateMs = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_ms');
var maxVibrateListLen = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_list_len'); var maxVibrateListLen = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_list_len');

353
dom/webidl/Navigator.webidl Normal file
View 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

View 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;
};

View File

@@ -8,6 +8,10 @@ generated_webidl_files = \
CSS2Properties.webidl \ CSS2Properties.webidl \
$(NULL) $(NULL)
preprocessed_webidl_files = \
Navigator.webidl \
$(NULL)
webidl_files = \ webidl_files = \
AnalyserNode.webidl \ AnalyserNode.webidl \
AnimationEvent.webidl \ AnimationEvent.webidl \
@@ -227,6 +231,7 @@ webidl_files = \
Screen.webidl \ Screen.webidl \
ScriptProcessorNode.webidl \ ScriptProcessorNode.webidl \
ScrollAreaEvent.webidl \ ScrollAreaEvent.webidl \
SettingsManager.webidl \
SimpleGestureEvent.webidl \ SimpleGestureEvent.webidl \
SourceBuffer.webidl \ SourceBuffer.webidl \
SourceBufferList.webidl \ SourceBufferList.webidl \

View File

@@ -1158,8 +1158,8 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
} }
else { else {
if (!mNavigatorStringsLoaded) { if (!mNavigatorStringsLoaded) {
if (NS_FAILED(NS_GetNavigatorAppName(mNavigatorStrings.mAppName)) || NS_GetNavigatorAppName(mNavigatorStrings.mAppName);
NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorStrings.mAppVersion)) || if (NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorStrings.mAppVersion)) ||
NS_FAILED(NS_GetNavigatorPlatform(mNavigatorStrings.mPlatform)) || NS_FAILED(NS_GetNavigatorPlatform(mNavigatorStrings.mPlatform)) ||
NS_FAILED(NS_GetNavigatorUserAgent(mNavigatorStrings.mUserAgent))) { NS_FAILED(NS_GetNavigatorUserAgent(mNavigatorStrings.mUserAgent))) {
JS_ReportError(aCx, "Failed to load navigator strings!"); JS_ReportError(aCx, "Failed to load navigator strings!");

View File

@@ -35,7 +35,8 @@ Tests of DOM Worker Navigator
return; 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) { worker.onerror = function(event) {

View File

@@ -61,6 +61,7 @@ VPATH += \
ifeq (android,$(MOZ_WIDGET_TOOLKIT)) ifeq (android,$(MOZ_WIDGET_TOOLKIT))
OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(CAIRO_FT_CFLAGS) OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(CAIRO_FT_CFLAGS)
DEFINES += -DSK_FONTHOST_CAIRO_STANDALONE=0
endif endif
ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT)) ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))

View File

@@ -222,8 +222,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
'ashmem.cpp', 'ashmem.cpp',
'SkDebug_android.cpp', 'SkDebug_android.cpp',
'SkFontHost_cairo.cpp', 'SkFontHost_cairo.cpp',
'SkFontHost_linux.cpp',
'SkFontHost_FreeType_common.cpp', 'SkFontHost_FreeType_common.cpp',
'SkFontHost_FreeType.cpp',
'SkImageRef_ashmem.cpp', 'SkImageRef_ashmem.cpp',
'SkOSFile.cpp',
'SkTime_Unix.cpp', 'SkTime_Unix.cpp',
'SkThread_pthread.cpp', 'SkThread_pthread.cpp',
'SkThreadUtils_pthread.cpp', 'SkThreadUtils_pthread.cpp',

View File

@@ -20,6 +20,10 @@
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#ifndef SK_FONTHOST_CAIRO_STANDALONE
#define SK_FONTHOST_CAIRO_STANDALONE 1
#endif
static cairo_user_data_key_t kSkTypefaceKey; static cairo_user_data_key_t kSkTypefaceKey;
class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base { class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
@@ -138,6 +142,7 @@ SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypefac
return typeface; return typeface;
} }
#if SK_FONTHOST_CAIRO_STANDALONE
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
const char famillyName[], const char famillyName[],
SkTypeface::Style style) SkTypeface::Style style)
@@ -157,6 +162,7 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*)
SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented"); SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
return NULL; return NULL;
} }
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@@ -355,10 +361,12 @@ SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID,
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#if SK_FONTHOST_CAIRO_STANDALONE
#include "SkFontMgr.h" #include "SkFontMgr.h"
SkFontMgr* SkFontMgr::Factory() { SkFontMgr* SkFontMgr::Factory() {
// todo // todo
return NULL; return NULL;
} }
#endif

View File

@@ -19,8 +19,12 @@
#include "SkTSearch.h" #include "SkTSearch.h"
#ifndef SK_FONT_FILE_PREFIX #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/" #define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/"
#endif #endif
#endif
#ifndef SK_FONT_FILE_DIR_SEPERATOR #ifndef SK_FONT_FILE_DIR_SEPERATOR
#define SK_FONT_FILE_DIR_SEPERATOR "/" #define SK_FONT_FILE_DIR_SEPERATOR "/"
#endif #endif
@@ -419,7 +423,13 @@ static void load_system_fonts() {
return; 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; unsigned int count = 0;
load_directory_fonts(baseDirectory, &count); load_directory_fonts(baseDirectory, &count);

View File

@@ -205,8 +205,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
canLazilyParse ? &syntaxParser.ref() : NULL, NULL); canLazilyParse ? &syntaxParser.ref() : NULL, NULL);
parser.sct = sct; parser.sct = sct;
GlobalSharedContext globalsc(cx, scopeChain, Directives directives(options.strictOption);
options.strictOption, options.extraWarningsOption); GlobalSharedContext globalsc(cx, scopeChain, directives, options.extraWarningsOption);
bool savedCallerFun = bool savedCallerFun =
options.compileAndGo && options.compileAndGo &&
@@ -240,7 +240,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
// reset when this occurs. // reset when this occurs.
Maybe<ParseContext<FullParseHandler> > pc; 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()) if (!pc.ref().init())
return NULL; return NULL;
@@ -267,7 +268,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
* wishes to decompile it while it's running. * wishes to decompile it while it's running.
*/ */
JSFunction *fun = evalCaller->functionOrCallerFunction(); 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) if (!funbox)
return NULL; return NULL;
bce.objectList.add(funbox); bce.objectList.add(funbox);
@@ -305,7 +307,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
pc.destroy(); pc.destroy();
pc.construct(&parser, (GenericParseContext *) NULL, &globalsc, pc.construct(&parser, (GenericParseContext *) NULL, &globalsc,
staticLevel, /* bodyid = */ 0); (Directives *) NULL, staticLevel, /* bodyid = */ 0);
if (!pc.ref().init()) if (!pc.ref().init())
return NULL; return NULL;
JS_ASSERT(parser.pc == pc.addr()); JS_ASSERT(parser.pc == pc.addr());
@@ -462,16 +464,19 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
fun->setArgCount(formals.length()); fun->setArgCount(formals.length());
// If the context is strict, immediately parse the body in strict // Speculatively parse using the default directives implied by the context.
// mode. Otherwise, we parse it normally. If we see a "use strict" // If a directive is encountered (e.g., "use strict") that changes how the
// directive, we backup and reparse it as strict. // function should have been parsed, we backup and reparse with the new set
ParseNode *fn; // of directives.
Directives directives(options.strictOption);
TokenStream::Position start(parser.keepAtoms); TokenStream::Position start(parser.keepAtoms);
parser.tokenStream.tell(&start); parser.tokenStream.tell(&start);
bool strict = options.strictOption;
bool becameStrict; ParseNode *fn;
while (true) { while (true) {
fn = parser.standaloneFunctionBody(fun, formals, strict, &becameStrict); Directives newDirectives = directives;
fn = parser.standaloneFunctionBody(fun, formals, directives, &newDirectives);
if (fn) if (fn)
break; break;
@@ -481,10 +486,12 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
// the parse. // the parse.
parser.clearAbortedSyntaxParse(); parser.clearAbortedSyntaxParse();
} else { } else {
// If the function became strict, reparse in strict mode. if (parser.tokenStream.hadError() || directives == newDirectives)
if (strict || !becameStrict || parser.tokenStream.hadError())
return false; 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); parser.tokenStream.seek(start);

View File

@@ -384,7 +384,8 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
MOZ_ASSUME_UNREACHABLE("module nodes cannot be cloned"); MOZ_ASSUME_UNREACHABLE("module nodes cannot be cloned");
} }
NULLCHECK(pn->pn_funbox = 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)); NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body));
pn->pn_cookie = opn->pn_cookie; pn->pn_cookie = opn->pn_cookie;
pn->pn_dflags = opn->pn_dflags; pn->pn_dflags = opn->pn_dflags;

View File

@@ -453,9 +453,10 @@ Parser<ParseHandler>::newObjectBox(JSObject *obj)
template <typename ParseHandler> template <typename ParseHandler>
FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun, 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), : ObjectBox(fun, traceListHead),
SharedContext(cx, strict, extraWarnings), SharedContext(cx, directives, extraWarnings),
bindings(), bindings(),
bufStart(0), bufStart(0),
bufEnd(0), bufEnd(0),
@@ -516,8 +517,8 @@ FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunct
template <typename ParseHandler> template <typename ParseHandler>
FunctionBox * FunctionBox *
Parser<ParseHandler>::newFunctionBox(JSFunction *fun, Parser<ParseHandler>::newFunctionBox(JSFunction *fun, ParseContext<ParseHandler> *outerpc,
ParseContext<ParseHandler> *outerpc, bool strict) Directives inheritedDirectives)
{ {
JS_ASSERT(fun && !IsPoisonedPtr(fun)); JS_ASSERT(fun && !IsPoisonedPtr(fun));
@@ -530,7 +531,7 @@ Parser<ParseHandler>::newFunctionBox(JSFunction *fun,
*/ */
FunctionBox *funbox = FunctionBox *funbox =
alloc.new_<FunctionBox>(context, traceListHead, fun, outerpc, alloc.new_<FunctionBox>(context, traceListHead, fun, outerpc,
strict, options().extraWarningsOption); inheritedDirectives, options().extraWarningsOption);
if (!funbox) { if (!funbox) {
js_ReportOutOfMemory(context); js_ReportOutOfMemory(context);
return NULL; return NULL;
@@ -544,7 +545,7 @@ Parser<ParseHandler>::newFunctionBox(JSFunction *fun,
ModuleBox::ModuleBox(ExclusiveContext *cx, ObjectBox *traceListHead, Module *module, ModuleBox::ModuleBox(ExclusiveContext *cx, ObjectBox *traceListHead, Module *module,
ParseContext<FullParseHandler> *pc, bool extraWarnings) ParseContext<FullParseHandler> *pc, bool extraWarnings)
: ObjectBox(module, traceListHead), : 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 * an object lock before it finishes generating bytecode into a script
* protected from the GC by a root or a stack frame reference. * protected from the GC by a root or a stack frame reference.
*/ */
GlobalSharedContext globalsc(context, chain, Directives directives(options().strictOption);
options().strictOption, options().extraWarningsOption); GlobalSharedContext globalsc(context, chain, directives, options().extraWarningsOption);
ParseContext<ParseHandler> globalpc(this, NULL, &globalsc, /* staticLevel = */ 0, /* bodyid = */ 0); ParseContext<ParseHandler> globalpc(this, /* parent = */ NULL, &globalsc,
/* newDirectives = */ NULL, /* staticLevel = */ 0,
/* bodyid = */ 0);
if (!globalpc.init()) if (!globalpc.init())
return null(); return null();
@@ -843,11 +846,9 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName *name, Node pn)
template <> template <>
ParseNode * ParseNode *
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals, Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
bool strict, bool *becameStrict) Directives inheritedDirectives,
Directives *newDirectives)
{ {
if (becameStrict)
*becameStrict = false;
Node fn = handler.newFunctionDefinition(); Node fn = handler.newFunctionDefinition();
if (!fn) if (!fn)
return null(); return null();
@@ -859,12 +860,13 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
argsbody->makeEmpty(); argsbody->makeEmpty();
fn->pn_body = argsbody; fn->pn_body = argsbody;
FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, strict); FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, inheritedDirectives);
if (!funbox) if (!funbox)
return null(); return null();
handler.setFunctionBox(fn, funbox); 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()) if (!funpc.init())
return null(); return null();
@@ -874,11 +876,8 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
} }
ParseNode *pn = functionBody(Statement, StatementListBody); ParseNode *pn = functionBody(Statement, StatementListBody);
if (!pn) { if (!pn)
if (becameStrict && pc->funBecameStrict)
*becameStrict = true;
return null(); return null();
}
if (!tokenStream.matchToken(TOK_EOF)) { if (!tokenStream.matchToken(TOK_EOF)) {
report(ParseError, false, null(), JSMSG_SYNTAX_ERROR); 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. // so we can skip over them after accounting for their free variables.
if (LazyScript *lazyOuter = handler.lazyOuterFunction()) { if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
JSFunction *fun = handler.nextLazyInnerFunction(); JSFunction *fun = handler.nextLazyInnerFunction();
FunctionBox *funbox = newFunctionBox(fun, pc, /* strict = */ false); FunctionBox *funbox = newFunctionBox(fun, pc, Directives(/* strict = */ false));
if (!funbox) if (!funbox)
return false; return false;
handler.setFunctionBox(pn, funbox); handler.setFunctionBox(pn, funbox);
@@ -1933,27 +1932,29 @@ Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream:
if (!fun) if (!fun)
return null(); return null();
// If the outer scope is strict, immediately parse the function in strict // Speculatively parse using the directives of the parent parsing context.
// mode. Otherwise, we parse it normally. If we see a "use strict" // If a directive is encountered (e.g., "use strict") that changes how the
// directive, we backup and reparse it as strict. // function should have been parsed, we backup and reparse with the new set
bool initiallyStrict = pc->sc->strict; // of directives.
bool becameStrict; Directives directives(pc);
if (!functionArgsAndBody(pn, fun, type, kind, initiallyStrict, Directives newDirectives = directives;
&becameStrict))
{ while (true) {
if (initiallyStrict || !becameStrict || tokenStream.hadError()) if (functionArgsAndBody(pn, fun, type, kind, directives, &newDirectives))
break;
if (tokenStream.hadError() || directives == newDirectives)
return null(); 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); tokenStream.seek(start);
if (funName && tokenStream.getToken() == TOK_ERROR) if (funName && tokenStream.getToken() == TOK_ERROR)
return null(); return null();
// functionArgsAndBody may have already set pn->pn_body before failing. // functionArgsAndBody may have already set pn->pn_body before failing.
handler.setFunctionBody(pn, null()); handler.setFunctionBody(pn, null());
if (!functionArgsAndBody(pn, fun, type, kind, true))
return null();
} }
return pn; return pn;
@@ -2054,14 +2055,13 @@ template <>
bool bool
Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun, Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
FunctionType type, FunctionSyntaxKind kind, FunctionType type, FunctionSyntaxKind kind,
bool strict, bool *becameStrict) Directives inheritedDirectives,
Directives *newDirectives)
{ {
if (becameStrict)
*becameStrict = false;
ParseContext<FullParseHandler> *outerpc = pc; ParseContext<FullParseHandler> *outerpc = pc;
// Create box for fun->object early to protect against last-ditch GC. // 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) if (!funbox)
return false; return false;
@@ -2077,13 +2077,13 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
tokenStream.tell(&position); tokenStream.tell(&position);
parser->tokenStream.seek(position, tokenStream); parser->tokenStream.seek(position, tokenStream);
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, funbox, ParseContext<SyntaxParseHandler> funpc(parser, outerpc, funbox, newDirectives,
outerpc->staticLevel + 1, outerpc->blockidGen); outerpc->staticLevel + 1, outerpc->blockidGen);
if (!funpc.init()) if (!funpc.init())
return false; return false;
if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric, if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
fun, type, kind, becameStrict)) fun, type, kind, newDirectives))
{ {
if (parser->hadAbortedSyntaxParse()) { if (parser->hadAbortedSyntaxParse()) {
// Try again with a full parse. // Try again with a full parse.
@@ -2111,12 +2111,12 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
} while (false); } while (false);
// Continue doing a full parse for this inner function. // 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); outerpc->staticLevel + 1, outerpc->blockidGen);
if (!funpc.init()) if (!funpc.init())
return false; return false;
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, becameStrict)) if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
return false; return false;
if (!leaveFunction(pn, outerpc, kind)) if (!leaveFunction(pn, outerpc, kind))
@@ -2138,24 +2138,23 @@ template <>
bool bool
Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun, Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
FunctionType type, FunctionSyntaxKind kind, FunctionType type, FunctionSyntaxKind kind,
bool strict, bool *becameStrict) Directives inheritedDirectives,
Directives *newDirectives)
{ {
if (becameStrict)
*becameStrict = false;
ParseContext<SyntaxParseHandler> *outerpc = pc; ParseContext<SyntaxParseHandler> *outerpc = pc;
// Create box for fun->object early to protect against last-ditch GC. // 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) if (!funbox)
return false; return false;
// Initialize early for possible flags mutation via destructuringExpr. // 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); outerpc->staticLevel + 1, outerpc->blockidGen);
if (!funpc.init()) if (!funpc.init())
return false; return false;
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, becameStrict)) if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
return false; return false;
if (!leaveFunction(pn, outerpc, kind)) if (!leaveFunction(pn, outerpc, kind))
@@ -2177,17 +2176,23 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
if (!pn) if (!pn)
return null(); return null();
FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, strict); Directives directives(/* strict = */ strict);
FunctionBox *funbox = newFunctionBox(fun, /* outerpc = */ NULL, directives);
if (!funbox) if (!funbox)
return null(); return null();
handler.setFunctionBox(pn, funbox); 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()) if (!funpc.init())
return null(); return null();
if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement, NULL)) if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement, &newDirectives)) {
JS_ASSERT(directives == newDirectives);
return null(); return null();
}
if (fun->isNamedLambda()) { if (fun->isNamedLambda()) {
if (AtomDefnPtr p = pc->lexdeps->lookup(fun->name())) { if (AtomDefnPtr p = pc->lexdeps->lookup(fun->name())) {
@@ -2208,7 +2213,8 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
template <typename ParseHandler> template <typename ParseHandler>
bool bool
Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type, 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 // Given a properly initialized parse context, try to parse an actual
// function without concern for conversion to strict mode, use of lazy // 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); Node body = functionBody(kind, bodyType);
if (!body) { if (!body)
// Notify the caller if this function was discovered to be strict.
if (becameStrict && pc->funBecameStrict)
*becameStrict = true;
return false; return false;
}
if (!yieldGuard.empty() && !yieldGuard.ref().checkValidBody(body, JSMSG_YIELD_IN_ARROW)) if (!yieldGuard.empty() && !yieldGuard.ref().checkValidBody(body, JSMSG_YIELD_IN_ARROW))
return false; return false;
@@ -2312,7 +2314,8 @@ Parser<FullParseHandler>::moduleDecl()
return NULL; return NULL;
pn->pn_modulebox = modulebox; 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()) if (!modulepc.init())
return NULL; return NULL;
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_MODULE); 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->strict) {
if (pc->sc->isFunctionBox()) { if (pc->sc->isFunctionBox()) {
// Request that this function be reparsed as strict. // Request that this function be reparsed as strict.
pc->funBecameStrict = true; pc->newDirectives->setStrict();
return false; return false;
} else { } else {
// We don't reparse global scopes, so we keep track of the // We don't reparse global scopes, so we keep track of the
@@ -5984,11 +5987,12 @@ Parser<FullParseHandler>::generatorExpr(ParseNode *kid)
return null(); return null();
/* Create box for fun->object early to protect against last-ditch GC. */ /* 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) if (!genFunbox)
return null(); return null();
ParseContext<FullParseHandler> genpc(this, outerpc, genFunbox, ParseContext<FullParseHandler> genpc(this, outerpc, genFunbox, /* newDirectives = */ NULL,
outerpc->staticLevel + 1, outerpc->blockidGen); outerpc->staticLevel + 1, outerpc->blockidGen);
if (!genpc.init()) if (!genpc.init())
return null(); return null();

View File

@@ -214,6 +214,13 @@ struct ParseContext : public GenericParseContext
// All inner functions in this context. Only filled in when parsing syntax. // All inner functions in this context. Only filled in when parsing syntax.
AutoFunctionVector innerFunctions; 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 // Set when parsing a declaration-like destructuring pattern. This flag
// causes PrimaryExpr to create PN_NAME parse nodes for variable references // 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 // 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. // they need to be treated differently.
bool inDeclDestructuring:1; 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, 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), : GenericParseContext(parent, sc),
bodyid(0), // initialized in init() bodyid(0), // initialized in init()
blockidGen(bodyid), // used to set |bodyid| and subsequently incremented in init() blockidGen(bodyid), // used to set |bodyid| and subsequently incremented in init()
@@ -250,8 +254,8 @@ struct ParseContext : public GenericParseContext
lexdeps(prs->context), lexdeps(prs->context),
funcStmts(NULL), funcStmts(NULL),
innerFunctions(prs->context), innerFunctions(prs->context),
inDeclDestructuring(false), newDirectives(newDirectives),
funBecameStrict(false) inDeclDestructuring(false)
{ {
prs->pc = this; 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> template <typename ParseHandler>
struct BindData; struct BindData;
@@ -369,7 +379,8 @@ class Parser : private AutoGCRooter, public StrictModeGetter
*/ */
ObjectBox *newObjectBox(JSObject *obj); ObjectBox *newObjectBox(JSObject *obj);
ModuleBox *newModuleBox(Module *module, ParseContext<ParseHandler> *pc); 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 * 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. // Parse a function, given only its body. Used for the Function constructor.
Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals, 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 // Parse a function, given only its arguments and body. Used for lazily
// parsed functions. // parsed functions.
@@ -416,7 +427,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type); Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type);
bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type, bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
FunctionSyntaxKind kind, bool *becameStrict); FunctionSyntaxKind kind, Directives *newDirectives);
virtual bool strictMode() { return pc->sc->strict; } virtual bool strictMode() { return pc->sc->strict; }
@@ -487,7 +498,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
FunctionType type, FunctionSyntaxKind kind); FunctionType type, FunctionSyntaxKind kind);
bool functionArgsAndBody(Node pn, HandleFunction fun, bool functionArgsAndBody(Node pn, HandleFunction fun,
FunctionType type, FunctionSyntaxKind kind, FunctionType type, FunctionSyntaxKind kind,
bool strict, bool *becameStrict = NULL); Directives inheritedDirectives, Directives *newDirectives);
Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin); Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);

View File

@@ -140,6 +140,30 @@ class FunctionContextFlags
class GlobalSharedContext; 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 * The struct SharedContext is part of the current parser context (see
* ParseContext). It stores information that is reused between the parser and * 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 function code, funbox must be non-NULL and scopeChain must be NULL.
// If it's global code, funbox 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), : context(cx),
anyCxFlags(), anyCxFlags(),
strict(strict), strict(directives.strict()),
extraWarnings(extraWarnings) extraWarnings(extraWarnings)
{} {}
@@ -192,8 +216,8 @@ class GlobalSharedContext : public SharedContext
public: public:
GlobalSharedContext(ExclusiveContext *cx, JSObject *scopeChain, GlobalSharedContext(ExclusiveContext *cx, JSObject *scopeChain,
bool strict, bool extraWarnings) Directives directives, bool extraWarnings)
: SharedContext(cx, strict, extraWarnings), : SharedContext(cx, directives, extraWarnings),
scopeChain_(cx, scopeChain) scopeChain_(cx, scopeChain)
{} {}
@@ -249,8 +273,8 @@ class FunctionBox : public ObjectBox, public SharedContext
template <typename ParseHandler> template <typename ParseHandler>
FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun, FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
ParseContext<ParseHandler> *pc, ParseContext<ParseHandler> *pc, Directives directives,
bool strict, bool extraWarnings); bool extraWarnings);
ObjectBox *toObjectBox() { return this; } ObjectBox *toObjectBox() { return this; }
JSFunction *function() const { return &object->as<JSFunction>(); } JSFunction *function() const { return &object->as<JSFunction>(); }

View File

@@ -966,7 +966,14 @@ TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
uint32_t i; uint32_t i;
if (js_IdIsIndex(id, &i)) if (js_IdIsIndex(id, &i))
return; 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);
} }
} }

View File

@@ -221,13 +221,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=668855
let dummy_test_map = new WeakMap; let dummy_test_map = new WeakMap;
let navi_fail = false; let rule_fail = false;
let got_rule = false;
try { 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) { } 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.");
} }

View File

@@ -1,6 +1,7 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
<head> <head>
<link rel="stylesheet" href="data:text/css,div {}">
<title>Test Cross-Compartment DOM WeakMaps</title> <title>Test Cross-Compartment DOM WeakMaps</title>
</head> </head>
<body> <body>

View File

@@ -16,13 +16,13 @@ function setup() {
my_map.set(item, "success_string"); my_map.set(item, "success_string");
var navi_fail = false; var rule_fail = false;
try { try {
my_map.set(window.frames[0].navigator, 1); my_map.set(window.frames[0].document.styleSheets[0].cssRules[0], 1);
} catch (e) { } 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() { function runTest() {

View File

@@ -333,8 +333,7 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
aBottomMarginResult.Zero(); aBottomMarginResult.Zero();
} }
nscoord x = mX; nsPoint position(mX, mY);
nscoord y = mY;
nscoord backupContainingBlockAdvance = 0; nscoord backupContainingBlockAdvance = 0;
// Check whether the block's bottom margin collapses with its top // Check whether the block's bottom margin collapses with its top
@@ -358,7 +357,7 @@ nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
printf(": "); printf(": ");
nsFrame::ListTag(stdout, mFrame); nsFrame::ListTag(stdout, mFrame);
printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n", printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n",
y, mSpace.y); position.y, mSpace.y);
#endif #endif
// Section 8.3.1 of CSS 2.1 says that blocks with adjoining // Section 8.3.1 of CSS 2.1 says that blocks with adjoining
// top/bottom margins whose top margin collapses with their // 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 + // even if there's some sort of integer overflow that makes y +
// mMetrics.height appear to go beyond the available height. // mMetrics.height appear to go beyond the available height.
if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) { if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) {
nscoord yMost = y - backupContainingBlockAdvance + mMetrics.height; nscoord yMost = position.y - backupContainingBlockAdvance + mMetrics.height;
if (yMost > mSpace.YMost()) { if (yMost > mSpace.YMost()) {
// didn't fit, we must acquit. // didn't fit, we must acquit.
mFrame->DidReflow(mPresContext, &aReflowState, nsDidReflowStatus::FINISHED); 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); mMetrics.width, mMetrics.height);
// Apply CSS relative positioning aReflowState.ApplyRelativePositioning(&position);
const nsStyleDisplay* styleDisp = mFrame->StyleDisplay();
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
x += aReflowState.mComputedOffsets.left;
y += aReflowState.mComputedOffsets.top;
}
// Now place the frame and complete the reflow process // 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; return true;
} }

View File

@@ -476,12 +476,8 @@ nsCanvasFrame::Reflow(nsPresContext* aPresContext,
nsPoint kidPt(kidReflowState.mComputedMargin.left, nsPoint kidPt(kidReflowState.mComputedMargin.left,
kidReflowState.mComputedMargin.top); kidReflowState.mComputedMargin.top);
// Apply CSS relative positioning
const nsStyleDisplay* styleDisp = kidFrame->StyleDisplay(); kidReflowState.ApplyRelativePositioning(&kidPt);
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
kidPt += nsPoint(kidReflowState.mComputedOffsets.left,
kidReflowState.mComputedOffsets.top);
}
// Reflow the frame // Reflow the frame
ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,

View File

@@ -2400,12 +2400,7 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
"We gave flex item unconstrained available height, so it " "We gave flex item unconstrained available height, so it "
"should be complete"); "should be complete");
// Apply CSS relative positioning childReflowState.ApplyRelativePositioning(&physicalPosn);
const nsStyleDisplay* styleDisp = curItem.Frame()->StyleDisplay();
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
physicalPosn.x += childReflowState.mComputedOffsets.left;
physicalPosn.y += childReflowState.mComputedOffsets.top;
}
rv = FinishReflowChild(curItem.Frame(), aPresContext, rv = FinishReflowChild(curItem.Frame(), aPresContext,
&childReflowState, childDesiredSize, &childReflowState, childDesiredSize,

View File

@@ -2934,10 +2934,6 @@ void nsGfxScrollFrameInner::CurPosAttributeChanged(nsIContent* aContent)
(mVScrollbarBox && mVScrollbarBox->GetContent() == aContent), (mVScrollbarBox && mVScrollbarBox->GetContent() == aContent),
"unexpected child"); "unexpected child");
if (mScrollbarActivity) {
mScrollbarActivity->ActivityOccurred();
}
// Attribute changes on the scrollbars happen in one of three ways: // Attribute changes on the scrollbars happen in one of three ways:
// 1) The scrollbar changed the attribute in response to some user event // 1) The scrollbar changed the attribute in response to some user event
// 2) We changed the attribute in response to a ScrollPositionDidChange // 2) We changed the attribute in response to a ScrollPositionDidChange
@@ -2970,6 +2966,10 @@ void nsGfxScrollFrameInner::CurPosAttributeChanged(nsIContent* aContent)
return; return;
} }
if (mScrollbarActivity) {
mScrollbarActivity->ActivityOccurred();
}
bool isSmooth = aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::smooth); bool isSmooth = aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::smooth);
if (isSmooth) { if (isSmooth) {
// Make sure an attribute-setting callback occurs even if the view // Make sure an attribute-setting callback occurs even if the view

View File

@@ -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* nsIFrame*
nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame, nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame* aFrame,
nscoord& aCBLeftEdge, nscoord& aCBLeftEdge,

View File

@@ -533,6 +533,15 @@ public:
nscoord aContainingBlockHeight, nscoord aContainingBlockHeight,
nsMargin& aComputedOffsets); 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 #ifdef DEBUG
// Reflow trace methods. Defined in nsFrame.cpp so they have access // Reflow trace methods. Defined in nsFrame.cpp so they have access
// to the display-reflow infrastructure. // to the display-reflow infrastructure.

View File

@@ -2628,8 +2628,9 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflo
if (pfd->GetFlag(PFD_RELATIVEPOS)) { if (pfd->GetFlag(PFD_RELATIVEPOS)) {
// right and bottom are handled by // right and bottom are handled by
// nsHTMLReflowState::ComputeRelativeOffsets // nsHTMLReflowState::ComputeRelativeOffsets
nsPoint change(pfd->mOffsets.left, pfd->mOffsets.top); nsHTMLReflowState::ApplyRelativePositioning(pfd->mFrame->StyleDisplay(),
origin += change; pfd->mOffsets,
&origin);
frame->SetPosition(origin); frame->SetPosition(origin);
} }

View File

@@ -34,6 +34,9 @@ LOCAL_INCLUDES += \
-I$(srcdir)/../../content/xul/document/src \ -I$(srcdir)/../../content/xul/document/src \
$(NULL) $(NULL)
nsStyleStructList.h : $(srcdir)/generate-stylestructlist.py
$(PYTHON) $< > $@
_FILES = \ _FILES = \
contenteditable.css \ contenteditable.css \
designmode.css \ designmode.css \
@@ -42,7 +45,10 @@ _FILES = \
TopLevelVideoDocument.css \ TopLevelVideoDocument.css \
$(NULL) $(NULL)
GARBAGE += $(addprefix $(DIST)/bin/res/,$(_FILES)) GARBAGE += \
$(addprefix $(DIST)/bin/res/,$(_FILES)) \
nsStyleStructList.h \
$(NULL)
libs:: $(_FILES) libs:: $(_FILES)
$(INSTALL) $^ $(DIST)/bin/res $(INSTALL) $^ $(DIST)/bin/res

View 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

View File

@@ -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

View File

@@ -113,7 +113,6 @@ abstract public class BrowserApp extends GeckoApp
} }
private Vector<MenuItemInfo> mAddonMenuItemsCache; private Vector<MenuItemInfo> mAddonMenuItemsCache;
private ButtonToast mToast;
private PropertyAnimator mMainLayoutAnimator; private PropertyAnimator mMainLayoutAnimator;
private static final Interpolator sTabsInterpolator = new Interpolator() { private static final Interpolator sTabsInterpolator = new Interpolator() {
@@ -395,15 +394,6 @@ abstract public class BrowserApp extends GeckoApp
mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browser_toolbar); 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).setTouchEventInterceptor(new HideTabsTouchListener());
((GeckoApp.MainLayout) mMainLayout).setMotionEventInterceptor(new MotionEventInterceptor() { ((GeckoApp.MainLayout) mMainLayout).setMotionEventInterceptor(new MotionEventInterceptor() {
@Override @Override
@@ -815,7 +805,7 @@ abstract public class BrowserApp extends GeckoApp
// If the page has shrunk so that the toolbar no longer scrolls, make // If the page has shrunk so that the toolbar no longer scrolls, make
// sure the toolbar is visible. // sure the toolbar is visible.
if (aMetrics.getPageHeight() < aMetrics.getHeight()) { if (aMetrics.getPageHeight() <= aMetrics.getHeight()) {
if (mDynamicToolbarCanScroll) { if (mDynamicToolbarCanScroll) {
mDynamicToolbarCanScroll = false; mDynamicToolbarCanScroll = false;
if (!mBrowserToolbar.isVisible()) { if (!mBrowserToolbar.isVisible()) {
@@ -1449,31 +1439,17 @@ abstract public class BrowserApp extends GeckoApp
}); });
if (info.icon != null) { if (info.icon != null) {
if (info.icon.startsWith("data")) { BitmapUtils.getDrawable(this, info.icon, new BitmapUtils.BitmapLoader() {
BitmapDrawable drawable = new BitmapDrawable(BitmapUtils.getBitmapFromDataURI(info.icon)); @Override
item.setIcon(drawable); public void onBitmapFound(Drawable d) {
} if (d == null) {
else if (info.icon.startsWith("jar:") || info.icon.startsWith("file://")) { item.setIcon(R.drawable.ic_menu_addons_filler);
ThreadUtils.postToBackgroundThread(new Runnable() { return;
@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);
}
} }
});
} else { item.setIcon(d);
item.setIcon(R.drawable.ic_menu_addons_filler); }
} });
} else { } else {
item.setIcon(R.drawable.ic_menu_addons_filler); item.setIcon(R.drawable.ic_menu_addons_filler);
} }
@@ -1699,10 +1675,18 @@ abstract public class BrowserApp extends GeckoApp
} else { } else {
tab.addBookmark(); tab.addBookmark();
mToast.show(false, mToast.show(false,
getResources().getString(R.string.bookmark_added), getResources().getString(R.string.bookmark_added),
getResources().getString(R.string.bookmark_options), getResources().getString(R.string.bookmark_options),
0, null,
ADD_SHORTCUT_TOAST); new ButtonToast.ToastListener() {
@Override
public void onButtonClicked() {
showBookmarkDialog();
}
@Override
public void onToastHidden(ButtonToast.ReasonHidden reason) { }
});
item.setIcon(R.drawable.ic_menu_bookmark_remove); item.setIcon(R.drawable.ic_menu_bookmark_remove);
} }
} }

View File

@@ -11,14 +11,14 @@ import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.menu.GeckoMenu; import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.MenuPopup; 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.Clipboard;
import org.mozilla.gecko.util.StringUtils; import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.HardwareUtils; import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask; import org.mozilla.gecko.util.UiAsyncTask;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.PrefsHelper;
import org.json.JSONObject; import org.json.JSONObject;
@@ -63,14 +63,14 @@ import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams; import android.widget.RelativeLayout.LayoutParams;
import android.widget.ViewSwitcher; import android.widget.ViewSwitcher;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
public class BrowserToolbar extends GeckoRelativeLayout public class BrowserToolbar extends GeckoRelativeLayout
implements Tabs.OnTabsChangedListener, implements Tabs.OnTabsChangedListener,
GeckoMenu.ActionItemBarPresenter, GeckoMenu.ActionItemBarPresenter,
Animation.AnimationListener { Animation.AnimationListener,
GeckoEventListener {
private static final String LOGTAG = "GeckoToolbar"; private static final String LOGTAG = "GeckoToolbar";
public static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode"; public static final String PREF_TITLEBAR_MODE = "browser.chrome.titlebarMode";
private LayoutParams mAwesomeBarParams; private LayoutParams mAwesomeBarParams;
@@ -88,7 +88,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
public ImageButton mFavicon; public ImageButton mFavicon;
public ImageButton mStop; public ImageButton mStop;
public ImageButton mSiteSecurity; public ImageButton mSiteSecurity;
public ImageButton mReader; public PageActionLayout mPageActionLayout;
private AnimationDrawable mProgressSpinner; private AnimationDrawable mProgressSpinner;
private TabCounter mTabsCounter; private TabCounter mTabsCounter;
private ImageView mShadow; private ImageView mShadow;
@@ -183,6 +183,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
mDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext)); mDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext));
mPrivateDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext_private)); mPrivateDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext_private));
registerEventListener("Reader:Click");
registerEventListener("Reader:LongClick");
mShowSiteSecurity = false; mShowSiteSecurity = false;
mShowReader = false; mShowReader = false;
@@ -221,8 +224,8 @@ public class BrowserToolbar extends GeckoRelativeLayout
mProgressSpinner = (AnimationDrawable) res.getDrawable(R.drawable.progress_spinner); mProgressSpinner = (AnimationDrawable) res.getDrawable(R.drawable.progress_spinner);
mStop = (ImageButton) findViewById(R.id.stop); mStop = (ImageButton) findViewById(R.id.stop);
mReader = (ImageButton) findViewById(R.id.reader);
mShadow = (ImageView) findViewById(R.id.shadow); mShadow = (ImageView) findViewById(R.id.shadow);
mPageActionLayout = (PageActionLayout) findViewById(R.id.page_action_layout);
if (Build.VERSION.SDK_INT >= 16) { if (Build.VERSION.SDK_INT >= 16) {
mShadow.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); mShadow.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -237,9 +240,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
// order appropriately. // order appropriately.
if (HardwareUtils.isTablet()) { if (HardwareUtils.isTablet()) {
mFocusOrder = Arrays.asList(mTabs, mBack, mForward, this, mFocusOrder = Arrays.asList(mTabs, mBack, mForward, this,
mSiteSecurity, mReader, mStop, mActionItemBar, mMenu); mSiteSecurity, mPageActionLayout, mStop, mActionItemBar, mMenu);
} else { } else {
mFocusOrder = Arrays.asList(this, mSiteSecurity, mReader, mStop, mFocusOrder = Arrays.asList(this, mSiteSecurity, mPageActionLayout, mStop,
mTabs, mMenu); 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() { mShadow.setOnClickListener(new Button.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@@ -474,7 +455,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
if (showProgress && tab.getState() == Tab.STATE_LOADING) if (showProgress && tab.getState() == Tab.STATE_LOADING)
setProgressVisibility(true); setProgressVisibility(true);
setSecurityMode(tab.getSecurityMode()); setSecurityMode(tab.getSecurityMode());
setReaderMode(tab.getReaderEnabled()); setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
} }
break; break;
case STOP: case STOP:
@@ -519,7 +500,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
break; break;
case READER_ENABLED: case READER_ENABLED:
if (Tabs.getInstance().isSelectedTab(tab)) { if (Tabs.getInstance().isSelectedTab(tab)) {
setReaderMode(tab.getReaderEnabled()); setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
} }
break; break;
} }
@@ -537,7 +518,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
mFavicon.setNextFocusDownId(nextId); mFavicon.setNextFocusDownId(nextId);
mStop.setNextFocusDownId(nextId); mStop.setNextFocusDownId(nextId);
mSiteSecurity.setNextFocusDownId(nextId); mSiteSecurity.setNextFocusDownId(nextId);
mReader.setNextFocusDownId(nextId); mPageActionLayout.setNextFocusDownId(nextId);
mMenu.setNextFocusDownId(nextId); mMenu.setNextFocusDownId(nextId);
} }
@@ -613,7 +594,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
ViewHelper.setTranslationX(mMenuIcon, curveTranslation); ViewHelper.setTranslationX(mMenuIcon, curveTranslation);
} }
ViewHelper.setAlpha(mReader, 0); ViewHelper.setAlpha(mPageActionLayout, 0);
ViewHelper.setAlpha(mStop, 0); ViewHelper.setAlpha(mStop, 0);
} }
@@ -661,7 +642,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
// Fade toolbar buttons (reader, stop) after the entry // Fade toolbar buttons (reader, stop) after the entry
// is schrunk back to its original size. // is schrunk back to its original size.
buttonsAnimator.attach(mReader, buttonsAnimator.attach(mPageActionLayout,
PropertyAnimator.Property.ALPHA, PropertyAnimator.Property.ALPHA,
1); 1);
buttonsAnimator.attach(mStop, buttonsAnimator.attach(mStop,
@@ -708,7 +689,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
setSelected(true); setSelected(true);
// Hide stop/reader buttons immediately // Hide stop/reader buttons immediately
ViewHelper.setAlpha(mReader, 0); ViewHelper.setAlpha(mPageActionLayout, 0);
ViewHelper.setAlpha(mStop, 0); ViewHelper.setAlpha(mStop, 0);
// Slide the right side elements of the toolbar // Slide the right side elements of the toolbar
@@ -827,22 +808,16 @@ public class BrowserToolbar extends GeckoRelativeLayout
// Handle the viewing mode page actions // Handle the viewing mode page actions
setSiteSecurityVisibility(mShowSiteSecurity && !isLoading); 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; boolean inReaderMode = false;
Tab tab = Tabs.getInstance().getSelectedTab(); Tab tab = Tabs.getInstance().getSelectedTab();
if (tab != null) if (tab != null)
inReaderMode = ReaderModeUtils.isAboutReader(tab.getURL()); 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 // 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 // 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. // padding in them. This is just to avoid wasting space when icons are shown.
mTitle.setPadding(0, 0, (!isLoading && !(mShowReader || inReaderMode) ? mTitlePadding : 0), 0); mTitle.setPadding(0, 0, (!isLoading && !(mShowReader || inReaderMode) ? mTitlePadding : 0), 0);
updateFocusOrder(); updateFocusOrder();
} }
@@ -997,11 +972,6 @@ public class BrowserToolbar extends GeckoRelativeLayout
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE); setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
} }
private void setReaderMode(boolean showReader) {
mShowReader = showReader;
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
}
public void prepareTabsAnimation(PropertyAnimator animator, boolean tabsAreShown) { public void prepareTabsAnimation(PropertyAnimator animator, boolean tabsAreShown) {
if (!tabsAreShown) { if (!tabsAreShown) {
PropertyAnimator buttonsAnimator = PropertyAnimator buttonsAnimator =
@@ -1162,7 +1132,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
setFavicon(tab.getFavicon()); setFavicon(tab.getFavicon());
setProgressVisibility(tab.getState() == Tab.STATE_LOADING); setProgressVisibility(tab.getState() == Tab.STATE_LOADING);
setSecurityMode(tab.getSecurityMode()); setSecurityMode(tab.getSecurityMode());
setReaderMode(tab.getReaderEnabled()); setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
setShadowVisibility(true); setShadowVisibility(true);
updateBackButton(tab.canDoBack()); updateBackButton(tab.canDoBack());
updateForwardButton(tab.canDoForward()); updateForwardButton(tab.canDoForward());
@@ -1189,6 +1159,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
mPrefObserverId = null; mPrefObserverId = null;
} }
Tabs.unregisterOnTabsChangedListener(this); Tabs.unregisterOnTabsChangedListener(this);
unregisterEventListener("Reader:Click");
unregisterEventListener("Reader:LongClick");
} }
public boolean openOptionsMenu() { public boolean openOptionsMenu() {
@@ -1225,4 +1198,27 @@ public class BrowserToolbar extends GeckoRelativeLayout
return true; 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();
}
}
}
} }

View File

@@ -25,6 +25,7 @@ import org.mozilla.gecko.util.GeckoEventResponder;
import org.mozilla.gecko.util.HardwareUtils; import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask; import org.mozilla.gecko.util.UiAsyncTask;
import org.mozilla.gecko.widget.ButtonToast;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@@ -44,6 +45,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.hardware.Sensor; import android.hardware.Sensor;
@@ -187,6 +189,7 @@ abstract public class GeckoApp
protected DoorHangerPopup mDoorHangerPopup; protected DoorHangerPopup mDoorHangerPopup;
protected FormAssistPopup mFormAssistPopup; protected FormAssistPopup mFormAssistPopup;
protected TabsPanel mTabsPanel; protected TabsPanel mTabsPanel;
protected ButtonToast mToast;
// Handles notification messages from javascript // Handles notification messages from javascript
protected NotificationHelper mNotificationHelper; protected NotificationHelper mNotificationHelper;
@@ -545,8 +548,16 @@ abstract public class GeckoApp
try { try {
if (event.equals("Toast:Show")) { if (event.equals("Toast:Show")) {
final String msg = message.getString("message"); final String msg = message.getString("message");
final String duration = message.getString("duration"); final JSONObject button = message.optJSONObject("button");
handleShowToast(msg, duration); 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");
showNormalToast(msg, duration);
}
} else if (event.equals("log")) { } else if (event.equals("log")) {
// generic log listener // generic log listener
final String msg = message.getString("msg"); 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() { ThreadUtils.postToUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
Toast toast; Toast toast;
if (duration.equals("long")) if (duration.equals("long")) {
toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_LONG); toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_LONG);
else } else {
toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_SHORT); toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_SHORT);
}
toast.show(); 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) { private void addFullScreenPluginView(View view) {
if (mFullScreenPluginView != null) { if (mFullScreenPluginView != null) {
Log.w(LOGTAG, "Already have a fullscreen plugin view"); Log.w(LOGTAG, "Already have a fullscreen plugin view");
@@ -1278,6 +1311,7 @@ abstract public class GeckoApp
// Set up tabs panel. // Set up tabs panel.
mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel); mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel);
mNotificationHelper = new NotificationHelper(this); mNotificationHelper = new NotificationHelper(this);
mToast = new ButtonToast(findViewById(R.id.toast));
// Check if the last run was exited due to a normal kill while // 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 // we were in the background, or a more harsh kill while we were

View File

@@ -129,6 +129,7 @@ FENNEC_JAVA_FILES = \
NotificationService.java \ NotificationService.java \
NSSBridge.java \ NSSBridge.java \
OrderedBroadcastHelper.java \ OrderedBroadcastHelper.java \
PageActionLayout.java \
PrefsHelper.java \ PrefsHelper.java \
PrivateDataPreference.java \ PrivateDataPreference.java \
PrivateTab.java \ PrivateTab.java \
@@ -641,6 +642,7 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/ic_menu_new_tab.png \ res/drawable-mdpi/ic_menu_new_tab.png \
res/drawable-mdpi/ic_menu_reload.png \ res/drawable-mdpi/ic_menu_reload.png \
res/drawable-mdpi/ic_status_logo.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_1.png \
res/drawable-mdpi/progress_spinner_2.png \ res/drawable-mdpi/progress_spinner_2.png \
res/drawable-mdpi/progress_spinner_3.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_new_tab.png \
res/drawable-hdpi/ic_menu_reload.png \ res/drawable-hdpi/ic_menu_reload.png \
res/drawable-hdpi/ic_status_logo.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_divider.9.png \
res/drawable-hdpi/tab_indicator_selected.9.png \ res/drawable-hdpi/tab_indicator_selected.9.png \
res/drawable-hdpi/tab_indicator_selected_focused.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_new_tab.png \
res/drawable-xhdpi/ic_menu_reload.png \ res/drawable-xhdpi/ic_menu_reload.png \
res/drawable-xhdpi/ic_status_logo.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_default.9.png \
res/drawable-xhdpi/spinner_focused.9.png \ res/drawable-xhdpi/spinner_focused.9.png \
res/drawable-xhdpi/spinner_pressed.9.png \ res/drawable-xhdpi/spinner_pressed.9.png \

View 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;
}
}
}

View File

@@ -5,14 +5,22 @@
package org.mozilla.gecko.gfx; 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.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import android.text.TextUtils;
import org.mozilla.gecko.R; import org.mozilla.gecko.R;
@@ -27,6 +35,70 @@ public final class BitmapUtils {
private 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) { public static Bitmap decodeByteArray(byte[] bytes) {
return decodeByteArray(bytes, null); return decodeByteArray(bytes, null);
} }

View File

@@ -854,6 +854,21 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
viewportMetricsChanged(true); 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 */ /** Implementation of PanZoomTarget */
@Override @Override
public void panZoomStopped() { public void panZoomStopped() {

View File

@@ -806,7 +806,11 @@ class JavaPanZoomController
if (FloatUtils.fuzzyEquals(displacement.x, 0.0f) && FloatUtils.fuzzyEquals(displacement.y, 0.0f)) { if (FloatUtils.fuzzyEquals(displacement.x, 0.0f) && FloatUtils.fuzzyEquals(displacement.y, 0.0f)) {
return; return;
} }
if (! mSubscroller.scrollBy(displacement)) { if (mSubscroller.scrollBy(displacement)) {
synchronized (mTarget.getLock()) {
mTarget.onSubdocumentScrollBy(displacement.x, displacement.y);
}
} else {
synchronized (mTarget.getLock()) { synchronized (mTarget.getLock()) {
scrollBy(displacement.x, displacement.y); scrollBy(displacement.x, displacement.y);
} }

View File

@@ -17,6 +17,7 @@ public interface PanZoomTarget {
public void setAnimationTarget(ImmutableViewportMetrics viewport); public void setAnimationTarget(ImmutableViewportMetrics viewport);
public void setViewportMetrics(ImmutableViewportMetrics viewport); public void setViewportMetrics(ImmutableViewportMetrics viewport);
public void scrollBy(float dx, float dy); public void scrollBy(float dx, float dy);
public void onSubdocumentScrollBy(float dx, float dy);
public void panZoomStopped(); public void panZoomStopped();
/** This triggers an (asynchronous) viewport update/redraw. */ /** This triggers an (asynchronous) viewport update/redraw. */
public void forceRedraw(DisplayPortMetrics displayPort); public void forceRedraw(DisplayPortMetrics displayPort);

View File

@@ -105,7 +105,7 @@ public class MenuPopup extends PopupWindow {
((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mPopupWidth - anchor.getWidth() + arrowOffset; ((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mPopupWidth - anchor.getWidth() + arrowOffset;
} else { } else {
// right align // right align
((LayoutParams) mArrowTop.getLayoutParams()).rightMargin = mArrowMargin; ((LayoutParams) mArrowTop.getLayoutParams()).rightMargin = screenWidth - anchorLocation[0] - anchor.getWidth()/2 - arrowWidth/2;
((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mArrowMargin; ((LayoutParams) mArrowBottom.getLayoutParams()).rightMargin = mArrowMargin;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

View File

@@ -103,11 +103,12 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
gecko:autoUpdateTheme="false"/> gecko:autoUpdateTheme="false"/>
<ImageButton android:id="@+id/reader" <org.mozilla.gecko.PageActionLayout android:id="@+id/page_action_layout"
style="@style/AddressBar.ImageButton.Icon" android:layout_width="wrap_content"
android:src="@drawable/reader" android:layout_height="match_parent"
android:contentDescription="@string/reader" android:layout_marginRight="@dimen/browser_toolbar_button_padding"
android:visibility="gone"/> android:visibility="gone"
android:orientation="horizontal"/>
<ImageButton android:id="@+id/stop" <ImageButton android:id="@+id/stop"
style="@style/AddressBar.ImageButton.Icon" style="@style/AddressBar.ImageButton.Icon"

View File

@@ -129,11 +129,12 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
gecko:autoUpdateTheme="false"/> gecko:autoUpdateTheme="false"/>
<ImageButton android:id="@+id/reader" <org.mozilla.gecko.PageActionLayout android:id="@+id/page_action_layout"
style="@style/AddressBar.ImageButton.Icon" android:layout_width="wrap_content"
android:src="@drawable/reader" android:layout_height="match_parent"
android:contentDescription="@string/reader" android:layout_marginRight="12dp"
android:visibility="gone"/> android:visibility="gone"
android:orientation="horizontal"/>
<ImageButton android:id="@+id/stop" <ImageButton android:id="@+id/stop"
style="@style/AddressBar.ImageButton.Icon" style="@style/AddressBar.ImageButton.Icon"

View File

@@ -76,4 +76,8 @@
<dimen name="validation_message_margin_top">6dp</dimen> <dimen name="validation_message_margin_top">6dp</dimen>
<dimen name="forward_default_offset">-13dip</dimen> <dimen name="forward_default_offset">-13dip</dimen>
<dimen name="addressbar_offset_left">32dp</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> </resources>

View File

@@ -506,7 +506,7 @@
<item name="android:textAppearance">?android:textAppearanceSmall</item> <item name="android:textAppearance">?android:textAppearanceSmall</item>
<item name="android:paddingTop">0dp</item> <item name="android:paddingTop">0dp</item>
<item name="android:paddingBottom">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:paddingRight">0dp</item>
<item name="android:layout_marginTop">0dp</item> <item name="android:layout_marginTop">0dp</item>
<item name="android:layout_marginBottom">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