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/
#
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;
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("value", state);
menuitem.setAttribute("label", SitePermissions.getStateLabel(state));
menuitem.setAttribute("label", SitePermissions.getStateLabel(aPermission, state));
menupopup.appendChild(menuitem);
}
menulist.appendChild(menupopup);

View File

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

View File

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

View File

@@ -200,8 +200,24 @@ function checkSocialUI(win) {
let active = Social.providers.length > 0 && !win.SocialUI._chromeless &&
!PrivateBrowsingUtils.isWindowPrivate(win);
// some local helpers to avoid log-spew for the many checks made here.
let numGoodTests = 0, numTests = 0;
function _ok(what, msg) {
numTests++;
if (!ok)
ok(what, msg)
else
++numGoodTests;
}
function _is(a, b, msg) {
numTests++;
if (a != b)
is(a, b, msg)
else
++numGoodTests;
}
function isbool(a, b, msg) {
is(!!a, !!b, msg);
_is(!!a, !!b, msg);
}
isbool(win.SocialSidebar.canShow, enabled, "social sidebar active?");
if (enabled)
@@ -216,15 +232,15 @@ function checkSocialUI(win) {
isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?");
if (active) {
if (!enabled) {
ok(!win.SocialToolbar.button.style.listStyleImage, "toolbar button is default icon");
_ok(!win.SocialToolbar.button.style.listStyleImage, "toolbar button is default icon");
} else {
is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
_is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
}
}
// the menus should always have the provider name
if (provider) {
for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"])
is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
_is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
}
// and for good measure, check all the social commands.
@@ -232,10 +248,12 @@ function checkSocialUI(win) {
isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
isbool(!doc.getElementById("Social:FocusChat").hidden, enabled && Social.haveLoggedInUser(), "Social:FocusChat visible?");
isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
_is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
// broadcasters.
isbool(!doc.getElementById("socialActiveBroadcaster").hidden, active, "socialActiveBroadcaster hidden?");
// and report on overall success of failure of the various checks here.
is(numGoodTests, numTests, "The Social UI tests succeeded.")
}
// blocklist testing

View File

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

View File

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

View File

@@ -2750,8 +2750,11 @@ nsDocument::SetDocumentURI(nsIURI* aURI)
nsIURI* newBase = GetDocBaseURI();
bool equalBases = false;
// Changing just the ref of a URI does not change how relative URIs would
// resolve wrt to it, so we can treat the bases as equal as long as they're
// equal ignoring the ref.
if (oldBase && newBase) {
oldBase->Equals(newBase, &equalBases);
oldBase->EqualsExceptRef(newBase, &equalBases);
}
else {
equalBases = !oldBase && !newBase;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,6 +25,29 @@
namespace mozilla {
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebAudioDecodeJob)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutput)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuccessCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFailureCallback)
tmp->mArrayBuffer = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebAudioDecodeJob)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutput)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuccessCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFailureCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArrayBuffer)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebAudioDecodeJob, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release)
using namespace dom;
#ifdef PR_LOGGING
@@ -793,6 +816,7 @@ MediaBufferDecoder::Shutdown() {
WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
AudioContext* aContext,
const ArrayBuffer& aBuffer,
DecodeSuccessCallback* aSuccessCallback,
DecodeErrorCallback* aFailureCallback)
: mContentType(aContentType)
@@ -805,15 +829,21 @@ WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(WebAudioDecodeJob);
mArrayBuffer = aBuffer.Obj();
MOZ_ASSERT(aSuccessCallback ||
(!aSuccessCallback && !aFailureCallback),
"If a success callback is not passed, no failure callback should be passed either");
nsContentUtils::HoldJSObjects(this, NS_CYCLE_COLLECTION_PARTICIPANT(WebAudioDecodeJob));
}
WebAudioDecodeJob::~WebAudioDecodeJob()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_DTOR(WebAudioDecodeJob);
mArrayBuffer = nullptr;
nsContentUtils::DropJSObjects(this);
}
void

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,7 @@ class nsIDOMMozConnection;
namespace mozilla {
namespace dom {
class Geolocation;
class systemMessageCallback;
}
}
@@ -69,6 +70,8 @@ class nsIDOMTelephony;
// Navigator: Script "navigator" object
//*****************************************************************************
void NS_GetNavigatorAppName(nsAString& aAppName);
namespace mozilla {
namespace dom {
@@ -79,6 +82,15 @@ class BatteryManager;
class DesktopNotificationCenter;
class SmsManager;
class MobileMessageManager;
class MozIdleObserver;
#ifdef MOZ_GAMEPAD
class Gamepad;
#endif // MOZ_GAMEPAD
#ifdef MOZ_MEDIA_NAVIGATOR
class MozDOMGetUserMediaSuccessCallback;
class MozDOMGetUserMediaErrorCallback;
class MozGetUserMediaDevicesSuccessCallback;
#endif // MOZ_MEDIA_NAVIGATOR
namespace icc {
#ifdef MOZ_B2G_RIL
@@ -192,7 +204,7 @@ public:
static void Init();
void Invalidate();
nsPIDOMWindow *GetWindow()
nsPIDOMWindow *GetWindow() const
{
return mWindow;
}
@@ -218,8 +230,186 @@ public:
NS_DECL_NSIDOMNAVIGATORCAMERA
// WebIDL API
void GetAppName(nsString& aAppName)
{
NS_GetNavigatorAppName(aAppName);
}
void GetAppVersion(nsString& aAppVersion, ErrorResult& aRv)
{
aRv = GetAppVersion(aAppVersion);
}
void GetPlatform(nsString& aPlatform, ErrorResult& aRv)
{
aRv = GetPlatform(aPlatform);
}
void GetUserAgent(nsString& aUserAgent, ErrorResult& aRv)
{
aRv = GetUserAgent(aUserAgent);
}
// The XPCOM GetProduct is OK
// The XPCOM GetLanguage is OK
bool OnLine();
void RegisterProtocolHandler(const nsAString& aScheme, const nsAString& aURL,
const nsAString& aTitle, ErrorResult& rv)
{
rv = RegisterProtocolHandler(aScheme, aURL, aTitle);
}
void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
const nsAString& aTitle, ErrorResult& rv)
{
rv = RegisterContentHandler(aMIMEType, aURL, aTitle);
}
nsMimeTypeArray* GetMimeTypes(ErrorResult& aRv);
nsPluginArray* GetPlugins(ErrorResult& aRv);
// The XPCOM GetDoNotTrack is ok
Geolocation* GetGeolocation(ErrorResult& aRv);
battery::BatteryManager* GetBattery(ErrorResult& aRv);
void Vibrate(uint32_t aDuration, ErrorResult& aRv);
void Vibrate(const nsTArray<uint32_t>& aDuration, ErrorResult& aRv);
void GetAppCodeName(nsString& aAppCodeName, ErrorResult& aRv)
{
aRv = GetAppCodeName(aAppCodeName);
}
void GetOscpu(nsString& aOscpu, ErrorResult& aRv)
{
aRv = GetOscpu(aOscpu);
}
// The XPCOM GetVendor is OK
// The XPCOM GetVendorSub is OK
// The XPCOM GetProductSub is OK
bool CookieEnabled();
void GetBuildID(nsString& aBuildID, ErrorResult& aRv)
{
aRv = GetBuildID(aBuildID);
}
nsIDOMMozPowerManager* GetMozPower(ErrorResult& aRv);
bool JavaEnabled(ErrorResult& aRv);
bool TaintEnabled()
{
return false;
}
void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
already_AddRefed<nsIDOMMozWakeLock> RequestWakeLock(const nsAString &aTopic,
ErrorResult& aRv);
nsDOMDeviceStorage* GetDeviceStorage(const nsAString& aType,
ErrorResult& aRv);
void GetDeviceStorages(const nsAString& aType,
nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
ErrorResult& aRv);
DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
bool MozIsLocallyAvailable(const nsAString& aURI, bool aWhenOffline,
ErrorResult& aRv)
{
bool available = false;
aRv = MozIsLocallyAvailable(aURI, aWhenOffline, &available);
return available;
}
nsIDOMMozSmsManager* GetMozSms();
nsIDOMMozMobileMessageManager* GetMozMobileMessage();
nsIDOMMozConnection* GetMozConnection();
nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
void MozSetMessageHandler(const nsAString& aType,
systemMessageCallback* aCallback,
ErrorResult& aRv);
bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
#ifdef MOZ_B2G_RIL
nsIDOMTelephony* GetMozTelephony(ErrorResult& aRv);
nsIDOMMozMobileConnection* GetMozMobileConnection(ErrorResult& aRv);
nsIDOMMozCellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
nsIDOMMozVoicemail* GetMozVoicemail(ErrorResult& aRv);
nsIDOMMozIccManager* GetMozIccManager(ErrorResult& aRv);
#endif // MOZ_B2G_RIL
#ifdef MOZ_GAMEPAD
void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
#endif // MOZ_GAMEPAD
#ifdef MOZ_B2G_BT
nsIDOMBluetoothManager* GetMozBluetooth(ErrorResult& aRv);
#endif // MOZ_B2G_BT
#ifdef MOZ_TIME_MANAGER
time::TimeManager* GetMozTime(ErrorResult& aRv);
#endif // MOZ_TIME_MANAGER
#ifdef MOZ_AUDIO_CHANNEL_MANAGER
system::AudioChannelManager* GetMozAudioChannelManager(ErrorResult& aRv);
#endif // MOZ_AUDIO_CHANNEL_MANAGER
#ifdef MOZ_MEDIA_NAVIGATOR
void MozGetUserMedia(nsIMediaStreamOptions* aParams,
MozDOMGetUserMediaSuccessCallback* aOnSuccess,
MozDOMGetUserMediaErrorCallback* aOnError,
ErrorResult& aRv);
void MozGetUserMedia(nsIMediaStreamOptions* aParams,
nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnError,
ErrorResult& aRv);
void MozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback* aOnSuccess,
MozDOMGetUserMediaErrorCallback* aOnError,
ErrorResult& aRv);
void MozGetUserMediaDevices(nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnError,
ErrorResult& aRv);
#endif // MOZ_MEDIA_NAVIGATOR
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
JS::Handle<jsid> aId, JS::MutableHandle<JS::Value> aValue);
// WebIDL helper methods
static bool HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */);
static bool HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal);
static bool HasIdleSupport(JSContext* /* unused */, JSObject* aGlobal);
static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
static bool HasDesktopNotificationSupport(JSContext* /* unused*/,
JSObject* /*unused */)
{
return HasDesktopNotificationSupport();
}
static bool HasSmsSupport(JSContext* /* unused */, JSObject* aGlobal);
static bool HasMobileMessageSupport(JSContext* /* unused */,
JSObject* aGlobal);
static bool HasCameraSupport(JSContext* /* unused */,
JSObject* aGlobal);
#ifdef MOZ_B2G_RIL
static bool HasTelephonySupport(JSContext* /* unused */,
JSObject* aGlobal);
static bool HasMobileConnectionSupport(JSContext* /* unused */,
JSObject* aGlobal);
static bool HasCellBroadcastSupport(JSContext* /* unused */,
JSObject* aGlobal);
static bool HasVoicemailSupport(JSContext* /* unused */,
JSObject* aGlobal);
static bool HasIccManagerSupport(JSContext* /* unused */,
JSObject* aGlobal);
#endif // MOZ_B2G_RIL
#ifdef MOZ_B2G_BT
static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_B2G_BT
#ifdef MOZ_TIME_MANAGER
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
#endif // MOZ_TIME_MANAGER
#ifdef MOZ_MEDIA_NAVIGATOR
static bool HasUserMediaSupport(JSContext* /* unused */,
JSObject* /* unused */);
#endif // MOZ_MEDIA_NAVIGATOR
nsPIDOMWindow* GetParentObject() const
{
return GetWindow();
}
virtual JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
private:
bool CheckPermission(const char* type);
static bool CheckPermission(nsPIDOMWindow* aWindow, const char* aType);
static bool HasMobileMessageSupport(nsPIDOMWindow* aWindow);
// GetWindowFromGlobal returns the inner window for this global, if
// any, else null.
static already_AddRefed<nsPIDOMWindow> GetWindowFromGlobal(JSObject* aGlobal);
// Methods to common up the XPCOM and WebIDL implementations of
// Add/RemoveIdleObserver.
void AddIdleObserver(nsIIdleObserver& aIdleObserver);
void RemoveIdleObserver(nsIIdleObserver& aIdleObserver);
nsRefPtr<nsMimeTypeArray> mMimeTypes;
nsRefPtr<nsPluginArray> mPlugins;
@@ -258,6 +448,5 @@ private:
nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
nsresult NS_GetNavigatorAppVersion(nsAString& aAppVersion);
nsresult NS_GetNavigatorAppName(nsAString& aAppName);
#endif // mozilla_dom_Navigator_h

View File

@@ -129,7 +129,6 @@
#include "nsIXSLTProcessorPrivate.h"
#include "nsXMLHttpRequest.h"
#include "nsIDOMSettingsManager.h"
#include "nsIDOMContactManager.h"
#include "nsIDOMPermissionSettings.h"
#include "nsIDOMApplicationRegistry.h"
@@ -4660,101 +4659,24 @@ nsNavigatorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
{
JS::Rooted<JSObject*> obj(cx, aObj);
JS::Rooted<jsid> id(cx, aId);
if (!JSID_IS_STRING(id)) {
return NS_OK;
}
nsScriptNameSpaceManager *nameSpaceManager =
nsJSRuntime::GetNameSpaceManager();
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
nsDependentJSString name(id);
const nsGlobalNameStruct* name_struct =
nameSpaceManager->LookupNavigatorName(name);
if (!name_struct) {
return NS_OK;
}
if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
mozilla::dom::ConstructNavigatorProperty construct = name_struct->mConstructNavigatorProperty;
MOZ_ASSERT(construct);
JS::Rooted<JSObject*> naviObj(cx, js::CheckedUnwrap(obj, /* stopAtOuter = */ false));
NS_ENSURE_TRUE(naviObj, NS_ERROR_DOM_SECURITY_ERR);
JS::Rooted<JSObject*> domObject(cx);
{
JSAutoCompartment ac(cx, naviObj);
// Check whether our constructor is enabled after we unwrap Xrays, since
// we don't want to define an interface on the Xray if it's disabled in
// the target global, even if it's enabled in the Xray's global.
if (name_struct->mConstructorEnabled &&
!(*name_struct->mConstructorEnabled)(cx, naviObj)) {
return NS_OK;
}
domObject = construct(cx, naviObj);
if (!domObject) {
return NS_ERROR_FAILURE;
}
}
if (!JS_WrapObject(cx, domObject.address()) ||
!JS_DefinePropertyById(cx, obj, id,
JS::ObjectValue(*domObject),
nullptr, nullptr, JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
*_retval = true;
*objp = obj;
return NS_OK;
}
NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
"unexpected type");
nsresult rv = NS_OK;
nsCOMPtr<nsISupports> native(do_CreateInstance(name_struct->mCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JS::Value> prop_val(cx, JS::UndefinedValue()); // Property value.
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
if (gpi) {
nsCOMPtr<nsIDOMNavigator> navigator = do_QueryWrappedNative(wrapper);
nsIDOMWindow *window = static_cast<Navigator*>(navigator.get())->GetWindow();
NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
rv = gpi->Init(window, prop_val.address());
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JS::Value> value(cx, JS::UndefinedValue());
if (!static_cast<Navigator*>(navigator.get())->DoNewResolve(cx, obj, id,
&value)) {
return NS_ERROR_FAILURE;
}
if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, native, true, prop_val.address(),
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
if (!value.isUndefined()) {
if (!JS_DefinePropertyById(cx, obj, id, value, JS_PropertyStub,
JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
if (!JS_WrapValue(cx, prop_val.address())) {
return NS_ERROR_UNEXPECTED;
*objp = obj;
}
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val,
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE);
*_retval = true;
*objp = obj;
return ok ? NS_OK : NS_ERROR_FAILURE;
return NS_OK;
}
// static

View File

@@ -1702,17 +1702,30 @@ addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
addExternalIface('LockedFile')
addExternalIface('MediaList')
addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
addExternalIface('MozBluetoothManager', nativeType='nsIDOMBluetoothManager')
addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
addExternalIface('MozCellBroadcast')
addExternalIface('MozConnection', headerFile='nsIDOMConnection.h')
addExternalIface('MozControllers', nativeType='nsIControllers')
addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
addExternalIface('MozIccManager', headerFile='nsIDOMIccManager.h')
addExternalIface('MozMediaStreamOptions', nativeType='nsIMediaStreamOptions',
headerFile='nsIDOMNavigatorUserMedia.h')
addExternalIface('MozMobileConnection', headerFile='nsIDOMMobileConnection.h')
addExternalIface('MozMobileMessageManager', headerFile='nsIDOMMobileMessageManager.h')
addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
addExternalIface('MozPowerManager', headerFile='nsIDOMPowerManager.h')
addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
notflattened=True)
addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
addExternalIface('MozSmsManager', headerFile='nsIDOMSmsManager.h')
addExternalIface('MozTelephony', nativeType='nsIDOMTelephony')
addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
notflattened=True)
addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
headerFile='nsITreeColumns.h')
addExternalIface('MozVoicemail')
addExternalIface('MozWakeLock', headerFile='nsIDOMWakeLock.h')
addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
addExternalIface('nsIControllers', nativeType='nsIControllers')
addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',

View File

@@ -85,6 +85,9 @@ class CGNativePropertyHooks(CGThing):
if self.descriptor.concrete and self.descriptor.proxy:
resolveOwnProperty = "ResolveOwnProperty"
enumerateOwnProperties = "EnumerateOwnProperties"
elif self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
resolveOwnProperty = "ResolveOwnPropertyViaNewresolve"
enumerateOwnProperties = "nullptr"
else:
resolveOwnProperty = "nullptr"
enumerateOwnProperties = "nullptr"
@@ -3732,7 +3735,7 @@ def convertConstIDLValueToJSVal(value):
return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
if tag in [IDLType.Tags.float, IDLType.Tags.double]:
return "DOUBLE_TO_JSVAL(%s)" % (value.value)
raise TypeError("Const value of unhandled type: " + value.type)
raise TypeError("Const value of unhandled type: %s" % value.type)
class CGArgumentConverter(CGThing):
"""
@@ -5130,8 +5133,9 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
"""
def __init__(self, descriptor, name, args, unwrapFailureCode=None,
getThisObj="args.computeThis(cx).toObjectOrNull()",
callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);"):
CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args)
callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);",
returnType="JSBool"):
CGAbstractStaticMethod.__init__(self, descriptor, name, returnType, args)
if unwrapFailureCode is None:
self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");' % descriptor.interface.identifier.name
@@ -5145,13 +5149,14 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
# we're someone's consequential interface. But for this-unwrapping, we
# know that we're the real deal. So fake a descriptor here for
# consumption by CastableObjectUnwrapper.
getThis = CGGeneric("""%s
JS::RootedObject obj(cx, %s);
if (!obj) {
return false;
}
%s* self;""" % (self.callArgs, self.getThisObj, self.descriptor.nativeType))
getThis = CGList([
CGGeneric(self.callArgs) if self.callArgs != "" else None,
CGGeneric("JS::RootedObject obj(cx, %s);\n"
"if (!obj) {\n"
" return false;\n"
"}" % self.getThisObj) if self.getThisObj else None,
CGGeneric("%s* self;" % self.descriptor.nativeType)
], "\n")
unwrapThis = CGGeneric(
str(CastableObjectUnwrapper(
self.descriptor,
@@ -5265,13 +5270,13 @@ class CGNewResolveHook(CGAbstractBindingMethod):
"""
def __init__(self, descriptor):
self._needNewResolve = descriptor.interface.getExtendedAttribute("NeedNewResolve")
args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'obj_'),
args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'obj'),
Argument('JS::Handle<jsid>', 'id'), Argument('unsigned', 'flags'),
Argument('JS::MutableHandle<JSObject*>', 'objp')]
# Our "self" is actually the callee in this case, not the thisval.
CGAbstractBindingMethod.__init__(
self, descriptor, NEWRESOLVE_HOOK_NAME,
args, getThisObj="obj_", callArgs="")
args, getThisObj="", callArgs="")
def define(self):
if not self._needNewResolve:
@@ -5279,7 +5284,19 @@ class CGNewResolveHook(CGAbstractBindingMethod):
return CGAbstractBindingMethod.define(self)
def generate_code(self):
return CGIndenter(CGGeneric("return self->DoNewResolve(cx, obj, id, flags, objp);"))
return CGIndenter(CGGeneric(
"JS::Rooted<JS::Value> value(cx);\n"
"if (!self->DoNewResolve(cx, obj, id, &value)) {\n"
" return false;\n"
"}\n"
"if (value.isUndefined()) {\n"
" return true;\n"
"}\n"
"if (!JS_DefinePropertyById(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE)) {\n"
" return false;\n"
"}\n"
"objp.set(obj);\n"
"return true;"))
class CppKeywords():
"""
@@ -6629,7 +6646,7 @@ class CGClass(CGThing):
result = result + memberString
return result
class CGResolveOwnProperty(CGAbstractMethod):
class CGResolveOwnProperty(CGAbstractStaticMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'wrapper'),
@@ -6637,18 +6654,47 @@ class CGResolveOwnProperty(CGAbstractMethod):
Argument('JS::Handle<jsid>', 'id'),
Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
]
CGAbstractMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args)
CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
"bool", args)
def definition_body(self):
return """ return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc, flags);
"""
class CGEnumerateOwnProperties(CGAbstractMethod):
class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod):
"""
An implementation of Xray ResolveOwnProperty stuff for things that have a
newresolve hook.
"""
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'wrapper'),
Argument('JS::Handle<JSObject*>', 'obj'),
Argument('JS::Handle<jsid>', 'id'),
Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
]
CGAbstractBindingMethod.__init__(self, descriptor,
"ResolveOwnPropertyViaNewresolve",
args, getThisObj="",
callArgs="", returnType="bool")
def generate_code(self):
return CGIndenter(CGGeneric(
"JS::Rooted<JS::Value> value(cx);\n"
"if (!self->DoNewResolve(cx, obj, id, &value)) {\n"
" return false;\n"
"}\n"
"if (!value.isUndefined()) {\n"
" FillPropertyDescriptor(desc, wrapper, value, /* readonly = */ false);\n"
"}\n"
"return true;"))
class CGEnumerateOwnProperties(CGAbstractStaticMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'wrapper'),
Argument('JS::Handle<JSObject*>', 'obj'),
Argument('JS::AutoIdVector&', 'props')]
CGAbstractMethod.__init__(self, descriptor, "EnumerateOwnProperties", "bool", args)
CGAbstractStaticMethod.__init__(self, descriptor,
"EnumerateOwnProperties", "bool", args)
def definition_body(self):
return """ return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
"""
@@ -7606,6 +7652,16 @@ class CGDescriptor(CGThing):
cgThings.append(CGGeneric(define=str(properties)))
cgThings.append(CGNativeProperties(descriptor, properties))
# Set up our Xray callbacks as needed. Note that we don't need to do
# it in workers.
if not descriptor.workers and descriptor.concrete and descriptor.proxy:
cgThings.append(CGResolveOwnProperty(descriptor))
cgThings.append(CGEnumerateOwnProperties(descriptor))
elif descriptor.interface.getExtendedAttribute("NeedNewResolve"):
cgThings.append(CGResolveOwnPropertyViaNewresolve(descriptor))
# Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
# done, set up our NativePropertyHooks.
cgThings.append(CGNativePropertyHooks(descriptor, properties))
if descriptor.interface.hasInterfaceObject():
@@ -7629,12 +7685,6 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasInterfaceObject():
cgThings.append(CGGetConstructorObjectMethod(descriptor))
# Set up our Xray callbacks as needed. Note that we don't need to do
# it in workers.
if not descriptor.workers and descriptor.concrete and descriptor.proxy:
cgThings.append(CGResolveOwnProperty(descriptor))
cgThings.append(CGEnumerateOwnProperties(descriptor))
if descriptor.interface.hasInterfaceObject():
cgThings.append(CGDefineDOMInterfaceMethod(descriptor))

View File

@@ -22,7 +22,7 @@ include $(topsrcdir)/dom/dom-config.mk
include $(topsrcdir)/dom/webidl/WebIDL.mk
binding_include_path := mozilla/dom
all_webidl_files = $(webidl_files) $(generated_webidl_files)
all_webidl_files = $(webidl_files) $(generated_webidl_files) $(preprocessed_webidl_files)
# Set exported_binding_headers before adding the test IDL to the mix
exported_binding_headers := $(subst .webidl,Binding.h,$(all_webidl_files))
# Set linked_binding_cpp_files before adding the test IDL to the mix
@@ -142,6 +142,23 @@ $(webidl_files): %: $(webidl_base)/%
$(test_webidl_files): %: $(srcdir)/test/%
$(INSTALL) $(IFLAGS1) $(srcdir)/test/$* .
# We can't easily use PP_TARGETS here because it insists on outputting targets
# that look like "$(CURDIR)/foo" whereas we want our target to just be "foo".
# Make sure to include $(GLOBAL_DEPS) so we pick up changes to what symbols are
# defined. Also make sure to remove $@ before writing to it, because otherwise
# if a file goes from non-preprocessed to preprocessed we can end up writing to
# a symlink, which will clobber files in the srcdir, which is bad.
$(preprocessed_webidl_files): %: $(webidl_base)/% $(GLOBAL_DEPS)
$(RM) $@
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
$(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(webidl_base)/$* -o $@
# Make is dumb and can get confused between "foo" and "$(CURDIR)/foo". Make
# sure that the latter depends on the former, since the latter gets used in .pp
# files.
all_webidl_files_absolute = $(addprefix $(CURDIR)/,$(all_webidl_files))
$(all_webidl_files_absolute): $(CURDIR)/%: %
$(binding_header_files): .BindingGen
$(binding_cpp_files): .BindingGen

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,13 +6,28 @@ MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document);
SpecialPowers.addPermission("settings-write", true, document);
let icc = navigator.mozIccManager;
ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor);
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let icc;
ifr.onload = function() {
icc = ifr.contentWindow.navigator.mozIccManager;
ok(icc instanceof ifr.contentWindow.MozIccManager,
"icc is instanceof " + icc.constructor);
is(icc.cardState, "ready");
// Enable Airplane mode, expect got cardstatechange to null
testCardStateChange(true, null,
// Disable Airplane mode, expect got cardstatechange to 'ready'
testCardStateChange.bind(window, false, "ready", cleanUp)
);
};
document.body.appendChild(ifr);
function setAirplaneModeEnabled(enabled) {
let settings = window.navigator.mozSettings;
let settings = ifr.contentWindow.navigator.mozSettings;
let setLock = settings.createLock();
let obj = {
"ril.radio.disabled": enabled
@@ -53,9 +68,3 @@ function cleanUp() {
finish();
}
// Enable Airplane mode, expect got cardstatechange to null
testCardStateChange(true, null,
// Disable Airplane mode, expect got cardstatechange to 'ready'
testCardStateChange.bind(this, false, "ready", cleanUp)
);

View File

@@ -5,10 +5,43 @@ MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document);
let icc = navigator.mozIccManager;
ok(icc instanceof MozIccManager,
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let icc;
let iccInfo;
ifr.onload = function() {
icc = ifr.contentWindow.navigator.mozIccManager;
ok(icc instanceof ifr.contentWindow.MozIccManager,
"icc is instanceof " + icc.constructor);
iccInfo = icc.iccInfo;
// The emulator's hard coded iccid value.
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
is(iccInfo.iccid, 89014103211118510720);
// The emulator's hard coded mcc and mnc codes.
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
is(iccInfo.mcc, 310);
is(iccInfo.mnc, 260);
is(iccInfo.spn, "Android");
// Phone number is hardcoded in MSISDN
// See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io()
is(iccInfo.msisdn, "15555215554");
testDisplayConditionChange(testSPN, [
// [MCC, MNC, isDisplayNetworkNameRequired, isDisplaySpnRequired]
[123, 456, false, true], // Not in HPLMN.
[234, 136, true, true], // Not in HPLMN, but in PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[466, 92, true, true], // Not in HPLMN, but in another PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[310, 260, true, true], // inside HPLMN.
], finalize);
};
document.body.appendChild(ifr);
let emulatorCmdPendingCount = 0;
function sendEmulatorCommand(cmd, callback) {
emulatorCmdPendingCount++;
@@ -39,21 +72,6 @@ function finalize() {
finish();
}
let iccInfo = icc.iccInfo;
// The emulator's hard coded iccid value.
// See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299.
is(iccInfo.iccid, 89014103211118510720);
// The emulator's hard coded mcc and mnc codes.
// See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465.
is(iccInfo.mcc, 310);
is(iccInfo.mnc, 260);
is(iccInfo.spn, "Android");
// Phone number is hardcoded in MSISDN
// See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io()
is(iccInfo.msisdn, "15555215554");
// Test display condition change.
function testDisplayConditionChange(func, caseArray, oncomplete) {
(function do_call(index) {
@@ -75,13 +93,3 @@ function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired,
});
setEmulatorMccMnc(mcc, mnc);
}
testDisplayConditionChange(testSPN, [
// [MCC, MNC, isDisplayNetworkNameRequired, isDisplaySpnRequired]
[123, 456, false, true], // Not in HPLMN.
[234, 136, true, true], // Not in HPLMN, but in PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[466, 92, true, true], // Not in HPLMN, but in another PLMN specified in SPDI.
[123, 456, false, true], // Not in HPLMN. Triggering iccinfochange
[310, 260, true, true], // inside HPLMN.
], finalize);

View File

@@ -6,7 +6,6 @@
XPIDL_SOURCES += [
'nsIDOMMozSettingsEvent.idl',
'nsIDOMSettingsManager.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"]);
/* Applications Specific Helper */
Cc["@mozilla.org/settingsManager;1"].getService(Ci["nsIDOMSettingsManager"]);
try {
// May throw if we don't have the settings permission
navigator.mozSettings;
} catch(e) {
}
try {
if (Services.prefs.getBoolPref("dom.sysmsg.enabled")) {
Cc["@mozilla.org/system-message-manager;1"].getService(Ci["nsIDOMNavigatorSystemMessages"]);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,10 +5,20 @@ MARIONETTE_TIMEOUT = 60000;
SpecialPowers.addPermission("mobileconnection", true, document);
let connection = navigator.mozMobileConnection;
ok(connection instanceof MozMobileConnection,
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let connection;
ifr.onload = function() {
connection = ifr.contentWindow.navigator.mozMobileConnection;
ok(connection instanceof ifr.contentWindow.MozMobileConnection,
"connection is instanceof " + connection.constructor);
testGetCallBarringOption();
};
document.body.appendChild(ifr);
function testGetCallBarringOption() {
let option = {'program': 0, 'password': '', 'serviceClass': 0};
let request = connection.getCallBarringOption(option);
@@ -27,5 +37,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
}
testGetCallBarringOption();

View File

@@ -5,10 +5,20 @@ MARIONETTE_TIMEOUT = 60000;
SpecialPowers.addPermission("mobileconnection", true, document);
let connection = navigator.mozMobileConnection;
ok(connection instanceof MozMobileConnection,
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let connection;
ifr.onload = function() {
connection = ifr.contentWindow.navigator.mozMobileConnection;
ok(connection instanceof ifr.contentWindow.MozMobileConnection,
"connection is instanceof " + connection.constructor);
nextTest();
};
document.body.appendChild(ifr);
let caseId = 0;
let options = [
buildOption(5, true, '0000', 0), // invalid program.
@@ -61,5 +71,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
}
nextTest();

View File

@@ -5,7 +5,18 @@ MARIONETTE_TIMEOUT = 20000;
SpecialPowers.addPermission("mobileconnection", true, document);
let mobileConnection = navigator.mozMobileConnection;
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let mobileConnection;
ifr.onload = function() {
mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
// Start the test
verifyInitialState();
};
document.body.appendChild(ifr);
let emulatorStartLac = 0;
let emulatorStartCid = 0;
@@ -114,6 +125,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
}
// Start the test
verifyInitialState();

View File

@@ -5,7 +5,17 @@ MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("mobileconnection", true, document);
let mobileConnection = navigator.mozMobileConnection;
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let mobileConnection;
ifr.onload = function() {
mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
// Start the test
verifyInitialState();
};
document.body.appendChild(ifr);
function verifyInitialState() {
log("Verifying initial state.");
@@ -116,6 +126,3 @@ function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
}
// Start the test
verifyInitialState();

View File

@@ -5,7 +5,16 @@ MARIONETTE_TIMEOUT = 20000;
SpecialPowers.addPermission("mobileconnection", true, document);
let mobileConnection = navigator.mozMobileConnection;
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let mobileConnection;
ifr.onload = function() {
mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
tasks.run();
};
document.body.appendChild(ifr);
let tasks = {
// List of test functions. Each of them should call |tasks.next()| when
@@ -43,7 +52,7 @@ let tasks = {
tasks.push(function verifyInitialState() {
log("Verifying initial state.");
ok(mobileConnection instanceof MozMobileConnection,
ok(mobileConnection instanceof ifr.contentWindow.MozMobileConnection,
"mobileConnection is instanceof " + mobileConnection.constructor);
tasks.next();
@@ -77,5 +86,3 @@ tasks.push(function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
});
tasks.run();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,5 @@
component {c40b1c70-00fb-11e2-a21f-0800200c9a66} SettingsManager.js
contract @mozilla.org/settingsManager;1 {c40b1c70-00fb-11e2-a21f-0800200c9a66}
category JavaScript-navigator-property mozSettings @mozilla.org/settingsManager;1
component {60c9357c-3ae0-4222-8f55-da01428470d5} SettingsManager.js
contract @mozilla.org/settingsLock;1 {60c9357c-3ae0-4222-8f55-da01428470d5}

View File

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

View File

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

View File

@@ -8,6 +8,9 @@
#define mozilla_dom_telephony_telephony_h__
#include "TelephonyCommon.h"
// Need to include TelephonyCall.h because we have inline methods that
// assume they see the definition of TelephonyCall.
#include "TelephonyCall.h"
#include "nsIDOMTelephony.h"
#include "nsIDOMTelephonyCall.h"
@@ -56,7 +59,9 @@ public:
nsDOMEventTargetHelper)
static already_AddRefed<Telephony>
Create(nsPIDOMWindow* aOwner, nsITelephonyProvider* aProvider);
Create(nsPIDOMWindow* aOwner, ErrorResult& aRv);
static bool CheckPermission(nsPIDOMWindow* aOwner);
nsISupports*
ToISupports()

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("settings-write", true, document);
let settings = window.navigator.mozSettings;
let telephony = window.navigator.mozTelephony;
// Permission changes can't change existing Navigator.prototype
// objects, so grab our objects from a new Navigator
let ifr = document.createElement("iframe");
let settings;
let telephony;
let number = "112";
let outgoing;
ifr.onload = function() {
settings = ifr.contentWindow.navigator.mozSettings;
telephony = ifr.contentWindow.navigator.mozTelephony;
getExistingCalls();
};
document.body.appendChild(ifr);
function getExistingCalls() {
runEmulatorCmd("gsm list", function(result) {
@@ -155,5 +164,3 @@ function cleanUp() {
SpecialPowers.removePermission("settings-write", document);
finish();
}
getExistingCalls();

View File

@@ -17,23 +17,28 @@ var idleObserver = {
onactive: null
};
function doAddIdleObserver(obs) {
var i = document.createElement("iframe");
document.body.appendChild(i);
var added = false;
try {
i.contentWindow.navigator.addIdleObserver(obs);
added = true;
} catch (e) { }
i.remove();
return added;
}
function run_test() {
// addIdleObserver checks whether time is > 0.
this.idleObserver.time = 100;
var added = false;
try {
navigator.addIdleObserver(this.idleObserver);
added = true;
} catch (e) { }
var added = doAddIdleObserver(this.idleObserver, false);
ok(!added, "Should not be able to add idle observer without permission");
SpecialPowers.addPermission("idle", true, document);
added = false;
try {
navigator.addIdleObserver(this.idleObserver);
added = true;
} catch (e) { }
added = doAddIdleObserver(this.idleObserver, true);
ok(added, "Should be able to add idle observer with permission.");
SimpleTest.finish();

View File

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

353
dom/webidl/Navigator.webidl Normal file
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 \
$(NULL)
preprocessed_webidl_files = \
Navigator.webidl \
$(NULL)
webidl_files = \
AnalyserNode.webidl \
AnimationEvent.webidl \
@@ -227,6 +231,7 @@ webidl_files = \
Screen.webidl \
ScriptProcessorNode.webidl \
ScrollAreaEvent.webidl \
SettingsManager.webidl \
SimpleGestureEvent.webidl \
SourceBuffer.webidl \
SourceBufferList.webidl \

View File

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

View File

@@ -35,7 +35,8 @@ Tests of DOM Worker Navigator
return;
}
is(navigator[args.name], args.value, "Mismatched navigator string!");
is(navigator[args.name], args.value,
"Mismatched navigator string for " + args.name + "!");
};
worker.onerror = function(event) {

View File

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

View File

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

View File

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

View File

@@ -19,8 +19,12 @@
#include "SkTSearch.h"
#ifndef SK_FONT_FILE_PREFIX
#ifdef SK_BUILD_FOR_ANDROID
#define SK_FONT_FILE_PREFIX "/fonts/"
#else
#define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/"
#endif
#endif
#ifndef SK_FONT_FILE_DIR_SEPERATOR
#define SK_FONT_FILE_DIR_SEPERATOR "/"
#endif
@@ -419,7 +423,13 @@ static void load_system_fonts() {
return;
}
SkString baseDirectory(SK_FONT_FILE_PREFIX);
SkString baseDirectory;
#ifdef SK_BUILD_FOR_ANDROID
baseDirectory.set(getenv("ANDROID_ROOT"));
#endif
baseDirectory.append(SK_FONT_FILE_PREFIX);
unsigned int count = 0;
load_directory_fonts(baseDirectory, &count);

View File

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

View File

@@ -384,7 +384,8 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
MOZ_ASSUME_UNREACHABLE("module nodes cannot be cloned");
}
NULLCHECK(pn->pn_funbox =
newFunctionBox(opn->pn_funbox->function(), pc, opn->pn_funbox->strict));
newFunctionBox(opn->pn_funbox->function(), pc,
Directives(/* strict = */ opn->pn_funbox->strict)));
NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body));
pn->pn_cookie = opn->pn_cookie;
pn->pn_dflags = opn->pn_dflags;

View File

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

View File

@@ -214,6 +214,13 @@ struct ParseContext : public GenericParseContext
// All inner functions in this context. Only filled in when parsing syntax.
AutoFunctionVector innerFunctions;
// In a function context, points to a Directive struct that can be updated
// to reflect new directives encountered in the Directive Prologue that
// require reparsing the function. In global/module/generator-tail contexts,
// we don't need to reparse when encountering a DirectivePrologue so this
// pointer may be NULL.
Directives *newDirectives;
// Set when parsing a declaration-like destructuring pattern. This flag
// causes PrimaryExpr to create PN_NAME parse nodes for variable references
// which are not hooked into any definition's use chain, added to any tree
@@ -225,12 +232,9 @@ struct ParseContext : public GenericParseContext
// they need to be treated differently.
bool inDeclDestructuring:1;
// True if we are in a function, saw a "use strict" directive, and weren't
// strict before.
bool funBecameStrict:1;
ParseContext(Parser<ParseHandler> *prs, GenericParseContext *parent,
SharedContext *sc, unsigned staticLevel, uint32_t bodyid)
SharedContext *sc, Directives *newDirectives,
unsigned staticLevel, uint32_t bodyid)
: GenericParseContext(parent, sc),
bodyid(0), // initialized in init()
blockidGen(bodyid), // used to set |bodyid| and subsequently incremented in init()
@@ -250,8 +254,8 @@ struct ParseContext : public GenericParseContext
lexdeps(prs->context),
funcStmts(NULL),
innerFunctions(prs->context),
inDeclDestructuring(false),
funBecameStrict(false)
newDirectives(newDirectives),
inDeclDestructuring(false)
{
prs->pc = this;
}
@@ -288,6 +292,12 @@ struct ParseContext : public GenericParseContext
}
};
template <typename ParseHandler>
inline
Directives::Directives(ParseContext<ParseHandler> *parent)
: strict_(parent->sc->strict)
{}
template <typename ParseHandler>
struct BindData;
@@ -369,7 +379,8 @@ class Parser : private AutoGCRooter, public StrictModeGetter
*/
ObjectBox *newObjectBox(JSObject *obj);
ModuleBox *newModuleBox(Module *module, ParseContext<ParseHandler> *pc);
FunctionBox *newFunctionBox(JSFunction *fun, ParseContext<ParseHandler> *pc, bool strict);
FunctionBox *newFunctionBox(JSFunction *fun, ParseContext<ParseHandler> *pc,
Directives directives);
/*
* Create a new function object given parse context (pc) and a name (which
@@ -402,7 +413,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
// Parse a function, given only its body. Used for the Function constructor.
Node standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
bool strict, bool *becameStrict);
Directives inheritedDirectives, Directives *newDirectives);
// Parse a function, given only its arguments and body. Used for lazily
// parsed functions.
@@ -416,7 +427,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
Node functionBody(FunctionSyntaxKind kind, FunctionBodyType type);
bool functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
FunctionSyntaxKind kind, bool *becameStrict);
FunctionSyntaxKind kind, Directives *newDirectives);
virtual bool strictMode() { return pc->sc->strict; }
@@ -487,7 +498,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
FunctionType type, FunctionSyntaxKind kind);
bool functionArgsAndBody(Node pn, HandleFunction fun,
FunctionType type, FunctionSyntaxKind kind,
bool strict, bool *becameStrict = NULL);
Directives inheritedDirectives, Directives *newDirectives);
Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin);

View File

@@ -140,6 +140,30 @@ class FunctionContextFlags
class GlobalSharedContext;
// List of directives that may be encountered in a Directive Prologue (ES5 15.1).
class Directives
{
bool strict_;
public:
explicit Directives(bool strict) : strict_(strict) {}
template <typename ParseHandler> explicit Directives(ParseContext<ParseHandler> *parent);
void setStrict() { strict_ = true; }
bool strict() const { return strict_; }
Directives &operator=(Directives rhs) {
strict_ = rhs.strict_;
return *this;
}
bool operator==(const Directives &rhs) const {
return strict_ == rhs.strict_;
}
bool operator!=(const Directives &rhs) const {
return strict_ != rhs.strict_;
}
};
/*
* The struct SharedContext is part of the current parser context (see
* ParseContext). It stores information that is reused between the parser and
@@ -156,10 +180,10 @@ class SharedContext
// If it's function code, funbox must be non-NULL and scopeChain must be NULL.
// If it's global code, funbox must be NULL.
SharedContext(ExclusiveContext *cx, bool strict, bool extraWarnings)
SharedContext(ExclusiveContext *cx, Directives directives, bool extraWarnings)
: context(cx),
anyCxFlags(),
strict(strict),
strict(directives.strict()),
extraWarnings(extraWarnings)
{}
@@ -192,8 +216,8 @@ class GlobalSharedContext : public SharedContext
public:
GlobalSharedContext(ExclusiveContext *cx, JSObject *scopeChain,
bool strict, bool extraWarnings)
: SharedContext(cx, strict, extraWarnings),
Directives directives, bool extraWarnings)
: SharedContext(cx, directives, extraWarnings),
scopeChain_(cx, scopeChain)
{}
@@ -249,8 +273,8 @@ class FunctionBox : public ObjectBox, public SharedContext
template <typename ParseHandler>
FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
ParseContext<ParseHandler> *pc,
bool strict, bool extraWarnings);
ParseContext<ParseHandler> *pc, Directives directives,
bool extraWarnings);
ObjectBox *toObjectBox() { return this; }
JSFunction *function() const { return &object->as<JSFunction>(); }

View File

@@ -966,7 +966,14 @@ TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
uint32_t i;
if (js_IdIsIndex(id, &i))
return;
MarkTypeObjectUnknownProperties(cx, obj->type());
// But if we don't have too many properties yet, don't do anything. The
// idea here is that normal object initialization should not trigger
// deoptimization in most cases, while actual usage as a hashmap should.
TypeObject* type = obj->type();
if (type->getPropertyCount() < 8)
return;
MarkTypeObjectUnknownProperties(cx, type);
}
}

View File

@@ -221,13 +221,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=668855
let dummy_test_map = new WeakMap;
let navi_fail = false;
let rule_fail = false;
let got_rule = false;
try {
dummy_test_map.set(window.navigator, 1);
var rule = document.styleSheets[0].cssRules[0];
got_rule = true;
dummy_test_map.set(rule, 1);
} catch (e) {
navi_fail = true;
rule_fail = true;
}
ok(navi_fail, "Using window.navigator as a weak map key should produce an exception because it can't be wrapper preserved.");
ok(got_rule, "Got the CSS rule");
ok(rule_fail, "Using a CSS rule as a weak map key should produce an exception because it can't be wrapper preserved.");
}

View File

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

View File

@@ -16,13 +16,13 @@ function setup() {
my_map.set(item, "success_string");
var navi_fail = false;
var rule_fail = false;
try {
my_map.set(window.frames[0].navigator, 1);
my_map.set(window.frames[0].document.styleSheets[0].cssRules[0], 1);
} catch (e) {
navi_fail = true;
rule_fail = true;
}
ok(navi_fail, "Using window.navigator as a weak map key across compartments should produce an exception because it can't be wrapper preserved.");
ok(rule_fail, "Using rule as a weak map key across compartments should produce an exception because it can't be wrapper preserved.");
}
function runTest() {

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -533,6 +533,15 @@ public:
nscoord aContainingBlockHeight,
nsMargin& aComputedOffsets);
// If a relatively positioned element, adjust the position appropriately.
static void ApplyRelativePositioning(const nsStyleDisplay* aDisplay,
const nsMargin& aComputedOffsets,
nsPoint* aPosition);
void ApplyRelativePositioning(nsPoint* aPosition) const {
ApplyRelativePositioning(mStyleDisplay, mComputedOffsets, aPosition);
}
#ifdef DEBUG
// Reflow trace methods. Defined in nsFrame.cpp so they have access
// to the display-reflow infrastructure.

View File

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

View File

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

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 ButtonToast mToast;
private PropertyAnimator mMainLayoutAnimator;
private static final Interpolator sTabsInterpolator = new Interpolator() {
@@ -395,15 +394,6 @@ abstract public class BrowserApp extends GeckoApp
mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browser_toolbar);
mToast = new ButtonToast(findViewById(R.id.toast), new ButtonToast.ToastListener() {
@Override
public void onButtonClicked(CharSequence token) {
if (ADD_SHORTCUT_TOAST.equals(token)) {
showBookmarkDialog();
}
}
});
((GeckoApp.MainLayout) mMainLayout).setTouchEventInterceptor(new HideTabsTouchListener());
((GeckoApp.MainLayout) mMainLayout).setMotionEventInterceptor(new MotionEventInterceptor() {
@Override
@@ -815,7 +805,7 @@ abstract public class BrowserApp extends GeckoApp
// If the page has shrunk so that the toolbar no longer scrolls, make
// sure the toolbar is visible.
if (aMetrics.getPageHeight() < aMetrics.getHeight()) {
if (aMetrics.getPageHeight() <= aMetrics.getHeight()) {
if (mDynamicToolbarCanScroll) {
mDynamicToolbarCanScroll = false;
if (!mBrowserToolbar.isVisible()) {
@@ -1449,34 +1439,20 @@ abstract public class BrowserApp extends GeckoApp
});
if (info.icon != null) {
if (info.icon.startsWith("data")) {
BitmapDrawable drawable = new BitmapDrawable(BitmapUtils.getBitmapFromDataURI(info.icon));
item.setIcon(drawable);
}
else if (info.icon.startsWith("jar:") || info.icon.startsWith("file://")) {
ThreadUtils.postToBackgroundThread(new Runnable() {
BitmapUtils.getDrawable(this, info.icon, new BitmapUtils.BitmapLoader() {
@Override
public void run() {
try {
URL url = new URL(info.icon);
InputStream is = (InputStream) url.getContent();
try {
Drawable drawable = Drawable.createFromStream(is, "src");
item.setIcon(drawable);
} finally {
is.close();
}
} catch (Exception e) {
Log.w(LOGTAG, "Unable to set icon", e);
public void onBitmapFound(Drawable d) {
if (d == null) {
item.setIcon(R.drawable.ic_menu_addons_filler);
return;
}
item.setIcon(d);
}
});
} else {
item.setIcon(R.drawable.ic_menu_addons_filler);
}
} else {
item.setIcon(R.drawable.ic_menu_addons_filler);
}
item.setCheckable(info.checkable);
item.setChecked(info.checked);
@@ -1701,8 +1677,16 @@ abstract public class BrowserApp extends GeckoApp
mToast.show(false,
getResources().getString(R.string.bookmark_added),
getResources().getString(R.string.bookmark_options),
0,
ADD_SHORTCUT_TOAST);
null,
new ButtonToast.ToastListener() {
@Override
public void onButtonClicked() {
showBookmarkDialog();
}
@Override
public void onToastHidden(ButtonToast.ReasonHidden reason) { }
});
item.setIcon(R.drawable.ic_menu_bookmark_remove);
}
}

View File

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

View File

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

View File

@@ -129,6 +129,7 @@ FENNEC_JAVA_FILES = \
NotificationService.java \
NSSBridge.java \
OrderedBroadcastHelper.java \
PageActionLayout.java \
PrefsHelper.java \
PrivateDataPreference.java \
PrivateTab.java \
@@ -641,6 +642,7 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/ic_menu_new_tab.png \
res/drawable-mdpi/ic_menu_reload.png \
res/drawable-mdpi/ic_status_logo.png \
res/drawable-mdpi/icon_pageaction.png \
res/drawable-mdpi/progress_spinner_1.png \
res/drawable-mdpi/progress_spinner_2.png \
res/drawable-mdpi/progress_spinner_3.png \
@@ -763,6 +765,7 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/ic_menu_new_tab.png \
res/drawable-hdpi/ic_menu_reload.png \
res/drawable-hdpi/ic_status_logo.png \
res/drawable-hdpi/icon_pageaction.png \
res/drawable-hdpi/tab_indicator_divider.9.png \
res/drawable-hdpi/tab_indicator_selected.9.png \
res/drawable-hdpi/tab_indicator_selected_focused.9.png \
@@ -861,6 +864,7 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/ic_menu_new_tab.png \
res/drawable-xhdpi/ic_menu_reload.png \
res/drawable-xhdpi/ic_status_logo.png \
res/drawable-xhdpi/icon_pageaction.png \
res/drawable-xhdpi/spinner_default.9.png \
res/drawable-xhdpi/spinner_focused.9.png \
res/drawable-xhdpi/spinner_pressed.9.png \

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;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.GeckoJarReader;
import org.mozilla.gecko.util.UiAsyncTask;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Base64;
import android.util.Log;
import android.text.TextUtils;
import org.mozilla.gecko.R;
@@ -27,6 +35,70 @@ public final class BitmapUtils {
private BitmapUtils() {}
public interface BitmapLoader {
public void onBitmapFound(Drawable d);
}
/* Given a string url, returns a drawable for the bitmap. Should work with data, file, jar,
* or chrome (converted to jar:jar) urls. Results are sent to the passed in BitmapLoader object.
* Can return null if a Drawable couldn't be created.
* Results are always posted on the UI thread.
* TODO: Support for http(s) and drawable urls.
*/
public static void getDrawable(final Context context, final String data, final BitmapLoader loader) {
if (TextUtils.isEmpty(data)) {
postResultToUiThread(null, loader);
return;
}
if (data.startsWith("data")) {
BitmapDrawable d = new BitmapDrawable(getBitmapFromDataURI(data));
postResultToUiThread(d, loader);
return;
}
if (!data.startsWith("jar:") && !data.startsWith("file://")) {
postResultToUiThread(null, loader);
return;
}
(new UiAsyncTask<Void, Void, Drawable>(ThreadUtils.getBackgroundHandler()) {
@Override
public Drawable doInBackground(Void... params) {
try {
if (data.startsWith("jar:jar")) {
return GeckoJarReader.getBitmapDrawable(context.getResources(), data);
}
URL url = new URL(data);
InputStream is = (InputStream) url.getContent();
try {
return Drawable.createFromStream(is, "src");
} finally {
is.close();
}
} catch (Exception e) {
Log.w(LOGTAG, "Unable to set icon", e);
}
return null;
}
@Override
public void onPostExecute(Drawable drawable) {
postResultToUiThread(drawable, loader);
}
}).execute();
}
private static void postResultToUiThread(final Drawable d, final BitmapLoader loader) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
loader.onBitmapFound(d);
}
});
}
public static Bitmap decodeByteArray(byte[] bytes) {
return decodeByteArray(bytes, null);
}

View File

@@ -854,6 +854,21 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
viewportMetricsChanged(true);
}
/** Implementation of PanZoomTarget
* Notification that a subdocument has been scrolled by a certain amount.
* This is used here to make sure that the margins are still accessible
* during subdocument scrolling.
*
* You must hold the monitor while calling this.
*/
@Override
public void onSubdocumentScrollBy(float dx, float dy) {
ImmutableViewportMetrics newMarginsMetrics =
mMarginsAnimator.scrollBy(mViewportMetrics, dx, dy);
mViewportMetrics = mViewportMetrics.setMarginsFrom(newMarginsMetrics);
viewportMetricsChanged(true);
}
/** Implementation of PanZoomTarget */
@Override
public void panZoomStopped() {

View File

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

View File

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

View File

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

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"
gecko:autoUpdateTheme="false"/>
<ImageButton android:id="@+id/reader"
style="@style/AddressBar.ImageButton.Icon"
android:src="@drawable/reader"
android:contentDescription="@string/reader"
android:visibility="gone"/>
<org.mozilla.gecko.PageActionLayout android:id="@+id/page_action_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="@dimen/browser_toolbar_button_padding"
android:visibility="gone"
android:orientation="horizontal"/>
<ImageButton android:id="@+id/stop"
style="@style/AddressBar.ImageButton.Icon"

View File

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

View File

@@ -76,4 +76,8 @@
<dimen name="validation_message_margin_top">6dp</dimen>
<dimen name="forward_default_offset">-13dip</dimen>
<dimen name="addressbar_offset_left">32dp</dimen>
<!-- PageActionButtons dimensions -->
<dimen name="page_action_button_width">32dp</dimen>
<dimen name="toast_button_padding">8dp</dimen>
</resources>

View File

@@ -506,7 +506,7 @@
<item name="android:textAppearance">?android:textAppearanceSmall</item>
<item name="android:paddingTop">0dp</item>
<item name="android:paddingBottom">0dp</item>
<item name="android:paddingLeft">8dp</item>
<item name="android:paddingLeft">@dimen/toast_button_padding</item>
<item name="android:paddingRight">0dp</item>
<item name="android:layout_marginTop">0dp</item>
<item name="android:layout_marginBottom">0dp</item>

Some files were not shown because too many files have changed in this diff Show More